diff --git a/app/src/gplay/java/com/nextcloud/talk/services/firebase/MagicFirebaseMessagingService.kt b/app/src/gplay/java/com/nextcloud/talk/services/firebase/MagicFirebaseMessagingService.kt index 8536c324c..4abfbe36b 100644 --- a/app/src/gplay/java/com/nextcloud/talk/services/firebase/MagicFirebaseMessagingService.kt +++ b/app/src/gplay/java/com/nextcloud/talk/services/firebase/MagicFirebaseMessagingService.kt @@ -44,12 +44,14 @@ import com.nextcloud.talk.jobs.MessageNotificationWorker import com.nextcloud.talk.models.SignatureVerification import com.nextcloud.talk.models.json.push.DecryptedPushMessage import com.nextcloud.talk.newarch.domain.repository.offline.UsersRepository +import com.nextcloud.talk.newarch.services.CallService import com.nextcloud.talk.newarch.utils.MagicJson import com.nextcloud.talk.utils.NotificationUtils import com.nextcloud.talk.utils.NotificationUtils.cancelAllNotificationsForAccount import com.nextcloud.talk.utils.NotificationUtils.cancelExistingNotificationWithId import com.nextcloud.talk.utils.PushUtils import com.nextcloud.talk.utils.bundle.BundleKeys +import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_INCOMING_PUSH_MESSSAGE import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_OPEN_INCOMING_CALL import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_USER_ENTITY import com.nextcloud.talk.utils.preferences.AppPreferences @@ -68,23 +70,6 @@ import javax.crypto.NoSuchPaddingException class MagicFirebaseMessagingService : FirebaseMessagingService(), KoinComponent { val tag: String = "MagicFirebaseMessagingService" val appPreferences: AppPreferences by inject() - val retrofit: Retrofit by inject() - val okHttpClient: OkHttpClient by inject() - val eventBus: EventBus by inject() - val usersRepository: UsersRepository by inject() - - private var isServiceInForeground: Boolean = false - - override fun onCreate() { - super.onCreate() - //eventBus.register(this) - } - - override fun onDestroy() { - super.onDestroy() - //eventBus.unregister(this) - isServiceInForeground = false - } override fun onNewToken(token: String) { super.onNewToken(token) @@ -93,110 +78,14 @@ class MagicFirebaseMessagingService : FirebaseMessagingService(), KoinComponent @SuppressLint("LongLogTag") override fun onMessageReceived(remoteMessage: RemoteMessage) { - remoteMessage.data.let { - decryptMessage(it["subject"]!!, it["signature"]!!) - } + val incomingCallIntent = Intent(applicationContext, CallService::class.java) + incomingCallIntent.action = KEY_INCOMING_PUSH_MESSSAGE + incomingCallIntent.putExtra(BundleKeys.KEY_ENCRYPTED_SUBJECT, remoteMessage.data["subject"]) + incomingCallIntent.putExtra(BundleKeys.KEY_ENCRYPTED_SIGNATURE, remoteMessage.data["signature"]) + applicationContext.startService(incomingCallIntent) } @SuppressLint("LongLogTag") - private fun decryptMessage(subject: String, signature: String) { - val signatureVerification: SignatureVerification - val decryptedPushMessage: DecryptedPushMessage - - try { - val base64DecodedSubject = Base64.decode(subject, Base64.DEFAULT) - val base64DecodedSignature = Base64.decode(signature, Base64.DEFAULT) - val pushUtils = PushUtils(usersRepository) - val privateKey = pushUtils.readKeyFromFile(false) as PrivateKey - try { - signatureVerification = pushUtils.verifySignature(base64DecodedSignature, base64DecodedSubject) - if (signatureVerification.signatureValid) { - val cipher = Cipher.getInstance("RSA/None/PKCS1Padding") - cipher.init(Cipher.DECRYPT_MODE, privateKey) - val decryptedSubject = cipher.doFinal(base64DecodedSubject) - decryptedPushMessage = LoganSquare.parse(String(decryptedSubject), DecryptedPushMessage::class.java) - decryptedPushMessage.apply { - when { - delete -> { - cancelExistingNotificationWithId(applicationContext, signatureVerification.userEntity!!, notificationId!!) - } - deleteAll -> { - cancelAllNotificationsForAccount(applicationContext, signatureVerification.userEntity!!) - } - type == "call" -> { - val fullScreenIntent = Intent(applicationContext, MagicCallActivity::class.java) - fullScreenIntent.action = KEY_OPEN_INCOMING_CALL - val bundle = Bundle() - bundle.putString(BundleKeys.KEY_ROOM_ID, decryptedPushMessage.id) - bundle.putParcelable(KEY_USER_ENTITY, signatureVerification.userEntity) - fullScreenIntent.putExtras(bundle) - - fullScreenIntent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_NEW_TASK - val fullScreenPendingIntent = PendingIntent.getActivity(this@MagicFirebaseMessagingService, 0, fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT) - - val audioAttributesBuilder = AudioAttributes.Builder().setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) - audioAttributesBuilder.setUsage(AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST) - - val soundUri = NotificationUtils.getCallSoundUri(applicationContext, appPreferences) - val vibrationEffect = NotificationUtils.getVibrationEffect(appPreferences) - - val notificationChannelId = NotificationUtils.getNotificationChannelId(applicationContext, applicationContext.resources - .getString(R.string.nc_notification_channel_calls), applicationContext.resources - .getString(R.string.nc_notification_channel_calls_description), true, - NotificationManagerCompat.IMPORTANCE_HIGH, soundUri!!, - audioAttributesBuilder.build(), vibrationEffect, false, null) - - val userBaseUrl = Uri.parse(signatureVerification.userEntity!!.baseUrl).toString() - - val notificationBuilder = NotificationCompat.Builder(this@MagicFirebaseMessagingService, notificationChannelId) - .setPriority(NotificationCompat.PRIORITY_HIGH) - .setCategory(NotificationCompat.CATEGORY_CALL) - .setSmallIcon(R.drawable.ic_call_black_24dp) - .setSubText(userBaseUrl) - .setShowWhen(true) - .setWhen(System.currentTimeMillis()) - .setContentTitle(EmojiCompat.get().process(decryptedPushMessage.subject.toString())) - .setAutoCancel(true) - .setOngoing(true) - //.setTimeoutAfter(45000L) - .setContentIntent(fullScreenPendingIntent) - .setFullScreenIntent(fullScreenPendingIntent, true) - .setSound(NotificationUtils.getCallSoundUri(applicationContext, appPreferences), AudioManager.STREAM_RING) - - if (vibrationEffect != null) { - notificationBuilder.setVibrate(vibrationEffect) - } - - val notification = notificationBuilder.build() - notification.flags = notification.flags or Notification.FLAG_INSISTENT - isServiceInForeground = true - checkIfCallIsActive(signatureVerification, decryptedPushMessage) - startForeground(timestamp.toInt(), notification) - } - else -> { - val json = Json(MagicJson.customJsonConfiguration) - - val messageData = Data.Builder() - .putString(BundleKeys.KEY_DECRYPTED_PUSH_MESSAGE, LoganSquare.serialize(decryptedPushMessage)) - .putString(BundleKeys.KEY_SIGNATURE_VERIFICATION, json.stringify(SignatureVerification.serializer(), signatureVerification)) - .build() - val pushNotificationWork = OneTimeWorkRequest.Builder(MessageNotificationWorker::class.java).setInputData(messageData).build() - WorkManager.getInstance().enqueue(pushNotificationWork) - } - } - } - } - } catch (e1: NoSuchAlgorithmException) { - Log.d(tag, "No proper algorithm to decrypt the message " + e1.localizedMessage) - } catch (e1: NoSuchPaddingException) { - Log.d(tag, "No proper padding to decrypt the message " + e1.localizedMessage) - } catch (e1: InvalidKeyException) { - Log.d(tag, "Invalid private key " + e1.localizedMessage) - } - } catch (exception: Exception) { - Log.d(tag, "Something went very wrong " + exception.localizedMessage) - } - } private fun checkIfCallIsActive(signatureVerification: SignatureVerification, decryptedPushMessage: DecryptedPushMessage) { /*val ncApi = retrofit.newBuilder().client(okHttpClient.newBuilder().cookieJar(JavaNetCookieJar(CookieManager())).build()).build().create(NcApi::class.java) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7612f2a4a..14f5bdd0b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -125,6 +125,8 @@ + { + NotificationUtils.cancelExistingNotificationWithId(applicationContext, signatureVerification.userEntity!!, notificationId!!) + } + deleteAll -> { + NotificationUtils.cancelAllNotificationsForAccount(applicationContext, signatureVerification.userEntity!!) + } + type == "call" -> { + val timestamp = System.currentTimeMillis() + + val fullScreenIntent = Intent(applicationContext, MagicCallActivity::class.java) + fullScreenIntent.action = BundleKeys.KEY_OPEN_INCOMING_CALL + val bundle = Bundle() + bundle.putString(BundleKeys.KEY_CONVERSATION_TOKEN, decryptedPushMessage.id) + bundle.putParcelable(BundleKeys.KEY_USER_ENTITY, signatureVerification.userEntity) + bundle.putLong(BundleKeys.KEY_NOTIFICATION_ID, timestamp) + fullScreenIntent.putExtras(bundle) + + fullScreenIntent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_NEW_TASK + val fullScreenPendingIntent = PendingIntent.getActivity(this@CallService, 0, fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT) + + val audioAttributesBuilder = AudioAttributes.Builder().setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) + audioAttributesBuilder.setUsage(AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST) + + val soundUri = NotificationUtils.getCallSoundUri(applicationContext, appPreferences) + val vibrationEffect = NotificationUtils.getVibrationEffect(appPreferences) + + val notificationChannelId = NotificationUtils.getNotificationChannelId(applicationContext, applicationContext.resources + .getString(R.string.nc_notification_channel_calls), applicationContext.resources + .getString(R.string.nc_notification_channel_calls_description), true, + NotificationManagerCompat.IMPORTANCE_HIGH, soundUri!!, + audioAttributesBuilder.build(), vibrationEffect, false, null) + + val userBaseUrl = Uri.parse(signatureVerification.userEntity!!.baseUrl).toString() + + val rejectCallIntent = Intent(this@CallService, CallService::class.java) + rejectCallIntent.action = BundleKeys.KEY_REJECT_INCOMING_CALL + rejectCallIntent.putExtra(BundleKeys.KEY_NOTIFICATION_ID, timestamp) + val rejectCallPendingIntent = PendingIntent.getService(this@CallService, 0, rejectCallIntent, 0) + val notificationBuilder = NotificationCompat.Builder(this@CallService, notificationChannelId) + .setPriority(NotificationCompat.PRIORITY_HIGH) + .setCategory(NotificationCompat.CATEGORY_CALL) + .setSmallIcon(R.drawable.ic_call_black_24dp) + .setSubText(userBaseUrl) + .setShowWhen(true) + .setWhen(timestamp) + .setContentTitle(EmojiCompat.get().process(decryptedPushMessage.subject.toString())) + .setAutoCancel(true) + .setOngoing(true) + .addAction(R.drawable.ic_call_end_white_24px, resources.getString(R.string.reject_call), rejectCallPendingIntent) + //.setTimeoutAfter(45000L) + .setFullScreenIntent(fullScreenPendingIntent, true) + .setSound(NotificationUtils.getCallSoundUri(applicationContext, appPreferences), AudioManager.STREAM_RING) + + if (vibrationEffect != null) { + notificationBuilder.setVibrate(vibrationEffect) + } + + val notification = notificationBuilder.build() + notification.flags = notification.flags or Notification.FLAG_INSISTENT + //checkIfCallIsActive(signatureVerification, decryptedPushMessage) + currentlyActiveNotificationId = timestamp + startForeground(timestamp.toInt(), notification) + } + else -> { + val json = Json(MagicJson.customJsonConfiguration) + + val messageData = Data.Builder() + .putString(BundleKeys.KEY_DECRYPTED_PUSH_MESSAGE, LoganSquare.serialize(decryptedPushMessage)) + .putString(BundleKeys.KEY_SIGNATURE_VERIFICATION, json.stringify(SignatureVerification.serializer(), signatureVerification)) + .build() + val pushNotificationWork = OneTimeWorkRequest.Builder(MessageNotificationWorker::class.java).setInputData(messageData).build() + WorkManager.getInstance().enqueue(pushNotificationWork) + } + } + } + } else { + // do absolutely nothing + } + } catch (e1: NoSuchAlgorithmException) { + Log.d(tag, "No proper algorithm to decrypt the message " + e1.localizedMessage) + } catch (e1: NoSuchPaddingException) { + Log.d(tag, "No proper padding to decrypt the message " + e1.localizedMessage) + } catch (e1: InvalidKeyException) { + Log.d(tag, "Invalid private key " + e1.localizedMessage) + } + } catch (exception: Exception) { + Log.d(tag, "Something went very wrong " + exception.localizedMessage) + } + } + } + + override fun onBind(intent: Intent?): IBinder? { + return null + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.kt b/app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.kt index e5da0af3f..6db46eb62 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.kt @@ -61,6 +61,12 @@ object BundleKeys { val KEY_NOTIFICATION_ID = "KEY_NOTIFICATION_ID" val KEY_CONVERSATION_ID = "KEY_CONVERSATION_ID" + val KEY_ENCRYPTED_SUBJECT = "KEY_ENCRYPTED_SUBJECT" + val KEY_ENCRYPTED_SIGNATURE = "KEY_ENCRYPTED_SIGNATURE" + + val KEY_REJECT_INCOMING_CALL = "KEY_REJECT_INCOMING_CALL" + val KEY_SHOW_INCOMING_CALL = "KEY_SHOW_INCOMING_CALL" + val KEY_INCOMING_PUSH_MESSSAGE = "KEY_INCOMING_PUSH_MESSAGE" val KEY_DECRYPTED_PUSH_MESSAGE = "KEY_DECRYPTED_PUSH_MESSAGE" val KEY_SIGNATURE_VERIFICATION = "KEY_SIGNATURE_VERIFICATION" } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index be246784e..2cfd8838a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -344,4 +344,5 @@ Search for more participants New group Where did they all hide? + Reject