fix: 修复 pairing required - 改用 openclaw-control-ui 客户端 ID 触发静默自动配对

上游源码分析发现根本原因:
- Gateway 的 shouldAllowSilentLocalPairing 需要 isControlUi=true
  才能在本地连接时静默自动批准设备配对
- 我们之前用 gateway-client+backend,isControlUi=false,加上
  Tauri WebView 会发 Origin 头(hasBrowserOriginHeader=true),
  导致 shouldAllowSilentLocalPairing 返回 false → 'pairing required'

修复内容:
- device.rs: client.id 改为 openclaw-control-ui,mode 改为 ui,
  v3 签名 payload 同步更新,本地连接触发静默自动配对
- pairing.rs: paired.json 的 clientId/clientMode 同步更新
- main.js: 启动时自动调用 autoPairDevice(),确保 device 已配对
  + allowedOrigins 已写入,无需用户手动点击一键修复
This commit is contained in:
晴天
2026-03-04 14:39:48 +08:00
parent 7a05625aee
commit 73d7d6e7f5
3 changed files with 13 additions and 8 deletions

View File

@@ -101,8 +101,10 @@ pub fn create_connect_frame(nonce: String, gateway_token: String) -> Result<Valu
let scopes_str = SCOPES.join(",");
// v3 格式v3|deviceId|clientId|clientMode|role|scopes|signedAt|token|nonce|platform|deviceFamily
// 使用 openclaw-control-ui + ui 模式,使 Gateway 识别为 Control UI 客户端,
// 本地连接时触发静默自动配对shouldAllowSilentLocalPairing = true
let payload_str = format!(
"v3|{device_id}|gateway-client|backend|operator|{scopes_str}|{signed_at}|{gateway_token}|{nonce}|{platform}|{device_family}"
"v3|{device_id}|openclaw-control-ui|ui|operator|{scopes_str}|{signed_at}|{gateway_token}|{nonce}|{platform}|{device_family}"
);
let signature = signing_key.sign(payload_str.as_bytes());
@@ -116,11 +118,11 @@ pub fn create_connect_frame(nonce: String, gateway_token: String) -> Result<Valu
"minProtocol": 3,
"maxProtocol": 3,
"client": {
"id": "gateway-client",
"id": "openclaw-control-ui",
"version": "1.0.0",
"platform": platform,
"deviceFamily": device_family,
"mode": "backend"
"mode": "ui"
},
"role": "operator",
"scopes": SCOPES,

View File

@@ -62,8 +62,8 @@ pub fn auto_pair_device() -> Result<String, String> {
"deviceId": device_id,
"publicKey": public_key,
"platform": "desktop",
"clientId": "gateway-client",
"clientMode": "backend",
"clientId": "openclaw-control-ui",
"clientMode": "ui",
"role": "operator",
"roles": ["operator"],
"scopes": [

View File

@@ -78,9 +78,12 @@ async function autoConnectWebSocket() {
const port = config?.gateway?.port || 18789
const token = config?.gateway?.auth?.token || ''
if (!token) {
console.warn('[main] Gateway token 未设置,跳过 WebSocket 连接')
return
// 启动前先确保设备已配对 + allowedOrigins 已写入,无需用户手动操作
try {
await api.autoPairDevice()
console.log('[main] 设备配对 + origins 已就绪')
} catch (pairErr) {
console.warn('[main] autoPairDevice 失败(非致命):', pairErr)
}
wsClient.connect(`127.0.0.1:${port}`, token)