feat: adding basic invite for new groups handling and immediate response, need to add handling for response and actually sending the invites via UI possibly
This commit is contained in:
parent
352246842f
commit
2448af0b73
|
@ -35,6 +35,7 @@ import org.session.libsession.messaging.jobs.RetrieveProfileAvatarJob
|
||||||
import org.session.libsession.messaging.messages.Destination
|
import org.session.libsession.messaging.messages.Destination
|
||||||
import org.session.libsession.messaging.messages.Message
|
import org.session.libsession.messaging.messages.Message
|
||||||
import org.session.libsession.messaging.messages.control.ConfigurationMessage
|
import org.session.libsession.messaging.messages.control.ConfigurationMessage
|
||||||
|
import org.session.libsession.messaging.messages.control.GroupUpdated
|
||||||
import org.session.libsession.messaging.messages.control.MessageRequestResponse
|
import org.session.libsession.messaging.messages.control.MessageRequestResponse
|
||||||
import org.session.libsession.messaging.messages.signal.IncomingEncryptedMessage
|
import org.session.libsession.messaging.messages.signal.IncomingEncryptedMessage
|
||||||
import org.session.libsession.messaging.messages.signal.IncomingGroupMessage
|
import org.session.libsession.messaging.messages.signal.IncomingGroupMessage
|
||||||
|
@ -50,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.GroupMember
|
||||||
import org.session.libsession.messaging.open_groups.OpenGroup
|
import org.session.libsession.messaging.open_groups.OpenGroup
|
||||||
import org.session.libsession.messaging.open_groups.OpenGroupApi
|
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.AttachmentId
|
||||||
import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAttachment
|
import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAttachment
|
||||||
import org.session.libsession.messaging.sending_receiving.data_extraction.DataExtractionNotificationInfoMessage
|
import org.session.libsession.messaging.sending_receiving.data_extraction.DataExtractionNotificationInfoMessage
|
||||||
|
@ -76,6 +78,8 @@ import org.session.libsignal.crypto.ecc.DjbECPublicKey
|
||||||
import org.session.libsignal.crypto.ecc.ECKeyPair
|
import org.session.libsignal.crypto.ecc.ECKeyPair
|
||||||
import org.session.libsignal.messages.SignalServiceAttachmentPointer
|
import org.session.libsignal.messages.SignalServiceAttachmentPointer
|
||||||
import org.session.libsignal.messages.SignalServiceGroup
|
import org.session.libsignal.messages.SignalServiceGroup
|
||||||
|
import org.session.libsignal.protos.SignalServiceProtos.DataMessage
|
||||||
|
import org.session.libsignal.protos.SignalServiceProtos.DataMessage.GroupUpdateInviteResponseMessage
|
||||||
import org.session.libsignal.utilities.Base64
|
import org.session.libsignal.utilities.Base64
|
||||||
import org.session.libsignal.utilities.Hex
|
import org.session.libsignal.utilities.Hex
|
||||||
import org.session.libsignal.utilities.IdPrefix
|
import org.session.libsignal.utilities.IdPrefix
|
||||||
|
@ -1199,6 +1203,28 @@ open class Storage(
|
||||||
override fun getMembers(groupPublicKey: String): List<LibSessionGroupMember> =
|
override fun getMembers(groupPublicKey: String): List<LibSessionGroupMember> =
|
||||||
configFactory.getGroupMemberConfig(SessionId.from(groupPublicKey))?.use { it.all() }?.toList() ?: emptyList()
|
configFactory.getGroupMemberConfig(SessionId.from(groupPublicKey))?.use { it.all() }?.toList() ?: emptyList()
|
||||||
|
|
||||||
|
override fun acceptClosedGroupInvite(groupId: SessionId, name: String, authData: ByteArray, invitingAdmin: SessionId) {
|
||||||
|
val recipient = Recipient.from(context, Address.fromSerialized(groupId.hexString()), false)
|
||||||
|
val profileManager = SSKEnvironment.shared.profileManager
|
||||||
|
val groups = configFactory.userGroups ?: return
|
||||||
|
val closedGroupInfo = GroupInfo.ClosedGroupInfo(
|
||||||
|
groupId, byteArrayOf(), authData, PRIORITY_VISIBLE
|
||||||
|
)
|
||||||
|
groups.set(closedGroupInfo)
|
||||||
|
profileManager.setName(context, recipient, name)
|
||||||
|
setRecipientApprovedMe(recipient, true)
|
||||||
|
setRecipientApproved(recipient, true)
|
||||||
|
getOrCreateThreadIdFor(recipient.address)
|
||||||
|
pollerFactory.pollerFor(groupId)?.start()
|
||||||
|
val invitingAdminAddress = Address.fromSerialized(invitingAdmin.hexString())
|
||||||
|
val inviteResponse = GroupUpdateInviteResponseMessage.newBuilder()
|
||||||
|
.setIsApproved(true)
|
||||||
|
val responseData = DataMessage.GroupUpdateMessage.newBuilder()
|
||||||
|
.setInviteResponse(inviteResponse)
|
||||||
|
val responseMessage = GroupUpdated(responseData.build())
|
||||||
|
MessageSender.send(responseMessage, invitingAdminAddress)
|
||||||
|
}
|
||||||
|
|
||||||
override fun setServerCapabilities(server: String, capabilities: List<String>) {
|
override fun setServerCapabilities(server: String, capabilities: List<String>) {
|
||||||
return DatabaseComponent.get(context).lokiAPIDatabase().setServerCapabilities(server, capabilities)
|
return DatabaseComponent.get(context).lokiAPIDatabase().setServerCapabilities(server, capabilities)
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,8 +13,9 @@ class PollerFactory(private val scope: CoroutineScope,
|
||||||
private val pollers = ConcurrentHashMap<SessionId, ClosedGroupPoller>()
|
private val pollers = ConcurrentHashMap<SessionId, ClosedGroupPoller>()
|
||||||
|
|
||||||
fun pollerFor(sessionId: SessionId): ClosedGroupPoller? {
|
fun pollerFor(sessionId: SessionId): ClosedGroupPoller? {
|
||||||
val activeGroup = configFactory.userGroups?.getClosedGroup(sessionId.hexString()) ?: return null
|
// Check if the group is currently in our config, don't start if it isn't
|
||||||
// TODO: add check for active group being invited / approved etc
|
configFactory.userGroups?.getClosedGroup(sessionId.hexString()) ?: return null
|
||||||
|
|
||||||
return pollers.getOrPut(sessionId) {
|
return pollers.getOrPut(sessionId) {
|
||||||
ClosedGroupPoller(scope + SupervisorJob(), sessionId, configFactory)
|
ClosedGroupPoller(scope + SupervisorJob(), sessionId, configFactory)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit cce0db485f5749a2891ce56170342c5b0e82272c
|
Subproject commit e4b0358a50a65796ac5e2da4938505bc8ebf0313
|
|
@ -229,4 +229,18 @@ Java_network_loki_messenger_libsession_1util_GroupKeysConfig_currentHashes(JNIEn
|
||||||
env->CallObjectMethod(our_list, push, hash_bytes);
|
env->CallObjectMethod(our_list, push, hash_bytes);
|
||||||
}
|
}
|
||||||
return our_list;
|
return our_list;
|
||||||
|
}
|
||||||
|
extern "C"
|
||||||
|
JNIEXPORT jbyteArray JNICALL
|
||||||
|
Java_network_loki_messenger_libsession_1util_GroupKeysConfig_makeSubAccount(JNIEnv *env,
|
||||||
|
jobject thiz,
|
||||||
|
jobject session_id,
|
||||||
|
jboolean can_write,
|
||||||
|
jboolean can_delete) {
|
||||||
|
std::lock_guard lock{util::util_mutex_};
|
||||||
|
auto ptr = ptrToKeys(env, thiz);
|
||||||
|
auto deserialized_id = util::deserialize_session_id(env, session_id);
|
||||||
|
auto new_subaccount_key = ptr->swarm_make_subaccount(deserialized_id.data(), can_write, can_delete);
|
||||||
|
auto jbytes = util::bytes_from_ustring(env, new_subaccount_key);
|
||||||
|
return jbytes;
|
||||||
}
|
}
|
|
@ -332,4 +332,6 @@ class GroupKeysConfig(pointer: Long): ConfigSig(pointer) {
|
||||||
|
|
||||||
external fun keys(): Stack<ByteArray>
|
external fun keys(): Stack<ByteArray>
|
||||||
|
|
||||||
|
external fun makeSubAccount(sessionId: SessionId, canWrite: Boolean = true, canDelete: Boolean = false): ByteArray
|
||||||
|
|
||||||
}
|
}
|
|
@ -35,6 +35,7 @@ import org.session.libsignal.messages.SignalServiceGroup
|
||||||
import org.session.libsignal.utilities.SessionId
|
import org.session.libsignal.utilities.SessionId
|
||||||
import org.session.libsignal.utilities.guava.Optional
|
import org.session.libsignal.utilities.guava.Optional
|
||||||
import network.loki.messenger.libsession_util.util.Contact as LibSessionContact
|
import network.loki.messenger.libsession_util.util.Contact as LibSessionContact
|
||||||
|
import network.loki.messenger.libsession_util.util.GroupMember as LibSessionGroupMember
|
||||||
|
|
||||||
interface StorageProtocol {
|
interface StorageProtocol {
|
||||||
|
|
||||||
|
@ -157,7 +158,8 @@ interface StorageProtocol {
|
||||||
|
|
||||||
// Closed Groups
|
// Closed Groups
|
||||||
fun createNewGroup(groupName: String, groupDescription: String, members: Set<SessionId>): Optional<Recipient>
|
fun createNewGroup(groupName: String, groupDescription: String, members: Set<SessionId>): Optional<Recipient>
|
||||||
fun getMembers(groupPublicKey: String): List<network.loki.messenger.libsession_util.util.GroupMember>
|
fun getMembers(groupPublicKey: String): List<LibSessionGroupMember>
|
||||||
|
fun acceptClosedGroupInvite(groupId: SessionId, name: String, authData: ByteArray, invitingAdmin: SessionId)
|
||||||
|
|
||||||
// Groups
|
// Groups
|
||||||
fun getAllGroups(includeInactive: Boolean): List<GroupRecord>
|
fun getAllGroups(includeInactive: Boolean): List<GroupRecord>
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
package org.session.libsession.messaging.messages.control
|
||||||
|
|
||||||
|
import org.session.libsignal.protos.SignalServiceProtos.Content
|
||||||
|
import org.session.libsignal.protos.SignalServiceProtos.DataMessage
|
||||||
|
import org.session.libsignal.protos.SignalServiceProtos.DataMessage.GroupUpdateMessage
|
||||||
|
|
||||||
|
class GroupUpdated(val inner: GroupUpdateMessage): ControlMessage() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun fromProto(message: GroupUpdateMessage): GroupUpdated = GroupUpdated(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toProto(): Content {
|
||||||
|
val dataMessage = DataMessage.newBuilder()
|
||||||
|
.setGroupUpdateMessage(inner)
|
||||||
|
.build()
|
||||||
|
return Content.newBuilder()
|
||||||
|
.setDataMessage(dataMessage)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
}
|
|
@ -153,7 +153,8 @@ object MessageReceiver {
|
||||||
MessageRequestResponse.fromProto(proto) ?:
|
MessageRequestResponse.fromProto(proto) ?:
|
||||||
CallMessage.fromProto(proto) ?:
|
CallMessage.fromProto(proto) ?:
|
||||||
SharedConfigurationMessage.fromProto(proto) ?:
|
SharedConfigurationMessage.fromProto(proto) ?:
|
||||||
VisibleMessage.fromProto(proto) ?: run {
|
VisibleMessage.fromProto(proto) ?:
|
||||||
|
ClosedGroupMessage.fromProto(proto) ?: run {
|
||||||
throw Error.UnknownMessage
|
throw Error.UnknownMessage
|
||||||
}
|
}
|
||||||
val isUserBlindedSender = sender == openGroupPublicKey?.let { SodiumUtilities.blindedKeyPair(it, MessagingModuleConfiguration.shared.getUserED25519KeyPair()!!) }?.let { SessionId(IdPrefix.BLINDED, it.publicKey.asBytes).hexString() }
|
val isUserBlindedSender = sender == openGroupPublicKey?.let { SodiumUtilities.blindedKeyPair(it, MessagingModuleConfiguration.shared.getUserED25519KeyPair()!!) }?.let { SessionId(IdPrefix.BLINDED, it.publicKey.asBytes).hexString() }
|
||||||
|
|
|
@ -12,6 +12,7 @@ import org.session.libsession.messaging.messages.control.CallMessage
|
||||||
import org.session.libsession.messaging.messages.control.ClosedGroupControlMessage
|
import org.session.libsession.messaging.messages.control.ClosedGroupControlMessage
|
||||||
import org.session.libsession.messaging.messages.control.ConfigurationMessage
|
import org.session.libsession.messaging.messages.control.ConfigurationMessage
|
||||||
import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate
|
import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate
|
||||||
|
import org.session.libsession.messaging.messages.control.GroupUpdated
|
||||||
import org.session.libsession.messaging.messages.control.MessageRequestResponse
|
import org.session.libsession.messaging.messages.control.MessageRequestResponse
|
||||||
import org.session.libsession.messaging.messages.control.SharedConfigurationMessage
|
import org.session.libsession.messaging.messages.control.SharedConfigurationMessage
|
||||||
import org.session.libsession.messaging.messages.control.UnsendRequest
|
import org.session.libsession.messaging.messages.control.UnsendRequest
|
||||||
|
@ -122,9 +123,15 @@ object MessageSender {
|
||||||
message.profile = storage.getUserProfile()
|
message.profile = storage.getUserProfile()
|
||||||
}
|
}
|
||||||
// Convert it to protobuf
|
// Convert it to protobuf
|
||||||
val proto = message.toProto() ?: throw Error.ProtoConversionFailed
|
val proto = message.toProto()?.toBuilder() ?: throw Error.ProtoConversionFailed
|
||||||
|
if (message is GroupUpdated) {
|
||||||
|
// Add all cases where we have to attach profile
|
||||||
|
if (message.inner.hasInviteResponse()) {
|
||||||
|
proto.mergeDataMessage(storage.getUserProfile().toProto())
|
||||||
|
}
|
||||||
|
}
|
||||||
// Serialize the protobuf
|
// Serialize the protobuf
|
||||||
val plaintext = PushTransportDetails.getPaddedMessageBody(proto.toByteArray())
|
val plaintext = PushTransportDetails.getPaddedMessageBody(proto.build().toByteArray())
|
||||||
|
|
||||||
// Envelope information
|
// Envelope information
|
||||||
val kind: SignalServiceProtos.Envelope.Type
|
val kind: SignalServiceProtos.Envelope.Type
|
||||||
|
@ -157,7 +164,7 @@ object MessageSender {
|
||||||
}
|
}
|
||||||
is Destination.ClosedGroup -> {
|
is Destination.ClosedGroup -> {
|
||||||
val groupKeys = configFactory.getGroupKeysConfig(SessionId.from(destination.publicKey)) ?: throw Error.NoKeyPair
|
val groupKeys = configFactory.getGroupKeysConfig(SessionId.from(destination.publicKey)) ?: throw Error.NoKeyPair
|
||||||
val envelope = MessageWrapper.createEnvelope(kind, message.sentTimestamp!!, senderPublicKey, proto.toByteArray())
|
val envelope = MessageWrapper.createEnvelope(kind, message.sentTimestamp!!, senderPublicKey, proto.build().toByteArray())
|
||||||
groupKeys.use { keys ->
|
groupKeys.use { keys ->
|
||||||
keys.encrypt(envelope.toByteArray())
|
keys.encrypt(envelope.toByteArray())
|
||||||
}
|
}
|
||||||
|
@ -189,6 +196,7 @@ object MessageSender {
|
||||||
val storage = MessagingModuleConfiguration.shared.storage
|
val storage = MessagingModuleConfiguration.shared.storage
|
||||||
val configFactory = MessagingModuleConfiguration.shared.configFactory
|
val configFactory = MessagingModuleConfiguration.shared.configFactory
|
||||||
val userPublicKey = storage.getUserPublicKey()
|
val userPublicKey = storage.getUserPublicKey()
|
||||||
|
val ourProfile = storage.getUserProfile()
|
||||||
|
|
||||||
// recipient will be set later, so initialize it as a function here
|
// recipient will be set later, so initialize it as a function here
|
||||||
val isSelfSend = { message.recipient == userPublicKey }
|
val isSelfSend = { message.recipient == userPublicKey }
|
||||||
|
|
|
@ -13,6 +13,7 @@ import org.session.libsession.messaging.messages.control.ClosedGroupControlMessa
|
||||||
import org.session.libsession.messaging.messages.control.ConfigurationMessage
|
import org.session.libsession.messaging.messages.control.ConfigurationMessage
|
||||||
import org.session.libsession.messaging.messages.control.DataExtractionNotification
|
import org.session.libsession.messaging.messages.control.DataExtractionNotification
|
||||||
import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate
|
import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate
|
||||||
|
import org.session.libsession.messaging.messages.control.GroupUpdated
|
||||||
import org.session.libsession.messaging.messages.control.MessageRequestResponse
|
import org.session.libsession.messaging.messages.control.MessageRequestResponse
|
||||||
import org.session.libsession.messaging.messages.control.ReadReceipt
|
import org.session.libsession.messaging.messages.control.ReadReceipt
|
||||||
import org.session.libsession.messaging.messages.control.TypingIndicator
|
import org.session.libsession.messaging.messages.control.TypingIndicator
|
||||||
|
@ -51,6 +52,7 @@ import org.session.libsignal.utilities.guava.Optional
|
||||||
import org.session.libsignal.utilities.removingIdPrefixIfNeeded
|
import org.session.libsignal.utilities.removingIdPrefixIfNeeded
|
||||||
import org.session.libsignal.utilities.toHexString
|
import org.session.libsignal.utilities.toHexString
|
||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
|
import java.security.SignatureException
|
||||||
import java.util.LinkedList
|
import java.util.LinkedList
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
|
@ -68,6 +70,7 @@ fun MessageReceiver.handle(message: Message, proto: SignalServiceProtos.Content,
|
||||||
is ReadReceipt -> handleReadReceipt(message)
|
is ReadReceipt -> handleReadReceipt(message)
|
||||||
is TypingIndicator -> handleTypingIndicator(message)
|
is TypingIndicator -> handleTypingIndicator(message)
|
||||||
is ClosedGroupControlMessage -> handleClosedGroupControlMessage(message)
|
is ClosedGroupControlMessage -> handleClosedGroupControlMessage(message)
|
||||||
|
is GroupUpdated -> handleNewLibSessionClosedGroupMessage(message)
|
||||||
is ExpirationTimerUpdate -> handleExpirationTimerUpdate(message)
|
is ExpirationTimerUpdate -> handleExpirationTimerUpdate(message)
|
||||||
is DataExtractionNotification -> handleDataExtractionNotification(message)
|
is DataExtractionNotification -> handleDataExtractionNotification(message)
|
||||||
is ConfigurationMessage -> handleConfigurationMessage(message)
|
is ConfigurationMessage -> handleConfigurationMessage(message)
|
||||||
|
@ -516,6 +519,48 @@ private fun ClosedGroupControlMessage.getPublicKey(): String = kind!!.let { when
|
||||||
is ClosedGroupControlMessage.Kind.NameChange -> groupPublicKey!!
|
is ClosedGroupControlMessage.Kind.NameChange -> groupPublicKey!!
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
private fun MessageReceiver.handleGroupUpdated(message: GroupUpdated) {
|
||||||
|
when {
|
||||||
|
message.inner.hasInviteMessage() -> handleNewLibSessionClosedGroupMessage(message)
|
||||||
|
message.inner.hasInviteResponse() -> handleInviteResponse(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun MessageReceiver.handleInviteResponse(message: GroupUpdated) {
|
||||||
|
val sender = message.sender!!
|
||||||
|
// val profile = message // maybe we do need data to be the inner so we can access profile
|
||||||
|
val storage = MessagingModuleConfiguration.shared.storage
|
||||||
|
val approved = message.inner.inviteResponse.isApproved
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun MessageReceiver.handleNewLibSessionClosedGroupMessage(message: GroupUpdated) {
|
||||||
|
val storage = MessagingModuleConfiguration.shared.storage
|
||||||
|
val ourUserId = storage.getUserPublicKey()!!
|
||||||
|
val invite = message.inner.inviteMessage
|
||||||
|
val groupId = SessionId.from(invite.groupSessionId)
|
||||||
|
verifyAdminSignature(groupId, invite.adminSignature.toByteArray(), "INVITE"+ourUserId+message.sentTimestamp!!)
|
||||||
|
val adminId = SessionId.from(message.sender!!)
|
||||||
|
// TODO: add the pending invite logic after testing initial group signing / message adding / encryption works for members as well
|
||||||
|
// add the group
|
||||||
|
storage.acceptClosedGroupInvite(groupId, invite.name, invite.memberAuthData.toByteArray(), adminId)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does nothing on successful signature verification, throws otherwise.
|
||||||
|
* Assumes the signer is using the ed25519 group key signing key
|
||||||
|
* @param groupSessionId the SessionId of the group to check the signature against
|
||||||
|
* @param signatureData the byte array supplied to us through a protobuf message from the admin
|
||||||
|
* @param messageToValidate the expected values used for this signature generation, often something like `INVITE||{inviteeSessionId}||{timestamp}`
|
||||||
|
* @throws SignatureException if signature cannot be verified with given parameters
|
||||||
|
*/
|
||||||
|
private fun verifyAdminSignature(groupSessionId: SessionId, signatureData: ByteArray, messageToValidate: String) {
|
||||||
|
val groupPubKey = groupSessionId.pubKeyBytes
|
||||||
|
if (!SodiumUtilities.verifySignature(signatureData, groupPubKey, messageToValidate.encodeToByteArray())) {
|
||||||
|
throw SignatureException("Verification failed for signature data")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun MessageReceiver.handleNewClosedGroup(message: ClosedGroupControlMessage) {
|
private fun MessageReceiver.handleNewClosedGroup(message: ClosedGroupControlMessage) {
|
||||||
val kind = message.kind!! as? ClosedGroupControlMessage.Kind.New ?: return
|
val kind = message.kind!! as? ClosedGroupControlMessage.Kind.New ?: return
|
||||||
val recipient = Recipient.from(MessagingModuleConfiguration.shared.context, Address.fromSerialized(message.sender!!), false)
|
val recipient = Recipient.from(MessagingModuleConfiguration.shared.context, Address.fromSerialized(message.sender!!), false)
|
||||||
|
|
|
@ -230,4 +230,11 @@ object SodiumUtilities {
|
||||||
} else null
|
} else null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true only if the signature verified successfully
|
||||||
|
*/
|
||||||
|
fun verifySignature(signature: ByteArray, publicKey: ByteArray, messageToVerify: ByteArray): Boolean {
|
||||||
|
return sodium.cryptoSignVerifyDetached(signature, messageToVerify, messageToVerify.size, publicKey)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,13 +120,6 @@ message DataMessage {
|
||||||
required string name = 3;
|
required string name = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message GroupMessage {
|
|
||||||
optional GroupDeleteMessage deleteMessage = 31;
|
|
||||||
optional GroupMemberLeftMessage memberLeftMessage = 32;
|
|
||||||
optional GroupInviteMessage inviteMessage = 33;
|
|
||||||
optional GroupPromoteMessage promoteMessage = 34;
|
|
||||||
}
|
|
||||||
|
|
||||||
// New closed group update messages
|
// New closed group update messages
|
||||||
message GroupUpdateMessage {
|
message GroupUpdateMessage {
|
||||||
optional GroupUpdateInviteMessage inviteMessage = 1;
|
optional GroupUpdateInviteMessage inviteMessage = 1;
|
||||||
|
@ -274,7 +267,7 @@ message DataMessage {
|
||||||
optional ClosedGroupControlMessage closedGroupControlMessage = 104;
|
optional ClosedGroupControlMessage closedGroupControlMessage = 104;
|
||||||
optional string syncTarget = 105;
|
optional string syncTarget = 105;
|
||||||
optional bool blocksCommunityMessageRequests = 106;
|
optional bool blocksCommunityMessageRequests = 106;
|
||||||
optional GroupMessage groupMessage = 120;
|
optional GroupUpdateMessage groupUpdateMessage = 120;
|
||||||
}
|
}
|
||||||
|
|
||||||
message GroupDeleteMessage {
|
message GroupDeleteMessage {
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue