remote.文件首頁

初始化、裝置二維碼與六位碼登入

Agent 預設 Exchange 為 wss://exchange.ivjn.us,CLI/Console 管理 API 地址為 https://exchange.ivjn.us。原有配置優先,不會覆蓋自建 Exchange 地址。

SaaS 註冊與首次登入

remote-cli register --username alice --email alice@example.com
# 按隐藏输入提示设置密码,注册后向邮箱发送验证码。
remote-cli verify-email --username alice
# 隐藏输入邮件中的 8 位数字验证码,然后登录。
remote-cli login --email alice@example.com
# init 是 login 的别名,不带 --email 时交互输入邮箱和密码。
remote-cli init
# 原有令牌仍可使用:
remote-cli login --server https://exchange.ivjn.us --token-stdin

註冊與登入預設連線 https://exchange.ivjn.us,自建服務可加 --server。登入以郵箱為賬號身份,地址會去空格並轉成小寫,格式不合法會直接拒絕。使用者名稱是註冊時的工作區名稱(3-64 位字母、數字或 ._-)。帳號密碼不設長度或字元格式限制;伺服器僅儲存密碼雜湊。自動化可使用 --password-stdin,不要把密碼寫進命令引數。新賬號驗證郵箱前不能登入。CLI 只儲存返回的會話令牌,不儲存密碼,註冊等待驗證期間保留已有登入。

每次註冊建立獨立工作區,賬號是該工作區的管理員。裝置、成員、遠端會話、指標和審計均隔離,不同工作區可使用相同裝置 ID。六位碼批准會把裝置或新成員加入批准人的工作區。加入已有工作區應使用該管理員提供的令牌或六位碼授權。

Android Console 同樣支援註冊、密碼登入、已有令牌登入和六位碼登入。密碼只用於當前請求,憑證仍儲存到 SecureStore。

密碼登入會話有效期 30 天,每個賬號最多 32 個有效會話;重複登入不擠掉其他客戶端。POST /api/auth/logout 使用當前 Bearer 會話令牌登出,已建立的 WebSocket 最多 5 秒內關閉;到期後重新登入。裝置與原有運維令牌保留原生命週期。

純令牌身份沒有密碼帳號,不能透過郵箱找回。當前不包含計費或跨例項 WebSocket 路由。

郵箱驗證與密碼找回

remote-cli resend-verification --email alice@example.com
remote-cli verify-email --username alice
remote-cli forgot-password --email alice@example.com
remote-cli reset-password --email alice@example.com
# 按提示输入邮件验证码、新密码,再重新登录。

# 已登录的旧密码账号绑定或更换邮箱,需要再次验证当前密码。
remote-cli set-email --email alice@example.com
remote-cli verify-email --username alice

驗證與找回使用不同用途的 8 位數字驗證碼,15 分鐘有效,連續輸錯 5 次後失效,重新發信會使舊碼失效;每個賬號每種用途一分鐘內只能發一次。驗證與重置命令可用 --code 自動化,預設隱藏輸入驗證碼。重置成功會撤銷該賬號的全部登入會話,已建立的 WebSocket 最多 5 秒內斷開;不影響工作區內其他成員和裝置。

Console 註冊頁填寫郵箱,隨後進入驗證頁;登入頁提供 驗證郵箱 和 忘記密碼。更換郵箱在驗證完成前保留原地址。重發驗證和找回請求返回統一提示,不暴露郵箱是否已註冊。

郵件功能需要遷移 0004_email.sql 和 SMTP 配置:SMTP_HOST、SMTP_PORT、SMTP_FROM、SMTP_USERNAME、SMTP_PASSWORD、SMTP_SECURITY。預設 STARTTLS,支援隱式 TLS;非加密 SMTP 僅允許本地測試迴環地址。SMTP 憑據放服務環境檔案,不提交到 Git。不配置郵件服務時,新版註冊和發信介面返回 503,既有賬號登入不受影響,因此生產啟用前必須完成發信配置。SMTP 暫時失敗可能留下待驗證賬號,恢復後使用重發驗證郵件,不必重複註冊。

Exchange 賬號 API

方法與路徑 鑑權 用途
POST /api/auth/register 無,限流 {username,password,email},建立待驗證賬號,返回 202 和 verification_required,不簽發會話
POST /api/auth/login 無,限流 {email,password},簽發獨立登入會話
GET /api/auth/me 運維令牌或登入會話 返回 name、tenant_id、role
POST /api/auth/logout 當前登入會話 撤銷當前會話;不撤銷其他客戶端
POST /api/auth/verify-email 無,限流 {username,code},消費郵箱驗證碼
POST /api/auth/resend-verification 無,限流 {email},向待驗證地址重發郵件
POST /api/auth/forgot-password 無,限流 {email},向已驗證地址傳送找回驗證碼
POST /api/auth/reset-password 無,限流 {email,code,password},修改密碼並撤銷舊會話
POST /api/auth/email 當前登入會話和賬號密碼 {email,password},申請繫結或更換郵箱,驗證後生效

登入成功返回 username、email(若已繫結)、tenant_id、token、expires_in,並設定 Cache-Control: no-store。賬號密碼使用 Argon2id 預設引數加鹽儲存;每個 TCP 來源 IP 每分鐘最多 20 次賬號請求,每個使用者名稱每分鐘最多 10 次,密碼雜湊併發最多 4 個。不信任客戶端提供的轉發 IP;反向代理後的客戶端共享 IP 配額,公共部署應在可信入口配置額外限流。

Rust Exchange 預設關閉公開註冊。須明確設定 EXCHANGE_ALLOW_REGISTRATION=true 並設定 SMTP 才能啟用;false 關閉新註冊,已有帳號仍可登入。

讓 Agent 顯示六位碼

Android Remote Agent:預設地址已填好,點選 Connect with a six-digit code。應用會顯示一個 5 分鐘有效的六位碼。在已登入的管理員 CLI 上執行:

remote-cli pair 012345
# 可选:覆盖默认 ID 和显示名称
remote-cli pair 012345 --device-id my-android --name "我的手机"

CLI 獲取連線碼時顯示裝置名、身份型別和建議裝置 ID,確認是自己的裝置後授權。預設 ID 使用裝置名的小寫 ASCII 字母、數字和 ._-,去掉空格及其他字元;無可用字元時使用 device,最多 64 字元。同一工作區重名時依次追加數字,例如 realmev5、realmev51、realmev52,必要時截短基礎 ID。Exchange 在建立時處理併發衝突,CLI 列印最終分配的 ID;手動指定的 ID 重名也追加數字。Android 使用系統裝置名(不可用時使用型號),原生 Agent 使用主機名。Agent 自動取得獨立裝置令牌、加密儲存並啟動連線。不會自動開啟輔助功能或螢幕控制。取消、過期或鑑權失敗不會替換已有配置;Agent 正在連線時需先停止。

電腦、路由器與 Linux Agent 新增裝置

Windows、macOS、OpenWrt、Linux Agent 無需手工填寫裝置令牌,任選一種方式:

平臺 方式一:配對碼 / 裝置二維碼 方式二:貼上邀請
Windows / macOS(桌面 --ui,雙擊啟動) 本地頁面 Add this device → Get pairing code,顯示六位碼和二維碼 本地頁面 Invite 文字框貼上後點 Join with invite
OpenWrt(luci-app-remote) LuCI 服務 → 遠端管理 → 新增裝置 → 獲取配對碼,顯示六位碼和二維碼 同頁 方式二:邀請內容 貼上後點 加入
Linux / 所有平臺命令列 remote-agent pair(終端顯示六位碼和字元二維碼) remote-agent join '<邀请内容>',或 remote-agent join - 從標準輸入讀取

方式一:Agent 申請 5 分鐘有效的六位碼,同時顯示二維碼,內容為 remote://pair?code=012345&server=wss%3A%2F%2Fexchange.ivjn.us(不含任何憑證)。管理員任選: Android Console 新增裝置 → 輸入配對碼 → 掃描裝置二維碼(相機掃描,核對服務端一致後查詢並確認批准);或輸入六位碼;Web Console 批准配對碼 可輸入六位碼或貼上 remote://pair?...;或 remote-cli pair 012345(也接受該 URI)。批准後 Agent 自動儲存令牌並連線。

方式二:管理員在 Android Console 新增裝置 → 掃碼新增 生成一次性邀請,點選 複製邀請(電腦 / 路由器貼上);或執行 remote-cli qr --device-id pc-01 --text。邀請是二維碼中的 JSON({"type":"remote-enrollment",...}),5 分鐘內有效、只能使用一次。也接受裝置令牌二維碼(remote-cli device qr)的內容。

儲存位置與連線:

  • 桌面 UI:寫入當前配置檔案(預設 %LOCALAPPDATA%\remote-agent\config.json / ~/.config/remote-agent/config.json)並立即連線。
  • OpenWrt:寫入 UCI remote-agent.main(server / device_id / token,enabled=1),再重啟 procd 服務。
  • 命令列:預設寫入桌面配置路徑(OpenWrt 預設寫 UCI),--config PATH 指定 JSON 檔案,--uci 強制寫 UCI;儲存後在前臺連線(--no-connect 只儲存)。如已有服務在用該配置,請重啟服務。

已配置憑證時預設拒絕替換:命令列需 --force,桌面 UI 與 LuCI 會先確認。已有的令牌方式(--device-id/--token、配置檔案、LuCI 設定頁)不變。

remote-agent pair                       # 显示六位码 + 二维码,批准后保存并连接
remote-agent pair --server wss://your-exchange.example.com --config ./agent.json
remote-agent join '{"type":"remote-enrollment","version":1,...}'
remote-agent join - < invite.txt --no-connect

原生配對要求 wss://,僅本機迴環允許 ws:// 以便測試;Android 和 Console 配對要求 HTTPS/WSS。

Console 六位碼登入

Android Remote Console 登入頁點選 使用六位碼登入;Web Console(/console)登入卡片選擇 六位碼 標籤,點選獲取登入碼。管理員可任選其一批准:

remote-cli pair 012345 --operator-name mobile-alice
# 只读客户端:追加 --role readonly

或在已登入的 Web Console 工作空間點選 批准配對碼(僅管理員可見;只讀操作員無此入口),輸入對方螢幕上的六位碼,核對型別與標籤後批准。

預設建立獨立 operator 賬號,不復制管理員自身的令牌。管理員可明確指定 --role admin 或 --role readonly。Android Console 收到授權後再次驗證憑證,儲存到 SecureStore 並進入裝置列表;Web Console 將操作員憑證保留在當前頁面記憶體中(與賬號 / 令牌登入相同),進入裝置列表。取消或失敗時仍可使用原有賬號或令牌登入,不會清掉後續其他登入方式的輸入。

Remote Agent 掃 CLI 碼登入

remote-cli qr --device-id my-phone
# 输出 SVG 供手机扫描:
remote-cli qr --device-id my-phone --output ./phone-login.svg

在已登入管理員 CLI 上生成二維碼,手機 Remote Agent 點選 Scan connection QR code,確認服務端和裝置 ID 後點選 Connect。二維碼只攜帶隨機 256 位臨時票據,5 分鐘有效,只能繫結一臺裝置,不含長期裝置令牌。掃描後由 Exchange 簽發裝置令牌,手機透過 Keystore 儲存並連線。二維碼對應的裝置 ID 必須是新的;不會替換或輪換已有裝置。

相同手機領取請求攜帶固定隨機 claim_id,網路斷開後重試可以取回同一結果;不同 claim_id 不能重複領取。儲存後手機確認清除票據。臨時票據在程序記憶體中儲存,Exchange 重啟會失效;已開始領取的結果另保留最多 5 分鐘供原客戶端重試。

方法與路徑 鑑權 用途
POST /api/pairing/invite 管理員 {device_id,name?},生成票據,限制每管理員每分鐘 10 次、全域性 256 個
POST /api/pairing/claim Bearer <ticket> {claim_id},返回獨立裝置憑證;重試必須沿用同一 32 位十六進位制 claim_id
POST /api/pairing/claim/complete 同上 儲存成功後確認清除

生成裝置二維碼

# 创建设备,同时在终端显示二维码
remote-cli device add my-android --qr
# 新建 SVG 文件,可在电脑打开后供手机扫描
remote-cli device add another-phone --qr-output ./another-phone.svg
# 使用手里已有的设备令牌,不创建或轮换设备
remote-cli device qr my-android --output ./my-android.svg
# 明确轮换令牌并生成二维码;原令牌立即失效
remote-cli device rotate-token my-android --qr

device qr 以隱藏輸入讀取裝置令牌,也支援 --token-stdin。裝置二維碼只包含裝置令牌,不能使用運維令牌。輸出檔案拒絕覆蓋,包含憑證,應妥善保管並在使用後刪除。二維碼要求 HTTPS/WSS。

Android Console:建立新裝置後會直接顯示裝置二維碼;裝置詳情的 輪換令牌並生成二維碼 會先說明斷線影響並要求確認。服務端只儲存令牌雜湊,不能從已存在的裝置記錄恢復舊二維碼,因此不會為了檢視二維碼而靜默輪換令牌。

Exchange 配對 API

方法與路徑 鑑權 用途
POST /api/pairing/start 無,限流 提交 kind: device/operator、label,取得 code、poll_token、expires_in: 300、interval: 3
GET /api/pairing/{code} 管理員運維令牌 檢視申請型別、標籤和剩餘時間,不返回憑證
POST /api/pairing/approve 管理員運維令牌 提交 code、kind、identity、可選 name、role,建立獨立裝置或賬號
POST /api/pairing/poll Authorization: Bearer <poll_token> 返回 pending 或 approved;批准結果含 credentials.kind/identity/token
POST /api/pairing/complete 同上 客戶端儲存成功後清除臨時授權;重複呼叫安全
GET /ws/pairing 無,限流 原生 Agent 配對 WebSocket,依次接收 code、approved 或 expired 事件,儲存後傳送文字 complete

六位碼只用來讓已認證管理員定位並確認請求,不能用來輪詢或換取憑證。輪詢憑證為隨機 256 位秘密,不放入 URL。重複批准被拒絕;身份建立失敗會釋放授權佔用以便重試。批准結果可在同一私有輪詢憑證下重讀,避免一次網路丟包導致憑證永久丟失;客戶端儲存後確認清除。

等待授權與批准待領取分別最多保留 5 分鐘。未配置 REDIS_URL 時,臨時會話只儲存在當前 Exchange 程序記憶體中,重啟後需重新領碼,多例項需把配對請求固定到同一例項。配置了 Redis 後,配對條目與限流計數寫入 Redis(與 5 分鐘 TTL 對齊),多例項可任意分發、不必粘性。每個實際 TCP 來源 IP 每分鐘最多領取 10 次,管理員每分鐘最多查詢或批准 20 次;記憶體模式另有全域性最多 256 個待處理會話的上限。代理轉發的客戶端 IP 不作為可信限流依據;同一反向代理後的使用者共享來源額度。過期資料由 TTL/定時清理清除,響應設定 Cache-Control: no-store,不記錄配對秘密或簽發令牌明文。

後端已有裝置 ID/賬號不能被配對請求覆蓋。管理員應核對程式碼和申請端;不要批准他人誘導提供的登入碼。

連線碼 API:POST /api/pairing/start 可提交可選 device_name,響應返回該裝置名。管理員 GET /api/pairing/{code} 返回 device_name 和當前工作區的 suggested_device_id,查詢不會佔用 ID。POST /api/pairing/approve 的裝置 identity 可省略,成功返回 200 和 {identity}(最終 ID,不含令牌)。原生 WebSocket /ws/pairing?device_name=... 支援 URL 編碼的裝置名。