Files
dsh-web/API.md
T

89 lines
8.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# DSH Web 面板 API(MVP)
默认监听 127.0.0.1:8088。JSON 错误统一为 {error:string}。登录使用 HttpOnly session/access/refresh cookie;写请求需 X-CSRF-Token 和精确同源 Origin(未配置 PANEL_PUBLIC_URL 时也校验)。access JWT 有效期5分钟,refresh轮换且受24小时session限制。
## 配置
- UPLOAD_ALLOWED_EXTENSIONS:可选逗号分隔扩展名白名单(例如 .txt,.md);空表示不限制。大小写不敏感,非内容/恶意软件检测。
## 管理员孤儿回收
GET /api/orphans 返回可回收的完整容器ID数组。DELETE /api/orphans?id=<id>&confirm=<相同完整id> 二次核验后非强制删除,保留bind数据及网络。仅接受本项目身份/挂载匹配、已停止、无实例或升级引用的容器;普通用户403,确认不匹配400,状态不安全409。
## 其他配置
- LISTEN_ADDR(默认 127.0.0.1:8088)
- DATA_ROOT(默认 ./data)
- HOST_DATA_ROOT(默认等于 DATA_ROOT 的绝对路径,用于 Docker bind source;容器部署必须显式设置宿主绝对路径)
- CONTAINER_DATA_ROOT(默认 DATA_ROOT)
- DOCKER_HOST(默认 unix:///var/run/docker.sock)
- PANEL_PUBLIC_URL(可选)
- ADMIN_USERNAME / ADMIN_PASSWORD(首次启动创建管理员;密码必须 12–72 字节,不设置则拒绝启动,不打印密码)
- WEB_DIR(可选静态前端目录)
- PANEL_CONTAINER_ID(面板容器名/ID,用于加入实例网络;宿主进程运行时留空)
- DEFAULT_QUOTA_BYTES(默认10GiB)
- DSH_DOCKER_ROOT_VISIBLE(与DockerRootDir相同路径的明确映射,用于构建前容量检查;未知容量拒绝新构建)
## 认证
- POST /api/login {username,password} → {user,csrf_token};user 字段为 id,username,admin,quota_bytes,created_at
- POST /api/logout → {ok:true}
- POST /api/refresh → {ok:true}(刷新HttpOnly cookie,需Origin和CSRF)
- GET /api/me → {user,csrf_token}
- POST /api/me/password {current_password,password} → {ok:true,reauthenticate:true}(普通用户及管理员仅修改本人;不接收目标 ID,未知 JSON 字段返回 400)。需有效 access/session、同源 Origin 和 X-CSRF-Token;新密码为 UTF-8 12–72 字节,非法 JSON、缺少当前密码或长度不符返回 400。错误当前密码返回 400 而非 401,客户端不应因此退出登录。未登录 401,Origin/CSRF 不符 403(失效 session 在 guard 中也可能返回 403),已认证的非 POST 请求返回 405。
- 与登录、管理员重设共用 authLoginMu,等待后复验会话与当前密码;沿用账户登录失败计数,累计 5 次错误锁定 15 分钟,锁定期间返回 429(即使当前密码正确),已登录不能绕过。认证存储故障返回 503。
- 同一事务保存 bcrypt hash、撤销本人全部 session/refresh、清除失败计数,并记录 user.change_password 审计(操作者和目标均为本人 ID,detail 为空,无密码/hash/token);事务失败返回 500 并完整回滚,其他用户不受影响。成功后客户端应清理登录状态并重新登录;旧密码、旧 access/session/refresh 不再可用。已建立的 runtime WS/SSE 不主动断开,下一次请求或重连重新鉴权。
## 管理
- GET /api/users(管理员)
- POST /api/users {username,password,admin?,quota_bytes?}(管理员)
- PATCH /api/users {id,quota_bytes}(管理员修改正数配额)
- POST /api/users/reset-password {id,password} → {ok:true,reauthenticate:boolean}(仅管理员;需有效 access/session、同源 Origin 和 X-CSRF-Token)。密码按 UTF-8 字节计为 12–72 字节,以 bcrypt 保存;缺少 ID、非法 JSON 或长度不符返回 400,目标不存在 404,未认证 401,非管理员或 Origin/CSRF 不符 403(失效 session 在 guard 中也可能返回 403),已认证的非 POST 请求返回 405。
- 同一事务更新密码、删除目标全部 session/refresh、清除目标登录失败锁定,并记录 user.reset_password 审计(操作者 ID、目标 ID、时间,detail 为空,不含密码/hash/token)。任何数据库失败返回 500 并回滚,不影响其他用户会话。与登录串行,等待后重新检查管理员会话和权限。
- 允许重设自身,此时 reauthenticate:true,当前会话也立即失效,客户端应清理登录状态并回到登录页;重设他人返回 false。旧密码不能再登录,旧 access/refresh 不能发起新的认证请求。已建立的 runtime WS/SSE 不会被主动立即断开:代理仅在请求/握手时鉴权,下一次请求或重连会被拒绝;现有 runtime 页面刷新认证脚本不是即时断连保证。
- GET /api/audit(管理员)
## 镜像与构建
- GET /api/images
- DELETE /api/images?image_id=sha256:...(管理员;保护实例、活动任务、升级及全部Docker容器引用,不force)
- GET /api/latest(查询 npm dist-tags.latest)
- GET /api/builds
- POST /api/builds {version}(固定版本,异步;版本/模板/平台去重,新任务每用户每小时最多3个,共享复用不扣次数)
## 实例
- GET /api/instances → Instance[];字段 id,uid,name,version,image_id,status,container_id,created_at
- POST /api/instances {name,image_id,version} → Instance(每用户最多 2 个)
- POST /api/instances/{id}/start|stop|restart
- DELETE /api/instances/{id} → {ok:true}
- POST /api/intents {name,version}(固定精确版本,持久预留构建后创建名额)
- GET /api/intents(当前用户意图)
- DELETE /api/intents/{id}(仅取消等待,不取消共享构建)
所有成功 JSON 列表均为顶层数组(不是 data 包装);错误均为 {error:string}。实现与验收仍在进行,不应仅凭接口列在此处认定已验收。
- GET /api/instances/{id}/logs
- /dsh/{id}/...(登录和 owner 校验;需同 Docker 网络)
## 工作区
- GET /api/ws/tree?path=.
- GET /api/ws/usage
- POST /api/ws/mkdir {path}
- POST /api/ws/rename {path,new_path}
- DELETE /api/ws/delete?path=...
- POST /api/ws/upload multipart file,path
- GET /api/ws/download?path=...:普通文件保持原始流与 Range 支持;目录返回 `application/zip` 附件(目录名.zip),空 path 或 `.` 下载整个工作区(workspace.zip)。ZIP 条目相对所选目录,保留空目录,不额外包裹顶层目录,使用 Store 模式(不压缩),不支持 ZIP Range。
- ZIP 先校验有界文件清单,再逐文件流式输出,不生成临时归档,不持 workspace/global 锁跨网络传输。每次最多 10,000 个文件/目录条目、64 层、10 GiB 文件总大小;进程最多同时 4 个目录下载,超出分别返回 413 / 429;扫描和传输合计限时 2 分钟。
- 路径必须位于工作区内;下载拒绝任意路径分量的符号链接、跨挂载点、特殊文件和多硬链接普通文件。目录含上述条目或含反斜杠/冒号的不安全 ZIP 文件名时整体拒绝(400),不静默漏文件。依赖 Linux openat2,内核不支持时安全失败。
- 下载不是原子快照:流式读取前复核文件身份、大小、类型及修改时间;并发修改、取消或传输错误可能导致连接中断/不完整 ZIP,请停止写入后重试。单文件下载不受 ZIP 数量、大小、并发和时限约束。
## profile / 备份
- GET /api/instances/{id}/profile
- PUT /api/instances/{id}/profile {content,restart?}(停机原子写;restart=true启动并检查就绪)
- GET /api/instances/{id}/profile-preview(bundle清单和脱敏dump-config,字符串值隐藏;运行中才能dump)
- POST /api/instances/{id}/backups {password}(当前登录密码加密;自动恢复原运行状态)
- POST /api/instances/{id}/backups multipart file,password(导入外部包,password为原包密码;不立即覆盖home)
- GET /api/instances/{id}/backups
- GET /api/instances/{id}/backups?download={backup_id}
- POST /api/instances/{id}/restore {backup_id,password}(原备份密码;旧平台key包可留空)
- POST /api/instances/{id}/upgrade {image_id,password}(当前登录密码,加密pre-upgrade备份)
Profile写入要求实例先停止。备份/还原/升级会受控停启;恢复保留原运行状态,升级成功运行新版,失败恢复旧状态。模板2入口先准备插件再启动应用。删除实例仅删除容器与网络并移除索引,保留数据目录。升级失败恢复实例home,不撤销共享workspace或外部系统副作用。
已实现并通过核心集成检查:镜像复用验证、Docker 生命周期、token/cookie 桥接、加密备份恢复、同镜像替换升级。WS/SSE 代理有单元测试,真实完整会话待验证。硬配额与跨公网租户域名隔离未实现;当前 dsh 发行版不支持 --public-url。默认仅 loopback 监听,不应直接暴露公网。完整限制见 README.md。