From 46e28d20e3a6f836d4d5dfd19f53e99d1897b647 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20M=C3=BCller?= Date: Sat, 21 Sep 2024 12:49:42 +0200 Subject: [PATCH] unified preauth key and custom server login views MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian Müller --- .../java/com/tailscale/ipn/MainActivity.kt | 4 -- .../com/tailscale/ipn/ui/view/CustomLogin.kt | 62 ++++++++----------- .../tailscale/ipn/ui/view/UserSwitcherView.kt | 6 -- .../ipn/ui/viewModel/CustomLoginViewModel.kt | 23 ++----- .../ipn/ui/viewModel/IpnViewModel.kt | 12 ++-- 5 files changed, 36 insertions(+), 71 deletions(-) diff --git a/android/src/main/java/com/tailscale/ipn/MainActivity.kt b/android/src/main/java/com/tailscale/ipn/MainActivity.kt index bfdfd1918a..2f6b02b595 100644 --- a/android/src/main/java/com/tailscale/ipn/MainActivity.kt +++ b/android/src/main/java/com/tailscale/ipn/MainActivity.kt @@ -55,7 +55,6 @@ import com.tailscale.ipn.ui.view.ExitNodePicker import com.tailscale.ipn.ui.view.HealthView import com.tailscale.ipn.ui.view.IntroView import com.tailscale.ipn.ui.view.LoginQRView -import com.tailscale.ipn.ui.view.LoginWithAuthKeyView import com.tailscale.ipn.ui.view.LoginWithCustomControlURLView import com.tailscale.ipn.ui.view.MDMSettingsDebugView import com.tailscale.ipn.ui.view.MainView @@ -249,9 +248,6 @@ class MainActivity : ComponentActivity() { composable("intro", exitTransition = { fadeOut(animationSpec = tween(150)) }) { IntroView(backTo("main")) } - composable("loginWithAuthKey") { - LoginWithAuthKeyView(onNavigateHome = backTo("main"), backTo("userSwitcher")) - } composable("loginWithCustomControl") { LoginWithCustomControlURLView( onNavigateHome = backTo("main"), backTo("userSwitcher")) diff --git a/android/src/main/java/com/tailscale/ipn/ui/view/CustomLogin.kt b/android/src/main/java/com/tailscale/ipn/ui/view/CustomLogin.kt index 82d2e37d2e..c2add35d01 100644 --- a/android/src/main/java/com/tailscale/ipn/ui/view/CustomLogin.kt +++ b/android/src/main/java/com/tailscale/ipn/ui/view/CustomLogin.kt @@ -31,7 +31,6 @@ import androidx.compose.ui.unit.dp import com.tailscale.ipn.R import com.tailscale.ipn.ui.theme.listItem import com.tailscale.ipn.ui.util.set -import com.tailscale.ipn.ui.viewModel.LoginWithAuthKeyViewModel import com.tailscale.ipn.ui.viewModel.LoginWithCustomControlURLViewModel data class LoginViewStrings( @@ -69,39 +68,8 @@ fun LoginWithCustomControlURLView( LoginView( innerPadding = innerPadding, strings = strings, - onSubmitAction = { viewModel.setControlURL(it, onNavigateHome) }) - } -} - -@Composable -fun LoginWithAuthKeyView( - onNavigateHome: BackNavigation, - backToSettings: BackNavigation, - viewModel: LoginWithAuthKeyViewModel = LoginWithAuthKeyViewModel() -) { - - Scaffold( - topBar = { - Header( - R.string.add_account, - onBack = backToSettings, + onSubmitAction = {it: String, it2: String -> viewModel.setControlURL(it, it2, onNavigateHome) } ) - }) { innerPadding -> - val error by viewModel.errorDialog.collectAsState() - val strings = - LoginViewStrings( - title = stringResource(id = R.string.auth_key_title), - explanation = stringResource(id = R.string.auth_key_explanation), - inputTitle = stringResource(id = R.string.auth_key_input_title), - placeholder = stringResource(id = R.string.auth_key_placeholder), - ) - // Show the error overlay if need be - error?.let { ErrorDialog(type = it, action = { viewModel.errorDialog.set(null) }) } - - LoginView( - innerPadding = innerPadding, - strings = strings, - onSubmitAction = { viewModel.setAuthKey(it, onNavigateHome) }) } } @@ -109,10 +77,11 @@ fun LoginWithAuthKeyView( fun LoginView( innerPadding: PaddingValues = PaddingValues(16.dp), strings: LoginViewStrings, - onSubmitAction: (String) -> Unit, + onSubmitAction: (it: String, it2: String) -> Unit, ) { - var textVal by remember { mutableStateOf("") } + var textVal by remember { mutableStateOf("") } + var textVal2 by remember { mutableStateOf("") } Column( modifier = @@ -144,12 +113,33 @@ fun LoginView( ) }) + ListItem( + colors = MaterialTheme.colorScheme.listItem, + headlineContent = { Text(text = "Preauth Key") }, // TODO: clean this up + supportingContent = { + OutlinedTextField( + modifier = Modifier.fillMaxWidth(), + colors = TextFieldDefaults.colors( + focusedContainerColor = Color.Transparent, + unfocusedContainerColor = Color.Transparent, + ), + textStyle = MaterialTheme.typography.bodyMedium, + value = textVal2, + onValueChange = { textVal2 = it }, + placeholder = { + Text("Key", style = MaterialTheme.typography.bodySmall) // TODO: clean this up + }, + keyboardOptions = KeyboardOptions(capitalization = KeyboardCapitalization.None) + ) + } + ) + ListItem( colors = MaterialTheme.colorScheme.listItem, headlineContent = { Box(modifier = Modifier.fillMaxWidth()) { Button( - onClick = { onSubmitAction(textVal) }, + onClick = { onSubmitAction(textVal, textVal2) }, content = { Text(stringResource(id = R.string.add_account_short)) }) } }) diff --git a/android/src/main/java/com/tailscale/ipn/ui/view/UserSwitcherView.kt b/android/src/main/java/com/tailscale/ipn/ui/view/UserSwitcherView.kt index 6fb76a6d81..649a6006b5 100644 --- a/android/src/main/java/com/tailscale/ipn/ui/view/UserSwitcherView.kt +++ b/android/src/main/java/com/tailscale/ipn/ui/view/UserSwitcherView.kt @@ -162,12 +162,6 @@ fun FusMenu( viewModel.showHeaderMenu.set(false) }, text = stringResource(id = R.string.custom_control_menu)) - MenuItem( - onClick = { - onAuthKeyClick() - viewModel.showHeaderMenu.set(false) - }, - text = stringResource(id = R.string.auth_key_menu)) } } diff --git a/android/src/main/java/com/tailscale/ipn/ui/viewModel/CustomLoginViewModel.kt b/android/src/main/java/com/tailscale/ipn/ui/viewModel/CustomLoginViewModel.kt index ed2c581fb5..dd030d0620 100644 --- a/android/src/main/java/com/tailscale/ipn/ui/viewModel/CustomLoginViewModel.kt +++ b/android/src/main/java/com/tailscale/ipn/ui/viewModel/CustomLoginViewModel.kt @@ -14,28 +14,17 @@ open class CustomLoginViewModel : IpnViewModel() { val errorDialog: StateFlow = MutableStateFlow(null) } -class LoginWithAuthKeyViewModel : CustomLoginViewModel() { - // Sets the auth key and invokes the login flow - fun setAuthKey(authKey: String, onSuccess: () -> Unit) { - // The most basic of checks for auth key syntax - if (authKey.isEmpty()) { - errorDialog.set(ErrorDialogType.INVALID_AUTH_KEY) - return - } - loginWithAuthKey(authKey) { - it.onFailure { errorDialog.set(ErrorDialogType.ADD_PROFILE_FAILED) } - it.onSuccess { onSuccess() } - } - } -} - class LoginWithCustomControlURLViewModel : CustomLoginViewModel() { // Sets the custom control URL and invokes the login flow - fun setControlURL(urlStr: String, onSuccess: () -> Unit) { + fun setControlURL(urlStr: String, authKey: String, onSuccess: () -> Unit) { // Some basic checks that the entered URL is "reasonable". The underlying // localAPIClient will use the default server if we give it a broken URL, // but we can make sure we can construct a URL from the input string and // ensure it has an http/https scheme + if (authKey.isEmpty()) { + errorDialog.set(ErrorDialogType.INVALID_AUTH_KEY) + return + } when (urlStr.startsWith("http", ignoreCase = true) && urlStr.contains("://") && urlStr.length > 7) { @@ -44,7 +33,7 @@ class LoginWithCustomControlURLViewModel : CustomLoginViewModel() { return } true -> { - loginWithCustomControlURL(urlStr) { + loginWithCustomControlURLAuthKey(urlStr, authKey) { it.onFailure { errorDialog.set(ErrorDialogType.ADD_PROFILE_FAILED) } it.onSuccess { onSuccess() } } diff --git a/android/src/main/java/com/tailscale/ipn/ui/viewModel/IpnViewModel.kt b/android/src/main/java/com/tailscale/ipn/ui/viewModel/IpnViewModel.kt index 3baab131dc..455cc8b82e 100644 --- a/android/src/main/java/com/tailscale/ipn/ui/viewModel/IpnViewModel.kt +++ b/android/src/main/java/com/tailscale/ipn/ui/viewModel/IpnViewModel.kt @@ -192,19 +192,15 @@ open class IpnViewModel : ViewModel() { } ?: run { startAction() } } - fun loginWithAuthKey(authKey: String, completionHandler: (Result) -> Unit = {}) { - val prefs = Ipn.MaskedPrefs() - prefs.WantRunning = true - login(prefs, authKey = authKey, completionHandler) - } - - fun loginWithCustomControlURL( + fun loginWithCustomControlURLAuthKey( controlURL: String, + authKey: String, completionHandler: (Result) -> Unit = {} ) { val prefs = Ipn.MaskedPrefs() prefs.ControlURL = controlURL - login(prefs, completionHandler = completionHandler) + prefs.WantRunning = true + login(prefs, authKey = authKey, completionHandler = completionHandler) } fun logout(completionHandler: (Result) -> Unit = {}) {