mirror of
https://github.com/oxen-io/session-android.git
synced 2025-01-12 09:33:39 +00:00
Open group message requests
This commit is contained in:
parent
d4fb77c695
commit
a24225cf8b
@ -62,14 +62,17 @@ import org.session.libsession.messaging.sending_receiving.MessageSender
|
||||
import org.session.libsession.messaging.sending_receiving.attachments.Attachment
|
||||
import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview
|
||||
import org.session.libsession.messaging.sending_receiving.quotes.QuoteModel
|
||||
import org.session.libsession.messaging.utilities.SessionId
|
||||
import org.session.libsession.utilities.Address
|
||||
import org.session.libsession.utilities.Address.Companion.fromSerialized
|
||||
import org.session.libsession.utilities.GroupUtil
|
||||
import org.session.libsession.utilities.MediaTypes
|
||||
import org.session.libsession.utilities.TextSecurePreferences
|
||||
import org.session.libsession.utilities.concurrent.SimpleTask
|
||||
import org.session.libsession.utilities.recipients.Recipient
|
||||
import org.session.libsession.utilities.recipients.RecipientModifiedListener
|
||||
import org.session.libsignal.crypto.MnemonicCodec
|
||||
import org.session.libsignal.utilities.IdPrefix
|
||||
import org.session.libsignal.utilities.ListenableFuture
|
||||
import org.session.libsignal.utilities.guava.Optional
|
||||
import org.session.libsignal.utilities.hexEncodedPrivateKey
|
||||
@ -129,6 +132,7 @@ import org.thoughtcrime.securesms.mms.VideoSlide
|
||||
import org.thoughtcrime.securesms.permissions.Permissions
|
||||
import org.thoughtcrime.securesms.util.ActivityDispatcher
|
||||
import org.thoughtcrime.securesms.util.ConfigurationMessageUtilities
|
||||
import org.thoughtcrime.securesms.util.ContactUtilities
|
||||
import org.thoughtcrime.securesms.util.DateUtils
|
||||
import org.thoughtcrime.securesms.util.MediaUtil
|
||||
import org.thoughtcrime.securesms.util.SaveAttachmentTask
|
||||
@ -176,7 +180,19 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
||||
private val viewModel: ConversationViewModel by viewModels {
|
||||
var threadId = intent.getLongExtra(THREAD_ID, -1L)
|
||||
if (threadId == -1L) {
|
||||
intent.getParcelableExtra<Address>(ADDRESS)?.let { address ->
|
||||
intent.getParcelableExtra<Address>(ADDRESS)?.let { it ->
|
||||
val sessionId = SessionId(it.serialize())
|
||||
val openGroup = lokiThreadDb.getOpenGroupChat(intent.getLongExtra(FROM_OPEN_GROUP_THREAD_ID, -1))
|
||||
val address = if (sessionId.prefix == IdPrefix.BLINDED && openGroup != null) {
|
||||
ContactUtilities.getBlindedIdMapping(this, sessionId.publicKey, openGroup.publicKey)?.let {
|
||||
fromSerialized(it.sessionId)
|
||||
} ?: run {
|
||||
val openGroupInboxId = "${openGroup.server}.${openGroup.publicKey}.${sessionId.hexString}".toByteArray()
|
||||
fromSerialized(GroupUtil.getEncodedOpenGroupInboxID(openGroupInboxId))
|
||||
}
|
||||
} else {
|
||||
it
|
||||
}
|
||||
val recipient = Recipient.from(this, address, false)
|
||||
threadId = threadDb.getOrCreateThreadIdFor(recipient)
|
||||
} ?: finish()
|
||||
@ -261,6 +277,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
||||
// Extras
|
||||
const val THREAD_ID = "thread_id"
|
||||
const val ADDRESS = "address"
|
||||
const val FROM_OPEN_GROUP_THREAD_ID = "from_open_group_id"
|
||||
const val SCROLL_MESSAGE_ID = "scroll_message_id"
|
||||
const val SCROLL_MESSAGE_AUTHOR = "scroll_message_author"
|
||||
// Request codes
|
||||
|
@ -1,6 +1,7 @@
|
||||
package org.thoughtcrime.securesms.conversation.v2.messages
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.res.Resources
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Rect
|
||||
@ -25,9 +26,12 @@ import network.loki.messenger.R
|
||||
import network.loki.messenger.databinding.ViewVisibleMessageBinding
|
||||
import org.session.libsession.messaging.contacts.Contact.ContactContext
|
||||
import org.session.libsession.messaging.open_groups.OpenGroupApi
|
||||
import org.session.libsession.utilities.Address
|
||||
import org.session.libsession.utilities.ViewUtil
|
||||
import org.session.libsignal.utilities.IdPrefix
|
||||
import org.session.libsignal.utilities.ThreadUtils
|
||||
import org.thoughtcrime.securesms.ApplicationContext
|
||||
import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2
|
||||
import org.thoughtcrime.securesms.database.LokiThreadDatabase
|
||||
import org.thoughtcrime.securesms.database.MmsDatabase
|
||||
import org.thoughtcrime.securesms.database.MmsSmsDatabase
|
||||
@ -123,7 +127,14 @@ class VisibleMessageView : LinearLayout {
|
||||
binding.profilePictureView.glide = glide
|
||||
binding.profilePictureView.update(message.individualRecipient)
|
||||
binding.profilePictureView.setOnClickListener {
|
||||
showUserDetails(senderSessionID, threadID)
|
||||
if (thread.isOpenGroupRecipient && IdPrefix.fromValue(senderSessionID) == IdPrefix.BLINDED) {
|
||||
val intent = Intent(context, ConversationActivityV2::class.java)
|
||||
intent.putExtra(ConversationActivityV2.FROM_OPEN_GROUP_THREAD_ID, threadID)
|
||||
intent.putExtra(ConversationActivityV2.ADDRESS, Address.fromSerialized(senderSessionID))
|
||||
context.startActivity(intent)
|
||||
} else {
|
||||
maybeShowUserDetails(senderSessionID, threadID)
|
||||
}
|
||||
}
|
||||
if (thread.isOpenGroupRecipient) {
|
||||
val openGroup = lokiThreadDb.getOpenGroupChat(threadID) ?: return
|
||||
@ -398,7 +409,7 @@ class VisibleMessageView : LinearLayout {
|
||||
pressCallback = null
|
||||
}
|
||||
|
||||
private fun showUserDetails(publicKey: String, threadID: Long) {
|
||||
private fun maybeShowUserDetails(publicKey: String, threadID: Long) {
|
||||
val userDetailsBottomSheet = UserDetailsBottomSheet()
|
||||
val bundle = bundleOf(
|
||||
UserDetailsBottomSheet.ARGUMENT_PUBLIC_KEY to publicKey,
|
||||
|
@ -1,6 +1,8 @@
|
||||
package org.thoughtcrime.securesms.util
|
||||
|
||||
import android.content.Context
|
||||
import org.session.libsession.messaging.utilities.BlindedIdMapping
|
||||
import org.session.libsession.messaging.utilities.SodiumUtilities
|
||||
import org.session.libsession.utilities.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
|
||||
|
||||
@ -20,4 +22,23 @@ object ContactUtilities {
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
fun getBlindedIdMapping(
|
||||
context: Context,
|
||||
blindedSessionId: String,
|
||||
serverPublicKey: String
|
||||
): BlindedIdMapping? {
|
||||
val threadDatabase = DatabaseComponent.get(context).threadDatabase()
|
||||
val cursor = threadDatabase.approvedConversationList
|
||||
threadDatabase.readerFor(cursor).use { reader ->
|
||||
while (reader.next != null) {
|
||||
val recipient = reader.current.recipient
|
||||
val sessionId = recipient.address.serialize()
|
||||
if (!recipient.isGroupRecipient && SodiumUtilities.sessionId(sessionId, blindedSessionId, serverPublicKey)) {
|
||||
return BlindedIdMapping(blindedSessionId, sessionId, serverPublicKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
@ -1,10 +1,8 @@
|
||||
package org.session.libsession.messaging.messages
|
||||
|
||||
import org.session.libsession.messaging.MessagingModuleConfiguration
|
||||
import org.session.libsession.messaging.utilities.SodiumUtilities
|
||||
import org.session.libsession.utilities.Address
|
||||
import org.session.libsession.utilities.GroupUtil
|
||||
import org.session.libsignal.utilities.IdPrefix
|
||||
import org.session.libsignal.utilities.toHexString
|
||||
|
||||
sealed class Destination {
|
||||
@ -38,17 +36,8 @@ sealed class Destination {
|
||||
fun from(address: Address): Destination {
|
||||
return when {
|
||||
address.isContact -> {
|
||||
val contact = address.contactIdentifier()
|
||||
if (SodiumUtilities.SessionId(contact).prefix == IdPrefix.BLINDED) {
|
||||
OpenGroupInbox(
|
||||
server = TODO(),
|
||||
serverPublicKey = TODO(),
|
||||
blinkedPublicKey = contact
|
||||
)
|
||||
} else {
|
||||
Contact(address.contactIdentifier())
|
||||
}
|
||||
}
|
||||
address.isClosedGroup -> {
|
||||
val groupID = address.toGroupString()
|
||||
val groupPublicKey = GroupUtil.doubleDecodeGroupID(groupID).toHexString()
|
||||
@ -63,6 +52,14 @@ sealed class Destination {
|
||||
else -> throw Exception("Missing open group for thread with ID: $threadID.")
|
||||
}
|
||||
}
|
||||
address.isOpenGroupInbox -> {
|
||||
val groupInboxId = GroupUtil.getDecodedGroupID(address.serialize()).split(".")
|
||||
OpenGroupInbox(
|
||||
groupInboxId.dropLast(2).joinToString("."),
|
||||
groupInboxId.dropLast(1).last(),
|
||||
groupInboxId.last()
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
throw Exception("TODO: Handle legacy closed groups.")
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ import okhttp3.MediaType
|
||||
import okhttp3.RequestBody
|
||||
import org.session.libsession.messaging.MessagingModuleConfiguration
|
||||
import org.session.libsession.messaging.sending_receiving.pollers.OpenGroupPoller.Companion.maxInactivityPeriod
|
||||
import org.session.libsession.messaging.utilities.SessionId
|
||||
import org.session.libsession.messaging.utilities.SodiumUtilities
|
||||
import org.session.libsession.snode.OnionRequestAPI
|
||||
import org.session.libsession.snode.OnionResponse
|
||||
@ -267,7 +268,7 @@ object OpenGroupApi {
|
||||
.plus(bodyHash)
|
||||
if (serverCapabilities.contains("blind")) {
|
||||
SodiumUtilities.blindedKeyPair(publicKey, ed25519KeyPair)?.let { keyPair ->
|
||||
pubKey = SodiumUtilities.SessionId(
|
||||
pubKey = SessionId(
|
||||
IdPrefix.BLINDED,
|
||||
keyPair.publicKey.asBytes
|
||||
).hexString
|
||||
@ -280,7 +281,7 @@ object OpenGroupApi {
|
||||
) ?: return Promise.ofFail(Error.SigningFailed)
|
||||
} ?: return Promise.ofFail(Error.SigningFailed)
|
||||
} else {
|
||||
pubKey = SodiumUtilities.SessionId(
|
||||
pubKey = SessionId(
|
||||
IdPrefix.UN_BLINDED,
|
||||
ed25519KeyPair.publicKey.asBytes
|
||||
).hexString
|
||||
|
@ -5,6 +5,7 @@ import com.goterl.lazysodium.LazySodiumAndroid
|
||||
import com.goterl.lazysodium.SodiumAndroid
|
||||
import com.goterl.lazysodium.interfaces.Box
|
||||
import com.goterl.lazysodium.interfaces.Sign
|
||||
import org.session.libsession.messaging.utilities.SessionId
|
||||
import org.session.libsignal.crypto.ecc.ECKeyPair
|
||||
import org.session.libsignal.utilities.Hex
|
||||
import org.session.libsignal.utilities.hexEncodedPublicKey
|
||||
@ -55,6 +56,7 @@ object MessageDecrypter {
|
||||
val senderX25519PublicKey = ByteArray(Sign.CURVE25519_PUBLICKEYBYTES)
|
||||
sodium.convertPublicKeyEd25519ToCurve25519(senderX25519PublicKey, senderED25519PublicKey)
|
||||
|
||||
return Pair(plaintext, "05" + senderX25519PublicKey.toHexString())
|
||||
val id = SessionId(IdPrefix.STANDARD, senderX25519PublicKey)
|
||||
return Pair(plaintext, id.hexString)
|
||||
}
|
||||
}
|
@ -16,6 +16,8 @@ import org.session.libsession.messaging.messages.visible.VisibleMessage
|
||||
import org.session.libsession.messaging.open_groups.OpenGroupApi
|
||||
import org.session.libsession.messaging.open_groups.OpenGroupMessage
|
||||
import org.session.libsession.messaging.utilities.MessageWrapper
|
||||
import org.session.libsession.messaging.utilities.SessionId
|
||||
import org.session.libsession.messaging.utilities.SodiumUtilities
|
||||
import org.session.libsession.snode.RawResponsePromise
|
||||
import org.session.libsession.snode.SnodeAPI
|
||||
import org.session.libsession.snode.SnodeMessage
|
||||
@ -26,6 +28,7 @@ import org.session.libsession.utilities.SSKEnvironment
|
||||
import org.session.libsignal.crypto.PushTransportDetails
|
||||
import org.session.libsignal.protos.SignalServiceProtos
|
||||
import org.session.libsignal.utilities.Base64
|
||||
import org.session.libsignal.utilities.IdPrefix
|
||||
import org.session.libsignal.utilities.Log
|
||||
import org.session.libsignal.utilities.hexEncodedPublicKey
|
||||
import java.util.concurrent.TimeUnit
|
||||
@ -56,7 +59,7 @@ object MessageSender {
|
||||
|
||||
// Convenience
|
||||
fun send(message: Message, destination: Destination): Promise<Unit, Exception> {
|
||||
return if (destination is Destination.LegacyOpenGroup || destination is Destination.OpenGroup) {
|
||||
return if (destination is Destination.LegacyOpenGroup || destination is Destination.OpenGroup || destination is Destination.OpenGroupInbox) {
|
||||
sendToOpenGroupDestination(destination, message)
|
||||
} else {
|
||||
sendToSnodeDestination(destination, message)
|
||||
@ -201,7 +204,14 @@ object MessageSender {
|
||||
if (message.sentTimestamp == null) {
|
||||
message.sentTimestamp = System.currentTimeMillis()
|
||||
}
|
||||
message.sender = storage.getUserPublicKey()
|
||||
val openGroup = storage.getOpenGroup(message.threadID!!)
|
||||
val userEdKeyPair = MessagingModuleConfiguration.shared.getUserED25519KeyPair()!!
|
||||
val blindedKeyPair = SodiumUtilities.blindedKeyPair(openGroup?.publicKey!!, userEdKeyPair)
|
||||
message.sender = if (openGroup.capabilities.contains("blind") && blindedKeyPair != null) {
|
||||
SessionId(IdPrefix.BLINDED, blindedKeyPair.publicKey.asBytes).hexString
|
||||
} else {
|
||||
SessionId(IdPrefix.UN_BLINDED, userEdKeyPair.publicKey.asBytes).hexString
|
||||
}
|
||||
// Set the failure handler (need it here already for precondition failure handling)
|
||||
fun handleFailure(error: Exception) {
|
||||
handleFailedMessageSend(message, error)
|
||||
|
@ -181,7 +181,9 @@ object SodiumUtilities {
|
||||
SessionId(IdPrefix.BLINDED, pk2).publicKey == blindedId.publicKey
|
||||
}
|
||||
|
||||
class SessionId {
|
||||
}
|
||||
|
||||
class SessionId {
|
||||
var prefix: IdPrefix?
|
||||
var publicKey: String
|
||||
|
||||
@ -197,6 +199,10 @@ object SodiumUtilities {
|
||||
|
||||
val hexString
|
||||
get() = prefix?.value + publicKey
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
data class BlindedIdMapping(
|
||||
val blindedId: String,
|
||||
val sessionId: String,
|
||||
val serverPublicKey: String
|
||||
)
|
||||
|
@ -25,6 +25,8 @@ class Address private constructor(address: String) : Parcelable, Comparable<Addr
|
||||
get() = GroupUtil.isClosedGroup(address)
|
||||
val isOpenGroup: Boolean
|
||||
get() = GroupUtil.isOpenGroup(address)
|
||||
val isOpenGroupInbox: Boolean
|
||||
get() = GroupUtil.isOpenGroupInbox(address)
|
||||
val isContact: Boolean
|
||||
get() = !isGroup
|
||||
|
||||
|
@ -8,12 +8,18 @@ import kotlin.jvm.Throws
|
||||
object GroupUtil {
|
||||
const val CLOSED_GROUP_PREFIX = "__textsecure_group__!"
|
||||
const val OPEN_GROUP_PREFIX = "__loki_public_chat_group__!"
|
||||
const val OPEN_GROUP_INBOX_PREFIX = "__loki_public_chat_group_inbox__!"
|
||||
|
||||
@JvmStatic
|
||||
fun getEncodedOpenGroupID(groupID: ByteArray): String {
|
||||
return OPEN_GROUP_PREFIX + Hex.toStringCondensed(groupID)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getEncodedOpenGroupInboxID(groupInboxID: ByteArray): String {
|
||||
return OPEN_GROUP_INBOX_PREFIX + Hex.toStringCondensed(groupInboxID)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getEncodedClosedGroupID(groupID: ByteArray): String {
|
||||
return CLOSED_GROUP_PREFIX + Hex.toStringCondensed(groupID)
|
||||
@ -46,7 +52,8 @@ object GroupUtil {
|
||||
}
|
||||
|
||||
fun isEncodedGroup(groupId: String): Boolean {
|
||||
return groupId.startsWith(CLOSED_GROUP_PREFIX) || groupId.startsWith(OPEN_GROUP_PREFIX)
|
||||
return groupId.startsWith(CLOSED_GROUP_PREFIX) || groupId.startsWith(OPEN_GROUP_PREFIX) ||
|
||||
groupId.startsWith(OPEN_GROUP_INBOX_PREFIX)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@ -54,6 +61,11 @@ object GroupUtil {
|
||||
return groupId.startsWith(OPEN_GROUP_PREFIX)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun isOpenGroupInbox(groupId: String): Boolean {
|
||||
return groupId.startsWith(OPEN_GROUP_INBOX_PREFIX)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun isClosedGroup(groupId: String): Boolean {
|
||||
return groupId.startsWith(CLOSED_GROUP_PREFIX)
|
||||
|
Loading…
x
Reference in New Issue
Block a user