mirror of
https://github.com/oxen-io/session-android.git
synced 2025-08-11 21:17:42 +00:00
feat: clear all data dialog with local and network only options
This commit is contained in:
@@ -107,9 +107,9 @@ object SnodeAPI {
|
||||
val parameters = mapOf(
|
||||
"method" to "get_n_service_nodes",
|
||||
"params" to mapOf(
|
||||
"active_only" to true,
|
||||
"limit" to 256,
|
||||
"fields" to mapOf( "public_ip" to true, "storage_port" to true, "pubkey_x25519" to true, "pubkey_ed25519" to true )
|
||||
"active_only" to true,
|
||||
"limit" to 256,
|
||||
"fields" to mapOf("public_ip" to true, "storage_port" to true, "pubkey_x25519" to true, "pubkey_ed25519" to true)
|
||||
)
|
||||
)
|
||||
val deferred = deferred<Snode, Exception>()
|
||||
@@ -185,8 +185,8 @@ object SnodeAPI {
|
||||
val base64EncodedNameHash = Base64.encodeBytes(nameHash)
|
||||
// Ask 3 different snodes for the Session ID associated with the given name hash
|
||||
val parameters = mapOf(
|
||||
"endpoint" to "ons_resolve",
|
||||
"params" to mapOf( "type" to 0, "name_hash" to base64EncodedNameHash )
|
||||
"endpoint" to "ons_resolve",
|
||||
"params" to mapOf( "type" to 0, "name_hash" to base64EncodedNameHash )
|
||||
)
|
||||
val promises = (1..validationCount).map {
|
||||
getRandomSnode().bind { snode ->
|
||||
@@ -293,7 +293,7 @@ object SnodeAPI {
|
||||
|
||||
fun getNetworkTime(snode: Snode): Promise<Pair<Snode,Long>, Exception> {
|
||||
return invoke(Snode.Method.Info, snode, null, emptyMap()).map { rawResponse ->
|
||||
val timestamp = rawResponse["timestamp"] as Long
|
||||
val timestamp = rawResponse["timestamp"] as? Long ?: -1
|
||||
snode to timestamp
|
||||
}
|
||||
}
|
||||
@@ -312,39 +312,6 @@ object SnodeAPI {
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteAllMessages(context: Context): Promise<Set<RawResponsePromise>, Exception> {
|
||||
|
||||
return retryIfNeeded(maxRetryCount) {
|
||||
// considerations: timestamp off in retrying logic, not being able to re-sign with latest timestamp? do we just not retry this as it will be synchronous
|
||||
val userED25519KeyPair = KeyPairUtilities.getUserED25519KeyPair(context) ?: return@retryIfNeeded Promise.ofFail(Error.Generic)
|
||||
val userPublicKey = MessagingModuleConfiguration.shared.storage.getUserPublicKey() ?: return@retryIfNeeded Promise.ofFail(Error.Generic)
|
||||
|
||||
val destination = if (useTestnet) userPublicKey.removing05PrefixIfNeeded() else userPublicKey
|
||||
|
||||
getSwarm(destination).map { swarm ->
|
||||
val promise = swarm.first().let { snode ->
|
||||
retryIfNeeded(maxRetryCount) {
|
||||
getNetworkTime(snode).bind { (_, timestamp) ->
|
||||
val signature = ByteArray(Sign.BYTES)
|
||||
val data = (Snode.Method.DeleteAll.rawValue + timestamp.toString()).toByteArray()
|
||||
sodium.cryptoSignDetached(signature, data, data.size.toLong(), userED25519KeyPair.secretKey.asBytes)
|
||||
val deleteMessageParams = mapOf(
|
||||
"pubkey" to userPublicKey,
|
||||
"pubkey_ed25519" to userED25519KeyPair.publicKey.asHexString,
|
||||
"timestamp" to timestamp,
|
||||
"signature" to Base64.encodeBytes(signature)
|
||||
)
|
||||
invoke(Snode.Method.DeleteAll, snode, destination, deleteMessageParams).map { rawResponse -> parseDeletions(timestamp, rawResponse) }.fail { e ->
|
||||
Log.e("Loki", "Failed to clear data",e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
setOf(promise)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parsing
|
||||
private fun parseSnodes(rawResponse: Any): List<Snode> {
|
||||
val json = rawResponse as? Map<*, *>
|
||||
@@ -370,6 +337,34 @@ object SnodeAPI {
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteAllMessages(context: Context): Promise<Map<String,Boolean>, Exception> {
|
||||
|
||||
return retryIfNeeded(maxRetryCount) {
|
||||
// considerations: timestamp off in retrying logic, not being able to re-sign with latest timestamp? do we just not retry this as it will be synchronous
|
||||
val userED25519KeyPair = KeyPairUtilities.getUserED25519KeyPair(context) ?: return@retryIfNeeded Promise.ofFail(Error.Generic)
|
||||
val userPublicKey = MessagingModuleConfiguration.shared.storage.getUserPublicKey() ?: return@retryIfNeeded Promise.ofFail(Error.Generic)
|
||||
|
||||
getSingleTargetSnode(userPublicKey).bind { snode ->
|
||||
retryIfNeeded(maxRetryCount) {
|
||||
getNetworkTime(snode).bind { (_, timestamp) ->
|
||||
val signature = ByteArray(Sign.BYTES)
|
||||
val data = (Snode.Method.DeleteAll.rawValue + timestamp.toString()).toByteArray()
|
||||
sodium.cryptoSignDetached(signature, data, data.size.toLong(), userED25519KeyPair.secretKey.asBytes)
|
||||
val deleteMessageParams = mapOf(
|
||||
"pubkey" to userPublicKey,
|
||||
"pubkey_ed25519" to userED25519KeyPair.publicKey.asHexString,
|
||||
"timestamp" to timestamp,
|
||||
"signature" to Base64.encodeBytes(signature)
|
||||
)
|
||||
invoke(Snode.Method.DeleteAll, snode, userPublicKey, deleteMessageParams).map { rawResponse -> parseDeletions(userPublicKey, timestamp, rawResponse) }.fail { e ->
|
||||
Log.e("Loki", "Failed to clear data", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun parseRawMessagesResponse(rawResponse: RawResponse, snode: Snode, publicKey: String): List<SignalServiceProtos.Envelope> {
|
||||
val messages = rawResponse["messages"] as? List<*>
|
||||
return if (messages != null) {
|
||||
@@ -429,10 +424,11 @@ object SnodeAPI {
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private fun parseDeletions(timestamp: Long, rawResponse: RawResponse): Map<String, Any> {
|
||||
val swarms = rawResponse["swarms"] as? Map<String,Any> ?: return mapOf()
|
||||
private fun parseDeletions(userPublicKey: String, timestamp: Long, rawResponse: RawResponse): Map<String, Boolean> {
|
||||
val swarms = rawResponse["swarm"] as? Map<String, Any> ?: return mapOf()
|
||||
val swarmResponsesValid = swarms.mapNotNull { (nodePubKeyHex, rawMap) ->
|
||||
val map = rawMap as? Map<String,Any> ?: return@mapNotNull null
|
||||
val map = rawMap as? Map<String, Any> ?: return@mapNotNull null
|
||||
|
||||
/** Deletes all messages owned by the given pubkey on this SN and broadcasts the delete request to
|
||||
* all other swarm members.
|
||||
* Returns dict of:
|
||||
@@ -448,17 +444,16 @@ object SnodeAPI {
|
||||
val reason = map["reason"] as? String
|
||||
|
||||
nodePubKeyHex to if (failed) {
|
||||
// return error probs
|
||||
Log.e("Loki", "Failed to delete all from $nodePubKeyHex with error code $code and reason $reason")
|
||||
false
|
||||
} else {
|
||||
// success
|
||||
val deleted = map["deleted"] as List<String> // list of deleted hashes
|
||||
Log.d("Loki", "node $nodePubKeyHex deleted ${deleted.size} messages")
|
||||
val signature = map["signature"] as String
|
||||
val nodePubKeyBytes = Hex.fromStringCondensed(nodePubKeyHex)
|
||||
val nodePubKey = Key.fromHexString(nodePubKeyHex)
|
||||
// signature of ( PUBKEY_HEX || TIMESTAMP || DELETEDHASH[0] || ... || DELETEDHASH[N] )
|
||||
val message = (signature + timestamp + deleted.fold("") { a, v -> a+v }).toByteArray()
|
||||
sodium.cryptoSignVerifyDetached(Base64.decode(signature), message, message.size, nodePubKeyBytes)
|
||||
val message = (userPublicKey + timestamp.toString() + deleted.fold("") { a, v -> a + v }).toByteArray()
|
||||
sodium.cryptoSignVerifyDetached(Base64.decode(signature), message, message.size, nodePubKey.asBytes)
|
||||
}
|
||||
}
|
||||
return swarmResponsesValid.toMap()
|
||||
|
Reference in New Issue
Block a user