mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-27 12:05:22 +00:00
Merge branch 'refactor' of https://github.com/RyanRory/loki-messenger-android into refactor
This commit is contained in:
commit
8e8abcbe81
@ -18,12 +18,12 @@ import org.session.libsession.messaging.threads.Address
|
|||||||
import org.session.libsession.messaging.threads.GroupRecord
|
import org.session.libsession.messaging.threads.GroupRecord
|
||||||
import org.session.libsession.messaging.threads.recipients.Recipient
|
import org.session.libsession.messaging.threads.recipients.Recipient
|
||||||
import org.session.libsession.utilities.TextSecurePreferences
|
import org.session.libsession.utilities.TextSecurePreferences
|
||||||
|
import org.session.libsignal.libsignal.ecc.ECKeyPair
|
||||||
import org.session.libsignal.libsignal.util.KeyHelper
|
import org.session.libsignal.libsignal.util.KeyHelper
|
||||||
import org.session.libsignal.libsignal.util.guava.Optional
|
import org.session.libsignal.libsignal.util.guava.Optional
|
||||||
import org.session.libsignal.service.api.messages.SignalServiceAttachmentPointer
|
import org.session.libsignal.service.api.messages.SignalServiceAttachmentPointer
|
||||||
import org.session.libsignal.service.api.messages.SignalServiceGroup
|
import org.session.libsignal.service.api.messages.SignalServiceGroup
|
||||||
import org.session.libsignal.service.internal.push.SignalServiceProtos
|
import org.session.libsignal.service.internal.push.SignalServiceProtos
|
||||||
import org.session.libsignal.service.loki.api.opengroups.PublicChat
|
|
||||||
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil
|
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil
|
||||||
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper
|
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper
|
||||||
import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase
|
import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase
|
||||||
@ -46,6 +46,10 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
|
|||||||
return Pair(userPublicKey, userPrivateKey)
|
return Pair(userPublicKey, userPrivateKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getUserX25519KeyPair(): ECKeyPair {
|
||||||
|
return DatabaseFactory.getLokiAPIDatabase(context).getUserX25519KeyPair()
|
||||||
|
}
|
||||||
|
|
||||||
override fun getUserDisplayName(): String? {
|
override fun getUserDisplayName(): String? {
|
||||||
return TextSecurePreferences.getProfileName(context)
|
return TextSecurePreferences.getProfileName(context)
|
||||||
}
|
}
|
||||||
@ -270,6 +274,18 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
|
|||||||
mmsDB.markAsSent(infoMessageID, true)
|
mmsDB.markAsSent(infoMessageID, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun isClosedGroup(publicKey: String): Boolean {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getClosedGroupEncryptionKeyPairs(groupPublicKey: String): MutableList<ECKeyPair> {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getLatestClosedGroupEncryptionKeyPair(groupPublicKey: String): ECKeyPair {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
override fun setProfileSharing(address: Address, value: Boolean) {
|
override fun setProfileSharing(address: Address, value: Boolean) {
|
||||||
val recipient = Recipient.from(context, address, false)
|
val recipient = Recipient.from(context, address, false)
|
||||||
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(recipient, value)
|
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(recipient, value)
|
||||||
|
@ -27,6 +27,7 @@ interface StorageProtocol {
|
|||||||
// General
|
// General
|
||||||
fun getUserPublicKey(): String?
|
fun getUserPublicKey(): String?
|
||||||
fun getUserKeyPair(): Pair<String, ByteArray>?
|
fun getUserKeyPair(): Pair<String, ByteArray>?
|
||||||
|
fun getUserX25519KeyPair(): ECKeyPair
|
||||||
fun getUserDisplayName(): String?
|
fun getUserDisplayName(): String?
|
||||||
fun getUserProfileKey(): ByteArray?
|
fun getUserProfileKey(): ByteArray?
|
||||||
fun getUserProfilePictureURL(): String?
|
fun getUserProfilePictureURL(): String?
|
||||||
@ -101,6 +102,9 @@ interface StorageProtocol {
|
|||||||
name: String, members: Collection<String>, admins: Collection<String>)
|
name: String, members: Collection<String>, admins: Collection<String>)
|
||||||
fun insertOutgoingInfoMessage(context: Context, groupID: String, type: SignalServiceProtos.GroupContext.Type, name: String,
|
fun insertOutgoingInfoMessage(context: Context, groupID: String, type: SignalServiceProtos.GroupContext.Type, name: String,
|
||||||
members: Collection<String>, admins: Collection<String>, threadID: Long)
|
members: Collection<String>, admins: Collection<String>, threadID: Long)
|
||||||
|
fun isClosedGroup(publicKey: String): Boolean //TODO
|
||||||
|
fun getClosedGroupEncryptionKeyPairs(groupPublicKey: String): MutableList<ECKeyPair> //TODO
|
||||||
|
fun getLatestClosedGroupEncryptionKeyPair(groupPublicKey: String): ECKeyPair //TODO
|
||||||
|
|
||||||
// Settings
|
// Settings
|
||||||
fun setProfileSharing(address: Address, value: Boolean)
|
fun setProfileSharing(address: Address, value: Boolean)
|
||||||
|
@ -7,8 +7,10 @@ import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate
|
|||||||
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
|
||||||
import org.session.libsession.messaging.messages.visible.VisibleMessage
|
import org.session.libsession.messaging.messages.visible.VisibleMessage
|
||||||
|
import org.session.libsignal.libsignal.ecc.ECKeyPair
|
||||||
|
|
||||||
import org.session.libsignal.service.internal.push.SignalServiceProtos
|
import org.session.libsignal.service.internal.push.SignalServiceProtos
|
||||||
|
import java.lang.Error
|
||||||
|
|
||||||
object MessageReceiver {
|
object MessageReceiver {
|
||||||
internal sealed class Error(val description: String) : Exception() {
|
internal sealed class Error(val description: String) : Exception() {
|
||||||
@ -16,7 +18,8 @@ object MessageReceiver {
|
|||||||
object InvalidMessage: Error("Invalid message.")
|
object InvalidMessage: Error("Invalid message.")
|
||||||
object UnknownMessage: Error("Unknown message type.")
|
object UnknownMessage: Error("Unknown message type.")
|
||||||
object UnknownEnvelopeType: Error("Unknown envelope type.")
|
object UnknownEnvelopeType: Error("Unknown envelope type.")
|
||||||
object NoUserPublicKey: Error("Couldn't find user key pair.")
|
object NoUserX25519KeyPair: Error("Couldn't find user X25519 key pair.")
|
||||||
|
object NoUserED25519KeyPair: Error("Couldn't find user ED25519 key pair.")
|
||||||
object NoData: Error("Received an empty envelope.")
|
object NoData: Error("Received an empty envelope.")
|
||||||
object SenderBlocked: Error("Received a message from a blocked user.")
|
object SenderBlocked: Error("Received a message from a blocked user.")
|
||||||
object NoThread: Error("Couldn't find thread for message.")
|
object NoThread: Error("Couldn't find thread for message.")
|
||||||
@ -24,7 +27,7 @@ object MessageReceiver {
|
|||||||
object ParsingFailed : Error("Couldn't parse ciphertext message.")
|
object ParsingFailed : Error("Couldn't parse ciphertext message.")
|
||||||
// Shared sender keys
|
// Shared sender keys
|
||||||
object InvalidGroupPublicKey: Error("Invalid group public key.")
|
object InvalidGroupPublicKey: Error("Invalid group public key.")
|
||||||
object NoGroupPrivateKey: Error("Missing group private key.")
|
object NoGroupKeyPair: Error("Missing group key pair.")
|
||||||
object SharedSecretGenerationFailed: Error("Couldn't generate a shared secret.")
|
object SharedSecretGenerationFailed: Error("Couldn't generate a shared secret.")
|
||||||
|
|
||||||
internal val isRetryable: Boolean = when (this) {
|
internal val isRetryable: Boolean = when (this) {
|
||||||
@ -47,8 +50,9 @@ object MessageReceiver {
|
|||||||
if (storage.getReceivedMessageTimestamps().contains(envelope.timestamp)) throw Error.DuplicateMessage
|
if (storage.getReceivedMessageTimestamps().contains(envelope.timestamp)) throw Error.DuplicateMessage
|
||||||
storage.addReceivedMessageTimestamp(envelope.timestamp)
|
storage.addReceivedMessageTimestamp(envelope.timestamp)
|
||||||
// Decrypt the contents
|
// Decrypt the contents
|
||||||
val plaintext: ByteArray
|
val ciphertext = envelope.content ?: throw Error.NoData
|
||||||
val sender: String
|
var plaintext: ByteArray? = null
|
||||||
|
var sender: String? = null
|
||||||
var groupPublicKey: String? = null
|
var groupPublicKey: String? = null
|
||||||
if (isOpenGroupMessage) {
|
if (isOpenGroupMessage) {
|
||||||
plaintext = envelope.content.toByteArray()
|
plaintext = envelope.content.toByteArray()
|
||||||
@ -56,20 +60,43 @@ object MessageReceiver {
|
|||||||
} else {
|
} else {
|
||||||
when (envelope.type) {
|
when (envelope.type) {
|
||||||
SignalServiceProtos.Envelope.Type.UNIDENTIFIED_SENDER -> {
|
SignalServiceProtos.Envelope.Type.UNIDENTIFIED_SENDER -> {
|
||||||
val decryptionResult = MessageReceiverDecryption.decryptWithSessionProtocol(envelope)
|
val userX25519KeyPair = MessagingConfiguration.shared.storage.getUserX25519KeyPair() ?: throw Error.NoUserX25519KeyPair
|
||||||
|
val decryptionResult = MessageReceiverDecryption.decryptWithSessionProtocol(ciphertext.toByteArray(), userX25519KeyPair)
|
||||||
plaintext = decryptionResult.first
|
plaintext = decryptionResult.first
|
||||||
sender = decryptionResult.second
|
sender = decryptionResult.second
|
||||||
}
|
}
|
||||||
SignalServiceProtos.Envelope.Type.CLOSED_GROUP_CIPHERTEXT -> {
|
SignalServiceProtos.Envelope.Type.CLOSED_GROUP_CIPHERTEXT -> {
|
||||||
val decryptionResult = MessageReceiverDecryption.decryptWithSharedSenderKeys(envelope)
|
val hexEncodedGroupPublicKey = envelope.source
|
||||||
|
if (hexEncodedGroupPublicKey == null || MessagingConfiguration.shared.storage.isClosedGroup(hexEncodedGroupPublicKey)) {
|
||||||
|
throw Error.InvalidGroupPublicKey
|
||||||
|
}
|
||||||
|
val encryptionKeyPairs = MessagingConfiguration.shared.storage.getClosedGroupEncryptionKeyPairs(hexEncodedGroupPublicKey)
|
||||||
|
if (encryptionKeyPairs.isEmpty()) { throw Error.NoGroupKeyPair }
|
||||||
|
// Loop through all known group key pairs in reverse order (i.e. try the latest key pair first (which'll more than
|
||||||
|
// likely be the one we want) but try older ones in case that didn't work)
|
||||||
|
var encryptionKeyPair = encryptionKeyPairs.removeLast()
|
||||||
|
fun decrypt() {
|
||||||
|
try {
|
||||||
|
val decryptionResult = MessageReceiverDecryption.decryptWithSessionProtocol(ciphertext.toByteArray(), encryptionKeyPair)
|
||||||
plaintext = decryptionResult.first
|
plaintext = decryptionResult.first
|
||||||
sender = decryptionResult.second
|
sender = decryptionResult.second
|
||||||
|
} catch (e: Exception) {
|
||||||
|
if (encryptionKeyPairs.isNotEmpty()) {
|
||||||
|
encryptionKeyPair = encryptionKeyPairs.removeLast()
|
||||||
|
decrypt()
|
||||||
|
} else {
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
decrypt()
|
||||||
|
groupPublicKey = envelope.source
|
||||||
}
|
}
|
||||||
else -> throw Error.UnknownEnvelopeType
|
else -> throw Error.UnknownEnvelopeType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Don't process the envelope any further if the sender is blocked
|
// Don't process the envelope any further if the sender is blocked
|
||||||
if (isBlock(sender)) throw Error.SenderBlocked
|
if (isBlock(sender!!)) throw Error.SenderBlocked
|
||||||
// Ignore self sends
|
// Ignore self sends
|
||||||
if (sender == userPublicKey) throw Error.SelfSend
|
if (sender == userPublicKey) throw Error.SelfSend
|
||||||
// Parse the proto
|
// Parse the proto
|
||||||
|
@ -4,6 +4,7 @@ import org.session.libsession.messaging.MessagingConfiguration
|
|||||||
import org.session.libsession.messaging.sending_receiving.MessageReceiver.Error
|
import org.session.libsession.messaging.sending_receiving.MessageReceiver.Error
|
||||||
import org.session.libsession.utilities.AESGCM
|
import org.session.libsession.utilities.AESGCM
|
||||||
import org.session.libsession.utilities.GroupUtil
|
import org.session.libsession.utilities.GroupUtil
|
||||||
|
import org.session.libsignal.libsignal.ecc.ECKeyPair
|
||||||
|
|
||||||
import org.whispersystems.curve25519.Curve25519
|
import org.whispersystems.curve25519.Curve25519
|
||||||
|
|
||||||
@ -32,11 +33,11 @@ object MessageReceiverDecryption {
|
|||||||
return Pair(ByteArray(1), result.sender) // TODO: Return real plaintext
|
return Pair(ByteArray(1), result.sender) // TODO: Return real plaintext
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
internal fun decryptWithSessionProtocol(envelope: SignalServiceProtos.Envelope): Pair<ByteArray, String> {
|
internal fun decryptWithSessionProtocol(ciphertext: ByteArray, x25519KeyPair: ECKeyPair): Pair<ByteArray, String> {
|
||||||
return MessagingConfiguration.shared.sessionProtocol.decrypt(SignalServiceEnvelope(envelope))
|
return MessagingConfiguration.shared.sessionProtocol.decrypt(ciphertext, x25519KeyPair)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun decryptWithSharedSenderKeys(envelope: SignalServiceProtos.Envelope): Pair<ByteArray, String> {
|
/*internal fun decryptWithSharedSenderKeys(envelope: SignalServiceProtos.Envelope): Pair<ByteArray, String> {
|
||||||
// 1. ) Check preconditions
|
// 1. ) Check preconditions
|
||||||
val groupPublicKey = envelope.source
|
val groupPublicKey = envelope.source
|
||||||
if (!GroupUtil.isClosedGroup(groupPublicKey)) { throw Error.InvalidGroupPublicKey }
|
if (!GroupUtil.isClosedGroup(groupPublicKey)) { throw Error.InvalidGroupPublicKey }
|
||||||
@ -61,5 +62,5 @@ object MessageReceiverDecryption {
|
|||||||
val plaintext = SharedSenderKeysImplementation.shared.decrypt(closedGroupCiphertextMessage.ivAndCiphertext, groupPublicKey, senderPublicKey, closedGroupCiphertextMessage.keyIndex)
|
val plaintext = SharedSenderKeysImplementation.shared.decrypt(closedGroupCiphertextMessage.ivAndCiphertext, groupPublicKey, senderPublicKey, closedGroupCiphertextMessage.keyIndex)
|
||||||
// 6. ) Return
|
// 6. ) Return
|
||||||
return Pair(plaintext, senderPublicKey)
|
return Pair(plaintext, senderPublicKey)
|
||||||
}
|
}*/
|
||||||
}
|
}
|
@ -23,6 +23,7 @@ import org.session.libsignal.service.api.messages.SignalServiceAttachment
|
|||||||
import org.session.libsignal.service.internal.push.SignalServiceProtos
|
import org.session.libsignal.service.internal.push.SignalServiceProtos
|
||||||
import org.session.libsignal.service.internal.util.Base64
|
import org.session.libsignal.service.internal.util.Base64
|
||||||
import org.session.libsignal.service.loki.api.crypto.ProofOfWork
|
import org.session.libsignal.service.loki.api.crypto.ProofOfWork
|
||||||
|
import org.session.libsignal.service.loki.utilities.hexEncodedPublicKey
|
||||||
|
|
||||||
|
|
||||||
object MessageSender {
|
object MessageSender {
|
||||||
@ -32,7 +33,10 @@ object MessageSender {
|
|||||||
object InvalidMessage : Error("Invalid message.")
|
object InvalidMessage : Error("Invalid message.")
|
||||||
object ProtoConversionFailed : Error("Couldn't convert message to proto.")
|
object ProtoConversionFailed : Error("Couldn't convert message to proto.")
|
||||||
object ProofOfWorkCalculationFailed : Error("Proof of work calculation failed.")
|
object ProofOfWorkCalculationFailed : Error("Proof of work calculation failed.")
|
||||||
object NoUserPublicKey : Error("Couldn't find user key pair.")
|
object NoUserX25519KeyPair : Error("Couldn't find user X25519 key pair.")
|
||||||
|
object NoUserED25519KeyPair : Error("Couldn't find user ED25519 key pair.")
|
||||||
|
object SigningFailed : Error("Couldn't sign message.")
|
||||||
|
object EncryptionFailed : Error("Couldn't encrypt message.")
|
||||||
|
|
||||||
// Closed groups
|
// Closed groups
|
||||||
object NoThread : Error("Couldn't find a thread associated with the given group public key.")
|
object NoThread : Error("Couldn't find a thread associated with the given group public key.")
|
||||||
@ -71,7 +75,7 @@ object MessageSender {
|
|||||||
var snodeMessage: SnodeMessage? = null
|
var snodeMessage: SnodeMessage? = null
|
||||||
// Set the timestamp, sender and recipient
|
// Set the timestamp, sender and recipient
|
||||||
message.sentTimestamp ?: run { message.sentTimestamp = System.currentTimeMillis() } /* Visible messages will already have their sent timestamp set */
|
message.sentTimestamp ?: run { message.sentTimestamp = System.currentTimeMillis() } /* Visible messages will already have their sent timestamp set */
|
||||||
message.sender = storage.getUserPublicKey()
|
message.sender = userPublicKey
|
||||||
try {
|
try {
|
||||||
when (destination) {
|
when (destination) {
|
||||||
is Destination.Contact -> message.recipient = destination.publicKey
|
is Destination.Contact -> message.recipient = destination.publicKey
|
||||||
@ -117,7 +121,10 @@ object MessageSender {
|
|||||||
val ciphertext: ByteArray
|
val ciphertext: ByteArray
|
||||||
when (destination) {
|
when (destination) {
|
||||||
is Destination.Contact -> ciphertext = MessageSenderEncryption.encryptWithSessionProtocol(plaintext, destination.publicKey)
|
is Destination.Contact -> ciphertext = MessageSenderEncryption.encryptWithSessionProtocol(plaintext, destination.publicKey)
|
||||||
is Destination.ClosedGroup -> ciphertext = MessageSenderEncryption.encryptWithSharedSenderKeys(plaintext, destination.groupPublicKey)
|
is Destination.ClosedGroup -> {
|
||||||
|
val encryptionKeyPair = MessagingConfiguration.shared.storage.getLatestClosedGroupEncryptionKeyPair(destination.groupPublicKey)
|
||||||
|
ciphertext = MessageSenderEncryption.encryptWithSessionProtocol(plaintext, encryptionKeyPair.hexEncodedPublicKey)
|
||||||
|
}
|
||||||
is Destination.OpenGroup -> throw preconditionFailure
|
is Destination.OpenGroup -> throw preconditionFailure
|
||||||
}
|
}
|
||||||
// Wrap the result
|
// Wrap the result
|
||||||
|
@ -38,7 +38,7 @@ object MessageSenderEncryption {
|
|||||||
return MessagingConfiguration.shared.sessionProtocol.encrypt(plaintext, recipientPublicKey)
|
return MessagingConfiguration.shared.sessionProtocol.encrypt(plaintext, recipientPublicKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun encryptWithSharedSenderKeys(plaintext: ByteArray, groupPublicKey: String): ByteArray {
|
/*internal fun encryptWithSharedSenderKeys(plaintext: ByteArray, groupPublicKey: String): ByteArray {
|
||||||
// 1. ) Encrypt the data with the user's sender key
|
// 1. ) Encrypt the data with the user's sender key
|
||||||
val userPublicKey = MessagingConfiguration.shared.storage.getUserPublicKey() ?: throw Error.NoUserPublicKey
|
val userPublicKey = MessagingConfiguration.shared.storage.getUserPublicKey() ?: throw Error.NoUserPublicKey
|
||||||
val ciphertextAndKeyIndex = SharedSenderKeysImplementation.shared.encrypt(plaintext, groupPublicKey, userPublicKey)
|
val ciphertextAndKeyIndex = SharedSenderKeysImplementation.shared.encrypt(plaintext, groupPublicKey, userPublicKey)
|
||||||
@ -52,5 +52,5 @@ object MessageSenderEncryption {
|
|||||||
.setCiphertext(ByteString.copyFrom(intermediate.ciphertext))
|
.setCiphertext(ByteString.copyFrom(intermediate.ciphertext))
|
||||||
.setEphemeralPublicKey(ByteString.copyFrom(intermediate.ephemeralPublicKey))
|
.setEphemeralPublicKey(ByteString.copyFrom(intermediate.ephemeralPublicKey))
|
||||||
.build().toByteArray()
|
.build().toByteArray()
|
||||||
}
|
}*/
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user