feat(WIP): build an authenticated delete with sign callback

This commit is contained in:
0x330a 2023-10-27 16:45:44 +11:00
parent 2fc83b87ad
commit b62cca2612
No known key found for this signature in database
GPG Key ID: 267811D6E6A2698C
5 changed files with 30 additions and 22 deletions

View File

@ -1,5 +1,6 @@
package org.thoughtcrime.securesms.dependencies package org.thoughtcrime.securesms.dependencies
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.plus import kotlinx.coroutines.plus
@ -8,6 +9,7 @@ import org.session.libsignal.utilities.SessionId
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
class PollerFactory(private val scope: CoroutineScope, class PollerFactory(private val scope: CoroutineScope,
private val executor: CoroutineDispatcher,
private val configFactory: ConfigFactory) { private val configFactory: ConfigFactory) {
private val pollers = ConcurrentHashMap<SessionId, ClosedGroupPoller>() private val pollers = ConcurrentHashMap<SessionId, ClosedGroupPoller>()
@ -17,7 +19,7 @@ class PollerFactory(private val scope: CoroutineScope,
configFactory.userGroups?.getClosedGroup(sessionId.hexString()) ?: return null configFactory.userGroups?.getClosedGroup(sessionId.hexString()) ?: return null
return pollers.getOrPut(sessionId) { return pollers.getOrPut(sessionId) {
ClosedGroupPoller(scope + SupervisorJob(), sessionId, configFactory) ClosedGroupPoller(scope + SupervisorJob(), executor, sessionId, configFactory)
} }
} }

View File

@ -6,7 +6,10 @@ import dagger.Provides
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent import dagger.hilt.components.SingletonComponent
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import org.session.libsession.utilities.ConfigFactoryUpdateListener import org.session.libsession.utilities.ConfigFactoryUpdateListener
import org.session.libsession.utilities.TextSecurePreferences import org.session.libsession.utilities.TextSecurePreferences
@ -42,9 +45,15 @@ object SessionUtilModule {
@Named(POLLER_SCOPE) @Named(POLLER_SCOPE)
fun providePollerScope(@ApplicationContext applicationContext: Context): CoroutineScope = GlobalScope fun providePollerScope(@ApplicationContext applicationContext: Context): CoroutineScope = GlobalScope
@OptIn(ExperimentalCoroutinesApi::class)
@Provides
@Named(POLLER_SCOPE)
fun provideExecutor(): CoroutineDispatcher = Dispatchers.IO.limitedParallelism(1)
@Provides @Provides
@Singleton @Singleton
fun providePollerFactory(@Named(POLLER_SCOPE) coroutineScope: CoroutineScope, fun providePollerFactory(@Named(POLLER_SCOPE) coroutineScope: CoroutineScope,
configFactory: ConfigFactory) = PollerFactory(coroutineScope, configFactory) @Named(POLLER_SCOPE) dispatcher: CoroutineDispatcher,
configFactory: ConfigFactory) = PollerFactory(coroutineScope, dispatcher, configFactory)
} }

View File

@ -84,7 +84,7 @@ data class ConfigurationSyncJob(val destination: Destination) : Job {
if (config is GroupKeysConfig) { if (config is GroupKeysConfig) {
config.messageInformation(destination.publicKey, signingKey) config.messageInformation(destination.publicKey, signingKey)
} else if (config is ConfigBase) { } else if (config is ConfigBase) {
config.messageInformation(toDelete, destination.publicKey, signingKey, groupId.publicKey) config.messageInformation(toDelete, destination.publicKey, signingKey)
} else { } else {
Log.e("ConfigurationSyncJob", "Tried to create a message from an unknown config") Log.e("ConfigurationSyncJob", "Tried to create a message from an unknown config")
null null

View File

@ -1,7 +1,7 @@
package org.session.libsession.messaging.sending_receiving.pollers package org.session.libsession.messaging.sending_receiving.pollers
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive import kotlinx.coroutines.isActive
@ -26,7 +26,8 @@ import org.session.libsignal.utilities.SessionId
import org.session.libsignal.utilities.Snode import org.session.libsignal.utilities.Snode
import kotlin.time.Duration.Companion.days import kotlin.time.Duration.Companion.days
class ClosedGroupPoller(private val executor: CoroutineScope, class ClosedGroupPoller(private val scope: CoroutineScope,
private val execute: CoroutineDispatcher,
private val closedGroupSessionId: SessionId, private val closedGroupSessionId: SessionId,
private val configFactoryProtocol: ConfigFactoryProtocol) { private val configFactoryProtocol: ConfigFactoryProtocol) {
@ -69,7 +70,7 @@ class ClosedGroupPoller(private val executor: CoroutineScope,
if (ENABLE_LOGGING) Log.d("ClosedGroupPoller", "Starting closed group poller for ${closedGroupSessionId.hexString().take(4)}") if (ENABLE_LOGGING) Log.d("ClosedGroupPoller", "Starting closed group poller for ${closedGroupSessionId.hexString().take(4)}")
job?.cancel() job?.cancel()
job = executor.launch(Dispatchers.IO) { job = scope.launch {
val closedGroups = configFactoryProtocol.userGroups ?: return@launch val closedGroups = configFactoryProtocol.userGroups ?: return@launch
isRunning = true isRunning = true
while (isActive && isRunning) { while (isActive && isRunning) {
@ -105,6 +106,8 @@ class ClosedGroupPoller(private val executor: CoroutineScope,
free = false free = false
) ?: return null ) ?: return null
val isAdmin = group.hasAdminKey()
val hashesToExtend = mutableSetOf<String>() val hashesToExtend = mutableSetOf<String>()
hashesToExtend += info.currentHashes() hashesToExtend += info.currentHashes()
@ -152,7 +155,7 @@ class ClosedGroupPoller(private val executor: CoroutineScope,
val requests = mutableListOf(keysPoll, infoPoll, membersPoll, messagePoll) val requests = mutableListOf(keysPoll, infoPoll, membersPoll, messagePoll)
if (hashesToExtend.isNotEmpty()) { if (isAdmin && hashesToExtend.isNotEmpty()) {
SnodeAPI.buildAuthenticatedAlterTtlBatchRequest( SnodeAPI.buildAuthenticatedAlterTtlBatchRequest(
messageHashes = hashesToExtend.toList(), messageHashes = hashesToExtend.toList(),
publicKey = closedGroupSessionId.hexString(), publicKey = closedGroupSessionId.hexString(),

View File

@ -439,21 +439,7 @@ object SnodeAPI {
return null return null
} }
val ed25519PublicKey = userEd25519KeyPair.publicKey.asHexString val ed25519PublicKey = userEd25519KeyPair.publicKey.asHexString
val signature = ByteArray(Sign.BYTES) val signCallback = signingKeyCallback(userEd25519KeyPair.secretKey.asBytes)
val verificationData = "delete${messageHashes.joinToString("")}".toByteArray()
try {
sodium.cryptoSignDetached(
signature,
verificationData,
verificationData.size.toLong(),
userEd25519KeyPair.secretKey.asBytes
)
} catch (e: Exception) {
Log.e("Loki", "Signing data failed with user secret key", e)
return null
}
params["pubkey_ed25519"] = ed25519PublicKey
params["signature"] = Base64.encodeBytes(signature)
return SnodeBatchRequestInfo( return SnodeBatchRequestInfo(
Snode.Method.DeleteMessage.rawValue, Snode.Method.DeleteMessage.rawValue,
params, params,
@ -461,6 +447,14 @@ object SnodeAPI {
) )
} }
fun buildAuthenticatedDeleteBatchInfo(
publicKey: String,
messageHashes: List<String>,
signCallback: SignCallback,
required: Boolean = false): SnodeBatchRequestInfo? {
val verificationData = "delete${messageHashes.joinToString("")}".toByteArray()
}
fun buildAuthenticatedRetrieveBatchRequest(snode: Snode, fun buildAuthenticatedRetrieveBatchRequest(snode: Snode,
publicKey: String, publicKey: String,
namespace: Int, namespace: Int,