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 2e4b889235..1202e799fe 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 @@ -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.OpenGroupApiV4 +import org.session.libsession.messaging.open_groups.OpenGroupApi 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 - OpenGroupApiV4.getMemberCount(openGroup.room, openGroup.server).successUi { updateSubtitle() } + OpenGroupApi.getMemberCount(openGroup.room, openGroup.server).successUi { updateSubtitle() } } // called from onCreate diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/components/MentionCandidateView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/components/MentionCandidateView.kt index f77dce5a0e..53d4d4fc48 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/components/MentionCandidateView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/components/MentionCandidateView.kt @@ -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.OpenGroupApiV4 +import org.session.libsession.messaging.open_groups.OpenGroupApi 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 = OpenGroupApiV4.isUserModerator(mentionCandidate.publicKey, openGroupRoom!!, openGroupServer!!) + val isUserModerator = OpenGroupApi.isUserModerator(mentionCandidate.publicKey, openGroupRoom!!, openGroupServer!!) moderatorIconImageView.visibility = if (isUserModerator) View.VISIBLE else View.GONE } else { moderatorIconImageView.visibility = View.GONE diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/mentions/MentionCandidateView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/mentions/MentionCandidateView.kt index 4c2cc4dec0..2d205558a8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/mentions/MentionCandidateView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/mentions/MentionCandidateView.kt @@ -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.OpenGroupApiV4 +import org.session.libsession.messaging.open_groups.OpenGroupApi 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 = OpenGroupApiV4.isUserModerator(candidate.publicKey, openGroupRoom!!, openGroupServer!!) + val isUserModerator = OpenGroupApi.isUserModerator(candidate.publicKey, openGroupRoom!!, openGroupServer!!) moderatorIconImageView.visibility = if (isUserModerator) View.VISIBLE else View.GONE } else { moderatorIconImageView.visibility = View.GONE diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationActionModeCallback.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationActionModeCallback.kt index a405b90352..b0d4fa11d8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationActionModeCallback.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationActionModeCallback.kt @@ -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.OpenGroupApiV4 +import org.session.libsession.messaging.open_groups.OpenGroupApi 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 OpenGroupApiV4.isUserModerator(userPublicKey, openGroup.room, openGroup.server) + return OpenGroupApi.isUserModerator(userPublicKey, openGroup.room, openGroup.server) } val allReceivedByCurrentUser = selectedItems.all { !it.isOutgoing } if (openGroup == null) { return allSentByCurrentUser || allReceivedByCurrentUser } if (allSentByCurrentUser) { return true } - return OpenGroupApiV4.isUserModerator(userPublicKey, openGroup.room, openGroup.server) + return OpenGroupApi.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 OpenGroupApiV4.isUserModerator(userPublicKey, openGroup.room, openGroup.server) + return OpenGroupApi.isUserModerator(userPublicKey, openGroup.room, openGroup.server) } // Delete message menu.findItem(R.id.menu_context_delete_message).isVisible = userCanDeleteSelectedItems() 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 47ab00282a..c02430aebd 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 @@ -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.OpenGroupApiV4 +import org.session.libsession.messaging.open_groups.OpenGroupApi 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 = OpenGroupApiV4.isUserModerator(senderSessionID, openGroup.room, openGroup.server) + val isModerator = OpenGroupApi.isUserModerator(senderSessionID, openGroup.room, openGroup.server) binding.moderatorIconImageView.visibility = if (isModerator) View.VISIBLE else View.INVISIBLE } else { binding.moderatorIconImageView.visibility = View.INVISIBLE diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/DefaultGroupsViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/groups/DefaultGroupsViewModel.kt index b499e772db..4a8be25655 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/DefaultGroupsViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/DefaultGroupsViewModel.kt @@ -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.OpenGroupApiV4 +import org.session.libsession.messaging.open_groups.OpenGroupApi import org.thoughtcrime.securesms.util.State -typealias DefaultGroups = List +typealias DefaultGroups = List typealias GroupState = State class DefaultGroupsViewModel : ViewModel() { init { - OpenGroupApiV4.getDefaultRoomsIfNeeded() + OpenGroupApi.getDefaultRoomsIfNeeded() } - val defaultRooms = OpenGroupApiV4.defaultRooms.map { + val defaultRooms = OpenGroupApi.defaultRooms.map { State.Success(it) }.onStart { emit(State.Loading) diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/JoinPublicChatActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/groups/JoinPublicChatActivity.kt index 40f628662e..d91f10137e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/JoinPublicChatActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/JoinPublicChatActivity.kt @@ -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.OpenGroupApiV4.DefaultGroup +import org.session.libsession.messaging.open_groups.OpenGroupApi.DefaultGroup import org.session.libsession.utilities.Address import org.session.libsession.utilities.GroupUtil import org.session.libsession.utilities.recipients.Recipient diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/OpenGroupManager.kt b/app/src/main/java/org/thoughtcrime/securesms/groups/OpenGroupManager.kt index 5ca8ac364a..772a87fb67 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/OpenGroupManager.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/OpenGroupManager.kt @@ -4,9 +4,9 @@ import android.content.Context import androidx.annotation.WorkerThread import okhttp3.HttpUrl import org.session.libsession.messaging.MessagingModuleConfiguration -import org.session.libsession.messaging.open_groups.OpenGroupApiV4 +import org.session.libsession.messaging.open_groups.OpenGroupApi import org.session.libsession.messaging.open_groups.OpenGroupV2 -import org.session.libsession.messaging.sending_receiving.pollers.OpenGroupPollerV4 +import org.session.libsession.messaging.sending_receiving.pollers.OpenGroupPoller import org.session.libsession.utilities.Util import org.session.libsignal.utilities.ThreadUtils import org.thoughtcrime.securesms.dependencies.DatabaseComponent @@ -14,7 +14,7 @@ import java.util.concurrent.Executors object OpenGroupManager { private val executorService = Executors.newScheduledThreadPool(4) - private var pollers = mutableMapOf() // One for each server + private var pollers = mutableMapOf() // One for each server private var isPolling = false val isAllCaughtUp: Boolean @@ -41,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 = OpenGroupPollerV4(server, executorService) + val poller = OpenGroupPoller(server, executorService) poller.startIfNeeded() pollers[server] = poller } @@ -67,11 +67,11 @@ object OpenGroupManager { // Store the public key storage.setOpenGroupPublicKey(server,publicKey) // Get an auth token - OpenGroupApiV4.getAuthToken(room, server).get() + OpenGroupApi.getAuthToken(room, server).get() // Get capabilities - val capabilities = OpenGroupApiV4.getCapabilities(room, server).get() + val capabilities = OpenGroupApi.getCapabilities(room, server).get() // Get group info - val info = OpenGroupApiV4.getInfo(room, server).get() + val info = OpenGroupApi.getInfo(room, server).get() // Create the group locally if not available already if (threadID < 0) { threadID = GroupManager.createOpenGroup(openGroupID, context, null, info.name).threadId @@ -80,7 +80,7 @@ object OpenGroupManager { threadDB.setOpenGroupChat(openGroup, threadID) // Start the poller if needed pollers[server]?.startIfNeeded() ?: run { - val poller = OpenGroupPollerV4(server, executorService) + val poller = OpenGroupPoller(server, executorService) Util.runOnMain { poller.startIfNeeded() } pollers[server] = poller } diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/OpenGroupUtilities.kt b/app/src/main/java/org/thoughtcrime/securesms/groups/OpenGroupUtilities.kt index 85f7cf4599..e5bc9b5fb7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/OpenGroupUtilities.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/OpenGroupUtilities.kt @@ -3,8 +3,7 @@ package org.thoughtcrime.securesms.groups 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.messaging.open_groups.OpenGroupApi import org.session.libsession.utilities.GroupUtil import org.session.libsession.utilities.recipients.Recipient import org.thoughtcrime.securesms.dependencies.DatabaseComponent @@ -30,8 +29,8 @@ object OpenGroupUtilities { throw IllegalStateException("Attempt to update open group info for non-existent DB record: $groupId") } - val info = OpenGroupApiV4.getInfo(room, server).get() // store info again? - OpenGroupApiV4.getMemberCount(room, server).get() + val info = OpenGroupApi.getInfo(room, server).get() // store info again? + OpenGroupApi.getMemberCount(room, server).get() EventBus.getDefault().post(GroupInfoUpdatedEvent(server, room = room)) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/notifications/BackgroundPollWorker.kt b/app/src/main/java/org/thoughtcrime/securesms/notifications/BackgroundPollWorker.kt index 9e2404db93..56749586c3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/notifications/BackgroundPollWorker.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/notifications/BackgroundPollWorker.kt @@ -16,7 +16,7 @@ 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.OpenGroupPollerV4 +import org.session.libsession.messaging.sending_receiving.pollers.OpenGroupPoller import org.session.libsession.snode.SnodeAPI import org.session.libsession.utilities.TextSecurePreferences import org.session.libsignal.utilities.Log @@ -74,7 +74,7 @@ class BackgroundPollWorker(val context: Context, params: WorkerParameters) : Wor val v2OpenGroupServers = v2OpenGroups.map { it.value.server }.toSet() for (server in v2OpenGroupServers) { - val poller = OpenGroupPollerV4(server, null) + val poller = OpenGroupPoller(server, null) poller.hasStarted = true promises.add(poller.poll()) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/repository/ConversationRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/repository/ConversationRepository.kt index 1ea638624b..cb33dc454d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/repository/ConversationRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/repository/ConversationRepository.kt @@ -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.OpenGroupApiV4 +import org.session.libsession.messaging.open_groups.OpenGroupApi 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 -> - OpenGroupApiV4.deleteMessage(messageServerID, openGroup.room, openGroup.server) + OpenGroupApi.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) { - OpenGroupApiV4.deleteMessage(messageServerID, openGroup.room, openGroup.server) + OpenGroupApi.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)!! - OpenGroupApiV4.ban(sessionID, openGroup.room, openGroup.server) + OpenGroupApi.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)!! - OpenGroupApiV4.banAndDeleteAll(sessionID, openGroup.room, openGroup.server) + OpenGroupApi.banAndDeleteAll(sessionID, openGroup.room, openGroup.server) .success { continuation.resume(ResultOf.Success(Unit)) }.fail { error -> diff --git a/libsession/src/main/java/org/session/libsession/messaging/file_server/FileServerApi.kt b/libsession/src/main/java/org/session/libsession/messaging/file_server/FileServerApi.kt index 97794f9f68..7d376253a1 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/file_server/FileServerApi.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/file_server/FileServerApi.kt @@ -6,7 +6,7 @@ import okhttp3.Headers import okhttp3.HttpUrl import okhttp3.MediaType import okhttp3.RequestBody -import org.session.libsession.messaging.open_groups.OpenGroupApiV4 +import org.session.libsession.messaging.open_groups.OpenGroupApi import org.session.libsession.snode.OnionRequestAPI import org.session.libsignal.utilities.Base64 import org.session.libsignal.utilities.HTTP @@ -53,7 +53,7 @@ object FileServerApi { } private fun send(request: Request): Promise, Exception> { - val url = HttpUrl.parse(server) ?: return Promise.ofFail(OpenGroupApiV4.Error.InvalidURL) + val url = HttpUrl.parse(server) ?: return Promise.ofFail(OpenGroupApi.Error.InvalidURL) val urlBuilder = HttpUrl.Builder() .scheme(url.scheme()) .host(url.host()) @@ -87,7 +87,7 @@ object FileServerApi { val parameters = mapOf( "file" to base64EncodedFile ) val request = Request(verb = HTTP.Verb.POST, endpoint = "files", parameters = parameters) return send(request).map { json -> - json["result"] as? Long ?: throw OpenGroupApiV4.Error.ParsingFailed + json["result"] as? Long ?: throw OpenGroupApi.Error.ParsingFailed } } diff --git a/libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentDownloadJob.kt b/libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentDownloadJob.kt index cbfdaac3df..3dab24e899 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentDownloadJob.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentDownloadJob.kt @@ -2,8 +2,7 @@ package org.session.libsession.messaging.jobs 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.OpenGroupApi import org.session.libsession.messaging.sending_receiving.attachments.AttachmentId import org.session.libsession.messaging.sending_receiving.attachments.AttachmentState import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAttachment @@ -18,7 +17,6 @@ import org.session.libsignal.utilities.Log import java.io.File import java.io.FileInputStream import java.io.InputStream -import java.lang.NullPointerException class AttachmentDownloadJob(val attachmentID: Long, val databaseMessageID: Long) : Job { override var delegate: JobDelegate? = null @@ -103,7 +101,7 @@ class AttachmentDownloadJob(val attachmentID: Long, val databaseMessageID: Long) } else { val url = HttpUrl.parse(attachment.url)!! val fileID = url.pathSegments().last() - OpenGroupApiV4.download(fileID.toLong(), openGroupV2.room, openGroupV2.server).get().let { + OpenGroupApi.download(fileID.toLong(), openGroupV2.room, openGroupV2.server).get().let { tempFile.writeBytes(it) } } diff --git a/libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentUploadJob.kt b/libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentUploadJob.kt index b39886cdb9..cdfca15af8 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentUploadJob.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentUploadJob.kt @@ -8,7 +8,7 @@ import okio.Buffer import org.session.libsession.messaging.MessagingModuleConfiguration import org.session.libsession.messaging.file_server.FileServerApi import org.session.libsession.messaging.messages.Message -import org.session.libsession.messaging.open_groups.OpenGroupApiV4 +import org.session.libsession.messaging.open_groups.OpenGroupApi import org.session.libsession.messaging.sending_receiving.MessageSender import org.session.libsession.messaging.utilities.Data import org.session.libsession.utilities.DecodedAudio @@ -53,7 +53,7 @@ class AttachmentUploadJob(val attachmentID: Long, val threadID: String, val mess val v2OpenGroup = storage.getV2OpenGroup(threadID.toLong()) if (v2OpenGroup != null) { val keyAndResult = upload(attachment, v2OpenGroup.server, false) { - OpenGroupApiV4.upload(it, v2OpenGroup.room, v2OpenGroup.server) + OpenGroupApi.upload(it, v2OpenGroup.room, v2OpenGroup.server) } handleSuccess(attachment, keyAndResult.first, keyAndResult.second) } else { diff --git a/libsession/src/main/java/org/session/libsession/messaging/jobs/GroupAvatarDownloadJob.kt b/libsession/src/main/java/org/session/libsession/messaging/jobs/GroupAvatarDownloadJob.kt index ccb0ea8e2a..f51643c0c5 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/jobs/GroupAvatarDownloadJob.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/jobs/GroupAvatarDownloadJob.kt @@ -1,7 +1,7 @@ package org.session.libsession.messaging.jobs import org.session.libsession.messaging.MessagingModuleConfiguration -import org.session.libsession.messaging.open_groups.OpenGroupApiV4 +import org.session.libsession.messaging.open_groups.OpenGroupApi import org.session.libsession.messaging.utilities.Data import org.session.libsession.utilities.GroupUtil @@ -15,8 +15,8 @@ class GroupAvatarDownloadJob(val room: String, val server: String) : Job { override fun execute() { val storage = MessagingModuleConfiguration.shared.storage try { - val info = OpenGroupApiV4.getInfo(room, server).get() - val bytes = OpenGroupApiV4.downloadOpenGroupProfilePicture(info.id, server).get() + val info = OpenGroupApi.getInfo(room, server).get() + val bytes = OpenGroupApi.downloadOpenGroupProfilePicture(info.id, server).get() val groupId = GroupUtil.getEncodedOpenGroupID("$server.$room".toByteArray()) storage.updateProfilePicture(groupId, bytes) storage.updateTimestampUpdated(groupId, System.currentTimeMillis()) diff --git a/libsession/src/main/java/org/session/libsession/messaging/open_groups/OpenGroupAPIV2.kt b/libsession/src/main/java/org/session/libsession/messaging/open_groups/OpenGroupAPIV2.kt deleted file mode 100644 index 9597c70aa6..0000000000 --- a/libsession/src/main/java/org/session/libsession/messaging/open_groups/OpenGroupAPIV2.kt +++ /dev/null @@ -1,486 +0,0 @@ -package org.session.libsession.messaging.open_groups - -import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.databind.PropertyNamingStrategy -import com.fasterxml.jackson.databind.annotation.JsonNaming -import com.fasterxml.jackson.databind.type.TypeFactory -import kotlinx.coroutines.* -import kotlinx.coroutines.flow.MutableSharedFlow -import nl.komponents.kovenant.Promise -import nl.komponents.kovenant.functional.bind -import nl.komponents.kovenant.functional.map -import okhttp3.Headers -import okhttp3.HttpUrl -import okhttp3.MediaType -import okhttp3.RequestBody -import org.session.libsession.messaging.MessagingModuleConfiguration -import org.session.libsession.messaging.sending_receiving.pollers.OpenGroupPollerV2 -import org.session.libsession.snode.OnionRequestAPI -import org.session.libsession.utilities.AESGCM -import org.session.libsession.utilities.TextSecurePreferences -import org.session.libsignal.utilities.* -import org.session.libsignal.utilities.Base64.* -import org.session.libsignal.utilities.HTTP.Verb.* -import org.whispersystems.curve25519.Curve25519 -import java.util.* - -object OpenGroupAPIV2 { - private val moderators: HashMap> = hashMapOf() // Server URL to (channel ID to set of moderator IDs) - private val curve = Curve25519.getInstance(Curve25519.BEST) - val defaultRooms = MutableSharedFlow>(replay = 1) - private val hasPerformedInitialPoll = mutableMapOf() - private var hasUpdatedLastOpenDate = false - - private val timeSinceLastOpen by lazy { - val context = MessagingModuleConfiguration.shared.context - val lastOpenDate = TextSecurePreferences.getLastOpenTimeDate(context) - val now = System.currentTimeMillis() - now - lastOpenDate - } - - private const val defaultServerPublicKey = "a03c383cf63c3c4efe67acc52112a6dd734b3a946b9545f488aaa93da7991238" - const val defaultServer = "http://116.203.70.33" - - sealed class Error(message: String) : Exception(message) { - object Generic : Error("An error occurred.") - object ParsingFailed : Error("Invalid response.") - object DecryptionFailed : Error("Couldn't decrypt response.") - object SigningFailed : Error("Couldn't sign message.") - object InvalidURL : Error("Invalid URL.") - object NoPublicKey : Error("Couldn't find server public key.") - } - - data class DefaultGroup(val id: String, val name: String, val image: ByteArray?) { - - val joinURL: String get() = "$defaultServer/$id?public_key=$defaultServerPublicKey" - } - - data class Info(val id: String, val name: String, val imageID: String?) - - @JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy::class) - data class CompactPollRequest(val roomID: String, val authToken: String, val fromDeletionServerID: Long?, val fromMessageServerID: Long?) - data class CompactPollResult(val messages: List, val deletions: List, val moderators: List) - - data class MessageDeletion( - @JsonProperty("id") - val id: Long = 0, - @JsonProperty("deleted_message_id") - val deletedMessageServerID: Long = 0 - ) { - - companion object { - val empty = MessageDeletion() - } - } - - data class Request( - val verb: HTTP.Verb, - val room: String?, - val server: String, - val endpoint: String, - val queryParameters: Map = mapOf(), - val parameters: Any? = null, - val headers: Map = mapOf(), - val isAuthRequired: Boolean = true, - /** - * Always `true` under normal circumstances. You might want to disable - * this when running over Lokinet. - */ - val useOnionRouting: Boolean = true - ) - - private fun createBody(parameters: Any?): RequestBody? { - if (parameters == null) return null - val parametersAsJSON = JsonUtil.toJson(parameters) - return RequestBody.create(MediaType.get("application/json"), parametersAsJSON) - } - - private fun send(request: Request): Promise, Exception> { - val url = HttpUrl.parse(request.server) ?: return Promise.ofFail(Error.InvalidURL) - val urlBuilder = HttpUrl.Builder() - .scheme(url.scheme()) - .host(url.host()) - .port(url.port()) - .addPathSegments(request.endpoint) - if (request.verb == GET) { - for ((key, value) in request.queryParameters) { - urlBuilder.addQueryParameter(key, value) - } - } - fun execute(token: String?): Promise, Exception> { - val requestBuilder = okhttp3.Request.Builder() - .url(urlBuilder.build()) - .headers(Headers.of(request.headers)) - if (request.isAuthRequired) { - if (token.isNullOrEmpty()) throw IllegalStateException("No auth token for request.") - requestBuilder.header("Authorization", token) - } - when (request.verb) { - GET -> requestBuilder.get() - PUT -> requestBuilder.put(createBody(request.parameters)!!) - POST -> requestBuilder.post(createBody(request.parameters)!!) - DELETE -> requestBuilder.delete(createBody(request.parameters)) - } - if (!request.room.isNullOrEmpty()) { - requestBuilder.header("Room", request.room) - } - if (request.useOnionRouting) { - val publicKey = MessagingModuleConfiguration.shared.storage.getOpenGroupPublicKey(request.server) - ?: return Promise.ofFail(Error.NoPublicKey) - return OnionRequestAPI.sendOnionRequest(requestBuilder.build(), request.server, publicKey).fail { e -> - // A 401 means that we didn't provide a (valid) auth token for a route that required one. We use this as an - // indication that the token we're using has expired. Note that a 403 has a different meaning; it means that - // we provided a valid token but it doesn't have a high enough permission level for the route in question. - if (e is OnionRequestAPI.HTTPRequestFailedAtDestinationException && e.statusCode == 401) { - val storage = MessagingModuleConfiguration.shared.storage - if (request.room != null) { - storage.removeAuthToken(request.room, request.server) - } - } - } - } else { - return Promise.ofFail(IllegalStateException("It's currently not allowed to send non onion routed requests.")) - } - } - return if (request.isAuthRequired) { - getAuthToken(request.room!!, request.server).bind { execute(it) } - } else { - execute(null) - } - } - - fun downloadOpenGroupProfilePicture(roomID: String, server: String): Promise { - val request = Request(verb = GET, room = roomID, server = server, endpoint = "rooms/$roomID/image", isAuthRequired = false) - return send(request).map { json -> - val result = json["result"] as? String ?: throw Error.ParsingFailed - decode(result) - } - } - - // region Authorization - fun getAuthToken(room: String, server: String): Promise { - val storage = MessagingModuleConfiguration.shared.storage - return storage.getAuthToken(room, server)?.let { - Promise.of(it) - } ?: run { - requestNewAuthToken(room, server) - .bind { claimAuthToken(it, room, server) } - .success { authToken -> - storage.setAuthToken(room, server, authToken) - } - } - } - - fun requestNewAuthToken(room: String, server: String): Promise { - val (publicKey, privateKey) = MessagingModuleConfiguration.shared.storage.getUserX25519KeyPair().let { it.publicKey.serialize() to it.privateKey.serialize() } - ?: return Promise.ofFail(Error.Generic) - val queryParameters = mutableMapOf( "public_key" to publicKey.toHexString() ) - val request = Request(GET, room, server, "auth_token_challenge", queryParameters, isAuthRequired = false, parameters = null) - return send(request).map { json -> - val challenge = json["challenge"] as? Map<*, *> ?: throw Error.ParsingFailed - val base64EncodedCiphertext = challenge["ciphertext"] as? String ?: throw Error.ParsingFailed - val base64EncodedEphemeralPublicKey = challenge["ephemeral_public_key"] as? String ?: throw Error.ParsingFailed - val ciphertext = decode(base64EncodedCiphertext) - val ephemeralPublicKey = decode(base64EncodedEphemeralPublicKey) - val symmetricKey = AESGCM.generateSymmetricKey(ephemeralPublicKey, privateKey) - val tokenAsData = try { - AESGCM.decrypt(ciphertext, symmetricKey) - } catch (e: Exception) { - throw Error.DecryptionFailed - } - tokenAsData.toHexString() - } - } - - fun claimAuthToken(authToken: String, room: String, server: String): Promise { - val parameters = mapOf( "public_key" to MessagingModuleConfiguration.shared.storage.getUserPublicKey()!! ) - val headers = mapOf( "Authorization" to authToken ) - val request = Request(verb = POST, room = room, server = server, endpoint = "claim_auth_token", - parameters = parameters, headers = headers, isAuthRequired = false) - return send(request).map { authToken } - } - - fun deleteAuthToken(room: String, server: String): Promise { - val request = Request(verb = DELETE, room = room, server = server, endpoint = "auth_token") - return send(request).map { - MessagingModuleConfiguration.shared.storage.removeAuthToken(room, server) - } - } - // endregion - - // region Upload/Download - fun upload(file: ByteArray, room: String, server: String): Promise { - val base64EncodedFile = encodeBytes(file) - val parameters = mapOf( "file" to base64EncodedFile ) - val request = Request(verb = POST, room = room, server = server, endpoint = "files", parameters = parameters) - return send(request).map { json -> - (json["result"] as? Number)?.toLong() ?: throw Error.ParsingFailed - } - } - - fun download(file: Long, room: String, server: String): Promise { - val request = Request(verb = GET, room = room, server = server, endpoint = "files/$file") - return send(request).map { json -> - val base64EncodedFile = json["result"] as? String ?: throw Error.ParsingFailed - decode(base64EncodedFile) ?: throw Error.ParsingFailed - } - } - // endregion - - // region Sending - fun send(message: OpenGroupMessageV2, room: String, server: String): Promise { - val signedMessage = message.sign() ?: return Promise.ofFail(Error.SigningFailed) - val jsonMessage = signedMessage.toJSON() - val request = Request(verb = POST, room = room, server = server, endpoint = "messages", parameters = jsonMessage) - return send(request).map { json -> - @Suppress("UNCHECKED_CAST") val rawMessage = json["message"] as? Map - ?: throw Error.ParsingFailed - val result = OpenGroupMessageV2.fromJSON(rawMessage) ?: throw Error.ParsingFailed - val storage = MessagingModuleConfiguration.shared.storage - storage.addReceivedMessageTimestamp(result.sentTimestamp) - result - } - } - // endregion - - // region Messages - fun getMessages(room: String, server: String): Promise, Exception> { - val storage = MessagingModuleConfiguration.shared.storage - val queryParameters = mutableMapOf() - storage.getLastMessageServerID(room, server)?.let { lastId -> - queryParameters += "from_server_id" to lastId.toString() - } - val request = Request(verb = GET, room = room, server = server, endpoint = "messages", queryParameters = queryParameters) - return send(request).map { json -> - @Suppress("UNCHECKED_CAST") val rawMessages = json["messages"] as? List> - ?: throw Error.ParsingFailed - parseMessages(room, server, rawMessages) - } - } - - private fun parseMessages(room: String, server: String, rawMessages: List>): List { - val messages = rawMessages.mapNotNull { json -> - json as Map - try { - val message = OpenGroupMessageV2.fromJSON(json) ?: return@mapNotNull null - if (message.serverID == null || message.sender.isNullOrEmpty()) return@mapNotNull null - val sender = message.sender - val data = decode(message.base64EncodedData) - val signature = decode(message.base64EncodedSignature) - val publicKey = Hex.fromStringCondensed(sender.removing05PrefixIfNeeded()) - val isValid = curve.verifySignature(publicKey, data, signature) - if (!isValid) { - Log.d("Loki", "Ignoring message with invalid signature.") - return@mapNotNull null - } - message - } catch (e: Exception) { - null - } - } - return messages - } - // endregion - - // region Message Deletion - @JvmStatic - fun deleteMessage(serverID: Long, room: String, server: String): Promise { - val request = Request(verb = DELETE, room = room, server = server, endpoint = "messages/$serverID") - return send(request).map { - Log.d("Loki", "Message deletion successful.") - } - } - - fun getDeletedMessages(room: String, server: String): Promise, Exception> { - val storage = MessagingModuleConfiguration.shared.storage - val queryParameters = mutableMapOf() - storage.getLastDeletionServerID(room, server)?.let { last -> - queryParameters["from_server_id"] = last.toString() - } - val request = Request(verb = GET, room = room, server = server, endpoint = "deleted_messages", queryParameters = queryParameters) - return send(request).map { json -> - val type = TypeFactory.defaultInstance().constructCollectionType(List::class.java, MessageDeletion::class.java) - val idsAsString = JsonUtil.toJson(json["ids"]) - val serverIDs = JsonUtil.fromJson>(idsAsString, type) ?: throw Error.ParsingFailed - val lastMessageServerId = storage.getLastDeletionServerID(room, server) ?: 0 - val serverID = serverIDs.maxByOrNull {it.id } ?: MessageDeletion.empty - if (serverID.id > lastMessageServerId) { - storage.setLastDeletionServerID(room, server, serverID.id) - } - serverIDs - } - } - // endregion - - // region Moderation - private fun handleModerators(serverRoomId: String, moderatorList: List) { - moderators[serverRoomId] = moderatorList.toMutableSet() - } - - fun getModerators(room: String, server: String): Promise, Exception> { - val request = Request(verb = GET, room = room, server = server, endpoint = "moderators") - return send(request).map { json -> - @Suppress("UNCHECKED_CAST") val moderatorsJson = json["moderators"] as? List - ?: throw Error.ParsingFailed - val id = "$server.$room" - handleModerators(id, moderatorsJson) - moderatorsJson - } - } - - @JvmStatic - fun ban(publicKey: String, room: String, server: String): Promise { - val parameters = mapOf( "public_key" to publicKey ) - val request = Request(verb = POST, room = room, server = server, endpoint = "block_list", parameters = parameters) - return send(request).map { - Log.d("Loki", "Banned user: $publicKey from: $server.$room.") - } - } - - fun banAndDeleteAll(publicKey: String, room: String, server: String): Promise { - val parameters = mapOf( "public_key" to publicKey ) - val request = Request(verb = POST, room = room, server = server, endpoint = "ban_and_delete_all", parameters = parameters) - return send(request).map { - Log.d("Loki", "Banned user: $publicKey from: $server.$room.") - } - } - - fun unban(publicKey: String, room: String, server: String): Promise { - val request = Request(verb = DELETE, room = room, server = server, endpoint = "block_list/$publicKey") - return send(request).map { - Log.d("Loki", "Unbanned user: $publicKey from: $server.$room") - } - } - - @JvmStatic - fun isUserModerator(publicKey: String, room: String, server: String): Boolean = - moderators["$server.$room"]?.contains(publicKey) ?: false - // endregion - - // region General - @Suppress("UNCHECKED_CAST") - fun compactPoll(rooms: List, server: String): Promise, Exception> { - val authTokenRequests = rooms.associateWith { room -> getAuthToken(room, server) } - val storage = MessagingModuleConfiguration.shared.storage - val context = MessagingModuleConfiguration.shared.context - val timeSinceLastOpen = this.timeSinceLastOpen - val useMessageLimit = (hasPerformedInitialPoll[server] != true - && timeSinceLastOpen > OpenGroupPollerV2.maxInactivityPeriod) - hasPerformedInitialPoll[server] = true - if (!hasUpdatedLastOpenDate) { - hasUpdatedLastOpenDate = true - TextSecurePreferences.setLastOpenDate(context) - } - val requests = rooms.mapNotNull { room -> - val authToken = try { - authTokenRequests[room]?.get() - } catch (e: Exception) { - Log.e("Loki", "Failed to get auth token for $room.", e) - null - } ?: return@mapNotNull null - CompactPollRequest( - roomID = room, - authToken = authToken, - fromDeletionServerID = if (useMessageLimit) null else storage.getLastDeletionServerID(room, server), - fromMessageServerID = if (useMessageLimit) null else storage.getLastMessageServerID(room, server) - ) - } - val request = Request(verb = POST, room = null, server = server, endpoint = "compact_poll", isAuthRequired = false, parameters = mapOf( "requests" to requests )) - return send(request = request).map { json -> - val results = json["results"] as? List<*> ?: throw Error.ParsingFailed - results.mapNotNull { json -> - if (json !is Map<*,*>) return@mapNotNull null - val roomID = json["room_id"] as? String ?: return@mapNotNull null - // A 401 means that we didn't provide a (valid) auth token for a route that required one. We use this as an - // indication that the token we're using has expired. Note that a 403 has a different meaning; it means that - // we provided a valid token but it doesn't have a high enough permission level for the route in question. - val statusCode = json["status_code"] as? Int ?: return@mapNotNull null - if (statusCode == 401) { - // delete auth token and return null - storage.removeAuthToken(roomID, server) - } - // Moderators - val moderators = json["moderators"] as? List ?: return@mapNotNull null - handleModerators("$server.$roomID", moderators) - // Deletions - val type = TypeFactory.defaultInstance().constructCollectionType(List::class.java, MessageDeletion::class.java) - val idsAsString = JsonUtil.toJson(json["deletions"]) - val deletions = JsonUtil.fromJson>(idsAsString, type) ?: throw Error.ParsingFailed - // Messages - val rawMessages = json["messages"] as? List> ?: return@mapNotNull null - val messages = parseMessages(roomID, server, rawMessages) - roomID to CompactPollResult( - messages = messages, - deletions = deletions, - moderators = moderators - ) - }.toMap() - } - } - - fun getDefaultRoomsIfNeeded(): Promise, Exception> { - val storage = MessagingModuleConfiguration.shared.storage - storage.setOpenGroupPublicKey(defaultServer, defaultServerPublicKey) - return getAllRooms(defaultServer).map { groups -> - val earlyGroups = groups.map { group -> - DefaultGroup(group.id, group.name, null) - } - // See if we have any cached rooms, and if they already have images don't overwrite them with early non-image results - defaultRooms.replayCache.firstOrNull()?.let { replayed -> - if (replayed.none { it.image?.isNotEmpty() == true}) { - defaultRooms.tryEmit(earlyGroups) - } - } - val images = groups.map { group -> - group.id to downloadOpenGroupProfilePicture(group.id, defaultServer) - }.toMap() - groups.map { group -> - val image = try { - images[group.id]!!.get() - } catch (e: Exception) { - // No image or image failed to download - null - } - DefaultGroup(group.id, group.name, image) - } - }.success { new -> - defaultRooms.tryEmit(new) - } - } - - fun getInfo(room: String, server: String): Promise { - val request = Request(verb = GET, room = null, server = server, endpoint = "rooms/$room", isAuthRequired = false) - return send(request).map { json -> - val rawRoom = json["room"] as? Map<*, *> ?: throw Error.ParsingFailed - val id = rawRoom["id"] as? String ?: throw Error.ParsingFailed - val name = rawRoom["name"] as? String ?: throw Error.ParsingFailed - val imageID = rawRoom["image_id"] as? String - Info(id = id, name = name, imageID = imageID) - } - } - - fun getAllRooms(server: String): Promise, Exception> { - val request = Request(verb = GET, room = null, server = server, endpoint = "rooms", isAuthRequired = false) - return send(request).map { json -> - val rawRooms = json["rooms"] as? List> ?: throw Error.ParsingFailed - rawRooms.mapNotNull { - val roomJson = it as? Map<*, *> ?: return@mapNotNull null - val id = roomJson["id"] as? String ?: return@mapNotNull null - val name = roomJson["name"] as? String ?: return@mapNotNull null - val imageID = roomJson["image_id"] as? String - Info(id, name, imageID) - } - } - } - - fun getMemberCount(room: String, server: String): Promise { - val request = Request(verb = GET, room = room, server = server, endpoint = "member_count") - return send(request).map { json -> - val memberCount = json["member_count"] as? Int ?: throw Error.ParsingFailed - val storage = MessagingModuleConfiguration.shared.storage - storage.setUserCount(room, server, memberCount) - memberCount - } - } - // endregion -} \ No newline at end of file diff --git a/libsession/src/main/java/org/session/libsession/messaging/open_groups/OpenGroupApiV4.kt b/libsession/src/main/java/org/session/libsession/messaging/open_groups/OpenGroupApi.kt similarity index 99% rename from libsession/src/main/java/org/session/libsession/messaging/open_groups/OpenGroupApiV4.kt rename to libsession/src/main/java/org/session/libsession/messaging/open_groups/OpenGroupApi.kt index a68166d726..e0d4be73eb 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/open_groups/OpenGroupApiV4.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/open_groups/OpenGroupApi.kt @@ -16,7 +16,7 @@ import okhttp3.HttpUrl import okhttp3.MediaType import okhttp3.RequestBody import org.session.libsession.messaging.MessagingModuleConfiguration -import org.session.libsession.messaging.sending_receiving.pollers.OpenGroupPollerV4.Companion.maxInactivityPeriod +import org.session.libsession.messaging.sending_receiving.pollers.OpenGroupPoller.Companion.maxInactivityPeriod import org.session.libsession.messaging.utilities.SodiumUtilities import org.session.libsession.snode.OnionRequestAPI import org.session.libsession.utilities.AESGCM @@ -39,7 +39,7 @@ import kotlin.collections.component1 import kotlin.collections.component2 import kotlin.collections.set -object OpenGroupApiV4 { +object OpenGroupApi { private val moderators: HashMap> = hashMapOf() // Server URL to (channel ID to set of moderator IDs) private val curve = Curve25519.getInstance(Curve25519.BEST) diff --git a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSender.kt b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSender.kt index 482b3fd231..ab51fb6fee 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSender.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSender.kt @@ -235,7 +235,7 @@ object MessageSender { sentTimestamp = message.sentTimestamp!!, base64EncodedData = Base64.encodeBytes(plaintext), ) - OpenGroupApiV4.send(openGroupMessage,room,server).success { + OpenGroupApi.send(openGroupMessage,room,server).success { message.openGroupServerMessageID = it.serverID handleSuccessfulMessageSend(message, destination, openGroupSentTimestamp = it.sentTimestamp) deferred.resolve(Unit) diff --git a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/pollers/OpenGroupPollerV4.kt b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/pollers/OpenGroupPoller.kt similarity index 93% rename from libsession/src/main/java/org/session/libsession/messaging/sending_receiving/pollers/OpenGroupPollerV4.kt rename to libsession/src/main/java/org/session/libsession/messaging/sending_receiving/pollers/OpenGroupPoller.kt index fbf571caf0..63a6c39ff3 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/pollers/OpenGroupPollerV4.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/pollers/OpenGroupPoller.kt @@ -8,7 +8,7 @@ import org.session.libsession.messaging.jobs.GroupAvatarDownloadJob import org.session.libsession.messaging.jobs.JobQueue import org.session.libsession.messaging.jobs.MessageReceiveJob import org.session.libsession.messaging.jobs.MessageReceiveParameters -import org.session.libsession.messaging.open_groups.OpenGroupApiV4 +import org.session.libsession.messaging.open_groups.OpenGroupApi import org.session.libsession.messaging.open_groups.OpenGroupMessageV2 import org.session.libsession.utilities.Address import org.session.libsession.utilities.GroupUtil @@ -19,7 +19,7 @@ import java.util.concurrent.ScheduledFuture import java.util.concurrent.TimeUnit import kotlin.math.max -class OpenGroupPollerV4(private val server: String, private val executorService: ScheduledExecutorService?) { +class OpenGroupPoller(private val server: String, private val executorService: ScheduledExecutorService?) { var hasStarted = false var isCaughtUp = false var secondToLastJob: MessageReceiveJob? = null @@ -45,7 +45,7 @@ class OpenGroupPollerV4(private val server: String, private val executorService: val storage = MessagingModuleConfiguration.shared.storage val rooms = storage.getAllV2OpenGroups().values.filter { it.server == server }.map { it.room } rooms.forEach { downloadGroupAvatarIfNeeded(it) } - return OpenGroupApiV4.batch(rooms, server).successBackground { responses -> + return OpenGroupApi.batch(rooms, server).successBackground { responses -> responses.forEach { (room, response) -> val openGroupID = "$server.$room" handleNewMessages(room, openGroupID, response.messages) @@ -55,7 +55,7 @@ class OpenGroupPollerV4(private val server: String, private val executorService: } } }.always { - executorService?.schedule(this@OpenGroupPollerV4::poll, pollInterval, TimeUnit.MILLISECONDS) + executorService?.schedule(this@OpenGroupPoller::poll, pollInterval, TimeUnit.MILLISECONDS) }.map { } } @@ -95,7 +95,7 @@ class OpenGroupPollerV4(private val server: String, private val executorService: } } - private fun handleDeletedMessages(room: String, openGroupID: String, deletions: List) { + private fun handleDeletedMessages(room: String, openGroupID: String, deletions: List) { val storage = MessagingModuleConfiguration.shared.storage val dataProvider = MessagingModuleConfiguration.shared.messageDataProvider val groupID = GroupUtil.getEncodedOpenGroupID(openGroupID.toByteArray()) diff --git a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/pollers/OpenGroupPollerV2.kt b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/pollers/OpenGroupPollerV2.kt deleted file mode 100644 index 90f4144cbf..0000000000 --- a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/pollers/OpenGroupPollerV2.kt +++ /dev/null @@ -1,118 +0,0 @@ -package org.session.libsession.messaging.sending_receiving.pollers - -import nl.komponents.kovenant.Promise -import nl.komponents.kovenant.functional.map -import org.session.libsession.messaging.MessagingModuleConfiguration -import org.session.libsession.messaging.jobs.* -import org.session.libsession.messaging.open_groups.OpenGroupAPIV2 -import org.session.libsession.messaging.open_groups.OpenGroupMessageV2 -import org.session.libsession.utilities.Address -import org.session.libsession.utilities.GroupUtil -import org.session.libsignal.protos.SignalServiceProtos -import org.session.libsignal.utilities.successBackground -import java.util.concurrent.ScheduledExecutorService -import java.util.concurrent.ScheduledFuture -import java.util.concurrent.TimeUnit -import kotlin.math.max - -class OpenGroupPollerV2(private val server: String, private val executorService: ScheduledExecutorService?) { - var hasStarted = false - var isCaughtUp = false - var secondToLastJob: MessageReceiveJob? = null - private var future: ScheduledFuture<*>? = null - - companion object { - private const val pollInterval: Long = 4000L - const val maxInactivityPeriod = 14 * 24 * 60 * 60 * 1000 - } - - fun startIfNeeded() { - if (hasStarted) { return } - hasStarted = true - future = executorService?.schedule(::poll, 0, TimeUnit.MILLISECONDS) - } - - fun stop() { - future?.cancel(false) - hasStarted = false - } - - fun poll(isBackgroundPoll: Boolean = false): Promise { - val storage = MessagingModuleConfiguration.shared.storage - val rooms = storage.getAllV2OpenGroups().values.filter { it.server == server }.map { it.room } - rooms.forEach { downloadGroupAvatarIfNeeded(it) } - return OpenGroupAPIV2.compactPoll(rooms, server).successBackground { responses -> - responses.forEach { (room, response) -> - val openGroupID = "$server.$room" - handleNewMessages(room, openGroupID, response.messages, isBackgroundPoll) - handleDeletedMessages(room, openGroupID, response.deletions) - if (secondToLastJob == null && !isCaughtUp) { - isCaughtUp = true - } - } - }.always { - executorService?.schedule(this@OpenGroupPollerV2::poll, pollInterval, TimeUnit.MILLISECONDS) - }.map { } - } - - private fun handleNewMessages(room: String, openGroupID: String, messages: List, isBackgroundPoll: Boolean) { - val storage = MessagingModuleConfiguration.shared.storage - val groupID = GroupUtil.getEncodedOpenGroupID(openGroupID.toByteArray()) - // check thread still exists - val threadId = storage.getThreadId(Address.fromSerialized(groupID)) ?: -1 - val threadExists = threadId >= 0 - if (!hasStarted || !threadExists) { return } - val envelopes = messages.sortedBy { it.serverID!! }.map { message -> - val senderPublicKey = message.sender!! - val builder = SignalServiceProtos.Envelope.newBuilder() - builder.type = SignalServiceProtos.Envelope.Type.SESSION_MESSAGE - builder.source = senderPublicKey - builder.sourceDevice = 1 - builder.content = message.toProto().toByteString() - builder.timestamp = message.sentTimestamp - builder.build() to message.serverID - } - - envelopes.chunked(256).forEach { list -> - val parameters = list.map { (message, serverId) -> - MessageReceiveParameters(message.toByteArray(), openGroupMessageServerID = serverId) - } - JobQueue.shared.add(BatchMessageReceiveJob(parameters, openGroupID)) - } - - val currentLastMessageServerID = storage.getLastMessageServerID(room, server) ?: 0 - val actualMax = max(messages.mapNotNull { it.serverID }.maxOrNull() ?: 0, currentLastMessageServerID) - if (actualMax > 0) { - storage.setLastMessageServerID(room, server, actualMax) - } - } - - private fun handleDeletedMessages(room: String, openGroupID: String, deletions: List) { - val storage = MessagingModuleConfiguration.shared.storage - val dataProvider = MessagingModuleConfiguration.shared.messageDataProvider - val groupID = GroupUtil.getEncodedOpenGroupID(openGroupID.toByteArray()) - val threadID = storage.getThreadId(Address.fromSerialized(groupID)) ?: return - val deletedMessageIDs = deletions.mapNotNull { deletion -> - dataProvider.getMessageID(deletion.deletedMessageServerID, threadID) - } - deletedMessageIDs.forEach { (messageId, isSms) -> - MessagingModuleConfiguration.shared.messageDataProvider.deleteMessage(messageId, isSms) - } - val currentMax = storage.getLastDeletionServerID(room, server) ?: 0L - val latestMax = deletions.map { it.id }.maxOrNull() ?: 0L - if (latestMax > currentMax && latestMax != 0L) { - storage.setLastDeletionServerID(room, server, latestMax) - } - } - - private fun downloadGroupAvatarIfNeeded(room: String) { - val storage = MessagingModuleConfiguration.shared.storage - if (storage.getGroupAvatarDownloadJob(server, room) != null) return - val groupId = GroupUtil.getEncodedOpenGroupID("$server.$room".toByteArray()) - storage.getGroup(groupId)?.let { - if (System.currentTimeMillis() > it.updatedTimestamp + TimeUnit.DAYS.toMillis(7)) { - JobQueue.shared.add(GroupAvatarDownloadJob(room, server)) - } - } - } -} \ No newline at end of file diff --git a/libsession/src/main/java/org/session/libsession/messaging/utilities/SodiumUtilities.kt b/libsession/src/main/java/org/session/libsession/messaging/utilities/SodiumUtilities.kt index 502c710d69..27fd835741 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/utilities/SodiumUtilities.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/utilities/SodiumUtilities.kt @@ -51,8 +51,6 @@ object SodiumUtilities { /* Constructs a "blinded" key pair (`ka, kA`) based on an open group server `publicKey` and an ed25519 `keyPair` */ fun blindedKeyPair(serverPublicKey: String, edKeyPair: KeyPair): KeyPair? { -// if (edKeyPair.publicKey.asBytes.size != publicKeyLength || -// edKeyPair.secretKey.asBytes.size != secretKeyLength) return null val kBytes = generateBlindingFactor(serverPublicKey) val aBytes = generatePrivateKeyScalar(edKeyPair.secretKey.asBytes) // Generate the blinded key pair `ka`, `kA`