Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
2f0b61e
Replace account cloud sync with GitHub identity and device-owned remo…
bobleer Sep 9, 2026
4a16c26
Isolate versioned relay ingress behind trusted WAF peers
bobleer Sep 9, 2026
203af6c
Allow QR camera access only on the trusted relay controller document
bobleer Sep 9, 2026
5f44830
Unify GitHub sign-in and use authenticated Relay device invitations
bobleer Sep 9, 2026
2b0bde2
Keep authenticated device QR visible across room status refreshes
bobleer Sep 9, 2026
ac1c7d5
refactor(remote-connect): unify official and LAN account transport
bobleer Sep 9, 2026
4ab71a7
fix(remote-connect): align LAN selector and remove redundant server a…
bobleer Sep 9, 2026
76b57ba
polish(remote-connect): unify account and mobile connection layouts
bobleer Sep 9, 2026
08a697b
fix(remote-connect): align sidebar icons and labels
bobleer Sep 9, 2026
446486e
fix(remote-connect): use consistent chat icons across entry points
bobleer Sep 9, 2026
388bb6f
simplify(mobile-web): remove redundant in-page QR scanner
bobleer Sep 9, 2026
3bb4ba6
fix(mobile-web): direct expired accounts back to GitHub sign-in
bobleer Sep 9, 2026
d97cae9
fix(mobile-web): remove desktop-dependent authorization guidance
bobleer Sep 9, 2026
8e0b4be
Merge upstream main and refresh remote connection capability document…
bobleer Sep 9, 2026
2ad783b
test(remote-connect): align identity and device contracts
bobleer Sep 9, 2026
0066ef9
fix(remote-connect): keep GitHub operations searchable in registry
bobleer Sep 9, 2026
d19bda2
test(cli): verify shared GitHub identity ownership
bobleer Sep 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
42 changes: 5 additions & 37 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ unic-langid = "0.9"
x25519-dalek = { version = "2.0", features = ["static_secrets"] }
aes-gcm = "0.10"
sha2 = "0.10"
hkdf = "0.12"
minisign-verify = "0.2"
sha1 = "0.10"
argon2 = "0.5"
Expand Down
3 changes: 0 additions & 3 deletions OpenBitFun-Installer/src/i18n/generatedLocaleContract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ export const SHARED_TERMS_BY_APP_LANGUAGE = {
},
"connectionMethods": {
"lan": "LAN",
"ngrok": "Ngrok",
"openbitfunServer": "OpenBitFun Server",
"customServer": "Custom Server",
"botFeishu": "Feishu Bot",
Expand Down Expand Up @@ -136,7 +135,6 @@ export const SHARED_TERMS_BY_APP_LANGUAGE = {
},
"connectionMethods": {
"lan": "局域网",
"ngrok": "Ngrok",
"openbitfunServer": "OpenBitFun Server",
"customServer": "自定义服务器",
"botFeishu": "飞书机器人",
Expand Down Expand Up @@ -186,7 +184,6 @@ export const SHARED_TERMS_BY_APP_LANGUAGE = {
},
"connectionMethods": {
"lan": "區域網路",
"ngrok": "Ngrok",
"openbitfunServer": "OpenBitFun Server",
"customServer": "自訂伺服器",
"botFeishu": "飛書機器人",
Expand Down
21 changes: 21 additions & 0 deletions deploy/miniapp-market/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -472,3 +472,24 @@ curl -s -o /dev/null -w "%{http_code} %{redirect_url}\n" \

每日备份保留 14 份,周备份保留 8 份。备份脚本的删除范围已经限制在市场专用
backup root;不要放宽该保护。

## 统一 GitHub 登录入口

`https://auth.openbitfun.com` 是市场与远控共用的登录入口,桌面授权完成页为
`/complete`,身份 API 为 `/api/v1`。它复用本服务和数据库;不新增账号库。
安装同目录 `nginx-auth.openbitfun.com.conf` 前,先确认该域名的 DNS、TLS/WAF
已覆盖,并配置当前可信 WAF 源网段。该配置只开放登录、身份、token 生命周期和
页面静态资源,不代理市场写接口。

GitHub OAuth App 的注册 callback 保持
`https://market.openbitfun.com/miniapp/api/v1/auth/github/callback`。回调仍在市场
host 上写入两组 host-only Cookie(`/miniapp` 与 `/skin`),然后桌面授权跳转到
独立完成页;不要通过 `Domain=.openbitfun.com` 扩大 Cookie 信任范围。桌面
poll token 仍受一次性 transaction secret 约束。旧市场 API 与旧完成页路径保留,
已有安装无需手动迁移。

发布顺序:先更新本服务及新增 auth vhost,验证 `/complete`、`/sign-in` 跳转、
匿名 `/api/v1/me` 返回 401、desktop start/poll 和旧市场 API;再发布使用新身份
API 的 Relay/客户端。两个市场各自的网页仍在所属 Compose 项目中构建发布。
回滚时先让新客户端/Relay 恢复旧 API,再撤回 auth vhost;不能让已发布客户端的
身份地址失效。旧 Relay 和已有市场业务数据均不在这个 vhost 的变更范围内。
50 changes: 50 additions & 0 deletions deploy/miniapp-market/nginx-auth.openbitfun.com.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Shared GitHub sign-in facade. Install beside the market host; keep the
# registered GitHub callback on market.openbitfun.com so host-only marketplace
# cookies remain isolated from other subdomains. Requires relay-v1.conf's
# trusted WAF peer map and the existing miniapp_market_json log format.
server {
listen 80;
listen [::]:80;
server_name auth.openbitfun.com;
if ($relay_v1_trusted_origin_peer = 0) { return 403; }
access_log /var/log/nginx/auth.openbitfun.com.access.log miniapp_market_json;
error_log /dev/null crit;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
set_real_ip_from 190.92.193.0/24;
set_real_ip_from 159.138.94.0/24;
set_real_ip_from 101.44.169.0/24;
set_real_ip_from 2405:f080:110::/120;
client_max_body_size 16k;
add_header X-Content-Type-Options nosniff always;
add_header Referrer-Policy no-referrer always;
add_header X-Frame-Options DENY always;

proxy_set_header Host market.openbitfun.com;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_connect_timeout 5s;
proxy_read_timeout 30s;

location = /sign-in {
proxy_pass http://127.0.0.1:9710/miniapp/api/v1/auth/github/start;
}
location = / {
proxy_pass http://127.0.0.1:9710/miniapp/auth/complete;
}
location = /complete {
proxy_pass http://127.0.0.1:9710/miniapp/auth/complete;
}
# Bearer-token APIs only; marketplace mutations are not exposed here.
location ~ ^/api/v1/(me|auth/desktop/(start|poll)|auth/(refresh|logout))$ {
rewrite ^/api/v1/(.*)$ /miniapp/api/v1/$1 break;
proxy_pass http://127.0.0.1:9710;
}
location ^~ /miniapp/assets/ {
proxy_pass http://127.0.0.1:9710;
}
location ~ ^/miniapp/(theme-init\.js|favicon\.(ico|svg)|apple-touch-icon\.png|site\.webmanifest)$ {
proxy_pass http://127.0.0.1:9710;
}
location / { return 404; }
}
32 changes: 32 additions & 0 deletions deploy/relay-v1/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Official Relay v1 deployment

The owner guide is [Relay Server](../../src/apps/relay-server/README.md).
Use this independent Compose project for `/v/1.0.0/`. Keep the older Relay
container, paths, image, database, and `/relay` proxy location intact.

Deploy from a committed checkout at `/srv/openbitfun-relay-v1/app`. Set
`RELAY_GIT_COMMIT` to that checkout's verified full commit. Build mobile web
from the same checkout with `pnpm run build:mobile-web` and stage its `dist`
contents into `/srv/openbitfun-relay-v1/static`. Create `data` and `assets`
under that root owned by UID/GID 10001 before starting Compose.

The Linux host network plus explicit `127.0.0.1:19700` listener lets the service
verify the immediate proxy peer before trusting its overwritten forwarded IP.
Do not publish this listener on a public interface. Install `nginx-http.conf` in the Nginx http context and include
`nginx-location.conf` in the existing remote server after the container passes
its health check. The new location accepts the existing explicit WAF origin
ranges and loopback; direct origin requests from other peers receive 403.
Forwarded client IPs are recursively resolved only for those trusted WAF
peers. Keep the range list synchronized with the WAF control plane. Raise
`worker_connections` to 8192 and retain a file descriptor limit of at least
16384; validate with `nginx -t` before a graceful reload.

Published Pages are disabled with an explicit 503 until both isolated public
and sign-in origins are configured. This prevents uploaded content from sharing
the mobile controller's account origin. Enabling Pages requires dedicated
origins, their proxy routes, and the Page isolation verification in the owner
guide; setting an arbitrary origin value alone is insufficient.

Before replacement, back up this version's database and assets and retain the
previous image tag. Roll back only this Compose project and its versioned
location. Never use the legacy relay Compose file to operate this deployment.
50 changes: 50 additions & 0 deletions deploy/relay-v1/compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: openbitfun-relay-v1
services:
relay-v1:
image: openbitfun-relay-v1:${RELAY_GIT_COMMIT:?Set the verified source commit}
build:
context: ../..
dockerfile: src/apps/relay-server/Dockerfile
args:
RELAY_GIT_COMMIT: ${RELAY_GIT_COMMIT:?Set the verified source commit}
CARGO_BUILD_JOBS: "4"
container_name: openbitfun-relay-v1
network_mode: host
user: "10001:10001"
read_only: true
cap_drop: [ALL]
security_opt: [no-new-privileges:true]
restart: unless-stopped
cpus: 4
mem_limit: 4g
pids_limit: 256
ulimits:
nofile:
soft: 16384
hard: 16384
tmpfs:
- /tmp:size=64m,mode=1777
environment:
RELAY_PORT: "19700"
RELAY_LISTEN_ADDR: 127.0.0.1:19700
RELAY_STATIC_DIR: /app/static
RELAY_DB_PATH: /app/data/relay.db
RELAY_ROOM_WEB_DIR: /app/room-web
RELAY_ASSET_STORE_MAX_BYTES: "1073741824"
RELAY_CORS_ALLOW_ORIGINS: https://remote.openbitfun.com
RUST_LOG: info
volumes:
- /srv/openbitfun-relay-v1/data:/app/data
- /srv/openbitfun-relay-v1/assets:/app/room-web
- /srv/openbitfun-relay-v1/static:/app/static:ro
logging:
driver: json-file
options:
max-size: 10m
max-file: "3"
healthcheck:
test: [CMD, curl, -fsS, http://127.0.0.1:19700/health]
interval: 15s
timeout: 5s
retries: 5
start_period: 30s
23 changes: 23 additions & 0 deletions deploy/relay-v1/nginx-http.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Install in /etc/nginx/conf.d/relay-v1.conf (http context).
map $http_upgrade $relay_v1_connection_upgrade {
default upgrade;
'' close;
}
# Same explicit Huawei WAF origin ranges as the existing market deployment.
# Refresh from the WAF control plane when its origin source ranges change.
geo $realip_remote_addr $relay_v1_trusted_origin_peer {
default 0;
127.0.0.1 1;
::1 1;
190.92.193.0/24 1;
159.138.94.0/24 1;
101.44.169.0/24 1;
2405:f080:110::/120 1;
}
limit_conn_zone $binary_remote_addr zone=relay_v1_client_connections:10m;
limit_conn_zone $server_name zone=relay_v1_global_connections:1m;
limit_req_zone $binary_remote_addr zone=relay_v1_client_requests:10m rate=100r/s;
limit_req_zone $server_name zone=relay_v1_global_requests:1m rate=2000r/s;
log_format relay_v1_json escape=json
'{"time":"$time_iso8601","method":"$request_method","path":"$uri",'
'"status":$status,"bytes":$body_bytes_sent,"requestTime":$request_time}';
39 changes: 39 additions & 0 deletions deploy/relay-v1/nginx-location.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Include inside the existing remote.openbitfun.com server block.
location = /v/1.0.0 {
return 308 /v/1.0.0/;
}
location ^~ /v/1.0.0/ {
# Trust forwarded addresses only from the existing explicit WAF peers.
# Recursive extraction selects the last non-trusted address, not a spoofed
# client-supplied leftmost XFF entry. Relay receives one overwritten value.
set_real_ip_from 190.92.193.0/24;
set_real_ip_from 159.138.94.0/24;
set_real_ip_from 101.44.169.0/24;
set_real_ip_from 2405:f080:110::/120;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
if ($relay_v1_trusted_origin_peer = 0) { return 403; }

limit_conn relay_v1_client_connections 256;
limit_conn relay_v1_global_connections 6144;
limit_conn_status 429;
limit_req zone=relay_v1_client_requests burst=200 nodelay;
limit_req zone=relay_v1_global_requests burst=1000 nodelay;
limit_req_status 429;

proxy_pass http://127.0.0.1:19700/;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $relay_v1_connection_upgrade;
proxy_buffering off;
proxy_request_buffering off;
client_max_body_size 49m;
client_body_timeout 15s;
proxy_connect_timeout 5s;
proxy_read_timeout 140s;
proxy_send_timeout 30s;
access_log /var/log/nginx/relay-v1-access.log relay_v1_json;
}
4 changes: 2 additions & 2 deletions docs/architecture/peer-device-mode.md
Original file line number Diff line number Diff line change
Expand Up @@ -284,8 +284,8 @@ FS) and must not be mixed with Peer Device Mode.
lifetime. Disconnect joins cancellation; replacing or dropping the client
retires the old socket and its reconnect attempts. A generation fence prevents
an old connection from publishing state into its replacement. Initial dial
failure returns to `Disconnected`. Reconnect restores room/account context,
including a server-assigned room id, before admitting new outgoing commands.
failure returns to `Disconnected`. Reconnect verifies the selected Relay account and device context before
admitting new outgoing commands. Anonymous room contexts are not supported.
The outgoing queue holds at most 64 messages and reports saturation explicitly;
its failed-socket contents are never replayed. Dial/write deadlines are 15s,
heartbeat cadence is 30s, with due heartbeats taking priority over queued
Expand Down
1 change: 1 addition & 0 deletions docs/architecture/rust-build-dependency-boundaries.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ Plugin Source 和完整 domain feature 集合一起带回 Agent Runtime。产品
- 真正创建 client 的 app、service 或 adapter 必须在自身依赖声明中显式选择实际使用的 Reqwest feature 和 provider-neutral 的 `reqwest/rustls-no-provider`;只使用 `reqwest::Url` 的 contract/assembly 路径不加载传输能力;
- capability crate 的每个 Reqwest owner feature 必须独立带齐自己的数据/传输 feature、`reqwest/rustls-no-provider` 和进程级 TLS provider owner,不能依赖 `product-full` 或其他 feature 的 Cargo feature-union 偶然补齐;
- workspace 级 `rustls` 只统一兼容版本并关闭默认 feature;`services-core/tls-provider` 是内置 crypto provider 的唯一 owner,精确选择并安装 `ring`、`std` 和 `tls12`。产品进程入口或集中 client helper 必须在构造 TLS client 前确保该 provider 已安装;
- 独立 Docker 构建的 Relay 身份校验器是限定例外:它不链接 workspace 服务 facade,只能将显式 ring `ClientConfig` 绑定到自己的 Reqwest client,不能安装或替换进程级 provider。该例外只覆盖 `relay-service/src/identity.rs`,边界检查同时强制 client 绑定并禁止 `install_default`;嵌入式产品的进程 provider 仍由 `services-core` 拥有。
- 边界检查以 Cargo metadata 的解码结果看护全部直接 consumer,并检查 resolved Reqwest/Rustls feature union,拒绝缺失 provider、同时选择多个 provider、传递依赖重新激活 AWS-LC 或 Native TLS,以及绕过集中 helper 的 Reqwest client 构造;
- 不并列启用 Native TLS 或 AWS-LC 兼容栈。只有真实产品场景无法由当前 Ring/Rustls 平台证书验证承载时,才以明确行为证据评审替换方案;替换时由同一 owner 切换 provider,不能在同一产品闭包叠加第二后端。

Expand Down
2 changes: 1 addition & 1 deletion docs/development/communications-e2e.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ SSH 与账号设备 RPC 两种传输各跑一轮;目标分别为 CLI daemon
| EXT-08 | 模型 SSE/WebSocket:多字节/JSON 跨块、首包超时、流中断、429、5xx | 调用与执行状态保真;不把部分响应当完整,也不重复已有工具副作用 |
| EXT-09 | AI relay 模型请求来自本地/peer/dispatch 不同执行端 | 使用声明的模型 provider 和凭据域;断线不能偷偷改变执行宿主 |
| EXT-10 | Plugin Host IPC、SDK stdio:帧边界、correlation、取消、worker 崩溃、背压 | 各协议独立限制与生命周期成立;不复用客户端数复制 Runtime owner |
| EXT-11 | LAN、ngrok/自建 Relay嵌入式 Relay 运行手机主线 | 同一共享路由契约;公网地址变化、端口占用和服务停止明确反映 |
| EXT-11 | 官方 Relay 与 LAN 嵌入式 Relay 运行同一账号设备主线 | 同一共享路由契约;公网地址变化、端口占用和服务停止明确反映 |
| EXT-12 | 发布页面/附件上传、读取、账号 sync 大包与设备 RPC 并发 | 各路由认证和大小上限一致;没有把 HTTP body limit 当业务完整性保证 |

## 5. 本地自动验证入口
Expand Down
Loading
Loading