feat: add a basic config send sign with group key

This commit is contained in:
0x330a
2023-09-08 17:21:45 +10:00
parent 7c4bf73774
commit 2527ac2e21
5 changed files with 82 additions and 19 deletions

View File

@@ -51,6 +51,7 @@ import org.session.libsession.messaging.messages.visible.VisibleMessage
import org.session.libsession.messaging.open_groups.GroupMember
import org.session.libsession.messaging.open_groups.OpenGroup
import org.session.libsession.messaging.open_groups.OpenGroupApi
import org.session.libsession.messaging.sending_receiving.MessageSender
import org.session.libsession.messaging.sending_receiving.attachments.AttachmentId
import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAttachment
import org.session.libsession.messaging.sending_receiving.data_extraction.DataExtractionNotificationInfoMessage
@@ -881,24 +882,17 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co
DatabaseComponent.get(context).groupDatabase().create(groupId, title, members, avatar, relay, admins, formationTimestamp)
}
override fun createNewGroup(groupName: String, groupDescription: String, members: Set<SessionId>): Long? {
override suspend fun createNewGroup(groupName: String, groupDescription: String, members: Set<SessionId>): Long? {
val userGroups = configFactory.userGroups ?: return null
val ourSessionId = getUserPublicKey() ?: return null
val userKp = MessagingModuleConfiguration.shared.getUserED25519KeyPair() ?: return null
val group = userGroups.createGroup()
val adminKey = group.adminKey
userGroups.set(group)
val groupInfo = configFactory.getOrConstructGroupInfoConfig(group.groupSessionId) ?: return null
val groupMembers = configFactory.getOrConstructGroupMemberConfig(group.groupSessionId) ?: return null
val groupKeys = GroupKeysConfig.newInstance(
userKp.secretKey.asBytes,
Hex.fromStringCondensed(group.groupSessionId.publicKey),
group.adminKey,
info = groupInfo,
members = groupMembers
)
with (groupInfo) {
setName(groupName)
setDescription(groupDescription)
@@ -908,10 +902,25 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co
LibSessionGroupMember(ourSessionId, "admin", admin = true)
)
// Test the sending
val userGroupsUpdate =
val groupKeys = GroupKeysConfig.newInstance(
userKp.secretKey.asBytes,
Hex.fromStringCondensed(group.groupSessionId.publicKey),
group.adminKey,
info = groupInfo,
members = groupMembers
)
TODO()
// Test the sending
try {
MessageSender.sendConfig(Destination.ClosedGroup(group.groupSessionId.hexString()), groupInfo, adminKey)
} catch (e: Exception) {
Log.e("Group Config", e)
Log.e("Group Config", "Deleting group from our group")
// delete the group from user groups
userGroups.erase(group)
}
return 0
}
override fun createInitialConfigGroup(groupPublicKey: String, name: String, members: Map<String, Boolean>, formationTimestamp: Long, encryptionKeyPair: ECKeyPair) {

View File

@@ -203,7 +203,7 @@ class UserGroupsConfig(pointer: Long): ConfigBase(pointer) {
external fun getOrConstructLegacyGroupInfo(sessionId: String): GroupInfo.LegacyGroupInfo
external fun getOrConstructClosedGroup(sessionId: String): GroupInfo.ClosedGroupInfo
external fun set(groupInfo: GroupInfo)
external fun erase(communityInfo: GroupInfo)
external fun erase(groupInfo: GroupInfo)
external fun eraseCommunity(baseCommunityInfo: BaseCommunityInfo): Boolean
external fun eraseCommunity(server: String, room: String): Boolean
external fun eraseLegacyGroup(sessionId: String): Boolean

View File

@@ -155,7 +155,7 @@ interface StorageProtocol {
fun setExpirationTimer(address: String, duration: Int)
// Closed Groups
fun createNewGroup(groupName: String, groupDescription: String, members: Set<SessionId>): Long?
suspend fun createNewGroup(groupName: String, groupDescription: String, members: Set<SessionId>): Long?
fun getMembers(groupPublicKey: String): List<network.loki.messenger.libsession_util.util.GroupMember>
// Groups

View File

@@ -1,5 +1,7 @@
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
@@ -49,6 +51,7 @@ object MessageSender {
object NoUserED25519KeyPair : Error("Couldn't find user ED25519 key pair.")
object SigningFailed : Error("Couldn't sign message.")
object EncryptionFailed : Error("Couldn't encrypt message.")
data class InvalidDestination(val destination: Destination): Error("Can't send this way to $destination")
// Closed groups
object NoThread : Error("Couldn't find a thread associated with the given group public key.")
@@ -70,6 +73,25 @@ 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 {
@@ -213,11 +235,6 @@ object MessageSender {
else -> false
}
/*
if (message is ClosedGroupControlMessage && message.kind is ClosedGroupControlMessage.Kind.New) {
shouldNotify = true
}
*/
if (shouldNotify) {
val notifyPNServerJob = NotifyPNServerJob(snodeMessage)
JobQueue.shared.add(notifyPNServerJob)

View File

@@ -3,6 +3,7 @@
package org.session.libsession.snode
import android.os.Build
import androidx.annotation.WorkerThread
import com.goterl.lazysodium.LazySodiumAndroid
import com.goterl.lazysodium.SodiumAndroid
import com.goterl.lazysodium.exceptions.SodiumException
@@ -18,6 +19,8 @@ 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
@@ -630,6 +633,40 @@ 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)
}
return retryIfNeeded(maxRetryCount) {
val timestamp = nowWithOffset
val signature = ByteArray(Sign.BYTES)
// assume namespace here is non-zero, as zero namespace doesn't require auth
val verificationData = "store$namespace$timestamp".toByteArray()
try {
sodium.cryptoSignDetached(signature, verificationData, verificationData.size.toLong(), signingKey)
} catch (exception: Exception) {
return@retryIfNeeded Promise.ofFail(Error.SigningFailed)
}
val parameters = mapOf(
"pubKey" to pubKey,
"data" to Base64.encodeBytes(rawMessage),
"ttl" to ttl.toString(),
"timestamp" to timestamp.toString(),
"sig_timestamp" to timestamp.toString(),
"signature" to Base64.encodeBytes(verificationData)
)
getSingleTargetSnode(pubKey).bind { targetSnode ->
invoke(Snode.Method.SendMessage, targetSnode, parameters, pubKey)
}
}.get()
}
fun sendMessage(message: SnodeMessage, requiresAuth: Boolean = false, namespace: Int = 0): RawResponsePromise {
val destination = message.recipient
return retryIfNeeded(maxRetryCount) {