mirror of
https://github.com/oxen-io/session-android.git
synced 2025-08-24 12:29:25 +00:00
refactor: fixing compile issues and namespace references throughout. figuring out config sig and base issues
This commit is contained in:
@@ -2,7 +2,7 @@ package org.session.libsession.database
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import network.loki.messenger.libsession_util.ConfigBase
|
||||
import network.loki.messenger.libsession_util.Config
|
||||
import org.session.libsession.messaging.BlindedIdMapping
|
||||
import org.session.libsession.messaging.calls.CallMessageType
|
||||
import org.session.libsession.messaging.contacts.Contact
|
||||
@@ -237,7 +237,7 @@ interface StorageProtocol {
|
||||
fun blockedContacts(): List<Recipient>
|
||||
|
||||
// Shared configs
|
||||
fun notifyConfigUpdates(forConfigObject: ConfigBase)
|
||||
fun notifyConfigUpdates(forConfigObject: Config)
|
||||
fun conversationInConfig(publicKey: String?, groupPublicKey: String?, openGroupId: String?, visibleOnly: Boolean): Boolean
|
||||
fun canPerformConfigChange(variant: String, publicKey: String, changeTimestampMs: Long): Boolean
|
||||
fun isCheckingCommunityRequests(): Boolean
|
||||
|
@@ -1,20 +1,20 @@
|
||||
package org.session.libsession.messaging.jobs
|
||||
|
||||
import network.loki.messenger.libsession_util.Config
|
||||
import network.loki.messenger.libsession_util.ConfigBase
|
||||
import network.loki.messenger.libsession_util.ConfigBase.Companion.protoKindFor
|
||||
import nl.komponents.kovenant.functional.bind
|
||||
import org.session.libsession.messaging.MessagingModuleConfiguration
|
||||
import org.session.libsession.messaging.messages.Destination
|
||||
import org.session.libsession.messaging.messages.control.SharedConfigurationMessage
|
||||
import org.session.libsession.messaging.sending_receiving.MessageSender
|
||||
import org.session.libsession.messaging.utilities.Data
|
||||
import org.session.libsession.snode.RawResponse
|
||||
import org.session.libsession.snode.SnodeAPI
|
||||
import org.session.libsession.snode.SnodeAPI.SnodeBatchRequestInfo
|
||||
import org.session.libsession.utilities.TextSecurePreferences
|
||||
import org.session.libsession.utilities.ConfigFactoryProtocol
|
||||
import org.session.libsignal.utilities.Log
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
typealias ConfigPair<T> = List<Pair<T, ConfigBase>>
|
||||
|
||||
class InvalidDestination: Exception("Trying to push configs somewhere other than our swarm or a closed group")
|
||||
class InvalidContactDestination: Exception("Trying to push to non-user config swarm")
|
||||
|
||||
// only contact (self) and closed group destinations will be supported
|
||||
data class ConfigurationSyncJob(val destination: Destination): Job {
|
||||
@@ -26,61 +26,47 @@ data class ConfigurationSyncJob(val destination: Destination): Job {
|
||||
|
||||
val shouldRunAgain = AtomicBoolean(false)
|
||||
|
||||
data class SyncInformation(val configs: ConfigPair<SnodeBatchRequestInfo>, val toDelete: List<String>)
|
||||
data class ConfigMessageInformation(val batch: SnodeBatchRequestInfo, val config: Config, val seqNo: Long?) // seqNo will be null for keys type
|
||||
|
||||
data class SyncInformation(val configs: List<ConfigMessageInformation>, val toDelete: List<String>)
|
||||
|
||||
private fun destinationConfigs(delegate: JobDelegate, configFactoryProtocol: ConfigFactoryProtocol): SyncInformation {
|
||||
TODO()
|
||||
}
|
||||
|
||||
override suspend fun execute(dispatcherName: String) {
|
||||
val storage = MessagingModuleConfiguration.shared.storage
|
||||
val forcedConfig = TextSecurePreferences.hasForcedNewConfig(MessagingModuleConfiguration.shared.context)
|
||||
val currentTime = SnodeAPI.nowWithOffset
|
||||
|
||||
val userPublicKey = storage.getUserPublicKey()
|
||||
val delegate = delegate ?: return Log.e("ConfigurationSyncJob", "No Delegate")
|
||||
if ((destination is Destination.Contact && destination.publicKey != userPublicKey)) {
|
||||
Log.w(TAG, "No need to run config sync job, TODO")
|
||||
return delegate.handleJobSucceeded(this, dispatcherName)
|
||||
if (destination is Destination.Contact && destination.publicKey != userPublicKey) {
|
||||
return delegate.handleJobFailedPermanently(this, dispatcherName, InvalidContactDestination())
|
||||
} else if (destination !is Destination.ClosedGroup) {
|
||||
return delegate.handleJobFailedPermanently(this, dispatcherName, InvalidDestination())
|
||||
}
|
||||
|
||||
// configFactory singleton instance will come in handy for modifying hashes and fetching configs for namespace etc
|
||||
val configFactory = MessagingModuleConfiguration.shared.configFactory
|
||||
|
||||
// **** start user ****
|
||||
// get latest states, filter out configs that don't need push
|
||||
val configsRequiringPush = configFactory.getUserConfigs().filter { config -> config.needsPush() }
|
||||
|
||||
// don't run anything if we don't need to push anything
|
||||
if (configsRequiringPush.isEmpty()) return delegate.handleJobSucceeded(this, dispatcherName)
|
||||
|
||||
// need to get the current hashes before we call `push()`
|
||||
val toDeleteHashes = mutableListOf<String>()
|
||||
|
||||
// **** end user ****
|
||||
// allow null results here so the list index matches configsRequiringPush
|
||||
val sentTimestamp: Long = SnodeAPI.nowWithOffset
|
||||
val batchObjects: List<Pair<SharedConfigurationMessage, SnodeBatchRequestInfo>?> = configsRequiringPush.map { config ->
|
||||
val (data, seqNo, obsoleteHashes) = config.push()
|
||||
toDeleteHashes += obsoleteHashes
|
||||
SharedConfigurationMessage(config.protoKindFor(), data, seqNo) to config
|
||||
}.map { (message, config) ->
|
||||
// return a list of batch request objects
|
||||
val snodeMessage = MessageSender.buildWrappedMessageToSnode(destination, message, true)
|
||||
val authenticated = SnodeAPI.buildAuthenticatedStoreBatchInfo(
|
||||
config.configNamespace(),
|
||||
snodeMessage
|
||||
) ?: return@map null // this entry will be null otherwise
|
||||
message to authenticated // to keep track of seqNo for calling confirmPushed later
|
||||
}
|
||||
val (batchObjects, toDeleteHashes) = destinationConfigs(delegate, configFactory)
|
||||
|
||||
val toDeleteRequest = toDeleteHashes.let { toDeleteFromAllNamespaces ->
|
||||
if (toDeleteFromAllNamespaces.isEmpty()) null
|
||||
else SnodeAPI.buildAuthenticatedDeleteBatchInfo(destination.destinationPublicKey(), toDeleteFromAllNamespaces)
|
||||
}
|
||||
|
||||
if (batchObjects.any { it == null }) {
|
||||
// stop running here, something like a signing error occurred
|
||||
return delegate.handleJobFailedPermanently(this, dispatcherName, NullPointerException("One or more requests had a null batch request info"))
|
||||
}
|
||||
|
||||
val allRequests = mutableListOf<SnodeBatchRequestInfo>()
|
||||
allRequests += batchObjects.requireNoNulls().map { (_, request) -> request }
|
||||
allRequests += batchObjects.map { (request) -> request }
|
||||
// add in the deletion if we have any hashes
|
||||
if (toDeleteRequest != null) {
|
||||
allRequests += toDeleteRequest
|
||||
@@ -118,23 +104,26 @@ data class ConfigurationSyncJob(val destination: Destination): Job {
|
||||
} ?: emptySet()
|
||||
|
||||
// at this point responseList index should line up with configsRequiringPush index
|
||||
configsRequiringPush.forEachIndexed { index, config ->
|
||||
val (toPushMessage, _) = batchObjects[index]!!
|
||||
batchObjects.forEachIndexed { index, (message, config, seqNo) ->
|
||||
val response = responseList[index]
|
||||
val responseBody = response["body"] as? RawResponse
|
||||
val insertHash = responseBody?.get("hash") as? String ?: run {
|
||||
Log.w(TAG, "No hash returned for the configuration in namespace ${config.configNamespace()}")
|
||||
Log.w(TAG, "No hash returned for the configuration in namespace ${config.namespace()}")
|
||||
return@forEachIndexed
|
||||
}
|
||||
Log.d(TAG, "Hash ${insertHash.take(4)} returned from store request for new config")
|
||||
|
||||
// confirm pushed seqno
|
||||
val thisSeqNo = toPushMessage.seqNo
|
||||
config.confirmPushed(thisSeqNo, insertHash)
|
||||
if (config is ConfigBase) {
|
||||
seqNo?.let {
|
||||
config.confirmPushed(it, insertHash)
|
||||
}
|
||||
}
|
||||
|
||||
Log.d(TAG, "Successfully removed the deleted hashes from ${config.javaClass.simpleName}")
|
||||
// dump and write config after successful
|
||||
if (config.needsDump()) { // usually this will be true?
|
||||
configFactory.persist(config, toPushMessage.sentTimestamp ?: sentTimestamp)
|
||||
if (config is ConfigBase && config.needsDump()) { // usually this will be true?
|
||||
configFactory.persist(config, (message.params["timestamp"] as String).toLong())
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
@@ -152,10 +141,6 @@ data class ConfigurationSyncJob(val destination: Destination): Job {
|
||||
val userEdKeyPair = MessagingModuleConfiguration.shared.getUserED25519KeyPair()
|
||||
}
|
||||
|
||||
private fun syncGroupConfigs(delegate: JobDelegate) {
|
||||
|
||||
}
|
||||
|
||||
fun Destination.destinationPublicKey(): String = when (this) {
|
||||
is Destination.Contact -> publicKey
|
||||
is Destination.ClosedGroup -> publicKey
|
||||
|
@@ -197,10 +197,10 @@ object MessageSender {
|
||||
val forkInfo = SnodeAPI.forkInfo
|
||||
val namespaces: List<Int> = when {
|
||||
destination is Destination.LegacyClosedGroup
|
||||
&& forkInfo.defaultRequiresAuth() -> listOf(Namespace.UNAUTHENTICATED_CLOSED_GROUP)
|
||||
&& forkInfo.defaultRequiresAuth() -> listOf(Namespace.UNAUTHENTICATED_CLOSED_GROUP())
|
||||
destination is Destination.LegacyClosedGroup
|
||||
&& forkInfo.hasNamespaces() -> listOf(Namespace.UNAUTHENTICATED_CLOSED_GROUP, Namespace.DEFAULT)
|
||||
else -> listOf(Namespace.DEFAULT)
|
||||
&& forkInfo.hasNamespaces() -> listOf(Namespace.UNAUTHENTICATED_CLOSED_GROUP(), Namespace.DEFAULT())
|
||||
else -> listOf(Namespace.DEFAULT())
|
||||
}
|
||||
namespaces.map { namespace ->
|
||||
if (destination is Destination.ClosedGroup) {
|
||||
|
@@ -104,28 +104,28 @@ class ClosedGroupPoller(private val executor: CoroutineScope,
|
||||
val messagePoll = SnodeAPI.buildAuthenticatedRetrieveBatchRequest(
|
||||
snode,
|
||||
closedGroupSessionId.hexString(),
|
||||
Namespace.DEFAULT,
|
||||
Namespace.DEFAULT(),
|
||||
maxSize = null,
|
||||
group.signingKey()
|
||||
) ?: return null
|
||||
val infoPoll = SnodeAPI.buildAuthenticatedRetrieveBatchRequest(
|
||||
snode,
|
||||
closedGroupSessionId.hexString(),
|
||||
info.configNamespace(),
|
||||
info.namespace(),
|
||||
maxSize = null,
|
||||
group.signingKey()
|
||||
) ?: return null
|
||||
val membersPoll = SnodeAPI.buildAuthenticatedRetrieveBatchRequest(
|
||||
snode,
|
||||
closedGroupSessionId.hexString(),
|
||||
members.configNamespace(),
|
||||
members.namespace(),
|
||||
maxSize = null,
|
||||
group.signingKey()
|
||||
) ?: return null
|
||||
val keysPoll = SnodeAPI.buildAuthenticatedRetrieveBatchRequest(
|
||||
snode,
|
||||
closedGroupSessionId.hexString(),
|
||||
GroupKeysConfig.storageNamespace(),
|
||||
keys.namespace(),
|
||||
maxSize = null,
|
||||
group.signingKey()
|
||||
) ?: return null
|
||||
|
@@ -108,13 +108,13 @@ class LegacyClosedGroupPollerV2 {
|
||||
if (!isPolling(groupPublicKey)) { throw PollingCanceledException() }
|
||||
val currentForkInfo = SnodeAPI.forkInfo
|
||||
when {
|
||||
currentForkInfo.defaultRequiresAuth() -> SnodeAPI.getRawMessages(snode, groupPublicKey, requiresAuth = false, namespace = Namespace.UNAUTHENTICATED_CLOSED_GROUP)
|
||||
.map { SnodeAPI.parseRawMessagesResponse(it, snode, groupPublicKey, Namespace.UNAUTHENTICATED_CLOSED_GROUP) }
|
||||
currentForkInfo.defaultRequiresAuth() -> SnodeAPI.getRawMessages(snode, groupPublicKey, requiresAuth = false, namespace = Namespace.UNAUTHENTICATED_CLOSED_GROUP())
|
||||
.map { SnodeAPI.parseRawMessagesResponse(it, snode, groupPublicKey, Namespace.UNAUTHENTICATED_CLOSED_GROUP()) }
|
||||
currentForkInfo.hasNamespaces() -> task {
|
||||
val unAuthed = SnodeAPI.getRawMessages(snode, groupPublicKey, requiresAuth = false, namespace = Namespace.UNAUTHENTICATED_CLOSED_GROUP)
|
||||
.map { SnodeAPI.parseRawMessagesResponse(it, snode, groupPublicKey, Namespace.UNAUTHENTICATED_CLOSED_GROUP) }
|
||||
val default = SnodeAPI.getRawMessages(snode, groupPublicKey, requiresAuth = false, namespace = Namespace.DEFAULT)
|
||||
.map { SnodeAPI.parseRawMessagesResponse(it, snode, groupPublicKey, Namespace.DEFAULT) }
|
||||
val unAuthed = SnodeAPI.getRawMessages(snode, groupPublicKey, requiresAuth = false, namespace = Namespace.UNAUTHENTICATED_CLOSED_GROUP())
|
||||
.map { SnodeAPI.parseRawMessagesResponse(it, snode, groupPublicKey, Namespace.UNAUTHENTICATED_CLOSED_GROUP()) }
|
||||
val default = SnodeAPI.getRawMessages(snode, groupPublicKey, requiresAuth = false, namespace = Namespace.DEFAULT())
|
||||
.map { SnodeAPI.parseRawMessagesResponse(it, snode, groupPublicKey, Namespace.DEFAULT()) }
|
||||
val unAuthedResult = unAuthed.get()
|
||||
val defaultResult = default.get()
|
||||
val format = DateFormat.getTimeInstance()
|
||||
@@ -123,7 +123,7 @@ class LegacyClosedGroupPollerV2 {
|
||||
}
|
||||
unAuthedResult + defaultResult
|
||||
}
|
||||
else -> SnodeAPI.getRawMessages(snode, groupPublicKey, requiresAuth = false, namespace = Namespace.DEFAULT)
|
||||
else -> SnodeAPI.getRawMessages(snode, groupPublicKey, requiresAuth = false, namespace = Namespace.DEFAULT())
|
||||
.map { SnodeAPI.parseRawMessagesResponse(it, snode, groupPublicKey) }
|
||||
}
|
||||
}
|
||||
|
@@ -180,7 +180,7 @@ class Poller(private val configFactory: ConfigFactoryProtocol, debounceTimer: Ti
|
||||
hashesToExtend += config.currentHashes()
|
||||
SnodeAPI.buildAuthenticatedRetrieveBatchRequest(
|
||||
snode, userPublicKey,
|
||||
config.configNamespace(),
|
||||
config.namespace(),
|
||||
maxSize = -8
|
||||
)
|
||||
}.forEach { request ->
|
||||
@@ -211,10 +211,10 @@ class Poller(private val configFactory: ConfigFactoryProtocol, debounceTimer: Ti
|
||||
// in case we had null configs, the array won't be fully populated
|
||||
// index of the sparse array key iterator should be the request index, with the key being the namespace
|
||||
listOfNotNull(
|
||||
configFactory.user?.configNamespace(),
|
||||
configFactory.contacts?.configNamespace(),
|
||||
configFactory.userGroups?.configNamespace(),
|
||||
configFactory.convoVolatile?.configNamespace()
|
||||
configFactory.user?.namespace(),
|
||||
configFactory.contacts?.namespace(),
|
||||
configFactory.userGroups?.namespace(),
|
||||
configFactory.convoVolatile?.namespace()
|
||||
).map {
|
||||
it to requestSparseArray.indexOfKey(it)
|
||||
}.filter { (_, i) -> i >= 0 }.forEach { (key, requestIndex) ->
|
||||
@@ -228,7 +228,7 @@ class Poller(private val configFactory: ConfigFactoryProtocol, debounceTimer: Ti
|
||||
Log.e("Loki", "Batch sub-request didn't contain a body")
|
||||
return@forEach
|
||||
}
|
||||
if (key == Namespace.DEFAULT) {
|
||||
if (key == Namespace.DEFAULT()) {
|
||||
return@forEach // continue, skip default namespace
|
||||
} else {
|
||||
when (ConfigBase.kindFor(key)) {
|
||||
@@ -242,7 +242,7 @@ class Poller(private val configFactory: ConfigFactoryProtocol, debounceTimer: Ti
|
||||
}
|
||||
|
||||
// the first response will be the personal messages (we want these to be processed after config messages)
|
||||
val personalResponseIndex = requestSparseArray.indexOfKey(Namespace.DEFAULT)
|
||||
val personalResponseIndex = requestSparseArray.indexOfKey(Namespace.DEFAULT())
|
||||
if (personalResponseIndex >= 0) {
|
||||
responseList.getOrNull(personalResponseIndex)?.let { rawResponse ->
|
||||
if (rawResponse["code"] as? Int != 200) {
|
||||
|
@@ -793,14 +793,14 @@ object SnodeAPI {
|
||||
retryIfNeeded(maxRetryCount) {
|
||||
getNetworkTime(snode).bind { (_, timestamp) ->
|
||||
val signature = ByteArray(Sign.BYTES)
|
||||
val verificationData = (Snode.Method.DeleteAll.rawValue + Namespace.ALL + timestamp.toString()).toByteArray()
|
||||
val verificationData = (Snode.Method.DeleteAll.rawValue + Namespace.ALL() + timestamp.toString()).toByteArray()
|
||||
sodium.cryptoSignDetached(signature, verificationData, verificationData.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),
|
||||
"namespace" to Namespace.ALL,
|
||||
"namespace" to Namespace.ALL(),
|
||||
)
|
||||
invoke(Snode.Method.DeleteAll, snode, deleteMessageParams, userPublicKey).map {
|
||||
rawResponse -> parseDeletions(userPublicKey, timestamp, rawResponse)
|
||||
|
@@ -1,5 +1,6 @@
|
||||
package org.session.libsession.utilities
|
||||
|
||||
import network.loki.messenger.libsession_util.Config
|
||||
import network.loki.messenger.libsession_util.ConfigBase
|
||||
import network.loki.messenger.libsession_util.Contacts
|
||||
import network.loki.messenger.libsession_util.ConversationVolatileConfig
|
||||
@@ -21,7 +22,7 @@ interface ConfigFactoryProtocol {
|
||||
fun getGroupKeysConfig(groupSessionId: SessionId): GroupKeysConfig?
|
||||
|
||||
fun getUserConfigs(): List<ConfigBase>
|
||||
fun persist(forConfigObject: ConfigBase, timestamp: Long)
|
||||
fun persist(forConfigObject: Config, timestamp: Long)
|
||||
|
||||
fun conversationInConfig(publicKey: String?, groupPublicKey: String?, openGroupId: String?, visibleOnly: Boolean): Boolean
|
||||
fun canPerformChange(variant: String, publicKey: String, changeTimestampMs: Long): Boolean
|
||||
@@ -33,5 +34,5 @@ interface ConfigFactoryProtocol {
|
||||
}
|
||||
|
||||
interface ConfigFactoryUpdateListener {
|
||||
fun notifyUpdates(forConfigObject: ConfigBase)
|
||||
fun notifyUpdates(forConfigObject: Config)
|
||||
}
|
Reference in New Issue
Block a user