mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-27 12:05:22 +00:00
feat: handling responses and using new updated params
This commit is contained in:
parent
fdc042e6d4
commit
05b0e5f308
@ -76,30 +76,37 @@ class ClearAllDataDialog(val deleteNetworkMessages: Boolean) : DialogFragment()
|
|||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e("Loki", "Failed to force sync", e)
|
Log.e("Loki", "Failed to force sync", e)
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
updateUI(false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// finish
|
// finish
|
||||||
val promises = SnodeAPI.deleteAllMessages(requireContext()).get()
|
val promises = try {
|
||||||
|
SnodeAPI.deleteAllMessages(requireContext()).get()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
val rawResponses = promises.map {
|
val rawResponses = promises?.map {
|
||||||
try {
|
try {
|
||||||
it.get()
|
it.get()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
}
|
} ?: listOf(null)
|
||||||
// TODO: process the responses here
|
// TODO: process the responses here
|
||||||
if (rawResponses.any { it == null || it["failed"] as? Boolean == true }) {
|
if (rawResponses.all { it != null }) {
|
||||||
// didn't succeed (at least one)
|
|
||||||
withContext(Dispatchers.Main) {
|
|
||||||
updateUI(false)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// don't force sync because all the messages are deleted?
|
// don't force sync because all the messages are deleted?
|
||||||
ApplicationContext.getInstance(context).clearAllData(false)
|
ApplicationContext.getInstance(context).clearAllData(false)
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
|
} else if (rawResponses.any { it == null || it["failed"] as? Boolean == true }) {
|
||||||
|
// didn't succeed (at least one)
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
updateUI(false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -312,41 +312,35 @@ object SnodeAPI {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Deletes all messages owned by the given pubkey on this SN and broadcasts the delete request to
|
|
||||||
* all other swarm members.
|
|
||||||
* Returns dict of:
|
|
||||||
* - "swarms" dict mapping ed25519 pubkeys (in hex) of swarm members to dict values of:
|
|
||||||
* - "failed" and other failure keys -- see `recursive`.
|
|
||||||
* - "deleted": hashes of deleted messages.
|
|
||||||
* - "signature": signature of ( PUBKEY_HEX || TIMESTAMP || DELETEDHASH[0] || ... || DELETEDHASH[N] ), signed
|
|
||||||
* by the node's ed25519 pubkey.
|
|
||||||
*/
|
|
||||||
fun deleteAllMessages(context: Context): Promise<Set<RawResponsePromise>, Exception> {
|
fun deleteAllMessages(context: Context): Promise<Set<RawResponsePromise>, Exception> {
|
||||||
|
|
||||||
return retryIfNeeded(1) {
|
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
|
// 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 ed = KeyPairUtilities.getUserED25519KeyPair(context) ?: return@retryIfNeeded Promise.ofFail(Error.Generic)
|
val userED25519KeyPair = KeyPairUtilities.getUserED25519KeyPair(context) ?: return@retryIfNeeded Promise.ofFail(Error.Generic)
|
||||||
val xPrivateKey = IdentityKeyUtil.getIdentityKeyPair(context).privateKey
|
|
||||||
val userKeyPair = MessagingModuleConfiguration.shared.storage.getUserX25519KeyPair()
|
|
||||||
val userPublicKey = MessagingModuleConfiguration.shared.storage.getUserPublicKey() ?: 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
|
val destination = if (useTestnet) userPublicKey.removing05PrefixIfNeeded() else userPublicKey
|
||||||
|
|
||||||
getTargetSnodes(destination).map { swarm ->
|
getSwarm(destination).map { swarm ->
|
||||||
swarm.map { snode ->
|
val promise = swarm.first().let { snode ->
|
||||||
retryIfNeeded(1) {
|
retryIfNeeded(maxRetryCount) {
|
||||||
getNetworkTime(snode).bind { (_, timestamp) ->
|
getNetworkTime(snode).bind { (_, timestamp) ->
|
||||||
val signature = ByteArray(Sign.BYTES)
|
val signature = ByteArray(Sign.BYTES)
|
||||||
val data = Snode.Method.DeleteAll.rawValue.toByteArray() + timestamp.toString().toByteArray()
|
val data = (Snode.Method.DeleteAll.rawValue + timestamp.toString()).toByteArray()
|
||||||
val signed = sodium.cryptoSignDetached(signature, data, data.size.toLong(), xPrivateKey.serialize())
|
sodium.cryptoSignDetached(signature, data, data.size.toLong(), userED25519KeyPair.secretKey.asBytes)
|
||||||
val deleteMessage = SnodeDeleteMessage(userPublicKey, timestamp, Base64.encodeBytes(signature))
|
val deleteMessageParams = mapOf(
|
||||||
val parameters = deleteMessage.toJSON()
|
"pubkey" to userPublicKey,
|
||||||
invoke(Snode.Method.DeleteAll, snode, destination, parameters).fail { e ->
|
"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)
|
Log.e("Loki", "Failed to clear data",e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.toSet()
|
}
|
||||||
|
setOf(promise)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -433,6 +427,43 @@ 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()
|
||||||
|
val swarmResponsesValid = swarms.mapNotNull { (nodePubKeyHex, rawMap) ->
|
||||||
|
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:
|
||||||
|
* - "swarms" dict mapping ed25519 pubkeys (in hex) of swarm members to dict values of:
|
||||||
|
* - "failed" and other failure keys -- see `recursive`.
|
||||||
|
* - "deleted": hashes of deleted messages.
|
||||||
|
* - "signature": signature of ( PUBKEY_HEX || TIMESTAMP || DELETEDHASH[0] || ... || DELETEDHASH[N] ), signed
|
||||||
|
* by the node's ed25519 pubkey.
|
||||||
|
*/
|
||||||
|
// failure
|
||||||
|
val failed = map["failed"] as? Boolean ?: false
|
||||||
|
val code = map["code"] as? String
|
||||||
|
val reason = map["reason"] as? String
|
||||||
|
|
||||||
|
nodePubKeyHex to if (failed) {
|
||||||
|
// return error probs
|
||||||
|
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)
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return swarmResponsesValid.toMap()
|
||||||
|
}
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
// Error Handling
|
// Error Handling
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
package org.session.libsession.snode
|
|
||||||
|
|
||||||
import org.session.libsignal.utilities.removing05PrefixIfNeeded
|
|
||||||
|
|
||||||
data class SnodeDeleteMessage(
|
|
||||||
/**
|
|
||||||
* The hex encoded public key of the user.
|
|
||||||
*/
|
|
||||||
val pubKey: String,
|
|
||||||
/**
|
|
||||||
* The timestamp at which this request was initiated, in milliseconds since unix epoch.
|
|
||||||
* Must be within Must be within ±60s of the current time.
|
|
||||||
* (For clients it is recommended to retrieve a timestamp via `info` first, to avoid client time sync issues).
|
|
||||||
*/
|
|
||||||
val timestamp: Long,
|
|
||||||
/**
|
|
||||||
* a Base64-encoded signature of ( "delete_all" || timestamp ), signed by the pubKey
|
|
||||||
*/
|
|
||||||
val signature: String,
|
|
||||||
) {
|
|
||||||
|
|
||||||
internal fun toJSON(): Map<String, Any> {
|
|
||||||
return mapOf(
|
|
||||||
"pubkey" to pubKey,
|
|
||||||
"timestamp" to timestamp,
|
|
||||||
"signature" to signature
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user