mirror of
https://github.com/oxen-io/session-android.git
synced 2025-12-30 20:06:13 +00:00
feat: add a basic config send sign with group key
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user