mirror of
https://github.com/oxen-io/session-android.git
synced 2025-08-11 21:07:42 +00:00
feat: testnet clearing network data on delete and differentiating dialogs
This commit is contained in:
@@ -28,7 +28,6 @@ interface StorageProtocol {
|
||||
|
||||
// General
|
||||
fun getUserPublicKey(): String?
|
||||
fun getUserKeyPair(): Pair<String, ByteArray>?
|
||||
fun getUserX25519KeyPair(): ECKeyPair
|
||||
fun getUserDisplayName(): String?
|
||||
fun getUserProfileKey(): ByteArray?
|
||||
|
@@ -172,9 +172,9 @@ object OpenGroupAPIV2 {
|
||||
}
|
||||
|
||||
fun requestNewAuthToken(room: String, server: String): Promise<String, Exception> {
|
||||
val (publicKey, privateKey) = MessagingModuleConfiguration.shared.storage.getUserKeyPair()
|
||||
val (publicKey, privateKey) = MessagingModuleConfiguration.shared.storage.getUserX25519KeyPair().let { it.publicKey.serialize() to it.privateKey.serialize() }
|
||||
?: return Promise.ofFail(Error.Generic)
|
||||
val queryParameters = mutableMapOf( "public_key" to publicKey )
|
||||
val queryParameters = mutableMapOf( "public_key" to publicKey.toHexString() )
|
||||
val request = Request(GET, room, server, "auth_token_challenge", queryParameters, isAuthRequired = false, parameters = null)
|
||||
return send(request).map { json ->
|
||||
val challenge = json["challenge"] as? Map<*, *> ?: throw Error.ParsingFailed
|
||||
|
@@ -6,6 +6,7 @@ import org.session.libsignal.protos.SignalServiceProtos
|
||||
import org.session.libsignal.utilities.Base64
|
||||
import org.session.libsignal.utilities.Base64.decode
|
||||
import org.session.libsignal.utilities.Log
|
||||
import org.session.libsignal.utilities.toHexString
|
||||
import org.whispersystems.curve25519.Curve25519
|
||||
|
||||
data class OpenGroupMessageV2(
|
||||
@@ -45,10 +46,10 @@ data class OpenGroupMessageV2(
|
||||
|
||||
fun sign(): OpenGroupMessageV2? {
|
||||
if (base64EncodedData.isEmpty()) return null
|
||||
val (publicKey, privateKey) = MessagingModuleConfiguration.shared.storage.getUserKeyPair() ?: return null
|
||||
if (sender != publicKey) return null
|
||||
val (publicKey, privateKey) = MessagingModuleConfiguration.shared.storage.getUserX25519KeyPair().let { it.publicKey to it.privateKey }
|
||||
if (sender != publicKey.serialize().toHexString()) return null
|
||||
val signature = try {
|
||||
curve.calculateSignature(privateKey, decode(base64EncodedData))
|
||||
curve.calculateSignature(privateKey.serialize(), decode(base64EncodedData))
|
||||
} catch (e: Exception) {
|
||||
Log.w("Loki", "Couldn't sign open group message.", e)
|
||||
return null
|
||||
|
@@ -23,7 +23,7 @@ object MessageEncrypter {
|
||||
*
|
||||
* @return the encrypted message.
|
||||
*/
|
||||
internal fun encrypt(plaintext: ByteArray, recipientHexEncodedX25519PublicKey: String): ByteArray{
|
||||
internal fun encrypt(plaintext: ByteArray, recipientHexEncodedX25519PublicKey: String): ByteArray {
|
||||
val context = MessagingModuleConfiguration.shared.context
|
||||
val userED25519KeyPair = KeyPairUtilities.getUserED25519KeyPair(context) ?: throw Error.NoUserED25519KeyPair
|
||||
val recipientX25519PublicKey = Hex.fromStringCondensed(recipientHexEncodedX25519PublicKey.removing05PrefixIfNeeded())
|
||||
|
@@ -2,6 +2,7 @@
|
||||
|
||||
package org.session.libsession.snode
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import com.goterl.lazysodium.LazySodiumAndroid
|
||||
import com.goterl.lazysodium.SodiumAndroid
|
||||
@@ -9,18 +10,25 @@ import com.goterl.lazysodium.exceptions.SodiumException
|
||||
import com.goterl.lazysodium.interfaces.GenericHash
|
||||
import com.goterl.lazysodium.interfaces.PwHash
|
||||
import com.goterl.lazysodium.interfaces.SecretBox
|
||||
import com.goterl.lazysodium.interfaces.Sign
|
||||
import com.goterl.lazysodium.utils.Key
|
||||
import nl.komponents.kovenant.*
|
||||
import nl.komponents.kovenant.functional.bind
|
||||
import nl.komponents.kovenant.functional.map
|
||||
import org.session.libsession.messaging.MessagingModuleConfiguration
|
||||
import org.session.libsession.messaging.utilities.MessageWrapper
|
||||
import org.session.libsession.utilities.IdentityKeyUtil
|
||||
import org.session.libsession.utilities.KeyPairUtilities
|
||||
import org.session.libsignal.crypto.getRandomElement
|
||||
import org.session.libsignal.database.LokiAPIDatabaseProtocol
|
||||
import org.session.libsignal.protos.SignalServiceProtos
|
||||
import org.session.libsignal.utilities.*
|
||||
import org.session.libsignal.utilities.Base64
|
||||
import org.whispersystems.curve25519.Curve25519
|
||||
import java.nio.charset.Charset
|
||||
import java.security.SecureRandom
|
||||
import java.util.*
|
||||
import kotlin.Pair
|
||||
|
||||
object SnodeAPI {
|
||||
private val sodium by lazy { LazySodiumAndroid(SodiumAndroid()) }
|
||||
@@ -52,7 +60,7 @@ object SnodeAPI {
|
||||
private val targetSwarmSnodeCount = 2
|
||||
private val useOnionRequests = true
|
||||
|
||||
internal val useTestnet = false
|
||||
internal val useTestnet = true
|
||||
|
||||
// Error
|
||||
internal sealed class Error(val description: String) : Exception(description) {
|
||||
@@ -283,6 +291,13 @@ 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
|
||||
snode to timestamp
|
||||
}
|
||||
}
|
||||
|
||||
fun sendMessage(message: SnodeMessage): Promise<Set<RawResponsePromise>, Exception> {
|
||||
val destination = if (useTestnet) message.recipient.removing05PrefixIfNeeded() else message.recipient
|
||||
return retryIfNeeded(maxRetryCount) {
|
||||
@@ -306,15 +321,30 @@ object SnodeAPI {
|
||||
* - "signature": signature of ( PUBKEY_HEX || TIMESTAMP || DELETEDHASH[0] || ... || DELETEDHASH[N] ), signed
|
||||
* by the node's ed25519 pubkey.
|
||||
*/
|
||||
fun deleteAllMessages(deleteMessage: SnodeDeleteMessage): Promise<Set<RawResponsePromise>, Exception> {
|
||||
// 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 destination = if (useTestnet) deleteMessage.pubKey.removing05PrefixIfNeeded() else deleteMessage.pubKey
|
||||
return retryIfNeeded(maxRetryCount) {
|
||||
fun deleteAllMessages(context: Context): Promise<Set<RawResponsePromise>, Exception> {
|
||||
|
||||
return retryIfNeeded(1) {
|
||||
// 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 xPrivateKey = IdentityKeyUtil.getIdentityKeyPair(context).privateKey
|
||||
val userKeyPair = MessagingModuleConfiguration.shared.storage.getUserX25519KeyPair()
|
||||
val userPublicKey = MessagingModuleConfiguration.shared.storage.getUserPublicKey() ?: return@retryIfNeeded Promise.ofFail(Error.Generic)
|
||||
|
||||
val destination = if (useTestnet) userPublicKey.removing05PrefixIfNeeded() else userPublicKey
|
||||
|
||||
getTargetSnodes(destination).map { swarm ->
|
||||
swarm.map { snode ->
|
||||
val parameters = deleteMessage.toJSON()
|
||||
retryIfNeeded(maxRetryCount) {
|
||||
invoke(Snode.Method.DeleteAll, snode, destination, parameters)
|
||||
retryIfNeeded(1) {
|
||||
getNetworkTime(snode).bind { (_, timestamp) ->
|
||||
val signature = ByteArray(Sign.BYTES)
|
||||
val data = Snode.Method.DeleteAll.rawValue.toByteArray() + timestamp.toString().toByteArray()
|
||||
val signed = sodium.cryptoSignDetached(signature, data, data.size.toLong(), xPrivateKey.serialize())
|
||||
val deleteMessage = SnodeDeleteMessage(userPublicKey, timestamp, Base64.encodeBytes(signature))
|
||||
val parameters = deleteMessage.toJSON()
|
||||
invoke(Snode.Method.DeleteAll, snode, destination, parameters).fail { e ->
|
||||
Log.e("Loki", "Failed to clear data",e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}.toSet()
|
||||
}
|
||||
|
@@ -14,15 +14,15 @@ data class SnodeDeleteMessage(
|
||||
*/
|
||||
val timestamp: Long,
|
||||
/**
|
||||
* an Ed25519 signature of ( "delete_all" || timestamp ), signed by the ed25519
|
||||
* a Base64-encoded signature of ( "delete_all" || timestamp ), signed by the pubKey
|
||||
*/
|
||||
val signature: String,
|
||||
) {
|
||||
|
||||
internal fun toJSON(): Map<String, String> {
|
||||
internal fun toJSON(): Map<String, Any> {
|
||||
return mapOf(
|
||||
"pubkey" to if (SnodeAPI.useTestnet) pubKey.removing05PrefixIfNeeded() else pubKey,
|
||||
"timestamp" to timestamp.toString(),
|
||||
"pubkey" to pubKey,
|
||||
"timestamp" to timestamp,
|
||||
"signature" to signature
|
||||
)
|
||||
}
|
||||
|
Reference in New Issue
Block a user