From 9aa1f2ad563965b4d5120cf9862a1e8ef35adc58 Mon Sep 17 00:00:00 2001 From: Dave Finkelstein Date: Sun, 25 Jan 2026 21:01:53 +0000 Subject: [PATCH] Add password field to Android manual gateway settings --- .../main/java/com/clawdbot/android/MainViewModel.kt | 5 +++++ .../main/java/com/clawdbot/android/NodeRuntime.kt | 12 +++++++++++- .../main/java/com/clawdbot/android/SecurePrefs.kt | 10 ++++++++++ .../java/com/clawdbot/android/ui/SettingsSheet.kt | 11 +++++++++++ 4 files changed, 37 insertions(+), 1 deletion(-) diff --git a/apps/android/app/src/main/java/com/clawdbot/android/MainViewModel.kt b/apps/android/app/src/main/java/com/clawdbot/android/MainViewModel.kt index 1329f06d4..98d0c8dcd 100644 --- a/apps/android/app/src/main/java/com/clawdbot/android/MainViewModel.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/MainViewModel.kt @@ -51,6 +51,7 @@ class MainViewModel(app: Application) : AndroidViewModel(app) { val manualHost: StateFlow = runtime.manualHost val manualPort: StateFlow = runtime.manualPort val manualTls: StateFlow = runtime.manualTls + val manualPassword: StateFlow = runtime.manualPassword val canvasDebugStatusEnabled: StateFlow = runtime.canvasDebugStatusEnabled val chatSessionKey: StateFlow = runtime.chatSessionKey @@ -104,6 +105,10 @@ class MainViewModel(app: Application) : AndroidViewModel(app) { runtime.setManualTls(value) } + fun setManualPassword(value: String) { + runtime.setManualPassword(value) + } + fun setCanvasDebugStatusEnabled(value: Boolean) { runtime.setCanvasDebugStatusEnabled(value) } diff --git a/apps/android/app/src/main/java/com/clawdbot/android/NodeRuntime.kt b/apps/android/app/src/main/java/com/clawdbot/android/NodeRuntime.kt index 603e4b82b..5cf7a3448 100644 --- a/apps/android/app/src/main/java/com/clawdbot/android/NodeRuntime.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/NodeRuntime.kt @@ -284,6 +284,7 @@ class NodeRuntime(context: Context) { val manualHost: StateFlow = prefs.manualHost val manualPort: StateFlow = prefs.manualPort val manualTls: StateFlow = prefs.manualTls + val manualPassword: StateFlow = prefs.manualPassword val lastDiscoveredStableId: StateFlow = prefs.lastDiscoveredStableId val canvasDebugStatusEnabled: StateFlow = prefs.canvasDebugStatusEnabled @@ -428,6 +429,10 @@ class NodeRuntime(context: Context) { prefs.setManualTls(value) } + fun setManualPassword(value: String) { + prefs.setManualPassword(value) + } + fun setCanvasDebugStatusEnabled(value: Boolean) { prefs.setCanvasDebugStatusEnabled(value) } @@ -563,7 +568,12 @@ class NodeRuntime(context: Context) { nodeStatusText = "Connecting…" updateStatus() val token = prefs.loadGatewayToken() - val password = prefs.loadGatewayPassword() + // For manual endpoints, use the manual password if set; otherwise fall back to stored password. + val password = if (endpoint.stableId.startsWith("manual|")) { + manualPassword.value.takeIf { it.isNotEmpty() } ?: prefs.loadGatewayPassword() + } else { + prefs.loadGatewayPassword() + } val tls = resolveTlsParams(endpoint) operatorSession.connect(endpoint, token, password, buildOperatorConnectOptions(), tls) nodeSession.connect(endpoint, token, password, buildNodeConnectOptions(), tls) diff --git a/apps/android/app/src/main/java/com/clawdbot/android/SecurePrefs.kt b/apps/android/app/src/main/java/com/clawdbot/android/SecurePrefs.kt index cd6270dd5..8ddd0c5fe 100644 --- a/apps/android/app/src/main/java/com/clawdbot/android/SecurePrefs.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/SecurePrefs.kt @@ -74,6 +74,10 @@ class SecurePrefs(context: Context) { MutableStateFlow(readBoolWithMigration("gateway.manual.tls", null, true)) val manualTls: StateFlow = _manualTls + private val _manualPassword = + MutableStateFlow(prefs.getString("gateway.manual.password", null)?.trim() ?: "") + val manualPassword: StateFlow = _manualPassword + private val _lastDiscoveredStableId = MutableStateFlow( readStringWithMigration( @@ -150,6 +154,12 @@ class SecurePrefs(context: Context) { _manualTls.value = value } + fun setManualPassword(value: String) { + val trimmed = value.trim() + prefs.edit { putString("gateway.manual.password", trimmed) } + _manualPassword.value = trimmed + } + fun setCanvasDebugStatusEnabled(value: Boolean) { prefs.edit { putBoolean("canvas.debugStatusEnabled", value) } _canvasDebugStatusEnabled.value = value diff --git a/apps/android/app/src/main/java/com/clawdbot/android/ui/SettingsSheet.kt b/apps/android/app/src/main/java/com/clawdbot/android/ui/SettingsSheet.kt index e3a9b3ecb..829dfe6bd 100644 --- a/apps/android/app/src/main/java/com/clawdbot/android/ui/SettingsSheet.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/ui/SettingsSheet.kt @@ -55,6 +55,7 @@ import androidx.compose.ui.focus.onFocusChanged import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.core.content.ContextCompat @@ -82,6 +83,7 @@ fun SettingsSheet(viewModel: MainViewModel) { val manualHost by viewModel.manualHost.collectAsState() val manualPort by viewModel.manualPort.collectAsState() val manualTls by viewModel.manualTls.collectAsState() + val manualPassword by viewModel.manualPassword.collectAsState() val canvasDebugStatusEnabled by viewModel.canvasDebugStatusEnabled.collectAsState() val statusText by viewModel.statusText.collectAsState() val serverName by viewModel.serverName.collectAsState() @@ -403,6 +405,15 @@ fun SettingsSheet(viewModel: MainViewModel) { modifier = Modifier.fillMaxWidth(), enabled = manualEnabled, ) + OutlinedTextField( + value = manualPassword, + onValueChange = viewModel::setManualPassword, + label = { Text("Password") }, + modifier = Modifier.fillMaxWidth(), + enabled = manualEnabled, + visualTransformation = PasswordVisualTransformation(), + singleLine = true, + ) ListItem( headlineContent = { Text("Require TLS") }, supportingContent = { Text("Pin the gateway certificate on first connect.") },