diff --git a/app/src/main/java/org/linphone/contacts/ContactsManager.kt b/app/src/main/java/org/linphone/contacts/ContactsManager.kt index d27b1968d..b188f5bbb 100644 --- a/app/src/main/java/org/linphone/contacts/ContactsManager.kt +++ b/app/src/main/java/org/linphone/contacts/ContactsManager.kt @@ -138,17 +138,8 @@ class ContactsManager @UiThread constructor() { @WorkerThread override fun onDefaultAccountChanged(core: Core, account: Account?) { - Log.i("$TAG Default account changed, update all contact models showTrust value") - val showTrust = account?.isEndToEndEncryptionMandatory() - knownContactsAvatarsMap.forEach { (_, contactAvatarModel) -> - contactAvatarModel.showTrust.postValue(showTrust) - } - unknownContactsAvatarsMap.forEach { (_, contactAvatarModel) -> - contactAvatarModel.showTrust.postValue(showTrust) - } - conferenceAvatarMap.forEach { (_, contactAvatarModel) -> - contactAvatarModel.showTrust.postValue(showTrust) - } + Log.i("$TAG Default account changed, update all contacts' model showTrust value") + updateContactsModelDependingOnDefaultAccountMode() } } @@ -212,6 +203,7 @@ class ContactsManager @UiThread constructor() { coreContext.contactsManager.notifyContactsListChanged() } + @WorkerThread fun contactRemoved(friend: Friend) { for (sipAddress in friend.addresses) { val sipUri = sipAddress.asStringUriOnly() @@ -611,6 +603,24 @@ class ContactsManager @UiThread constructor() { return personBuilder.build() } + @WorkerThread + fun updateContactsModelDependingOnDefaultAccountMode() { + val account = coreContext.core.defaultAccount + val showTrust = account?.isEndToEndEncryptionMandatory() == true + Log.i( + "$TAG Default account mode is [${if (showTrust) "end-to-end encryption mandatory" else "interoperable"}], update all contact models showTrust value" + ) + knownContactsAvatarsMap.forEach { (_, contactAvatarModel) -> + contactAvatarModel.showTrust.postValue(showTrust) + } + unknownContactsAvatarsMap.forEach { (_, contactAvatarModel) -> + contactAvatarModel.showTrust.postValue(showTrust) + } + conferenceAvatarMap.forEach { (_, contactAvatarModel) -> + contactAvatarModel.showTrust.postValue(showTrust) + } + } + @WorkerThread private fun getAvatarModelFromCache(key: String): ContactAvatarModel? { return knownContactsAvatarsMap[key] ?: unknownContactsAvatarsMap[key] diff --git a/app/src/main/java/org/linphone/ui/assistant/fragment/ProfileModeFragment.kt b/app/src/main/java/org/linphone/ui/assistant/fragment/ProfileModeFragment.kt index b30489ef1..26513b642 100644 --- a/app/src/main/java/org/linphone/ui/assistant/fragment/ProfileModeFragment.kt +++ b/app/src/main/java/org/linphone/ui/assistant/fragment/ProfileModeFragment.kt @@ -64,6 +64,7 @@ class ProfileModeFragment : Fragment() { } binding.setContinueClickListener { + viewModel.applySelectedMode() requireActivity().finish() } diff --git a/app/src/main/java/org/linphone/ui/assistant/viewmodel/AccountLoginViewModel.kt b/app/src/main/java/org/linphone/ui/assistant/viewmodel/AccountLoginViewModel.kt index adb3875ac..f0176ddaa 100644 --- a/app/src/main/java/org/linphone/ui/assistant/viewmodel/AccountLoginViewModel.kt +++ b/app/src/main/java/org/linphone/ui/assistant/viewmodel/AccountLoginViewModel.kt @@ -35,6 +35,8 @@ import org.linphone.core.Factory import org.linphone.core.Reason import org.linphone.core.RegistrationState import org.linphone.core.tools.Log +import org.linphone.ui.main.model.setEndToEndEncryptionMandatory +import org.linphone.ui.main.model.setInteroperabilityMode import org.linphone.utils.AppUtils import org.linphone.utils.Event @@ -221,6 +223,27 @@ open class AccountLoginViewModel @UiThread constructor() : ViewModel() { isCurrentlySelectedModeSecure.value = false } + @UiThread + fun applySelectedMode() { + coreContext.postOnCoreThread { core -> + if (::newlyCreatedAccount.isInitialized) { + if (isCurrentlySelectedModeSecure.value == true) { + Log.i( + "$TAG Selected mode is end-to-end encrypted, forcing media & im encryption to mandatory and setting media encryption to ZRTP" + ) + newlyCreatedAccount.setEndToEndEncryptionMandatory() + } else { + Log.i( + "$TAG Selected mode is interoperable, not forcing media & im encryption to mandatory and setting media encryption to SRTP" + ) + newlyCreatedAccount.setInteroperabilityMode() + } + } else { + Log.e("$TAG Failed to find newlyCreatedAccount!") + } + } + } + @UiThread private fun isLoginButtonEnabled(): Boolean { return sipIdentity.value.orEmpty().trim().isNotEmpty() && password.value.orEmpty().isNotEmpty() diff --git a/app/src/main/java/org/linphone/ui/main/chat/model/ConversationModel.kt b/app/src/main/java/org/linphone/ui/main/chat/model/ConversationModel.kt index 10f8b5c2b..fb05106f1 100644 --- a/app/src/main/java/org/linphone/ui/main/chat/model/ConversationModel.kt +++ b/app/src/main/java/org/linphone/ui/main/chat/model/ConversationModel.kt @@ -39,10 +39,7 @@ import org.linphone.utils.LinphoneUtils import org.linphone.utils.ShortcutUtils import org.linphone.utils.TimestampUtils -class ConversationModel @WorkerThread constructor( - val chatRoom: ChatRoom, - val isDisabledBecauseNotSecured: Boolean = false -) { +class ConversationModel @WorkerThread constructor(val chatRoom: ChatRoom) { companion object { private const val TAG = "[Conversation Model]" } @@ -57,6 +54,8 @@ class ConversationModel @WorkerThread constructor( Capabilities.Conference.toInt() ) + val isEncrypted = chatRoom.hasCapability(Capabilities.Encrypted.toInt()) + val isReadOnly = chatRoom.isReadOnly val subject = MutableLiveData() diff --git a/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationsListViewModel.kt b/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationsListViewModel.kt index 0743ea3bf..4e95f6e12 100644 --- a/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationsListViewModel.kt +++ b/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationsListViewModel.kt @@ -27,12 +27,10 @@ import org.linphone.R import org.linphone.contacts.ContactsManager import org.linphone.core.ChatMessage import org.linphone.core.ChatRoom -import org.linphone.core.ChatRoom.Capabilities import org.linphone.core.Core import org.linphone.core.CoreListenerStub import org.linphone.core.tools.Log import org.linphone.ui.main.chat.model.ConversationModel -import org.linphone.ui.main.model.isEndToEndEncryptionMandatory import org.linphone.ui.main.viewmodel.AbstractMainViewModel import org.linphone.utils.AppUtils import org.linphone.utils.Event @@ -147,11 +145,8 @@ class ConversationsListViewModel @UiThread constructor() : AbstractMainViewModel val account = LinphoneUtils.getDefaultAccount() val chatRooms = account?.chatRooms ?: coreContext.core.chatRooms for (chatRoom in chatRooms) { - val disabledBecauseNotSecured = account?.isEndToEndEncryptionMandatory() == true && !chatRoom.hasCapability( - Capabilities.Encrypted.toInt() - ) if (filter.isEmpty()) { - val model = ConversationModel(chatRoom, disabledBecauseNotSecured) + val model = ConversationModel(chatRoom) list.add(model) count += 1 } else { @@ -173,7 +168,7 @@ class ConversationsListViewModel @UiThread constructor() : AbstractMainViewModel chatRoom.peerAddress.asStringUriOnly().contains(filter, ignoreCase = true) || chatRoom.subject.orEmpty().contains(filter, ignoreCase = true) ) { - val model = ConversationModel(chatRoom, disabledBecauseNotSecured) + val model = ConversationModel(chatRoom) list.add(model) count += 1 } diff --git a/app/src/main/java/org/linphone/ui/main/model/AccountModel.kt b/app/src/main/java/org/linphone/ui/main/model/AccountModel.kt index 264512663..f71d95418 100644 --- a/app/src/main/java/org/linphone/ui/main/model/AccountModel.kt +++ b/app/src/main/java/org/linphone/ui/main/model/AccountModel.kt @@ -24,6 +24,7 @@ import androidx.annotation.UiThread import androidx.annotation.WorkerThread import androidx.lifecycle.MutableLiveData import org.linphone.LinphoneApplication.Companion.coreContext +import org.linphone.LinphoneApplication.Companion.corePreferences import org.linphone.R import org.linphone.contacts.AbstractAvatarModel import org.linphone.core.Account @@ -113,8 +114,6 @@ class AccountModel @WorkerThread constructor( account.addListener(accountListener) coreContext.core.addListener(coreListener) - trust.postValue(SecurityLevel.EndToEndEncryptedAndVerified) - showTrust.postValue(account.isEndToEndEncryptionMandatory()) presenceStatus.postValue(ConsolidatedPresence.Offline) update() @@ -166,6 +165,9 @@ class AccountModel @WorkerThread constructor( "$TAG Refreshing info for account [${account.params.identityAddress?.asStringUriOnly()}]" ) + trust.postValue(SecurityLevel.EndToEndEncryptedAndVerified) + showTrust.postValue(account.isEndToEndEncryptionMandatory()) + val name = LinphoneUtils.getDisplayName(account.params.identityAddress) displayName.postValue(name) @@ -233,7 +235,47 @@ class AccountModel @WorkerThread constructor( } } +@WorkerThread fun Account.isEndToEndEncryptionMandatory(): Boolean { - // TODO FIXME: use real API when available - return params.identityAddress?.domain == "sip.linphone.org" + val defaultDomain = params.identityAddress?.domain == corePreferences.defaultDomain + // TODO FIXME: use API when available + // val encryption = params.mediaEncryption == MediaEncryption.ZRTP && params.mediaEncryptionMandatory && params.instantMessagingEncryptionMandatory + val encryption = corePreferences.config.getBool("test", "account_e2e_mode", false) + return defaultDomain && encryption +} + +@WorkerThread +fun Account.setEndToEndEncryptionMandatory() { + /* + TODO FIXME: use API when available + val clone = params.clone() + clone.mediaEncryption = MediaEncryption.ZRTP + clone.mediaEncryptionMandatory = true + clone.instantMessagingEncryptionMandatory = true + params = clone + */ + corePreferences.config.setBool("test", "account_e2e_mode", true) + + if (this == core.defaultAccount) { + coreContext.contactsManager.updateContactsModelDependingOnDefaultAccountMode() + } + Log.i("[Account] End-to-end encryption set mandatory on account") +} + +@WorkerThread +fun Account.setInteroperabilityMode() { + /* + TODO FIXME: use API when available + val clone = params.clone() + clone.mediaEncryption = MediaEncryption.SRTP + clone.mediaEncryptionMandatory = false + clone.instantMessagingEncryptionMandatory = false + params = clone + */ + corePreferences.config.setBool("test", "account_e2e_mode", false) + + if (this == core.defaultAccount) { + coreContext.contactsManager.updateContactsModelDependingOnDefaultAccountMode() + } + Log.i("[Account] Account configured in interoperable mode") } diff --git a/app/src/main/java/org/linphone/ui/main/settings/viewmodel/AccountProfileViewModel.kt b/app/src/main/java/org/linphone/ui/main/settings/viewmodel/AccountProfileViewModel.kt index 736eceda4..6714b0639 100644 --- a/app/src/main/java/org/linphone/ui/main/settings/viewmodel/AccountProfileViewModel.kt +++ b/app/src/main/java/org/linphone/ui/main/settings/viewmodel/AccountProfileViewModel.kt @@ -30,6 +30,8 @@ import org.linphone.core.Factory import org.linphone.core.tools.Log import org.linphone.ui.main.model.AccountModel import org.linphone.ui.main.model.isEndToEndEncryptionMandatory +import org.linphone.ui.main.model.setEndToEndEncryptionMandatory +import org.linphone.ui.main.model.setInteroperabilityMode import org.linphone.ui.main.settings.model.AccountDeviceModel import org.linphone.utils.Event @@ -299,6 +301,18 @@ class AccountProfileViewModel @UiThread constructor() : ViewModel() { @UiThread fun applySelectedMode() { - // TODO + coreContext.postOnCoreThread { core -> + if (isCurrentlySelectedModeSecure.value == true) { + Log.i( + "$TAG Selected mode is end-to-end encrypted, forcing media & im encryption to mandatory and setting media encryption to ZRTP" + ) + account.setEndToEndEncryptionMandatory() + } else { + Log.i( + "$TAG Selected mode is interoperable, not forcing media & im encryption to mandatory and setting media encryption to SRTP" + ) + account.setInteroperabilityMode() + } + } } } diff --git a/app/src/main/res/layout/account_profile_fragment.xml b/app/src/main/res/layout/account_profile_fragment.xml index 813455e87..e00d1c463 100644 --- a/app/src/main/res/layout/account_profile_fragment.xml +++ b/app/src/main/res/layout/account_profile_fragment.xml @@ -415,7 +415,7 @@ android:layout_height="wrap_content" android:layout_marginStart="16dp" android:layout_marginEnd="16dp" - android:text="@{viewModel.isCurrentlySelectedModeSecure ? @string/manage_account_secure_mode_default_title : @string/manage_account_secure_mode_interoperable_title, default=@string/manage_account_secure_mode_default_title}" + android:text="@{viewModel.isCurrentlySelectedModeSecure ? @string/manage_account_e2e_encrypted_mode_default_title : @string/manage_account_e2e_encrypted_mode_interoperable_title, default=@string/manage_account_e2e_encrypted_mode_default_title}" app:layout_constraintTop_toTopOf="@id/mode_background" app:layout_constraintStart_toStartOf="@id/mode_background" app:layout_constraintBottom_toBottomOf="@id/mode_background"/> diff --git a/app/src/main/res/layout/account_profile_secure_mode_fragment.xml b/app/src/main/res/layout/account_profile_secure_mode_fragment.xml index 52e1a8295..bc6b39203 100644 --- a/app/src/main/res/layout/account_profile_secure_mode_fragment.xml +++ b/app/src/main/res/layout/account_profile_secure_mode_fragment.xml @@ -85,7 +85,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="20dp" - android:text="@string/manage_account_secure_mode_default_title" + android:text="@string/manage_account_e2e_encrypted_mode_default_title" android:textSize="16sp" android:textColor="?attr/color_main2_900" android:checked="@{viewModel.isCurrentlySelectedModeSecure}" @@ -119,7 +119,7 @@ android:paddingBottom="10dp" android:paddingStart="16dp" android:paddingEnd="16dp" - android:text="@string/manage_account_secure_mode_default_summary" + android:text="@string/manage_account_e2e_encrypted_mode_default_summary" android:textSize="14sp" android:gravity="start" android:drawableEnd="@drawable/profile_secure_logo" @@ -146,7 +146,7 @@ android:layout_height="wrap_content" android:layout_marginTop="32dp" android:layout_marginStart="20dp" - android:text="@string/manage_account_secure_mode_interoperable_title" + android:text="@string/manage_account_e2e_encrypted_mode_interoperable_title" android:textSize="16sp" android:textColor="?attr/color_main2_900" android:checked="@{!viewModel.isCurrentlySelectedModeSecure}" @@ -180,7 +180,7 @@ android:paddingBottom="20dp" android:paddingStart="16dp" android:paddingEnd="16dp" - android:text="@string/manage_account_secure_mode_interoperable_summary" + android:text="@string/manage_account_e2e_encrypted_mode_interoperable_summary" android:textSize="14sp" android:gravity="start" android:drawableEnd="@drawable/profile_interop_logo" diff --git a/app/src/main/res/layout/assistant_secure_mode_fragment.xml b/app/src/main/res/layout/assistant_secure_mode_fragment.xml index 664c45d85..4a50cdf08 100644 --- a/app/src/main/res/layout/assistant_secure_mode_fragment.xml +++ b/app/src/main/res/layout/assistant_secure_mode_fragment.xml @@ -92,7 +92,7 @@ android:layout_height="wrap_content" android:layout_marginTop="32dp" android:layout_marginStart="16dp" - android:text="@string/manage_account_secure_mode_default_title" + android:text="@string/manage_account_e2e_encrypted_mode_default_title" android:textSize="16sp" android:textColor="?attr/color_main2_900" android:checked="@{viewModel.isCurrentlySelectedModeSecure}" @@ -127,7 +127,7 @@ android:paddingBottom="20dp" android:paddingStart="16dp" android:paddingEnd="16dp" - android:text="@string/manage_account_secure_mode_default_summary" + android:text="@string/manage_account_e2e_encrypted_mode_default_summary" android:textSize="14sp" android:gravity="start" android:drawableEnd="@drawable/profile_secure_logo" @@ -144,7 +144,7 @@ android:layout_height="wrap_content" android:layout_marginTop="32dp" android:layout_marginStart="16dp" - android:text="@string/manage_account_secure_mode_interoperable_title" + android:text="@string/manage_account_e2e_encrypted_mode_interoperable_title" android:textSize="16sp" android:textColor="?attr/color_main2_900" android:checked="@{!viewModel.isCurrentlySelectedModeSecure}" @@ -179,7 +179,7 @@ android:paddingBottom="20dp" android:paddingStart="16dp" android:paddingEnd="16dp" - android:text="@string/manage_account_secure_mode_interoperable_summary" + android:text="@string/manage_account_e2e_encrypted_mode_interoperable_summary" android:textSize="14sp" android:gravity="start" android:drawableEnd="@drawable/profile_interop_logo" diff --git a/app/src/main/res/layout/chat_list_cell.xml b/app/src/main/res/layout/chat_list_cell.xml index 0ba73f376..362430a9a 100644 --- a/app/src/main/res/layout/chat_list_cell.xml +++ b/app/src/main/res/layout/chat_list_cell.xml @@ -57,7 +57,7 @@ android:layout_height="wrap_content" app:barrierDirection="start" app:barrierMargin="-5dp" - app:constraint_referenced_ids="notifications_count, warning_disabled_not_secured, ephemeral, muted, date_time, last_sent_message_status" /> + app:constraint_referenced_ids="notifications_count, warning_not_secured, ephemeral, muted, date_time, last_sent_message_status" /> Supprimer le compte Choisir le mode Appliquer - Chiffré de bout en bout - Intéropérable - Ce mode vous garantit la confidentialité de tous vos échanges. Notre technologie de chiffrement de bout en bout assure un niveau de sécurité maximal pour tous vos échanges. - Ce mode vous permet de profiter de toutes les fonctionnalités de &appName; tout en restant interopérable avec n’importe qu’elle autre service SIP. + Chiffré de bout en bout + Intéropérable + Ce mode vous garantit la confidentialité de tous vos échanges. Notre technologie de chiffrement de bout en bout assure un niveau de sécurité maximal pour tous vos échanges. + Ce mode vous permet de profiter de toutes les fonctionnalités de &appName; tout en restant interopérable avec n’importe qu’elle autre service SIP. Supprimer Dernière connexion : - Blah - Blah + Blah + Blah Supprimer %s ? Vous pouvez vous reconnecter à tout moment en cliquant sur "Ajouter un compte".Cependant toutes les informations stockées sur ce périphérique seront supprimées. diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 995d3f32a..405e3e56e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -327,14 +327,14 @@ Delete account Choose account mode Apply - Default mode - Interoperable mode - This mode guarantee your data confidentiality. Our end-to-end encryption technology provide the highest level or security for your communications. - This mode allows you to enjoy all &appName; features while staying interoperable with any SIP service through point-to-point encryption. + End-to-end encrypted mode + Interoperable mode + This mode guarantee your data confidentiality. Our end-to-end encryption technology provide the highest level or security for your communications. + This mode allows you to enjoy all &appName; features while staying interoperable with any SIP service through point-to-point encryption. Remove Last connection: - Blah - Blah + Blah + Blah Delete %s? You can reconnect at any time by clicking “Add an account”. However, all data on this phone will be deleted.