sending & receiving $ make things compile

This commit is contained in:
Ryan ZHAO 2020-12-10 15:33:57 +11:00
parent 072aa0e7c6
commit c0dff9cdea
8 changed files with 143 additions and 124 deletions

View File

@ -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

View File

@ -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

View File

@ -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) {

View File

@ -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()

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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

View File

@ -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)
}