From 31bbc9a4d5bddcb4f347e125e64fb857c725ba4e Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 2 Oct 2020 12:01:55 +0200 Subject: [PATCH] Use FLAG_SECURE for sensitive screens such as encrypted chat rooms --- .../activities/main/about/AboutFragment.kt | 4 +- .../fragments/ChatRoomCreationFragment.kt | 4 +- .../chat/fragments/DetailChatRoomFragment.kt | 1 + .../main/chat/fragments/DevicesFragment.kt | 6 +- .../main/chat/fragments/EphemeralFragment.kt | 5 +- .../main/chat/fragments/GroupInfoFragment.kt | 5 +- .../main/chat/fragments/ImdnFragment.kt | 6 +- .../chat/fragments/MasterChatRoomsFragment.kt | 1 + .../main/dialer/fragments/DialerFragment.kt | 4 +- .../main/fragments/MasterFragment.kt | 3 +- .../main/fragments/SecureFragment.kt | 89 +++++++++++++++++++ .../settings/fragments/SettingsFragment.kt | 4 +- app/src/main/res/layout/empty_fragment.xml | 6 +- 13 files changed, 118 insertions(+), 20 deletions(-) create mode 100644 app/src/main/java/org/linphone/activities/main/fragments/SecureFragment.kt diff --git a/app/src/main/java/org/linphone/activities/main/about/AboutFragment.kt b/app/src/main/java/org/linphone/activities/main/about/AboutFragment.kt index 926de5de0..dc07a0b9b 100644 --- a/app/src/main/java/org/linphone/activities/main/about/AboutFragment.kt +++ b/app/src/main/java/org/linphone/activities/main/about/AboutFragment.kt @@ -25,12 +25,12 @@ import android.os.Bundle import androidx.lifecycle.ViewModelProvider import androidx.navigation.fragment.findNavController import org.linphone.R -import org.linphone.activities.GenericFragment import org.linphone.activities.main.MainActivity +import org.linphone.activities.main.fragments.SecureFragment import org.linphone.databinding.AboutFragmentBinding import org.linphone.utils.AppUtils -class AboutFragment : GenericFragment() { +class AboutFragment : SecureFragment() { private lateinit var viewModel: AboutViewModel override fun getLayoutId(): Int = R.layout.about_fragment diff --git a/app/src/main/java/org/linphone/activities/main/chat/fragments/ChatRoomCreationFragment.kt b/app/src/main/java/org/linphone/activities/main/chat/fragments/ChatRoomCreationFragment.kt index bb1748469..0ff734b41 100644 --- a/app/src/main/java/org/linphone/activities/main/chat/fragments/ChatRoomCreationFragment.kt +++ b/app/src/main/java/org/linphone/activities/main/chat/fragments/ChatRoomCreationFragment.kt @@ -26,15 +26,15 @@ import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import org.linphone.R -import org.linphone.activities.GenericFragment import org.linphone.activities.main.MainActivity import org.linphone.activities.main.chat.adapters.ChatRoomCreationContactsAdapter import org.linphone.activities.main.chat.viewmodels.ChatRoomCreationViewModel +import org.linphone.activities.main.fragments.SecureFragment import org.linphone.activities.main.viewmodels.SharedMainViewModel import org.linphone.core.Address import org.linphone.databinding.ChatRoomCreationFragmentBinding -class ChatRoomCreationFragment : GenericFragment() { +class ChatRoomCreationFragment : SecureFragment() { private lateinit var viewModel: ChatRoomCreationViewModel private lateinit var sharedViewModel: SharedMainViewModel private lateinit var adapter: ChatRoomCreationContactsAdapter diff --git a/app/src/main/java/org/linphone/activities/main/chat/fragments/DetailChatRoomFragment.kt b/app/src/main/java/org/linphone/activities/main/chat/fragments/DetailChatRoomFragment.kt index 9511ca3ea..19f215f98 100644 --- a/app/src/main/java/org/linphone/activities/main/chat/fragments/DetailChatRoomFragment.kt +++ b/app/src/main/java/org/linphone/activities/main/chat/fragments/DetailChatRoomFragment.kt @@ -95,6 +95,7 @@ class DetailChatRoomFragment : MasterFragment() { +class DevicesFragment : SecureFragment() { private lateinit var listViewModel: DevicesListViewModel private lateinit var sharedViewModel: SharedMainViewModel @@ -47,6 +47,8 @@ class DevicesFragment : GenericFragment() { val chatRoom = sharedViewModel.selectedChatRoom.value chatRoom ?: return + isSecure = chatRoom.currentParams.encryptionEnabled() + listViewModel = ViewModelProvider( this, DevicesListViewModelFactory(chatRoom) diff --git a/app/src/main/java/org/linphone/activities/main/chat/fragments/EphemeralFragment.kt b/app/src/main/java/org/linphone/activities/main/chat/fragments/EphemeralFragment.kt index 9935db461..647bb44a2 100644 --- a/app/src/main/java/org/linphone/activities/main/chat/fragments/EphemeralFragment.kt +++ b/app/src/main/java/org/linphone/activities/main/chat/fragments/EphemeralFragment.kt @@ -23,13 +23,13 @@ import android.os.Bundle import androidx.lifecycle.ViewModelProvider import androidx.navigation.fragment.findNavController import org.linphone.R -import org.linphone.activities.GenericFragment import org.linphone.activities.main.chat.viewmodels.EphemeralViewModel import org.linphone.activities.main.chat.viewmodels.EphemeralViewModelFactory +import org.linphone.activities.main.fragments.SecureFragment import org.linphone.activities.main.viewmodels.SharedMainViewModel import org.linphone.databinding.ChatRoomEphemeralFragmentBinding -class EphemeralFragment : GenericFragment() { +class EphemeralFragment : SecureFragment() { private lateinit var viewModel: EphemeralViewModel private lateinit var sharedViewModel: SharedMainViewModel @@ -40,6 +40,7 @@ class EphemeralFragment : GenericFragment() { override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) + isSecure = true binding.lifecycleOwner = this sharedViewModel = activity?.run { diff --git a/app/src/main/java/org/linphone/activities/main/chat/fragments/GroupInfoFragment.kt b/app/src/main/java/org/linphone/activities/main/chat/fragments/GroupInfoFragment.kt index f394a853f..27c280eb1 100644 --- a/app/src/main/java/org/linphone/activities/main/chat/fragments/GroupInfoFragment.kt +++ b/app/src/main/java/org/linphone/activities/main/chat/fragments/GroupInfoFragment.kt @@ -26,12 +26,12 @@ import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import org.linphone.R -import org.linphone.activities.GenericFragment import org.linphone.activities.main.MainActivity import org.linphone.activities.main.chat.GroupChatRoomMember import org.linphone.activities.main.chat.adapters.GroupInfoParticipantsAdapter import org.linphone.activities.main.chat.viewmodels.GroupInfoViewModel import org.linphone.activities.main.chat.viewmodels.GroupInfoViewModelFactory +import org.linphone.activities.main.fragments.SecureFragment import org.linphone.activities.main.viewmodels.DialogViewModel import org.linphone.activities.main.viewmodels.SharedMainViewModel import org.linphone.core.Address @@ -40,7 +40,7 @@ import org.linphone.core.ChatRoomCapabilities import org.linphone.databinding.ChatRoomGroupInfoFragmentBinding import org.linphone.utils.DialogUtils -class GroupInfoFragment : GenericFragment() { +class GroupInfoFragment : SecureFragment() { private lateinit var viewModel: GroupInfoViewModel private lateinit var sharedViewModel: SharedMainViewModel private lateinit var adapter: GroupInfoParticipantsAdapter @@ -58,6 +58,7 @@ class GroupInfoFragment : GenericFragment() { } ?: throw Exception("Invalid Activity") val chatRoom: ChatRoom? = sharedViewModel.selectedGroupChatRoom.value + isSecure = chatRoom?.currentParams?.encryptionEnabled() ?: false viewModel = ViewModelProvider( this, diff --git a/app/src/main/java/org/linphone/activities/main/chat/fragments/ImdnFragment.kt b/app/src/main/java/org/linphone/activities/main/chat/fragments/ImdnFragment.kt index 763382148..c0f04f962 100644 --- a/app/src/main/java/org/linphone/activities/main/chat/fragments/ImdnFragment.kt +++ b/app/src/main/java/org/linphone/activities/main/chat/fragments/ImdnFragment.kt @@ -25,16 +25,16 @@ import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import org.linphone.R -import org.linphone.activities.GenericFragment import org.linphone.activities.main.chat.adapters.ImdnAdapter import org.linphone.activities.main.chat.viewmodels.ImdnViewModel import org.linphone.activities.main.chat.viewmodels.ImdnViewModelFactory +import org.linphone.activities.main.fragments.SecureFragment import org.linphone.activities.main.viewmodels.SharedMainViewModel import org.linphone.core.tools.Log import org.linphone.databinding.ChatRoomImdnFragmentBinding import org.linphone.utils.RecyclerViewHeaderDecoration -class ImdnFragment : GenericFragment() { +class ImdnFragment : SecureFragment() { private lateinit var viewModel: ImdnViewModel private lateinit var adapter: ImdnAdapter private lateinit var sharedViewModel: SharedMainViewModel @@ -55,6 +55,8 @@ class ImdnFragment : GenericFragment() { val chatRoom = sharedViewModel.selectedChatRoom.value chatRoom ?: return + isSecure = chatRoom.currentParams.encryptionEnabled() + if (arguments != null) { val messageId = arguments?.getString("MessageId") val message = if (messageId != null) chatRoom.findMessage(messageId) else null diff --git a/app/src/main/java/org/linphone/activities/main/chat/fragments/MasterChatRoomsFragment.kt b/app/src/main/java/org/linphone/activities/main/chat/fragments/MasterChatRoomsFragment.kt index 5cec07e2f..1f8dc86d7 100644 --- a/app/src/main/java/org/linphone/activities/main/chat/fragments/MasterChatRoomsFragment.kt +++ b/app/src/main/java/org/linphone/activities/main/chat/fragments/MasterChatRoomsFragment.kt @@ -71,6 +71,7 @@ class MasterChatRoomsFragment : MasterFragment() { +class DialerFragment : SecureFragment() { private lateinit var viewModel: DialerViewModel private lateinit var sharedViewModel: SharedMainViewModel diff --git a/app/src/main/java/org/linphone/activities/main/fragments/MasterFragment.kt b/app/src/main/java/org/linphone/activities/main/fragments/MasterFragment.kt index 891236e02..de54adab7 100644 --- a/app/src/main/java/org/linphone/activities/main/fragments/MasterFragment.kt +++ b/app/src/main/java/org/linphone/activities/main/fragments/MasterFragment.kt @@ -24,7 +24,6 @@ import android.os.Bundle import androidx.databinding.ViewDataBinding import androidx.lifecycle.ViewModelProvider import org.linphone.R -import org.linphone.activities.GenericFragment import org.linphone.activities.main.viewmodels.DialogViewModel import org.linphone.activities.main.viewmodels.ListTopBarViewModel import org.linphone.utils.AppUtils @@ -35,7 +34,7 @@ import org.linphone.utils.SelectionListAdapter * This fragment can be inherited by all fragments that will display a list * where items can be selected for removal through the ListTopBarFragment */ -abstract class MasterFragment> : GenericFragment() { +abstract class MasterFragment> : SecureFragment() { protected var _adapter: U? = null protected val adapter get() = _adapter!! diff --git a/app/src/main/java/org/linphone/activities/main/fragments/SecureFragment.kt b/app/src/main/java/org/linphone/activities/main/fragments/SecureFragment.kt new file mode 100644 index 000000000..e5c166da0 --- /dev/null +++ b/app/src/main/java/org/linphone/activities/main/fragments/SecureFragment.kt @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2010-2020 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.activities.main.fragments + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.view.WindowManager +import androidx.core.view.ViewCompat +import androidx.databinding.ViewDataBinding +import androidx.lifecycle.lifecycleScope +import java.util.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import org.linphone.activities.GenericFragment +import org.linphone.core.tools.Log + +abstract class SecureFragment : GenericFragment() { + protected var isSecure: Boolean = false + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + // Assume we might want to be secure to prevent quick visible blink while screen recording. + enableSecureMode(true) + return super.onCreateView(inflater, container, savedInstanceState) + } + + override fun onResume() { + if (isSecure) { + enableSecureMode(isSecure) + } else { + // This is a workaround to prevent a small blink showing the previous secured screen + lifecycleScope.launch { + withContext(Dispatchers.Main) { + delay(200) + enableSecureMode(isSecure) + } + } + } + super.onResume() + } + + private fun enableSecureMode(enable: Boolean) { + Log.d("[Secure Fragment] ${if (enable) "Enabling" else "Disabling"} secure flag on window") + val window = requireActivity().window + val windowManager = requireActivity().windowManager + + val flags: Int = window.attributes.flags + if ((enable && flags and WindowManager.LayoutParams.FLAG_SECURE != 0) || + (!enable && flags and WindowManager.LayoutParams.FLAG_SECURE == 0)) { + Log.d("[Secure Fragment] Secure flag is already ${if (enable) "enabled" else "disabled"}, skipping...") + return + } + + if (enable) { + window.addFlags(WindowManager.LayoutParams.FLAG_SECURE) + } else { + window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE) + } + + if (ViewCompat.isAttachedToWindow(window.decorView)) { + Log.d("[Secure Fragment] Redrawing window decorView to apply flag") + windowManager.updateViewLayout(window.decorView, window.attributes) + } + } +} diff --git a/app/src/main/java/org/linphone/activities/main/settings/fragments/SettingsFragment.kt b/app/src/main/java/org/linphone/activities/main/settings/fragments/SettingsFragment.kt index 09dbc432d..b4199fe51 100644 --- a/app/src/main/java/org/linphone/activities/main/settings/fragments/SettingsFragment.kt +++ b/app/src/main/java/org/linphone/activities/main/settings/fragments/SettingsFragment.kt @@ -23,8 +23,8 @@ import android.os.Bundle import androidx.lifecycle.ViewModelProvider import androidx.navigation.fragment.findNavController import org.linphone.R -import org.linphone.activities.GenericFragment import org.linphone.activities.main.* +import org.linphone.activities.main.fragments.SecureFragment import org.linphone.activities.main.navigateToAccountSettings import org.linphone.activities.main.navigateToAudioSettings import org.linphone.activities.main.navigateToTunnelSettings @@ -34,7 +34,7 @@ import org.linphone.activities.main.viewmodels.SharedMainViewModel import org.linphone.core.tools.Log import org.linphone.databinding.SettingsFragmentBinding -class SettingsFragment : GenericFragment() { +class SettingsFragment : SecureFragment() { private lateinit var sharedViewModel: SharedMainViewModel private lateinit var viewModel: SettingsViewModel diff --git a/app/src/main/res/layout/empty_fragment.xml b/app/src/main/res/layout/empty_fragment.xml index 3509b8411..2c5d8a485 100644 --- a/app/src/main/res/layout/empty_fragment.xml +++ b/app/src/main/res/layout/empty_fragment.xml @@ -1,6 +1,8 @@ + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="?attr/backgroundColor"> \ No newline at end of file