设备 / 账号 / 任务 API
网关 HTTP/WS 接口、op、鉴权
接入 backend 的应用(前端、自定义客户端)通过这些 HTTP/WS 接口操作设备,无需链接 SDK。
网关接口速查
| 接口 | 说明 |
|---|---|
POST /api/nodes {name} | 签发节点 token → {id, token}。需身份(项目 key/secret 或用户 JWT),节点归属调用方 |
GET /api/devices | 列调用方名下持久化设备(按鉴权作用域) |
POST /api/devices/:id/op {op,...} | 设备操作代理:转发给拥有该设备的节点(503=无在线节点 / 504=超时 / 502=节点错误) |
POST /api/devices/provision {platform, name, proxy?, packages?} | 创建云设备:按 platform 选能力匹配的节点(redroid/vphone),开通并注册、开计费会话 → {device_id, tier, node_class} |
POST /api/devices/:id/power {action} | 生命周期:start/stop/reboot/reset/destroy/snapshot/restore/control |
GET · PUT /api/admin/package-defaults | 平台管理员 配置 (platform, software) 默认安装版本 |
POST /api/devices/:id/ws-access | 签发 5 分钟设备 token → {token, expires_in, relay_ws} |
GET /ws/device/:id?token=… | 单设备专用 WS 通道:承载 adb/wda/frida 类型化命令 + 原始隧道 |
POST /api/fleet/runs {flow,mode,device_ids} | 创建运行 → {run_id}。CallerScope,device_ids 须为本人名下设备 |
GET /api/fleet/runs/:run_id · /cancel · /pause · /resume | 运行详情/控制;非本人 run → 404 |
GET·POST /api/clusters … | 设备分组 CRUD + 启动,按 owner 收口 |
GET·POST /api/scripts · /api/locators … | 脚本/定位器资产,按 owner_user_id 收口 |
GET /api/ice · /ws/signal · /mirror | WebRTC 屏幕镜像(节点发起 offer,浏览器为 viewer) |
设备操作 op
POST /api/devices/:id/op 的 body:
{ "op": "screenshot" } // → { png_base64 }
{ "op": "screen_size" } // → { width, height }
{ "op": "capture_ui_tree" } // → UI 树
{ "op": "tap", "x": 100, "y": 200 }
{ "op": "swipe", "x1":0, "y1":0, "x2":0, "y2":0, "duration":0.3 }
{ "op": "input_text", "text": "hello" }
{ "op": "press_key", "key": "Enter" }
{ "op": "find_element", "locator": { "strategy":"text", "value":"登录" } }
{ "op": "find_elements", "locator": { "strategy":"resource_id", "value":"id/btn" } }单设备专用 WS 通道(/ws/device/:id)
外部调用方先 POST /api/devices/:id/ws-access 拿 {token, relay_ws},再连 wss://…/ws/device/:id?token=…。一条连接绑定一台设备 + 其归属。帧为 JSON:
// 类型化请求(外部 → backend → 节点)
{ "t":"adb_exec", "id":"<corr>", "argv":["shell","input","tap","100","200"], "timeout_ms":30000 }
{ "t":"wda_req", "id":"<corr>", "method":"POST", "path":"/session/…/wda/tap/0", "body":{} }
{ "t":"frida_run", "id":"<corr>", "script":"<js>", "target":{"pid":1234}, "spawn":false }
// 响应(节点 → 外部):id 回显用于关联
{ "t":"ret", "id":"<corr>", "ok":true, "value":{} }
{ "t":"ret", "id":"<corr>", "ok":false, "error":"…" }
// 流式事件(frida 脚本 send() 推送)
{ "t":"frida_event", "run_id":"<rid>", "name":"send", "data":{} }约定与限制:
adb_exec:argv全部为字符串;禁止设备选择标志(-s/-t/-e/-d/-H/-P/-L),命令恒绑定本设备 serial。wda_req:path必须是单/开头的绝对路径,且不得改变 WDA 目标 host(防节点本地 SSRF)。frida_*:节点需以--features frida构建;隧道addr仅允许 loopback。
账号体系与凭证
三层身份,鉴权方式各不同:
| 层级 | 凭证 | 获取 |
|---|---|---|
| Developer 开发者 | Authorization: Bearer <dev JWT>(typ=dev) | 邮箱+密码登录 |
| Project 项目 | X-Project-Key + X-Project-Secret 头 | 开发者在项目下签发;后端解析为该项目「代表用户」 |
| User 终端用户 | Authorization: Bearer <user JWT>(typ=user,30 天) | SDK 用项目凭证调 POST /api/users(按 email 幂等) |
- 统一网关(any-of):请求带任一可解析为用户的凭证即放行。浏览器只持 user JWT 即可直连
/api/devices等,无需共享密钥。 X-API-Key不是资源凭证:旧的全局共享密钥仅作粗粒度边界,不标识用户,单凭它不能操作任何用户级资源(401)。- 资源端点 =
CallerScope:接受项目 key/secret 或用户 Bearer,两者归一到 user 身份。⚠️ 不接受开发者typ=devtoken——开发者须先经POST /api/auth/project-user换取 user token。 - owner 由凭证推导:创建资源时 owner = 凭证用户;读/改/删按 owner 收口(非属主 404)。前端永不传 owner。
入站任务 Webhook
// POST /api/webhook/tasks body —— flow 与 script_id 二选一
{
"flow": {}, // 或 "script_id": "<uuid>"
"params": {}, // 合并进 flow
"device_ids": ["<uuid>"], // 必填;每个须在调用方可见范围内
"mode": "Broadcast",
"expires_in": 3600
}GET /api/webhook/tasks/:id 轮询任务与每设备状态。
项目出站回调 Webhook
项目用 key/secret 注册回调地址(POST /api/webhooks/callbacks {url,events,secret},仅项目 key/secret),任务生命周期事件经 HMAC-SHA256 签名 POST 回该地址(签名头 X-Aumx-Signature,事件头 X-Aumx-Event)。事件:task.created · task.target.succeeded · task.target.failed · task.completed。
路径区分:出站回调
/api/webhooks(复数);入站任务/api/webhook/tasks(单数)。