From 8f34c3ea5cd3aa88e8243c9856fe0485b99a62e9 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 20 Jun 2024 17:42:52 +0200 Subject: [PATCH] Added dialog when ZRTP SAS token doesn't match or when clicking on 'nothing matches' button --- .../ui/call/fragment/ActiveCallFragment.kt | 28 +++- .../ui/call/model/ZrtpAlertDialogModel.kt | 45 ++++++ .../ui/call/viewmodel/CurrentCallViewModel.kt | 11 +- .../java/org/linphone/utils/DialogUtils.kt | 24 +++- .../drawable/shape_red_button_background.xml | 5 + .../shape_zrtp_dialog_error_background.xml | 18 +++ ...pe_zrtp_dialog_error_header_background.xml | 10 ++ app/src/main/res/drawable/shield_warning.xml | 9 ++ ...sas.xml => dialog_zrtp_sas_validation.xml} | 0 ...sas.xml => dialog_zrtp_sas_validation.xml} | 0 .../res/layout/dialog_zrtp_security_alert.xml | 133 ++++++++++++++++++ app/src/main/res/values-fr/strings.xml | 3 + app/src/main/res/values/strings.xml | 3 + 13 files changed, 281 insertions(+), 8 deletions(-) create mode 100644 app/src/main/java/org/linphone/ui/call/model/ZrtpAlertDialogModel.kt create mode 100644 app/src/main/res/drawable/shape_red_button_background.xml create mode 100644 app/src/main/res/drawable/shape_zrtp_dialog_error_background.xml create mode 100644 app/src/main/res/drawable/shape_zrtp_dialog_error_header_background.xml create mode 100644 app/src/main/res/drawable/shield_warning.xml rename app/src/main/res/layout-land/{dialog_confirm_zrtp_sas.xml => dialog_zrtp_sas_validation.xml} (100%) rename app/src/main/res/layout/{dialog_confirm_zrtp_sas.xml => dialog_zrtp_sas_validation.xml} (100%) create mode 100644 app/src/main/res/layout/dialog_zrtp_security_alert.xml diff --git a/app/src/main/java/org/linphone/ui/call/fragment/ActiveCallFragment.kt b/app/src/main/java/org/linphone/ui/call/fragment/ActiveCallFragment.kt index 8a32af5a6..ab4d9e3a7 100644 --- a/app/src/main/java/org/linphone/ui/call/fragment/ActiveCallFragment.kt +++ b/app/src/main/java/org/linphone/ui/call/fragment/ActiveCallFragment.kt @@ -42,6 +42,7 @@ import org.linphone.core.tools.Log import org.linphone.databinding.CallActiveFragmentBinding import org.linphone.ui.GenericActivity import org.linphone.ui.call.CallActivity +import org.linphone.ui.call.model.ZrtpAlertDialogModel import org.linphone.ui.call.model.ZrtpSasConfirmationDialogModel import org.linphone.ui.call.viewmodel.CallsViewModel import org.linphone.ui.call.viewmodel.CurrentCallViewModel @@ -238,10 +239,7 @@ class ActiveCallFragment : GenericCallFragment() { doNotTint = true ) } else { - (requireActivity() as GenericActivity).showRedToast( - getString(R.string.call_can_not_be_trusted_alert_toast), - R.drawable.warning_circle - ) + showZrtpAlertDialog() } } } @@ -445,4 +443,26 @@ class ActiveCallFragment : GenericCallFragment() { dialog.show() zrtpSasDialog = dialog } + + private fun showZrtpAlertDialog() { + val model = ZrtpAlertDialogModel() + val dialog = DialogUtils.getZrtpAlertDialog(requireActivity(), model) + + model.tryAgainEvent.observe(viewLifecycleOwner) { event -> + event.consume { + callViewModel.showZrtpSasDialogIfPossible() + dialog.dismiss() + } + } + + model.hangUpEvent.observe(viewLifecycleOwner) { event -> + event.consume { + callViewModel.hangUp() + dialog.dismiss() + } + } + + dialog.show() + zrtpSasDialog = dialog + } } diff --git a/app/src/main/java/org/linphone/ui/call/model/ZrtpAlertDialogModel.kt b/app/src/main/java/org/linphone/ui/call/model/ZrtpAlertDialogModel.kt new file mode 100644 index 000000000..a7005c352 --- /dev/null +++ b/app/src/main/java/org/linphone/ui/call/model/ZrtpAlertDialogModel.kt @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2010-2024 Belledonne Communications SARL. + * + * This file is part of linphone-android + * (see https://www.linphone.org). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.linphone.ui.call.model + +import androidx.annotation.UiThread +import androidx.lifecycle.MutableLiveData +import org.linphone.ui.GenericViewModel +import org.linphone.utils.Event + +class ZrtpAlertDialogModel @UiThread constructor() : GenericViewModel() { + companion object { + private const val TAG = "[ZRTP Alert Dialog]" + } + + val tryAgainEvent = MutableLiveData>() + + val hangUpEvent = MutableLiveData>() + + @UiThread + fun tryAgain() { + tryAgainEvent.value = Event(true) + } + + @UiThread + fun hangUp() { + hangUpEvent.value = Event(true) + } +} diff --git a/app/src/main/java/org/linphone/ui/call/viewmodel/CurrentCallViewModel.kt b/app/src/main/java/org/linphone/ui/call/viewmodel/CurrentCallViewModel.kt index a7d236cc7..13898fa8b 100644 --- a/app/src/main/java/org/linphone/ui/call/viewmodel/CurrentCallViewModel.kt +++ b/app/src/main/java/org/linphone/ui/call/viewmodel/CurrentCallViewModel.kt @@ -245,6 +245,9 @@ class CurrentCallViewModel @UiThread constructor() : GenericViewModel() { ) isZrtpSasValidationRequired.postValue(!verified) zrtpAuthTokenVerifiedEvent.postValue(Event(verified)) + if (verified) { + isMediaEncrypted.postValue(true) + } } override fun onRemoteRecording(call: Call, recording: Boolean) { @@ -956,13 +959,19 @@ class CurrentCallViewModel @UiThread constructor() : GenericViewModel() { coreContext.postOnCoreThread { if (currentCall.currentParams.mediaEncryption == MediaEncryption.ZRTP) { val isDeviceTrusted = currentCall.authenticationTokenVerified + val cacheMismatch = currentCall.zrtpCacheMismatchFlag Log.i( "$TAG Current call media encryption is ZRTP, auth token is [${if (isDeviceTrusted) "trusted" else "not trusted yet"}]" ) val tokenToRead = currentCall.localAuthenticationToken val tokensToDisplay = currentCall.remoteAuthenticationTokens.toList() if (!tokenToRead.isNullOrEmpty() && tokensToDisplay.size == 4) { - showZrtpSasDialogEvent.postValue(Event(Pair(tokenToRead, tokensToDisplay))) + val event = Event(Pair(tokenToRead, tokensToDisplay)) + if (cacheMismatch) { + showZrtpSasCacheMismatchDialogEvent.postValue(event) + } else { + showZrtpSasDialogEvent.postValue(event) + } } else { Log.w( "$TAG Either local auth token is null/empty or remote tokens list doesn't contains 4 elements!" diff --git a/app/src/main/java/org/linphone/utils/DialogUtils.kt b/app/src/main/java/org/linphone/utils/DialogUtils.kt index a270a45f5..cc02556e6 100644 --- a/app/src/main/java/org/linphone/utils/DialogUtils.kt +++ b/app/src/main/java/org/linphone/utils/DialogUtils.kt @@ -37,7 +37,6 @@ import org.linphone.databinding.DialogAssistantAcceptConditionsAndPolicyBinding import org.linphone.databinding.DialogAssistantCreateAccountConfirmPhoneNumberBinding import org.linphone.databinding.DialogCancelContactChangesBinding import org.linphone.databinding.DialogCancelMeetingBinding -import org.linphone.databinding.DialogConfirmZrtpSasBinding import org.linphone.databinding.DialogContactConfirmTrustCallBinding import org.linphone.databinding.DialogContactTrustProcessBinding import org.linphone.databinding.DialogDeleteContactBinding @@ -53,8 +52,11 @@ import org.linphone.databinding.DialogRemoveConversationHistoryBinding import org.linphone.databinding.DialogSetOrEditGroupSubjectBindingImpl import org.linphone.databinding.DialogUpdateAccountPasswordBinding import org.linphone.databinding.DialogUpdateAvailableBinding +import org.linphone.databinding.DialogZrtpSasValidationBinding +import org.linphone.databinding.DialogZrtpSecurityAlertBinding import org.linphone.ui.assistant.model.AcceptConditionsAndPolicyDialogModel import org.linphone.ui.assistant.model.ConfirmPhoneNumberDialogModel +import org.linphone.ui.call.model.ZrtpAlertDialogModel import org.linphone.ui.call.model.ZrtpSasConfirmationDialogModel import org.linphone.ui.main.contacts.model.NumberOrAddressPickerDialogModel import org.linphone.ui.main.contacts.model.TrustCallDialogModel @@ -343,9 +345,25 @@ class DialogUtils { context: Context, viewModel: ZrtpSasConfirmationDialogModel ): Dialog { - val binding: DialogConfirmZrtpSasBinding = DataBindingUtil.inflate( + val binding: DialogZrtpSasValidationBinding = DataBindingUtil.inflate( LayoutInflater.from(context), - R.layout.dialog_confirm_zrtp_sas, + R.layout.dialog_zrtp_sas_validation, + null, + false + ) + binding.viewModel = viewModel + + return getDialog(context, binding) + } + + @UiThread + fun getZrtpAlertDialog( + context: Context, + viewModel: ZrtpAlertDialogModel + ): Dialog { + val binding: DialogZrtpSecurityAlertBinding = DataBindingUtil.inflate( + LayoutInflater.from(context), + R.layout.dialog_zrtp_security_alert, null, false ) diff --git a/app/src/main/res/drawable/shape_red_button_background.xml b/app/src/main/res/drawable/shape_red_button_background.xml new file mode 100644 index 000000000..e94a9096f --- /dev/null +++ b/app/src/main/res/drawable/shape_red_button_background.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_zrtp_dialog_error_background.xml b/app/src/main/res/drawable/shape_zrtp_dialog_error_background.xml new file mode 100644 index 000000000..e5bf1ba07 --- /dev/null +++ b/app/src/main/res/drawable/shape_zrtp_dialog_error_background.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_zrtp_dialog_error_header_background.xml b/app/src/main/res/drawable/shape_zrtp_dialog_error_header_background.xml new file mode 100644 index 000000000..da6383e65 --- /dev/null +++ b/app/src/main/res/drawable/shape_zrtp_dialog_error_header_background.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shield_warning.xml b/app/src/main/res/drawable/shield_warning.xml new file mode 100644 index 000000000..76fbdb097 --- /dev/null +++ b/app/src/main/res/drawable/shield_warning.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout-land/dialog_confirm_zrtp_sas.xml b/app/src/main/res/layout-land/dialog_zrtp_sas_validation.xml similarity index 100% rename from app/src/main/res/layout-land/dialog_confirm_zrtp_sas.xml rename to app/src/main/res/layout-land/dialog_zrtp_sas_validation.xml diff --git a/app/src/main/res/layout/dialog_confirm_zrtp_sas.xml b/app/src/main/res/layout/dialog_zrtp_sas_validation.xml similarity index 100% rename from app/src/main/res/layout/dialog_confirm_zrtp_sas.xml rename to app/src/main/res/layout/dialog_zrtp_sas_validation.xml diff --git a/app/src/main/res/layout/dialog_zrtp_security_alert.xml b/app/src/main/res/layout/dialog_zrtp_security_alert.xml new file mode 100644 index 000000000..f8b87e820 --- /dev/null +++ b/app/src/main/res/layout/dialog_zrtp_security_alert.xml @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 5e3a1d141..0b56ef70a 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -592,6 +592,9 @@ Votre code : Code correspondant : Aucune correspondance + Security alert + Réessayer + La confidentialité de votre appel peut être compromise ! Oreilette Haut parleur diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4df340fe1..c68d4faf6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -629,6 +629,9 @@ Your code: Correspondent code: Nothing matches + Security alert + Try again + This call confidentiality may be compromise! Earpiece Speaker