diff --git a/app/build.gradle b/app/build.gradle index db9c42d43a..91ee23fbb4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -133,7 +133,7 @@ android { apply plugin: 'com.google.gms.google-services' ext.websiteUpdateUrl = "null" buildConfigField "boolean", "PLAY_STORE_DISABLED", "false" - buildConfigField "String", "DEVICE", "\"android\"" + buildConfigField "org.session.libsession.utilities.Device", "DEVICE", "org.session.libsession.utilities.Device.ANDROID" buildConfigField "String", "NOPLAY_UPDATE_URL", "$ext.websiteUpdateUrl" } @@ -141,7 +141,7 @@ android { dimension "distribution" ext.websiteUpdateUrl = "null" buildConfigField "boolean", "PLAY_STORE_DISABLED", "true" - buildConfigField "String", "DEVICE", "\"huawei\"" + buildConfigField "org.session.libsession.utilities.Device", "DEVICE", "org.session.libsession.utilities.Device.HUAWEI" buildConfigField "String", "NOPLAY_UPDATE_URL", "$ext.websiteUpdateUrl" } @@ -149,7 +149,7 @@ android { dimension "distribution" ext.websiteUpdateUrl = "https://github.com/oxen-io/session-android/releases" buildConfigField "boolean", "PLAY_STORE_DISABLED", "true" - buildConfigField "String", "DEVICE", "\"android\"" + buildConfigField "org.session.libsession.utilities.Device", "DEVICE", "org.session.libsession.utilities.Device.ANDROID" buildConfigField "String", "NOPLAY_UPDATE_URL", "\"$ext.websiteUpdateUrl\"" } } diff --git a/app/src/huawei/kotlin/org/thoughtcrime/securesms/notifications/HuaweiPushManager.kt b/app/src/huawei/kotlin/org/thoughtcrime/securesms/notifications/HuaweiPushManager.kt index 72a22ecfa4..f17b35f292 100644 --- a/app/src/huawei/kotlin/org/thoughtcrime/securesms/notifications/HuaweiPushManager.kt +++ b/app/src/huawei/kotlin/org/thoughtcrime/securesms/notifications/HuaweiPushManager.kt @@ -1,9 +1,29 @@ package org.thoughtcrime.securesms.notifications import android.content.Context +import com.huawei.hms.aaid.HmsInstanceId +import kotlinx.coroutines.Job class HuaweiPushManager(val context: Context): PushManager { + private var huaweiPushInstanceIdJob: Job? = null + + @Synchronized override fun refresh(force: Boolean) { + val huaweiPushInstanceIdJob = huaweiPushInstanceIdJob + + huaweiPushInstanceIdJob?.apply { + if (force) cancel() else if (isActive) return + } + + val hmsInstanceId = HmsInstanceId.getInstance(context) + + val task = hmsInstanceId.aaid +// HuaweiPushNotificationService().start() +// +// huaweiPushInstanceIdJob = HmsInstanceId.getInstance(this) { hmsInstanceId -> +// RegisterHuaweiPushService(hmsInstanceId, this, force).start() +// Unit.INSTANCE +// } } } diff --git a/app/src/huawei/kotlin/org/thoughtcrime/securesms/notifications/HuaweiPushNotificationService.kt b/app/src/huawei/kotlin/org/thoughtcrime/securesms/notifications/HuaweiPushNotificationService.kt index dd475c8344..e6941a563d 100644 --- a/app/src/huawei/kotlin/org/thoughtcrime/securesms/notifications/HuaweiPushNotificationService.kt +++ b/app/src/huawei/kotlin/org/thoughtcrime/securesms/notifications/HuaweiPushNotificationService.kt @@ -18,42 +18,19 @@ import javax.inject.Inject @AndroidEntryPoint class HuaweiPushNotificationService: HmsMessageService() { - @Inject token + @Inject lateinit var pushManager: PushManager + @Inject lateinit var pushHandler: PushHandler override fun onNewToken(token: String?, bundle: Bundle?) { Log.d("Loki", "New HCM token: $token.") - - if (!token.isNullOrEmpty()) { - val userPublicKey = TextSecurePreferences.getLocalNumber(this) ?: return - PushManager.register(token, userPublicKey, this, false) - } + pushManager.refresh(true) } override fun onMessageReceived(message: RemoteMessage?) { - Log.d("Loki", "Received a push notification.") - val base64EncodedData = message?.data - val data = base64EncodedData?.let { Base64.decode(it) } - if (data != null) { - try { - val envelopeAsData = MessageWrapper.unwrap(data).toByteArray() - val job = BatchMessageReceiveJob(listOf(MessageReceiveParameters(envelopeAsData)), null) - JobQueue.shared.add(job) - } catch (e: Exception) { - Log.d("Loki", "Failed to unwrap data for message due to error: $e.") - } - } else { - Log.d("Loki", "Failed to decode data for message.") - val builder = NotificationCompat.Builder(this, NotificationChannels.OTHER) - .setSmallIcon(network.loki.messenger.R.drawable.ic_notification) - .setColor(this.getResources().getColor(network.loki.messenger.R.color.textsecure_primary)) - .setContentTitle("Session") - .setContentText("You've got a new message.") - .setPriority(NotificationCompat.PRIORITY_DEFAULT) - .setAutoCancel(true) - with(NotificationManagerCompat.from(this)) { - notify(11111, builder.build()) - } - } + pushHandler.onPush(message?.dataOfMap) } -} \ No newline at end of file + override fun onDeletedMessages() { + pushManager.refresh(true) + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java b/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java index 0ba8a77879..2fe1b1e1c7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java +++ b/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java @@ -41,6 +41,7 @@ import org.session.libsession.messaging.sending_receiving.pollers.Poller; import org.session.libsession.snode.SnodeModule; import org.session.libsession.utilities.Address; import org.session.libsession.utilities.ConfigFactoryUpdateListener; +import org.session.libsession.utilities.Device; import org.session.libsession.utilities.ProfilePictureUtilities; import org.session.libsession.utilities.SSKEnvironment; import org.session.libsession.utilities.TextSecurePreferences; @@ -142,6 +143,7 @@ public class ApplicationContext extends Application implements DefaultLifecycleO @Inject LokiAPIDatabase lokiAPIDatabase; @Inject public Storage storage; + @Inject Device device; @Inject MessageDataProvider messageDataProvider; @Inject TextSecurePreferences textSecurePreferences; @Inject PushManager pushManager; @@ -207,8 +209,10 @@ public class ApplicationContext extends Application implements DefaultLifecycleO DatabaseModule.init(this); MessagingModuleConfiguration.configure(this); super.onCreate(); - messagingModuleConfiguration = new MessagingModuleConfiguration(this, + messagingModuleConfiguration = new MessagingModuleConfiguration( + this, storage, + device, messageDataProvider, ()-> KeyPairUtilities.INSTANCE.getUserED25519KeyPair(this), configFactory diff --git a/app/src/main/java/org/thoughtcrime/securesms/DeviceModule.kt b/app/src/main/java/org/thoughtcrime/securesms/DeviceModule.kt new file mode 100644 index 0000000000..bdfa9b6088 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/DeviceModule.kt @@ -0,0 +1,16 @@ +package org.thoughtcrime.securesms + +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import network.loki.messenger.BuildConfig +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +object DeviceModule { + @Provides + @Singleton + fun provides() = BuildConfig.DEVICE +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/CreateGroupFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/groups/CreateGroupFragment.kt index ead979b773..ecd40938a1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/CreateGroupFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/CreateGroupFragment.kt @@ -21,6 +21,7 @@ import nl.komponents.kovenant.ui.successUi import org.session.libsession.messaging.sending_receiving.MessageSender import org.session.libsession.messaging.sending_receiving.groupSizeLimit import org.session.libsession.utilities.Address +import org.session.libsession.utilities.Device import org.session.libsession.utilities.TextSecurePreferences import org.session.libsession.utilities.recipients.Recipient import org.thoughtcrime.securesms.contacts.SelectContactsAdapter @@ -31,10 +32,14 @@ import org.thoughtcrime.securesms.keyboard.emoji.KeyboardPageSearchView import org.thoughtcrime.securesms.mms.GlideApp import org.thoughtcrime.securesms.util.fadeIn import org.thoughtcrime.securesms.util.fadeOut +import javax.inject.Inject @AndroidEntryPoint class CreateGroupFragment : Fragment() { + @Inject + lateinit var device: Device + private lateinit var binding: FragmentCreateGroupBinding private val viewModel: CreateGroupViewModel by viewModels() @@ -86,7 +91,7 @@ class CreateGroupFragment : Fragment() { val userPublicKey = TextSecurePreferences.getLocalNumber(requireContext())!! isLoading = true binding.loaderContainer.fadeIn() - MessageSender.createClosedGroup(name.toString(), selectedMembers + setOf( userPublicKey )).successUi { groupID -> + MessageSender.createClosedGroup(device, name.toString(), selectedMembers + setOf( userPublicKey )).successUi { groupID -> binding.loaderContainer.fadeOut() isLoading = false val threadID = DatabaseComponent.get(requireContext()).threadDatabase().getOrCreateThreadIdFor(Recipient.from(requireContext(), Address.fromSerialized(groupID), false)) diff --git a/app/src/main/kotlin/org/thoughtcrime/securesms/notifications/ExpiryManager.kt b/app/src/main/java/org/thoughtcrime/securesms/notifications/ExpiryManager.kt similarity index 100% rename from app/src/main/kotlin/org/thoughtcrime/securesms/notifications/ExpiryManager.kt rename to app/src/main/java/org/thoughtcrime/securesms/notifications/ExpiryManager.kt diff --git a/app/src/main/kotlin/org/thoughtcrime/securesms/notifications/FcmTokenManager.kt b/app/src/main/java/org/thoughtcrime/securesms/notifications/FcmTokenManager.kt similarity index 100% rename from app/src/main/kotlin/org/thoughtcrime/securesms/notifications/FcmTokenManager.kt rename to app/src/main/java/org/thoughtcrime/securesms/notifications/FcmTokenManager.kt diff --git a/app/src/main/java/org/thoughtcrime/securesms/notifications/PushHandler.kt b/app/src/main/java/org/thoughtcrime/securesms/notifications/PushHandler.kt index be4832104d..bba89d2e96 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/notifications/PushHandler.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/notifications/PushHandler.kt @@ -29,24 +29,26 @@ private const val TAG = "PushHandler" class PushHandler @Inject constructor(@ApplicationContext val context: Context) { private val sodium = LazySodiumAndroid(SodiumAndroid()) - fun onPush(dataMap: Map) { - val data: ByteArray? = if (dataMap.containsKey("spns")) { - // this is a v2 push notification - try { - decrypt(Base64.decode(dataMap["enc_payload"])) - } catch(e: Exception) { - Log.e(TAG, "Invalid push notification: ${e.message}") - return - } - } else { - // old v1 push notification; we still need this for receiving legacy closed group notifications - dataMap.get("ENCRYPTED_DATA")?.let(Base64::decode) + fun onPush(dataMap: Map?) { + onPush(dataMap?.asByteArray()) + } + + private fun onPush(data: ByteArray?) { + if (data == null) { + onPush() + return } - data?.let { onPush(data) } ?: onPush() + try { + val envelopeAsData = MessageWrapper.unwrap(data).toByteArray() + val job = BatchMessageReceiveJob(listOf(MessageReceiveParameters(envelopeAsData)), null) + JobQueue.shared.add(job) + } catch (e: Exception) { + Log.d(TAG, "Failed to unwrap data for message due to error: $e.") + } } - fun onPush() { + private fun onPush() { Log.d(TAG, "Failed to decode data for message.") val builder = NotificationCompat.Builder(context, NotificationChannels.OTHER) .setSmallIcon(network.loki.messenger.R.drawable.ic_notification) @@ -58,15 +60,20 @@ class PushHandler @Inject constructor(@ApplicationContext val context: Context) NotificationManagerCompat.from(context).notify(11111, builder.build()) } - fun onPush(data: ByteArray) { - try { - val envelopeAsData = MessageWrapper.unwrap(data).toByteArray() - val job = BatchMessageReceiveJob(listOf(MessageReceiveParameters(envelopeAsData)), null) - JobQueue.shared.add(job) - } catch (e: Exception) { - Log.d(TAG, "Failed to unwrap data for message due to error: $e.") + private fun Map.asByteArray() = + when { + // this is a v2 push notification + containsKey("spns") -> { + try { + decrypt(Base64.decode(this["enc_payload"])) + } catch (e: Exception) { + Log.e(TAG, "Invalid push notification: ${e.message}") + null + } + } + // old v1 push notification; we still need this for receiving legacy closed group notifications + else -> this["ENCRYPTED_DATA"]?.let(Base64::decode) } - } fun decrypt(encPayload: ByteArray): ByteArray? { Log.d(TAG, "decrypt() called") @@ -84,14 +91,18 @@ class PushHandler @Inject constructor(@ApplicationContext val context: Context) val metadataJson = (expectedList[0] as? BencodeString)?.value ?: error("no metadata") val metadata: PushNotificationMetadata = Json.decodeFromString(String(metadataJson)) - val content: ByteArray? = if (expectedList.size >= 2) (expectedList[1] as? BencodeString)?.value else null + val content: ByteArray? = + if (expectedList.size >= 2) (expectedList[1] as? BencodeString)?.value else null // null content is valid only if we got a "data_too_long" flag if (content == null) check(metadata.data_too_long) { "missing message data, but no too-long flag" } else check(metadata.data_len == content.size) { "wrong message data size" } - Log.d(TAG, "Received push for ${metadata.account}/${metadata.namespace}, msg ${metadata.msg_hash}, ${metadata.data_len}B") + Log.d( + TAG, + "Received push for ${metadata.account}/${metadata.namespace}, msg ${metadata.msg_hash}, ${metadata.data_len}B" + ) return content } @@ -102,6 +113,11 @@ class PushHandler @Inject constructor(@ApplicationContext val context: Context) val key = sodium.keygen(AEAD.Method.XCHACHA20_POLY1305_IETF) IdentityKeyUtil.save(context, IdentityKeyUtil.NOTIFICATION_KEY, key.asHexString) } - return Key.fromHexString(IdentityKeyUtil.retrieve(context, IdentityKeyUtil.NOTIFICATION_KEY)) + return Key.fromHexString( + IdentityKeyUtil.retrieve( + context, + IdentityKeyUtil.NOTIFICATION_KEY + ) + ) } } diff --git a/app/src/play/kotlin/org/thoughtcrime/securesms/notifications/FirebasePushManager.kt b/app/src/play/kotlin/org/thoughtcrime/securesms/notifications/FirebasePushManager.kt index df15efe80c..3df54fc119 100644 --- a/app/src/play/kotlin/org/thoughtcrime/securesms/notifications/FirebasePushManager.kt +++ b/app/src/play/kotlin/org/thoughtcrime/securesms/notifications/FirebasePushManager.kt @@ -1,60 +1,22 @@ package org.thoughtcrime.securesms.notifications import android.content.Context -import com.goterl.lazysodium.LazySodiumAndroid -import com.goterl.lazysodium.SodiumAndroid -import com.goterl.lazysodium.interfaces.AEAD -import com.goterl.lazysodium.interfaces.Sign -import com.goterl.lazysodium.utils.Key -import com.goterl.lazysodium.utils.KeyPair +import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.Job -import kotlinx.serialization.decodeFromString -import kotlinx.serialization.encodeToString -import kotlinx.serialization.json.Json -import kotlinx.serialization.json.decodeFromStream -import nl.komponents.kovenant.Promise -import nl.komponents.kovenant.combine.and -import nl.komponents.kovenant.functional.map -import okhttp3.MediaType -import okhttp3.Request -import okhttp3.RequestBody -import org.session.libsession.messaging.sending_receiving.notifications.PushManagerV1 -import org.session.libsession.messaging.sending_receiving.notifications.PushNotificationMetadata -import org.session.libsession.messaging.sending_receiving.notifications.Response -import org.session.libsession.messaging.sending_receiving.notifications.SubscriptionRequest -import org.session.libsession.messaging.sending_receiving.notifications.SubscriptionResponse -import org.session.libsession.messaging.sending_receiving.notifications.UnsubscribeResponse -import org.session.libsession.messaging.sending_receiving.notifications.UnsubscriptionRequest -import org.session.libsession.messaging.utilities.SodiumUtilities -import org.session.libsession.snode.OnionRequestAPI -import org.session.libsession.snode.SnodeAPI -import org.session.libsession.snode.Version -import org.session.libsession.utilities.TextSecurePreferences.Companion.getLocalNumber -import org.session.libsession.utilities.bencode.Bencode -import org.session.libsession.utilities.bencode.BencodeList -import org.session.libsession.utilities.bencode.BencodeString -import org.session.libsignal.utilities.Base64 +import org.session.libsession.utilities.Device import org.session.libsignal.utilities.Log -import org.session.libsignal.utilities.Namespace -import org.session.libsignal.utilities.emptyPromise -import org.session.libsignal.utilities.retryIfNeeded -import org.thoughtcrime.securesms.crypto.IdentityKeyUtil -import org.thoughtcrime.securesms.crypto.KeyPairUtilities import javax.inject.Inject +import javax.inject.Singleton private const val TAG = "FirebasePushManager" -class FirebasePushManager( - private val context: Context - ): PushManager { +@Singleton +class FirebasePushManager @Inject constructor( + @ApplicationContext private val context: Context +): PushManager { - @Inject lateinit var pushManagerV2: PushManagerV2 + @Inject lateinit var genericPushManager: GenericPushManager - companion object { - const val maxRetryCount = 4 - } - - private val tokenManager = FcmTokenManager(context, ExpiryManager(context)) private var firebaseInstanceIdJob: Job? = null @Synchronized @@ -67,70 +29,9 @@ class FirebasePushManager( firebaseInstanceIdJob = getFcmInstanceId { task -> when { - task.isSuccessful -> try { task.result?.token?.let { refresh(it, force).get() } } catch(e: Exception) { Log.e(TAG, "refresh() failed", e) } + task.isSuccessful -> try { task.result?.token?.let { genericPushManager.refresh(it, force).get() } } catch(e: Exception) { Log.e(TAG, "refresh() failed", e) } else -> Log.w(TAG, "getFcmInstanceId failed." + task.exception) } } } - - private fun refresh(token: String, force: Boolean): Promise<*, Exception> { - Log.d(TAG, "refresh() called") - - val userPublicKey = getLocalNumber(context) ?: return emptyPromise() - val userEdKey = KeyPairUtilities.getUserED25519KeyPair(context) ?: return emptyPromise() - - return when { - tokenManager.isUsingFCM -> register(force, token, userPublicKey, userEdKey) - tokenManager.requiresUnregister -> unregister(token, userPublicKey, userEdKey) - else -> emptyPromise() - } - } - - /** - * Register for push notifications if: - * force is true - * there is no FCM Token - * FCM Token has expired - */ - private fun register( - force: Boolean, - token: String, - publicKey: String, - userEd25519Key: KeyPair, - namespaces: List = listOf(Namespace.DEFAULT) - ): Promise<*, Exception> = if (force || tokenManager.isInvalid()) { - register(token, publicKey, userEd25519Key, namespaces) - } else emptyPromise() - - /** - * Register for push notifications. - */ - private fun register( - token: String, - publicKey: String, - userEd25519Key: KeyPair, - namespaces: List = listOf(Namespace.DEFAULT) - ): Promise<*, Exception> = PushManagerV1.register( - token = token, - publicKey = publicKey - ) and pushManagerV2.register( - token, publicKey, userEd25519Key, namespaces - ) fail { - Log.e(TAG, "registerBoth failed", it) - } success { - Log.d(TAG, "registerBoth success... saving token!!") - tokenManager.fcmToken = token - } - - private fun unregister( - token: String, - userPublicKey: String, - userEdKey: KeyPair - ): Promise<*, Exception> = PushManagerV1.unregister() and pushManagerV2.unregister( - token, userPublicKey, userEdKey - ) fail { - Log.e(TAG, "unregisterBoth failed", it) - } success { - tokenManager.fcmToken = null - } } diff --git a/app/src/play/kotlin/org/thoughtcrime/securesms/notifications/FirebasePushModule.kt b/app/src/play/kotlin/org/thoughtcrime/securesms/notifications/FirebasePushModule.kt index 3f33016a02..925ad9d4d7 100644 --- a/app/src/play/kotlin/org/thoughtcrime/securesms/notifications/FirebasePushModule.kt +++ b/app/src/play/kotlin/org/thoughtcrime/securesms/notifications/FirebasePushModule.kt @@ -1,28 +1,13 @@ package org.thoughtcrime.securesms.notifications -import android.content.Context import dagger.Binds import dagger.Module -import dagger.Provides import dagger.hilt.InstallIn -import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.components.SingletonComponent -import org.session.libsession.utilities.TextSecurePreferences -import javax.inject.Singleton - -@Module -@InstallIn(SingletonComponent::class) -object FirebasePushModule { - @Provides - @Singleton - fun provideFirebasePushManager( - @ApplicationContext context: Context, - ) = FirebasePushManager(context) -} @Module @InstallIn(SingletonComponent::class) abstract class FirebaseBindingModule { @Binds abstract fun bindPushManager(firebasePushManager: FirebasePushManager): PushManager -} \ No newline at end of file +} diff --git a/app/src/play/kotlin/org/thoughtcrime/securesms/notifications/GenericPushManager.kt b/app/src/play/kotlin/org/thoughtcrime/securesms/notifications/GenericPushManager.kt new file mode 100644 index 0000000000..692826225d --- /dev/null +++ b/app/src/play/kotlin/org/thoughtcrime/securesms/notifications/GenericPushManager.kt @@ -0,0 +1,87 @@ +package org.thoughtcrime.securesms.notifications + +import android.content.Context +import com.goterl.lazysodium.utils.KeyPair +import nl.komponents.kovenant.Promise +import nl.komponents.kovenant.combine.and +import org.session.libsession.messaging.sending_receiving.notifications.PushManagerV1 +import org.session.libsession.utilities.Device +import org.session.libsession.utilities.TextSecurePreferences +import org.session.libsignal.utilities.Log +import org.session.libsignal.utilities.Namespace +import org.session.libsignal.utilities.emptyPromise +import org.thoughtcrime.securesms.crypto.KeyPairUtilities +import javax.inject.Inject +import javax.inject.Singleton + +private const val TAG = "GenericPushManager" + +@Singleton +class GenericPushManager @Inject constructor( + private val context: Context, + private val device: Device, + private val tokenManager: FcmTokenManager, + private val pushManagerV2: PushManagerV2, +) { + fun refresh(token: String, force: Boolean): Promise<*, Exception> { + Log.d(TAG, "refresh() called") + + val userPublicKey = TextSecurePreferences.getLocalNumber(context) ?: return emptyPromise() + val userEdKey = KeyPairUtilities.getUserED25519KeyPair(context) ?: return emptyPromise() + + return when { + tokenManager.isUsingFCM -> register(force, token, userPublicKey, userEdKey) + tokenManager.requiresUnregister -> unregister(token, userPublicKey, userEdKey) + else -> emptyPromise() + } + } + + /** + * Register for push notifications if: + * force is true + * there is no FCM Token + * FCM Token has expired + */ + private fun register( + force: Boolean, + token: String, + publicKey: String, + userEd25519Key: KeyPair, + namespaces: List = listOf(Namespace.DEFAULT) + ): Promise<*, Exception> = if (force || tokenManager.isInvalid()) { + register(token, publicKey, userEd25519Key, namespaces) + } else emptyPromise() + + /** + * Register for push notifications. + */ + private fun register( + token: String, + publicKey: String, + userEd25519Key: KeyPair, + namespaces: List = listOf(Namespace.DEFAULT) + ): Promise<*, Exception> = PushManagerV1.register( + token = token, + device = device, + publicKey = publicKey + ) and pushManagerV2.register( + token, publicKey, userEd25519Key, namespaces + ) fail { + Log.e(TAG, "registerBoth failed", it) + } success { + Log.d(TAG, "registerBoth success... saving token!!") + tokenManager.fcmToken = token + } + + private fun unregister( + token: String, + userPublicKey: String, + userEdKey: KeyPair + ): Promise<*, Exception> = PushManagerV1.unregister() and pushManagerV2.unregister( + token, userPublicKey, userEdKey + ) fail { + Log.e(TAG, "unregisterBoth failed", it) + } success { + tokenManager.fcmToken = null + } +} \ No newline at end of file diff --git a/app/src/play/kotlin/org/thoughtcrime/securesms/notifications/PushManagerV2.kt b/app/src/play/kotlin/org/thoughtcrime/securesms/notifications/PushManagerV2.kt index 4fe885758f..9f9a132aba 100644 --- a/app/src/play/kotlin/org/thoughtcrime/securesms/notifications/PushManagerV2.kt +++ b/app/src/play/kotlin/org/thoughtcrime/securesms/notifications/PushManagerV2.kt @@ -1,13 +1,9 @@ package org.thoughtcrime.securesms.notifications -import android.content.Context import com.goterl.lazysodium.LazySodiumAndroid import com.goterl.lazysodium.SodiumAndroid -import com.goterl.lazysodium.interfaces.AEAD import com.goterl.lazysodium.interfaces.Sign -import com.goterl.lazysodium.utils.Key import com.goterl.lazysodium.utils.KeyPair -import kotlinx.serialization.decodeFromString import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import kotlinx.serialization.json.decodeFromStream @@ -16,30 +12,22 @@ import nl.komponents.kovenant.functional.map import okhttp3.MediaType import okhttp3.Request import okhttp3.RequestBody -import org.session.libsession.messaging.sending_receiving.notifications.PushManagerV1 -import org.session.libsession.messaging.sending_receiving.notifications.PushNotificationMetadata -import org.session.libsession.messaging.sending_receiving.notifications.Response -import org.session.libsession.messaging.sending_receiving.notifications.Server -import org.session.libsession.messaging.sending_receiving.notifications.SubscriptionRequest -import org.session.libsession.messaging.sending_receiving.notifications.SubscriptionResponse -import org.session.libsession.messaging.sending_receiving.notifications.UnsubscribeResponse -import org.session.libsession.messaging.sending_receiving.notifications.UnsubscriptionRequest -import org.session.libsession.messaging.utilities.SodiumUtilities +import org.session.libsession.messaging.sending_receiving.notifications.* import org.session.libsession.snode.OnionRequestAPI import org.session.libsession.snode.SnodeAPI import org.session.libsession.snode.Version -import org.session.libsession.utilities.bencode.Bencode -import org.session.libsession.utilities.bencode.BencodeList -import org.session.libsession.utilities.bencode.BencodeString import org.session.libsignal.utilities.Base64 import org.session.libsignal.utilities.Log import org.session.libsignal.utilities.Namespace import org.session.libsignal.utilities.retryIfNeeded -import org.thoughtcrime.securesms.crypto.IdentityKeyUtil +import javax.inject.Inject +import javax.inject.Singleton private const val TAG = "PushManagerV2" +private const val maxRetryCount = 4 -class PushManagerV2(private val pushHandler: PushHandler) { +@Singleton +class PushManagerV2 @Inject constructor(private val pushHandler: PushHandler) { private val sodium = LazySodiumAndroid(SodiumAndroid()) fun register( @@ -98,7 +86,7 @@ class PushManagerV2(private val pushHandler: PushHandler) { } private inline fun retryResponseBody(path: String, requestParameters: String): Promise = - retryIfNeeded(FirebasePushManager.maxRetryCount) { getResponseBody(path, requestParameters) } + retryIfNeeded(maxRetryCount) { getResponseBody(path, requestParameters) } private inline fun getResponseBody(path: String, requestParameters: String): Promise { val server = Server.LATEST diff --git a/app/src/play/kotlin/org/thoughtcrime/securesms/notifications/PushNotificationService.kt b/app/src/play/kotlin/org/thoughtcrime/securesms/notifications/PushNotificationService.kt index e546053fce..bc641f82cd 100644 --- a/app/src/play/kotlin/org/thoughtcrime/securesms/notifications/PushNotificationService.kt +++ b/app/src/play/kotlin/org/thoughtcrime/securesms/notifications/PushNotificationService.kt @@ -19,7 +19,7 @@ private const val TAG = "PushNotificationService" @AndroidEntryPoint class PushNotificationService : FirebaseMessagingService() { - @Inject lateinit var pushManager: FirebasePushManager + @Inject lateinit var pushManager: PushManager @Inject lateinit var pushHandler: PushHandler override fun onNewToken(token: String) { diff --git a/libsession/src/main/java/org/session/libsession/messaging/MessagingModuleConfiguration.kt b/libsession/src/main/java/org/session/libsession/messaging/MessagingModuleConfiguration.kt index 0437196772..3d48325bf7 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/MessagingModuleConfiguration.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/MessagingModuleConfiguration.kt @@ -5,10 +5,12 @@ import com.goterl.lazysodium.utils.KeyPair import org.session.libsession.database.MessageDataProvider import org.session.libsession.database.StorageProtocol import org.session.libsession.utilities.ConfigFactoryProtocol +import org.session.libsession.utilities.Device class MessagingModuleConfiguration( val context: Context, val storage: StorageProtocol, + val device: Device, val messageDataProvider: MessageDataProvider, val getUserED25519KeyPair: () -> KeyPair?, val configFactory: ConfigFactoryProtocol 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 804b2f15be..be7075dc54 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 @@ -29,6 +29,7 @@ import org.session.libsession.snode.SnodeAPI import org.session.libsession.snode.SnodeMessage import org.session.libsession.snode.SnodeModule import org.session.libsession.utilities.Address +import org.session.libsession.utilities.Device import org.session.libsession.utilities.GroupUtil import org.session.libsession.utilities.SSKEnvironment import org.session.libsignal.crypto.PushTransportDetails @@ -454,8 +455,8 @@ object MessageSender { } // Closed groups - fun createClosedGroup(name: String, members: Collection): Promise { - return create(name, members) + fun createClosedGroup(device: Device, name: String, members: Collection): Promise { + return create(device, name, members) } fun explicitNameChange(groupPublicKey: String, newName: String) { diff --git a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSenderClosedGroupHandler.kt b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSenderClosedGroupHandler.kt index 3b4b4b583c..9a068f68c3 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSenderClosedGroupHandler.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSenderClosedGroupHandler.kt @@ -13,6 +13,7 @@ import org.session.libsession.messaging.sending_receiving.pollers.ClosedGroupPol import org.session.libsession.snode.SnodeAPI import org.session.libsession.utilities.Address import org.session.libsession.utilities.Address.Companion.fromSerialized +import org.session.libsession.utilities.Device import org.session.libsession.utilities.GroupUtil import org.session.libsession.utilities.TextSecurePreferences import org.session.libsession.utilities.recipients.Recipient @@ -33,7 +34,11 @@ const val groupSizeLimit = 100 val pendingKeyPairs = ConcurrentHashMap>() -fun MessageSender.create(name: String, members: Collection): Promise { +fun MessageSender.create( + device: Device, + name: String, + members: Collection +): Promise { val deferred = deferred() ThreadUtils.queue { // Prepare @@ -89,7 +94,7 @@ fun MessageSender.create(name: String, members: Collection): Promise = MessagingModuleConfiguration.shared.storage.getAllClosedGroupPublicKeys() ): Promise<*, Exception> = if (!isUsingFCM) { emptyPromise() } else retryIfNeeded(maxRetryCount) { - doRegister(token, publicKey, legacyGroupPublicKeys) + doRegister(token, publicKey, device, legacyGroupPublicKeys) } fail { exception -> Log.d(TAG, "Couldn't register for FCM due to error: $exception.") } - private fun doRegister(token: String?, publicKey: String?, legacyGroupPublicKeys: Collection): Promise<*, Exception> { + private fun doRegister(token: String?, publicKey: String?, device: Device, legacyGroupPublicKeys: Collection): Promise<*, Exception> { Log.d(TAG, "registerV1 requested") token ?: return emptyPromise() @@ -48,6 +50,7 @@ object PushManagerV1 { val parameters = mapOf( "token" to token, "pubKey" to publicKey, + "device" to device, "legacyGroupPublicKeys" to legacyGroupPublicKeys ) diff --git a/libsession/src/main/java/org/session/libsession/utilities/Device.kt b/libsession/src/main/java/org/session/libsession/utilities/Device.kt new file mode 100644 index 0000000000..3f8d0d6d5a --- /dev/null +++ b/libsession/src/main/java/org/session/libsession/utilities/Device.kt @@ -0,0 +1,6 @@ +package org.session.libsession.utilities + +enum class Device(val value: String) { + ANDROID("android"), + HUAWEI("huawei"); +}