> ## Documentation Index
> Fetch the complete documentation index at: https://vibex.peatboy.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Remote v2 與 Relay

> 實現配對、認證、同步和自託管加密傳輸時遵循的協議邊界。

Remote v2 是權威執行階段與客戶端之間的型別化協議。它把業務授權留在權威端，把傳輸路線（Direct、Tailnet、Relay、區域網）當作可替換的基礎設施。

線協議的完整定義在倉庫 `docs/remote/protocol-v2.md`，`crates/core/src/remote_v2.rs` 是 wire 層面的唯一事實源。本頁只覆蓋實現時必須遵守的邊界。

## 兩種配對路徑

Vibex 有兩條形式不同的配對路徑，不要混用：

| 路徑 | 連結形式 | 有效期 | 由誰生成 |
| - | - | - | - |
| 桌面端 SAS offer | `vibex://open/<transport>#/pair/<base64url-offer>` | 60–120 秒 | 桌面端（配對手機） |
| 無頭執行階段配對碼 | `vibex://pair#/code/<base64url-payload>` | 預設 5 分鐘，最長 30 分鐘 | `vibex-server` |

`<transport>` 取值 `direct`、`tailnet` 或 `self_hosted_relay`。

### offer 路徑

* 桌面端身份在執行階段 home 中生成，Unix 下以 `0600` 權限儲存。
* offer 可取消、只能使用一次，其消費與裝置授權的建立在**同一個 SQLite 事務**中完成。
* offer 包含候選路線、桌面公鑰、權限摘要、過期時間和一次性 challenge，**不包含**長期授權、金鑰或工作區資料。
* 行動端在本地解析連結，非同步處理前先剝離 fragment。

### 配對碼路徑

* 九位數字，按 `NNN-NNN-NNN` 分組，由 UUIDv4 派生，**只持久化它的 SHA-256 雜湊**。
* 客戶端在 `POST /api/v2/pairing/code/claim` 宣告配對碼；配對碼**只出現在請求體裡，從不放進 URL**，因此不會進入代理和訪問日誌。
* 該端點與其他未認證路由共享每對端限流和認證失敗預算。
* 宣告是一次性的：重複使用、格式錯誤或已過期會返回 `remote_pairing_code_invalid` / `remote_pairing_code_expired`，並寫入 `pairing_code_rejected` 審計記錄。
* 成功宣告返回**恰好一個**裝置授權，權限級別在建立配對碼時確定。

### 連線串與證書固定

`vibex://pair#/code/<payload>` 的 payload 是一個 JSON 物件：

```json theme={null}
{
  "schemaVersion": "vibex-pairing-code.v1",
  "serverUrl": "https://192.168.1.10:8765",
  "pairingCode": "123-456-789",
  "tlsCertificateDer": "<base64 DER>"
}
```

`tlsCertificateDer` 是可選的。**證書隨連線串帶外傳遞**（來自伺服器控制台，而不是網路），客戶端在發出第一個 TLS 請求之前就固定它，因此區域網自籤場景不需要公共 CA。指紋格式為 `sha256:<base64url(sha256(DER))>`。

固定型連結必須是 `https` 且指向數值型區域網地址（loopback、RFC1918 或鏈路本地 / 唯一本地 IPv6），否則返回 `remote_pairing_link_invalid`。這是有意限制：配對不能變成繞過公網 CA 體系的手段。

伺服器身份金鑰與 TLS 證書**分開**固定，前者從 `/api/v2/info` 的 `serverIdentityPublicKey` 取得。

## 握手和金鑰

實現使用 X25519、HKDF-SHA256、HMAC-SHA256 和 ChaCha20-Poly1305 等成熟原語。

* 連線以 `control/hello` 開始，收到 `control/server_info` 結束握手；協議使用範圍協商，當前選擇 `2.0`。
* WebSocket ticket 有效期 30 秒、單次使用，通過受控 subprotocol 交換，**不放在 URL 中**。
* hello proof 繫結 ticket challenge、完整 hello transcript、伺服器身份、session epoch、裝置身份和客戶端臨時金鑰。
* `server_info` 返回伺服器臨時金鑰和會話金鑰確認。

## 幀型別

| 型別 | 用途 |
| - | - |
| JSON `control` | hello、ping/pong、subscribe、attach/detach、resync、close。 |
| JSON `rpc_request` / `rpc_response` | 帶請求與關聯 id。RPC 超時只結束該請求，不斷開 socket；每條連線有有界 in-flight 上限。 |
| JSON `event` | 攜帶 domain generation 與單調序號。 |
| 二進位制幀 | 以 `VBX2` 開頭，接大端 JSON 頭長度、型別化頭和原始負載。終端機位元組**從不**轉成 UTF-8。 |

未知的 client、control、JSON message、attachment、binary frame、timeout、close 和 transport 列舉值一律解碼為 `unknown`；未知的活動訊息以結構化協議原因關閉，而不是 panic。舊版 `0.4` HTTP 與 `/ws` 路由是相容端點，新客戶端使用 `/ws/v2`。

## RPC、事件和同步

所有業務操作都經過裝置認證、權限和工作區授權。變更使用有界冪等鍵；檔案操作額外使用內容修訂 / CAS。

客戶端發現序號或游標缺口時返回 `resync_required`，並指向一個權威操作重新獲取。附件流在開始前重新認證並授權其 domain；終端機附件帶工作區作用域，終端機輸入需 generation 檢查、授權和審計，**不保留原始位元組**。

裝置授權撤銷後，該裝置的所有活動連線立即收到 `device_revoked`。執行階段關閉時傳送 `server_shutdown`，排空監聽並釋放 socket。

## 權限模型

`RemoteDevicePermissionLevel` 有三個取值，序列化為 `read_only` / `approve_only` / `full_control`：

| 級別 | 允許的操作類 |
| - | - |
| `read_only` | `ReadProject`、`ReadAgentSession`、`ReadProviderSettings`；其餘一律拒絕並審計為 `permission_denied`。 |
| `approve_only` | 上述讀取，加 `ResolvePermission`、`ResolveElicitation`。 |
| `full_control` | 全部 13 類，包含 `MutateAgentSession`、`MutateAgentAuthentication`、`MutateFile`、`MutateGit`、`MutateTerminal`、`MutateProviderSettings`、`ReadDeviceManagement`、`MutateDeviceManagement`。 |

級別在權威端建立 offer / 配對碼時確定，客戶端無法自行提權。

## 閘道器端點

| 端點 | 說明 |
| - | - |
| `/api/v2/info` | 能力、`serverIdentityPublicKey`、`pairingCodeClaimPath`。 |
| `/api/v2/pairing/claim` | offer 宣告。 |
| `/api/v2/pairing/code/claim` | 配對碼宣告。 |
| `/api/v2/pairing/lan`、`/request`、`/status` | 區域網配對。 |
| `/api/v2/ws-ticket` | 換取 WebSocket ticket。 |
| `/ws/v2` | Remote v2 主通道。 |

## Relay 約束

Relay 是一個**零知識房間路由器**：它只轉發不透明加密幀，可以暴露 `/health`、`/api/info` 和 WebSocket bridge 所需的路由後設資料，但**不**執行業務授權、不讀寫工作區、不儲存供應商設定或時間線。

Relay 上的端點是 `/health`、`/api/info`、`/ws`、`/api/rooms/{room_id}/pair|command` 和兩個 `/api/push/*`。**Relay 上沒有 `/api/v2/info`**——那是權威執行階段的端點。

本地檢查：

```bash theme={null}
pnpm smoke:relay:local
cargo test -p vibex-remote-client --test relay_smoke --locked -- --nocapture
```

## 連線策略

客戶端可以在 Direct、Tailnet、Relay 和區域網之間探測和回退。路線恢復後應重新探測並切換，**不需要重複配對**；如果裝置已被撤銷，任何路線都必須失敗。

## 部署

```bash theme={null}
docker compose -f deploy/relay/docker-compose.yml up --build -d relay-server
curl -fsS http://127.0.0.1:9700/health
```

釋出到公網前請配置 HTTPS/WSS、Host/Origin 校驗、連線與房間上限，並閱讀倉庫中的 `docs/smoke/relay-nat.md` 與 `docs/smoke/remote-lan.md`。

## 日誌與證據要求

不要在 Relay 日誌和測試證據中記錄：token、配對碼、私鑰、提示詞、檔案路徑、終端機內容、Git diff、供應商設定、原始密文或 nonce。

Relay 日誌應只包含路由、計數和時序後設資料。


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.