mirror of
https://github.com/oxen-io/session-android.git
synced 2025-02-19 19:18:27 +00:00
sending & receiving $ make things compile
This commit is contained in:
parent
072aa0e7c6
commit
c0dff9cdea
@ -5,11 +5,10 @@ import nl.komponents.kovenant.Promise
|
||||
import nl.komponents.kovenant.deferred
|
||||
import nl.komponents.kovenant.functional.map
|
||||
import nl.komponents.kovenant.then
|
||||
import org.session.libsession.messaging.Configuration
|
||||
import org.session.libsession.messaging.MessagingConfiguration
|
||||
|
||||
import org.session.libsession.messaging.utilities.DotNetAPI
|
||||
import org.session.libsession.messaging.fileserver.FileServerAPI
|
||||
import org.session.libsession.snode.SnodeAPI
|
||||
|
||||
import org.session.libsignal.libsignal.logging.Log
|
||||
import org.session.libsignal.service.internal.util.Base64
|
||||
@ -56,7 +55,7 @@ object OpenGroupAPI: DotNetAPI() {
|
||||
// region Public API
|
||||
public fun getMessages(channel: Long, server: String): Promise<List<OpenGroupMessage>, Exception> {
|
||||
Log.d("Loki", "Getting messages for open group with ID: $channel on server: $server.")
|
||||
val storage = Configuration.shared.storage
|
||||
val storage = MessagingConfiguration.shared.storage
|
||||
val parameters = mutableMapOf<String, Any>( "include_annotations" to 1 )
|
||||
val lastMessageServerID = storage.getLastMessageServerID(channel, server)
|
||||
if (lastMessageServerID != null) {
|
||||
@ -161,7 +160,7 @@ object OpenGroupAPI: DotNetAPI() {
|
||||
|
||||
public fun getDeletedMessageServerIDs(channel: Long, server: String): Promise<List<Long>, Exception> {
|
||||
Log.d("Loki", "Getting deleted messages for open group with ID: $channel on server: $server.")
|
||||
val storage = Configuration.shared.storage
|
||||
val storage = MessagingConfiguration.shared.storage
|
||||
val parameters = mutableMapOf<String, Any>()
|
||||
val lastDeletionServerID = storage.getLastDeletionServerID(channel, server)
|
||||
if (lastDeletionServerID != null) {
|
||||
@ -193,7 +192,7 @@ object OpenGroupAPI: DotNetAPI() {
|
||||
|
||||
public fun sendMessage(message: OpenGroupMessage, channel: Long, server: String): Promise<OpenGroupMessage, Exception> {
|
||||
val deferred = deferred<OpenGroupMessage, Exception>()
|
||||
val storage = Configuration.shared.storage
|
||||
val storage = MessagingConfiguration.shared.storage
|
||||
val userKeyPair = storage.getUserKeyPair() ?: throw Error.Generic
|
||||
val userDisplayName = storage.getUserDisplayName() ?: throw Error.Generic
|
||||
Thread {
|
||||
@ -287,7 +286,7 @@ object OpenGroupAPI: DotNetAPI() {
|
||||
val memberCount = countInfo["subscribers"] as? Int ?: (countInfo["subscribers"] as? Long)?.toInt() ?: (countInfo["subscribers"] as String).toInt()
|
||||
val profilePictureURL = info["avatar"] as String
|
||||
val publicChatInfo = OpenGroupInfo(displayName, profilePictureURL, memberCount)
|
||||
Configuration.shared.storage.setUserCount(channel, server, memberCount)
|
||||
MessagingConfiguration.shared.storage.setUserCount(channel, server, memberCount)
|
||||
publicChatInfo
|
||||
} catch (exception: Exception) {
|
||||
Log.d("Loki", "Couldn't parse info for open group with ID: $channel on server: $server.")
|
||||
@ -298,7 +297,7 @@ object OpenGroupAPI: DotNetAPI() {
|
||||
}
|
||||
|
||||
public fun updateProfileIfNeeded(channel: Long, server: String, groupID: String, info: OpenGroupInfo, isForcedUpdate: Boolean) {
|
||||
val storage = Configuration.shared.storage
|
||||
val storage = MessagingConfiguration.shared.storage
|
||||
storage.setUserCount(channel, server, info.memberCount)
|
||||
storage.updateTitle(groupID, info.displayName)
|
||||
// Download and update profile picture if needed
|
||||
|
@ -1,6 +1,6 @@
|
||||
package org.session.libsession.messaging.sending_receiving
|
||||
|
||||
import org.session.libsession.messaging.Configuration
|
||||
import org.session.libsession.messaging.MessagingConfiguration
|
||||
import org.session.libsession.messaging.sending_receiving.MessageReceiver.Error
|
||||
import org.session.libsession.utilities.AESGCM
|
||||
|
||||
@ -21,26 +21,26 @@ import javax.crypto.spec.SecretKeySpec
|
||||
object MessageReceiverDecryption {
|
||||
|
||||
internal fun decryptWithSignalProtocol(envelope: SignalServiceProtos.Envelope): Pair<ByteArray, String> {
|
||||
val storage = Configuration.shared.signalStorage
|
||||
val sskDatabase = Configuration.shared.sskDatabase
|
||||
val sessionResetImp = Configuration.shared.sessionResetImp
|
||||
val certificateValidator = Configuration.shared.certificateValidator
|
||||
val storage = MessagingConfiguration.shared.signalStorage
|
||||
val sskDatabase = MessagingConfiguration.shared.sskDatabase
|
||||
val sessionResetImp = MessagingConfiguration.shared.sessionResetImp
|
||||
val certificateValidator = MessagingConfiguration.shared.certificateValidator
|
||||
val data = envelope.content
|
||||
if (data.count() == 0) { throw Error.NoData }
|
||||
val userPublicKey = Configuration.shared.storage.getUserPublicKey() ?: throw Error.NoUserPublicKey
|
||||
val userPublicKey = MessagingConfiguration.shared.storage.getUserPublicKey() ?: throw Error.NoUserPublicKey
|
||||
val localAddress = SignalServiceAddress(userPublicKey)
|
||||
val cipher = SignalServiceCipher(localAddress, storage, sskDatabase, sessionResetImp, certificateValidator)
|
||||
val result = cipher.decrypt(SignalServiceEnvelope(envelope))
|
||||
return Pair(result, result.sender)
|
||||
return Pair(ByteArray(1), result.sender) // TODO: Return real plaintext
|
||||
}
|
||||
|
||||
internal fun decryptWithSharedSenderKeys(envelope: SignalServiceProtos.Envelope): Pair<ByteArray, String> {
|
||||
// 1. ) Check preconditions
|
||||
val groupPublicKey = envelope.source
|
||||
if (!Configuration.shared.storage.isClosedGroup(groupPublicKey)) { throw Error.InvalidGroupPublicKey }
|
||||
if (!MessagingConfiguration.shared.storage.isClosedGroup(groupPublicKey)) { throw Error.InvalidGroupPublicKey }
|
||||
val data = envelope.content
|
||||
if (data.count() == 0) { throw Error.NoData }
|
||||
val groupPrivateKey = Configuration.shared.storage.getClosedGroupPrivateKey(groupPublicKey) ?: throw Error.NoGroupPrivateKey
|
||||
val groupPrivateKey = MessagingConfiguration.shared.storage.getClosedGroupPrivateKey(groupPublicKey) ?: throw Error.NoGroupPrivateKey
|
||||
// 2. ) Parse the wrapper
|
||||
val wrapper = SignalServiceProtos.ClosedGroupCiphertextMessageWrapper.parseFrom(data)
|
||||
val ivAndCiphertext = wrapper.ciphertext.toByteArray()
|
||||
@ -54,7 +54,7 @@ object MessageReceiverDecryption {
|
||||
// 4. ) Parse the closed group ciphertext message
|
||||
val closedGroupCiphertextMessage = ClosedGroupCiphertextMessage.from(closedGroupCiphertextMessageAsData) ?: throw Error.ParsingFailed
|
||||
val senderPublicKey = closedGroupCiphertextMessage.senderPublicKey.toHexString()
|
||||
if (senderPublicKey == Configuration.shared.storage.getUserPublicKey()) { throw Error.SelfSend }
|
||||
if (senderPublicKey == MessagingConfiguration.shared.storage.getUserPublicKey()) { throw Error.SelfSend }
|
||||
// 5. ) Use the info inside the closed group ciphertext message to decrypt the actual message content
|
||||
val plaintext = SharedSenderKeysImplementation.shared.decrypt(closedGroupCiphertextMessage.ivAndCiphertext, groupPublicKey, senderPublicKey, closedGroupCiphertextMessage.keyIndex)
|
||||
// 6. ) Return
|
||||
|
@ -1,6 +1,6 @@
|
||||
package org.session.libsession.messaging.sending_receiving
|
||||
|
||||
import org.session.libsession.messaging.Configuration
|
||||
import org.session.libsession.messaging.MessagingConfiguration
|
||||
import org.session.libsession.messaging.messages.Destination
|
||||
import org.session.libsession.messaging.messages.Message
|
||||
import org.session.libsession.messaging.messages.control.ClosedGroupUpdate
|
||||
@ -9,9 +9,9 @@ import org.session.libsession.messaging.messages.control.ReadReceipt
|
||||
import org.session.libsession.messaging.messages.control.TypingIndicator
|
||||
import org.session.libsession.messaging.messages.visible.VisibleMessage
|
||||
import org.session.libsession.messaging.sending_receiving.notifications.PushNotificationAPI
|
||||
import org.session.libsession.utilities.LKGroupUtilities
|
||||
import org.session.libsession.messaging.threads.Address
|
||||
import org.session.libsession.utilities.GroupUtil
|
||||
import org.session.libsignal.libsignal.util.Hex
|
||||
import org.session.libsignal.service.api.messages.SignalServiceGroup
|
||||
|
||||
import org.session.libsignal.service.internal.push.SignalServiceProtos
|
||||
import org.session.libsignal.service.loki.protocol.closedgroups.ClosedGroupRatchet
|
||||
@ -37,7 +37,7 @@ fun MessageReceiver.handle(message: Message, proto: SignalServiceProtos.Content,
|
||||
}
|
||||
|
||||
private fun MessageReceiver.handleReadReceipt(message: ReadReceipt) {
|
||||
|
||||
// TODO
|
||||
}
|
||||
|
||||
private fun MessageReceiver.handleTypingIndicator(message: TypingIndicator) {
|
||||
@ -89,8 +89,8 @@ private fun MessageReceiver.handleClosedGroupUpdate(message: ClosedGroupUpdate)
|
||||
}
|
||||
|
||||
private fun MessageReceiver.handleNewGroup(message: ClosedGroupUpdate) {
|
||||
val storage = Configuration.shared.storage
|
||||
val sskDatabase = Configuration.shared.sskDatabase
|
||||
val storage = MessagingConfiguration.shared.storage
|
||||
val sskDatabase = MessagingConfiguration.shared.sskDatabase
|
||||
val kind = message.kind!! as ClosedGroupUpdate.Kind.New
|
||||
val groupPublicKey = kind.groupPublicKey.toHexString()
|
||||
val name = kind.name
|
||||
@ -122,27 +122,24 @@ private fun MessageReceiver.handleNewGroup(message: ClosedGroupUpdate) {
|
||||
MessageSender.requestSenderKey(groupPublicKey, publicKey)
|
||||
}
|
||||
// Create the group
|
||||
val groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey)
|
||||
val groupDB = DatabaseFactory.getGroupDatabase(context)
|
||||
if (groupDB.getGroup(groupID).orNull() != null) {
|
||||
val groupID = GroupUtil.getEncodedClosedGroupID(groupPublicKey)
|
||||
if (storage.getGroup(groupID) != null) {
|
||||
// Update the group
|
||||
groupDB.updateTitle(groupID, name)
|
||||
groupDB.updateMembers(groupID, members.map { Address.fromSerialized(it) })
|
||||
storage.updateTitle(groupID, name)
|
||||
storage.updateMembers(groupID, members.map { Address.fromSerialized(it) })
|
||||
} else {
|
||||
groupDB.create(groupID, name, LinkedList<Address>(members.map { Address.fromSerialized(it) }),
|
||||
null, null, LinkedList<Address>(admins.map { Address.fromSerialized(it) }))
|
||||
storage.createGroup(groupID, name, LinkedList(members.map { Address.fromSerialized(it) }),
|
||||
null, null, LinkedList(admins.map { Address.fromSerialized(it) }))
|
||||
}
|
||||
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(Recipient.from(context, Address.fromSerialized(groupID), false), true)
|
||||
storage.setProfileSharing(Address.fromSerialized(groupID), true)
|
||||
// Add the group to the user's set of public keys to poll for
|
||||
sskDatabase.setClosedGroupPrivateKey(groupPublicKey, groupPrivateKey.toHexString())
|
||||
// Notify the PN server
|
||||
PushNotificationAPI.performOperation(context, ClosedGroupOperation.Subscribe, groupPublicKey, userPublicKey)
|
||||
PushNotificationAPI.performOperation(PushNotificationAPI.ClosedGroupOperation.Subscribe, groupPublicKey, userPublicKey)
|
||||
// Notify the user
|
||||
/* TODO
|
||||
insertIncomingInfoMessage(context, senderPublicKey, groupID, SignalServiceProtos.GroupContext.Type.UPDATE, SignalServiceGroup.Type.UPDATE, name, members, admins)
|
||||
// Establish sessions if needed
|
||||
establishSessionsWithMembersIfNeeded(context, members)
|
||||
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
private fun MessageReceiver.handleGroupUpdate(message: ClosedGroupUpdate) {
|
||||
|
@ -1,10 +1,9 @@
|
||||
package org.session.libsession.messaging.sending_receiving
|
||||
|
||||
import com.google.protobuf.MessageOrBuilder
|
||||
import nl.komponents.kovenant.Promise
|
||||
import nl.komponents.kovenant.deferred
|
||||
|
||||
import org.session.libsession.messaging.Configuration
|
||||
import org.session.libsession.messaging.MessagingConfiguration
|
||||
import org.session.libsession.messaging.jobs.JobQueue
|
||||
import org.session.libsession.messaging.messages.Destination
|
||||
import org.session.libsession.messaging.messages.Message
|
||||
@ -64,7 +63,7 @@ object MessageSender {
|
||||
fun sendToSnodeDestination(destination: Destination, message: Message): Promise<Unit, Exception> {
|
||||
val deferred = deferred<Unit, Exception>()
|
||||
val promise = deferred.promise
|
||||
val storage = Configuration.shared.storage
|
||||
val storage = MessagingConfiguration.shared.storage
|
||||
val preconditionFailure = Exception("Destination should not be open groups!")
|
||||
var snodeMessage: SnodeMessage? = null
|
||||
message.sentTimestamp ?: run { message.sentTimestamp = System.currentTimeMillis() } /* Visible messages will already have their sent timestamp set */
|
||||
@ -152,7 +151,7 @@ object MessageSender {
|
||||
fun sendToOpenGroupDestination(destination: Destination, message: Message): Promise<Unit, Exception> {
|
||||
val deferred = deferred<Unit, Exception>()
|
||||
val promise = deferred.promise
|
||||
val storage = Configuration.shared.storage
|
||||
val storage = MessagingConfiguration.shared.storage
|
||||
val preconditionFailure = Exception("Destination should not be contacts or closed groups!")
|
||||
message.sentTimestamp = System.currentTimeMillis()
|
||||
message.sender = storage.getUserPublicKey()
|
||||
|
@ -2,16 +2,17 @@
|
||||
|
||||
package org.session.libsession.messaging.sending_receiving
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import nl.komponents.kovenant.Promise
|
||||
import nl.komponents.kovenant.deferred
|
||||
|
||||
import org.session.libsession.messaging.Configuration
|
||||
import org.session.libsession.messaging.messages.Destination
|
||||
import org.session.libsession.messaging.MessagingConfiguration
|
||||
import org.session.libsession.messaging.messages.control.ClosedGroupUpdate
|
||||
import org.session.libsession.messaging.sending_receiving.notifications.PushNotificationAPI
|
||||
import org.session.libsession.utilities.LKGroupUtilities
|
||||
import org.session.libsession.messaging.sending_receiving.MessageSender.Error
|
||||
import org.session.libsession.messaging.threads.Address
|
||||
import org.session.libsession.utilities.GroupUtil
|
||||
|
||||
|
||||
import org.session.libsignal.libsignal.ecc.Curve
|
||||
import org.session.libsignal.libsignal.util.Hex
|
||||
@ -26,8 +27,9 @@ import java.util.*
|
||||
fun MessageSender.createClosedGroup(name: String, members: Collection<String>): Promise<String, Exception> {
|
||||
val deferred = deferred<String, Exception>()
|
||||
// Prepare
|
||||
val storage = MessagingConfiguration.shared.storage
|
||||
val members = members
|
||||
val userPublicKey = Configuration.shared.storage.getUserPublicKey()!!
|
||||
val userPublicKey = storage.getUserPublicKey()!!
|
||||
// Generate a key pair for the group
|
||||
val groupKeyPair = Curve.generateKeyPair()
|
||||
val groupPublicKey = groupKeyPair.hexEncodedPublicKey // Includes the "05" prefix
|
||||
@ -41,12 +43,9 @@ fun MessageSender.createClosedGroup(name: String, members: Collection<String>):
|
||||
// Create the group
|
||||
val admins = setOf( userPublicKey )
|
||||
val adminsAsData = admins.map { Hex.fromStringCondensed(it) }
|
||||
val groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey)
|
||||
/* TODO:
|
||||
DatabaseFactory.getGroupDatabase(context).create(groupID, name, LinkedList<Address>(members.map { Address.fromSerialized(it) }),
|
||||
null, null, LinkedList<Address>(admins.map { Address.fromSerialized(it) }))
|
||||
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(Recipient.from(context, Address.fromSerialized(groupID), false), true)
|
||||
*/
|
||||
val groupID = GroupUtil.getEncodedClosedGroupID(groupPublicKey)
|
||||
storage.createGroup(groupID, name, LinkedList(members.map { Address.fromSerialized(it) }), null, null, LinkedList(admins.map { Address.fromSerialized(it) }))
|
||||
storage.setProfileSharing(Address.fromSerialized(groupID), true)
|
||||
// Send a closed group update message to all members using established channels
|
||||
val promises = mutableListOf<Promise<Unit, Exception>>()
|
||||
for (member in members) {
|
||||
@ -55,16 +54,17 @@ fun MessageSender.createClosedGroup(name: String, members: Collection<String>):
|
||||
senderKeys, membersAsData, adminsAsData)
|
||||
val closedGroupUpdate = ClosedGroupUpdate()
|
||||
closedGroupUpdate.kind = closedGroupUpdateKind
|
||||
val promise = MessageSender.sendNonDurably(closedGroupUpdate, threadID)
|
||||
val address = Address.fromSerialized(member)
|
||||
val promise = MessageSender.sendNonDurably(closedGroupUpdate, address)
|
||||
promises.add(promise)
|
||||
}
|
||||
// Add the group to the user's set of public keys to poll for
|
||||
Configuration.shared.sskDatabase.setClosedGroupPrivateKey(groupPublicKey, groupKeyPair.hexEncodedPrivateKey)
|
||||
MessagingConfiguration.shared.sskDatabase.setClosedGroupPrivateKey(groupPublicKey, groupKeyPair.hexEncodedPrivateKey)
|
||||
// Notify the PN server
|
||||
PushNotificationAPI.performOperation(PushNotificationAPI.ClosedGroupOperation.Subscribe, groupPublicKey, userPublicKey)
|
||||
// Notify the user
|
||||
val threadID =storage.getOrCreateThreadIdFor(Address.fromSerialized(groupID))
|
||||
/* TODO
|
||||
val threadID = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(Recipient.from(context, Address.fromSerialized(groupID), false))
|
||||
insertOutgoingInfoMessage(context, groupID, GroupContext.Type.UPDATE, name, members, admins, threadID)
|
||||
*/
|
||||
// Fulfill the promise
|
||||
@ -75,46 +75,47 @@ fun MessageSender.createClosedGroup(name: String, members: Collection<String>):
|
||||
|
||||
fun MessageSender.update(groupPublicKey: String, members: Collection<String>, name: String): Promise<Unit, Exception> {
|
||||
val deferred = deferred<Unit, Exception>()
|
||||
val userPublicKey = Configuration.shared.storage.getUserPublicKey()!!
|
||||
val sskDatabase = Configuration.shared.sskDatabase
|
||||
val groupDB = DatabaseFactory.getGroupDatabase(context)
|
||||
val groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey)
|
||||
val group = groupDB.getGroup(groupID).orNull()
|
||||
val storage = MessagingConfiguration.shared.storage
|
||||
val userPublicKey = storage.getUserPublicKey()!!
|
||||
val sskDatabase = MessagingConfiguration.shared.sskDatabase
|
||||
val groupID = GroupUtil.getEncodedClosedGroupID(groupPublicKey)
|
||||
val group = storage.getGroup(groupID)
|
||||
if (group == null) {
|
||||
Log.d("Loki", "Can't update nonexistent closed group.")
|
||||
return deferred.reject(Error.NoThread)
|
||||
deferred.reject(Error.NoThread)
|
||||
return deferred.promise
|
||||
}
|
||||
val oldMembers = group.members.map { it.serialize() }.toSet()
|
||||
val newMembers = members.minus(oldMembers)
|
||||
val membersAsData = members.map { Hex.fromStringCondensed(it) }
|
||||
val admins = group.admins.map { it.serialize() }
|
||||
val adminsAsData = admins.map { Hex.fromStringCondensed(it) }
|
||||
val groupPrivateKey = DatabaseFactory.getSSKDatabase(context).getClosedGroupPrivateKey(groupPublicKey)
|
||||
val groupPrivateKey = sskDatabase.getClosedGroupPrivateKey(groupPublicKey)
|
||||
if (groupPrivateKey == null) {
|
||||
Log.d("Loki", "Couldn't get private key for closed group.")
|
||||
return@Thread deferred.reject(Error.NoPrivateKey)
|
||||
deferred.reject(Error.NoPrivateKey)
|
||||
return deferred.promise
|
||||
}
|
||||
val wasAnyUserRemoved = members.toSet().intersect(oldMembers) != oldMembers.toSet()
|
||||
val removedMembers = oldMembers.minus(members)
|
||||
val isUserLeaving = removedMembers.contains(userPublicKey)
|
||||
var newSenderKeys = listOf<ClosedGroupSenderKey>()
|
||||
val newSenderKeys: List<ClosedGroupSenderKey>
|
||||
if (wasAnyUserRemoved) {
|
||||
if (isUserLeaving && removedMembers.count() != 1) {
|
||||
Log.d("Loki", "Can't remove self and others simultaneously.")
|
||||
return@Thread deferred.reject(Error.InvalidUpdate)
|
||||
deferred.reject(Error.InvalidClosedGroupUpdate)
|
||||
return deferred.promise
|
||||
}
|
||||
// Establish sessions if needed
|
||||
establishSessionsWithMembersIfNeeded(context, members)
|
||||
// Send the update to the existing members using established channels (don't include new ratchets as everyone should regenerate new ratchets individually)
|
||||
for (member in oldMembers) {
|
||||
@Suppress("NAME_SHADOWING")
|
||||
val closedGroupUpdateKind = ClosedGroupUpdateMessageSendJob.Kind.Info(Hex.fromStringCondensed(groupPublicKey),
|
||||
val promises = oldMembers.map { member ->
|
||||
val closedGroupUpdateKind = ClosedGroupUpdate.Kind.Info(Hex.fromStringCondensed(groupPublicKey),
|
||||
name, setOf(), membersAsData, adminsAsData)
|
||||
@Suppress("NAME_SHADOWING")
|
||||
val job = ClosedGroupUpdateMessageSendJob(member, closedGroupUpdateKind)
|
||||
job.setContext(context)
|
||||
job.onRun() // Run the job immediately
|
||||
val closedGroupUpdate = ClosedGroupUpdate()
|
||||
closedGroupUpdate.kind = closedGroupUpdateKind
|
||||
val address = Address.fromSerialized(member)
|
||||
MessageSender.sendNonDurably(closedGroupUpdate, address).get()
|
||||
}
|
||||
|
||||
val allOldRatchets = sskDatabase.getAllClosedGroupRatchets(groupPublicKey, ClosedGroupRatchetCollectionType.Current)
|
||||
for (pair in allOldRatchets) {
|
||||
val senderPublicKey = pair.first
|
||||
@ -128,30 +129,30 @@ fun MessageSender.update(groupPublicKey: String, members: Collection<String>, na
|
||||
// send it out to all members (minus the removed ones) using established channels.
|
||||
if (isUserLeaving) {
|
||||
sskDatabase.removeClosedGroupPrivateKey(groupPublicKey)
|
||||
groupDB.setActive(groupID, false)
|
||||
groupDB.removeMember(groupID, Address.fromSerialized(userPublicKey))
|
||||
storage.setActive(groupID, false)
|
||||
storage.removeMember(groupID, Address.fromSerialized(userPublicKey))
|
||||
// Notify the PN server
|
||||
LokiPushNotificationManager.performOperation(context, ClosedGroupOperation.Unsubscribe, groupPublicKey, userPublicKey)
|
||||
PushNotificationAPI.performOperation(PushNotificationAPI.ClosedGroupOperation.Unsubscribe, groupPublicKey, userPublicKey)
|
||||
} else {
|
||||
// Send closed group update messages to any new members using established channels
|
||||
for (member in newMembers) {
|
||||
@Suppress("NAME_SHADOWING")
|
||||
val closedGroupUpdateKind = ClosedGroupUpdateMessageSendJob.Kind.New(Hex.fromStringCondensed(groupPublicKey), name,
|
||||
val closedGroupUpdateKind = ClosedGroupUpdate.Kind.New(Hex.fromStringCondensed(groupPublicKey), name,
|
||||
Hex.fromStringCondensed(groupPrivateKey), listOf(), membersAsData, adminsAsData)
|
||||
@Suppress("NAME_SHADOWING")
|
||||
val job = ClosedGroupUpdateMessageSendJob(member, closedGroupUpdateKind)
|
||||
ApplicationContext.getInstance(context).jobManager.add(job)
|
||||
val closedGroupUpdate = ClosedGroupUpdate()
|
||||
closedGroupUpdate.kind = closedGroupUpdateKind
|
||||
val address = Address.fromSerialized(member)
|
||||
MessageSender.sendNonDurably(closedGroupUpdate, address)
|
||||
}
|
||||
// Send out the user's new ratchet to all members (minus the removed ones) using established channels
|
||||
val userRatchet = SharedSenderKeysImplementation.shared.generateRatchet(groupPublicKey, userPublicKey)
|
||||
val userSenderKey = ClosedGroupSenderKey(Hex.fromStringCondensed(userRatchet.chainKey), userRatchet.keyIndex, Hex.fromStringCondensed(userPublicKey))
|
||||
for (member in members) {
|
||||
if (member == userPublicKey) { continue }
|
||||
@Suppress("NAME_SHADOWING")
|
||||
val closedGroupUpdateKind = ClosedGroupUpdateMessageSendJob.Kind.SenderKey(Hex.fromStringCondensed(groupPublicKey), userSenderKey)
|
||||
@Suppress("NAME_SHADOWING")
|
||||
val job = ClosedGroupUpdateMessageSendJob(member, closedGroupUpdateKind)
|
||||
ApplicationContext.getInstance(context).jobManager.add(job)
|
||||
val closedGroupUpdateKind = ClosedGroupUpdate.Kind.SenderKey(Hex.fromStringCondensed(groupPublicKey), userSenderKey)
|
||||
val closedGroupUpdate = ClosedGroupUpdate()
|
||||
closedGroupUpdate.kind = closedGroupUpdateKind
|
||||
val address = Address.fromSerialized(member)
|
||||
MessageSender.sendNonDurably(closedGroupUpdate, address)
|
||||
}
|
||||
}
|
||||
} else if (newMembers.isNotEmpty()) {
|
||||
@ -161,49 +162,68 @@ fun MessageSender.update(groupPublicKey: String, members: Collection<String>, na
|
||||
ClosedGroupSenderKey(Hex.fromStringCondensed(ratchet.chainKey), ratchet.keyIndex, Hex.fromStringCondensed(publicKey))
|
||||
}
|
||||
// Send a closed group update message to the existing members with the new members' ratchets (this message is aimed at the group)
|
||||
val closedGroupUpdateKind = ClosedGroupUpdateMessageSendJob.Kind.Info(Hex.fromStringCondensed(groupPublicKey), name,
|
||||
val closedGroupUpdateKind = ClosedGroupUpdate.Kind.Info(Hex.fromStringCondensed(groupPublicKey), name,
|
||||
newSenderKeys, membersAsData, adminsAsData)
|
||||
val job = ClosedGroupUpdateMessageSendJob(groupPublicKey, closedGroupUpdateKind)
|
||||
ApplicationContext.getInstance(context).jobManager.add(job)
|
||||
// Establish sessions if needed
|
||||
establishSessionsWithMembersIfNeeded(context, newMembers)
|
||||
val closedGroupUpdate = ClosedGroupUpdate()
|
||||
closedGroupUpdate.kind = closedGroupUpdateKind
|
||||
val address = Address.fromSerialized(groupID)
|
||||
MessageSender.send(closedGroupUpdate, address)
|
||||
// Send closed group update messages to the new members using established channels
|
||||
var allSenderKeys = sskDatabase.getAllClosedGroupSenderKeys(groupPublicKey, ClosedGroupRatchetCollectionType.Current)
|
||||
allSenderKeys = allSenderKeys.union(newSenderKeys)
|
||||
for (member in newMembers) {
|
||||
@Suppress("NAME_SHADOWING")
|
||||
val closedGroupUpdateKind = ClosedGroupUpdateMessageSendJob.Kind.New(Hex.fromStringCondensed(groupPublicKey), name,
|
||||
val closedGroupUpdateKind = ClosedGroupUpdate.Kind.New(Hex.fromStringCondensed(groupPublicKey), name,
|
||||
Hex.fromStringCondensed(groupPrivateKey), allSenderKeys, membersAsData, adminsAsData)
|
||||
@Suppress("NAME_SHADOWING")
|
||||
val job = ClosedGroupUpdateMessageSendJob(member, closedGroupUpdateKind)
|
||||
ApplicationContext.getInstance(context).jobManager.add(job)
|
||||
val closedGroupUpdate = ClosedGroupUpdate()
|
||||
closedGroupUpdate.kind = closedGroupUpdateKind
|
||||
val address = Address.fromSerialized(member)
|
||||
MessageSender.send(closedGroupUpdate, address)
|
||||
}
|
||||
} else {
|
||||
val allSenderKeys = sskDatabase.getAllClosedGroupSenderKeys(groupPublicKey, ClosedGroupRatchetCollectionType.Current)
|
||||
val closedGroupUpdateKind = ClosedGroupUpdateMessageSendJob.Kind.Info(Hex.fromStringCondensed(groupPublicKey), name,
|
||||
val closedGroupUpdateKind = ClosedGroupUpdate.Kind.Info(Hex.fromStringCondensed(groupPublicKey), name,
|
||||
allSenderKeys, membersAsData, adminsAsData)
|
||||
val job = ClosedGroupUpdateMessageSendJob(groupPublicKey, closedGroupUpdateKind)
|
||||
ApplicationContext.getInstance(context).jobManager.add(job)
|
||||
val closedGroupUpdate = ClosedGroupUpdate()
|
||||
closedGroupUpdate.kind = closedGroupUpdateKind
|
||||
val address = Address.fromSerialized(groupID)
|
||||
MessageSender.send(closedGroupUpdate, address)
|
||||
}
|
||||
// Update the group
|
||||
groupDB.updateTitle(groupID, name)
|
||||
storage.updateTitle(groupID, name)
|
||||
if (!isUserLeaving) {
|
||||
// The call below sets isActive to true, so if the user is leaving we have to use groupDB.remove(...) instead
|
||||
groupDB.updateMembers(groupID, members.map { Address.fromSerialized(it) })
|
||||
storage.updateMembers(groupID, members.map { Address.fromSerialized(it) })
|
||||
}
|
||||
// Notify the user
|
||||
val infoType = if (isUserLeaving) SignalServiceProtos.GroupContext.Type.QUIT else SignalServiceProtos.GroupContext.Type.UPDATE
|
||||
val threadID = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(Recipient.from(context, Address.fromSerialized(groupID), false))
|
||||
val threadID = storage.getOrCreateThreadIdFor(Address.fromSerialized(groupID))
|
||||
/* TODO
|
||||
insertOutgoingInfoMessage(context, groupID, infoType, name, members, admins, threadID)
|
||||
*/
|
||||
deferred.resolve(Unit)
|
||||
return deferred.promise
|
||||
}
|
||||
|
||||
fun MessageSender.leave(groupPublicKey: String) {
|
||||
val storage = MessagingConfiguration.shared.storage
|
||||
val userPublicKey = storage.getUserPublicKey()!!
|
||||
val groupID = GroupUtil.getEncodedClosedGroupID(groupPublicKey)
|
||||
val group = storage.getGroup(groupID)
|
||||
if (group == null) {
|
||||
Log.d("Loki", "Can't leave nonexistent closed group.")
|
||||
return
|
||||
}
|
||||
val name = group.title
|
||||
val oldMembers = group.members.map { it.serialize() }.toSet()
|
||||
val newMembers = oldMembers.minus(userPublicKey)
|
||||
return update(groupPublicKey, newMembers, name).get()
|
||||
}
|
||||
|
||||
fun MessageSender.requestSenderKey(groupPublicKey: String, senderPublicKey: String) {
|
||||
Log.d("Loki", "Requesting sender key for group public key: $groupPublicKey, sender public key: $senderPublicKey.")
|
||||
// Send the request
|
||||
val address = Address.fromSerialized(senderPublicKey)
|
||||
val closedGroupUpdateKind = ClosedGroupUpdate.Kind.SenderKeyRequest(Hex.fromStringCondensed(groupPublicKey))
|
||||
val closedGroupUpdate = ClosedGroupUpdate()
|
||||
closedGroupUpdate.kind = closedGroupUpdateKind
|
||||
MessageSender.send(closedGroupUpdate, Destination.ClosedGroup(groupPublicKey))
|
||||
MessageSender.send(closedGroupUpdate, address)
|
||||
}
|
@ -1,35 +1,39 @@
|
||||
package org.session.libsession.messaging.sending_receiving
|
||||
|
||||
import nl.komponents.kovenant.Promise
|
||||
import org.session.libsession.messaging.MessagingConfiguration
|
||||
|
||||
import org.session.libsession.messaging.jobs.JobQueue
|
||||
import org.session.libsession.messaging.jobs.MessageSendJob
|
||||
import org.session.libsession.messaging.messages.Destination
|
||||
import org.session.libsession.messaging.messages.Message
|
||||
import org.session.libsession.messaging.messages.visible.VisibleMessage
|
||||
import org.session.libsession.messaging.threads.Address
|
||||
|
||||
import org.session.libsignal.service.api.messages.SignalServiceAttachment
|
||||
|
||||
fun MessageSender.send(message: VisibleMessage, attachments: List<SignalServiceAttachment>, threadID: String) {
|
||||
fun MessageSender.send(message: VisibleMessage, attachments: List<SignalServiceAttachment>, address: Address) {
|
||||
prep(attachments, message)
|
||||
send(message, threadID)
|
||||
send(message, address)
|
||||
}
|
||||
|
||||
fun MessageSender.send(message: Message, threadID: String) {
|
||||
fun MessageSender.send(message: Message, address: Address) {
|
||||
val threadID = MessagingConfiguration.shared.storage.getOrCreateThreadIdFor(address)
|
||||
message.threadID = threadID
|
||||
val destination = Destination.from(threadID)
|
||||
val destination = Destination.from(address)
|
||||
val job = MessageSendJob(message, destination)
|
||||
JobQueue.shared.add(job)
|
||||
}
|
||||
|
||||
fun MessageSender.sendNonDurably(message: VisibleMessage, attachments: List<SignalServiceAttachment>, threadID: String): Promise<Unit, Exception> {
|
||||
fun MessageSender.sendNonDurably(message: VisibleMessage, attachments: List<SignalServiceAttachment>, address: Address): Promise<Unit, Exception> {
|
||||
prep(attachments, message)
|
||||
// TODO: Deal with attachments
|
||||
return sendNonDurably(message, threadID)
|
||||
return sendNonDurably(message, address)
|
||||
}
|
||||
|
||||
fun MessageSender.sendNonDurably(message: Message, threadID: String): Promise<Unit, Exception> {
|
||||
fun MessageSender.sendNonDurably(message: Message, address: Address): Promise<Unit, Exception> {
|
||||
val threadID = MessagingConfiguration.shared.storage.getOrCreateThreadIdFor(address)
|
||||
message.threadID = threadID
|
||||
val destination = Destination.from(threadID)
|
||||
val destination = Destination.from(address)
|
||||
return MessageSender.send(message, destination)
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
package org.session.libsession.messaging.sending_receiving
|
||||
|
||||
import com.google.protobuf.ByteString
|
||||
import org.session.libsession.messaging.Configuration
|
||||
import org.session.libsession.messaging.MessagingConfiguration
|
||||
import org.session.libsession.messaging.messages.Message
|
||||
import org.session.libsession.messaging.sending_receiving.MessageSender.Error
|
||||
import org.session.libsession.messaging.utilities.UnidentifiedAccessUtil
|
||||
@ -21,11 +21,11 @@ import org.session.libsignal.service.loki.utilities.removing05PrefixIfNeeded
|
||||
object MessageSenderEncryption {
|
||||
|
||||
internal fun encryptWithSignalProtocol(plaintext: ByteArray, message: Message, recipientPublicKey: String): ByteArray{
|
||||
val storage = Configuration.shared.signalStorage
|
||||
val sskDatabase = Configuration.shared.sskDatabase
|
||||
val sessionResetImp = Configuration.shared.sessionResetImp
|
||||
val storage = MessagingConfiguration.shared.signalStorage
|
||||
val sskDatabase = MessagingConfiguration.shared.sskDatabase
|
||||
val sessionResetImp = MessagingConfiguration.shared.sessionResetImp
|
||||
val localAddress = SignalServiceAddress(recipientPublicKey)
|
||||
val certificateValidator = Configuration.shared.certificateValidator
|
||||
val certificateValidator = MessagingConfiguration.shared.certificateValidator
|
||||
val cipher = SignalServiceCipher(localAddress, storage, sskDatabase, sessionResetImp, certificateValidator)
|
||||
val signalProtocolAddress = SignalProtocolAddress(recipientPublicKey, 1)
|
||||
val unidentifiedAccessPair = UnidentifiedAccessUtil.getAccessFor(recipientPublicKey)
|
||||
@ -36,7 +36,7 @@ object MessageSenderEncryption {
|
||||
|
||||
internal fun encryptWithSharedSenderKeys(plaintext: ByteArray, groupPublicKey: String): ByteArray {
|
||||
// 1. ) Encrypt the data with the user's sender key
|
||||
val userPublicKey = Configuration.shared.storage.getUserPublicKey() ?: throw Error.NoUserPublicKey
|
||||
val userPublicKey = MessagingConfiguration.shared.storage.getUserPublicKey() ?: throw Error.NoUserPublicKey
|
||||
val ciphertextAndKeyIndex = SharedSenderKeysImplementation.shared.encrypt(plaintext, groupPublicKey, userPublicKey)
|
||||
val ivAndCiphertext = ciphertextAndKeyIndex.first
|
||||
val keyIndex = ciphertextAndKeyIndex.second
|
||||
|
@ -1,16 +1,16 @@
|
||||
package org.session.libsession.messaging.sending_receiving.notifications
|
||||
|
||||
import android.content.Context
|
||||
import nl.komponents.kovenant.functional.map
|
||||
import okhttp3.*
|
||||
import org.session.libsession.messaging.Configuration
|
||||
import org.session.libsession.messaging.MessagingConfiguration
|
||||
import org.session.libsession.utilities.TextSecurePreferences
|
||||
import org.session.libsignal.libsignal.logging.Log
|
||||
import org.session.libsignal.service.internal.util.JsonUtil
|
||||
import org.session.libsignal.service.loki.api.onionrequests.OnionRequestAPI
|
||||
import org.session.libsignal.service.loki.utilities.retryIfNeeded
|
||||
import java.io.IOException
|
||||
|
||||
object PushNotificationAPI {
|
||||
val context = MessagingConfiguration.shared.context
|
||||
val server = "https://live.apns.getsession.org"
|
||||
val serverPublicKey = "642a6585919742e5a2d4dc51244964fbcd8bcab2b75612407de58b810740d049"
|
||||
private val maxRetryCount = 4
|
||||
@ -46,8 +46,8 @@ object PushNotificationAPI {
|
||||
}
|
||||
}
|
||||
// Unsubscribe from all closed groups
|
||||
val allClosedGroupPublicKeys = Configuration.shared.sskDatabase.getAllClosedGroupPublicKeys()
|
||||
val userPublicKey = Configuration.shared.storage.getUserPublicKey()!!
|
||||
val allClosedGroupPublicKeys = MessagingConfiguration.shared.sskDatabase.getAllClosedGroupPublicKeys()
|
||||
val userPublicKey = MessagingConfiguration.shared.storage.getUserPublicKey()!!
|
||||
allClosedGroupPublicKeys.forEach { closedGroup ->
|
||||
performOperation(ClosedGroupOperation.Unsubscribe, closedGroup, userPublicKey)
|
||||
}
|
||||
@ -76,7 +76,7 @@ object PushNotificationAPI {
|
||||
}
|
||||
}
|
||||
// Subscribe to all closed groups
|
||||
val allClosedGroupPublicKeys = Configuration.shared.sskDatabase.getAllClosedGroupPublicKeys()
|
||||
val allClosedGroupPublicKeys = MessagingConfiguration.shared.sskDatabase.getAllClosedGroupPublicKeys()
|
||||
allClosedGroupPublicKeys.forEach { closedGroup ->
|
||||
performOperation(ClosedGroupOperation.Subscribe, closedGroup, publicKey)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user