feat: add finishing of group push for initial group creation and saving group configs to DB. re-implement key signing messages properly for the signing config which doesn't override the config base

This commit is contained in:
0x330a
2023-09-11 18:07:23 +10:00
parent 2527ac2e21
commit 6067916da9
12 changed files with 174 additions and 68 deletions

View File

@@ -33,6 +33,7 @@ import org.session.libsignal.crypto.ecc.ECKeyPair
import org.session.libsignal.messages.SignalServiceAttachmentPointer
import org.session.libsignal.messages.SignalServiceGroup
import org.session.libsignal.utilities.SessionId
import org.session.libsignal.utilities.guava.Optional
import network.loki.messenger.libsession_util.util.Contact as LibSessionContact
interface StorageProtocol {
@@ -155,7 +156,7 @@ interface StorageProtocol {
fun setExpirationTimer(address: String, duration: Int)
// Closed Groups
suspend fun createNewGroup(groupName: String, groupDescription: String, members: Set<SessionId>): Long?
fun createNewGroup(groupName: String, groupDescription: String, members: Set<SessionId>): Optional<Boolean>
fun getMembers(groupPublicKey: String): List<network.loki.messenger.libsession_util.util.GroupMember>
// Groups

View File

@@ -69,7 +69,6 @@ data class ConfigurationSyncJob(val destination: Destination): Job {
// return a list of batch request objects
val snodeMessage = MessageSender.buildWrappedMessageToSnode(destination, message, true)
val authenticated = SnodeAPI.buildAuthenticatedStoreBatchInfo(
destination.destinationPublicKey(),
config.configNamespace(),
snodeMessage
) ?: return@map null // this entry will be null otherwise

View File

@@ -1,7 +1,5 @@
package org.session.libsession.messaging.sending_receiving
import androidx.annotation.WorkerThread
import network.loki.messenger.libsession_util.ConfigBase
import nl.komponents.kovenant.Promise
import nl.komponents.kovenant.deferred
import org.session.libsession.messaging.MessagingModuleConfiguration
@@ -73,25 +71,6 @@ object MessageSender {
}
}
// New closed groups and configs not requiring additional overhead (already handled by libsession)
@WorkerThread
fun sendConfig(destination: Destination, config: ConfigBase, signingKey: ByteArray): Result<String> {
if (destination !is Destination.ClosedGroup) return Result.failure(Error.InvalidDestination(destination))
val (bytes, _) = config.push()
val testTtl = 30 * 24 * 60 * 60 * 1000L // 30 days
// handle this error thrown case
val response = SnodeAPI.sendMessage(destination, bytes, testTtl, signingKey, config.configNamespace())
Log.d("Send Config", "Response is good")
val hash = response["hash"] as? String ?: return Result.failure(Error("No returned hash of string type"))
return Result.success(hash)
}
// One-on-One Chats & Closed Groups
@Throws(Exception::class)
fun buildWrappedMessageToSnode(destination: Destination, message: Message, isSyncMessage: Boolean): SnodeMessage {

View File

@@ -19,8 +19,6 @@ import nl.komponents.kovenant.functional.bind
import nl.komponents.kovenant.functional.map
import nl.komponents.kovenant.task
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.messages.Destination
import org.session.libsession.messaging.sending_receiving.MessageSender
import org.session.libsession.messaging.utilities.MessageWrapper
import org.session.libsignal.crypto.getRandomElement
import org.session.libsignal.database.LokiAPIDatabaseProtocol
@@ -219,7 +217,7 @@ object SnodeAPI {
}
}
internal fun getSingleTargetSnode(publicKey: String): Promise<Snode, Exception> {
fun getSingleTargetSnode(publicKey: String): Promise<Snode, Exception> {
// SecureRandom() should be cryptographically secure
return getSwarm(publicKey).map { it.shuffled(SecureRandom()).random() }
}
@@ -374,7 +372,7 @@ object SnodeAPI {
return invoke(Snode.Method.Retrieve, snode, parameters, publicKey)
}
fun buildAuthenticatedStoreBatchInfo(publicKey: String, namespace: Int, message: SnodeMessage): SnodeBatchRequestInfo? {
fun buildAuthenticatedStoreBatchInfo(namespace: Int, message: SnodeMessage, signingKey: ByteArray, ed25519PubKey: String? = null): SnodeBatchRequestInfo {
val params = mutableMapOf<String, Any>()
// load the message data params into the sub request
// currently loads:
@@ -388,13 +386,6 @@ object SnodeAPI {
// used for sig generation since it is also the value used in timestamp parameter
val messageTimestamp = message.timestamp
val userEd25519KeyPair = try {
MessagingModuleConfiguration.shared.getUserED25519KeyPair() ?: return null
} catch (e: Exception) {
return null
}
val ed25519PublicKey = userEd25519KeyPair.publicKey.asHexString
val signature = ByteArray(Sign.BYTES)
val verificationData = "store$namespace$messageTimestamp".toByteArray()
try {
@@ -402,13 +393,15 @@ object SnodeAPI {
signature,
verificationData,
verificationData.size.toLong(),
userEd25519KeyPair.secretKey.asBytes
signingKey
)
} catch (e: Exception) {
Log.e("Loki", "Signing data failed with user secret key", e)
}
// timestamp already set
params["pubkey_ed25519"] = ed25519PublicKey
if (ed25519PubKey != null) {
params["pubkey_ed25519"] = ed25519PubKey
}
params["signature"] = Base64.encodeBytes(signature)
return SnodeBatchRequestInfo(
Snode.Method.SendMessage.rawValue,
@@ -417,6 +410,16 @@ object SnodeAPI {
)
}
fun buildAuthenticatedStoreBatchInfo(namespace: Int, message: SnodeMessage): SnodeBatchRequestInfo? {
val userEd25519KeyPair = try {
MessagingModuleConfiguration.shared.getUserED25519KeyPair() ?: return null
} catch (e: Exception) {
return null
}
val ed25519PublicKey = userEd25519KeyPair.publicKey.asHexString
return buildAuthenticatedStoreBatchInfo(namespace, message, userEd25519KeyPair.secretKey.asBytes, ed25519PublicKey)
}
/**
* Message hashes can be shared across multiple namespaces (for a single public key destination)
* @param publicKey the destination's identity public key to delete from (05...)
@@ -634,11 +637,8 @@ object SnodeAPI {
}
@WorkerThread
fun sendMessage(destination: Destination, rawMessage: ByteArray, ttl: Long, signingKey: ByteArray, namespace: Int): RawResponse {
val pubKey = when (destination) {
is Destination.ClosedGroup -> destination.publicKey
else -> throw MessageSender.Error.InvalidDestination(destination)
}
fun sendAuthenticatedMessage(message: SnodeMessage, signingKey: ByteArray, namespace: Int): RawResponse {
val pubKey = message.recipient
return retryIfNeeded(maxRetryCount) {
val timestamp = nowWithOffset
@@ -654,8 +654,7 @@ object SnodeAPI {
val parameters = mapOf(
"pubKey" to pubKey,
"data" to Base64.encodeBytes(rawMessage),
"ttl" to ttl.toString(),
"data" to message.data,
"timestamp" to timestamp.toString(),
"sig_timestamp" to timestamp.toString(),
"signature" to Base64.encodeBytes(verificationData)

View File

@@ -25,6 +25,11 @@ interface ConfigFactoryProtocol {
fun conversationInConfig(publicKey: String?, groupPublicKey: String?, openGroupId: String?, visibleOnly: Boolean): Boolean
fun canPerformChange(variant: String, publicKey: String, changeTimestampMs: Long): Boolean
fun saveGroupConfigs(
groupKeys: GroupKeysConfig,
groupInfo: GroupInfoConfig,
groupMembers: GroupMembersConfig
)
}
interface ConfigFactoryUpdateListener {