diff --git a/apps/.i18n/native-source.json b/apps/.i18n/native-source.json index 66b344ce1c6..14bfaef5817 100644 --- a/apps/.i18n/native-source.json +++ b/apps/.i18n/native-source.json @@ -691,7 +691,7 @@ }, { "kind": "ui-call", - "line": 170, + "line": 173, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Resolution outcome unknown. Actions stay disabled until the Gateway record is verified.", "surface": "android", @@ -699,7 +699,7 @@ }, { "kind": "ui-call", - "line": 172, + "line": 175, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "The Gateway still shows this approval as pending. Review it before trying again.", "surface": "android", @@ -707,7 +707,7 @@ }, { "kind": "ui-call", - "line": 174, + "line": 177, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Could not load approval details. Refresh and try again.", "surface": "android", @@ -715,7 +715,7 @@ }, { "kind": "ui-call", - "line": 176, + "line": 179, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Could not load approvals.", "surface": "android", @@ -723,7 +723,7 @@ }, { "kind": "ui-call", - "line": 178, + "line": 181, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Could not resolve approval. Refresh and try again.", "surface": "android", @@ -731,7 +731,7 @@ }, { "kind": "ui-call", - "line": 193, + "line": 196, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Proposal applied.", "surface": "android", @@ -739,7 +739,7 @@ }, { "kind": "ui-call", - "line": 193, + "line": 196, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "apply", "surface": "android", @@ -747,7 +747,7 @@ }, { "kind": "ui-call", - "line": 194, + "line": 197, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Proposal rejected.", "surface": "android", @@ -755,7 +755,7 @@ }, { "kind": "ui-call", - "line": 194, + "line": 197, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "reject", "surface": "android", @@ -763,7 +763,7 @@ }, { "kind": "ui-call", - "line": 195, + "line": 198, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Proposal quarantined.", "surface": "android", @@ -771,7 +771,7 @@ }, { "kind": "ui-call", - "line": 195, + "line": 198, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "quarantine", "surface": "android", @@ -779,7 +779,7 @@ }, { "kind": "ui-call", - "line": 202, + "line": 205, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "unknown", "surface": "android", @@ -787,7 +787,7 @@ }, { "kind": "ui-call", - "line": 203, + "line": 206, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Gateway returned status '$statusLabel' after ${action.verb}.", "surface": "android", @@ -795,7 +795,7 @@ }, { "kind": "ui-call", - "line": 211, + "line": 214, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Could not ${action.verb} Skill Workshop proposal.", "surface": "android", @@ -803,7 +803,7 @@ }, { "kind": "ui-call", - "line": 393, + "line": 396, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Connected (node offline)", "surface": "android", @@ -811,7 +811,7 @@ }, { "kind": "ui-call", - "line": 394, + "line": 397, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Connected (operator offline)", "surface": "android", @@ -819,7 +819,7 @@ }, { "kind": "ui-call", - "line": 396, + "line": 399, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Reconnecting…", "surface": "android", @@ -827,7 +827,7 @@ }, { "kind": "ui-call", - "line": 404, + "line": 407, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Connected (operator: $operator)", "surface": "android", @@ -835,7 +835,7 @@ }, { "kind": "ui-call", - "line": 1978, + "line": 1983, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "This automation already has a queued run.", "surface": "android", @@ -843,7 +843,7 @@ }, { "kind": "ui-call", - "line": 2008, + "line": 2013, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Automation run queued.", "surface": "android", @@ -851,7 +851,7 @@ }, { "kind": "ui-call", - "line": 2008, + "line": 2013, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Automation started.", "surface": "android", @@ -859,7 +859,7 @@ }, { "kind": "ui-call", - "line": 2021, + "line": 2026, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Gateway rejected the automation run.", "surface": "android", @@ -867,7 +867,7 @@ }, { "kind": "ui-call", - "line": 2052, + "line": 2057, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Automation enabled.", "surface": "android", @@ -875,7 +875,7 @@ }, { "kind": "ui-call", - "line": 2052, + "line": 2057, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Automation paused.", "surface": "android", @@ -883,7 +883,7 @@ }, { "kind": "ui-call", - "line": 2074, + "line": 2079, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "This automation changed on the gateway. Review the latest version before saving again.", "surface": "android", @@ -891,7 +891,7 @@ }, { "kind": "ui-call", - "line": 2080, + "line": 2085, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Automation updated.", "surface": "android", @@ -899,7 +899,7 @@ }, { "kind": "ui-call", - "line": 2095, + "line": 2100, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Automation deleted.", "surface": "android", @@ -907,7 +907,7 @@ }, { "kind": "ui-call", - "line": 2300, + "line": 2305, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Node offline. Reconnect and retry.", "surface": "android", @@ -915,7 +915,7 @@ }, { "kind": "ui-named-argument-concatenated", - "line": 2311, + "line": 2316, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Restore canvas now for session=$sessionKey source=$source. If existing A2UI state exists, replay it immediately. If not, create and render a compact mobile-friendly dashboard in Canvas.", "surface": "android", @@ -923,7 +923,7 @@ }, { "kind": "ui-call", - "line": 2332, + "line": 2337, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Failed to request restore. Tap to retry.", "surface": "android", @@ -931,7 +931,7 @@ }, { "kind": "ui-call", - "line": 2343, + "line": 2348, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "No canvas update yet. Tap to retry.", "surface": "android", @@ -939,7 +939,7 @@ }, { "kind": "ui-call", - "line": 3301, + "line": 3306, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Connect to a Gateway to save wake words", "surface": "android", @@ -947,7 +947,7 @@ }, { "kind": "ui-call", - "line": 3329, + "line": 3334, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Wake words saved", "surface": "android", @@ -955,7 +955,7 @@ }, { "kind": "ui-call", - "line": 3338, + "line": 3343, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Could not save wake words", "surface": "android", @@ -963,7 +963,7 @@ }, { "kind": "ui-call", - "line": 4031, + "line": 4057, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Failed: no secure gateway endpoint was detected. Enable gateway TLS or Tailscale Serve, or use a trusted private LAN address with Unencrypted selected.", "surface": "android", @@ -971,7 +971,7 @@ }, { "kind": "ui-call", - "line": 4035, + "line": 4061, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Failed: secure endpoint reached, but TLS fingerprint verification timed out. Check Tailscale Serve or gateway TLS and retry.", "surface": "android", @@ -979,7 +979,7 @@ }, { "kind": "ui-call", - "line": 4039, + "line": 4065, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Failed: couldn't reach the secure gateway endpoint for this host.", "surface": "android", @@ -987,7 +987,7 @@ }, { "kind": "ui-named-argument", - "line": 4083, + "line": 4109, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Connecting…", "surface": "android", @@ -995,7 +995,7 @@ }, { "kind": "ui-named-argument", - "line": 4266, + "line": 4292, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Offline", "surface": "android", @@ -1003,7 +1003,7 @@ }, { "kind": "ui-call", - "line": 5000, + "line": 5026, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Could not load provider catalog.", "surface": "android", @@ -1011,7 +1011,7 @@ }, { "kind": "ui-call", - "line": 5031, + "line": 5057, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Update your Gateway to view provider model config.", "surface": "android", @@ -1019,7 +1019,7 @@ }, { "kind": "ui-call", - "line": 5033, + "line": 5059, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Could not load provider model config.", "surface": "android", @@ -1027,7 +1027,7 @@ }, { "kind": "ui-call", - "line": 5049, + "line": 5075, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Provider models loaded, but readiness is unavailable.", "surface": "android", @@ -1035,7 +1035,7 @@ }, { "kind": "ui-call", - "line": 5136, + "line": 5162, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Could not load automations.", "surface": "android", @@ -1043,7 +1043,7 @@ }, { "kind": "ui-call", - "line": 5222, + "line": 5248, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Connect the gateway to inspect automations.", "surface": "android", @@ -1051,7 +1051,7 @@ }, { "kind": "ui-call", - "line": 5232, + "line": 5258, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Gateway returned an invalid automation.", "surface": "android", @@ -1059,7 +1059,7 @@ }, { "kind": "ui-call", - "line": 5236, + "line": 5262, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Could not load automation.", "surface": "android", @@ -1067,7 +1067,7 @@ }, { "kind": "ui-call", - "line": 5248, + "line": 5274, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Connect the gateway to inspect automation run history.", "surface": "android", @@ -1075,7 +1075,7 @@ }, { "kind": "ui-call", - "line": 5279, + "line": 5305, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Could not load automation run history.", "surface": "android", @@ -1083,7 +1083,7 @@ }, { "kind": "ui-call", - "line": 5296, + "line": 5322, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Cron changes require operator.admin access.", "surface": "android", @@ -1091,7 +1091,7 @@ }, { "kind": "ui-call", - "line": 5305, + "line": 5331, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Connect the gateway to manage automations.", "surface": "android", @@ -1099,7 +1099,7 @@ }, { "kind": "ui-call", - "line": 5317, + "line": 5343, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Another cron action is still finishing.", "surface": "android", @@ -1107,7 +1107,7 @@ }, { "kind": "ui-call", - "line": 5364, + "line": 5390, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Cron action failed.", "surface": "android", @@ -1115,7 +1115,7 @@ }, { "kind": "ui-call", - "line": 5491, + "line": 5517, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Could not load usage.", "surface": "android", @@ -1123,7 +1123,7 @@ }, { "kind": "ui-call", - "line": 5526, + "line": 5552, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Could not load skills.", "surface": "android", @@ -1131,7 +1131,7 @@ }, { "kind": "ui-call", - "line": 5539, + "line": 5565, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Connect the gateway to update skills.", "surface": "android", @@ -1139,7 +1139,7 @@ }, { "kind": "ui-call", - "line": 5543, + "line": 5569, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "This gateway connection needs operator.admin to update skills.", "surface": "android", @@ -1147,7 +1147,7 @@ }, { "kind": "conditional-branch", - "line": 5558, + "line": 5584, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Could not disable skill.", "surface": "android", @@ -1155,7 +1155,7 @@ }, { "kind": "conditional-branch", - "line": 5558, + "line": 5584, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Could not enable skill.", "surface": "android", @@ -1163,7 +1163,7 @@ }, { "kind": "ui-call", - "line": 5576, + "line": 5602, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Connect the gateway to search ClawHub skills.", "surface": "android", @@ -1171,7 +1171,7 @@ }, { "kind": "ui-call", - "line": 5622, + "line": 5648, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Could not search ClawHub skills.", "surface": "android", @@ -1179,7 +1179,7 @@ }, { "kind": "ui-call", - "line": 5635, + "line": 5661, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Connect the gateway to inspect ClawHub skills.", "surface": "android", @@ -1187,7 +1187,7 @@ }, { "kind": "conditional-branch", - "line": 5668, + "line": 5694, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "ClawHub did not return an installable version for ${skill.slug}.", "surface": "android", @@ -1195,7 +1195,7 @@ }, { "kind": "ui-call", - "line": 5684, + "line": 5710, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Could not load ClawHub details for ${skill.slug}.", "surface": "android", @@ -1203,7 +1203,7 @@ }, { "kind": "ui-call", - "line": 5700, + "line": 5726, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Connect the gateway to install ClawHub skills.", "surface": "android", @@ -1211,7 +1211,7 @@ }, { "kind": "ui-call", - "line": 5716, + "line": 5742, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "This gateway connection needs operator.admin to install ClawHub skills.", "surface": "android", @@ -1219,7 +1219,7 @@ }, { "kind": "conditional-branch", - "line": 5806, + "line": 5832, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Installed $slug.", "surface": "android", @@ -1227,7 +1227,7 @@ }, { "kind": "ui-call", - "line": 5813, + "line": 5839, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Could not install ${slug} from ClawHub.", "surface": "android", @@ -1235,7 +1235,7 @@ }, { "kind": "ui-call", - "line": 5853, + "line": 5879, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Connect the gateway to load Skill Workshop proposals.", "surface": "android", @@ -1243,7 +1243,7 @@ }, { "kind": "ui-call", - "line": 5893, + "line": 5919, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Could not load Skill Workshop proposals.", "surface": "android", @@ -1251,7 +1251,7 @@ }, { "kind": "ui-call", - "line": 5913, + "line": 5939, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Connect the gateway to inspect Skill Workshop proposals.", "surface": "android", @@ -1259,7 +1259,7 @@ }, { "kind": "ui-call", - "line": 5965, + "line": 5991, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Could not inspect Skill Workshop proposal.", "surface": "android", @@ -1267,7 +1267,7 @@ }, { "kind": "ui-call", - "line": 5985, + "line": 6011, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Skill Workshop proposal actions require operator.admin scope.", "surface": "android", @@ -1275,7 +1275,7 @@ }, { "kind": "ui-call", - "line": 5990, + "line": 6016, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Connect the gateway to update Skill Workshop proposals.", "surface": "android", @@ -1283,7 +1283,7 @@ }, { "kind": "ui-named-argument", - "line": 6149, + "line": 6175, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Connected", "surface": "android", @@ -1291,7 +1291,7 @@ }, { "kind": "ui-call", - "line": 6175, + "line": 6201, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Could not load nodes and devices.", "surface": "android", @@ -1299,7 +1299,7 @@ }, { "kind": "ui-call", - "line": 6833, + "line": 6859, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Could not load channels.", "surface": "android", @@ -1307,7 +1307,7 @@ }, { "kind": "ui-call", - "line": 6863, + "line": 6889, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Could not load dreaming.", "surface": "android", @@ -1315,7 +1315,7 @@ }, { "kind": "ui-call", - "line": 6900, + "line": 6926, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Could not load gateway logs.", "surface": "android", @@ -1323,7 +1323,7 @@ }, { "kind": "ui-call", - "line": 7357, + "line": 7383, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "One time", "surface": "android", @@ -1331,7 +1331,7 @@ }, { "kind": "ui-call", - "line": 7366, + "line": 7392, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Cron", "surface": "android", @@ -1339,7 +1339,7 @@ }, { "kind": "ui-call", - "line": 7367, + "line": 7393, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Scheduled", "surface": "android", @@ -1347,7 +1347,7 @@ }, { "kind": "ui-call", - "line": 7375, + "line": 7401, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Every ${days}d", "surface": "android", @@ -1355,7 +1355,7 @@ }, { "kind": "ui-call", - "line": 7376, + "line": 7402, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Every ${hours}h", "surface": "android", @@ -1363,7 +1363,7 @@ }, { "kind": "ui-call", - "line": 7377, + "line": 7403, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Every ${minutes}m", "surface": "android", @@ -1371,7 +1371,7 @@ }, { "kind": "ui-call", - "line": 7378, + "line": 7404, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Repeating", "surface": "android", @@ -1379,7 +1379,7 @@ }, { "kind": "ui-call", - "line": 7394, + "line": 7420, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "No prompt", "surface": "android", @@ -1387,7 +1387,7 @@ }, { "kind": "ui-call", - "line": 7411, + "line": 7437, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Gateway", "surface": "android", @@ -1395,7 +1395,7 @@ }, { "kind": "ui-call", - "line": 7419, + "line": 7445, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Connected to $gatewayLabel", "surface": "android", @@ -1403,7 +1403,7 @@ }, { "kind": "ui-call", - "line": 7420, + "line": 7446, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Your agents are ready", "surface": "android", @@ -1411,7 +1411,7 @@ }, { "kind": "ui-call", - "line": 7422, + "line": 7448, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "This phone stays dormant until the gateway needs it, then wakes, syncs, and goes back to sleep.", "surface": "android", @@ -1419,7 +1419,7 @@ }, { "kind": "ui-call", - "line": 7426, + "line": 7452, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Selected on this phone", "surface": "android", @@ -1427,7 +1427,7 @@ }, { "kind": "ui-call", - "line": 7429, + "line": 7455, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "The overview refreshes on reconnect and when this screen opens.", "surface": "android", @@ -1435,7 +1435,7 @@ }, { "kind": "ui-call", - "line": 7434, + "line": 7460, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Reconnecting", "surface": "android", @@ -1443,7 +1443,7 @@ }, { "kind": "ui-call", - "line": 7435, + "line": 7461, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "OpenClaw is syncing back up", "surface": "android", @@ -1451,7 +1451,7 @@ }, { "kind": "ui-call", - "line": 7437, + "line": 7463, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "The gateway session is coming back online. Agent shortcuts should settle automatically in a moment.", "surface": "android", @@ -1459,7 +1459,7 @@ }, { "kind": "ui-call", - "line": 7441, + "line": 7467, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Gateway session in progress", "surface": "android", @@ -1467,7 +1467,7 @@ }, { "kind": "ui-call", - "line": 7444, + "line": 7470, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "If the gateway is reachable, reconnect should complete without intervention.", "surface": "android", @@ -1475,7 +1475,7 @@ }, { "kind": "ui-call", - "line": 7449, + "line": 7475, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Welcome to OpenClaw", "surface": "android", @@ -1483,7 +1483,7 @@ }, { "kind": "ui-call", - "line": 7450, + "line": 7476, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Your phone stays quiet until it is needed", "surface": "android", @@ -1491,7 +1491,7 @@ }, { "kind": "ui-call", - "line": 7452, + "line": 7478, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Pair this device to your gateway to wake it only for real work, keep a live agent overview handy, and avoid battery-draining background loops.", "surface": "android", @@ -1499,7 +1499,7 @@ }, { "kind": "ui-call", - "line": 7456, + "line": 7482, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Connect to load your agents", "surface": "android", @@ -1507,7 +1507,7 @@ }, { "kind": "ui-call", - "line": 7459, + "line": 7485, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "When connected, the gateway can wake the phone with a silent push instead of holding an always-on session.", "surface": "android", @@ -1515,7 +1515,7 @@ }, { "kind": "ui-call", - "line": 7491, + "line": 7517, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Main", "surface": "android", @@ -1523,7 +1523,7 @@ }, { "kind": "ui-call", - "line": 7506, + "line": 7532, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Active on this phone", "surface": "android", @@ -1531,7 +1531,7 @@ }, { "kind": "ui-call", - "line": 7507, + "line": 7533, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Default agent", "surface": "android", @@ -1539,7 +1539,7 @@ }, { "kind": "ui-call", - "line": 7508, + "line": 7534, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Ready", "surface": "android", @@ -1547,7 +1547,7 @@ }, { "kind": "ui-call", - "line": 8067, + "line": 8093, "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt", "source": "Dream", "surface": "android", @@ -4099,7 +4099,7 @@ }, { "kind": "ui-call", - "line": 270, + "line": 272, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Enter the setup code from openclaw qr.", "surface": "android", @@ -4107,7 +4107,7 @@ }, { "kind": "ui-call", - "line": 271, + "line": 273, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Setup code was not accepted. Generate a fresh code with openclaw qr.", "surface": "android", @@ -4115,7 +4115,7 @@ }, { "kind": "ui-call", - "line": 273, + "line": 275, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "That QR code is not an OpenClaw setup QR. Generate a fresh code with openclaw qr, then try again.", "surface": "android", @@ -4123,7 +4123,7 @@ }, { "kind": "ui-call", - "line": 275, + "line": 277, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "That looks like a setup code. Go back and choose Setup Gateway, then Use setup code.", "surface": "android", @@ -4131,7 +4131,7 @@ }, { "kind": "ui-call", - "line": 277, + "line": 279, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Could not read that image. Choose a clear screenshot or image of the QR from openclaw qr.", "surface": "android", @@ -4139,7 +4139,7 @@ }, { "kind": "ui-call", - "line": 279, + "line": 281, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "No setup QR code was found in that image. Choose the QR generated by openclaw qr, or enter the setup code manually.", "surface": "android", @@ -4147,7 +4147,7 @@ }, { "kind": "ui-call", - "line": 281, + "line": 283, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Could not read a QR code from that image. Choose a clearer image or enter the setup code manually.", "surface": "android", @@ -4155,7 +4155,7 @@ }, { "kind": "ui-call", - "line": 283, + "line": 285, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Could not start the camera. Choose a QR image from gallery or enter the setup code manually.", "surface": "android", @@ -4163,7 +4163,31 @@ }, { "kind": "ui-call", - "line": 838, + "line": 832, + "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "surface": "android", + "id": "native.android.7a18be21a62739bf" + }, + { + "kind": "ui-call", + "line": 852, + "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", + "source": "This gateway now presents a certificate trusted by this device.", + "surface": "android", + "id": "native.android.aa489429ad39aa39" + }, + { + "kind": "ui-call", + "line": 862, + "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", + "source": "SHA-256 fingerprint", + "surface": "android", + "id": "native.android.b3db82f1162808ad" + }, + { + "kind": "ui-call", + "line": 875, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Trust", "surface": "android", @@ -4171,7 +4195,15 @@ }, { "kind": "ui-call", - "line": 843, + "line": 882, + "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", + "source": "Use system trust", + "surface": "android", + "id": "native.android.09245320d3878458" + }, + { + "kind": "ui-call", + "line": 886, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Cancel", "surface": "android", @@ -4179,7 +4211,7 @@ }, { "kind": "ui-call", - "line": 1038, + "line": 1082, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Welcome to OpenClaw", "surface": "android", @@ -4187,7 +4219,7 @@ }, { "kind": "ui-call", - "line": 1039, + "line": 1083, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Turn this device into a secure OpenClaw node for chat, voice, camera, and device tools.", "surface": "android", @@ -4195,7 +4227,7 @@ }, { "kind": "ui-call", - "line": 1070, + "line": 1114, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "OpenClaw logo", "surface": "android", @@ -4203,7 +4235,7 @@ }, { "kind": "ui-call", - "line": 1129, + "line": 1173, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Connect to your Gateway", "surface": "android", @@ -4211,7 +4243,7 @@ }, { "kind": "ui-call", - "line": 1130, + "line": 1174, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Choose device permissions", "surface": "android", @@ -4219,7 +4251,7 @@ }, { "kind": "ui-call", - "line": 1131, + "line": 1175, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Use OpenClaw from your phone", "surface": "android", @@ -4227,7 +4259,7 @@ }, { "kind": "ui-call", - "line": 1153, + "line": 1197, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Security notice", "surface": "android", @@ -4235,7 +4267,7 @@ }, { "kind": "ui-call", - "line": 1155, + "line": 1199, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "The connected OpenClaw agent can use device capabilities you enable. Continue only if you trust the Gateway and agent you connect to.", "surface": "android", @@ -4243,7 +4275,7 @@ }, { "kind": "ui-call", - "line": 1196, + "line": 1240, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Connect Gateway", "surface": "android", @@ -4251,7 +4283,7 @@ }, { "kind": "ui-call", - "line": 1197, + "line": 1241, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Scan a QR code or use the setup code from your OpenClaw Gateway.", "surface": "android", @@ -4259,7 +4291,7 @@ }, { "kind": "ui-call", - "line": 1206, + "line": 1250, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Could not open setup guide.", "surface": "android", @@ -4267,7 +4299,7 @@ }, { "kind": "ui-call", - "line": 1214, + "line": 1258, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Scan QR or setup code", "surface": "android", @@ -4275,7 +4307,7 @@ }, { "kind": "ui-call", - "line": 1220, + "line": 1264, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Set up manually", "surface": "android", @@ -4283,7 +4315,7 @@ }, { "kind": "ui-call", - "line": 1242, + "line": 1286, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Before you start", "surface": "android", @@ -4291,7 +4323,7 @@ }, { "kind": "ui-call", - "line": 1248, + "line": 1292, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Access to the Gateway device", "surface": "android", @@ -4299,7 +4331,7 @@ }, { "kind": "ui-call", - "line": 1249, + "line": 1293, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Have a terminal open on the device running OpenClaw.", "surface": "android", @@ -4307,7 +4339,7 @@ }, { "kind": "ui-call", - "line": 1252, + "line": 1296, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Phone can reach the Gateway", "surface": "android", @@ -4315,7 +4347,7 @@ }, { "kind": "ui-call", - "line": 1253, + "line": 1297, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Use the same network, or a secure remote Gateway URL.", "surface": "android", @@ -4323,7 +4355,7 @@ }, { "kind": "ui-call", - "line": 1259, + "line": 1303, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Android setup guide", "surface": "android", @@ -4331,7 +4363,7 @@ }, { "kind": "ui-call", - "line": 1302, + "line": 1346, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Setup Gateway", "surface": "android", @@ -4339,7 +4371,7 @@ }, { "kind": "ui-call", - "line": 1307, + "line": 1351, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Step 1", "surface": "android", @@ -4347,7 +4379,7 @@ }, { "kind": "ui-call", - "line": 1308, + "line": 1352, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Start your Gateway.", "surface": "android", @@ -4355,7 +4387,7 @@ }, { "kind": "ui-named-argument", - "line": 1309, + "line": 1353, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "openclaw gateway", "surface": "android", @@ -4363,7 +4395,7 @@ }, { "kind": "ui-call", - "line": 1313, + "line": 1357, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Step 2", "surface": "android", @@ -4371,7 +4403,7 @@ }, { "kind": "ui-call", - "line": 1314, + "line": 1358, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Generate a QR code.", "surface": "android", @@ -4379,7 +4411,7 @@ }, { "kind": "ui-named-argument", - "line": 1315, + "line": 1359, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "openclaw qr", "surface": "android", @@ -4387,7 +4419,7 @@ }, { "kind": "ui-call", - "line": 1338, + "line": 1382, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Choose from gallery", "surface": "android", @@ -4395,7 +4427,7 @@ }, { "kind": "ui-call", - "line": 1393, + "line": 1437, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "QR code not accepted", "surface": "android", @@ -4403,7 +4435,7 @@ }, { "kind": "ui-call", - "line": 1412, + "line": 1456, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Choose another image", "surface": "android", @@ -4411,7 +4443,7 @@ }, { "kind": "ui-call", - "line": 1465, + "line": 1509, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Scan QR code", "surface": "android", @@ -4419,7 +4451,7 @@ }, { "kind": "ui-call", - "line": 1467, + "line": 1511, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Open the camera and frame the code from openclaw qr.", "surface": "android", @@ -4427,7 +4459,7 @@ }, { "kind": "ui-call", - "line": 1501, + "line": 1545, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Align the QR code inside the square.", "surface": "android", @@ -4435,7 +4467,7 @@ }, { "kind": "ui-call", - "line": 1519, + "line": 1563, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Camera access is needed to scan the setup QR.", "surface": "android", @@ -4443,7 +4475,7 @@ }, { "kind": "ui-call", - "line": 1524, + "line": 1568, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Allow camera", "surface": "android", @@ -4451,7 +4483,7 @@ }, { "kind": "ui-call", - "line": 1545, + "line": 1589, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Close scanner", "surface": "android", @@ -4459,7 +4491,7 @@ }, { "kind": "ui-call", - "line": 1708, + "line": 1752, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Enter setup code", "surface": "android", @@ -4467,7 +4499,7 @@ }, { "kind": "ui-call", - "line": 1714, + "line": 1758, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Setup code", "surface": "android", @@ -4475,7 +4507,7 @@ }, { "kind": "ui-call", - "line": 1718, + "line": 1762, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Paste setup code", "surface": "android", @@ -4483,7 +4515,7 @@ }, { "kind": "ui-call", - "line": 1726, + "line": 1770, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Use setup code", "surface": "android", @@ -4491,7 +4523,7 @@ }, { "kind": "ui-call", - "line": 1766, + "line": 1810, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Manual setup", "surface": "android", @@ -4499,7 +4531,7 @@ }, { "kind": "ui-call", - "line": 1769, + "line": 1813, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Gateway URL", "surface": "android", @@ -4507,7 +4539,7 @@ }, { "kind": "ui-call", - "line": 1778, + "line": 1822, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Host", "surface": "android", @@ -4515,7 +4547,7 @@ }, { "kind": "ui-call", - "line": 1779, + "line": 1823, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Port", "surface": "android", @@ -4523,7 +4555,7 @@ }, { "kind": "ui-call", - "line": 1784, + "line": 1828, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Use the Gateway computer's LAN address or secure remote hostname.", "surface": "android", @@ -4531,7 +4563,7 @@ }, { "kind": "ui-call", - "line": 1791, + "line": 1835, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Token", "surface": "android", @@ -4539,7 +4571,7 @@ }, { "kind": "ui-call", - "line": 1792, + "line": 1836, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Paste token", "surface": "android", @@ -4547,7 +4579,7 @@ }, { "kind": "ui-call", - "line": 1794, + "line": 1838, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Paste a shared Gateway token or operator-issued token.", "surface": "android", @@ -4555,7 +4587,7 @@ }, { "kind": "ui-call", - "line": 1801, + "line": 1845, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Password", "surface": "android", @@ -4563,7 +4595,7 @@ }, { "kind": "ui-call", - "line": 1802, + "line": 1846, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Password optional", "surface": "android", @@ -4571,7 +4603,7 @@ }, { "kind": "ui-call", - "line": 1806, + "line": 1850, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Connection security", "surface": "android", @@ -4579,7 +4611,7 @@ }, { "kind": "ui-call", - "line": 1828, + "line": 1872, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Unencrypted", "surface": "android", @@ -4587,7 +4619,7 @@ }, { "kind": "ui-call", - "line": 1834, + "line": 1878, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Secure (TLS)", "surface": "android", @@ -4595,7 +4627,7 @@ }, { "kind": "ui-call", - "line": 1857, + "line": 1901, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Could not test connection", "surface": "android", @@ -4603,7 +4635,7 @@ }, { "kind": "ui-call", - "line": 1862, + "line": 1906, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Test connection", "surface": "android", @@ -4611,7 +4643,7 @@ }, { "kind": "ui-call", - "line": 1949, + "line": 1993, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Setup code was not accepted", "surface": "android", @@ -4619,7 +4651,7 @@ }, { "kind": "ui-call", - "line": 1955, + "line": 1999, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Your phone is paired with ${recoveryGatewayName(serverName = serverName, attemptedGatewayName = attemptedGatewayName)}. Continue to finish node access.", "surface": "android", @@ -4627,7 +4659,7 @@ }, { "kind": "ui-call", - "line": 2007, + "line": 2051, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Gateway paired", "surface": "android", @@ -4635,7 +4667,7 @@ }, { "kind": "ui-call", - "line": 2008, + "line": 2052, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Pair Gateway", "surface": "android", @@ -4643,7 +4675,7 @@ }, { "kind": "ui-call", - "line": 2060, + "line": 2104, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "View details", "surface": "android", @@ -4651,7 +4683,7 @@ }, { "kind": "ui-call", - "line": 2093, + "line": 2137, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Connection details", "surface": "android", @@ -4659,7 +4691,7 @@ }, { "kind": "ui-call", - "line": 2105, + "line": 2149, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Copy", "surface": "android", @@ -4667,7 +4699,7 @@ }, { "kind": "ui-call", - "line": 2110, + "line": 2154, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Close", "surface": "android", @@ -4675,7 +4707,7 @@ }, { "kind": "ui-call", - "line": 2122, + "line": 2166, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Details copied", "surface": "android", @@ -4683,7 +4715,7 @@ }, { "kind": "ui-call", - "line": 2167, + "line": 2211, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Approve node access", "surface": "android", @@ -4691,7 +4723,7 @@ }, { "kind": "ui-call", - "line": 2174, + "line": 2218, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Gateway pairing is complete. Approve this phone as a node so OpenClaw can use the device capabilities you enable.", "surface": "android", @@ -4699,7 +4731,7 @@ }, { "kind": "ui-call", - "line": 2182, + "line": 2226, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "On the Gateway computer, run:", "surface": "android", @@ -4707,7 +4739,7 @@ }, { "kind": "ui-call", - "line": 2191, + "line": 2235, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Use the requestId from the pending command in the approve command.", "surface": "android", @@ -4715,7 +4747,7 @@ }, { "kind": "ui-call", - "line": 2202, + "line": 2246, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "I have approved", "surface": "android", @@ -4723,7 +4755,7 @@ }, { "kind": "ui-call", - "line": 2203, + "line": 2247, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Checking approval…", "surface": "android", @@ -4731,7 +4763,7 @@ }, { "kind": "ui-call", - "line": 2215, + "line": 2259, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Still waiting for approval", "surface": "android", @@ -4739,7 +4771,7 @@ }, { "kind": "ui-call", - "line": 2218, + "line": 2262, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Run the approve command on the Gateway computer, then check again.", "surface": "android", @@ -4747,7 +4779,7 @@ }, { "kind": "ui-call", - "line": 2225, + "line": 2269, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "OK", "surface": "android", @@ -4755,7 +4787,7 @@ }, { "kind": "ui-call", - "line": 2375, + "line": 2419, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Copy approval command", "surface": "android", @@ -4763,7 +4795,7 @@ }, { "kind": "ui-call", - "line": 2406, + "line": 2450, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Only enable access you are comfortable letting OpenClaw use while this phone is connected. You can change these later in Android Settings.", "surface": "android", @@ -4771,7 +4803,7 @@ }, { "kind": "ui-call", - "line": 2445, + "line": 2489, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Back", "surface": "android", @@ -4779,7 +4811,7 @@ }, { "kind": "ui-call", - "line": 2496, + "line": 2540, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Permissions", "surface": "android", @@ -4787,7 +4819,7 @@ }, { "kind": "ui-call", - "line": 2557, + "line": 2601, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Connected", "surface": "android", @@ -4795,7 +4827,7 @@ }, { "kind": "ui-call", - "line": 2558, + "line": 2602, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Your Gateway is ready.", "surface": "android", @@ -4803,7 +4835,7 @@ }, { "kind": "ui-call", - "line": 2562, + "line": 2606, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Approve this phone on the gateway.\nThen retry the connection.", "surface": "android", @@ -4811,7 +4843,7 @@ }, { "kind": "ui-call", - "line": 2565, + "line": 2609, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Node Approval Pending", "surface": "android", @@ -4819,7 +4851,7 @@ }, { "kind": "ui-call", - "line": 2566, + "line": 2610, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Gateway pairing worked.\nApprove this phone's node capabilities from an operator UI.", "surface": "android", @@ -4827,7 +4859,7 @@ }, { "kind": "ui-call", - "line": 2569, + "line": 2613, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Pairing Gateway", "surface": "android", @@ -4835,7 +4867,7 @@ }, { "kind": "ui-call", - "line": 2570, + "line": 2614, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Approval is in progress.\nOpenClaw will reconnect automatically.", "surface": "android", @@ -4843,7 +4875,7 @@ }, { "kind": "ui-call", - "line": 2573, + "line": 2617, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Connecting Gateway", "surface": "android", @@ -4851,7 +4883,7 @@ }, { "kind": "ui-call", - "line": 2574, + "line": 2618, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "OpenClaw is checking gateway and node access.", "surface": "android", @@ -4859,7 +4891,7 @@ }, { "kind": "ui-call", - "line": 2577, + "line": 2621, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Still connecting", "surface": "android", @@ -4867,7 +4899,7 @@ }, { "kind": "ui-call", - "line": 2578, + "line": 2622, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "This is taking longer than expected.\nCheck that the Gateway is running and reachable.", "surface": "android", @@ -4875,7 +4907,7 @@ }, { "kind": "ui-call", - "line": 2581, + "line": 2625, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Connection issue", "surface": "android", @@ -4883,7 +4915,7 @@ }, { "kind": "ui-call", - "line": 2582, + "line": 2626, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "We could not reach your Gateway.\nLet's fix this.", "surface": "android", @@ -4891,7 +4923,7 @@ }, { "kind": "ui-call", - "line": 2590, + "line": 2634, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Continue", "surface": "android", @@ -4899,7 +4931,7 @@ }, { "kind": "ui-call", - "line": 2591, + "line": 2635, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Retry connection", "surface": "android", @@ -4907,7 +4939,7 @@ }, { "kind": "ui-call", - "line": 2592, + "line": 2636, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Go back", "surface": "android", @@ -4915,7 +4947,7 @@ }, { "kind": "ui-call", - "line": 2688, + "line": 2732, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Gateway received this phone", "surface": "android", @@ -4923,7 +4955,7 @@ }, { "kind": "ui-call", - "line": 2689, + "line": 2733, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Waiting for device approval", "surface": "android", @@ -4931,7 +4963,7 @@ }, { "kind": "ui-call", - "line": 2690, + "line": 2734, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Retrying automatically", "surface": "android", @@ -4939,7 +4971,7 @@ }, { "kind": "ui-call", - "line": 2694, + "line": 2738, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Gateway needs device approval", "surface": "android", @@ -4947,7 +4979,7 @@ }, { "kind": "ui-call", - "line": 2695, + "line": 2739, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Run the approval command on the Gateway", "surface": "android", @@ -4955,7 +4987,7 @@ }, { "kind": "ui-call", - "line": 2711, + "line": 2755, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Opening Gateway connection", "surface": "android", @@ -4963,7 +4995,7 @@ }, { "kind": "ui-call", - "line": 2720, + "line": 2764, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Checking pairing access", "surface": "android", @@ -4971,7 +5003,7 @@ }, { "kind": "ui-call", - "line": 2728, + "line": 2772, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Checking node access", "surface": "android", @@ -4979,7 +5011,7 @@ }, { "kind": "ui-call", - "line": 2797, + "line": 2841, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Ready for chat and voice", "surface": "android", @@ -4987,7 +5019,7 @@ }, { "kind": "ui-call", - "line": 2799, + "line": 2843, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Gateway paired. Waiting for node capability approval.", "surface": "android", @@ -4995,7 +5027,7 @@ }, { "kind": "ui-call", - "line": 2802, + "line": 2846, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Gateway approval is pending. Run this on the gateway host:", "surface": "android", @@ -5003,7 +5035,7 @@ }, { "kind": "ui-call", - "line": 2803, + "line": 2847, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Gateway approval is pending. Run openclaw devices list on the gateway host, approve this phone, then retry.", "surface": "android", @@ -5011,7 +5043,7 @@ }, { "kind": "ui-call", - "line": 2811, + "line": 2855, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Gateway paired. Checking node capability approval.", "surface": "android", @@ -5019,7 +5051,7 @@ }, { "kind": "ui-call", - "line": 2813, + "line": 2857, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Gateway paired. Waiting for operator access.", "surface": "android", @@ -5027,7 +5059,7 @@ }, { "kind": "ui-call", - "line": 2815, + "line": 2859, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Gateway approval is in progress. OpenClaw will retry automatically.", "surface": "android", @@ -5035,7 +5067,7 @@ }, { "kind": "ui-call", - "line": 2817, + "line": 2861, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Gateway unreachable", "surface": "android", @@ -5043,7 +5075,7 @@ }, { "kind": "ui-call", - "line": 2823, + "line": 2867, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "The code may have expired or been generated for another Gateway.", "surface": "android", @@ -5051,7 +5083,7 @@ }, { "kind": "ui-call", - "line": 2827, + "line": 2871, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Gateway password is required. Enter it again or edit this connection.", "surface": "android", @@ -5059,7 +5091,7 @@ }, { "kind": "ui-call", - "line": 2828, + "line": 2872, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Gateway password is invalid. Re-enter it or reset this gateway connection.", "surface": "android", @@ -5067,7 +5099,7 @@ }, { "kind": "ui-call", - "line": 2829, + "line": 2873, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Gateway token is required. Enter it again or edit this connection.", "surface": "android", @@ -5075,7 +5107,7 @@ }, { "kind": "ui-call", - "line": 2832, + "line": 2876, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Gateway requires this device identity. Re-authenticate or reset this gateway connection.", "surface": "android", @@ -5083,7 +5115,7 @@ }, { "kind": "ui-call", - "line": 2835, + "line": 2879, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Saved authentication is invalid. Re-authenticate or reset this gateway connection.", "surface": "android", @@ -5091,7 +5123,7 @@ }, { "kind": "ui-call", - "line": 2836, + "line": 2880, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Gateway authentication is not configured. Edit this connection and try again.", "surface": "android", @@ -5099,7 +5131,7 @@ }, { "kind": "ui-call", - "line": 2837, + "line": 2881, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Gateway authentication needs review. Check gateway settings, then retry.", "surface": "android", @@ -5107,7 +5139,7 @@ }, { "kind": "ui-call", - "line": 2838, + "line": 2882, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Gateway authentication needs attention.", "surface": "android", @@ -5115,7 +5147,7 @@ }, { "kind": "ui-call", - "line": 2849, + "line": 2893, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "This app is older than the Gateway. Update OpenClaw on this device, then retry.", "surface": "android", @@ -5123,7 +5155,7 @@ }, { "kind": "ui-call", - "line": 2851, + "line": 2895, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "The Gateway is older than this app. Update OpenClaw on the Gateway host, then retry.", "surface": "android", @@ -5131,7 +5163,7 @@ }, { "kind": "ui-call", - "line": 2852, + "line": 2896, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "The app and Gateway use incompatible protocol versions. Update OpenClaw on both, then retry.", "surface": "android", @@ -5139,7 +5171,7 @@ }, { "kind": "ui-call", - "line": 2854, + "line": 2898, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "$summary $details", "surface": "android", @@ -5147,7 +5179,7 @@ }, { "kind": "conditional-branch", - "line": 2889, + "line": 2933, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "openclaw devices approve $requestId", "surface": "android", @@ -5155,7 +5187,7 @@ }, { "kind": "conditional-branch", - "line": 2891, + "line": 2935, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "openclaw devices list", "surface": "android", @@ -5163,7 +5195,7 @@ }, { "kind": "conditional-branch", - "line": 2898, + "line": 2942, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "openclaw nodes approve $requestId", "surface": "android", @@ -5171,7 +5203,7 @@ }, { "kind": "conditional-branch", - "line": 2900, + "line": 2944, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "openclaw nodes approve REQUEST_ID", "surface": "android", @@ -5179,7 +5211,7 @@ }, { "kind": "ui-call", - "line": 2985, + "line": 3029, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Approval command copied", "surface": "android", @@ -5187,7 +5219,7 @@ }, { "kind": "ui-call", - "line": 2994, + "line": 3038, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Command copied", "surface": "android", @@ -5195,7 +5227,7 @@ }, { "kind": "ui-call", - "line": 3061, + "line": 3105, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Enabled", "surface": "android", @@ -5203,7 +5235,7 @@ }, { "kind": "ui-call", - "line": 3062, + "line": 3106, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Off", "surface": "android", @@ -5211,7 +5243,7 @@ }, { "kind": "ui-call", - "line": 3063, + "line": 3107, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Not allowed", "surface": "android", @@ -5219,7 +5251,7 @@ }, { "kind": "ui-call", - "line": 3071, + "line": 3115, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Granted", "surface": "android", @@ -5227,7 +5259,7 @@ }, { "kind": "ui-call", - "line": 3071, + "line": 3115, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Not granted", "surface": "android", @@ -5235,7 +5267,7 @@ }, { "kind": "ui-call", - "line": 3197, + "line": 3241, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Transcribe voice prompts", "surface": "android", @@ -5243,7 +5275,7 @@ }, { "kind": "ui-call", - "line": 3197, + "line": 3241, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Voice", "surface": "android", @@ -5251,7 +5283,7 @@ }, { "kind": "ui-call", - "line": 3202, + "line": 3246, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Camera", "surface": "android", @@ -5259,7 +5291,7 @@ }, { "kind": "ui-call", - "line": 3203, + "line": 3247, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Capture photos and clips from this phone", "surface": "android", @@ -5267,7 +5299,7 @@ }, { "kind": "ui-call", - "line": 3212, + "line": 3256, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Location", "surface": "android", @@ -5275,7 +5307,7 @@ }, { "kind": "ui-call", - "line": 3212, + "line": 3256, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Read this phone's location", "surface": "android", @@ -5283,7 +5315,7 @@ }, { "kind": "ui-call", - "line": 3216, + "line": 3260, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Photos", "surface": "android", @@ -5291,7 +5323,7 @@ }, { "kind": "ui-call", - "line": 3216, + "line": 3260, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Read recent photos and media", "surface": "android", @@ -5299,7 +5331,7 @@ }, { "kind": "ui-call", - "line": 3222, + "line": 3266, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Contacts", "surface": "android", @@ -5307,7 +5339,7 @@ }, { "kind": "ui-call", - "line": 3222, + "line": 3266, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Find people and contact details", "surface": "android", @@ -5315,7 +5347,7 @@ }, { "kind": "ui-call", - "line": 3225, + "line": 3269, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Calendar", "surface": "android", @@ -5323,7 +5355,7 @@ }, { "kind": "ui-call", - "line": 3225, + "line": 3269, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Read and update events", "surface": "android", @@ -5331,7 +5363,7 @@ }, { "kind": "ui-call", - "line": 3228, + "line": 3272, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Notifications", "surface": "android", @@ -5339,7 +5371,7 @@ }, { "kind": "ui-call", - "line": 3228, + "line": 3272, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Show OpenClaw alerts", "surface": "android", @@ -5347,7 +5379,7 @@ }, { "kind": "ui-call", - "line": 3231, + "line": 3275, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Notification listener", "surface": "android", @@ -5355,7 +5387,7 @@ }, { "kind": "ui-call", - "line": 3231, + "line": 3275, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Read selected app notifications", "surface": "android", @@ -5363,7 +5395,7 @@ }, { "kind": "ui-call", - "line": 3235, + "line": 3279, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Motion", "surface": "android", @@ -5371,7 +5403,7 @@ }, { "kind": "ui-call", - "line": 3235, + "line": 3279, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Share steps and activity", "surface": "android", @@ -5379,7 +5411,7 @@ }, { "kind": "ui-call", - "line": 3242, + "line": 3286, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Device access; Gateway opt-in still required", "surface": "android", @@ -5387,7 +5419,7 @@ }, { "kind": "ui-call", - "line": 3242, + "line": 3286, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "SMS", "surface": "android", @@ -5395,7 +5427,7 @@ }, { "kind": "ui-call", - "line": 3249, + "line": 3293, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Call Log", "surface": "android", @@ -5403,7 +5435,7 @@ }, { "kind": "ui-call", - "line": 3249, + "line": 3293, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Show recent call history", "surface": "android", @@ -8683,7 +8715,7 @@ }, { "kind": "ui-call", - "line": 132, + "line": 134, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Home", "surface": "android", @@ -8691,7 +8723,7 @@ }, { "kind": "ui-call", - "line": 361, + "line": 364, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Close Canvas", "surface": "android", @@ -8699,7 +8731,39 @@ }, { "kind": "ui-call", - "line": 509, + "line": 394, + "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "surface": "android", + "id": "native.android.846fe5afd08b8089" + }, + { + "kind": "ui-call", + "line": 422, + "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", + "source": "This gateway now presents a certificate trusted by this device.", + "surface": "android", + "id": "native.android.b263dca13f55dad9" + }, + { + "kind": "ui-call", + "line": 432, + "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", + "source": "SHA-256 fingerprint", + "surface": "android", + "id": "native.android.dca0f8814b658170" + }, + { + "kind": "ui-call", + "line": 452, + "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", + "source": "Use system trust", + "surface": "android", + "id": "native.android.bb5d50fcdd5ebafe" + }, + { + "kind": "ui-call", + "line": 557, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Overview", "surface": "android", @@ -8707,7 +8771,7 @@ }, { "kind": "ui-call", - "line": 556, + "line": 604, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Start a chat and your active OpenClaw conversations will appear here.", "surface": "android", @@ -8715,7 +8779,7 @@ }, { "kind": "ui-call", - "line": 557, + "line": 605, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Start Chat", "surface": "android", @@ -8723,7 +8787,7 @@ }, { "kind": "ui-call", - "line": 611, + "line": 659, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Search", "surface": "android", @@ -8731,7 +8795,7 @@ }, { "kind": "ui-call", - "line": 664, + "line": 712, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "ACTIVE AGENT", "surface": "android", @@ -8739,7 +8803,7 @@ }, { "kind": "ui-call", - "line": 669, + "line": 717, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "$agentName is working", "surface": "android", @@ -8747,7 +8811,7 @@ }, { "kind": "ui-call", - "line": 673, + "line": 721, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "View", "surface": "android", @@ -8755,7 +8819,7 @@ }, { "kind": "ui-call", - "line": 676, + "line": 724, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "$pendingRunCount active", "surface": "android", @@ -8763,7 +8827,7 @@ }, { "kind": "ui-call", - "line": 676, + "line": 724, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Idle", "surface": "android", @@ -8771,7 +8835,7 @@ }, { "kind": "ui-call", - "line": 676, + "line": 724, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Runs", "surface": "android", @@ -8779,7 +8843,7 @@ }, { "kind": "ui-call", - "line": 677, + "line": 725, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "$sessionCount recent", "surface": "android", @@ -8787,7 +8851,7 @@ }, { "kind": "ui-call", - "line": 678, + "line": 726, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Cron", "surface": "android", @@ -8795,7 +8859,7 @@ }, { "kind": "ui-call", - "line": 681, + "line": 729, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Chat", "surface": "android", @@ -8803,7 +8867,7 @@ }, { "kind": "ui-call", - "line": 685, + "line": 733, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Reconnect gateway", "surface": "android", @@ -8811,7 +8875,7 @@ }, { "kind": "ui-call", - "line": 836, + "line": 884, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Open ${card.title}", "surface": "android", @@ -8819,7 +8883,7 @@ }, { "kind": "ui-call", - "line": 916, + "line": 964, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Talk", "surface": "android", @@ -8827,7 +8891,7 @@ }, { "kind": "ui-call", - "line": 917, + "line": 965, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Open Talk", "surface": "android", @@ -8835,7 +8899,7 @@ }, { "kind": "ui-call", - "line": 919, + "line": 967, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Talk settings", "surface": "android", @@ -8843,7 +8907,7 @@ }, { "kind": "ui-call", - "line": 927, + "line": 975, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Recent Threads", "surface": "android", @@ -8851,7 +8915,7 @@ }, { "kind": "ui-call", - "line": 937, + "line": 985, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "View all", "surface": "android", @@ -8859,7 +8923,7 @@ }, { "kind": "ui-call", - "line": 1055, + "line": 1103, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Online", "surface": "android", @@ -8867,7 +8931,7 @@ }, { "kind": "ui-call", - "line": 1056, + "line": 1104, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Healthy", "surface": "android", @@ -8875,7 +8939,7 @@ }, { "kind": "ui-call", - "line": 1060, + "line": 1108, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Reconnect to continue", "surface": "android", @@ -8883,7 +8947,7 @@ }, { "kind": "ui-call", - "line": 1061, + "line": 1109, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Review highlighted items", "surface": "android", @@ -8891,7 +8955,7 @@ }, { "kind": "ui-call", - "line": 1062, + "line": 1110, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "All systems nominal", "surface": "android", @@ -8899,7 +8963,7 @@ }, { "kind": "ui-call", - "line": 1075, + "line": 1123, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Nodes", "surface": "android", @@ -8907,7 +8971,7 @@ }, { "kind": "ui-call", - "line": 1076, + "line": 1124, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "$onlineNodes/$nodeCount", "surface": "android", @@ -8915,7 +8979,7 @@ }, { "kind": "ui-call", - "line": 1076, + "line": 1124, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "None", "surface": "android", @@ -8923,7 +8987,7 @@ }, { "kind": "ui-call", - "line": 1079, + "line": 1127, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Review node access", "surface": "android", @@ -8931,7 +8995,7 @@ }, { "kind": "ui-call", - "line": 1081, + "line": 1129, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "${nodeOnlinePercent(onlineNodes = onlineNodes, nodeCount = nodeCount)}% online", "surface": "android", @@ -8939,7 +9003,7 @@ }, { "kind": "ui-call", - "line": 1109, + "line": 1157, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Threads", "surface": "android", @@ -8947,7 +9011,7 @@ }, { "kind": "ui-call", - "line": 1111, + "line": 1159, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "No recent threads", "surface": "android", @@ -8955,7 +9019,7 @@ }, { "kind": "ui-call", - "line": 1111, + "line": 1159, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Recent conversations", "surface": "android", @@ -8963,7 +9027,7 @@ }, { "kind": "ui-call", - "line": 1117, + "line": 1165, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Files", "surface": "android", @@ -8971,7 +9035,7 @@ }, { "kind": "ui-call", - "line": 1118, + "line": 1166, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Browse", "surface": "android", @@ -8979,7 +9043,7 @@ }, { "kind": "ui-call", - "line": 1118, + "line": 1166, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Offline", "surface": "android", @@ -8987,7 +9051,7 @@ }, { "kind": "ui-call", - "line": 1119, + "line": 1167, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Agent workspace files", "surface": "android", @@ -8995,7 +9059,7 @@ }, { "kind": "ui-call", - "line": 1177, + "line": 1225, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Working · 1 active run", "surface": "android", @@ -9003,7 +9067,7 @@ }, { "kind": "ui-call", - "line": 1179, + "line": 1227, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Working · $pendingRunCount active runs", "surface": "android", @@ -9011,7 +9075,7 @@ }, { "kind": "ui-call", - "line": 1183, + "line": 1231, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Monitoring · 1 thread", "surface": "android", @@ -9019,7 +9083,7 @@ }, { "kind": "ui-call", - "line": 1184, + "line": 1232, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Monitoring · $sessionCount threads", "surface": "android", @@ -9027,7 +9091,7 @@ }, { "kind": "ui-call", - "line": 1185, + "line": 1233, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Monitoring · 1 scheduled job", "surface": "android", @@ -9035,7 +9099,7 @@ }, { "kind": "ui-call", - "line": 1186, + "line": 1234, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Monitoring · $cronJobCount scheduled jobs", "surface": "android", @@ -9043,7 +9107,7 @@ }, { "kind": "ui-call", - "line": 1236, + "line": 1284, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "OpenClaw", "surface": "android", @@ -9051,7 +9115,7 @@ }, { "kind": "ui-call", - "line": 1268, + "line": 1316, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Connect before chat, voice, and live status.", "surface": "android", @@ -9059,7 +9123,7 @@ }, { "kind": "ui-call", - "line": 1292, + "line": 1340, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "No ready providers", "surface": "android", @@ -9067,7 +9131,7 @@ }, { "kind": "ui-call", - "line": 1292, + "line": 1340, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Providers", "surface": "android", @@ -9075,7 +9139,7 @@ }, { "kind": "ui-call", - "line": 1487, + "line": 1535, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Open thread", "surface": "android", @@ -9083,7 +9147,7 @@ }, { "kind": "ui-call", - "line": 1585, + "line": 1633, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Back", "surface": "android", @@ -9091,7 +9155,7 @@ }, { "kind": "ui-call", - "line": 1588, + "line": 1636, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Settings", "surface": "android", @@ -9099,7 +9163,7 @@ }, { "kind": "ui-call", - "line": 1591, + "line": 1639, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Search settings", "surface": "android", @@ -9107,7 +9171,7 @@ }, { "kind": "ui-call", - "line": 1604, + "line": 1652, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Gateway", "surface": "android", @@ -9115,7 +9179,7 @@ }, { "kind": "ui-call", - "line": 1610, + "line": 1658, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Nodes & Devices", "surface": "android", @@ -9123,7 +9187,7 @@ }, { "kind": "ui-call", - "line": 1611, + "line": 1659, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Channels", "surface": "android", @@ -9131,7 +9195,7 @@ }, { "kind": "ui-call", - "line": 1612, + "line": 1660, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "${agents.size} available", "surface": "android", @@ -9139,7 +9203,7 @@ }, { "kind": "ui-call", - "line": 1612, + "line": 1660, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Agents", "surface": "android", @@ -9147,7 +9211,7 @@ }, { "kind": "ui-call", - "line": 1612, + "line": 1660, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Load from gateway", "surface": "android", @@ -9155,7 +9219,7 @@ }, { "kind": "ui-call", - "line": 1614, + "line": 1662, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Providers & Models", "surface": "android", @@ -9163,7 +9227,7 @@ }, { "kind": "ui-call", - "line": 1616, + "line": 1664, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "$readyProviderCount ready", "surface": "android", @@ -9171,7 +9235,7 @@ }, { "kind": "ui-call", - "line": 1617, + "line": 1665, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Availability unknown", "surface": "android", @@ -9179,7 +9243,7 @@ }, { "kind": "ui-call", - "line": 1618, + "line": 1666, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Review readiness", "surface": "android", @@ -9187,7 +9251,7 @@ }, { "kind": "ui-call", - "line": 1630, + "line": 1678, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Approvals", "surface": "android", @@ -9195,7 +9259,7 @@ }, { "kind": "ui-call", - "line": 1631, + "line": 1679, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Automations", "surface": "android", @@ -9203,7 +9267,7 @@ }, { "kind": "ui-call", - "line": 1632, + "line": 1680, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Usage", "surface": "android", @@ -9211,7 +9275,7 @@ }, { "kind": "ui-call", - "line": 1633, + "line": 1681, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Skills", "surface": "android", @@ -9219,7 +9283,7 @@ }, { "kind": "ui-call", - "line": 1635, + "line": 1683, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Skill Workshop", "surface": "android", @@ -9227,7 +9291,7 @@ }, { "kind": "ui-call", - "line": 1641, + "line": 1689, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Dreaming", "surface": "android", @@ -9235,7 +9299,7 @@ }, { "kind": "ui-call", - "line": 1642, + "line": 1690, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Shell in the agent workspace", "surface": "android", @@ -9243,7 +9307,7 @@ }, { "kind": "ui-call", - "line": 1642, + "line": 1690, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Terminal", "surface": "android", @@ -9251,7 +9315,7 @@ }, { "kind": "ui-call", - "line": 1643, + "line": 1691, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Speaker muted", "surface": "android", @@ -9259,7 +9323,7 @@ }, { "kind": "ui-call", - "line": 1643, + "line": 1691, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Speaker on", "surface": "android", @@ -9267,7 +9331,7 @@ }, { "kind": "ui-call", - "line": 1643, + "line": 1691, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Voice", "surface": "android", @@ -9275,7 +9339,7 @@ }, { "kind": "ui-call", - "line": 1644, + "line": 1692, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Canvas", "surface": "android", @@ -9283,7 +9347,7 @@ }, { "kind": "ui-call", - "line": 1644, + "line": 1692, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Screen surface", "surface": "android", @@ -9291,7 +9355,7 @@ }, { "kind": "ui-call", - "line": 1645, + "line": 1693, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Notifications", "surface": "android", @@ -9299,7 +9363,7 @@ }, { "kind": "ui-call", - "line": 1645, + "line": 1693, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Smart delivery", "surface": "android", @@ -9307,7 +9371,7 @@ }, { "kind": "ui-call", - "line": 1646, + "line": 1694, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Camera enabled", "surface": "android", @@ -9315,7 +9379,7 @@ }, { "kind": "ui-call", - "line": 1646, + "line": 1694, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Locked", "surface": "android", @@ -9323,7 +9387,7 @@ }, { "kind": "ui-call", - "line": 1646, + "line": 1694, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Phone Capabilities", "surface": "android", @@ -9331,7 +9395,7 @@ }, { "kind": "ui-call", - "line": 1648, + "line": 1696, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Appearance", "surface": "android", @@ -9339,7 +9403,7 @@ }, { "kind": "ui-call", - "line": 1656, + "line": 1704, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "About", "surface": "android", @@ -9347,7 +9411,7 @@ }, { "kind": "ui-call", - "line": 1656, + "line": 1704, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Version and update", "surface": "android", @@ -9355,7 +9419,7 @@ }, { "kind": "ui-call", - "line": 1657, + "line": 1705, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Health", "surface": "android", @@ -9363,7 +9427,7 @@ }, { "kind": "ui-call", - "line": 1670, + "line": 1718, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Account", "surface": "android", @@ -9371,7 +9435,7 @@ }, { "kind": "ui-call", - "line": 1674, + "line": 1722, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Return to setup", "surface": "android", @@ -9379,7 +9443,7 @@ }, { "kind": "ui-call", - "line": 1674, + "line": 1722, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Sign Out", "surface": "android", @@ -9387,7 +9451,7 @@ }, { "kind": "ui-call", - "line": 1685, + "line": 1733, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Licenses", "surface": "android", @@ -9395,7 +9459,7 @@ }, { "kind": "ui-call", - "line": 1696, + "line": 1744, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "OpenClaw ${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})", "surface": "android", @@ -9403,7 +9467,7 @@ }, { "kind": "ui-call", - "line": 1699, + "line": 1747, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "All systems operational", "surface": "android", @@ -9411,7 +9475,7 @@ }, { "kind": "ui-call", - "line": 1699, + "line": 1747, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Gateway not connected", "surface": "android", @@ -9419,7 +9483,7 @@ }, { "kind": "ui-call", - "line": 1713, + "line": 1761, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "No pending approvals", "surface": "android", @@ -9427,7 +9491,7 @@ }, { "kind": "ui-call", - "line": 1715, + "line": 1763, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "$count pending", "surface": "android", @@ -9435,7 +9499,7 @@ }, { "kind": "ui-call", - "line": 1723, + "line": 1771, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "No scheduled jobs", "surface": "android", @@ -9443,7 +9507,7 @@ }, { "kind": "ui-call", - "line": 1724, + "line": 1772, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "1 scheduled", "surface": "android", @@ -9451,7 +9515,7 @@ }, { "kind": "ui-call", - "line": 1725, + "line": 1773, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "$count scheduled", "surface": "android", @@ -9459,7 +9523,7 @@ }, { "kind": "ui-call", - "line": 1731, + "line": 1779, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "No provider usage", "surface": "android", @@ -9467,7 +9531,7 @@ }, { "kind": "ui-call", - "line": 1732, + "line": 1780, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "1 provider", "surface": "android", @@ -9475,7 +9539,7 @@ }, { "kind": "ui-call", - "line": 1733, + "line": 1781, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "$count providers", "surface": "android", @@ -9483,7 +9547,7 @@ }, { "kind": "ui-call", - "line": 1743, + "line": 1791, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "No skills", "surface": "android", @@ -9491,7 +9555,7 @@ }, { "kind": "ui-call", - "line": 1745, + "line": 1793, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "$ready/${skills.size} ready", "surface": "android", @@ -9499,7 +9563,7 @@ }, { "kind": "ui-call", - "line": 1764, + "line": 1812, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "$pending pending", "surface": "android", @@ -9507,7 +9571,7 @@ }, { "kind": "ui-call", - "line": 1764, + "line": 1812, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "1 pending", "surface": "android", @@ -9515,7 +9579,7 @@ }, { "kind": "ui-call", - "line": 1768, + "line": 1816, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "No proposals", "surface": "android", @@ -9523,7 +9587,7 @@ }, { "kind": "ui-call", - "line": 1769, + "line": 1817, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "$held held", "surface": "android", @@ -9531,7 +9595,7 @@ }, { "kind": "ui-call", - "line": 1769, + "line": 1817, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "1 held", "surface": "android", @@ -9539,7 +9603,7 @@ }, { "kind": "ui-call", - "line": 1770, + "line": 1818, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "$applied applied", "surface": "android", @@ -9547,7 +9611,7 @@ }, { "kind": "ui-call", - "line": 1770, + "line": 1818, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "1 applied", "surface": "android", @@ -9555,7 +9619,7 @@ }, { "kind": "ui-call", - "line": 1771, + "line": 1819, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "${summary.proposals.size} proposals", "surface": "android", @@ -9563,7 +9627,7 @@ }, { "kind": "ui-call", - "line": 1788, + "line": 1836, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "${summary.pendingDevices.size} pending", "surface": "android", @@ -9571,7 +9635,7 @@ }, { "kind": "ui-call", - "line": 1789, + "line": 1837, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Node approval pending", "surface": "android", @@ -9579,7 +9643,7 @@ }, { "kind": "ui-call", - "line": 1790, + "line": 1838, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "$online/${summary.nodes.size} online", "surface": "android", @@ -9587,7 +9651,7 @@ }, { "kind": "ui-call", - "line": 1791, + "line": 1839, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "$devices paired", "surface": "android", @@ -9595,7 +9659,7 @@ }, { "kind": "ui-call", - "line": 1792, + "line": 1840, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "No devices", "surface": "android", @@ -9603,7 +9667,7 @@ }, { "kind": "ui-call", - "line": 1818, + "line": 1866, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "1 issue", "surface": "android", @@ -9611,7 +9675,7 @@ }, { "kind": "ui-call", - "line": 1819, + "line": 1867, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "$issueCount issues", "surface": "android", @@ -9619,7 +9683,7 @@ }, { "kind": "ui-call", - "line": 1820, + "line": 1868, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "$connected/${summary.channels.size} connected", "surface": "android", @@ -9627,7 +9691,7 @@ }, { "kind": "ui-call", - "line": 1821, + "line": 1869, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "No channels", "surface": "android", @@ -9635,7 +9699,7 @@ }, { "kind": "ui-call", - "line": 1837, + "line": 1885, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Needs attention", "surface": "android", @@ -9643,7 +9707,7 @@ }, { "kind": "ui-call", - "line": 1838, + "line": 1886, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "${summary.shortTermCount} waiting", "surface": "android", @@ -9651,7 +9715,7 @@ }, { "kind": "ui-call", - "line": 1839, + "line": 1887, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Off", "surface": "android", @@ -9659,7 +9723,7 @@ }, { "kind": "ui-call", - "line": 1883, + "line": 1931, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Connection", "surface": "android", @@ -9667,7 +9731,7 @@ }, { "kind": "ui-call", - "line": 1894, + "line": 1942, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Agents & automation", "surface": "android", @@ -9675,7 +9739,7 @@ }, { "kind": "ui-call", - "line": 1900, + "line": 1948, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Phone context & privacy", "surface": "android", @@ -9683,7 +9747,7 @@ }, { "kind": "ui-call", - "line": 1906, + "line": 1954, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Profile & device", "surface": "android", @@ -9691,7 +9755,7 @@ }, { "kind": "ui-call", - "line": 1909, + "line": 1957, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Diagnostics", "surface": "android", @@ -9699,7 +9763,7 @@ }, { "kind": "ui-call", - "line": 1955, + "line": 2003, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "OpenClaw mobile", "surface": "android", @@ -9707,7 +9771,7 @@ }, { "kind": "ui-call", - "line": 1959, + "line": 2007, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Open profile", "surface": "android", @@ -9715,7 +9779,7 @@ }, { "kind": "ui-call", - "line": 2039, + "line": 2087, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Open ${row.title}", "surface": "android", @@ -9723,7 +9787,7 @@ }, { "kind": "ui-call", - "line": 2047, + "line": 2095, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "now", "surface": "android", @@ -9731,7 +9795,7 @@ }, { "kind": "ui-call", - "line": 2048, + "line": 2096, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "${minutes}m", "surface": "android", @@ -9739,7 +9803,7 @@ }, { "kind": "ui-call", - "line": 2050, + "line": 2098, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "${hours}h", "surface": "android", @@ -9747,7 +9811,7 @@ }, { "kind": "ui-call", - "line": 2052, + "line": 2100, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "${days}d", "surface": "android", @@ -9755,7 +9819,7 @@ }, { "kind": "ui-call", - "line": 2055, + "line": 2103, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Main thread", "surface": "android", @@ -9763,7 +9827,7 @@ }, { "kind": "ui-call", - "line": 2062, + "line": 2110, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Online and ready", "surface": "android", @@ -9771,7 +9835,7 @@ }, { "kind": "ui-call", - "line": 2065, + "line": 2113, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Connecting...", "surface": "android", @@ -9779,7 +9843,7 @@ }, { "kind": "ui-call", - "line": 2066, + "line": 2114, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Waiting for pairing", "surface": "android", @@ -9787,7 +9851,7 @@ }, { "kind": "ui-call", - "line": 2067, + "line": 2115, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Authentication needed", "surface": "android", @@ -9795,7 +9859,7 @@ }, { "kind": "ui-call", - "line": 2068, + "line": 2116, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "TLS timed out", "surface": "android", @@ -9803,7 +9867,7 @@ }, { "kind": "ui-call", - "line": 2069, + "line": 2117, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "No TLS endpoint", "surface": "android", @@ -9811,7 +9875,7 @@ }, { "kind": "ui-call", - "line": 2070, + "line": 2118, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Certificate review needed", "surface": "android", @@ -9819,7 +9883,7 @@ }, { "kind": "ui-call", - "line": 2071, + "line": 2119, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt", "source": "Not connected", "surface": "android", diff --git a/apps/.i18n/native/ar.json b/apps/.i18n/native/ar.json index 903f9db8455..8012798775f 100644 --- a/apps/.i18n/native/ar.json +++ b/apps/.i18n/native/ar.json @@ -2603,11 +2603,31 @@ "source": "Could not start the camera. Choose a QR image from gallery or enter the setup code manually.", "translated": "تعذّر تشغيل الكاميرا. اختر صورة QR من المعرض أو أدخل رمز الإعداد يدويًا." }, + { + "id": "native.android.7a18be21a62739bf", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "translated": "تعذّرت قراءة شهادة Gateway تلقائيًا. الصق بصمة SHA-256 التي حصلت عليها من مضيف Gateway." + }, + { + "id": "native.android.aa489429ad39aa39", + "source": "This gateway now presents a certificate trusted by this device.", + "translated": "يقدّم Gateway هذا الآن شهادة موثوقة من هذا الجهاز." + }, + { + "id": "native.android.b3db82f1162808ad", + "source": "SHA-256 fingerprint", + "translated": "بصمة SHA-256" + }, { "id": "native.android.9ac2d4498b17d478", "source": "Trust", "translated": "الوثوق" }, + { + "id": "native.android.09245320d3878458", + "source": "Use system trust", + "translated": "استخدام ثقة النظام" + }, { "id": "native.android.e26ee07a1d1911be", "source": "Cancel", @@ -5438,6 +5458,26 @@ "source": "Close Canvas", "translated": "إغلاق Canvas" }, + { + "id": "native.android.846fe5afd08b8089", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "translated": "تعذّرت قراءة شهادة Gateway تلقائيًا. الصق بصمة SHA-256 التي حصلت عليها من مضيف Gateway." + }, + { + "id": "native.android.b263dca13f55dad9", + "source": "This gateway now presents a certificate trusted by this device.", + "translated": "يقدّم Gateway هذا الآن شهادة موثوقة من هذا الجهاز." + }, + { + "id": "native.android.dca0f8814b658170", + "source": "SHA-256 fingerprint", + "translated": "بصمة SHA-256" + }, + { + "id": "native.android.bb5d50fcdd5ebafe", + "source": "Use system trust", + "translated": "استخدام ثقة النظام" + }, { "id": "native.android.3d83e0755437a5f9", "source": "Overview", diff --git a/apps/.i18n/native/de.json b/apps/.i18n/native/de.json index 7cb56f79194..48325661c0d 100644 --- a/apps/.i18n/native/de.json +++ b/apps/.i18n/native/de.json @@ -2603,11 +2603,31 @@ "source": "Could not start the camera. Choose a QR image from gallery or enter the setup code manually.", "translated": "Die Kamera konnte nicht gestartet werden. Wähle ein QR-Bild aus der Galerie oder gib den Einrichtungscode manuell ein." }, + { + "id": "native.android.7a18be21a62739bf", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "translated": "Das Gateway-Zertifikat konnte nicht automatisch gelesen werden. Fügen Sie den auf dem Gateway-Host ermittelten SHA-256-Fingerabdruck ein." + }, + { + "id": "native.android.aa489429ad39aa39", + "source": "This gateway now presents a certificate trusted by this device.", + "translated": "Dieses Gateway verwendet jetzt ein Zertifikat, dem dieses Gerät vertraut." + }, + { + "id": "native.android.b3db82f1162808ad", + "source": "SHA-256 fingerprint", + "translated": "SHA-256-Fingerabdruck" + }, { "id": "native.android.9ac2d4498b17d478", "source": "Trust", "translated": "Vertrauen" }, + { + "id": "native.android.09245320d3878458", + "source": "Use system trust", + "translated": "Systemvertrauen verwenden" + }, { "id": "native.android.e26ee07a1d1911be", "source": "Cancel", @@ -5438,6 +5458,26 @@ "source": "Close Canvas", "translated": "Canvas schließen" }, + { + "id": "native.android.846fe5afd08b8089", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "translated": "Das Gateway-Zertifikat konnte nicht automatisch gelesen werden. Fügen Sie den auf dem Gateway-Host ermittelten SHA-256-Fingerabdruck ein." + }, + { + "id": "native.android.b263dca13f55dad9", + "source": "This gateway now presents a certificate trusted by this device.", + "translated": "Dieses Gateway verwendet jetzt ein Zertifikat, dem dieses Gerät vertraut." + }, + { + "id": "native.android.dca0f8814b658170", + "source": "SHA-256 fingerprint", + "translated": "SHA-256-Fingerabdruck" + }, + { + "id": "native.android.bb5d50fcdd5ebafe", + "source": "Use system trust", + "translated": "Systemvertrauen verwenden" + }, { "id": "native.android.3d83e0755437a5f9", "source": "Overview", diff --git a/apps/.i18n/native/es.json b/apps/.i18n/native/es.json index 6f69b95b947..163998d3cbd 100644 --- a/apps/.i18n/native/es.json +++ b/apps/.i18n/native/es.json @@ -2603,11 +2603,31 @@ "source": "Could not start the camera. Choose a QR image from gallery or enter the setup code manually.", "translated": "No se pudo iniciar la cámara. Selecciona una imagen QR de la galería o introduce manualmente el código de configuración." }, + { + "id": "native.android.7a18be21a62739bf", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "translated": "No se pudo leer automáticamente el certificado del gateway. Pega la huella digital SHA-256 obtenida en el host del gateway." + }, + { + "id": "native.android.aa489429ad39aa39", + "source": "This gateway now presents a certificate trusted by this device.", + "translated": "Este gateway ahora presenta un certificado en el que confía este dispositivo." + }, + { + "id": "native.android.b3db82f1162808ad", + "source": "SHA-256 fingerprint", + "translated": "Huella digital SHA-256" + }, { "id": "native.android.9ac2d4498b17d478", "source": "Trust", "translated": "Confiar" }, + { + "id": "native.android.09245320d3878458", + "source": "Use system trust", + "translated": "Usar la confianza del sistema" + }, { "id": "native.android.e26ee07a1d1911be", "source": "Cancel", @@ -5438,6 +5458,26 @@ "source": "Close Canvas", "translated": "Cerrar Canvas" }, + { + "id": "native.android.846fe5afd08b8089", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "translated": "No se pudo leer automáticamente el certificado del gateway. Pega la huella digital SHA-256 obtenida en el host del gateway." + }, + { + "id": "native.android.b263dca13f55dad9", + "source": "This gateway now presents a certificate trusted by this device.", + "translated": "Este gateway ahora presenta un certificado en el que confía este dispositivo." + }, + { + "id": "native.android.dca0f8814b658170", + "source": "SHA-256 fingerprint", + "translated": "Huella digital SHA-256" + }, + { + "id": "native.android.bb5d50fcdd5ebafe", + "source": "Use system trust", + "translated": "Usar la confianza del sistema" + }, { "id": "native.android.3d83e0755437a5f9", "source": "Overview", diff --git a/apps/.i18n/native/fa.json b/apps/.i18n/native/fa.json index 7cf734154cd..914608d88fc 100644 --- a/apps/.i18n/native/fa.json +++ b/apps/.i18n/native/fa.json @@ -2603,11 +2603,31 @@ "source": "Could not start the camera. Choose a QR image from gallery or enter the setup code manually.", "translated": "راه‌اندازی دوربین ممکن نبود. یک تصویر QR از گالری انتخاب کنید یا کد راه‌اندازی را به‌صورت دستی وارد کنید." }, + { + "id": "native.android.7a18be21a62739bf", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "translated": "گواهی Gateway به‌طور خودکار قابل خواندن نبود. اثر انگشت SHA-256 دریافت‌شده در میزبان Gateway را جای‌گذاری کنید." + }, + { + "id": "native.android.aa489429ad39aa39", + "source": "This gateway now presents a certificate trusted by this device.", + "translated": "این Gateway اکنون گواهی‌ای ارائه می‌کند که مورد اعتماد این دستگاه است." + }, + { + "id": "native.android.b3db82f1162808ad", + "source": "SHA-256 fingerprint", + "translated": "اثر انگشت SHA-256" + }, { "id": "native.android.9ac2d4498b17d478", "source": "Trust", "translated": "اعتماد" }, + { + "id": "native.android.09245320d3878458", + "source": "Use system trust", + "translated": "استفاده از اعتماد سیستم" + }, { "id": "native.android.e26ee07a1d1911be", "source": "Cancel", @@ -5438,6 +5458,26 @@ "source": "Close Canvas", "translated": "بستن Canvas" }, + { + "id": "native.android.846fe5afd08b8089", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "translated": "گواهی Gateway به‌طور خودکار قابل خواندن نبود. اثر انگشت SHA-256 دریافت‌شده در میزبان Gateway را جای‌گذاری کنید." + }, + { + "id": "native.android.b263dca13f55dad9", + "source": "This gateway now presents a certificate trusted by this device.", + "translated": "این Gateway اکنون گواهی‌ای ارائه می‌کند که مورد اعتماد این دستگاه است." + }, + { + "id": "native.android.dca0f8814b658170", + "source": "SHA-256 fingerprint", + "translated": "اثر انگشت SHA-256" + }, + { + "id": "native.android.bb5d50fcdd5ebafe", + "source": "Use system trust", + "translated": "استفاده از اعتماد سیستم" + }, { "id": "native.android.3d83e0755437a5f9", "source": "Overview", diff --git a/apps/.i18n/native/fr.json b/apps/.i18n/native/fr.json index 1c9e7f7af7b..3b95b55b609 100644 --- a/apps/.i18n/native/fr.json +++ b/apps/.i18n/native/fr.json @@ -2603,11 +2603,31 @@ "source": "Could not start the camera. Choose a QR image from gallery or enter the setup code manually.", "translated": "Impossible de démarrer l’appareil photo. Choisissez une image du code QR dans la galerie ou saisissez manuellement le code de configuration." }, + { + "id": "native.android.7a18be21a62739bf", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "translated": "Le certificat du Gateway n’a pas pu être lu automatiquement. Collez l’empreinte SHA-256 obtenue sur l’hôte du Gateway." + }, + { + "id": "native.android.aa489429ad39aa39", + "source": "This gateway now presents a certificate trusted by this device.", + "translated": "Ce Gateway présente désormais un certificat approuvé par cet appareil." + }, + { + "id": "native.android.b3db82f1162808ad", + "source": "SHA-256 fingerprint", + "translated": "Empreinte SHA-256" + }, { "id": "native.android.9ac2d4498b17d478", "source": "Trust", "translated": "Faire confiance" }, + { + "id": "native.android.09245320d3878458", + "source": "Use system trust", + "translated": "Utiliser la confiance du système" + }, { "id": "native.android.e26ee07a1d1911be", "source": "Cancel", @@ -5438,6 +5458,26 @@ "source": "Close Canvas", "translated": "Fermer Canvas" }, + { + "id": "native.android.846fe5afd08b8089", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "translated": "Le certificat du Gateway n’a pas pu être lu automatiquement. Collez l’empreinte SHA-256 obtenue sur l’hôte du Gateway." + }, + { + "id": "native.android.b263dca13f55dad9", + "source": "This gateway now presents a certificate trusted by this device.", + "translated": "Ce Gateway présente désormais un certificat approuvé par cet appareil." + }, + { + "id": "native.android.dca0f8814b658170", + "source": "SHA-256 fingerprint", + "translated": "Empreinte SHA-256" + }, + { + "id": "native.android.bb5d50fcdd5ebafe", + "source": "Use system trust", + "translated": "Utiliser la confiance du système" + }, { "id": "native.android.3d83e0755437a5f9", "source": "Overview", diff --git a/apps/.i18n/native/hi.json b/apps/.i18n/native/hi.json index d80d0fb394a..d0e95d59cc4 100644 --- a/apps/.i18n/native/hi.json +++ b/apps/.i18n/native/hi.json @@ -2603,11 +2603,31 @@ "source": "Could not start the camera. Choose a QR image from gallery or enter the setup code manually.", "translated": "कैमरा शुरू नहीं किया जा सका। गैलरी से QR इमेज चुनें या सेटअप कोड मैन्युअल रूप से दर्ज करें।" }, + { + "id": "native.android.7a18be21a62739bf", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "translated": "Gateway प्रमाणपत्र को स्वचालित रूप से पढ़ा नहीं जा सका। Gateway होस्ट पर प्राप्त SHA-256 फ़िंगरप्रिंट पेस्ट करें।" + }, + { + "id": "native.android.aa489429ad39aa39", + "source": "This gateway now presents a certificate trusted by this device.", + "translated": "यह Gateway अब इस डिवाइस द्वारा विश्वसनीय प्रमाणपत्र प्रस्तुत करता है।" + }, + { + "id": "native.android.b3db82f1162808ad", + "source": "SHA-256 fingerprint", + "translated": "SHA-256 फ़िंगरप्रिंट" + }, { "id": "native.android.9ac2d4498b17d478", "source": "Trust", "translated": "भरोसा करें" }, + { + "id": "native.android.09245320d3878458", + "source": "Use system trust", + "translated": "सिस्टम विश्वसनीयता का उपयोग करें" + }, { "id": "native.android.e26ee07a1d1911be", "source": "Cancel", @@ -5438,6 +5458,26 @@ "source": "Close Canvas", "translated": "Canvas बंद करें" }, + { + "id": "native.android.846fe5afd08b8089", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "translated": "Gateway प्रमाणपत्र को स्वचालित रूप से पढ़ा नहीं जा सका। Gateway होस्ट पर प्राप्त SHA-256 फ़िंगरप्रिंट पेस्ट करें।" + }, + { + "id": "native.android.b263dca13f55dad9", + "source": "This gateway now presents a certificate trusted by this device.", + "translated": "यह Gateway अब इस डिवाइस द्वारा विश्वसनीय प्रमाणपत्र प्रस्तुत करता है।" + }, + { + "id": "native.android.dca0f8814b658170", + "source": "SHA-256 fingerprint", + "translated": "SHA-256 फ़िंगरप्रिंट" + }, + { + "id": "native.android.bb5d50fcdd5ebafe", + "source": "Use system trust", + "translated": "सिस्टम विश्वसनीयता का उपयोग करें" + }, { "id": "native.android.3d83e0755437a5f9", "source": "Overview", diff --git a/apps/.i18n/native/id.json b/apps/.i18n/native/id.json index f02767f95e7..bba123ede3a 100644 --- a/apps/.i18n/native/id.json +++ b/apps/.i18n/native/id.json @@ -2603,11 +2603,31 @@ "source": "Could not start the camera. Choose a QR image from gallery or enter the setup code manually.", "translated": "Kamera tidak dapat dimulai. Pilih gambar QR dari galeri atau masukkan kode penyiapan secara manual." }, + { + "id": "native.android.7a18be21a62739bf", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "translated": "Sertifikat Gateway tidak dapat dibaca secara otomatis. Tempelkan sidik jari SHA-256 yang diperoleh di host Gateway." + }, + { + "id": "native.android.aa489429ad39aa39", + "source": "This gateway now presents a certificate trusted by this device.", + "translated": "Gateway ini sekarang menyajikan sertifikat yang dipercaya oleh perangkat ini." + }, + { + "id": "native.android.b3db82f1162808ad", + "source": "SHA-256 fingerprint", + "translated": "Sidik jari SHA-256" + }, { "id": "native.android.9ac2d4498b17d478", "source": "Trust", "translated": "Percayai" }, + { + "id": "native.android.09245320d3878458", + "source": "Use system trust", + "translated": "Gunakan kepercayaan sistem" + }, { "id": "native.android.e26ee07a1d1911be", "source": "Cancel", @@ -5438,6 +5458,26 @@ "source": "Close Canvas", "translated": "Tutup Canvas" }, + { + "id": "native.android.846fe5afd08b8089", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "translated": "Sertifikat Gateway tidak dapat dibaca secara otomatis. Tempelkan sidik jari SHA-256 yang diperoleh di host Gateway." + }, + { + "id": "native.android.b263dca13f55dad9", + "source": "This gateway now presents a certificate trusted by this device.", + "translated": "Gateway ini sekarang menyajikan sertifikat yang dipercaya oleh perangkat ini." + }, + { + "id": "native.android.dca0f8814b658170", + "source": "SHA-256 fingerprint", + "translated": "Sidik jari SHA-256" + }, + { + "id": "native.android.bb5d50fcdd5ebafe", + "source": "Use system trust", + "translated": "Gunakan kepercayaan sistem" + }, { "id": "native.android.3d83e0755437a5f9", "source": "Overview", diff --git a/apps/.i18n/native/it.json b/apps/.i18n/native/it.json index f132ed21c07..c050de6efd6 100644 --- a/apps/.i18n/native/it.json +++ b/apps/.i18n/native/it.json @@ -2603,11 +2603,31 @@ "source": "Could not start the camera. Choose a QR image from gallery or enter the setup code manually.", "translated": "Impossibile avviare la fotocamera. Scegli un'immagine QR dalla galleria oppure inserisci manualmente il codice di configurazione." }, + { + "id": "native.android.7a18be21a62739bf", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "translated": "Non è stato possibile leggere automaticamente il certificato del Gateway. Incolla l'impronta digitale SHA-256 ottenuta sull'host del Gateway." + }, + { + "id": "native.android.aa489429ad39aa39", + "source": "This gateway now presents a certificate trusted by this device.", + "translated": "Questo Gateway ora presenta un certificato considerato attendibile da questo dispositivo." + }, + { + "id": "native.android.b3db82f1162808ad", + "source": "SHA-256 fingerprint", + "translated": "Impronta digitale SHA-256" + }, { "id": "native.android.9ac2d4498b17d478", "source": "Trust", "translated": "Autorizza" }, + { + "id": "native.android.09245320d3878458", + "source": "Use system trust", + "translated": "Usa l'attendibilità di sistema" + }, { "id": "native.android.e26ee07a1d1911be", "source": "Cancel", @@ -5438,6 +5458,26 @@ "source": "Close Canvas", "translated": "Chiudi Canvas" }, + { + "id": "native.android.846fe5afd08b8089", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "translated": "Non è stato possibile leggere automaticamente il certificato del Gateway. Incolla l'impronta digitale SHA-256 ottenuta sull'host del Gateway." + }, + { + "id": "native.android.b263dca13f55dad9", + "source": "This gateway now presents a certificate trusted by this device.", + "translated": "Questo Gateway ora presenta un certificato considerato attendibile da questo dispositivo." + }, + { + "id": "native.android.dca0f8814b658170", + "source": "SHA-256 fingerprint", + "translated": "Impronta digitale SHA-256" + }, + { + "id": "native.android.bb5d50fcdd5ebafe", + "source": "Use system trust", + "translated": "Usa l'attendibilità di sistema" + }, { "id": "native.android.3d83e0755437a5f9", "source": "Overview", diff --git a/apps/.i18n/native/ja-JP.json b/apps/.i18n/native/ja-JP.json index 4123ac977fb..aa0c113468e 100644 --- a/apps/.i18n/native/ja-JP.json +++ b/apps/.i18n/native/ja-JP.json @@ -2603,11 +2603,31 @@ "source": "Could not start the camera. Choose a QR image from gallery or enter the setup code manually.", "translated": "カメラを起動できませんでした。ギャラリーからQR画像を選択するか、セットアップコードを手動で入力してください。" }, + { + "id": "native.android.7a18be21a62739bf", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "translated": "Gateway証明書を自動的に読み取れませんでした。Gatewayホストで取得したSHA-256フィンガープリントを貼り付けてください。" + }, + { + "id": "native.android.aa489429ad39aa39", + "source": "This gateway now presents a certificate trusted by this device.", + "translated": "このGatewayは現在、このデバイスによって信頼されている証明書を提示しています。" + }, + { + "id": "native.android.b3db82f1162808ad", + "source": "SHA-256 fingerprint", + "translated": "SHA-256フィンガープリント" + }, { "id": "native.android.9ac2d4498b17d478", "source": "Trust", "translated": "信頼" }, + { + "id": "native.android.09245320d3878458", + "source": "Use system trust", + "translated": "システムの信頼設定を使用" + }, { "id": "native.android.e26ee07a1d1911be", "source": "Cancel", @@ -5438,6 +5458,26 @@ "source": "Close Canvas", "translated": "Canvas を閉じる" }, + { + "id": "native.android.846fe5afd08b8089", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "translated": "Gateway証明書を自動的に読み取れませんでした。Gatewayホストで取得したSHA-256フィンガープリントを貼り付けてください。" + }, + { + "id": "native.android.b263dca13f55dad9", + "source": "This gateway now presents a certificate trusted by this device.", + "translated": "このGatewayは現在、このデバイスによって信頼されている証明書を提示しています。" + }, + { + "id": "native.android.dca0f8814b658170", + "source": "SHA-256 fingerprint", + "translated": "SHA-256フィンガープリント" + }, + { + "id": "native.android.bb5d50fcdd5ebafe", + "source": "Use system trust", + "translated": "システムの信頼設定を使用" + }, { "id": "native.android.3d83e0755437a5f9", "source": "Overview", diff --git a/apps/.i18n/native/ko.json b/apps/.i18n/native/ko.json index f57a647f889..9c7f972c81e 100644 --- a/apps/.i18n/native/ko.json +++ b/apps/.i18n/native/ko.json @@ -2603,11 +2603,31 @@ "source": "Could not start the camera. Choose a QR image from gallery or enter the setup code manually.", "translated": "카메라를 시작할 수 없습니다. 갤러리에서 QR 이미지를 선택하거나 설정 코드를 직접 입력하세요." }, + { + "id": "native.android.7a18be21a62739bf", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "translated": "Gateway 인증서를 자동으로 읽을 수 없습니다. Gateway 호스트에서 확인한 SHA-256 지문을 붙여넣으세요." + }, + { + "id": "native.android.aa489429ad39aa39", + "source": "This gateway now presents a certificate trusted by this device.", + "translated": "이제 이 Gateway는 이 기기에서 신뢰하는 인증서를 제공합니다." + }, + { + "id": "native.android.b3db82f1162808ad", + "source": "SHA-256 fingerprint", + "translated": "SHA-256 지문" + }, { "id": "native.android.9ac2d4498b17d478", "source": "Trust", "translated": "신뢰" }, + { + "id": "native.android.09245320d3878458", + "source": "Use system trust", + "translated": "시스템 신뢰 사용" + }, { "id": "native.android.e26ee07a1d1911be", "source": "Cancel", @@ -5438,6 +5458,26 @@ "source": "Close Canvas", "translated": "Canvas 닫기" }, + { + "id": "native.android.846fe5afd08b8089", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "translated": "Gateway 인증서를 자동으로 읽을 수 없습니다. Gateway 호스트에서 확인한 SHA-256 지문을 붙여넣으세요." + }, + { + "id": "native.android.b263dca13f55dad9", + "source": "This gateway now presents a certificate trusted by this device.", + "translated": "이제 이 Gateway는 이 기기에서 신뢰하는 인증서를 제공합니다." + }, + { + "id": "native.android.dca0f8814b658170", + "source": "SHA-256 fingerprint", + "translated": "SHA-256 지문" + }, + { + "id": "native.android.bb5d50fcdd5ebafe", + "source": "Use system trust", + "translated": "시스템 신뢰 사용" + }, { "id": "native.android.3d83e0755437a5f9", "source": "Overview", diff --git a/apps/.i18n/native/nl.json b/apps/.i18n/native/nl.json index 42bd4213774..5b7424cee4b 100644 --- a/apps/.i18n/native/nl.json +++ b/apps/.i18n/native/nl.json @@ -2603,11 +2603,31 @@ "source": "Could not start the camera. Choose a QR image from gallery or enter the setup code manually.", "translated": "Kan de camera niet starten. Kies een QR-afbeelding uit de galerij of voer de installatiecode handmatig in." }, + { + "id": "native.android.7a18be21a62739bf", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "translated": "Het Gateway-certificaat kon niet automatisch worden gelezen. Plak de SHA-256-vingerafdruk die op de Gateway-host is verkregen." + }, + { + "id": "native.android.aa489429ad39aa39", + "source": "This gateway now presents a certificate trusted by this device.", + "translated": "Deze Gateway gebruikt nu een certificaat dat door dit apparaat wordt vertrouwd." + }, + { + "id": "native.android.b3db82f1162808ad", + "source": "SHA-256 fingerprint", + "translated": "SHA-256-vingerafdruk" + }, { "id": "native.android.9ac2d4498b17d478", "source": "Trust", "translated": "Vertrouwen" }, + { + "id": "native.android.09245320d3878458", + "source": "Use system trust", + "translated": "Systeemvertrouwen gebruiken" + }, { "id": "native.android.e26ee07a1d1911be", "source": "Cancel", @@ -5438,6 +5458,26 @@ "source": "Close Canvas", "translated": "Canvas sluiten" }, + { + "id": "native.android.846fe5afd08b8089", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "translated": "Het Gateway-certificaat kon niet automatisch worden gelezen. Plak de SHA-256-vingerafdruk die op de Gateway-host is verkregen." + }, + { + "id": "native.android.b263dca13f55dad9", + "source": "This gateway now presents a certificate trusted by this device.", + "translated": "Deze Gateway gebruikt nu een certificaat dat door dit apparaat wordt vertrouwd." + }, + { + "id": "native.android.dca0f8814b658170", + "source": "SHA-256 fingerprint", + "translated": "SHA-256-vingerafdruk" + }, + { + "id": "native.android.bb5d50fcdd5ebafe", + "source": "Use system trust", + "translated": "Systeemvertrouwen gebruiken" + }, { "id": "native.android.3d83e0755437a5f9", "source": "Overview", diff --git a/apps/.i18n/native/pl.json b/apps/.i18n/native/pl.json index d101d0e9180..8ccb421e19d 100644 --- a/apps/.i18n/native/pl.json +++ b/apps/.i18n/native/pl.json @@ -2603,11 +2603,31 @@ "source": "Could not start the camera. Choose a QR image from gallery or enter the setup code manually.", "translated": "Nie udało się uruchomić aparatu. Wybierz obraz kodu QR z galerii lub wprowadź kod konfiguracji ręcznie." }, + { + "id": "native.android.7a18be21a62739bf", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "translated": "Nie udało się automatycznie odczytać certyfikatu Gateway. Wklej odcisk SHA-256 uzyskany na hoście Gateway." + }, + { + "id": "native.android.aa489429ad39aa39", + "source": "This gateway now presents a certificate trusted by this device.", + "translated": "Ten Gateway używa teraz certyfikatu zaufanego przez to urządzenie." + }, + { + "id": "native.android.b3db82f1162808ad", + "source": "SHA-256 fingerprint", + "translated": "Odcisk SHA-256" + }, { "id": "native.android.9ac2d4498b17d478", "source": "Trust", "translated": "Zaufaj" }, + { + "id": "native.android.09245320d3878458", + "source": "Use system trust", + "translated": "Użyj zaufania systemowego" + }, { "id": "native.android.e26ee07a1d1911be", "source": "Cancel", @@ -5438,6 +5458,26 @@ "source": "Close Canvas", "translated": "Zamknij Canvas" }, + { + "id": "native.android.846fe5afd08b8089", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "translated": "Nie udało się automatycznie odczytać certyfikatu Gateway. Wklej odcisk SHA-256 uzyskany na hoście Gateway." + }, + { + "id": "native.android.b263dca13f55dad9", + "source": "This gateway now presents a certificate trusted by this device.", + "translated": "Ten Gateway używa teraz certyfikatu zaufanego przez to urządzenie." + }, + { + "id": "native.android.dca0f8814b658170", + "source": "SHA-256 fingerprint", + "translated": "Odcisk SHA-256" + }, + { + "id": "native.android.bb5d50fcdd5ebafe", + "source": "Use system trust", + "translated": "Użyj zaufania systemowego" + }, { "id": "native.android.3d83e0755437a5f9", "source": "Overview", diff --git a/apps/.i18n/native/pt-BR.json b/apps/.i18n/native/pt-BR.json index 05ee48479e3..f41e9d494b6 100644 --- a/apps/.i18n/native/pt-BR.json +++ b/apps/.i18n/native/pt-BR.json @@ -2603,11 +2603,31 @@ "source": "Could not start the camera. Choose a QR image from gallery or enter the setup code manually.", "translated": "Não foi possível iniciar a câmera. Escolha uma imagem de QR na galeria ou insira o código de configuração manualmente." }, + { + "id": "native.android.7a18be21a62739bf", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "translated": "Não foi possível ler automaticamente o certificado do Gateway. Cole a impressão digital SHA-256 obtida no host do Gateway." + }, + { + "id": "native.android.aa489429ad39aa39", + "source": "This gateway now presents a certificate trusted by this device.", + "translated": "Este Gateway agora apresenta um certificado confiável para este dispositivo." + }, + { + "id": "native.android.b3db82f1162808ad", + "source": "SHA-256 fingerprint", + "translated": "Impressão digital SHA-256" + }, { "id": "native.android.9ac2d4498b17d478", "source": "Trust", "translated": "Confiar" }, + { + "id": "native.android.09245320d3878458", + "source": "Use system trust", + "translated": "Usar confiança do sistema" + }, { "id": "native.android.e26ee07a1d1911be", "source": "Cancel", @@ -5438,6 +5458,26 @@ "source": "Close Canvas", "translated": "Fechar Canvas" }, + { + "id": "native.android.846fe5afd08b8089", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "translated": "Não foi possível ler automaticamente o certificado do Gateway. Cole a impressão digital SHA-256 obtida no host do Gateway." + }, + { + "id": "native.android.b263dca13f55dad9", + "source": "This gateway now presents a certificate trusted by this device.", + "translated": "Este Gateway agora apresenta um certificado confiável para este dispositivo." + }, + { + "id": "native.android.dca0f8814b658170", + "source": "SHA-256 fingerprint", + "translated": "Impressão digital SHA-256" + }, + { + "id": "native.android.bb5d50fcdd5ebafe", + "source": "Use system trust", + "translated": "Usar confiança do sistema" + }, { "id": "native.android.3d83e0755437a5f9", "source": "Overview", diff --git a/apps/.i18n/native/ru.json b/apps/.i18n/native/ru.json index 7d1b527eab6..efbd3f01cf1 100644 --- a/apps/.i18n/native/ru.json +++ b/apps/.i18n/native/ru.json @@ -2603,11 +2603,31 @@ "source": "Could not start the camera. Choose a QR image from gallery or enter the setup code manually.", "translated": "Не удалось запустить камеру. Выберите изображение QR-кода из галереи или введите код настройки вручную." }, + { + "id": "native.android.7a18be21a62739bf", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "translated": "Не удалось автоматически прочитать сертификат Gateway. Вставьте отпечаток SHA-256, полученный на хосте Gateway." + }, + { + "id": "native.android.aa489429ad39aa39", + "source": "This gateway now presents a certificate trusted by this device.", + "translated": "Теперь этот Gateway предоставляет сертификат, которому доверяет это устройство." + }, + { + "id": "native.android.b3db82f1162808ad", + "source": "SHA-256 fingerprint", + "translated": "Отпечаток SHA-256" + }, { "id": "native.android.9ac2d4498b17d478", "source": "Trust", "translated": "Доверять" }, + { + "id": "native.android.09245320d3878458", + "source": "Use system trust", + "translated": "Использовать системное доверие" + }, { "id": "native.android.e26ee07a1d1911be", "source": "Cancel", @@ -5438,6 +5458,26 @@ "source": "Close Canvas", "translated": "Закрыть Canvas" }, + { + "id": "native.android.846fe5afd08b8089", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "translated": "Не удалось автоматически прочитать сертификат Gateway. Вставьте отпечаток SHA-256, полученный на хосте Gateway." + }, + { + "id": "native.android.b263dca13f55dad9", + "source": "This gateway now presents a certificate trusted by this device.", + "translated": "Теперь этот Gateway предоставляет сертификат, которому доверяет это устройство." + }, + { + "id": "native.android.dca0f8814b658170", + "source": "SHA-256 fingerprint", + "translated": "Отпечаток SHA-256" + }, + { + "id": "native.android.bb5d50fcdd5ebafe", + "source": "Use system trust", + "translated": "Использовать системное доверие" + }, { "id": "native.android.3d83e0755437a5f9", "source": "Overview", diff --git a/apps/.i18n/native/sv.json b/apps/.i18n/native/sv.json index b270e45e54a..a3554ea7e6b 100644 --- a/apps/.i18n/native/sv.json +++ b/apps/.i18n/native/sv.json @@ -2603,11 +2603,31 @@ "source": "Could not start the camera. Choose a QR image from gallery or enter the setup code manually.", "translated": "Det gick inte att starta kameran. Välj en QR-bild från galleriet eller ange konfigurationskoden manuellt." }, + { + "id": "native.android.7a18be21a62739bf", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "translated": "Gateway-certifikatet kunde inte läsas automatiskt. Klistra in SHA-256-fingeravtrycket som hämtats på Gateway-värden." + }, + { + "id": "native.android.aa489429ad39aa39", + "source": "This gateway now presents a certificate trusted by this device.", + "translated": "Denna Gateway använder nu ett certifikat som den här enheten litar på." + }, + { + "id": "native.android.b3db82f1162808ad", + "source": "SHA-256 fingerprint", + "translated": "SHA-256-fingeravtryck" + }, { "id": "native.android.9ac2d4498b17d478", "source": "Trust", "translated": "Lita på" }, + { + "id": "native.android.09245320d3878458", + "source": "Use system trust", + "translated": "Använd systemets förtroende" + }, { "id": "native.android.e26ee07a1d1911be", "source": "Cancel", @@ -5438,6 +5458,26 @@ "source": "Close Canvas", "translated": "Stäng Canvas" }, + { + "id": "native.android.846fe5afd08b8089", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "translated": "Gateway-certifikatet kunde inte läsas automatiskt. Klistra in SHA-256-fingeravtrycket som hämtats på Gateway-värden." + }, + { + "id": "native.android.b263dca13f55dad9", + "source": "This gateway now presents a certificate trusted by this device.", + "translated": "Denna Gateway använder nu ett certifikat som den här enheten litar på." + }, + { + "id": "native.android.dca0f8814b658170", + "source": "SHA-256 fingerprint", + "translated": "SHA-256-fingeravtryck" + }, + { + "id": "native.android.bb5d50fcdd5ebafe", + "source": "Use system trust", + "translated": "Använd systemets förtroende" + }, { "id": "native.android.3d83e0755437a5f9", "source": "Overview", diff --git a/apps/.i18n/native/th.json b/apps/.i18n/native/th.json index 7659399bc61..33ac801273e 100644 --- a/apps/.i18n/native/th.json +++ b/apps/.i18n/native/th.json @@ -2603,11 +2603,31 @@ "source": "Could not start the camera. Choose a QR image from gallery or enter the setup code manually.", "translated": "ไม่สามารถเปิดกล้องได้ โปรดเลือกรูปภาพคิวอาร์จากแกลเลอรีหรือป้อนรหัสตั้งค่าด้วยตนเอง" }, + { + "id": "native.android.7a18be21a62739bf", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "translated": "ไม่สามารถอ่านใบรับรองของ Gateway โดยอัตโนมัติได้ ให้วางลายนิ้วมือ SHA-256 ที่ได้รับจากโฮสต์ Gateway" + }, + { + "id": "native.android.aa489429ad39aa39", + "source": "This gateway now presents a certificate trusted by this device.", + "translated": "ขณะนี้ Gateway นี้แสดงใบรับรองที่อุปกรณ์นี้เชื่อถือ" + }, + { + "id": "native.android.b3db82f1162808ad", + "source": "SHA-256 fingerprint", + "translated": "ลายนิ้วมือ SHA-256" + }, { "id": "native.android.9ac2d4498b17d478", "source": "Trust", "translated": "เชื่อถือ" }, + { + "id": "native.android.09245320d3878458", + "source": "Use system trust", + "translated": "ใช้ความเชื่อถือของระบบ" + }, { "id": "native.android.e26ee07a1d1911be", "source": "Cancel", @@ -5438,6 +5458,26 @@ "source": "Close Canvas", "translated": "ปิด Canvas" }, + { + "id": "native.android.846fe5afd08b8089", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "translated": "ไม่สามารถอ่านใบรับรองของ Gateway โดยอัตโนมัติได้ ให้วางลายนิ้วมือ SHA-256 ที่ได้รับจากโฮสต์ Gateway" + }, + { + "id": "native.android.b263dca13f55dad9", + "source": "This gateway now presents a certificate trusted by this device.", + "translated": "ขณะนี้ Gateway นี้แสดงใบรับรองที่อุปกรณ์นี้เชื่อถือ" + }, + { + "id": "native.android.dca0f8814b658170", + "source": "SHA-256 fingerprint", + "translated": "ลายนิ้วมือ SHA-256" + }, + { + "id": "native.android.bb5d50fcdd5ebafe", + "source": "Use system trust", + "translated": "ใช้ความเชื่อถือของระบบ" + }, { "id": "native.android.3d83e0755437a5f9", "source": "Overview", diff --git a/apps/.i18n/native/tr.json b/apps/.i18n/native/tr.json index 653d509a053..277e2e99c6f 100644 --- a/apps/.i18n/native/tr.json +++ b/apps/.i18n/native/tr.json @@ -2603,11 +2603,31 @@ "source": "Could not start the camera. Choose a QR image from gallery or enter the setup code manually.", "translated": "Kamera başlatılamadı. Galeriden bir QR görseli seçin veya kurulum kodunu manuel olarak girin." }, + { + "id": "native.android.7a18be21a62739bf", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "translated": "Gateway sertifikası otomatik olarak okunamadı. Gateway ana bilgisayarından alınan SHA-256 parmak izini yapıştırın." + }, + { + "id": "native.android.aa489429ad39aa39", + "source": "This gateway now presents a certificate trusted by this device.", + "translated": "Bu Gateway artık bu cihazın güvendiği bir sertifika sunuyor." + }, + { + "id": "native.android.b3db82f1162808ad", + "source": "SHA-256 fingerprint", + "translated": "SHA-256 parmak izi" + }, { "id": "native.android.9ac2d4498b17d478", "source": "Trust", "translated": "Güven" }, + { + "id": "native.android.09245320d3878458", + "source": "Use system trust", + "translated": "Sistem güvenini kullan" + }, { "id": "native.android.e26ee07a1d1911be", "source": "Cancel", @@ -5438,6 +5458,26 @@ "source": "Close Canvas", "translated": "Canvas'ı Kapat" }, + { + "id": "native.android.846fe5afd08b8089", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "translated": "Gateway sertifikası otomatik olarak okunamadı. Gateway ana bilgisayarından alınan SHA-256 parmak izini yapıştırın." + }, + { + "id": "native.android.b263dca13f55dad9", + "source": "This gateway now presents a certificate trusted by this device.", + "translated": "Bu Gateway artık bu cihazın güvendiği bir sertifika sunuyor." + }, + { + "id": "native.android.dca0f8814b658170", + "source": "SHA-256 fingerprint", + "translated": "SHA-256 parmak izi" + }, + { + "id": "native.android.bb5d50fcdd5ebafe", + "source": "Use system trust", + "translated": "Sistem güvenini kullan" + }, { "id": "native.android.3d83e0755437a5f9", "source": "Overview", diff --git a/apps/.i18n/native/uk.json b/apps/.i18n/native/uk.json index b5fc4c381f9..dd6454b9cdc 100644 --- a/apps/.i18n/native/uk.json +++ b/apps/.i18n/native/uk.json @@ -2603,11 +2603,31 @@ "source": "Could not start the camera. Choose a QR image from gallery or enter the setup code manually.", "translated": "Не вдалося запустити камеру. Виберіть зображення QR-коду з галереї або введіть код налаштування вручну." }, + { + "id": "native.android.7a18be21a62739bf", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "translated": "Не вдалося автоматично прочитати сертифікат Gateway. Вставте відбиток SHA-256, отриманий на хості Gateway." + }, + { + "id": "native.android.aa489429ad39aa39", + "source": "This gateway now presents a certificate trusted by this device.", + "translated": "Тепер цей Gateway надає сертифікат, якому довіряє цей пристрій." + }, + { + "id": "native.android.b3db82f1162808ad", + "source": "SHA-256 fingerprint", + "translated": "Відбиток SHA-256" + }, { "id": "native.android.9ac2d4498b17d478", "source": "Trust", "translated": "Довіряти" }, + { + "id": "native.android.09245320d3878458", + "source": "Use system trust", + "translated": "Використовувати системну довіру" + }, { "id": "native.android.e26ee07a1d1911be", "source": "Cancel", @@ -5438,6 +5458,26 @@ "source": "Close Canvas", "translated": "Закрити Canvas" }, + { + "id": "native.android.846fe5afd08b8089", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "translated": "Не вдалося автоматично прочитати сертифікат Gateway. Вставте відбиток SHA-256, отриманий на хості Gateway." + }, + { + "id": "native.android.b263dca13f55dad9", + "source": "This gateway now presents a certificate trusted by this device.", + "translated": "Тепер цей Gateway надає сертифікат, якому довіряє цей пристрій." + }, + { + "id": "native.android.dca0f8814b658170", + "source": "SHA-256 fingerprint", + "translated": "Відбиток SHA-256" + }, + { + "id": "native.android.bb5d50fcdd5ebafe", + "source": "Use system trust", + "translated": "Використовувати системну довіру" + }, { "id": "native.android.3d83e0755437a5f9", "source": "Overview", diff --git a/apps/.i18n/native/vi.json b/apps/.i18n/native/vi.json index 5dcdf0f2298..ae9a0928ab3 100644 --- a/apps/.i18n/native/vi.json +++ b/apps/.i18n/native/vi.json @@ -2603,11 +2603,31 @@ "source": "Could not start the camera. Choose a QR image from gallery or enter the setup code manually.", "translated": "Không thể khởi động camera. Hãy chọn hình ảnh mã QR từ thư viện hoặc nhập mã thiết lập theo cách thủ công." }, + { + "id": "native.android.7a18be21a62739bf", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "translated": "Không thể tự động đọc chứng chỉ của Gateway. Hãy dán dấu vân tay SHA-256 lấy được trên máy chủ Gateway." + }, + { + "id": "native.android.aa489429ad39aa39", + "source": "This gateway now presents a certificate trusted by this device.", + "translated": "Gateway này hiện cung cấp chứng chỉ được thiết bị này tin cậy." + }, + { + "id": "native.android.b3db82f1162808ad", + "source": "SHA-256 fingerprint", + "translated": "Dấu vân tay SHA-256" + }, { "id": "native.android.9ac2d4498b17d478", "source": "Trust", "translated": "Tin cậy" }, + { + "id": "native.android.09245320d3878458", + "source": "Use system trust", + "translated": "Sử dụng độ tin cậy của hệ thống" + }, { "id": "native.android.e26ee07a1d1911be", "source": "Cancel", @@ -5438,6 +5458,26 @@ "source": "Close Canvas", "translated": "Đóng Canvas" }, + { + "id": "native.android.846fe5afd08b8089", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "translated": "Không thể tự động đọc chứng chỉ của Gateway. Hãy dán dấu vân tay SHA-256 lấy được trên máy chủ Gateway." + }, + { + "id": "native.android.b263dca13f55dad9", + "source": "This gateway now presents a certificate trusted by this device.", + "translated": "Gateway này hiện cung cấp chứng chỉ được thiết bị này tin cậy." + }, + { + "id": "native.android.dca0f8814b658170", + "source": "SHA-256 fingerprint", + "translated": "Dấu vân tay SHA-256" + }, + { + "id": "native.android.bb5d50fcdd5ebafe", + "source": "Use system trust", + "translated": "Sử dụng độ tin cậy của hệ thống" + }, { "id": "native.android.3d83e0755437a5f9", "source": "Overview", diff --git a/apps/.i18n/native/zh-CN.json b/apps/.i18n/native/zh-CN.json index 625effa4f1d..86a91a036f9 100644 --- a/apps/.i18n/native/zh-CN.json +++ b/apps/.i18n/native/zh-CN.json @@ -2603,11 +2603,31 @@ "source": "Could not start the camera. Choose a QR image from gallery or enter the setup code manually.", "translated": "无法启动相机。请从图库中选择二维码图片,或手动输入设置代码。" }, + { + "id": "native.android.7a18be21a62739bf", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "translated": "无法自动读取 Gateway 证书。请粘贴在 Gateway 主机上获取的 SHA-256 指纹。" + }, + { + "id": "native.android.aa489429ad39aa39", + "source": "This gateway now presents a certificate trusted by this device.", + "translated": "此 Gateway 现在提供的证书已受此设备信任。" + }, + { + "id": "native.android.b3db82f1162808ad", + "source": "SHA-256 fingerprint", + "translated": "SHA-256 指纹" + }, { "id": "native.android.9ac2d4498b17d478", "source": "Trust", "translated": "信任" }, + { + "id": "native.android.09245320d3878458", + "source": "Use system trust", + "translated": "使用系统信任" + }, { "id": "native.android.e26ee07a1d1911be", "source": "Cancel", @@ -5438,6 +5458,26 @@ "source": "Close Canvas", "translated": "关闭 Canvas" }, + { + "id": "native.android.846fe5afd08b8089", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "translated": "无法自动读取 Gateway 证书。请粘贴在 Gateway 主机上获取的 SHA-256 指纹。" + }, + { + "id": "native.android.b263dca13f55dad9", + "source": "This gateway now presents a certificate trusted by this device.", + "translated": "此 Gateway 现在提供的证书已受此设备信任。" + }, + { + "id": "native.android.dca0f8814b658170", + "source": "SHA-256 fingerprint", + "translated": "SHA-256 指纹" + }, + { + "id": "native.android.bb5d50fcdd5ebafe", + "source": "Use system trust", + "translated": "使用系统信任" + }, { "id": "native.android.3d83e0755437a5f9", "source": "Overview", diff --git a/apps/.i18n/native/zh-TW.json b/apps/.i18n/native/zh-TW.json index f6048f4c5ef..80f75f0fec8 100644 --- a/apps/.i18n/native/zh-TW.json +++ b/apps/.i18n/native/zh-TW.json @@ -2603,11 +2603,31 @@ "source": "Could not start the camera. Choose a QR image from gallery or enter the setup code manually.", "translated": "無法啟動相機。請從相簿選擇 QR 圖片,或手動輸入設定代碼。" }, + { + "id": "native.android.7a18be21a62739bf", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "translated": "無法自動讀取 Gateway 憑證。請貼上從 Gateway 主機取得的 SHA-256 指紋。" + }, + { + "id": "native.android.aa489429ad39aa39", + "source": "This gateway now presents a certificate trusted by this device.", + "translated": "此 Gateway 現在提供的憑證已受此裝置信任。" + }, + { + "id": "native.android.b3db82f1162808ad", + "source": "SHA-256 fingerprint", + "translated": "SHA-256 指紋" + }, { "id": "native.android.9ac2d4498b17d478", "source": "Trust", "translated": "信任" }, + { + "id": "native.android.09245320d3878458", + "source": "Use system trust", + "translated": "使用系統信任設定" + }, { "id": "native.android.e26ee07a1d1911be", "source": "Cancel", @@ -5438,6 +5458,26 @@ "source": "Close Canvas", "translated": "關閉 Canvas" }, + { + "id": "native.android.846fe5afd08b8089", + "source": "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + "translated": "無法自動讀取 Gateway 憑證。請貼上從 Gateway 主機取得的 SHA-256 指紋。" + }, + { + "id": "native.android.b263dca13f55dad9", + "source": "This gateway now presents a certificate trusted by this device.", + "translated": "此 Gateway 現在提供的憑證已受此裝置信任。" + }, + { + "id": "native.android.dca0f8814b658170", + "source": "SHA-256 fingerprint", + "translated": "SHA-256 指紋" + }, + { + "id": "native.android.bb5d50fcdd5ebafe", + "source": "Use system trust", + "translated": "使用系統信任設定" + }, { "id": "native.android.3d83e0755437a5f9", "source": "Overview", diff --git a/apps/android/app/src/main/java/ai/openclaw/app/MainViewModel.kt b/apps/android/app/src/main/java/ai/openclaw/app/MainViewModel.kt index 7b807e37339..480d24a271e 100644 --- a/apps/android/app/src/main/java/ai/openclaw/app/MainViewModel.kt +++ b/apps/android/app/src/main/java/ai/openclaw/app/MainViewModel.kt @@ -1238,8 +1238,12 @@ class MainViewModel private constructor( } } - fun acceptGatewayTrustPrompt() { - runtimeRef.value?.acceptGatewayTrustPrompt() + fun acceptGatewayTrustPrompt(manualFingerprint: String? = null) { + runtimeRef.value?.acceptGatewayTrustPrompt(manualFingerprint) + } + + fun useSystemGatewayTrustPrompt() { + runtimeRef.value?.useSystemGatewayTrustPrompt() } fun declineGatewayTrustPrompt() { diff --git a/apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt b/apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt index 5ed8a8e4c23..41b2566b05a 100644 --- a/apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt +++ b/apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt @@ -45,12 +45,15 @@ import ai.openclaw.app.gateway.GatewayRequestRejected import ai.openclaw.app.gateway.GatewaySession import ai.openclaw.app.gateway.GatewayTlsProbeFailure import ai.openclaw.app.gateway.GatewayTlsProbeResult +import ai.openclaw.app.gateway.GatewayTlsTrustDecision import ai.openclaw.app.gateway.GatewayUpdateAvailableSummary import ai.openclaw.app.gateway.NetworkMonitor import ai.openclaw.app.gateway.NodeEventSendOutcome +import ai.openclaw.app.gateway.decideGatewayTlsTrust import ai.openclaw.app.gateway.formatGatewayAuthority +import ai.openclaw.app.gateway.isGatewayTlsSystemTrustCandidate import ai.openclaw.app.gateway.normalizeGatewayApprovalRequestId -import ai.openclaw.app.gateway.normalizeGatewayTlsFingerprint +import ai.openclaw.app.gateway.normalizeGatewayTlsFingerprintInput import ai.openclaw.app.gateway.parseChatSendAck import ai.openclaw.app.gateway.probeGatewayTlsFingerprint import ai.openclaw.app.i18n.NativeText @@ -798,9 +801,11 @@ class NodeRuntime private constructor( */ data class GatewayTrustPrompt( val endpoint: GatewayEndpoint, - val fingerprintSha256: String, + val fingerprintSha256: String?, val auth: GatewayConnectAuth, val previousFingerprintSha256: String? = null, + val probeFailure: GatewayTlsProbeFailure? = null, + val systemTrustAvailable: Boolean = false, ) data class VoiceE2eSliceResult( @@ -3844,43 +3849,47 @@ class NodeRuntime private constructor( _pendingGatewayTrust.value = null val tls = connectionManager.resolveTlsParams(endpoint) if (tls?.required == true) { - val expectedFingerprint = - tls.expectedFingerprint - ?.let(::normalizeGatewayTlsFingerprint) - ?.takeIf { it.isNotBlank() } + val storedFingerprint = tls.expectedFingerprint setStandaloneGatewayStatus("Verify gateway TLS fingerprint…") scope.launch { val tlsProbe = tlsFingerprintProbe(endpoint.host, endpoint.port) if (!isCurrentConnectAttempt(connectAttemptId)) return@launch - val fp = - tlsProbe.fingerprintSha256 ?: run { - if (expectedFingerprint == null) { - connectingEndpointStableId = null - setStandaloneGatewayStatus(gatewayTlsProbeFailureMessage(tlsProbe.failure)) - } else { - connectAfterTlsCheck(endpoint = endpoint, auth = auth, connectAttemptId = connectAttemptId) - } - return@launch + when ( + val decision = + decideGatewayTlsTrust( + storedFingerprint = storedFingerprint, + systemTrustCandidate = isGatewayTlsSystemTrustCandidate(endpoint.host), + probeResult = tlsProbe, + ) + ) { + GatewayTlsTrustDecision.SystemTrusted -> { + // Automatic platform trust only applies where no user-accepted pin exists. + // Replacing a pin always requires explicit confirmation in the trust prompt. + registerGateway(endpoint, setActive = true) + connectAfterTlsCheck(endpoint = endpoint, auth = auth, connectAttemptId = connectAttemptId) + } + is GatewayTlsTrustDecision.PinnedTrust -> + connectAfterTlsCheck(endpoint = endpoint, auth = auth, connectAttemptId = connectAttemptId) + is GatewayTlsTrustDecision.PromptRequired -> { + decision.probeFailure?.let { setStandaloneGatewayStatus(gatewayTlsProbeFailureMessage(it)) } + publishGatewayTrustPromptIfCurrent( + connectAttemptId = connectAttemptId, + prompt = + GatewayTrustPrompt( + endpoint = endpoint, + fingerprintSha256 = decision.fingerprintSha256, + auth = auth, + previousFingerprintSha256 = decision.previousFingerprintSha256, + probeFailure = decision.probeFailure, + systemTrustAvailable = decision.systemTrustAvailable, + ), + ) + } + is GatewayTlsTrustDecision.Failed -> { + connectingEndpointStableId = null + setStandaloneGatewayStatus(gatewayTlsProbeFailureMessage(decision.reason)) } - val observedFingerprint = - normalizeGatewayTlsFingerprint(fp) - .takeIf { it.isNotBlank() } - ?: fp - val previousFingerprint = expectedFingerprint?.takeUnless { it == observedFingerprint } - if (expectedFingerprint == null || previousFingerprint != null) { - publishGatewayTrustPromptIfCurrent( - connectAttemptId = connectAttemptId, - prompt = - GatewayTrustPrompt( - endpoint = endpoint, - fingerprintSha256 = observedFingerprint, - auth = auth, - previousFingerprintSha256 = previousFingerprint, - ), - ) - return@launch } - connectAfterTlsCheck(endpoint = endpoint, auth = auth, connectAttemptId = connectAttemptId) } return } @@ -4004,13 +4013,30 @@ class NodeRuntime private constructor( ) } - fun acceptGatewayTrustPrompt() { + fun acceptGatewayTrustPrompt(manualFingerprint: String? = null) { val prompt = _pendingGatewayTrust.value ?: return + val acceptedFingerprint = + normalizeGatewayTlsFingerprintInput( + prompt.fingerprintSha256 ?: manualFingerprint ?: return, + ) ?: return gatewayLifecycleIntentSeq.incrementAndGet() launchGatewayLifecycle { if (_pendingGatewayTrust.value != prompt) return@launchGatewayLifecycle _pendingGatewayTrust.value = null - prefs.saveGatewayTlsFingerprint(prompt.endpoint.stableId, prompt.fingerprintSha256) + prefs.saveGatewayTlsFingerprint(prompt.endpoint.stableId, acceptedFingerprint) + registerGateway(prompt.endpoint, setActive = true) + beginConnect(endpoint = prompt.endpoint, auth = prompt.auth) + } + } + + fun useSystemGatewayTrustPrompt() { + val prompt = _pendingGatewayTrust.value ?: return + if (!prompt.systemTrustAvailable) return + gatewayLifecycleIntentSeq.incrementAndGet() + launchGatewayLifecycle { + if (_pendingGatewayTrust.value != prompt) return@launchGatewayLifecycle + _pendingGatewayTrust.value = null + prefs.clearGatewayTlsFingerprint(prompt.endpoint.stableId) registerGateway(prompt.endpoint, setActive = true) beginConnect(endpoint = prompt.endpoint, auth = prompt.auth) } @@ -4025,7 +4051,7 @@ class NodeRuntime private constructor( } } - private fun gatewayTlsProbeFailureMessage(failure: GatewayTlsProbeFailure?): String = + private fun gatewayTlsProbeFailureMessage(failure: GatewayTlsProbeFailure): String = when (failure) { GatewayTlsProbeFailure.TLS_UNAVAILABLE -> nativeText( @@ -4035,7 +4061,7 @@ class NodeRuntime private constructor( nativeText( "Failed: secure endpoint reached, but TLS fingerprint verification timed out. Check Tailscale Serve or gateway TLS and retry.", ).source - GatewayTlsProbeFailure.ENDPOINT_UNREACHABLE, null -> + GatewayTlsProbeFailure.ENDPOINT_UNREACHABLE -> nativeText("Failed: couldn't reach the secure gateway endpoint for this host.").source } diff --git a/apps/android/app/src/main/java/ai/openclaw/app/gateway/GatewayTls.kt b/apps/android/app/src/main/java/ai/openclaw/app/gateway/GatewayTls.kt index ee9673d67ef..2af22dd64b5 100644 --- a/apps/android/app/src/main/java/ai/openclaw/app/gateway/GatewayTls.kt +++ b/apps/android/app/src/main/java/ai/openclaw/app/gateway/GatewayTls.kt @@ -59,10 +59,106 @@ enum class GatewayTlsProbeFailure { data class GatewayTlsProbeResult( val fingerprintSha256: String? = null, val failure: GatewayTlsProbeFailure? = null, + val systemTrusted: Boolean = false, ) +/** Final trust policy selected before opening gateway sessions. */ +sealed interface GatewayTlsTrustDecision { + data object SystemTrusted : GatewayTlsTrustDecision + + data class PinnedTrust( + val fingerprintSha256: String, + ) : GatewayTlsTrustDecision + + data class PromptRequired( + val fingerprintSha256: String?, + val previousFingerprintSha256: String?, + val probeFailure: GatewayTlsProbeFailure? = null, + val systemTrustAvailable: Boolean = false, + ) : GatewayTlsTrustDecision + + data class Failed( + val reason: GatewayTlsProbeFailure, + ) : GatewayTlsTrustDecision +} + internal const val GATEWAY_TLS_PROBE_CONNECT_TIMEOUT_MS = 3_000 internal const val GATEWAY_TLS_PROBE_HANDSHAKE_TIMEOUT_MS = 10_000 +private const val GATEWAY_TLS_FALLBACK_TIMEOUT_FLOOR_MS = 250 + +internal data class GatewayTlsProbeTimeouts( + val connectTimeoutMs: Int, + val handshakeTimeoutMs: Int, +) + +internal fun splitGatewayTlsFallbackProbeTimeouts( + connectTimeoutMs: Int, + handshakeTimeoutMs: Int, + elapsedMs: Long, +): GatewayTlsProbeTimeouts? { + val totalBudgetMs = connectTimeoutMs.toLong() + handshakeTimeoutMs.toLong() + val remainingBudgetMs = (totalBudgetMs - elapsedMs).coerceIn(0, totalBudgetMs) + val minimumBudgetMs = GATEWAY_TLS_FALLBACK_TIMEOUT_FLOOR_MS.toLong() * 2 + if (remainingBudgetMs < minimumBudgetMs) return null + val remainingMs = remainingBudgetMs.coerceAtMost(Int.MAX_VALUE.toLong()).toInt() + val proportionalConnectMs = ((remainingMs.toLong() * connectTimeoutMs) / totalBudgetMs).toInt() + val fallbackConnectMs = + proportionalConnectMs.coerceIn( + GATEWAY_TLS_FALLBACK_TIMEOUT_FLOOR_MS, + remainingMs - GATEWAY_TLS_FALLBACK_TIMEOUT_FLOOR_MS, + ) + return GatewayTlsProbeTimeouts( + connectTimeoutMs = fallbackConnectMs, + handshakeTimeoutMs = remainingMs - fallbackConnectMs, + ) +} + +/** Public-DNS candidates may use Android's CA store and HTTPS hostname validation. */ +internal fun isGatewayTlsSystemTrustCandidate(rawHost: String): Boolean = normalizedGatewayTlsDnsHost(rawHost) != null + +/** Resolves probe evidence and any stored pin into one exhaustive trust decision. */ +internal fun decideGatewayTlsTrust( + storedFingerprint: String?, + systemTrustCandidate: Boolean, + probeResult: GatewayTlsProbeResult, +): GatewayTlsTrustDecision { + val stored = + storedFingerprint + ?.takeIf { it.isNotBlank() } + ?.let(::normalizeGatewayTlsFingerprintInput) + ?: if (storedFingerprint.isNullOrBlank()) { + null + } else { + return GatewayTlsTrustDecision.Failed(probeResult.failure ?: GatewayTlsProbeFailure.TLS_UNAVAILABLE) + } + val observed = + probeResult.fingerprintSha256?.let { raw -> + normalizeGatewayTlsFingerprintInput(raw) + ?: return GatewayTlsTrustDecision.Failed(probeResult.failure ?: GatewayTlsProbeFailure.TLS_UNAVAILABLE) + } + + if (stored == null && systemTrustCandidate && probeResult.systemTrusted) { + return GatewayTlsTrustDecision.SystemTrusted + } + + if (observed != null) { + return if (stored == observed) { + GatewayTlsTrustDecision.PinnedTrust(observed) + } else { + GatewayTlsTrustDecision.PromptRequired( + fingerprintSha256 = observed, + previousFingerprintSha256 = stored, + systemTrustAvailable = stored != null && systemTrustCandidate && probeResult.systemTrusted, + ) + } + } + if (stored != null) return GatewayTlsTrustDecision.PinnedTrust(stored) + return GatewayTlsTrustDecision.PromptRequired( + fingerprintSha256 = null, + previousFingerprintSha256 = null, + probeFailure = probeResult.failure, + ) +} /** Builds a TLS config that supports pinned fingerprints and trust-on-first-use. */ fun buildGatewayTlsConfig( @@ -82,12 +178,13 @@ internal fun buildGatewayTlsConfig( defaultTrust: X509TrustManager, onStore: ((String) -> Unit)? = null, ): GatewayTlsConfig { + val expectedInput = params.expectedFingerprint?.takeIf { it.isNotBlank() } val expected = - params.expectedFingerprint + expectedInput ?.let(::normalizeGatewayTlsFingerprint) ?.takeIf { it.isNotBlank() } val effectiveFingerprint = AtomicReference(expected) - val usesPlatformTrust = expected == null && !params.allowTOFU + val usesPlatformTrust = expectedInput == null && !params.allowTOFU fun recordAcceptedFingerprint(chain: Array) { val certificate = chain.firstOrNull() ?: return @@ -134,7 +231,10 @@ internal fun buildGatewayTlsConfig( ) { if (chain.isEmpty()) throw CertificateException("empty certificate chain") val fingerprint = sha256Hex(chain[0].encoded) - if (expected != null) { + if (expectedInput != null) { + if (expected == null) { + throw CertificateException("invalid gateway TLS fingerprint") + } if (fingerprint != expected) { throw CertificateException("gateway TLS fingerprint mismatch") } @@ -186,7 +286,7 @@ internal fun buildGatewayTlsConfig( val context = SSLContext.getInstance("TLS") context.init(null, arrayOf(trustManager), SecureRandom()) val verifier = - if (expected != null || params.allowTOFU) { + if (expectedInput != null || params.allowTOFU) { // When pinning, we intentionally ignore hostname mismatch (service discovery often yields IPs). HostnameVerifier { _, _ -> true } } else { @@ -200,7 +300,7 @@ internal fun buildGatewayTlsConfig( ) } -/** Connects with a probe trust manager that captures the presented cert hash. */ +/** Uses platform trust for public DNS, otherwise captures the presented cert hash. */ suspend fun probeGatewayTlsFingerprint( host: String, port: Int, @@ -224,6 +324,32 @@ internal suspend fun probeGatewayTlsFingerprint( if (connectTimeoutMs <= 0 || handshakeTimeoutMs <= 0) return GatewayTlsProbeResult(failure = GatewayTlsProbeFailure.ENDPOINT_UNREACHABLE) return withContext(Dispatchers.IO) { + val probeDeadlineNanos = + System.nanoTime() + + (connectTimeoutMs.toLong() + handshakeTimeoutMs.toLong()) * 1_000_000L + var fallbackTimeouts = GatewayTlsProbeTimeouts(connectTimeoutMs, handshakeTimeoutMs) + if (isGatewayTlsSystemTrustCandidate(trimmedHost)) { + val fingerprintSha256 = + probeGatewayTlsSystemTrust( + host = trimmedHost, + port = port, + connectTimeoutMs = connectTimeoutMs, + handshakeTimeoutMs = handshakeTimeoutMs, + ) + if (fingerprintSha256 != null) { + return@withContext GatewayTlsProbeResult(fingerprintSha256 = fingerprintSha256, systemTrusted = true) + } + // One probe budget total, not one budget for each trust attempt. + val totalBudgetMs = connectTimeoutMs.toLong() + handshakeTimeoutMs.toLong() + val remainingBudgetMs = ((probeDeadlineNanos - System.nanoTime()) / 1_000_000L).coerceAtLeast(0) + fallbackTimeouts = + splitGatewayTlsFallbackProbeTimeouts( + connectTimeoutMs = connectTimeoutMs, + handshakeTimeoutMs = handshakeTimeoutMs, + elapsedMs = totalBudgetMs - remainingBudgetMs, + ) ?: return@withContext GatewayTlsProbeResult(failure = GatewayTlsProbeFailure.TLS_HANDSHAKE_TIMEOUT) + } + val fingerprintRef = AtomicReference(null) val probeTrustManager = @SuppressLint("CustomX509TrustManager") @@ -279,8 +405,8 @@ internal suspend fun probeGatewayTlsFingerprint( // TCP reachability and TLS handshake progress fail differently on mobile // tailnets; keep the budgets separate so a reachable-but-slow secure // endpoint does not collapse into generic gateway unreachable guidance. - socket.soTimeout = handshakeTimeoutMs - socket.connect(InetSocketAddress(trimmedHost, port), connectTimeoutMs) + socket.soTimeout = fallbackTimeouts.handshakeTimeoutMs + socket.connect(InetSocketAddress(trimmedHost, port), fallbackTimeouts.connectTimeoutMs) connected = true // Best-effort SNI for hostnames (avoid crashing on IP literals). @@ -335,6 +461,33 @@ internal suspend fun probeGatewayTlsFingerprint( } } +private fun probeGatewayTlsSystemTrust( + host: String, + port: Int, + connectTimeoutMs: Int, + handshakeTimeoutMs: Int, +): String? { + val dnsHost = normalizedGatewayTlsDnsHost(host) ?: return null + val context = SSLContext.getInstance("TLS") + context.init(null, arrayOf(defaultTrustManager()), SecureRandom()) + val socket = context.socketFactory.createSocket() as SSLSocket + return try { + socket.soTimeout = handshakeTimeoutMs + val parameters = socket.sslParameters + parameters.endpointIdentificationAlgorithm = "HTTPS" + parameters.serverNames = listOf(SNIHostName(dnsHost)) + socket.sslParameters = parameters + socket.connect(InetSocketAddress(dnsHost, port), connectTimeoutMs) + socket.startHandshake() + val certificate = socket.session.peerCertificates.firstOrNull() as? X509Certificate ?: return null + sha256Hex(certificate.encoded) + } catch (_: Exception) { + null + } finally { + runCatching { socket.close() } + } +} + private fun defaultTrustManager(): X509TrustManager { val factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()) factory.init(null as java.security.KeyStore?) @@ -352,11 +505,37 @@ private fun sha256Hex(data: ByteArray): String { return out.toString() } -/** Normalizes user-visible fingerprint text to lowercase bare SHA-256 hex. */ -fun normalizeGatewayTlsFingerprint(raw: String): String { +/** Normalizes accepted fingerprint text to lowercase bare SHA-256 hex. */ +fun normalizeGatewayTlsFingerprintInput(raw: String): String? { val stripped = raw .trim() - .replace(Regex("^sha-?256\\s*:?\\s*", RegexOption.IGNORE_CASE), "") - return stripped.lowercase(Locale.US).filter { it in '0'..'9' || it in 'a'..'f' } + .replace(Regex("^sha-?256\\s*:\\s*", RegexOption.IGNORE_CASE), "") + val compact = + stripped + .filterNot { it == ':' || it.isWhitespace() } + .lowercase(Locale.US) + return compact.takeIf { value -> + value.length == 64 && value.all { it in '0'..'9' || it in 'a'..'f' } + } +} + +/** Normalizes internal fingerprint text; invalid values become empty. */ +fun normalizeGatewayTlsFingerprint(raw: String): String = normalizeGatewayTlsFingerprintInput(raw).orEmpty() + +private fun normalizedGatewayTlsDnsHost(rawHost: String): String? { + val trimmed = rawHost.trim() + if (trimmed.startsWith('[') || trimmed.endsWith(']')) return null + val host = trimmed.trimEnd('.').lowercase(Locale.US) + if (host.isEmpty() || host.length > 253 || host.endsWith(".local")) return null + if (host.contains(':')) return null + val labels = host.split('.') + if (labels.size < 2 || labels.any { !isGatewayTlsDnsLabel(it) }) return null + if (labels.all { label -> label.all { it in '0'..'9' } }) return null + return host +} + +private fun isGatewayTlsDnsLabel(label: String): Boolean { + if (label.isEmpty() || label.length > 63 || label.first() == '-' || label.last() == '-') return false + return label.all { it in 'a'..'z' || it in '0'..'9' || it == '-' } } diff --git a/apps/android/app/src/main/java/ai/openclaw/app/i18n/NativeStringResources.kt b/apps/android/app/src/main/java/ai/openclaw/app/i18n/NativeStringResources.kt index 9087ca81a40..f714f6b2ff6 100644 --- a/apps/android/app/src/main/java/ai/openclaw/app/i18n/NativeStringResources.kt +++ b/apps/android/app/src/main/java/ai/openclaw/app/i18n/NativeStringResources.kt @@ -1045,6 +1045,7 @@ internal val nativeStringResourceIds: Map = "Runs" to R.string.native_848f54e89660cea4, "Runs on-device while OpenClaw is visible." to R.string.native_83e2faed20a3cda4, "Runtime" to R.string.native_1093115897879aa3, + "SHA-256 fingerprint" to R.string.native_684889f0079cc145, "SMS" to R.string.native_40b601a10ca536c1, "Save & Connect" to R.string.native_a2f29836cda5ceb1, "Save Changes" to R.string.native_35322b5bb5a218a1, @@ -1231,6 +1232,7 @@ internal val nativeStringResourceIds: Map = "The connected OpenClaw agent can use device capabilities you enable. Continue only if you trust the Gateway and agent you connect to." to R.string.native_d20f43f925e706ce, "The diary is waiting for its first entry." to R.string.native_5fc1927ca948f31c, "The gateway can change this path but cannot clear an existing path." to R.string.native_23a91dbf4886c1f9, + "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host." to R.string.native_385001409de8562a, "The gateway session is coming back online. Agent shortcuts should settle automatically in a moment." to R.string.native_fa4f9ee12d15faec, "The overview refreshes on reconnect and when this screen opens." to R.string.native_d9f641e1a02807cb, "The result for \$slug is unknown. Reconnect, refresh Skills, then retry; the Gateway safely joins a matching install that is still running." to R.string.native_a6a20a23827b4cbd, @@ -1251,6 +1253,7 @@ internal val nativeStringResourceIds: Map = "This folder has no files yet." to R.string.native_027d7c7db6d8b3ef, "This gateway connection needs operator.admin to install ClawHub skills." to R.string.native_f113b3bd283e216c, "This gateway connection needs operator.admin to update skills." to R.string.native_6eddcceb82e4c01f, + "This gateway now presents a certificate trusted by this device." to R.string.native_430df68ec29a85a2, "This gateway sign-in can list connected nodes, but it cannot approve new phone pairing. Pair new phones from a gateway admin session. Node capability approval is separate and still uses nodes approve ." to R.string.native_adca3171c270301a, "This image could not be decoded." to R.string.native_f2da2e47cd31a5dd, "This is taking longer than expected.\nCheck that the Gateway is running and reachable." to R.string.native_af60a38d6b5866ce, @@ -1319,6 +1322,7 @@ internal val nativeStringResourceIds: Map = "Use a secure wss:// or Tailscale Serve Gateway, generate a full-access setup code in the Control UI or with openclaw qr, then scan or paste it below and reconnect to enable settings and upgrades." to R.string.native_57efc4ebe625cab5, "Use only on a trusted private network." to R.string.native_24e1028cd7aef320, "Use setup code" to R.string.native_57666930af1af35e, + "Use system trust" to R.string.native_f4e2076014711222, "Use the Gateway computer's LAN address or secure remote hostname." to R.string.native_1291833ee42d8143, "Use the recovery options below to reconnect." to R.string.native_e330f9d64f5ad4dd, "Use the requestId from the pending command in the approve command." to R.string.native_f41d9e8b7e09aa24, diff --git a/apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt b/apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt index b48c2d8642a..b16dc04ea30 100644 --- a/apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt +++ b/apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt @@ -8,6 +8,7 @@ import ai.openclaw.app.R import ai.openclaw.app.SensitiveFeatureConfig import ai.openclaw.app.gateway.GatewayEndpoint import ai.openclaw.app.gateway.isLocalCleartextGatewayHost +import ai.openclaw.app.gateway.normalizeGatewayTlsFingerprintInput import ai.openclaw.app.hasPhotoReadPermission import ai.openclaw.app.i18n.NativeText import ai.openclaw.app.i18n.nativeString @@ -106,6 +107,7 @@ import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.Icon +import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.TextButton @@ -812,35 +814,77 @@ fun OnboardingFlow( } pendingTrust?.let { prompt -> + val manualEntry = prompt.fingerprintSha256 == null + val systemTrustAvailable = prompt.systemTrustAvailable + var manualFingerprint by + rememberSaveable(prompt.endpoint.stableId, prompt.probeFailure) { + mutableStateOf("") + } + val normalizedManualFingerprint = normalizeGatewayTlsFingerprintInput(manualFingerprint) AlertDialog( onDismissRequest = viewModel::declineGatewayTrustPrompt, containerColor = ClawTheme.colors.surfaceRaised, title = { Text(stringResource(R.string.trust_this_gateway), style = ClawTheme.type.section, color = ClawTheme.colors.text) }, text = { val message = - if (prompt.previousFingerprintSha256.isNullOrBlank()) { - stringResource(R.string.gateway_trust_first_seen, prompt.fingerprintSha256) - } else { - stringResource( - R.string.gateway_trust_changed, - prompt.previousFingerprintSha256, - prompt.fingerprintSha256, + when { + manualEntry -> + nativeString( + "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + ) + prompt.previousFingerprintSha256.isNullOrBlank() -> + stringResource(R.string.gateway_trust_first_seen, prompt.fingerprintSha256) + else -> + stringResource( + R.string.gateway_trust_changed, + prompt.previousFingerprintSha256, + prompt.fingerprintSha256, + ) + } + Column(verticalArrangement = Arrangement.spacedBy(12.dp)) { + Text( + message, + style = ClawTheme.type.body, + color = ClawTheme.colors.textMuted, + ) + if (systemTrustAvailable) { + Text( + nativeString("This gateway now presents a certificate trusted by this device."), + style = ClawTheme.type.body, + color = ClawTheme.colors.textMuted, ) } - Text( - message, - style = ClawTheme.type.body, - color = ClawTheme.colors.textMuted, - ) + if (manualEntry) { + OutlinedTextField( + value = manualFingerprint, + onValueChange = { manualFingerprint = it }, + modifier = Modifier.fillMaxWidth(), + label = { Text(nativeString("SHA-256 fingerprint")) }, + singleLine = true, + ) + } + } }, confirmButton = { - TextButton(onClick = viewModel::acceptGatewayTrustPrompt) { + TextButton( + onClick = { + viewModel.acceptGatewayTrustPrompt(if (manualEntry) normalizedManualFingerprint else null) + }, + enabled = !manualEntry || normalizedManualFingerprint != null, + ) { Text(nativeString("Trust")) } }, dismissButton = { - TextButton(onClick = viewModel::declineGatewayTrustPrompt) { - Text(nativeString("Cancel")) + Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) { + if (systemTrustAvailable) { + TextButton(onClick = viewModel::useSystemGatewayTrustPrompt) { + Text(nativeString("Use system trust")) + } + } + TextButton(onClick = viewModel::declineGatewayTrustPrompt) { + Text(nativeString("Cancel")) + } } }, ) diff --git a/apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt b/apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt index 512c0262d89..99a953b75d0 100644 --- a/apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt +++ b/apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt @@ -17,6 +17,7 @@ import ai.openclaw.app.R import ai.openclaw.app.chat.ChatSessionEntry import ai.openclaw.app.currentAppLanguage import ai.openclaw.app.firstGraphemeOrNull +import ai.openclaw.app.gateway.normalizeGatewayTlsFingerprintInput import ai.openclaw.app.i18n.NativeText import ai.openclaw.app.i18n.joinedNativeText import ai.openclaw.app.i18n.nativeString @@ -99,6 +100,7 @@ import androidx.compose.material.icons.outlined.Terminal import androidx.compose.material3.AlertDialog import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon +import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Scaffold import androidx.compose.material3.Surface import androidx.compose.material3.Text @@ -332,6 +334,7 @@ fun ShellScreen( GatewayTrustDialog( prompt = prompt, onAccept = viewModel::acceptGatewayTrustPrompt, + onUseSystemTrust = viewModel::useSystemGatewayTrustPrompt, onDecline = viewModel::declineGatewayTrustPrompt, ) } @@ -374,18 +377,31 @@ private fun CanvasOverlay( @Composable private fun GatewayTrustDialog( prompt: NodeRuntime.GatewayTrustPrompt, - onAccept: () -> Unit, + onAccept: (String?) -> Unit, + onUseSystemTrust: () -> Unit, onDecline: () -> Unit, ) { + val manualEntry = prompt.fingerprintSha256 == null + val systemTrustAvailable = prompt.systemTrustAvailable + var manualFingerprint by + rememberSaveable(prompt.endpoint.stableId, prompt.probeFailure) { + mutableStateOf("") + } + val normalizedManualFingerprint = normalizeGatewayTlsFingerprintInput(manualFingerprint) val message = - if (prompt.previousFingerprintSha256.isNullOrBlank()) { - stringResource(R.string.gateway_trust_first_seen, prompt.fingerprintSha256) - } else { - stringResource( - R.string.gateway_trust_changed, - prompt.previousFingerprintSha256, - prompt.fingerprintSha256, - ) + when { + manualEntry -> + nativeString( + "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host.", + ) + prompt.previousFingerprintSha256.isNullOrBlank() -> + stringResource(R.string.gateway_trust_first_seen, prompt.fingerprintSha256) + else -> + stringResource( + R.string.gateway_trust_changed, + prompt.previousFingerprintSha256, + prompt.fingerprintSha256, + ) } AlertDialog( @@ -398,15 +414,47 @@ private fun GatewayTrustDialog( color = ClawTheme.colors.text, ) }, - text = { Text(message, style = ClawTheme.type.body, color = ClawTheme.colors.textMuted) }, + text = { + Column(verticalArrangement = Arrangement.spacedBy(12.dp)) { + Text(message, style = ClawTheme.type.body, color = ClawTheme.colors.textMuted) + if (systemTrustAvailable) { + Text( + nativeString("This gateway now presents a certificate trusted by this device."), + style = ClawTheme.type.body, + color = ClawTheme.colors.textMuted, + ) + } + if (manualEntry) { + OutlinedTextField( + value = manualFingerprint, + onValueChange = { manualFingerprint = it }, + modifier = Modifier.fillMaxWidth(), + label = { Text(nativeString("SHA-256 fingerprint")) }, + singleLine = true, + ) + } + } + }, confirmButton = { - TextButton(onClick = onAccept) { + TextButton( + onClick = { + onAccept(if (manualEntry) normalizedManualFingerprint else null) + }, + enabled = !manualEntry || normalizedManualFingerprint != null, + ) { Text(stringResource(R.string.trust_and_continue)) } }, dismissButton = { - TextButton(onClick = onDecline) { - Text(stringResource(R.string.cancel)) + Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) { + if (systemTrustAvailable) { + TextButton(onClick = onUseSystemTrust) { + Text(nativeString("Use system trust")) + } + } + TextButton(onClick = onDecline) { + Text(stringResource(R.string.cancel)) + } } }, ) diff --git a/apps/android/app/src/main/res/values-ar/strings.xml b/apps/android/app/src/main/res/values-ar/strings.xml index 66442ae0d44..513b09d02c1 100644 --- a/apps/android/app/src/main/res/values-ar/strings.xml +++ b/apps/android/app/src/main/res/values-ar/strings.xml @@ -346,6 +346,7 @@ "Conversation Send" "اللوحة" "مزوّد واحد" + "تعذّرت قراءة شهادة Gateway تلقائيًا. الصق بصمة SHA-256 التي حصلت عليها من مضيف Gateway." "فشل الإرسال: %1$s" "الجسر" "خطأ في التسليم" @@ -403,6 +404,7 @@ "Sub-agent" "في انتظار الموافقة على الجهاز" "جارٍ تحميل سلسلة المحادثة" + "يقدّم Gateway هذا الآن شهادة موثوقة من هذا الجهاز." "التداخل بالميلي ثانية" "event create" "مستند" @@ -619,6 +621,7 @@ "Dashboard" "لصق الرمز المميز" "لا يوجد موفرون" + "بصمة SHA-256" "لا توجد سلاسل محادثات بعد" "ميكروفون Bluetooth" "الأخيرة" @@ -1434,6 +1437,7 @@ "الحمولة · %1$s" "قيد التشغيل" "إنهاء" + "استخدام ثقة النظام" "لا يوجد مزوّدون جاهزون" "يعطي الأولوية لميكروفونات Bluetooth المتصلة." "تم حظر %1$s تطبيق من إعادة التوجيه." diff --git a/apps/android/app/src/main/res/values-de/strings.xml b/apps/android/app/src/main/res/values-de/strings.xml index 0d91da3189d..2fbe1b563cf 100644 --- a/apps/android/app/src/main/res/values-de/strings.xml +++ b/apps/android/app/src/main/res/values-de/strings.xml @@ -346,6 +346,7 @@ "Conversation Send" "Canvas" "1 Anbieter" + "Das Gateway-Zertifikat konnte nicht automatisch gelesen werden. Fügen Sie den auf dem Gateway-Host ermittelten SHA-256-Fingerabdruck ein." "Senden fehlgeschlagen: %1$s" "Bridge" "Zustellungsfehler" @@ -403,6 +404,7 @@ "Sub-agent" "Warten auf Gerätefreigabe" "Thread wird geladen" + "Dieses Gateway verwendet jetzt ein Zertifikat, dem dieses Gerät vertraut." "Staffelung in ms" "event create" "Dokument" @@ -619,6 +621,7 @@ "Dashboard" "Token einfügen" "Keine Anbieter" + "SHA-256-Fingerabdruck" "Noch keine Threads" "Bluetooth-Mikrofon" "Zuletzt verwendet" @@ -1434,6 +1437,7 @@ "Nutzdaten · %1$s" "Wird ausgeführt" "Beenden" + "Systemvertrauen verwenden" "Keine Anbieter bereit" "Priorisiert verbundene Bluetooth-Mikrofone." "%1$s App ist für die Weiterleitung blockiert." diff --git a/apps/android/app/src/main/res/values-es/strings.xml b/apps/android/app/src/main/res/values-es/strings.xml index 22242d99f62..cb981fd9667 100644 --- a/apps/android/app/src/main/res/values-es/strings.xml +++ b/apps/android/app/src/main/res/values-es/strings.xml @@ -346,6 +346,7 @@ "Conversation Send" "Lienzo" "1 proveedor" + "No se pudo leer automáticamente el certificado del gateway. Pega la huella digital SHA-256 obtenida en el host del gateway." "Error al enviar: %1$s" "Puente" "Error de entrega" @@ -403,6 +404,7 @@ "Sub-agent" "Esperando la aprobación del dispositivo" "Cargando hilo" + "Este gateway ahora presenta un certificado en el que confía este dispositivo." "Escalonar ms" "event create" "documento" @@ -619,6 +621,7 @@ "Dashboard" "Pegar token" "No hay proveedores" + "Huella digital SHA-256" "Aún no hay hilos" "Micrófono Bluetooth" "Reciente" @@ -1434,6 +1437,7 @@ "Carga útil · %1$s" "En ejecución" "Finalizar" + "Usar la confianza del sistema" "No hay proveedores listos" "Prioriza los micrófonos Bluetooth conectados." "%1$s aplicación bloqueada para el reenvío." diff --git a/apps/android/app/src/main/res/values-fa/strings.xml b/apps/android/app/src/main/res/values-fa/strings.xml index a0656141955..a9e5ba13498 100644 --- a/apps/android/app/src/main/res/values-fa/strings.xml +++ b/apps/android/app/src/main/res/values-fa/strings.xml @@ -346,6 +346,7 @@ "Conversation Send" "بوم" "۱ ارائه‌دهنده" + "گواهی Gateway به‌طور خودکار قابل خواندن نبود. اثر انگشت SHA-256 دریافت‌شده در میزبان Gateway را جای‌گذاری کنید." "ارسال ناموفق بود: %1$s" "پل ارتباطی" "خطای تحویل" @@ -403,6 +404,7 @@ "Sub-agent" "در انتظار تأیید دستگاه" "در حال بارگیری رشته" + "این Gateway اکنون گواهی‌ای ارائه می‌کند که مورد اعتماد این دستگاه است." "میلی‌ثانیه پراکندگی" "event create" "سند" @@ -619,6 +621,7 @@ "Dashboard" "چسباندن توکن" "ارائه‌دهنده‌ای وجود ندارد" + "اثر انگشت SHA-256" "هنوز رشته‌ای وجود ندارد" "میکروفون Bluetooth" "اخیر" @@ -1434,6 +1437,7 @@ "بار داده · %1$s" "در حال اجرا" "پایان" + "استفاده از اعتماد سیستم" "هیچ ارائه‌دهنده آماده‌ای وجود ندارد" "میکروفون‌های Bluetooth متصل را در اولویت قرار می‌دهد." "%1$s برنامه از بازارسال مسدود شده است." diff --git a/apps/android/app/src/main/res/values-fr/strings.xml b/apps/android/app/src/main/res/values-fr/strings.xml index 1d0d2d4bab0..a71b7dbba4e 100644 --- a/apps/android/app/src/main/res/values-fr/strings.xml +++ b/apps/android/app/src/main/res/values-fr/strings.xml @@ -346,6 +346,7 @@ "Conversation Send" "Canevas" "1 fournisseur" + "Le certificat du Gateway n’a pas pu être lu automatiquement. Collez l’empreinte SHA-256 obtenue sur l’hôte du Gateway." "Échec de l’envoi : %1$s" "Pont" "Erreur de livraison" @@ -403,6 +404,7 @@ "Sub-agent" "En attente de l’approbation de l’appareil" "Chargement du fil" + "Ce Gateway présente désormais un certificat approuvé par cet appareil." "Décalage ms" "event create" "document" @@ -619,6 +621,7 @@ "Dashboard" "Coller le jeton" "Aucun fournisseur" + "Empreinte SHA-256" "Aucun fil pour le moment" "Microphone Bluetooth" "Récent" @@ -1434,6 +1437,7 @@ "Charge utile · %1$s" "En cours" "Terminer" + "Utiliser la confiance du système" "Aucun fournisseur prêt" "Donne la priorité aux microphones Bluetooth connectés." "%1$s application empêchée de transférer." diff --git a/apps/android/app/src/main/res/values-hi/strings.xml b/apps/android/app/src/main/res/values-hi/strings.xml index 56924ab6114..81145796b9b 100644 --- a/apps/android/app/src/main/res/values-hi/strings.xml +++ b/apps/android/app/src/main/res/values-hi/strings.xml @@ -346,6 +346,7 @@ "Conversation Send" "कैनवास" "1 प्रदाता" + "Gateway प्रमाणपत्र को स्वचालित रूप से पढ़ा नहीं जा सका। Gateway होस्ट पर प्राप्त SHA-256 फ़िंगरप्रिंट पेस्ट करें।" "भेजना विफल रहा: %1$s" "ब्रिज" "डिलीवरी त्रुटि" @@ -403,6 +404,7 @@ "Sub-agent" "डिवाइस की स्वीकृति की प्रतीक्षा है" "थ्रेड लोड हो रहा है" + "यह Gateway अब इस डिवाइस द्वारा विश्वसनीय प्रमाणपत्र प्रस्तुत करता है।" "विलंब ms" "event create" "दस्तावेज़" @@ -619,6 +621,7 @@ "Dashboard" "टोकन पेस्ट करें" "कोई प्रदाता नहीं" + "SHA-256 फ़िंगरप्रिंट" "अभी तक कोई थ्रेड नहीं" "Bluetooth माइक्रोफ़ोन" "हाल के" @@ -1434,6 +1437,7 @@ "पेलोड · %1$s" "चल रहा है" "समाप्त करें" + "सिस्टम विश्वसनीयता का उपयोग करें" "कोई तैयार प्रोवाइडर नहीं" "कनेक्ट किए गए Bluetooth माइक्रोफ़ोन को प्राथमिकता देता है।" "%1$s ऐप को फ़ॉरवर्ड करने से ब्लॉक किया गया है।" diff --git a/apps/android/app/src/main/res/values-in/strings.xml b/apps/android/app/src/main/res/values-in/strings.xml index 379ab242d26..41459778b09 100644 --- a/apps/android/app/src/main/res/values-in/strings.xml +++ b/apps/android/app/src/main/res/values-in/strings.xml @@ -346,6 +346,7 @@ "Conversation Send" "Kanvas" "1 penyedia" + "Sertifikat Gateway tidak dapat dibaca secara otomatis. Tempelkan sidik jari SHA-256 yang diperoleh di host Gateway." "Gagal mengirim: %1$s" "Jembatan" "Kesalahan Pengiriman" @@ -403,6 +404,7 @@ "Sub-agent" "Menunggu persetujuan perangkat" "Memuat utas" + "Gateway ini sekarang menyajikan sertifikat yang dipercaya oleh perangkat ini." "Jeda ms" "event create" "dokumen" @@ -619,6 +621,7 @@ "Dashboard" "Tempel token" "Tidak ada penyedia" + "Sidik jari SHA-256" "Belum ada utas" "Mikrofon Bluetooth" "Terbaru" @@ -1434,6 +1437,7 @@ "Muatan · %1$s" "Berjalan" "Akhiri" + "Gunakan kepercayaan sistem" "Tidak ada penyedia yang siap" "Memprioritaskan mikrofon Bluetooth yang terhubung." "%1$s aplikasi diblokir agar tidak meneruskan." diff --git a/apps/android/app/src/main/res/values-it/strings.xml b/apps/android/app/src/main/res/values-it/strings.xml index efd231f0915..e9649b0f7f3 100644 --- a/apps/android/app/src/main/res/values-it/strings.xml +++ b/apps/android/app/src/main/res/values-it/strings.xml @@ -346,6 +346,7 @@ "Conversation Send" "Canvas" "1 provider" + "Non è stato possibile leggere automaticamente il certificato del Gateway. Incolla l\'impronta digitale SHA-256 ottenuta sull\'host del Gateway." "Invio non riuscito: %1$s" "Bridge" "Errore di consegna" @@ -403,6 +404,7 @@ "Sub-agent" "In attesa dell\'approvazione del dispositivo" "Caricamento della conversazione" + "Questo Gateway ora presenta un certificato considerato attendibile da questo dispositivo." "Sfalsamento ms" "event create" "documento" @@ -619,6 +621,7 @@ "Dashboard" "Incolla token" "Nessun provider" + "Impronta digitale SHA-256" "Nessun thread" "Microfono Bluetooth" "Recenti" @@ -1434,6 +1437,7 @@ "Payload · %1$s" "In esecuzione" "Termina" + "Usa l\'attendibilità di sistema" "Nessun provider pronto" "Dà priorità ai microfoni Bluetooth connessi." "%1$s app bloccata dall\'inoltro." diff --git a/apps/android/app/src/main/res/values-ja/strings.xml b/apps/android/app/src/main/res/values-ja/strings.xml index 60c7888bcad..81a6dc882da 100644 --- a/apps/android/app/src/main/res/values-ja/strings.xml +++ b/apps/android/app/src/main/res/values-ja/strings.xml @@ -346,6 +346,7 @@ "Conversation Send" "キャンバス" "プロバイダー1件" + "Gateway証明書を自動的に読み取れませんでした。Gatewayホストで取得したSHA-256フィンガープリントを貼り付けてください。" "送信に失敗しました: %1$s" "ブリッジ" "配信エラー" @@ -403,6 +404,7 @@ "Sub-agent" "デバイスの承認を待っています" "スレッドを読み込み中" + "このGatewayは現在、このデバイスによって信頼されている証明書を提示しています。" "ずらしミリ秒" "event create" "ドキュメント" @@ -619,6 +621,7 @@ "Dashboard" "トークンを貼り付け" "プロバイダーがありません" + "SHA-256フィンガープリント" "スレッドはまだありません" "Bluetoothマイク" "最近" @@ -1434,6 +1437,7 @@ "ペイロード · %1$s" "実行中" "終了" + "システムの信頼設定を使用" "準備完了のプロバイダーはありません" "接続されているBluetoothマイクを優先します。" "%1$s 個のアプリの転送をブロックしました。" diff --git a/apps/android/app/src/main/res/values-ko/strings.xml b/apps/android/app/src/main/res/values-ko/strings.xml index 81adec8c889..8cfc78415e0 100644 --- a/apps/android/app/src/main/res/values-ko/strings.xml +++ b/apps/android/app/src/main/res/values-ko/strings.xml @@ -346,6 +346,7 @@ "Conversation Send" "캔버스" "공급자 1개" + "Gateway 인증서를 자동으로 읽을 수 없습니다. Gateway 호스트에서 확인한 SHA-256 지문을 붙여넣으세요." "전송 실패: %1$s" "브리지" "전달 오류" @@ -403,6 +404,7 @@ "Sub-agent" "기기 승인 대기 중" "스레드 불러오는 중" + "이제 이 Gateway는 이 기기에서 신뢰하는 인증서를 제공합니다." "지연 ms" "event create" "문서" @@ -619,6 +621,7 @@ "Dashboard" "토큰 붙여넣기" "제공자 없음" + "SHA-256 지문" "아직 스레드가 없습니다" "Bluetooth 마이크" "최근" @@ -1434,6 +1437,7 @@ "페이로드 · %1$s" "실행 중" "종료" + "시스템 신뢰 사용" "준비된 제공자 없음" "연결된 Bluetooth 마이크를 우선 사용합니다." "%1$s개 앱의 전달이 차단되었습니다." diff --git a/apps/android/app/src/main/res/values-nl/strings.xml b/apps/android/app/src/main/res/values-nl/strings.xml index 4dc056301bb..919ef5c74ac 100644 --- a/apps/android/app/src/main/res/values-nl/strings.xml +++ b/apps/android/app/src/main/res/values-nl/strings.xml @@ -346,6 +346,7 @@ "Conversation Send" "Canvas" "1 provider" + "Het Gateway-certificaat kon niet automatisch worden gelezen. Plak de SHA-256-vingerafdruk die op de Gateway-host is verkregen." "Verzenden mislukt: %1$s" "Brug" "Bezorgfout" @@ -403,6 +404,7 @@ "Sub-agent" "Wachten op apparaatgoedkeuring" "Thread laden" + "Deze Gateway gebruikt nu een certificaat dat door dit apparaat wordt vertrouwd." "Spreiding ms" "event create" "document" @@ -619,6 +621,7 @@ "Dashboard" "Token plakken" "Geen providers" + "SHA-256-vingerafdruk" "Nog geen threads" "Bluetooth-microfoon" "Recent" @@ -1434,6 +1437,7 @@ "Payload · %1$s" "Actief" "Beëindigen" + "Systeemvertrouwen gebruiken" "Geen providers gereed" "Geeft prioriteit aan verbonden Bluetooth-microfoons." "%1$s app is geblokkeerd voor doorsturen." diff --git a/apps/android/app/src/main/res/values-pl/strings.xml b/apps/android/app/src/main/res/values-pl/strings.xml index 74cc3f94fc7..b7024b6c71c 100644 --- a/apps/android/app/src/main/res/values-pl/strings.xml +++ b/apps/android/app/src/main/res/values-pl/strings.xml @@ -346,6 +346,7 @@ "Conversation Send" "Kanwa" "1 dostawca" + "Nie udało się automatycznie odczytać certyfikatu Gateway. Wklej odcisk SHA-256 uzyskany na hoście Gateway." "Wysyłanie nie powiodło się: %1$s" "Most" "Błąd dostarczenia" @@ -403,6 +404,7 @@ "Sub-agent" "Oczekiwanie na zatwierdzenie urządzenia" "Wczytywanie wątku" + "Ten Gateway używa teraz certyfikatu zaufanego przez to urządzenie." "Rozłożenie ms" "event create" "dokument" @@ -619,6 +621,7 @@ "Dashboard" "Wklej token" "Brak dostawców" + "Odcisk SHA-256" "Nie ma jeszcze żadnych wątków" "Mikrofon Bluetooth" "Ostatnie" @@ -1434,6 +1437,7 @@ "Ładunek · %1$s" "Uruchomione" "Zakończ" + "Użyj zaufania systemowego" "Brak gotowych dostawców" "Nadaje priorytet podłączonym mikrofonom Bluetooth." "Zablokowano przekazywanie dla %1$s aplikacji." diff --git a/apps/android/app/src/main/res/values-pt-rBR/strings.xml b/apps/android/app/src/main/res/values-pt-rBR/strings.xml index b5f1f79fefc..11dc3ab4d70 100644 --- a/apps/android/app/src/main/res/values-pt-rBR/strings.xml +++ b/apps/android/app/src/main/res/values-pt-rBR/strings.xml @@ -346,6 +346,7 @@ "Conversation Send" "Canvas" "1 provedor" + "Não foi possível ler automaticamente o certificado do Gateway. Cole a impressão digital SHA-256 obtida no host do Gateway." "Falha no envio: %1$s" "Ponte" "Erro de entrega" @@ -403,6 +404,7 @@ "Sub-agent" "Aguardando aprovação do dispositivo" "Carregando conversa" + "Este Gateway agora apresenta um certificado confiável para este dispositivo." "Escalonamento ms" "event create" "documento" @@ -619,6 +621,7 @@ "Dashboard" "Colar token" "Nenhum provedor" + "Impressão digital SHA-256" "Ainda não há conversas" "Microfone Bluetooth" "Recentes" @@ -1434,6 +1437,7 @@ "Payload · %1$s" "Em execução" "Encerrar" + "Usar confiança do sistema" "Nenhum provedor pronto" "Prioriza microfones Bluetooth conectados." "%1$s app impedido de encaminhar." diff --git a/apps/android/app/src/main/res/values-ru/strings.xml b/apps/android/app/src/main/res/values-ru/strings.xml index f5cba7baf5a..b9a4c153b45 100644 --- a/apps/android/app/src/main/res/values-ru/strings.xml +++ b/apps/android/app/src/main/res/values-ru/strings.xml @@ -346,6 +346,7 @@ "Conversation Send" "Холст" "1 провайдер" + "Не удалось автоматически прочитать сертификат Gateway. Вставьте отпечаток SHA-256, полученный на хосте Gateway." "Не удалось отправить: %1$s" "Мост" "Ошибка доставки" @@ -403,6 +404,7 @@ "Sub-agent" "Ожидание подтверждения устройства" "Загрузка ветки" + "Теперь этот Gateway предоставляет сертификат, которому доверяет это устройство." "Интервал разброса, мс" "event create" "документ" @@ -619,6 +621,7 @@ "Dashboard" "Вставить токен" "Нет провайдеров" + "Отпечаток SHA-256" "Веток пока нет" "Bluetooth-микрофон" "Недавние" @@ -1434,6 +1437,7 @@ "Полезная нагрузка · %1$s" "Выполняется" "Завершить" + "Использовать системное доверие" "Нет готовых провайдеров" "Приоритет отдается подключенным Bluetooth-микрофонам." "Переадресация заблокирована для %1$s приложения." diff --git a/apps/android/app/src/main/res/values-sv/strings.xml b/apps/android/app/src/main/res/values-sv/strings.xml index 99bdcad1cce..2f1e7503a03 100644 --- a/apps/android/app/src/main/res/values-sv/strings.xml +++ b/apps/android/app/src/main/res/values-sv/strings.xml @@ -346,6 +346,7 @@ "Conversation Send" "Arbetsyta" "1 leverantör" + "Gateway-certifikatet kunde inte läsas automatiskt. Klistra in SHA-256-fingeravtrycket som hämtats på Gateway-värden." "Det gick inte att skicka: %1$s" "Brygga" "Leveransfel" @@ -403,6 +404,7 @@ "Sub-agent" "Väntar på enhetsgodkännande" "Läser in tråd" + "Denna Gateway använder nu ett certifikat som den här enheten litar på." "Förskjutning ms" "event create" "dokument" @@ -619,6 +621,7 @@ "Dashboard" "Klistra in token" "Inga leverantörer" + "SHA-256-fingeravtryck" "Inga trådar ännu" "Bluetooth-mikrofon" "Senaste" @@ -1434,6 +1437,7 @@ "Nyttolast · %1$s" "Körs" "Avsluta" + "Använd systemets förtroende" "Inga leverantörer redo" "Prioriterar anslutna Bluetooth-mikrofoner." "%1$s app blockerad från att vidarebefordra." diff --git a/apps/android/app/src/main/res/values-th/strings.xml b/apps/android/app/src/main/res/values-th/strings.xml index 463b82c2fc2..042fd482965 100644 --- a/apps/android/app/src/main/res/values-th/strings.xml +++ b/apps/android/app/src/main/res/values-th/strings.xml @@ -346,6 +346,7 @@ "Conversation Send" "แคนวาส" "ผู้ให้บริการ 1 ราย" + "ไม่สามารถอ่านใบรับรองของ Gateway โดยอัตโนมัติได้ ให้วางลายนิ้วมือ SHA-256 ที่ได้รับจากโฮสต์ Gateway" "ส่งไม่สำเร็จ: %1$s" "บริดจ์" "ข้อผิดพลาดในการส่ง" @@ -403,6 +404,7 @@ "Sub-agent" "กำลังรอการอนุมัติอุปกรณ์" "กำลังโหลดเธรด" + "ขณะนี้ Gateway นี้แสดงใบรับรองที่อุปกรณ์นี้เชื่อถือ" "การหน่วงเหลื่อม ms" "event create" "เอกสาร" @@ -619,6 +621,7 @@ "Dashboard" "วางโทเค็น" "ไม่มีผู้ให้บริการ" + "ลายนิ้วมือ SHA-256" "ยังไม่มีเธรด" "ไมโครโฟน Bluetooth" "ล่าสุด" @@ -1434,6 +1437,7 @@ "เพย์โหลด · %1$s" "กำลังทำงาน" "สิ้นสุด" + "ใช้ความเชื่อถือของระบบ" "ไม่มีผู้ให้บริการที่พร้อมใช้งาน" "ให้ความสำคัญกับไมโครโฟน Bluetooth ที่เชื่อมต่ออยู่" "บล็อกไม่ให้ส่งต่อ %1$s แอป" diff --git a/apps/android/app/src/main/res/values-tr/strings.xml b/apps/android/app/src/main/res/values-tr/strings.xml index 4cf65561c86..c2744b48392 100644 --- a/apps/android/app/src/main/res/values-tr/strings.xml +++ b/apps/android/app/src/main/res/values-tr/strings.xml @@ -346,6 +346,7 @@ "Conversation Send" "Tuval" "1 sağlayıcı" + "Gateway sertifikası otomatik olarak okunamadı. Gateway ana bilgisayarından alınan SHA-256 parmak izini yapıştırın." "Gönderilemedi: %1$s" "Köprü" "Teslim Hatası" @@ -403,6 +404,7 @@ "Sub-agent" "Cihaz onayı bekleniyor" "İleti dizisi yükleniyor" + "Bu Gateway artık bu cihazın güvendiği bir sertifika sunuyor." "Kaydırma ms" "event create" "belge" @@ -619,6 +621,7 @@ "Dashboard" "Token\'ı yapıştır" "Sağlayıcı yok" + "SHA-256 parmak izi" "Henüz ileti dizisi yok" "Bluetooth mikrofonu" "Son" @@ -1434,6 +1437,7 @@ "Veri yükü · %1$s" "Çalışıyor" "Bitir" + "Sistem güvenini kullan" "Hazır sağlayıcı yok" "Bağlı Bluetooth mikrofonlarına öncelik verir." "%1$s uygulamanın yönlendirmesi engellendi." diff --git a/apps/android/app/src/main/res/values-uk/strings.xml b/apps/android/app/src/main/res/values-uk/strings.xml index b9573d887dc..2f99bb07b71 100644 --- a/apps/android/app/src/main/res/values-uk/strings.xml +++ b/apps/android/app/src/main/res/values-uk/strings.xml @@ -346,6 +346,7 @@ "Conversation Send" "Полотно" "1 провайдер" + "Не вдалося автоматично прочитати сертифікат Gateway. Вставте відбиток SHA-256, отриманий на хості Gateway." "Не вдалося надіслати: %1$s" "Міст" "Помилка доставки" @@ -403,6 +404,7 @@ "Sub-agent" "Очікування схвалення пристрою" "Завантаження гілки" + "Тепер цей Gateway надає сертифікат, якому довіряє цей пристрій." "Зсув мс" "event create" "документ" @@ -619,6 +621,7 @@ "Dashboard" "Вставити токен" "Немає постачальників" + "Відбиток SHA-256" "Гілок ще немає" "Bluetooth-мікрофон" "Нещодавні" @@ -1434,6 +1437,7 @@ "Корисне навантаження · %1$s" "Виконується" "Завершити" + "Використовувати системну довіру" "Немає готових провайдерів" "Надає пріоритет підключеним Bluetooth-мікрофонам." "Пересилання заблоковано для %1$s застосунку." diff --git a/apps/android/app/src/main/res/values-vi/strings.xml b/apps/android/app/src/main/res/values-vi/strings.xml index d38953778be..aa95afadf56 100644 --- a/apps/android/app/src/main/res/values-vi/strings.xml +++ b/apps/android/app/src/main/res/values-vi/strings.xml @@ -346,6 +346,7 @@ "Conversation Send" "Bảng vẽ" "1 nhà cung cấp" + "Không thể tự động đọc chứng chỉ của Gateway. Hãy dán dấu vân tay SHA-256 lấy được trên máy chủ Gateway." "Gửi không thành công: %1$s" "Cầu nối" "Lỗi gửi" @@ -403,6 +404,7 @@ "Sub-agent" "Đang chờ phê duyệt thiết bị" "Đang tải luồng" + "Gateway này hiện cung cấp chứng chỉ được thiết bị này tin cậy." "Độ lệch ms" "event create" "tài liệu" @@ -619,6 +621,7 @@ "Dashboard" "Dán token" "Không có nhà cung cấp" + "Dấu vân tay SHA-256" "Chưa có luồng nào" "Micrô Bluetooth" "Gần đây" @@ -1434,6 +1437,7 @@ "Payload · %1$s" "Đang chạy" "Kết thúc" + "Sử dụng độ tin cậy của hệ thống" "Không có nhà cung cấp nào sẵn sàng" "Ưu tiên micrô Bluetooth đã kết nối." "%1$s ứng dụng bị chặn chuyển tiếp." diff --git a/apps/android/app/src/main/res/values-zh-rCN/strings.xml b/apps/android/app/src/main/res/values-zh-rCN/strings.xml index b2277acf927..0de210c7d60 100644 --- a/apps/android/app/src/main/res/values-zh-rCN/strings.xml +++ b/apps/android/app/src/main/res/values-zh-rCN/strings.xml @@ -346,6 +346,7 @@ "Conversation Send" "画布" "1 个提供商" + "无法自动读取 Gateway 证书。请粘贴在 Gateway 主机上获取的 SHA-256 指纹。" "发送失败:%1$s" "桥接" "投递错误" @@ -403,6 +404,7 @@ "Sub-agent" "正在等待设备批准" "正在加载对话" + "此 Gateway 现在提供的证书已受此设备信任。" "错开毫秒数" "event create" "文档" @@ -619,6 +621,7 @@ "Dashboard" "粘贴令牌" "无提供商" + "SHA-256 指纹" "暂无对话" "蓝牙麦克风" "最近" @@ -1434,6 +1437,7 @@ "负载 · %1$s" "运行中" "结束" + "使用系统信任" "没有就绪的提供方" "优先使用已连接的蓝牙麦克风。" "已阻止 %1$s 个应用转发。" diff --git a/apps/android/app/src/main/res/values-zh-rTW/strings.xml b/apps/android/app/src/main/res/values-zh-rTW/strings.xml index 504632d054a..129cdd2a364 100644 --- a/apps/android/app/src/main/res/values-zh-rTW/strings.xml +++ b/apps/android/app/src/main/res/values-zh-rTW/strings.xml @@ -346,6 +346,7 @@ "Conversation Send" "畫布" "1 個提供者" + "無法自動讀取 Gateway 憑證。請貼上從 Gateway 主機取得的 SHA-256 指紋。" "傳送失敗:%1$s" "橋接" "傳送錯誤" @@ -403,6 +404,7 @@ "Sub-agent" "正在等待裝置核准" "正在載入對話串" + "此 Gateway 現在提供的憑證已受此裝置信任。" "錯開毫秒數" "event create" "文件" @@ -619,6 +621,7 @@ "Dashboard" "貼上 token" "沒有提供者" + "SHA-256 指紋" "尚無對話串" "Bluetooth 麥克風" "最近" @@ -1434,6 +1437,7 @@ "承載內容 · %1$s" "執行中" "結束" + "使用系統信任設定" "沒有已就緒的提供者" "優先使用已連線的 Bluetooth 麥克風。" "已封鎖 %1$s 個應用程式進行轉送。" diff --git a/apps/android/app/src/main/res/values/strings.xml b/apps/android/app/src/main/res/values/strings.xml index 386b48d31a1..4dea4d46fdb 100644 --- a/apps/android/app/src/main/res/values/strings.xml +++ b/apps/android/app/src/main/res/values/strings.xml @@ -346,6 +346,7 @@ "Conversation Send" "Canvas" "1 provider" + "The gateway certificate could not be read automatically. Paste the SHA-256 fingerprint obtained on the gateway host." "Send failed: %1$s" "Bridge" "Delivery Error" @@ -403,6 +404,7 @@ "Sub-agent" "Waiting for device approval" "Loading thread" + "This gateway now presents a certificate trusted by this device." "Stagger ms" "event create" "document" @@ -619,6 +621,7 @@ "Dashboard" "Paste token" "No providers" + "SHA-256 fingerprint" "No threads yet" "Bluetooth microphone" "Recent" @@ -1434,6 +1437,7 @@ "Payload · %1$s" "Running" "End" + "Use system trust" "No ready providers" "Prioritizes connected Bluetooth microphones." "%1$s app blocked from forwarding." diff --git a/apps/android/app/src/test/java/ai/openclaw/app/GatewayBootstrapAuthTest.kt b/apps/android/app/src/test/java/ai/openclaw/app/GatewayBootstrapAuthTest.kt index 401f40f2294..4c3fd61e2de 100644 --- a/apps/android/app/src/test/java/ai/openclaw/app/GatewayBootstrapAuthTest.kt +++ b/apps/android/app/src/test/java/ai/openclaw/app/GatewayBootstrapAuthTest.kt @@ -8,6 +8,7 @@ import ai.openclaw.app.gateway.GatewayErrorDetails import ai.openclaw.app.gateway.GatewayRegistryEntry import ai.openclaw.app.gateway.GatewayRegistryEntryKind import ai.openclaw.app.gateway.GatewaySession +import ai.openclaw.app.gateway.GatewayTlsParams import ai.openclaw.app.gateway.GatewayTlsProbeFailure import ai.openclaw.app.gateway.GatewayTlsProbeResult import ai.openclaw.app.node.ConnectionManager @@ -430,7 +431,7 @@ class GatewayBootstrapAuthTest { NodeRuntime( app, prefs, - tlsFingerprintProbe = { _, _ -> GatewayTlsProbeResult(fingerprintSha256 = "fp:1") }, + tlsFingerprintProbe = { _, _ -> GatewayTlsProbeResult(fingerprintSha256 = "ab".repeat(32)) }, ) val explicitAuth = NodeRuntime.GatewayConnectAuth( @@ -445,7 +446,7 @@ class GatewayBootstrapAuthTest { runtime.acceptGatewayTrustPrompt() - assertEquals("f1", prefs.loadGatewayTlsFingerprint(endpoint.stableId)) + assertEquals("ab".repeat(32), prefs.loadGatewayTlsFingerprint(endpoint.stableId)) assertEquals("setup-bootstrap-token", waitForDesiredBootstrapToken(runtime, "nodeSession")) assertNull(desiredBootstrapToken(runtime, "operatorSession")) } @@ -461,12 +462,14 @@ class GatewayBootstrapAuthTest { ) val prefs = SecurePrefs(app, securePrefsOverride = securePrefs) val endpoint = GatewayEndpoint.manual(host = "gateway.example", port = 18789) - prefs.saveGatewayTlsFingerprint(endpoint.stableId, "sha256:aa:aa:aa:aa") + val oldFingerprint = "aa".repeat(32) + val newFingerprint = "bb".repeat(32) + prefs.saveGatewayTlsFingerprint(endpoint.stableId, oldFingerprint) val runtime = NodeRuntime( app, prefs, - tlsFingerprintProbe = { _, _ -> GatewayTlsProbeResult(fingerprintSha256 = "sha256:bb:bb:bb:bb") }, + tlsFingerprintProbe = { _, _ -> GatewayTlsProbeResult(fingerprintSha256 = newFingerprint, systemTrusted = true) }, ) runtime.connect( @@ -475,13 +478,14 @@ class GatewayBootstrapAuthTest { ) val prompt = waitForGatewayTrustPrompt(runtime) - assertEquals("aaaaaaaa", prompt.previousFingerprintSha256) - assertEquals("bbbbbbbb", prompt.fingerprintSha256) - assertEquals("sha256:aa:aa:aa:aa", prefs.loadGatewayTlsFingerprint(endpoint.stableId)) + assertEquals(oldFingerprint, prompt.previousFingerprintSha256) + assertEquals(newFingerprint, prompt.fingerprintSha256) + assertTrue(prompt.systemTrustAvailable) + assertEquals(oldFingerprint, prefs.loadGatewayTlsFingerprint(endpoint.stableId)) runtime.declineGatewayTrustPrompt() - assertEquals("sha256:aa:aa:aa:aa", prefs.loadGatewayTlsFingerprint(endpoint.stableId)) + assertEquals(oldFingerprint, prefs.loadGatewayTlsFingerprint(endpoint.stableId)) runtime.connect( endpoint, @@ -490,9 +494,76 @@ class GatewayBootstrapAuthTest { waitForGatewayTrustPrompt(runtime) runtime.acceptGatewayTrustPrompt() - assertEquals("bbbbbbbb", prefs.loadGatewayTlsFingerprint(endpoint.stableId)) + assertEquals(newFingerprint, prefs.loadGatewayTlsFingerprint(endpoint.stableId)) } + @Test + fun connect_systemTrustedCandidateWithoutStoredPinUsesPlatformTrust() { + val app = RuntimeEnvironment.getApplication() + val securePrefs = + app.getSharedPreferences( + "openclaw.node.secure.test.${UUID.randomUUID()}", + android.content.Context.MODE_PRIVATE, + ) + val prefs = SecurePrefs(app, securePrefsOverride = securePrefs) + val endpoint = GatewayEndpoint.manual(host = "gateway.example", port = 18789) + val runtime = + NodeRuntime( + app, + prefs, + tlsFingerprintProbe = { _, _ -> GatewayTlsProbeResult(fingerprintSha256 = "bb".repeat(32), systemTrusted = true) }, + ) + + runtime.connect( + endpoint, + NodeRuntime.GatewayConnectAuth(token = "test-token-placeholder", bootstrapToken = null, password = null), + ) + + val desired = waitForDesiredConnection(runtime, "nodeSession") + val tls = readField(desired, "tls") + assertNull(tls.expectedFingerprint) + assertNull(prefs.loadGatewayTlsFingerprint(endpoint.stableId)) + assertEquals(endpoint.stableId, prefs.gatewayRegistry.activeStableId.value) + assertNull(runtime.pendingGatewayTrust.value) + } + + @Test + fun connect_systemTrustedChangedPinSwitchClearsPinAndUsesPlatformTrust() { + val app = RuntimeEnvironment.getApplication() + val securePrefs = + app.getSharedPreferences( + "openclaw.node.secure.test.${UUID.randomUUID()}", + android.content.Context.MODE_PRIVATE, + ) + val prefs = SecurePrefs(app, securePrefsOverride = securePrefs) + val endpoint = GatewayEndpoint.manual(host = "gateway.example", port = 18789) + val oldFingerprint = "aa".repeat(32) + val newFingerprint = "bb".repeat(32) + prefs.saveGatewayTlsFingerprint(endpoint.stableId, oldFingerprint) + val runtime = + NodeRuntime( + app, + prefs, + tlsFingerprintProbe = { _, _ -> GatewayTlsProbeResult(fingerprintSha256 = newFingerprint, systemTrusted = true) }, + ) + + runtime.connect( + endpoint, + NodeRuntime.GatewayConnectAuth(token = "test-token-placeholder", bootstrapToken = null, password = null), + ) + + val prompt = waitForGatewayTrustPrompt(runtime) + assertTrue(prompt.systemTrustAvailable) + assertEquals(oldFingerprint, prefs.loadGatewayTlsFingerprint(endpoint.stableId)) + + runtime.useSystemGatewayTrustPrompt() + + val desired = waitForDesiredConnection(runtime, "nodeSession") + val tls = readField(desired, "tls") + assertNull(tls.expectedFingerprint) + assertNull(prefs.loadGatewayTlsFingerprint(endpoint.stableId)) + } + @Test fun connect_ignoresStaleTlsProbeAfterDisconnect() = runBlocking { @@ -504,7 +575,8 @@ class GatewayBootstrapAuthTest { ) val prefs = SecurePrefs(app, securePrefsOverride = securePrefs) val endpoint = GatewayEndpoint.manual(host = "gateway.example", port = 18789) - prefs.saveGatewayTlsFingerprint(endpoint.stableId, "aaaaaaaa") + val fingerprint = "aa".repeat(32) + prefs.saveGatewayTlsFingerprint(endpoint.stableId, fingerprint) val probeStarted = CompletableDeferred() val probeResult = CompletableDeferred() val runtime = @@ -535,13 +607,13 @@ class GatewayBootstrapAuthTest { ?: error("Expected one TLS probe job") runtime.disconnect() - probeResult.complete(GatewayTlsProbeResult(fingerprintSha256 = "aaaaaaaa")) + probeResult.complete(GatewayTlsProbeResult(fingerprintSha256 = fingerprint)) // Join the owning coroutine so assertions run after its stale-attempt guard. probeJob.join() assertNull(runtime.pendingGatewayTrust.value) assertNull(desiredBootstrapToken(runtime, "nodeSession")) - assertEquals("aaaaaaaa", prefs.loadGatewayTlsFingerprint(endpoint.stableId)) + assertEquals(fingerprint, prefs.loadGatewayTlsFingerprint(endpoint.stableId)) } @Test @@ -580,7 +652,7 @@ class GatewayBootstrapAuthTest { runtime.connect(endpoint) probeStarted.await() assertTrue(runtime.forgetGateway(endpoint.stableId)) - probeResult.complete(GatewayTlsProbeResult(fingerprintSha256 = "aaaaaaaa")) + probeResult.complete(GatewayTlsProbeResult(fingerprintSha256 = "aa".repeat(32))) yield() assertNull( @@ -685,7 +757,39 @@ class GatewayBootstrapAuthTest { "Failed: no secure gateway endpoint was detected. Enable gateway TLS or Tailscale Serve, or use a trusted private LAN address with Unencrypted selected.", waitForStatusText(runtime), ) - assertNull(runtime.pendingGatewayTrust.value) + val prompt = waitForGatewayTrustPrompt(runtime) + assertNull(prompt.fingerprintSha256) + assertEquals(GatewayTlsProbeFailure.TLS_UNAVAILABLE, prompt.probeFailure) + } + + @Test + fun connect_enforcesAcceptedManualFingerprintAfterTlsProbeFailure() { + val app = RuntimeEnvironment.getApplication() + val prefs = + SecurePrefs( + app, + app.getSharedPreferences("openclaw.node.secure.test.${UUID.randomUUID()}", android.content.Context.MODE_PRIVATE), + ) + val runtime = + NodeRuntime( + app, + prefs, + tlsFingerprintProbe = { _, _ -> GatewayTlsProbeResult(failure = GatewayTlsProbeFailure.TLS_UNAVAILABLE) }, + ) + val endpoint = GatewayEndpoint.manual(host = "gateway.example", port = 18789) + + runtime.connect( + endpoint, + NodeRuntime.GatewayConnectAuth(token = "test-token-placeholder", bootstrapToken = null, password = null), + ) + waitForGatewayTrustPrompt(runtime) + val manualFingerprint = "cd".repeat(32) + runtime.acceptGatewayTrustPrompt("SHA256: ${manualFingerprint.uppercase()}") + + val desired = waitForDesiredConnection(runtime, "nodeSession") + val tls = readField(desired, "tls") + assertEquals(manualFingerprint, tls.expectedFingerprint) + assertEquals(manualFingerprint, prefs.loadGatewayTlsFingerprint(endpoint.stableId)) } @Test @@ -712,7 +816,9 @@ class GatewayBootstrapAuthTest { "Failed: secure endpoint reached, but TLS fingerprint verification timed out. Check Tailscale Serve or gateway TLS and retry.", waitForStatusText(runtime), ) - assertNull(runtime.pendingGatewayTrust.value) + val prompt = waitForGatewayTrustPrompt(runtime) + assertNull(prompt.fingerprintSha256) + assertEquals(GatewayTlsProbeFailure.TLS_HANDSHAKE_TIMEOUT, prompt.probeFailure) } @Test diff --git a/apps/android/app/src/test/java/ai/openclaw/app/gateway/GatewaySessionCustomHeadersTest.kt b/apps/android/app/src/test/java/ai/openclaw/app/gateway/GatewaySessionCustomHeadersTest.kt index f4a3f45fa7d..61847a5a533 100644 --- a/apps/android/app/src/test/java/ai/openclaw/app/gateway/GatewaySessionCustomHeadersTest.kt +++ b/apps/android/app/src/test/java/ai/openclaw/app/gateway/GatewaySessionCustomHeadersTest.kt @@ -68,7 +68,7 @@ class GatewaySessionCustomHeadersTest { val prefs = SecurePrefs(app, securePrefsOverride = securePrefsBacking) val stableId = "manual|gateway.example|443" val endpoint = GatewayEndpoint.manual(host = "gateway.example", port = 443) - val tls = GatewayTlsParams(required = true, expectedFingerprint = "aa", allowTOFU = false, stableId = stableId) + val tls = GatewayTlsParams(required = true, expectedFingerprint = "aa".repeat(32), allowTOFU = false, stableId = stableId) prefs.saveGatewayCustomHeaders(stableId, mapOf("CF-Access-Client-Id" to "client-id")) securePrefsBacking diff --git a/apps/android/app/src/test/java/ai/openclaw/app/gateway/GatewayTlsTest.kt b/apps/android/app/src/test/java/ai/openclaw/app/gateway/GatewayTlsTest.kt index 2ef99b48f71..0632edad1fb 100644 --- a/apps/android/app/src/test/java/ai/openclaw/app/gateway/GatewayTlsTest.kt +++ b/apps/android/app/src/test/java/ai/openclaw/app/gateway/GatewayTlsTest.kt @@ -2,6 +2,9 @@ package ai.openclaw.app.gateway import kotlinx.coroutines.runBlocking import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertNull +import org.junit.Assert.assertTrue import org.junit.Test import java.net.InetAddress import java.net.ServerSocket @@ -14,6 +17,123 @@ import javax.net.ssl.X509ExtendedTrustManager import kotlin.concurrent.thread class GatewayTlsTest { + @Test + fun splitGatewayTlsFallbackProbeTimeouts_skipsFallbackAfterBudgetExpires() { + assertNull( + splitGatewayTlsFallbackProbeTimeouts( + connectTimeoutMs = 3_000, + handshakeTimeoutMs = 10_000, + elapsedMs = 13_001, + ), + ) + } + + @Test + fun splitGatewayTlsFallbackProbeTimeouts_preservesNearFullBudgetAfterFastFailure() { + val timeouts = + splitGatewayTlsFallbackProbeTimeouts( + connectTimeoutMs = 3_000, + handshakeTimeoutMs = 10_000, + elapsedMs = 50, + ) ?: error("expected fallback timeouts") + + assertEquals(2_988, timeouts.connectTimeoutMs) + assertEquals(9_962, timeouts.handshakeTimeoutMs) + assertEquals(12_950, timeouts.connectTimeoutMs + timeouts.handshakeTimeoutMs) + } + + @Test + fun normalizeGatewayTlsFingerprintInput_acceptsPrefixColonsWhitespaceAndCase() { + val expected = "ab".repeat(32) + val colonSeparated = expected.uppercase().chunked(2).joinToString(":") + + assertEquals(expected, normalizeGatewayTlsFingerprintInput(" SHA256: $colonSeparated\n")) + assertEquals(expected, normalizeGatewayTlsFingerprintInput("sha-256:\t${expected.uppercase()}")) + assertEquals(expected, normalizeGatewayTlsFingerprintInput(expected)) + } + + @Test + fun normalizeGatewayTlsFingerprintInput_rejectsWrongLengthAndGarbage() { + assertNull(normalizeGatewayTlsFingerprintInput("ab".repeat(31))) + assertNull(normalizeGatewayTlsFingerprintInput("ab".repeat(32) + "00")) + assertNull(normalizeGatewayTlsFingerprintInput("sha256: ${"ab".repeat(31)}:gg")) + assertNull(normalizeGatewayTlsFingerprintInput("not-a-fingerprint")) + } + + @Test + fun isGatewayTlsSystemTrustCandidate_classifiesPublicDnsOnly() { + assertFalse(isGatewayTlsSystemTrustCandidate("gateway.local")) + assertFalse(isGatewayTlsSystemTrustCandidate("gateway.local.")) + assertFalse(isGatewayTlsSystemTrustCandidate("192.0.2.10")) + assertFalse(isGatewayTlsSystemTrustCandidate("127.1")) + assertFalse(isGatewayTlsSystemTrustCandidate("[2001:db8::10]")) + assertFalse(isGatewayTlsSystemTrustCandidate("2001:db8::10")) + assertFalse(isGatewayTlsSystemTrustCandidate("[gateway.example.com]")) + assertFalse(isGatewayTlsSystemTrustCandidate("gateway")) + assertTrue(isGatewayTlsSystemTrustCandidate("gateway.example.com")) + assertTrue(isGatewayTlsSystemTrustCandidate("node.tailnet-name.ts.net")) + } + + @Test + fun decideGatewayTlsTrust_coversStoredPinSystemTrustCandidateMatrix() { + val stored = "aa".repeat(32) + val observed = "bb".repeat(32) + for (hasStoredPin in listOf(false, true)) { + for (systemTrusted in listOf(false, true)) { + for (candidate in listOf(false, true)) { + val decision = + decideGatewayTlsTrust( + storedFingerprint = stored.takeIf { hasStoredPin }, + systemTrustCandidate = candidate, + probeResult = GatewayTlsProbeResult(fingerprintSha256 = observed, systemTrusted = systemTrusted), + ) + if (!hasStoredPin && systemTrusted && candidate) { + assertEquals(GatewayTlsTrustDecision.SystemTrusted, decision) + } else { + val prompt = decision as GatewayTlsTrustDecision.PromptRequired + assertEquals(observed, prompt.fingerprintSha256) + assertEquals(stored.takeIf { hasStoredPin }, prompt.previousFingerprintSha256) + assertEquals(hasStoredPin && systemTrusted && candidate, prompt.systemTrustAvailable) + } + } + } + } + } + + @Test + fun decideGatewayTlsTrust_keepsPinWhenSystemTrustDoesNotReplaceIt() { + val stored = "aa".repeat(32) + + assertEquals( + GatewayTlsTrustDecision.PinnedTrust(stored), + decideGatewayTlsTrust( + storedFingerprint = stored, + systemTrustCandidate = true, + probeResult = GatewayTlsProbeResult(fingerprintSha256 = stored, systemTrusted = true), + ), + ) + assertEquals( + GatewayTlsTrustDecision.PinnedTrust(stored), + decideGatewayTlsTrust( + storedFingerprint = stored, + systemTrustCandidate = true, + probeResult = GatewayTlsProbeResult(failure = GatewayTlsProbeFailure.TLS_UNAVAILABLE), + ), + ) + assertEquals( + GatewayTlsTrustDecision.PromptRequired( + fingerprintSha256 = null, + previousFingerprintSha256 = null, + probeFailure = GatewayTlsProbeFailure.TLS_UNAVAILABLE, + ), + decideGatewayTlsTrust( + storedFingerprint = null, + systemTrustCandidate = true, + probeResult = GatewayTlsProbeResult(failure = GatewayTlsProbeFailure.TLS_UNAVAILABLE), + ), + ) + } + @Test fun buildGatewayTlsConfig_exposesNormalizedExpectedRouteFingerprint() { val expected = "ab".repeat(32) @@ -62,6 +182,37 @@ class GatewayTlsTest { assertEquals(0, defaultTrust.serverTwoArgumentCalls) } + @Test + fun buildGatewayTlsConfig_rejectsInvalidStoredFingerprintInsteadOfUsingPlatformTrust() { + val defaultTrust = RecordingExtendedTrustManager() + val config = + buildGatewayTlsConfig( + params = + GatewayTlsParams( + required = true, + expectedFingerprint = "not-a-sha256-fingerprint", + allowTOFU = false, + stableId = "gateway-1", + ), + defaultTrust = defaultTrust, + ) + + val failure = + runCatching { + Socket().use { socket -> + (config.trustManager as X509ExtendedTrustManager).checkServerTrusted( + emptyArray(), + "RSA", + socket, + ) + } + }.exceptionOrNull() + + assertTrue(failure is java.security.cert.CertificateException) + assertEquals(0, defaultTrust.serverSocketCalls) + assertEquals(0, defaultTrust.serverTwoArgumentCalls) + } + @Test fun probeGatewayTlsFingerprint_reportsHandshakeTimeoutAfterTcpConnect() = runBlocking {