From 443cdfa4ebc41675bfb1905c2024f3b6ee288f87 Mon Sep 17 00:00:00 2001 From: Ryan ZHAO Date: Fri, 4 Sep 2020 15:55:32 +1000 Subject: [PATCH 01/17] enable push notification for shared sender keys --- .../loki/api/LokiPushNotificationManager.kt | 89 ++++++++++++++++++- .../loki/protocol/ClosedGroupsProtocol.kt | 13 ++- 2 files changed, 97 insertions(+), 5 deletions(-) diff --git a/src/org/thoughtcrime/securesms/loki/api/LokiPushNotificationManager.kt b/src/org/thoughtcrime/securesms/loki/api/LokiPushNotificationManager.kt index 39a9c46078..e59502174d 100644 --- a/src/org/thoughtcrime/securesms/loki/api/LokiPushNotificationManager.kt +++ b/src/org/thoughtcrime/securesms/loki/api/LokiPushNotificationManager.kt @@ -2,11 +2,18 @@ package org.thoughtcrime.securesms.loki.api import android.content.Context import okhttp3.* +import org.thoughtcrime.securesms.database.DatabaseFactory +import org.thoughtcrime.securesms.jobmanager.Data +import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint +import org.thoughtcrime.securesms.jobs.BaseJob +import org.thoughtcrime.securesms.loki.protocol.ClosedGroupUpdateMessageSendJob import org.thoughtcrime.securesms.util.TextSecurePreferences import org.whispersystems.libsignal.logging.Log import org.whispersystems.signalservice.internal.util.JsonUtil import org.whispersystems.signalservice.loki.api.PushNotificationAcknowledgement import java.io.IOException +import java.lang.Exception +import java.util.concurrent.TimeUnit object LokiPushNotificationManager { private val connection = OkHttpClient() @@ -15,11 +22,14 @@ object LokiPushNotificationManager { PushNotificationAcknowledgement.shared.server } + public const val subscribe = "subscribe_closed_group" + public const val unsubscribe = "unsubscribe_closed_group" + private const val tokenExpirationInterval = 12 * 60 * 60 * 1000 @JvmStatic fun unregister(token: String, context: Context?) { - val parameters = mapOf( "token" to token ) + val parameters = mapOf("token" to token) val url = "$server/register" val body = RequestBody.create(MediaType.get("application/json"), JsonUtil.toJson(parameters)) val request = Request.Builder().url(url).post(body).build() @@ -30,7 +40,7 @@ object LokiPushNotificationManager { 200 -> { val bodyAsString = response.body()!!.string() val json = JsonUtil.fromJson(bodyAsString, Map::class.java) - val code = json?.get("code") as? Int + val code = json?.get("code") as? Int if (code != null && code != 0) { TextSecurePreferences.setIsUsingFCM(context, false) } else { @@ -44,6 +54,10 @@ object LokiPushNotificationManager { Log.d("Loki", "Couldn't disable FCM.") } }) + + for (closedGroup: String in DatabaseFactory.getSSKDatabase(context).getAllClosedGroupPublicKeys()) { + operateClosedGroup(closedGroup, TextSecurePreferences.getLocalNumber(context), context, unsubscribe) + } } @JvmStatic @@ -51,7 +65,7 @@ object LokiPushNotificationManager { val oldToken = TextSecurePreferences.getFCMToken(context) val lastUploadDate = TextSecurePreferences.getLastFCMUploadTime(context) if (!force && token == oldToken && System.currentTimeMillis() - lastUploadDate < tokenExpirationInterval) { return } - val parameters = mapOf( "token" to token, "pubKey" to publicKey ) + val parameters = mapOf("token" to token, "pubKey" to publicKey) val url = "$server/register" val body = RequestBody.create(MediaType.get("application/json"), JsonUtil.toJson(parameters)) val request = Request.Builder().url(url).post(body).build() @@ -62,7 +76,7 @@ object LokiPushNotificationManager { 200 -> { val bodyAsString = response.body()!!.string() val json = JsonUtil.fromJson(bodyAsString, Map::class.java) - val code = json?.get("code") as? Int + val code = json?.get("code") as? Int if (code != null && code != 0) { TextSecurePreferences.setIsUsingFCM(context, true) TextSecurePreferences.setFCMToken(context, token) @@ -78,5 +92,72 @@ object LokiPushNotificationManager { Log.d("Loki", "Couldn't register for FCM.") } }) + + for (closedGroup: String in DatabaseFactory.getSSKDatabase(context).getAllClosedGroupPublicKeys()) { + operateClosedGroup(closedGroup, publicKey, context, subscribe) + } + } + + @JvmStatic + fun operateClosedGroup(closedGroupPublicKey: String, publicKey: String, context: Context?, operation: String) { + Log.d("Loki", "Start to notify PN server of closed group.") + if (!TextSecurePreferences.isUsingFCM(context)) { return } + val parameters = mapOf("closedGroupPublicKey" to closedGroupPublicKey, "pubKey" to publicKey) + val url = "$server/$operation" + val body = RequestBody.create(MediaType.get("application/json"), JsonUtil.toJson(parameters)) + val request = Request.Builder().url(url).post(body).build() + connection.newCall(request).enqueue(object : Callback { + + override fun onResponse(call: Call, response: Response) { + when (response.code()) { + 200 -> { + val bodyAsString = response.body()!!.string() + val json = JsonUtil.fromJson(bodyAsString, Map::class.java) + val code = json?.get("code") as? Int + if (code == null || code == 0) { + Log.d("Loki", "Couldn't subscribe/unsubscribe $closedGroupPublicKey due to error: ${json?.get("message") as? String ?: "null"}.") + } else { + Log.d("Loki", "Subscribe/unsubscribe success.") + } + } + } + } + + override fun onFailure(call: Call, exception: IOException) { + Log.d("Loki", "Couldn't subscribe/unsubscribe $closedGroupPublicKey.") + } + }) + } +} + +class ClosedGroupSubscribeJob private constructor(parameters: Parameters, private val closedGroupPublicKey: String) : BaseJob(parameters) { + + companion object { + const val KEY = "ClosedGroupSubscribeJob" + } + + constructor(closedGroupPublicKey: String) : this(Parameters.Builder() + .addConstraint(NetworkConstraint.KEY) + .setQueue(KEY) + .setLifespan(TimeUnit.DAYS.toMillis(1)) + .setMaxAttempts(1) + .build(), + closedGroupPublicKey) + + override fun serialize(): Data { + val builder = Data.Builder() + builder.putString("closedGroupPublicKey", closedGroupPublicKey) + return builder.build() + } + + override fun getFactoryKey(): String { return KEY } + + override fun onCanceled() { } + + public override fun onRun() { + LokiPushNotificationManager.operateClosedGroup(closedGroupPublicKey, TextSecurePreferences.getLocalNumber(context), context, LokiPushNotificationManager.subscribe) + } + + override fun onShouldRetry(e: Exception): Boolean { return false } } diff --git a/src/org/thoughtcrime/securesms/loki/protocol/ClosedGroupsProtocol.kt b/src/org/thoughtcrime/securesms/loki/protocol/ClosedGroupsProtocol.kt index 0841aaf2a6..aa5d282792 100644 --- a/src/org/thoughtcrime/securesms/loki/protocol/ClosedGroupsProtocol.kt +++ b/src/org/thoughtcrime/securesms/loki/protocol/ClosedGroupsProtocol.kt @@ -8,6 +8,8 @@ import nl.komponents.kovenant.deferred import org.thoughtcrime.securesms.ApplicationContext import org.thoughtcrime.securesms.database.Address import org.thoughtcrime.securesms.database.DatabaseFactory +import org.thoughtcrime.securesms.loki.api.ClosedGroupSubscribeJob +import org.thoughtcrime.securesms.loki.api.LokiPushNotificationManager import org.thoughtcrime.securesms.loki.utilities.recipient import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage import org.thoughtcrime.securesms.recipients.Recipient @@ -33,7 +35,7 @@ import java.io.IOException import java.util.* object ClosedGroupsProtocol { - val isSharedSenderKeysEnabled = false + val isSharedSenderKeysEnabled = true val groupSizeLimit = 10 public fun createClosedGroup(context: Context, name: String, members: Collection): Promise { @@ -70,6 +72,10 @@ object ClosedGroupsProtocol { } // Add the group to the user's set of public keys to poll for DatabaseFactory.getSSKDatabase(context).setClosedGroupPrivateKey(groupPublicKey, groupKeyPair.hexEncodedPrivateKey) + // Notify PN server + val jobForPN = ClosedGroupSubscribeJob(groupPublicKey) + jobForPN.setContext(context) + jobForPN.onRun() // Notify the user val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(Recipient.from(context, Address.fromSerialized(groupID), false)) insertOutgoingInfoMessage(context, groupID, GroupContext.Type.UPDATE, name, members, admins, threadID) @@ -137,6 +143,8 @@ object ClosedGroupsProtocol { sskDatabase.removeClosedGroupPrivateKey(groupPublicKey) groupDB.setActive(groupID, false) groupDB.remove(groupID, Address.fromSerialized(userPublicKey)) + // Notify PN server + LokiPushNotificationManager.operateClosedGroup(groupPublicKey, userPublicKey, context, LokiPushNotificationManager.unsubscribe) } else { // Establish sessions if needed establishSessionsWithMembersIfNeeded(context, members) @@ -231,6 +239,7 @@ object ClosedGroupsProtocol { public fun handleNewClosedGroup(context: Context, closedGroupUpdate: SignalServiceProtos.ClosedGroupUpdate, senderPublicKey: String) { // Prepare + val userPublicKey = TextSecurePreferences.getLocalNumber(context) val sskDatabase = DatabaseFactory.getSSKDatabase(context) // Unwrap the message val groupPublicKey = closedGroupUpdate.groupPublicKey.toByteArray().toHexString() @@ -258,6 +267,8 @@ object ClosedGroupsProtocol { insertIncomingInfoMessage(context, senderPublicKey, groupID, GroupContext.Type.UPDATE, SignalServiceGroup.Type.UPDATE, name, members, admins) // Establish sessions if needed establishSessionsWithMembersIfNeeded(context, members) + // Notify PN server + LokiPushNotificationManager.operateClosedGroup(groupPublicKey, userPublicKey, context, LokiPushNotificationManager.subscribe) } public fun handleClosedGroupUpdate(context: Context, closedGroupUpdate: SignalServiceProtos.ClosedGroupUpdate, senderPublicKey: String) { From 81e1f2d60b87f1dca2f7c81e7cfcd051165e0e07 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Fri, 11 Sep 2020 13:51:14 +1000 Subject: [PATCH 02/17] Minor refactoring --- .../securesms/mediasend/MediaRepository.java | 7 ++++--- .../securesms/mms/AttachmentManager.java | 7 +++---- .../securesms/permissions/Permissions.java | 18 ++++++++++-------- .../securesms/util/SaveAttachmentTask.kt | 2 +- 4 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/org/thoughtcrime/securesms/mediasend/MediaRepository.java b/src/org/thoughtcrime/securesms/mediasend/MediaRepository.java index ffdfecbac5..401ecabeab 100644 --- a/src/org/thoughtcrime/securesms/mediasend/MediaRepository.java +++ b/src/org/thoughtcrime/securesms/mediasend/MediaRepository.java @@ -8,14 +8,14 @@ import android.os.AsyncTask; import android.provider.MediaStore.Images; import android.provider.MediaStore.Video; import android.provider.OpenableColumns; +import android.util.Pair; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.WorkerThread; -import android.util.Pair; import com.annimon.stream.Stream; -import network.loki.messenger.R; import org.thoughtcrime.securesms.mms.PartAuthority; import org.thoughtcrime.securesms.util.MediaUtil; import org.thoughtcrime.securesms.util.Util; @@ -30,6 +30,8 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; +import network.loki.messenger.R; + /** * Handles the retrieval of media present on the user's device. */ @@ -139,7 +141,6 @@ class MediaRepository { @WorkerThread private @NonNull List getMediaInBucket(@NonNull Context context, @NonNull String bucketId, @NonNull Uri contentUri, boolean hasOrientation) { - //TODO Constrain media file size to match the Loki protocol limit. List media = new LinkedList<>(); String selection = Images.Media.BUCKET_ID + " = ? AND " + Images.Media.DATA + " NOT NULL"; String[] selectionArgs = new String[] { bucketId }; diff --git a/src/org/thoughtcrime/securesms/mms/AttachmentManager.java b/src/org/thoughtcrime/securesms/mms/AttachmentManager.java index 16c0d44ed0..80af560c00 100644 --- a/src/org/thoughtcrime/securesms/mms/AttachmentManager.java +++ b/src/org/thoughtcrime/securesms/mms/AttachmentManager.java @@ -30,13 +30,14 @@ import android.os.AsyncTask; import android.provider.ContactsContract; import android.provider.MediaStore; import android.provider.OpenableColumns; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import android.text.TextUtils; import android.util.Pair; import android.view.View; import android.widget.Toast; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import org.thoughtcrime.securesms.MediaPreviewActivity; import org.thoughtcrime.securesms.TransportOption; import org.thoughtcrime.securesms.attachments.Attachment; @@ -378,7 +379,6 @@ public class AttachmentManager { Permissions.with(activity) .request(Manifest.permission.READ_EXTERNAL_STORAGE) .withPermanentDenialDialog(activity.getString(R.string.AttachmentManager_signal_requires_the_external_storage_permission_in_order_to_attach_photos_videos_or_audio)) -// .onAllGranted(() -> selectMediaType(activity, "image/*", new String[] {"image/*", "video/*"}, requestCode)) .onAllGranted(() -> activity.startActivityForResult(MediaSendActivity.buildGalleryIntent(activity, recipient, body, transport), requestCode)) .execute(); } @@ -455,7 +455,6 @@ public class AttachmentManager { } private static void selectMediaType(Activity activity, @NonNull String type, @Nullable String[] extraMimeType, int requestCode) { - //TODO Constrain media file size to match the Loki protocol limit. final Intent intent = new Intent(); intent.setType(type); diff --git a/src/org/thoughtcrime/securesms/permissions/Permissions.java b/src/org/thoughtcrime/securesms/permissions/Permissions.java index 41cce6f8ef..638c9512e8 100644 --- a/src/org/thoughtcrime/securesms/permissions/Permissions.java +++ b/src/org/thoughtcrime/securesms/permissions/Permissions.java @@ -8,20 +8,20 @@ import android.content.pm.PackageManager; import android.net.Uri; import android.os.Build; import android.provider.Settings; -import androidx.annotation.DrawableRes; -import androidx.annotation.NonNull; -import androidx.core.app.ActivityCompat; -import androidx.fragment.app.Fragment; -import androidx.core.content.ContextCompat; import android.util.DisplayMetrics; import android.view.Display; import android.view.ViewGroup; import android.view.WindowManager; +import androidx.annotation.DrawableRes; +import androidx.annotation.NonNull; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; +import androidx.fragment.app.Fragment; + import com.annimon.stream.Stream; import com.annimon.stream.function.Consumer; -import network.loki.messenger.R; import org.thoughtcrime.securesms.util.LRUCache; import org.thoughtcrime.securesms.util.ServiceUtil; @@ -31,6 +31,8 @@ import java.util.Arrays; import java.util.List; import java.util.Map; +import network.loki.messenger.R; + public class Permissions { private static final Map OUTSTANDING = new LRUCache<>(2); @@ -140,9 +142,9 @@ public class Permissions { PermissionsRequest request = new PermissionsRequest(allGrantedListener, anyDeniedListener, anyPermanentlyDeniedListener, anyResultListener, someGrantedListener, someDeniedListener, somePermanentlyDeniedListener); - boolean targetSdk = Build.VERSION.SDK_INT >= minSdkVersion && Build.VERSION.SDK_INT <= maxSdkVersion; + boolean isInTargetSDKRange = (Build.VERSION.SDK_INT >= minSdkVersion && Build.VERSION.SDK_INT <= maxSdkVersion); - if (!targetSdk || permissionObject.hasAll(requestedPermissions)) { + if (!isInTargetSDKRange || permissionObject.hasAll(requestedPermissions)) { executePreGrantedPermissionsRequest(request); } else if (rationaleDialogMessage != null && rationalDialogHeader != null) { executePermissionsRequestWithRationale(request); diff --git a/src/org/thoughtcrime/securesms/util/SaveAttachmentTask.kt b/src/org/thoughtcrime/securesms/util/SaveAttachmentTask.kt index 6e4938dd8c..d4dc58eb7b 100644 --- a/src/org/thoughtcrime/securesms/util/SaveAttachmentTask.kt +++ b/src/org/thoughtcrime/securesms/util/SaveAttachmentTask.kt @@ -157,7 +157,7 @@ class SaveAttachmentTask : ProgressDialogAsyncTask Date: Fri, 11 Sep 2020 13:52:03 +1000 Subject: [PATCH 03/17] Update version number --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 8d5a6f88ab..1b72fc29a1 100644 --- a/build.gradle +++ b/build.gradle @@ -181,8 +181,8 @@ dependencies { testImplementation 'org.robolectric:shadows-multidex:4.2' } -def canonicalVersionCode = 93 -def canonicalVersionName = "1.5.2" +def canonicalVersionCode = 94 +def canonicalVersionName = "1.5.3" def postFixSize = 10 def abiPostFix = ['armeabi-v7a' : 1, From 4f3526d20d4b2b61452bd7eb958b41091ac9827a Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Sat, 12 Sep 2020 08:52:44 +1000 Subject: [PATCH 04/17] Fix open group profile picture bug --- .../securesms/conversation/ConversationItem.java | 13 ++++++++++--- .../securesms/loki/views/ProfilePictureView.kt | 7 ++++++- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/org/thoughtcrime/securesms/conversation/ConversationItem.java b/src/org/thoughtcrime/securesms/conversation/ConversationItem.java index ed4f24d110..a86f02e073 100644 --- a/src/org/thoughtcrime/securesms/conversation/ConversationItem.java +++ b/src/org/thoughtcrime/securesms/conversation/ConversationItem.java @@ -797,14 +797,21 @@ public class ConversationItem extends LinearLayout LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams)bodyBubble.getLayoutParams(); int groupThreadMargin = (int)((12 * getResources().getDisplayMetrics().density) + getResources().getDimension(R.dimen.small_profile_picture_size)); int defaultMargin = 0; - Recipient r = DatabaseFactory.getThreadDatabase(context).getRecipientForThreadId(messageRecord.getThreadId()); + long threadID = messageRecord.getThreadId(); + Recipient r = DatabaseFactory.getThreadDatabase(context).getRecipientForThreadId(threadID); String threadName = r != null ? r.getName() : ""; boolean isRSSFeed = threadName != null && (threadName.equals("Loki News") || threadName.equals("Session Updates")); layoutParams.setMarginStart((groupThread && !isRSSFeed) ? groupThreadMargin : defaultMargin); bodyBubble.setLayoutParams(layoutParams); if (profilePictureView == null) return; - profilePictureView.setPublicKey(recipient.getAddress().toString()); - profilePictureView.setDisplayName(recipient.getName()); + String publicKey = recipient.getAddress().toString(); + profilePictureView.setPublicKey(publicKey); + String displayName = recipient.getName(); + PublicChat publicChat = DatabaseFactory.getLokiThreadDatabase(context).getPublicChat(threadID); + if (displayName == null && publicChat != null) { + displayName = DatabaseFactory.getLokiUserDatabase(context).getServerDisplayName(publicChat.getId(), publicKey); + } + profilePictureView.setDisplayName(displayName); profilePictureView.setAdditionalPublicKey(null); profilePictureView.setRSSFeed(false); profilePictureView.setGlide(glideRequests); diff --git a/src/org/thoughtcrime/securesms/loki/views/ProfilePictureView.kt b/src/org/thoughtcrime/securesms/loki/views/ProfilePictureView.kt index 3ca3317f4f..9a7b9f0c11 100644 --- a/src/org/thoughtcrime/securesms/loki/views/ProfilePictureView.kt +++ b/src/org/thoughtcrime/securesms/loki/views/ProfilePictureView.kt @@ -60,7 +60,12 @@ class ProfilePictureView : RelativeLayout { if (publicKey == null || publicKey.isBlank()) { return null } else { - return DatabaseFactory.getLokiUserDatabase(context).getDisplayName(publicKey!!) + var result = DatabaseFactory.getLokiUserDatabase(context).getDisplayName(publicKey) + val publicChat = DatabaseFactory.getLokiThreadDatabase(context).getPublicChat(threadID) + if (result == null && publicChat != null) { + result = DatabaseFactory.getLokiUserDatabase(context).getServerDisplayName(publicChat.id, publicKey) + } + return result } } if (recipient.isGroupRecipient) { From cb91e6f0f635e50ef7218a8bfc43a0e31dc73a1b Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Sat, 12 Sep 2020 08:55:03 +1000 Subject: [PATCH 05/17] Update build number --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 1b72fc29a1..c7dbb48acd 100644 --- a/build.gradle +++ b/build.gradle @@ -181,7 +181,7 @@ dependencies { testImplementation 'org.robolectric:shadows-multidex:4.2' } -def canonicalVersionCode = 94 +def canonicalVersionCode = 95 def canonicalVersionName = "1.5.3" def postFixSize = 10 From 572ce5fed31029d15004af21145f8b6861611197 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 15 Sep 2020 16:01:45 +1000 Subject: [PATCH 06/17] Debug --- .../securesms/loki/protocol/ClosedGroupUpdateMessageSendJob.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/org/thoughtcrime/securesms/loki/protocol/ClosedGroupUpdateMessageSendJob.kt b/src/org/thoughtcrime/securesms/loki/protocol/ClosedGroupUpdateMessageSendJob.kt index 2c0f4ef702..57310ee18d 100644 --- a/src/org/thoughtcrime/securesms/loki/protocol/ClosedGroupUpdateMessageSendJob.kt +++ b/src/org/thoughtcrime/securesms/loki/protocol/ClosedGroupUpdateMessageSendJob.kt @@ -132,7 +132,6 @@ class ClosedGroupUpdateMessageSendJob private constructor(parameters: Parameters useFallbackEncryption, false, false) } catch (e: Exception) { Log.d("Loki", "Failed to send closed group update message to: $destination due to error: $e.") - throw e } } From 557eecffd1f05c363eb9287aa9094345a09d1270 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 15 Sep 2020 16:57:50 +1000 Subject: [PATCH 07/17] Add missing unsubscribe case --- .../loki/api/LokiPushNotificationManager.kt | 79 +++++++------------ .../loki/protocol/ClosedGroupsProtocol.kt | 22 +++--- 2 files changed, 39 insertions(+), 62 deletions(-) diff --git a/src/org/thoughtcrime/securesms/loki/api/LokiPushNotificationManager.kt b/src/org/thoughtcrime/securesms/loki/api/LokiPushNotificationManager.kt index e59502174d..59fa012e2d 100644 --- a/src/org/thoughtcrime/securesms/loki/api/LokiPushNotificationManager.kt +++ b/src/org/thoughtcrime/securesms/loki/api/LokiPushNotificationManager.kt @@ -17,19 +17,27 @@ import java.util.concurrent.TimeUnit object LokiPushNotificationManager { private val connection = OkHttpClient() + private val tokenExpirationInterval = 12 * 60 * 60 * 1000 private val server by lazy { PushNotificationAcknowledgement.shared.server } - public const val subscribe = "subscribe_closed_group" - public const val unsubscribe = "unsubscribe_closed_group" + enum class ClosedGroupOperation { + Subscribe, Unsubscribe; - private const val tokenExpirationInterval = 12 * 60 * 60 * 1000 + val rawValue: String + get() { + return when (this) { + Subscribe -> "subscribe_closed_group" + Unsubscribe -> "unsubscribe_closed_group" + } + } + } @JvmStatic - fun unregister(token: String, context: Context?) { - val parameters = mapOf("token" to token) + fun unregister(token: String, context: Context) { + val parameters = mapOf( "token" to token ) val url = "$server/register" val body = RequestBody.create(MediaType.get("application/json"), JsonUtil.toJson(parameters)) val request = Request.Builder().url(url).post(body).build() @@ -54,18 +62,20 @@ object LokiPushNotificationManager { Log.d("Loki", "Couldn't disable FCM.") } }) - - for (closedGroup: String in DatabaseFactory.getSSKDatabase(context).getAllClosedGroupPublicKeys()) { - operateClosedGroup(closedGroup, TextSecurePreferences.getLocalNumber(context), context, unsubscribe) + // Unsubscribe from all closed groups + val allClosedGroupPublicKeys = DatabaseFactory.getSSKDatabase(context).getAllClosedGroupPublicKeys() + val userPublicKey = TextSecurePreferences.getLocalNumber(context) + allClosedGroupPublicKeys.forEach { closedGroup -> + performOperation(context, ClosedGroupOperation.Unsubscribe, closedGroup, userPublicKey) } } @JvmStatic - fun register(token: String, publicKey: String, context: Context?, force: Boolean) { + fun register(token: String, publicKey: String, context: Context, force: Boolean) { val oldToken = TextSecurePreferences.getFCMToken(context) val lastUploadDate = TextSecurePreferences.getLastFCMUploadTime(context) if (!force && token == oldToken && System.currentTimeMillis() - lastUploadDate < tokenExpirationInterval) { return } - val parameters = mapOf("token" to token, "pubKey" to publicKey) + val parameters = mapOf( "token" to token, "pubKey" to publicKey ) val url = "$server/register" val body = RequestBody.create(MediaType.get("application/json"), JsonUtil.toJson(parameters)) val request = Request.Builder().url(url).post(body).build() @@ -92,19 +102,19 @@ object LokiPushNotificationManager { Log.d("Loki", "Couldn't register for FCM.") } }) - - for (closedGroup: String in DatabaseFactory.getSSKDatabase(context).getAllClosedGroupPublicKeys()) { - operateClosedGroup(closedGroup, publicKey, context, subscribe) + // Subscribe to all closed groups + val allClosedGroupPublicKeys = DatabaseFactory.getSSKDatabase(context).getAllClosedGroupPublicKeys() + allClosedGroupPublicKeys.forEach { closedGroup -> + performOperation(context, ClosedGroupOperation.Subscribe, closedGroup, publicKey) } - } @JvmStatic - fun operateClosedGroup(closedGroupPublicKey: String, publicKey: String, context: Context?, operation: String) { + fun performOperation(context: Context, operation: ClosedGroupOperation, closedGroupPublicKey: String, publicKey: String) { Log.d("Loki", "Start to notify PN server of closed group.") if (!TextSecurePreferences.isUsingFCM(context)) { return } val parameters = mapOf("closedGroupPublicKey" to closedGroupPublicKey, "pubKey" to publicKey) - val url = "$server/$operation" + val url = "$server/${operation.rawValue}" val body = RequestBody.create(MediaType.get("application/json"), JsonUtil.toJson(parameters)) val request = Request.Builder().url(url).post(body).build() connection.newCall(request).enqueue(object : Callback { @@ -116,48 +126,15 @@ object LokiPushNotificationManager { val json = JsonUtil.fromJson(bodyAsString, Map::class.java) val code = json?.get("code") as? Int if (code == null || code == 0) { - Log.d("Loki", "Couldn't subscribe/unsubscribe $closedGroupPublicKey due to error: ${json?.get("message") as? String ?: "null"}.") - } else { - Log.d("Loki", "Subscribe/unsubscribe success.") + Log.d("Loki", "Couldn't subscribe/unsubscribe to/from PNs for closed group with ID: $closedGroupPublicKey due to error: ${json?.get("message") as? String ?: "null"}.") } } } } override fun onFailure(call: Call, exception: IOException) { - Log.d("Loki", "Couldn't subscribe/unsubscribe $closedGroupPublicKey.") + Log.d("Loki", "Couldn't subscribe/unsubscribe to/from PNs for closed group with ID: $closedGroupPublicKey due to error: $exception.") } }) } } - -class ClosedGroupSubscribeJob private constructor(parameters: Parameters, private val closedGroupPublicKey: String) : BaseJob(parameters) { - - companion object { - const val KEY = "ClosedGroupSubscribeJob" - } - - constructor(closedGroupPublicKey: String) : this(Parameters.Builder() - .addConstraint(NetworkConstraint.KEY) - .setQueue(KEY) - .setLifespan(TimeUnit.DAYS.toMillis(1)) - .setMaxAttempts(1) - .build(), - closedGroupPublicKey) - - override fun serialize(): Data { - val builder = Data.Builder() - builder.putString("closedGroupPublicKey", closedGroupPublicKey) - return builder.build() - } - - override fun getFactoryKey(): String { return KEY } - - override fun onCanceled() { } - - public override fun onRun() { - LokiPushNotificationManager.operateClosedGroup(closedGroupPublicKey, TextSecurePreferences.getLocalNumber(context), context, LokiPushNotificationManager.subscribe) - } - - override fun onShouldRetry(e: Exception): Boolean { return false } -} diff --git a/src/org/thoughtcrime/securesms/loki/protocol/ClosedGroupsProtocol.kt b/src/org/thoughtcrime/securesms/loki/protocol/ClosedGroupsProtocol.kt index aa5d282792..2ff6e2a137 100644 --- a/src/org/thoughtcrime/securesms/loki/protocol/ClosedGroupsProtocol.kt +++ b/src/org/thoughtcrime/securesms/loki/protocol/ClosedGroupsProtocol.kt @@ -8,8 +8,8 @@ import nl.komponents.kovenant.deferred import org.thoughtcrime.securesms.ApplicationContext import org.thoughtcrime.securesms.database.Address import org.thoughtcrime.securesms.database.DatabaseFactory -import org.thoughtcrime.securesms.loki.api.ClosedGroupSubscribeJob import org.thoughtcrime.securesms.loki.api.LokiPushNotificationManager +import org.thoughtcrime.securesms.loki.api.LokiPushNotificationManager.ClosedGroupOperation import org.thoughtcrime.securesms.loki.utilities.recipient import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage import org.thoughtcrime.securesms.recipients.Recipient @@ -35,7 +35,7 @@ import java.io.IOException import java.util.* object ClosedGroupsProtocol { - val isSharedSenderKeysEnabled = true + val isSharedSenderKeysEnabled = false val groupSizeLimit = 10 public fun createClosedGroup(context: Context, name: String, members: Collection): Promise { @@ -68,17 +68,15 @@ object ClosedGroupsProtocol { if (member == userPublicKey) { continue } val job = ClosedGroupUpdateMessageSendJob(member, closedGroupUpdateKind) job.setContext(context) - job.onRun() // Run the job immediately + job.onRun() // Run the job immediately to make all of this sync } // Add the group to the user's set of public keys to poll for DatabaseFactory.getSSKDatabase(context).setClosedGroupPrivateKey(groupPublicKey, groupKeyPair.hexEncodedPrivateKey) - // Notify PN server - val jobForPN = ClosedGroupSubscribeJob(groupPublicKey) - jobForPN.setContext(context) - jobForPN.onRun() // Notify the user val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(Recipient.from(context, Address.fromSerialized(groupID), false)) insertOutgoingInfoMessage(context, groupID, GroupContext.Type.UPDATE, name, members, admins, threadID) + // Notify the PN server + LokiPushNotificationManager.performOperation(context, ClosedGroupOperation.Subscribe, groupPublicKey, userPublicKey) // Fulfill the promise deferred.resolve(groupID) }.start() @@ -143,8 +141,8 @@ object ClosedGroupsProtocol { sskDatabase.removeClosedGroupPrivateKey(groupPublicKey) groupDB.setActive(groupID, false) groupDB.remove(groupID, Address.fromSerialized(userPublicKey)) - // Notify PN server - LokiPushNotificationManager.operateClosedGroup(groupPublicKey, userPublicKey, context, LokiPushNotificationManager.unsubscribe) + // Notify the PN server + LokiPushNotificationManager.performOperation(context, ClosedGroupOperation.Unsubscribe, groupPublicKey, userPublicKey) } else { // Establish sessions if needed establishSessionsWithMembersIfNeeded(context, members) @@ -267,8 +265,8 @@ object ClosedGroupsProtocol { insertIncomingInfoMessage(context, senderPublicKey, groupID, GroupContext.Type.UPDATE, SignalServiceGroup.Type.UPDATE, name, members, admins) // Establish sessions if needed establishSessionsWithMembersIfNeeded(context, members) - // Notify PN server - LokiPushNotificationManager.operateClosedGroup(groupPublicKey, userPublicKey, context, LokiPushNotificationManager.subscribe) + // Notify the PN server + LokiPushNotificationManager.performOperation(context, ClosedGroupOperation.Subscribe, groupPublicKey, userPublicKey) } public fun handleClosedGroupUpdate(context: Context, closedGroupUpdate: SignalServiceProtos.ClosedGroupUpdate, senderPublicKey: String) { @@ -314,6 +312,8 @@ object ClosedGroupsProtocol { sskDatabase.removeClosedGroupPrivateKey(groupPublicKey) groupDB.setActive(groupID, false) groupDB.remove(groupID, Address.fromSerialized(userPublicKey)) + // Notify the PN server + LokiPushNotificationManager.performOperation(context, ClosedGroupOperation.Unsubscribe, groupPublicKey, userPublicKey) } else { establishSessionsWithMembersIfNeeded(context, members) val userRatchet = SharedSenderKeysImplementation.shared.generateRatchet(groupPublicKey, userPublicKey) From 518e88bd0a9f312a79cbf2dee6eca307c43a39c2 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 15 Sep 2020 17:00:18 +1000 Subject: [PATCH 08/17] Clean --- .../securesms/loki/api/LokiPushNotificationManager.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/org/thoughtcrime/securesms/loki/api/LokiPushNotificationManager.kt b/src/org/thoughtcrime/securesms/loki/api/LokiPushNotificationManager.kt index 59fa012e2d..ac81b2a284 100644 --- a/src/org/thoughtcrime/securesms/loki/api/LokiPushNotificationManager.kt +++ b/src/org/thoughtcrime/securesms/loki/api/LokiPushNotificationManager.kt @@ -111,9 +111,8 @@ object LokiPushNotificationManager { @JvmStatic fun performOperation(context: Context, operation: ClosedGroupOperation, closedGroupPublicKey: String, publicKey: String) { - Log.d("Loki", "Start to notify PN server of closed group.") if (!TextSecurePreferences.isUsingFCM(context)) { return } - val parameters = mapOf("closedGroupPublicKey" to closedGroupPublicKey, "pubKey" to publicKey) + val parameters = mapOf( "closedGroupPublicKey" to closedGroupPublicKey, "pubKey" to publicKey ) val url = "$server/${operation.rawValue}" val body = RequestBody.create(MediaType.get("application/json"), JsonUtil.toJson(parameters)) val request = Request.Builder().url(url).post(body).build() From c4ea3240e39a93b2e1d527e67cd9fc8511544128 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 15 Sep 2020 17:10:48 +1000 Subject: [PATCH 09/17] Handle non-200 response codes --- .../securesms/loki/api/LokiPushNotificationManager.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/org/thoughtcrime/securesms/loki/api/LokiPushNotificationManager.kt b/src/org/thoughtcrime/securesms/loki/api/LokiPushNotificationManager.kt index ac81b2a284..19f49bf67e 100644 --- a/src/org/thoughtcrime/securesms/loki/api/LokiPushNotificationManager.kt +++ b/src/org/thoughtcrime/securesms/loki/api/LokiPushNotificationManager.kt @@ -128,6 +128,9 @@ object LokiPushNotificationManager { Log.d("Loki", "Couldn't subscribe/unsubscribe to/from PNs for closed group with ID: $closedGroupPublicKey due to error: ${json?.get("message") as? String ?: "null"}.") } } + else -> { + Log.d("Loki", "Couldn't subscribe/unsubscribe to/from PNs for closed group with ID: $closedGroupPublicKey.") + } } } From 4246c8c6a4f7bd3e68956c57657ae77039583946 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Wed, 16 Sep 2020 09:11:39 +1000 Subject: [PATCH 10/17] Minor UI tweaks --- res/layout-sw400dp/fragment_enter_chat_url.xml | 1 + res/layout/fragment_enter_chat_url.xml | 1 + res/values-notnight-v21/styles.xml | 5 +++++ res/values-notnight-v21/themes.xml | 1 - 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/res/layout-sw400dp/fragment_enter_chat_url.xml b/res/layout-sw400dp/fragment_enter_chat_url.xml index 7e81c7dd7b..a1bf13aedc 100644 --- a/res/layout-sw400dp/fragment_enter_chat_url.xml +++ b/res/layout-sw400dp/fragment_enter_chat_url.xml @@ -21,6 +21,7 @@ android:layout_marginLeft="@dimen/large_spacing" android:layout_marginTop="@dimen/large_spacing" android:layout_marginRight="@dimen/large_spacing" + android:inputType="textWebEmailAddress" android:hint="Enter an open group URL" /> 4dp + + \ No newline at end of file diff --git a/res/values-notnight-v21/themes.xml b/res/values-notnight-v21/themes.xml index 3743b4fc5a..f1c362efda 100644 --- a/res/values-notnight-v21/themes.xml +++ b/res/values-notnight-v21/themes.xml @@ -31,7 +31,6 @@ -