From d80cad57b6285ebae65e822b116fddf9f01e2b0e Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Mon, 30 Jan 2023 13:24:15 +0000 Subject: [PATCH] android: require auth when opening users list (#1860) * android: require auth when opening users list * different logic in asking to auth * unused code --- .../chat/simplex/app/views/TerminalView.kt | 60 --------------- .../app/views/usersettings/SettingsView.kt | 73 +++++++++++++------ 2 files changed, 52 insertions(+), 81 deletions(-) diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/TerminalView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/TerminalView.kt index 8f6d97d084..424bb978a0 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/TerminalView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/TerminalView.kt @@ -1,29 +1,21 @@ package chat.simplex.app.views -import android.content.Context import android.content.res.Configuration -import android.os.SystemClock import androidx.activity.compose.BackHandler import androidx.compose.foundation.* import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.* import androidx.compose.foundation.text.selection.SelectionContainer import androidx.compose.material.* -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.outlined.Lock import androidx.compose.runtime.* -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import androidx.fragment.app.FragmentActivity -import chat.simplex.app.R import chat.simplex.app.model.* import chat.simplex.app.ui.theme.* import chat.simplex.app.views.chat.* @@ -31,70 +23,18 @@ import chat.simplex.app.views.helpers.* import com.google.accompanist.insets.ProvideWindowInsets import com.google.accompanist.insets.navigationBarsWithImePadding -private val lastSuccessfulAuth: MutableState = mutableStateOf(null) - @Composable fun TerminalView(chatModel: ChatModel, close: () -> Unit) { val composeState = remember { mutableStateOf(ComposeState(useLinkPreviews = false)) } - val lastSuccessfulAuth = remember { lastSuccessfulAuth } BackHandler(onBack = { - lastSuccessfulAuth.value = null close() }) - val authorized = remember { !chatModel.controller.appPrefs.performLA.get() } - val context = LocalContext.current - LaunchedEffect(lastSuccessfulAuth.value) { - if (!authorized && !authorizedPreviously(lastSuccessfulAuth)) { - runAuth(lastSuccessfulAuth, context) - } - } - if (authorized || authorizedPreviously(lastSuccessfulAuth)) { - LaunchedEffect(Unit) { - // Update auth each time user visits this screen in authenticated state just to prolong authorized time - lastSuccessfulAuth.value = SystemClock.elapsedRealtime() - } TerminalLayout( remember { chatModel.terminalItems }, composeState, sendCommand = { sendCommand(chatModel, composeState) }, close ) - } else { - Surface(Modifier.fillMaxSize()) { - Column(Modifier.background(MaterialTheme.colors.background)) { - CloseSheetBar(close) - Box( - Modifier.fillMaxSize(), - contentAlignment = Alignment.Center - ) { - SimpleButton( - stringResource(R.string.auth_unlock), - icon = Icons.Outlined.Lock, - click = { - runAuth(lastSuccessfulAuth, context) - } - ) - } - } - } - } -} - -private fun authorizedPreviously(lastSuccessfulAuth: State): Boolean = - lastSuccessfulAuth.value?.let { SystemClock.elapsedRealtime() - it < 30_000 } ?: false - -private fun runAuth(lastSuccessfulAuth: MutableState, context: Context) { - authenticate( - generalGetString(R.string.auth_open_chat_console), - generalGetString(R.string.auth_log_in_using_credential), - context as FragmentActivity, - completed = { laResult -> - lastSuccessfulAuth.value = when (laResult) { - LAResult.Success, LAResult.Unavailable -> SystemClock.elapsedRealtime() - is LAResult.Error, LAResult.Failed -> null - } - } - ) } private fun sendCommand(chatModel: ChatModel, composeState: MutableState) { diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/SettingsView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/SettingsView.kt index 2faf4c18f3..eb412baa86 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/SettingsView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/SettingsView.kt @@ -4,8 +4,8 @@ import SectionDivider import SectionItemView import SectionSpacer import SectionView +import android.content.Context import android.content.res.Configuration -import android.icu.util.VersionInfo import androidx.compose.foundation.* import androidx.compose.foundation.layout.* import androidx.compose.material.* @@ -17,14 +17,14 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.platform.LocalUriHandler -import androidx.compose.ui.platform.UriHandler +import androidx.compose.ui.platform.* import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.* +import androidx.fragment.app.FragmentActivity import chat.simplex.app.* import chat.simplex.app.R import chat.simplex.app.model.* @@ -45,6 +45,8 @@ fun SettingsView(chatModel: ChatModel, setPerformLA: (Boolean) -> Unit) { MaintainIncognitoState(chatModel) if (user != null) { + val requireAuth = remember { chatModel.controller.appPrefs.performLA.state } + val context = LocalContext.current SettingsLayout( profile = user.profile, stopped, @@ -57,7 +59,6 @@ fun SettingsView(chatModel: ChatModel, setPerformLA: (Boolean) -> Unit) { showModal = { modalView -> { ModalManager.shared.showModal { modalView(chatModel) } } }, showSettingsModal = { modalView -> { ModalManager.shared.showModal(true) { modalView(chatModel) } } }, showCustomModal = { modalView -> { ModalManager.shared.showCustomModal { close -> modalView(chatModel, close) } } }, - showTerminal = { ModalManager.shared.showCustomModal { close -> TerminalView(chatModel, close) } }, showVersion = { withApi { val info = chatModel.controller.apiGetVersion() @@ -65,7 +66,36 @@ fun SettingsView(chatModel: ChatModel, setPerformLA: (Boolean) -> Unit) { ModalManager.shared.showModal { VersionInfoView(info) } } } - } + }, + withAuth = { block -> + if (!requireAuth.value) { + block() + } else { + ModalManager.shared.showModalCloseable { close -> + val onFinishAuth = { success: Boolean -> + if (success) { + close() + block() + } + } + LaunchedEffect(Unit) { + runAuth(context, onFinishAuth) + } + Box( + Modifier.fillMaxSize(), + contentAlignment = Alignment.Center + ) { + SimpleButton( + stringResource(R.string.auth_unlock), + icon = Icons.Outlined.Lock, + click = { + runAuth(context, onFinishAuth) + } + ) + } + } + } + }, ) } } @@ -73,16 +103,6 @@ fun SettingsView(chatModel: ChatModel, setPerformLA: (Boolean) -> Unit) { val simplexTeamUri = "simplex:/contact#/?v=1&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FK1rslx-m5bpXVIdMZg9NLUZ_8JBm8xTt%23MCowBQYDK2VuAyEALDeVe-sG8mRY22LsXlPgiwTNs9dbiLrNuA7f3ZMAJ2w%3D" -// TODO pass close -//fun showSectionedModal(chatModel: ChatModel, modalView: (@Composable (ChatModel) -> Unit)) { -// ModalManager.shared.showCustomModal { close -> -// ModalView(close = close, modifier = Modifier, -// background = if (isInDarkTheme()) MaterialTheme.colors.background else SettingsBackgroundLight) { -// modalView(chatModel) -// } -// } -//} - @Composable fun SettingsLayout( profile: LocalProfile, @@ -96,8 +116,8 @@ fun SettingsLayout( showModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit), showSettingsModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit), showCustomModal: (@Composable (ChatModel, () -> Unit) -> Unit) -> (() -> Unit), - showTerminal: () -> Unit, - showVersion: () -> Unit + showVersion: () -> Unit, + withAuth: (block: () -> Unit) -> Unit ) { val uriHandler = LocalUriHandler.current Surface(Modifier.fillMaxSize().verticalScroll(rememberScrollState())) { @@ -121,7 +141,7 @@ fun SettingsLayout( ProfilePreview(profile, stopped = stopped) } SectionDivider() - SettingsActionItem(Icons.Outlined.HowToReg, stringResource(R.string.your_chat_profiles), showSettingsModal { UserProfilesView(it) }, disabled = stopped) + SettingsActionItem(Icons.Outlined.HowToReg, stringResource(R.string.your_chat_profiles), { withAuth { showSettingsModal { UserProfilesView(it) }() } }, disabled = stopped) SectionDivider() SettingsIncognitoActionItem(incognitoPref, incognito, stopped) { showModal { IncognitoView() }() } SectionDivider() @@ -173,7 +193,7 @@ fun SettingsLayout( SettingsPreferenceItem(Icons.Outlined.Construction, stringResource(R.string.settings_developer_tools), developerTools, devTools) SectionDivider() if (devTools.value) { - ChatConsoleItem(showTerminal) + ChatConsoleItem { withAuth(showCustomModal { it, close -> TerminalView(it, close) }) } SectionDivider() InstallTerminalAppItem(uriHandler) SectionDivider() @@ -479,6 +499,17 @@ fun PreferenceToggleWithIcon( } } +private fun runAuth(context: Context, onFinish: (success: Boolean) -> Unit) { + authenticate( + generalGetString(R.string.auth_open_chat_console), + generalGetString(R.string.auth_log_in_using_credential), + context as FragmentActivity, + completed = { laResult -> + onFinish(laResult == LAResult.Success || laResult == LAResult.Unavailable) + } + ) +} + @Preview(showBackground = true) @Preview( uiMode = Configuration.UI_MODE_NIGHT_YES, @@ -500,8 +531,8 @@ fun PreviewSettingsLayout() { showModal = { {} }, showSettingsModal = { {} }, showCustomModal = { {} }, - showTerminal = {}, - showVersion = {} + showVersion = {}, + withAuth = {}, ) } }