Skip to content

Add board authentication client and unify server config#154

Open
ZCShou wants to merge 11 commits into
mainfrom
pub
Open

Add board authentication client and unify server config#154
ZCShou wants to merge 11 commits into
mainfrom
pub

Conversation

@ZCShou

@ZCShou ZCShou commented Jul 20, 2026

Copy link
Copy Markdown

ostool 登录与令牌管理变更说明

变更内容与边界

本 PR 为 ostool 增加登录、凭据保存、Token 刷新和注销能力,并将 board 服务地址统一为 URL 配置。

  • 不修改局域网直接运行的 ostool-server;现有匿名 board API 保持可用。
  • 公网部署通过认证网关提供 OAuth 接口,并在需要时保护 board API 与串口 WebSocket。
  • 不保存用户密码;不将 Token 写入项目配置、命令行参数、日志或 shell history。
  • 支持短期 Access Token、可轮换 Refresh Token、PAT 和自动化环境变量 Token。

配置与命令行

局域网仍使用匿名访问,但配置格式统一为 URL 型 server

[board]
server = "http://192.168.1.20"
port = 2999
auth_mode = "disabled"

公网认证网关使用完整 HTTPS 地址:

[board]
server = "https://board.example.com"
auth_mode = "required"

规则:

  • server 必须为包含 http://https:// 的完整 URL;
  • port 为可选覆盖项;未填写时保留 URL 的显式端口或使用协议默认端口;
  • auth_mode = "required" 时必须使用 HTTPS;
  • 项目级 .board.toml 可设置 serverportauth_mode,并由命令行参数覆盖。
  • 相对于 dev,原有的 server_ip 被替换为 URL 型 server,原来必填的 port 变为可选覆盖项;命令行 --server 也必须使用完整 URL。

新增命令:

# 浏览器 Device Authorization 登录
ostool login [--server URL] [--port PORT]

# 从标准输入导入 Web 管理台创建的 PAT
printf '%s' "$OSTOOL_PAT" | ostool login --with-token [--server URL] [--port PORT]

# 显示登录状态,不显示 Token
ostool auth status [--server URL] [--port PORT]

# 尽力撤销 OAuth 会话并删除本地凭据
ostool logout [--server URL] [--port PORT]

客户端调用的认证网关接口

采用 OAuth 2.0 Device Authorization Grant,全部请求为 application/x-www-form-urlencoded

方法 路径 请求字段 用途
POST /oauth/device/code client_id=ostool-cliscope=board:operate offline_access 发起浏览器登录。
POST /oauth/token grant_type=urn:ietf:params:oauth:grant-type:device_codedevice_codeclient_id 轮询换取 Token。
POST /oauth/token grant_type=refresh_tokenrefresh_tokenclient_id 刷新 Access Token。
POST /oauth/revoke tokentoken_type_hint=refresh_tokenclient_id 撤销 OAuth 会话。

Device Code 响应至少应包含:

{
  "device_code": "...",
  "user_code": "ABCD-EFGH",
  "verification_uri": "https://board.example.com/activate",
  "expires_in": 600,
  "interval": 5
}

Token 响应应包含:

{
  "access_token": "...",
  "refresh_token": "...",
  "token_type": "Bearer",
  "expires_in": 900
}

scope 为可选字段。服务端应在刷新时返回新的 Refresh Token,以支持 Token rotation。token_type 必须为 Bearerexpires_in 必须为正数。

轮询期间,认证网关应按 OAuth 约定以非 2xx 响应返回 authorization_pendingslow_down。客户端分别继续等待或将轮询间隔增加 5 秒;成功的 2xx 响应必须包含完整的 Token 字段。

凭据与生命周期

凭据按认证网关 URL 隔离保存,优先使用系统 credential store:

  • macOS:Keychain;
  • Windows:Credential Manager;
  • Linux:Secret Service 兼容服务。

系统凭据库不可用时,回退到 $XDG_CONFIG_HOME/ostool/hosts.json(或 ~/.config/ostool/hosts.json),并限制文件权限为 0600

保存的敏感数据仅包括 OAuth Refresh Token、缓存的 Access Token 或 PAT。用户密码不落盘。

Token 使用策略:

  1. auth_mode = "disabled":不读取、不发送 Token;
  2. OSTOOL_BOARD_ACCESS_TOKEN:只用于当前进程,不保存、不刷新;
  3. PAT:直接作为 Bearer Token 使用,不刷新;
  4. OAuth Access Token 剩余有效期超过 60 秒:直接使用;
  5. 否则使用 Refresh Token 刷新并覆盖本地凭据。

多个 ostool 进程共用 Refresh Token 时,使用 $XDG_CACHE_HOME/ostool/auth-locks/ 下的 URL 哈希锁文件避免并发刷新。收到 invalid_grantinvalid_token 或 board API 的 401 时,删除本地凭据并提示重新登录;临时网络错误保留凭据供后续重试。

Board 请求认证

auth_mode = "required" 时,所有现有 board REST 请求、文件上传和串口 WebSocket 握手均附加:

Authorization: Bearer <access-token>

认证模式下禁用 HTTP 重定向,并拒绝向不同 scheme、host 或 port 的绝对 WebSocket URL 发送 Token。匿名局域网模式不携带 Authorization Header。

修改范围

  • 新增 ostool/src/auth/:OAuth 客户端、凭据存储、Token 生命周期管理;
  • 扩展全局和项目级 board 配置,支持 URL 型 server、可选 portauth_mode
  • 增加 loginlogoutauth status CLI;
  • 在 board HTTP 与 WebSocket 请求边界注入 Bearer Token;
  • 更新中英文 README 和本文档;
  • 增加 URL 配置、CLI 参数、WebSocket Bearer Header 与跨源限制测试。

尚未提供 OAuth 生命周期、REST Bearer Header、凭据文件回退和 401 凭据失效的 mock 网关自动化测试;这些场景列在下方作为手工验收项。

验收

本地编译与自动化测试

cargo fmt --check
cargo build -p ostool
cargo test -p ostool --quiet
cargo clippy -p ostool --all-targets -- -D warnings

编译后的 CLI 位于 target/debug/ostool

target/debug/ostool --help

本地匿名 board 服务

启动本地 ostool-server 后,使用以下匿名配置验证局域网访问:

# ~/.ostool/config.toml
[board]
server = "http://127.0.0.1"
port = 2999
auth_mode = "disabled"
target/debug/ostool board ls
target/debug/ostool board connect --board-type <TYPE>

本地认证网关

登录鉴权测试需要一个本地 HTTPS 认证网关;它应在同一 Base URL 下提供 /oauth/device/code/oauth/token/oauth/revoke,并代理或实现 /api/v1/... board API。开发证书必须被操作系统信任,客户端不提供跳过 TLS 校验的选项。

# ~/.ostool/config.toml
[board]
server = "https://localhost:8443"
auth_mode = "required"

可先用 PAT 验证 Bearer Header 是否被携带:

printf '%s' 'local-test-token' | target/debug/ostool login --with-token --server https://localhost:8443
target/debug/ostool auth status
target/debug/ostool board ls
target/debug/ostool logout

可再用 mock 网关手工验证 Device Code 轮询、刷新、撤销、Refresh Token rotation、凭据文件回退和 401 失效处理。可将 OAuth Token 响应的 expires_in 设为很短的值,再执行 board ls 确认刷新请求;不依赖真实开发板或真实公网服务。

@ZCShou
ZCShou marked this pull request as draft July 20, 2026 02:07
@ZCShou
ZCShou marked this pull request as ready for review July 21, 2026 00:27

@mai-team-app mai-team-app Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR adds OAuth/PAT authentication, credential storage, URL-based board endpoint resolution, and Bearer propagation to board HTTP/WebSocket flows. The authentication behavior is largely isolated to the board-client path, but the endpoint migration changes the default contract used by every ostool board command.

Blocking issue:

  • A newly created global config now resolves to http://localhost/ (HTTP port 80), whereas the existing client default and ostool-server default both use port 2999. Consequently a fresh install—or any board command before configuring a port—cannot reach the bundled/default server. Preserve :2999 in the URL default or keep port = Some(2999) while retaining URL overrides, and add a resolution-level regression test.

Validation: helper self-tests passed and git diff --check passed. I could not run cargo fmt --check, clippy, or crate tests locally because this environment has no cargo binary. Both current GitHub Actions check (stable, x86_64-unknown-linux-gnu) runs succeeded; no CI failure is attributed to this PR.

Previous review comments and PR discussion: none were present. I found no materially overlapping authentication PR in the repository search. Remaining risk after the blocking fix is the unrun hardware/OAuth integration path; the current code changes real board, serial, and credential workflows.

Powered by gpt-5.6-terra

Comment thread ostool/src/board/global_config.rs Outdated

@mai-team-app mai-team-app Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR adds OAuth/PAT authentication and credential lifecycle handling, moves board endpoints to URL-based configuration, and propagates Bearer credentials through board HTTP and serial WebSocket requests. It addresses public authenticated board gateways, while retaining anonymous LAN mode; however, the global endpoint configuration is a shared contract for every existing ostool board command.

The current blocking issue is migration of existing global configuration, described inline. The base release writes [board] server_ip and port, but the new schema rejects that persisted format outright. This breaks upgrades before board commands—or the new login/status commands that load the same global config—can reach their endpoint.

Validation: both current GitHub Actions check (stable, x86_64-unknown-linux-gnu) runs succeeded, with no CI failure attributable to this PR. Locally, prepare-review, helper self-tests, and git diff --check origin/main...HEAD passed. The planned cargo fmt --check, package clippy with -D warnings, and package tests could not run because this environment has neither cargo nor rustc; no hardware/OAuth gateway integration was attempted.

Previous review feedback was considered: the earlier blocking default-port issue is resolved at this head (http://localhost:2999) and has a regression test. Its old inline comment is therefore resolved; no other actionable review or PR comments remain. A repository PR search found no overlapping authentication/client change (the other open PR is unrelated boot-readiness work).

Remaining risk after the requested migration is the unexercised real credential-store, OAuth, board, and serial-hardware paths. The configuration migration remains blocking.

Powered by gpt-5.6-terra

Comment thread ostool/src/board/global_config.rs Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant