mirror of
https://github.com/oxen-io/session-android.git
synced 2024-12-22 07:57:30 +00:00
Connect Huawei push notifications
This commit is contained in:
parent
34990b13d3
commit
55216875ac
@ -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\""
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
override fun refresh(force: Boolean) {
|
||||
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
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
override fun onDeletedMessages() {
|
||||
pushManager.refresh(true)
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
16
app/src/main/java/org/thoughtcrime/securesms/DeviceModule.kt
Normal file
16
app/src/main/java/org/thoughtcrime/securesms/DeviceModule.kt
Normal file
@ -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
|
||||
}
|
@ -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))
|
||||
|
@ -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<String, String>) {
|
||||
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)
|
||||
}
|
||||
data?.let { onPush(data) } ?: onPush()
|
||||
|
||||
fun onPush(dataMap: Map<String, String>?) {
|
||||
onPush(dataMap?.asByteArray())
|
||||
}
|
||||
|
||||
fun onPush() {
|
||||
private fun onPush(data: ByteArray?) {
|
||||
if (data == null) {
|
||||
onPush()
|
||||
return
|
||||
}
|
||||
|
||||
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 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<String, String>.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
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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<String>): Promise<String, Exception> {
|
||||
return create(name, members)
|
||||
fun createClosedGroup(device: Device, name: String, members: Collection<String>): Promise<String, Exception> {
|
||||
return create(device, name, members)
|
||||
}
|
||||
|
||||
fun explicitNameChange(groupPublicKey: String, newName: String) {
|
||||
|
@ -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<String, Optional<ECKeyPair>>()
|
||||
|
||||
fun MessageSender.create(name: String, members: Collection<String>): Promise<String, Exception> {
|
||||
fun MessageSender.create(
|
||||
device: Device,
|
||||
name: String,
|
||||
members: Collection<String>
|
||||
): Promise<String, Exception> {
|
||||
val deferred = deferred<String, Exception>()
|
||||
ThreadUtils.queue {
|
||||
// Prepare
|
||||
@ -89,7 +94,7 @@ fun MessageSender.create(name: String, members: Collection<String>): Promise<Str
|
||||
// Add the group to the config now that it was successfully created
|
||||
storage.createInitialConfigGroup(groupPublicKey, name, GroupUtil.createConfigMemberMap(members, admins), sentTime, encryptionKeyPair)
|
||||
// Notify the PN server
|
||||
PushManagerV1.register(publicKey = userPublicKey)
|
||||
PushManagerV1.register(publicKey = userPublicKey, device = device)
|
||||
// Start polling
|
||||
ClosedGroupPollerV2.shared.startPolling(groupPublicKey)
|
||||
// Fulfill the promise
|
||||
|
@ -556,7 +556,7 @@ private fun handleNewClosedGroup(sender: String, sentTimestamp: Long, groupPubli
|
||||
// Set expiration timer
|
||||
storage.setExpirationTimer(groupID, expireTimer)
|
||||
// Notify the PN server
|
||||
PushManagerV1.register(publicKey = userPublicKey)
|
||||
PushManagerV1.register(publicKey = userPublicKey, device = MessagingModuleConfiguration.shared.device)
|
||||
// Notify the user
|
||||
if (userPublicKey == sender && !groupExists) {
|
||||
val threadID = storage.getOrCreateThreadIdFor(Address.fromSerialized(groupID))
|
||||
|
@ -9,6 +9,7 @@ import org.session.libsession.messaging.MessagingModuleConfiguration
|
||||
import org.session.libsession.snode.OnionRequestAPI
|
||||
import org.session.libsession.snode.OnionResponse
|
||||
import org.session.libsession.snode.Version
|
||||
import org.session.libsession.utilities.Device
|
||||
import org.session.libsession.utilities.TextSecurePreferences
|
||||
import org.session.libsignal.utilities.JsonUtil
|
||||
import org.session.libsignal.utilities.Log
|
||||
@ -29,17 +30,18 @@ object PushManagerV1 {
|
||||
isUsingFCM: Boolean = TextSecurePreferences.isUsingFCM(context),
|
||||
token: String? = TextSecurePreferences.getFCMToken(context),
|
||||
publicKey: String? = TextSecurePreferences.getLocalNumber(context),
|
||||
device: Device,
|
||||
legacyGroupPublicKeys: Collection<String> = 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<String>): Promise<*, Exception> {
|
||||
private fun doRegister(token: String?, publicKey: String?, device: Device, legacyGroupPublicKeys: Collection<String>): 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
|
||||
)
|
||||
|
||||
|
@ -0,0 +1,6 @@
|
||||
package org.session.libsession.utilities
|
||||
|
||||
enum class Device(val value: String) {
|
||||
ANDROID("android"),
|
||||
HUAWEI("huawei");
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user