diff --git a/app/src/main/java/org/thoughtcrime/securesms/BaseActionBarActivity.java b/app/src/main/java/org/thoughtcrime/securesms/BaseActionBarActivity.java index c43d406575..a99fe83430 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/BaseActionBarActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/BaseActionBarActivity.java @@ -30,13 +30,15 @@ public abstract class BaseActionBarActivity extends AppCompatActivity { private static final String TAG = BaseActionBarActivity.class.getSimpleName(); public ThemeState currentThemeState; + private Resources.Theme modifiedTheme; + private TextSecurePreferences getPreferences() { ApplicationContext appContext = (ApplicationContext) getApplicationContext(); return appContext.textSecurePreferences; } @StyleRes - public int getDesiredTheme() { + private int getDesiredTheme() { ThemeState themeState = ActivityUtilitiesKt.themeState(getPreferences()); int userSelectedTheme = themeState.getTheme(); @@ -58,7 +60,7 @@ public abstract class BaseActionBarActivity extends AppCompatActivity { } @StyleRes @Nullable - public Integer getAccentTheme() { + private Integer getAccentTheme() { if (!getPreferences().hasPreference(SELECTED_ACCENT_COLOR)) return null; ThemeState themeState = ActivityUtilitiesKt.themeState(getPreferences()); return themeState.getAccentStyle(); @@ -66,8 +68,12 @@ public abstract class BaseActionBarActivity extends AppCompatActivity { @Override public Resources.Theme getTheme() { + if (modifiedTheme != null) { + return modifiedTheme; + } + // New themes - Resources.Theme modifiedTheme = super.getTheme(); + modifiedTheme = super.getTheme(); modifiedTheme.applyStyle(getDesiredTheme(), true); Integer accentTheme = getAccentTheme(); if (accentTheme != null) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/audio/AudioSlidePlayer.java b/app/src/main/java/org/thoughtcrime/securesms/audio/AudioSlidePlayer.java index 61a92105aa..ef404bb070 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/audio/AudioSlidePlayer.java +++ b/app/src/main/java/org/thoughtcrime/securesms/audio/AudioSlidePlayer.java @@ -80,6 +80,11 @@ public class AudioSlidePlayer implements SensorEventListener { } } + @Nullable + public synchronized static AudioSlidePlayer getInstance() { + return playing.orNull(); + } + private AudioSlidePlayer(@NonNull Context context, @NonNull AudioSlide slide, @NonNull Listener listener) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt index 76bf7b875f..187ded770e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt @@ -61,7 +61,6 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import network.loki.messenger.R import network.loki.messenger.databinding.ActivityConversationV2Binding -import network.loki.messenger.databinding.ViewVisibleMessageBinding import network.loki.messenger.libsession_util.util.ExpiryMode import nl.komponents.kovenant.ui.successUi import org.session.libsession.messaging.MessagingModuleConfiguration @@ -1558,8 +1557,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe if (indexInAdapter < 0 || indexInAdapter >= adapter.itemCount) { return } val viewHolder = binding?.conversationRecyclerView?.findViewHolderForAdapterPosition(indexInAdapter) as? ConversationAdapter.VisibleMessageViewHolder ?: return - val visibleMessageView = ViewVisibleMessageBinding.bind(viewHolder.view).visibleMessageView - visibleMessageView.playVoiceMessage() + viewHolder.view.playVoiceMessage() } override fun sendMessage() { diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationAdapter.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationAdapter.kt index 7b01eba71e..d051d7d93c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationAdapter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationAdapter.kt @@ -5,9 +5,7 @@ import android.content.Intent import android.database.Cursor import android.util.SparseArray import android.util.SparseBooleanArray -import android.view.LayoutInflater import android.view.MotionEvent -import android.view.View import android.view.ViewGroup import androidx.annotation.WorkerThread import androidx.core.util.getOrDefault @@ -20,14 +18,11 @@ import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.isActive import kotlinx.coroutines.launch import network.loki.messenger.R -import network.loki.messenger.databinding.ViewVisibleMessageBinding import org.session.libsession.messaging.contacts.Contact -import org.session.libsession.utilities.TextSecurePreferences import org.thoughtcrime.securesms.conversation.v2.messages.ControlMessageView import org.thoughtcrime.securesms.conversation.v2.messages.VisibleMessageView import org.thoughtcrime.securesms.conversation.v2.messages.VisibleMessageViewDelegate import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter -import org.thoughtcrime.securesms.database.MmsSmsColumns import org.thoughtcrime.securesms.database.model.MessageRecord import org.thoughtcrime.securesms.dependencies.DatabaseComponent import org.thoughtcrime.securesms.mms.GlideRequests @@ -90,7 +85,7 @@ class ConversationAdapter( } } - class VisibleMessageViewHolder(val view: View) : ViewHolder(view) + class VisibleMessageViewHolder(val view: VisibleMessageView) : ViewHolder(view) class ControlMessageViewHolder(val view: ControlMessageView) : ViewHolder(view) override fun getItemViewType(cursor: Cursor): Int { @@ -103,7 +98,7 @@ class ConversationAdapter( @Suppress("NAME_SHADOWING") val viewType = ViewType.allValues[viewType] return when (viewType) { - ViewType.Visible -> VisibleMessageViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.view_visible_message, parent, false)) + ViewType.Visible -> VisibleMessageViewHolder(VisibleMessageView(context)) ViewType.Control -> ControlMessageViewHolder(ControlMessageView(context)) else -> throw IllegalStateException("Unexpected view type: $viewType.") } @@ -115,7 +110,7 @@ class ConversationAdapter( val messageBefore = getMessageBefore(position, cursor) when (viewHolder) { is VisibleMessageViewHolder -> { - val visibleMessageView = ViewVisibleMessageBinding.bind(viewHolder.view).visibleMessageView + val visibleMessageView = viewHolder.view val isSelected = selectedItems.contains(message) visibleMessageView.snIsSelected = isSelected visibleMessageView.indexInAdapter = position @@ -181,7 +176,7 @@ class ConversationAdapter( override fun onItemViewRecycled(viewHolder: ViewHolder?) { when (viewHolder) { - is VisibleMessageViewHolder -> viewHolder.view.findViewById(R.id.visibleMessageView).recycle() + is VisibleMessageViewHolder -> viewHolder.view.recycle() is ControlMessageViewHolder -> viewHolder.view.recycle() } super.onItemViewRecycled(viewHolder) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModel.kt index 80d6df87fe..1a036eee11 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModel.kt @@ -27,10 +27,11 @@ import org.session.libsession.utilities.Address import org.session.libsession.utilities.recipients.Recipient import org.session.libsignal.utilities.IdPrefix import org.session.libsignal.utilities.Log -import org.thoughtcrime.securesms.database.MmsSmsDatabase +import org.thoughtcrime.securesms.audio.AudioSlidePlayer import org.thoughtcrime.securesms.database.Storage import org.thoughtcrime.securesms.database.model.MessageRecord +import org.thoughtcrime.securesms.database.model.MmsMessageRecord import org.thoughtcrime.securesms.repository.ConversationRepository import java.util.UUID @@ -103,6 +104,13 @@ class ConversationViewModel( } } + override fun onCleared() { + super.onCleared() + + // Stop all voice message when exiting this page + AudioSlidePlayer.stopAll() + } + fun saveDraft(text: String) { GlobalScope.launch(Dispatchers.IO) { repository.saveDraft(threadId, text) @@ -142,10 +150,20 @@ class ConversationViewModel( } fun deleteLocally(message: MessageRecord) { + stopPlayingAudioMessage(message) val recipient = recipient ?: return Log.w("Loki", "Recipient was null for delete locally action") repository.deleteLocally(recipient, message) } + /** + * Stops audio player if its current playing is the one given in the message. + */ + private fun stopPlayingAudioMessage(message: MessageRecord) { + val mmsMessage = message as? MmsMessageRecord ?: return + val audioSlide = mmsMessage.slideDeck.audioSlide ?: return + AudioSlidePlayer.getInstance()?.takeIf { it.audioSlide == audioSlide }?.stop() + } + fun setRecipientApproved() { val recipient = recipient ?: return Log.w("Loki", "Recipient was null for set approved action") repository.setApproved(recipient, true) @@ -153,10 +171,12 @@ class ConversationViewModel( fun deleteForEveryone(message: MessageRecord) = viewModelScope.launch { val recipient = recipient ?: return@launch Log.w("Loki", "Recipient was null for delete for everyone - aborting delete operation.") + stopPlayingAudioMessage(message) repository.deleteForEveryone(threadId, recipient, message) .onSuccess { Log.d("Loki", "Deleted message ${message.id} ") + stopPlayingAudioMessage(message) } .onFailure { Log.w("Loki", "FAILED TO delete message ${message.id} ") diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/ControlMessageView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/ControlMessageView.kt index 88df4c4508..1177b4afc9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/ControlMessageView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/ControlMessageView.kt @@ -25,16 +25,15 @@ class ControlMessageView : LinearLayout { private val TAG = "ControlMessageView" - private lateinit var binding: ViewControlMessageBinding + private val binding = ViewControlMessageBinding.inflate(LayoutInflater.from(context), this, true) - constructor(context: Context) : super(context) { initialize() } - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { initialize() } - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { initialize() } + constructor(context: Context) : super(context) + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) @Inject lateinit var disappearingMessages: DisappearingMessages - private fun initialize() { - binding = ViewControlMessageBinding.inflate(LayoutInflater.from(context), this, true) + init { layoutParams = RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/QuoteView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/QuoteView.kt index 4e91400430..2e0dae6b0d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/QuoteView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/QuoteView.kt @@ -72,7 +72,7 @@ class QuoteView @JvmOverloads constructor(context: Context, attrs: AttributeSet? // Author val author = contactDb.getContactWithSessionID(authorPublicKey) val localNumber = TextSecurePreferences.getLocalNumber(context) - val quoteIsLocalUser = localNumber != null && localNumber == author?.sessionID + val quoteIsLocalUser = localNumber != null && authorPublicKey == localNumber val authorDisplayName = if (quoteIsLocalUser) context.getString(R.string.QuoteView_you) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt index 64017e2ad9..ec26e39986 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt @@ -11,8 +11,10 @@ import android.os.Looper import android.util.AttributeSet import android.view.Gravity import android.view.HapticFeedbackConstants +import android.view.LayoutInflater import android.view.MotionEvent import android.view.View +import android.view.ViewGroup import android.widget.FrameLayout import android.widget.LinearLayout import androidx.annotation.ColorInt @@ -26,17 +28,17 @@ import androidx.core.view.isVisible import androidx.core.view.marginBottom import dagger.hilt.android.AndroidEntryPoint import network.loki.messenger.R +import network.loki.messenger.databinding.ViewEmojiReactionsBinding import network.loki.messenger.databinding.ViewVisibleMessageBinding +import network.loki.messenger.databinding.ViewstubVisibleMessageMarkerContainerBinding import org.session.libsession.messaging.contacts.Contact 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.TextSecurePreferences import org.session.libsession.utilities.ViewUtil import org.session.libsession.utilities.getColorFromAttr import org.session.libsession.utilities.modifyLayoutParams import org.session.libsignal.utilities.IdPrefix -import org.session.libsignal.utilities.Log import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2 import org.thoughtcrime.securesms.database.LastSentTimestampCache import org.thoughtcrime.securesms.database.LokiAPIDatabase @@ -65,7 +67,7 @@ import kotlin.math.sqrt private const val TAG = "VisibleMessageView" @AndroidEntryPoint -class VisibleMessageView : LinearLayout { +class VisibleMessageView : FrameLayout { private var replyDisabled: Boolean = false @Inject lateinit var threadDb: ThreadDatabase @Inject lateinit var lokiThreadDb: LokiThreadDatabase @@ -75,7 +77,16 @@ class VisibleMessageView : LinearLayout { @Inject lateinit var mmsDb: MmsDatabase @Inject lateinit var lastSentTimestampCache: LastSentTimestampCache - private val binding by lazy { ViewVisibleMessageBinding.bind(this) } + private val binding = ViewVisibleMessageBinding.inflate(LayoutInflater.from(context), this, true) + + private val markerContainerBinding = lazy(LazyThreadSafetyMode.NONE) { + ViewstubVisibleMessageMarkerContainerBinding.bind(binding.unreadMarkerContainerStub.inflate()) + } + + private val emojiReactionsBinding = lazy(LazyThreadSafetyMode.NONE) { + ViewEmojiReactionsBinding.bind(binding.emojiReactionsView.inflate()) + } + private val swipeToReplyIcon = ContextCompat.getDrawable(context, R.drawable.ic_baseline_reply_24)!!.mutate() private val swipeToReplyIconRect = Rect() private var dx = 0.0f @@ -94,7 +105,7 @@ class VisibleMessageView : LinearLayout { var onPress: ((event: MotionEvent) -> Unit)? = null var onSwipeToReply: (() -> Unit)? = null var onLongPress: (() -> Unit)? = null - val messageContentView: VisibleMessageContentView by lazy { binding.messageContentView.root } + val messageContentView: VisibleMessageContentView get() = binding.messageContentView.root companion object { const val swipeToReplyThreshold = 64.0f // dp @@ -108,12 +119,7 @@ class VisibleMessageView : LinearLayout { constructor(context: Context, attrs: AttributeSet) : super(context, attrs) constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) - override fun onFinishInflate() { - super.onFinishInflate() - initialize() - } - - private fun initialize() { + init { isHapticFeedbackEnabled = true setWillNotDraw(false) binding.root.disableClipping() @@ -121,7 +127,11 @@ class VisibleMessageView : LinearLayout { binding.messageInnerContainer.disableClipping() binding.messageInnerLayout.disableClipping() binding.messageContentView.root.disableClipping() + + // Default layout params + layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) } + // endregion // region Updating @@ -203,7 +213,13 @@ class VisibleMessageView : LinearLayout { binding.senderNameTextView.text = contact?.displayName(contactContext) ?: senderSessionID // Unread marker - binding.unreadMarkerContainer.isVisible = lastSeen != -1L && message.timestamp > lastSeen && (previous == null || previous.timestamp <= lastSeen) && !message.isOutgoing + val shouldShowUnreadMarker = lastSeen != -1L && message.timestamp > lastSeen && (previous == null || previous.timestamp <= lastSeen) && !message.isOutgoing + if (shouldShowUnreadMarker) { + markerContainerBinding.value.root.isVisible = true + } else if (markerContainerBinding.isInitialized()) { + // Only need to hide the binding when the binding is inflated. (default is gone) + markerContainerBinding.value.root.isVisible = false + } // Date break val showDateBreak = isStartOfMessageCluster || snIsSelected @@ -214,21 +230,22 @@ class VisibleMessageView : LinearLayout { showStatusMessage(message) // Emoji Reactions - val emojiLayoutParams = binding.emojiReactionsView.root.layoutParams as ConstraintLayout.LayoutParams - emojiLayoutParams.horizontalBias = if (message.isOutgoing) 1f else 0f - binding.emojiReactionsView.root.layoutParams = emojiLayoutParams - if (message.reactions.isNotEmpty()) { val capabilities = lokiThreadDb.getOpenGroupChat(threadID)?.server?.let { lokiApiDb.getServerCapabilities(it) } if (capabilities.isNullOrEmpty() || capabilities.contains(OpenGroupApi.Capability.REACTIONS.name.lowercase())) { - binding.emojiReactionsView.root.setReactions(message.id, message.reactions, message.isOutgoing, delegate) - binding.emojiReactionsView.root.isVisible = true - } else { - binding.emojiReactionsView.root.isVisible = false + emojiReactionsBinding.value.root.let { root -> + root.setReactions(message.id, message.reactions, message.isOutgoing, delegate) + root.isVisible = true + (root.layoutParams as ConstraintLayout.LayoutParams).apply { + horizontalBias = if (message.isOutgoing) 1f else 0f + } + } + } else if (emojiReactionsBinding.isInitialized()) { + emojiReactionsBinding.value.root.isVisible = false } } - else { - binding.emojiReactionsView.root.isVisible = false + else if (emojiReactionsBinding.isInitialized()) { + emojiReactionsBinding.value.root.isVisible = false } // Populate content view diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VoiceMessageView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VoiceMessageView.kt index 2b829af152..06a5168a99 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VoiceMessageView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VoiceMessageView.kt @@ -68,7 +68,7 @@ class VoiceMessageView : RelativeLayout, AudioSlidePlayer.Listener { return } - val player = AudioSlidePlayer.createFor(context, audio, this) + val player = AudioSlidePlayer.createFor(context.applicationContext, audio, this) this.player = player (audio.asAttachment() as? DatabaseAttachment)?.let { attachment -> diff --git a/app/src/main/java/org/thoughtcrime/securesms/dependencies/AppModule.kt b/app/src/main/java/org/thoughtcrime/securesms/dependencies/AppModule.kt index 936e4f287f..a9a72e7665 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/dependencies/AppModule.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/dependencies/AppModule.kt @@ -19,11 +19,11 @@ abstract class AppModule { @Binds abstract fun bindConversationRepository(repository: DefaultConversationRepository): ConversationRepository - } @EntryPoint @InstallIn(SingletonComponent::class) interface AppComponent { fun getPrefs(): TextSecurePreferences + } \ No newline at end of file diff --git a/app/src/main/res/layout/view_visible_message.xml b/app/src/main/res/layout/view_visible_message.xml index 19f9b4f9ad..1e099e319e 100644 --- a/app/src/main/res/layout/view_visible_message.xml +++ b/app/src/main/res/layout/view_visible_message.xml @@ -1,5 +1,5 @@ - - - - - - + android:id="@+id/unreadMarkerContainerStub" + android:layout="@layout/viewstub_visible_message_marker_container" /> - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/viewstub_visible_message_marker_container.xml b/app/src/main/res/layout/viewstub_visible_message_marker_container.xml new file mode 100644 index 0000000000..d9a1cc15d0 --- /dev/null +++ b/app/src/main/res/layout/viewstub_visible_message_marker_container.xml @@ -0,0 +1,38 @@ + + + + + + + + + diff --git a/libsession/src/main/java/org/session/libsession/messaging/jobs/BackgroundGroupAddJob.kt b/libsession/src/main/java/org/session/libsession/messaging/jobs/BackgroundGroupAddJob.kt index 20442e5594..f284f2539d 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/jobs/BackgroundGroupAddJob.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/jobs/BackgroundGroupAddJob.kt @@ -37,6 +37,7 @@ class BackgroundGroupAddJob(val joinUrl: String): Job { delegate?.handleJobFailed(this, dispatcherName, DuplicateGroupException()) return } + storage.addOpenGroup(openGroup.joinUrl()) storage.onOpenGroupAdded(openGroup.server, openGroup.room) } catch (e: Exception) { diff --git a/libsession/src/main/java/org/session/libsession/messaging/open_groups/OpenGroupApi.kt b/libsession/src/main/java/org/session/libsession/messaging/open_groups/OpenGroupApi.kt index a5203827ea..6e73c16f5e 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/open_groups/OpenGroupApi.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/open_groups/OpenGroupApi.kt @@ -273,7 +273,6 @@ object OpenGroupApi { val queryParameters: Map = mapOf(), val parameters: Any? = null, val headers: Map = mapOf(), - val isAuthRequired: Boolean = true, val body: ByteArray? = null, /** * Always `true` under normal circumstances. You might want to disable @@ -319,73 +318,72 @@ object OpenGroupApi { ?: return Promise.ofFail(Error.NoEd25519KeyPair) val urlRequest = urlBuilder.toString() val headers = request.headers.toMutableMap() - if (request.isAuthRequired) { - val nonce = sodium.nonce(16) - val timestamp = TimeUnit.MILLISECONDS.toSeconds(SnodeAPI.nowWithOffset) - var pubKey = "" - var signature = ByteArray(Sign.BYTES) - var bodyHash = ByteArray(0) - if (request.parameters != null) { - val parameterBytes = JsonUtil.toJson(request.parameters).toByteArray() - val parameterHash = ByteArray(GenericHash.BYTES_MAX) - if (sodium.cryptoGenericHash( - parameterHash, - parameterHash.size, - parameterBytes, - parameterBytes.size.toLong() - ) - ) { - bodyHash = parameterHash - } - } else if (request.body != null) { - val byteHash = ByteArray(GenericHash.BYTES_MAX) - if (sodium.cryptoGenericHash( - byteHash, - byteHash.size, - request.body, - request.body.size.toLong() - ) - ) { - bodyHash = byteHash - } - } - val messageBytes = Hex.fromStringCondensed(publicKey) - .plus(nonce) - .plus("$timestamp".toByteArray(Charsets.US_ASCII)) - .plus(request.verb.rawValue.toByteArray()) - .plus("/${request.endpoint.value}".toByteArray()) - .plus(bodyHash) - if (serverCapabilities.isEmpty() || serverCapabilities.contains(Capability.BLIND.name.lowercase())) { - SodiumUtilities.blindedKeyPair(publicKey, ed25519KeyPair)?.let { keyPair -> - pubKey = SessionId( - IdPrefix.BLINDED, - keyPair.publicKey.asBytes - ).hexString - signature = SodiumUtilities.sogsSignature( - messageBytes, - ed25519KeyPair.secretKey.asBytes, - keyPair.secretKey.asBytes, - keyPair.publicKey.asBytes - ) ?: return Promise.ofFail(Error.SigningFailed) - } ?: return Promise.ofFail(Error.SigningFailed) - } else { - pubKey = SessionId( - IdPrefix.UN_BLINDED, - ed25519KeyPair.publicKey.asBytes - ).hexString - sodium.cryptoSignDetached( - signature, - messageBytes, - messageBytes.size.toLong(), - ed25519KeyPair.secretKey.asBytes + val nonce = sodium.nonce(16) + val timestamp = TimeUnit.MILLISECONDS.toSeconds(SnodeAPI.nowWithOffset) + var pubKey = "" + var signature = ByteArray(Sign.BYTES) + var bodyHash = ByteArray(0) + if (request.parameters != null) { + val parameterBytes = JsonUtil.toJson(request.parameters).toByteArray() + val parameterHash = ByteArray(GenericHash.BYTES_MAX) + if (sodium.cryptoGenericHash( + parameterHash, + parameterHash.size, + parameterBytes, + parameterBytes.size.toLong() ) + ) { + bodyHash = parameterHash + } + } else if (request.body != null) { + val byteHash = ByteArray(GenericHash.BYTES_MAX) + if (sodium.cryptoGenericHash( + byteHash, + byteHash.size, + request.body, + request.body.size.toLong() + ) + ) { + bodyHash = byteHash } - headers["X-SOGS-Nonce"] = encodeBytes(nonce) - headers["X-SOGS-Timestamp"] = "$timestamp" - headers["X-SOGS-Pubkey"] = pubKey - headers["X-SOGS-Signature"] = encodeBytes(signature) } + val messageBytes = Hex.fromStringCondensed(publicKey) + .plus(nonce) + .plus("$timestamp".toByteArray(Charsets.US_ASCII)) + .plus(request.verb.rawValue.toByteArray()) + .plus("/${request.endpoint.value}".toByteArray()) + .plus(bodyHash) + if (serverCapabilities.isEmpty() || serverCapabilities.contains(Capability.BLIND.name.lowercase())) { + SodiumUtilities.blindedKeyPair(publicKey, ed25519KeyPair)?.let { keyPair -> + pubKey = SessionId( + IdPrefix.BLINDED, + keyPair.publicKey.asBytes + ).hexString + + signature = SodiumUtilities.sogsSignature( + messageBytes, + ed25519KeyPair.secretKey.asBytes, + keyPair.secretKey.asBytes, + keyPair.publicKey.asBytes + ) ?: return Promise.ofFail(Error.SigningFailed) + } ?: return Promise.ofFail(Error.SigningFailed) + } else { + pubKey = SessionId( + IdPrefix.UN_BLINDED, + ed25519KeyPair.publicKey.asBytes + ).hexString + sodium.cryptoSignDetached( + signature, + messageBytes, + messageBytes.size.toLong(), + ed25519KeyPair.secretKey.asBytes + ) + } + headers["X-SOGS-Nonce"] = encodeBytes(nonce) + headers["X-SOGS-Timestamp"] = "$timestamp" + headers["X-SOGS-Pubkey"] = pubKey + headers["X-SOGS-Signature"] = encodeBytes(signature) val requestBuilder = okhttp3.Request.Builder() .url(urlRequest) @@ -927,7 +925,7 @@ object OpenGroupApi { } fun getCapabilities(server: String): Promise { - val request = Request(verb = GET, room = null, server = server, endpoint = Endpoint.Capabilities, isAuthRequired = false) + val request = Request(verb = GET, room = null, server = server, endpoint = Endpoint.Capabilities) return getResponseBody(request).map { response -> JsonUtil.fromJson(response, Capabilities::class.java) } diff --git a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/ReceivedMessageHandler.kt b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/ReceivedMessageHandler.kt index e65472c1fe..6450d927a3 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/ReceivedMessageHandler.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/ReceivedMessageHandler.kt @@ -260,7 +260,7 @@ fun MessageReceiver.handleUnsendRequest(message: UnsendRequest): Long? { SnodeAPI.deleteMessage(author, listOf(serverHash)) } val deletedMessageId = messageDataProvider.updateMessageAsDeleted(timestamp, author) - if (!messageDataProvider.isOutgoingMessage(messageIdToDelete)) { + if (!messageDataProvider.isOutgoingMessage(timestamp)) { SSKEnvironment.shared.notificationManager.updateNotification(context) }