Use FLAG_SECURE for sensitive screens such as encrypted chat rooms

This commit is contained in:
Sylvain Berfini 2020-10-02 12:01:55 +02:00
parent c86b548fa9
commit 31bbc9a4d5
13 changed files with 118 additions and 20 deletions

View file

@ -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<AboutFragmentBinding>() {
class AboutFragment : SecureFragment<AboutFragmentBinding>() {
private lateinit var viewModel: AboutViewModel
override fun getLayoutId(): Int = R.layout.about_fragment

View file

@ -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<ChatRoomCreationFragmentBinding>() {
class ChatRoomCreationFragment : SecureFragment<ChatRoomCreationFragmentBinding>() {
private lateinit var viewModel: ChatRoomCreationViewModel
private lateinit var sharedViewModel: SharedMainViewModel
private lateinit var adapter: ChatRoomCreationContactsAdapter

View file

@ -95,6 +95,7 @@ class DetailChatRoomFragment : MasterFragment<ChatRoomDetailFragmentBinding, Cha
val chatRoom = sharedViewModel.selectedChatRoom.value
chatRoom ?: return
chatRoomAddress = chatRoom.peerAddress.asStringUriOnly()
isSecure = chatRoom.currentParams.encryptionEnabled()
viewModel = ViewModelProvider(
this,

View file

@ -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.DevicesListViewModel
import org.linphone.activities.main.chat.viewmodels.DevicesListViewModelFactory
import org.linphone.activities.main.fragments.SecureFragment
import org.linphone.activities.main.viewmodels.SharedMainViewModel
import org.linphone.databinding.ChatRoomDevicesFragmentBinding
class DevicesFragment : GenericFragment<ChatRoomDevicesFragmentBinding>() {
class DevicesFragment : SecureFragment<ChatRoomDevicesFragmentBinding>() {
private lateinit var listViewModel: DevicesListViewModel
private lateinit var sharedViewModel: SharedMainViewModel
@ -47,6 +47,8 @@ class DevicesFragment : GenericFragment<ChatRoomDevicesFragmentBinding>() {
val chatRoom = sharedViewModel.selectedChatRoom.value
chatRoom ?: return
isSecure = chatRoom.currentParams.encryptionEnabled()
listViewModel = ViewModelProvider(
this,
DevicesListViewModelFactory(chatRoom)

View file

@ -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<ChatRoomEphemeralFragmentBinding>() {
class EphemeralFragment : SecureFragment<ChatRoomEphemeralFragmentBinding>() {
private lateinit var viewModel: EphemeralViewModel
private lateinit var sharedViewModel: SharedMainViewModel
@ -40,6 +40,7 @@ class EphemeralFragment : GenericFragment<ChatRoomEphemeralFragmentBinding>() {
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
isSecure = true
binding.lifecycleOwner = this
sharedViewModel = activity?.run {

View file

@ -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<ChatRoomGroupInfoFragmentBinding>() {
class GroupInfoFragment : SecureFragment<ChatRoomGroupInfoFragmentBinding>() {
private lateinit var viewModel: GroupInfoViewModel
private lateinit var sharedViewModel: SharedMainViewModel
private lateinit var adapter: GroupInfoParticipantsAdapter
@ -58,6 +58,7 @@ class GroupInfoFragment : GenericFragment<ChatRoomGroupInfoFragmentBinding>() {
} ?: throw Exception("Invalid Activity")
val chatRoom: ChatRoom? = sharedViewModel.selectedGroupChatRoom.value
isSecure = chatRoom?.currentParams?.encryptionEnabled() ?: false
viewModel = ViewModelProvider(
this,

View file

@ -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<ChatRoomImdnFragmentBinding>() {
class ImdnFragment : SecureFragment<ChatRoomImdnFragmentBinding>() {
private lateinit var viewModel: ImdnViewModel
private lateinit var adapter: ImdnAdapter
private lateinit var sharedViewModel: SharedMainViewModel
@ -55,6 +55,8 @@ class ImdnFragment : GenericFragment<ChatRoomImdnFragmentBinding>() {
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

View file

@ -71,6 +71,7 @@ class MasterChatRoomsFragment : MasterFragment<ChatRoomMasterFragmentBinding, Ch
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
isSecure = true
binding.lifecycleOwner = this
listViewModel = ViewModelProvider(this).get(ChatRoomsListViewModel::class.java)

View file

@ -33,9 +33,9 @@ import org.linphone.BuildConfig
import org.linphone.LinphoneApplication.Companion.coreContext
import org.linphone.LinphoneApplication.Companion.corePreferences
import org.linphone.R
import org.linphone.activities.GenericFragment
import org.linphone.activities.main.MainActivity
import org.linphone.activities.main.dialer.viewmodels.DialerViewModel
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.tools.Log
@ -43,7 +43,7 @@ import org.linphone.databinding.DialerFragmentBinding
import org.linphone.utils.AppUtils
import org.linphone.utils.DialogUtils
class DialerFragment : GenericFragment<DialerFragmentBinding>() {
class DialerFragment : SecureFragment<DialerFragmentBinding>() {
private lateinit var viewModel: DialerViewModel
private lateinit var sharedViewModel: SharedMainViewModel

View file

@ -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<T : ViewDataBinding, U : SelectionListAdapter<*, *>> : GenericFragment<T>() {
abstract class MasterFragment<T : ViewDataBinding, U : SelectionListAdapter<*, *>> : SecureFragment<T>() {
protected var _adapter: U? = null
protected val adapter get() = _adapter!!

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
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<T : ViewDataBinding> : GenericFragment<T>() {
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)
}
}
}

View file

@ -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<SettingsFragmentBinding>() {
class SettingsFragment : SecureFragment<SettingsFragmentBinding>() {
private lateinit var sharedViewModel: SharedMainViewModel
private lateinit var viewModel: SettingsViewModel

View file

@ -1,6 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/backgroundColor">
</LinearLayout>