Connect Huawei push notifications

This commit is contained in:
Andrew
2023-07-26 10:48:20 +09:30
parent 34990b13d3
commit 55216875ac
20 changed files with 231 additions and 215 deletions

View File

@@ -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<Int> = 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<Int> = 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
}
}

View File

@@ -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
}
}

View File

@@ -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<Int> = 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<Int> = 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
}
}

View File

@@ -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 <reified T: Response> retryResponseBody(path: String, requestParameters: String): Promise<T, Exception> =
retryIfNeeded(FirebasePushManager.maxRetryCount) { getResponseBody(path, requestParameters) }
retryIfNeeded(maxRetryCount) { getResponseBody(path, requestParameters) }
private inline fun <reified T: Response> getResponseBody(path: String, requestParameters: String): Promise<T, Exception> {
val server = Server.LATEST

View File

@@ -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) {