feat: Add Session Id blinding

Including modified version of lazysodium-android to expose missing libsodium functions, we could build from a fork which we still need to setup.
This commit is contained in:
ceokot
2022-03-25 05:34:31 +02:00
parent 2445418e3e
commit 85456b5ea2
28 changed files with 1097 additions and 54 deletions

View File

@@ -104,7 +104,8 @@ dependencies {
implementation project(":libsession")
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinxJsonVersion"
implementation "org.whispersystems:curve25519-java:$curve25519Version"
implementation 'com.goterl:lazysodium-android:5.0.2@aar'
implementation project(":liblazysodium")
// implementation 'com.goterl:lazysodium-android:5.0.2@aar'
implementation "net.java.dev.jna:jna:5.8.0@aar"
implementation "com.google.protobuf:protobuf-java:$protobufVersion"
implementation "com.fasterxml.jackson.core:jackson-databind:$jacksonDatabindVersion"

View File

@@ -0,0 +1,28 @@
package network.loki.messenger
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.goterl.lazysodium.utils.Key
import com.goterl.lazysodium.utils.KeyPair
import org.hamcrest.CoreMatchers.equalTo
import org.hamcrest.MatcherAssert.assertThat
import org.junit.Test
import org.junit.runner.RunWith
import org.session.libsession.messaging.utilities.SodiumUtilities
@RunWith(AndroidJUnit4::class)
class SodiumUtilitiesTest {
private val serverPublicKey = "c3b3c6f32f0ab5a57f853cc4f30f5da7fda5624b0c77b3fb0829de562ada081d"
private val pubKey = Key.fromHexString("bac6e71efd7dfa4a83c98ed24f254ab2c267f9ccdb172a5280a0444ad24e89cc")
private val secKey = Key.fromHexString("c010d89eccbaf5d1c6d19df766c6eedf965d4a28a56f87c9fc819edb59896dd9")
@Test
fun blindedKeyPair() {
val blindedKey = "98932d4bccbe595a8789d7eb1629cefc483a0eaddc7e20e8fe5c771efafd9af5"
val keyPair = SodiumUtilities.blindedKeyPair(serverPublicKey, KeyPair(pubKey, secKey))!!
assertThat(keyPair.publicKey.asHexString.lowercase(), equalTo(blindedKey))
}
}

View File

@@ -57,7 +57,7 @@ import org.session.libsession.messaging.messages.control.DataExtractionNotificat
import org.session.libsession.messaging.messages.signal.OutgoingMediaMessage
import org.session.libsession.messaging.messages.signal.OutgoingTextMessage
import org.session.libsession.messaging.messages.visible.VisibleMessage
import org.session.libsession.messaging.open_groups.OpenGroupAPIV2
import org.session.libsession.messaging.open_groups.OpenGroupApiV4
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
@@ -500,7 +500,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
private fun getLatestOpenGroupInfoIfNeeded() {
val openGroup = lokiThreadDb.getOpenGroupChat(viewModel.threadId) ?: return
OpenGroupAPIV2.getMemberCount(openGroup.room, openGroup.server).successUi { updateSubtitle() }
OpenGroupApiV4.getMemberCount(openGroup.room, openGroup.server).successUi { updateSubtitle() }
}
// called from onCreate

View File

@@ -7,7 +7,7 @@ import android.view.View
import android.widget.LinearLayout
import network.loki.messenger.databinding.ViewMentionCandidateBinding
import org.session.libsession.messaging.mentions.Mention
import org.session.libsession.messaging.open_groups.OpenGroupAPIV2
import org.session.libsession.messaging.open_groups.OpenGroupApiV4
import org.thoughtcrime.securesms.mms.GlideRequests
class MentionCandidateView : LinearLayout {
@@ -34,7 +34,7 @@ class MentionCandidateView : LinearLayout {
profilePictureView.glide = glide!!
profilePictureView.update()
if (openGroupServer != null && openGroupRoom != null) {
val isUserModerator = OpenGroupAPIV2.isUserModerator(mentionCandidate.publicKey, openGroupRoom!!, openGroupServer!!)
val isUserModerator = OpenGroupApiV4.isUserModerator(mentionCandidate.publicKey, openGroupRoom!!, openGroupServer!!)
moderatorIconImageView.visibility = if (isUserModerator) View.VISIBLE else View.GONE
} else {
moderatorIconImageView.visibility = View.GONE

View File

@@ -7,7 +7,7 @@ import android.view.View
import android.widget.RelativeLayout
import network.loki.messenger.databinding.ViewMentionCandidateV2Binding
import org.session.libsession.messaging.mentions.Mention
import org.session.libsession.messaging.open_groups.OpenGroupAPIV2
import org.session.libsession.messaging.open_groups.OpenGroupApiV4
import org.thoughtcrime.securesms.mms.GlideRequests
class MentionCandidateView : RelativeLayout {
@@ -34,7 +34,7 @@ class MentionCandidateView : RelativeLayout {
profilePictureView.glide = glide!!
profilePictureView.update()
if (openGroupServer != null && openGroupRoom != null) {
val isUserModerator = OpenGroupAPIV2.isUserModerator(candidate.publicKey, openGroupRoom!!, openGroupServer!!)
val isUserModerator = OpenGroupApiV4.isUserModerator(candidate.publicKey, openGroupRoom!!, openGroupServer!!)
moderatorIconImageView.visibility = if (isUserModerator) View.VISIBLE else View.GONE
} else {
moderatorIconImageView.visibility = View.GONE

View File

@@ -5,7 +5,7 @@ import android.view.ActionMode
import android.view.Menu
import android.view.MenuItem
import network.loki.messenger.R
import org.session.libsession.messaging.open_groups.OpenGroupAPIV2
import org.session.libsession.messaging.open_groups.OpenGroupApiV4
import org.session.libsession.utilities.TextSecurePreferences
import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2
import org.thoughtcrime.securesms.conversation.v2.ConversationAdapter
@@ -41,13 +41,13 @@ class ConversationActionModeCallback(private val adapter: ConversationAdapter, p
if (!ConversationActivityV2.IS_UNSEND_REQUESTS_ENABLED) {
if (openGroup == null) { return true }
if (allSentByCurrentUser) { return true }
return OpenGroupAPIV2.isUserModerator(userPublicKey, openGroup.room, openGroup.server)
return OpenGroupApiV4.isUserModerator(userPublicKey, openGroup.room, openGroup.server)
}
val allReceivedByCurrentUser = selectedItems.all { !it.isOutgoing }
if (openGroup == null) { return allSentByCurrentUser || allReceivedByCurrentUser }
if (allSentByCurrentUser) { return true }
return OpenGroupAPIV2.isUserModerator(userPublicKey, openGroup.room, openGroup.server)
return OpenGroupApiV4.isUserModerator(userPublicKey, openGroup.room, openGroup.server)
}
fun userCanBanSelectedUsers(): Boolean {
if (openGroup == null) { return false }
@@ -55,7 +55,7 @@ class ConversationActionModeCallback(private val adapter: ConversationAdapter, p
if (anySentByCurrentUser) { return false } // Users can't ban themselves
val selectedUsers = selectedItems.map { it.recipient.address.toString() }.toSet()
if (selectedUsers.size > 1) { return false }
return OpenGroupAPIV2.isUserModerator(userPublicKey, openGroup.room, openGroup.server)
return OpenGroupApiV4.isUserModerator(userPublicKey, openGroup.room, openGroup.server)
}
// Delete message
menu.findItem(R.id.menu_context_delete_message).isVisible = userCanDeleteSelectedItems()

View File

@@ -24,7 +24,7 @@ import dagger.hilt.android.AndroidEntryPoint
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.OpenGroupAPIV2
import org.session.libsession.messaging.open_groups.OpenGroupApiV4
import org.session.libsession.utilities.ViewUtil
import org.session.libsignal.utilities.ThreadUtils
import org.thoughtcrime.securesms.ApplicationContext
@@ -127,7 +127,7 @@ class VisibleMessageView : LinearLayout {
}
if (thread.isOpenGroupRecipient) {
val openGroup = lokiThreadDb.getOpenGroupChat(threadID) ?: return
val isModerator = OpenGroupAPIV2.isUserModerator(senderSessionID, openGroup.room, openGroup.server)
val isModerator = OpenGroupApiV4.isUserModerator(senderSessionID, openGroup.room, openGroup.server)
binding.moderatorIconImageView.visibility = if (isModerator) View.VISIBLE else View.INVISIBLE
} else {
binding.moderatorIconImageView.visibility = View.INVISIBLE

View File

@@ -4,19 +4,19 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
import org.session.libsession.messaging.open_groups.OpenGroupAPIV2
import org.session.libsession.messaging.open_groups.OpenGroupApiV4
import org.thoughtcrime.securesms.util.State
typealias DefaultGroups = List<OpenGroupAPIV2.DefaultGroup>
typealias DefaultGroups = List<OpenGroupApiV4.DefaultGroup>
typealias GroupState = State<DefaultGroups>
class DefaultGroupsViewModel : ViewModel() {
init {
OpenGroupAPIV2.getDefaultRoomsIfNeeded()
OpenGroupApiV4.getDefaultRoomsIfNeeded()
}
val defaultRooms = OpenGroupAPIV2.defaultRooms.map<DefaultGroups, GroupState> {
val defaultRooms = OpenGroupApiV4.defaultRooms.map<DefaultGroups, GroupState> {
State.Success(it)
}.onStart {
emit(State.Loading)

View File

@@ -25,7 +25,7 @@ import network.loki.messenger.R
import network.loki.messenger.databinding.ActivityJoinPublicChatBinding
import network.loki.messenger.databinding.FragmentEnterChatUrlBinding
import okhttp3.HttpUrl
import org.session.libsession.messaging.open_groups.OpenGroupAPIV2.DefaultGroup
import org.session.libsession.messaging.open_groups.OpenGroupApiV4.DefaultGroup
import org.session.libsession.utilities.Address
import org.session.libsession.utilities.GroupUtil
import org.session.libsession.utilities.recipients.Recipient

View File

@@ -4,18 +4,17 @@ import android.content.Context
import androidx.annotation.WorkerThread
import okhttp3.HttpUrl
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.open_groups.OpenGroupAPIV2
import org.session.libsession.messaging.open_groups.OpenGroupApiV4
import org.session.libsession.messaging.open_groups.OpenGroupV2
import org.session.libsession.messaging.sending_receiving.pollers.OpenGroupPollerV2
import org.session.libsession.messaging.sending_receiving.pollers.OpenGroupPollerV4
import org.session.libsession.utilities.Util
import org.session.libsignal.utilities.ThreadUtils
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
import org.thoughtcrime.securesms.util.BitmapUtil
import java.util.concurrent.Executors
object OpenGroupManager {
private val executorService = Executors.newScheduledThreadPool(4)
private var pollers = mutableMapOf<String, OpenGroupPollerV2>() // One for each server
private var pollers = mutableMapOf<String, OpenGroupPollerV4>() // One for each server
private var isPolling = false
val isAllCaughtUp: Boolean
@@ -42,7 +41,7 @@ object OpenGroupManager {
val servers = storage.getAllV2OpenGroups().values.map { it.server }.toSet()
servers.forEach { server ->
pollers[server]?.stop() // Shouldn't be necessary
val poller = OpenGroupPollerV2(server, executorService)
val poller = OpenGroupPollerV4(server, executorService)
poller.startIfNeeded()
pollers[server] = poller
}
@@ -68,18 +67,20 @@ object OpenGroupManager {
// Store the public key
storage.setOpenGroupPublicKey(server,publicKey)
// Get an auth token
OpenGroupAPIV2.getAuthToken(room, server).get()
OpenGroupApiV4.getAuthToken(room, server).get()
// Get capabilities
val capabilities = OpenGroupApiV4.getCapabilities(room, server).get()
// Get group info
val info = OpenGroupAPIV2.getInfo(room, server).get()
val info = OpenGroupApiV4.getInfo(room, server).get()
// Create the group locally if not available already
if (threadID < 0) {
threadID = GroupManager.createOpenGroup(openGroupID, context, null, info.name).threadId
}
val openGroup = OpenGroupV2(server, room, info.name, publicKey)
val openGroup = OpenGroupV2(server, room, info.name, publicKey, capabilities)
threadDB.setOpenGroupChat(openGroup, threadID)
// Start the poller if needed
pollers[server]?.startIfNeeded() ?: run {
val poller = OpenGroupPollerV2(server, executorService)
val poller = OpenGroupPollerV4(server, executorService)
Util.runOnMain { poller.startIfNeeded() }
pollers[server] = poller
}

View File

@@ -4,6 +4,7 @@ import android.content.Context
import androidx.annotation.WorkerThread
import org.greenrobot.eventbus.EventBus
import org.session.libsession.messaging.open_groups.OpenGroupAPIV2
import org.session.libsession.messaging.open_groups.OpenGroupApiV4
import org.session.libsession.utilities.GroupUtil
import org.session.libsession.utilities.recipients.Recipient
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
@@ -29,8 +30,8 @@ object OpenGroupUtilities {
throw IllegalStateException("Attempt to update open group info for non-existent DB record: $groupId")
}
val info = OpenGroupAPIV2.getInfo(room, server).get() // store info again?
OpenGroupAPIV2.getMemberCount(room, server).get()
val info = OpenGroupApiV4.getInfo(room, server).get() // store info again?
OpenGroupApiV4.getMemberCount(room, server).get()
EventBus.getDefault().post(GroupInfoUpdatedEvent(server, room = room))
}

View File

@@ -3,14 +3,20 @@ package org.thoughtcrime.securesms.notifications
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import androidx.work.*
import androidx.work.Constraints
import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.NetworkType
import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkManager
import androidx.work.Worker
import androidx.work.WorkerParameters
import nl.komponents.kovenant.Promise
import nl.komponents.kovenant.all
import nl.komponents.kovenant.functional.map
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.jobs.MessageReceiveJob
import org.session.libsession.messaging.sending_receiving.pollers.ClosedGroupPollerV2
import org.session.libsession.messaging.sending_receiving.pollers.OpenGroupPollerV2
import org.session.libsession.messaging.sending_receiving.pollers.OpenGroupPollerV4
import org.session.libsession.snode.SnodeAPI
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsignal.utilities.Log
@@ -68,9 +74,9 @@ class BackgroundPollWorker(val context: Context, params: WorkerParameters) : Wor
val v2OpenGroupServers = v2OpenGroups.map { it.value.server }.toSet()
for (server in v2OpenGroupServers) {
val poller = OpenGroupPollerV2(server, null)
val poller = OpenGroupPollerV4(server, null)
poller.hasStarted = true
promises.add(poller.poll(true))
promises.add(poller.poll())
}
// Wait until all the promises are resolved

View File

@@ -7,7 +7,7 @@ import org.session.libsession.messaging.messages.control.UnsendRequest
import org.session.libsession.messaging.messages.signal.OutgoingTextMessage
import org.session.libsession.messaging.messages.visible.OpenGroupInvitation
import org.session.libsession.messaging.messages.visible.VisibleMessage
import org.session.libsession.messaging.open_groups.OpenGroupAPIV2
import org.session.libsession.messaging.open_groups.OpenGroupApiV4
import org.session.libsession.messaging.sending_receiving.MessageSender
import org.session.libsession.snode.SnodeAPI
import org.session.libsession.utilities.Address
@@ -154,7 +154,7 @@ class DefaultConversationRepository @Inject constructor(
val openGroup = lokiThreadDb.getOpenGroupChat(threadId)
if (openGroup != null) {
lokiMessageDb.getServerID(message.id, !message.isMms)?.let { messageServerID ->
OpenGroupAPIV2.deleteMessage(messageServerID, openGroup.room, openGroup.server)
OpenGroupApiV4.deleteMessage(messageServerID, openGroup.room, openGroup.server)
.success {
messageDataProvider.deleteMessage(message.id, !message.isMms)
continuation.resume(ResultOf.Success(Unit))
@@ -206,7 +206,7 @@ class DefaultConversationRepository @Inject constructor(
messageServerIDs[messageServerID] = message
}
for ((messageServerID, message) in messageServerIDs) {
OpenGroupAPIV2.deleteMessage(messageServerID, openGroup.room, openGroup.server)
OpenGroupApiV4.deleteMessage(messageServerID, openGroup.room, openGroup.server)
.success {
messageDataProvider.deleteMessage(message.id, !message.isMms)
}.fail { error ->
@@ -229,7 +229,7 @@ class DefaultConversationRepository @Inject constructor(
suspendCoroutine { continuation ->
val sessionID = recipient.address.toString()
val openGroup = lokiThreadDb.getOpenGroupChat(threadId)!!
OpenGroupAPIV2.ban(sessionID, openGroup.room, openGroup.server)
OpenGroupApiV4.ban(sessionID, openGroup.room, openGroup.server)
.success {
continuation.resume(ResultOf.Success(Unit))
}.fail { error ->
@@ -241,7 +241,7 @@ class DefaultConversationRepository @Inject constructor(
suspendCoroutine { continuation ->
val sessionID = recipient.address.toString()
val openGroup = lokiThreadDb.getOpenGroupChat(threadId)!!
OpenGroupAPIV2.banAndDeleteAll(sessionID, openGroup.room, openGroup.server)
OpenGroupApiV4.banAndDeleteAll(sessionID, openGroup.room, openGroup.server)
.success {
continuation.resume(ResultOf.Success(Unit))
}.fail { error ->