feat: 桌面去登录 + 解锁门(商业化改造 PR-A) - #247
Conversation
身份与鉴权: - local-mode 下 getUserIdFromSession 统一解析为本机用户(LocalIdentityService, 老安装复用 admin userId 零迁移;local 用户一旦存在永远优先,杜绝重启后 userId 翻转导致数据换主) - LoopbackGuard 启动强不变式:local-mode 必须绑定回环地址 - DataInitializer local-mode 下不再打印口令类提示 解锁门: - LicenseService/LicenseController:试用码(Ed25519 离线验签,内置公钥)与 账户 Key(在线校验,valid 即解锁,对齐 Spec §1)双路解锁;状态落盘 ~/.aiworkdeck/license.json;account 模式 30 天离线宽限 + 启动机会性复验 - status 返回 activatedAt 供授权卡片展示激活时间 - 前端 launch 分流页 + unlock 解锁页;试用版 chip 与说明弹窗 权限清理与桌面壳: - admin 页删用户管理面板;userprofile 改「项目主页」+ 授权卡片 + 解除授权; wizard 删 admin/123 提示;api.js 修 401 拦截清错 storage key,桌面端不再跳登录页 - userprofile loadProjects 失败兜底桌面端不再逆流进 login 死胡同 - desktop 暴露 shell.openExternal(checkba:shell-open-external,仅 http(s)), 解锁页外链走系统浏览器——window.open 会被 setWindowOpenHandler 转成 无人消费的事件而静默失效 e2e:app-e2e J1 重写为首启解锁门旅程,其余旅程免登直达;desktop-e2e provision 自动试用码解锁+置向导。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
PR-A 让桌面 local-mode 免登后,「状态变更必须携带自定义头 X-Session-Id」
这条事实上的 CSRF 防线消失了:跨源请求原本会因自定义头触发预检、预检拿不到
ACAO 而被浏览器拦死,免登之后不带任何头也能通过鉴权。而 CorsConfig 只是
不回显 ACAO,并不阻断请求本身,multipart 表单提交这类简单请求照样执行到
controller——POST /api/files/{fileId}/upload 是就地覆盖字节、fileId 又是可
枚举的数字主键,恶意页面可批量覆写用户文档。
新增 LocalModeAccessFilter(仅 local-mode 生效,server 模式行为一字不变):
- F1 跨站硬拦截:非 GET/HEAD/OPTIONS/TRACE 的请求,带了 Origin 且不在
CorsConfig 白名单内直接 403,而不只是不回 ACAO。缺 Origin 一律放行——
同源请求、curl、桌面壳内部调用、git 客户端都不带 Origin。已实测打包态
渲染进程(file:// + webSecurity=false)发出的 POST/multipart 完全不带
Origin 头,开发态与 e2e 则是 localhost:5173/5174,均命中放行分支。
字面量 "null"(sandbox iframe / file:// 恶意页)不在白名单内。
- F2 反代识别:LocalModeLoopbackGuard 只证明绑定回环,不证明外部不可达。
这里逐请求校验 remoteAddr 回环;又因 deploy/web 基线里 nginx 与后端同机、
反代过来的 remoteAddr 恰是 127.0.0.1,再加一条——出现任何反代痕迹头
(X-Forwarded-* / X-Real-IP / Forwarded)一律 403。不是信任这些头,而是
把它们的出现当作「这台机器被反代了」的信号。
- F3:POST /api/license/deactivate 匿名无 body,任意站点可打掉用户已存的
account 模式与明文 awdk_ Key,现已落在 F1 闸内。
F5 顺带:
- license.json 写盘后收敛为 0600(内含明文 awdk_ 账户 Key,默认 umask 是 0644)。
- ai.account.base-url 强制 https,配成 http 时拒绝启动并给出中文原因。
CorsConfig 的来源白名单抽成共用判定,与新过滤器同口径;过滤器顺序让位一格,
保证被拒请求拿不到任何 CORS 响应头。
验证:mvn test 723 通过(基线 706 + 新增 17);app-e2e 104/104;desktop-e2e
全通;check:emits 通过;curl 手工复验跨源 multipart 上传与 deactivate 均 403、
无 Origin 与 localhost 来源正常放行、反代痕迹头 403。lowa-e2e 不触碰后端 API
(零引用),不受影响。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
安全加固:补上 local-mode 免登消除的 CSRF 防线(da649dac)针对本 PR 安全审查提出的 F1/F2/F3/F5,已在同分支追加修复。核心是新增 F1(高危)跨站可写面 —— 已闭合免登之后「状态变更必须带 X-Session-Id」这条事实上的 CSRF 防线消失了,而 修法:非 关键前提是实测过的,不是推断:
F2(中)守卫只证明绑定回环 —— 已闭合,但比审查设想的多一步只加「每请求 remoteAddr 回环校验」并不足以闭合 F2: 所以在回环校验之外再加一条:local-mode 下出现任何反代痕迹头( F3(中低)deactivate CSRF 靶子 —— 由 F1 覆盖
F5(低)
关于建议中的 (b) 本地随机令牌 —— 本次未做理由:(a) 已经完整闭合浏览器侧的 CSRF。浏览器对任何跨源的非 GET/HEAD 请求(含 form/multipart 简单请求)必发 Origin,这正是 (a) 的判据。(b) 的边际价值只覆盖「浏览器不发 Origin」的理论情形,而代价是要把令牌注入到全部请求发起点(uni.request / 裸 fetch / XHR / uni.uploadFile),且会打断三个现实链路:dev Electron 复用外部已跑的后端(令牌对不上)、app-e2e 的 puppeteer 直连、以及日常 也评估过用 残留风险:若某浏览器在跨站非 GET 请求上不发 Origin,(a) 会漏过。已知主流浏览器均不属此列。此外 local-mode 下 GET 仍不受跨站拦截(跨站读依旧被 CORS 挡在浏览器侧,且 GET 不改状态)。 验证
|
只写文档,未改任何功能代码。以 PR-A 至 PR-E(#247/#248/#249/#250/#251/#252) 合并后的实际代码行为为准,Spec 有数处已被实现修正,逐条记在偏差记录里而不是 反过来照抄 Spec。 README(中英双份,紧随「下载即用/Download & Run」之后):新增「获取与解锁」—— 公开试用码全串、离线验签不联网的说明、试用版标识、正式版走官网账户 Key、 解锁按机器且状态在 ~/.aiworkdeck/、团队服务器部署不设解锁门。 这一节不是可有可无的营销文案:解锁页「获取试用码」链接直指 github.com/zeweihan/aiworkdeck#readme,删掉或挪走等于弄坏产品里的一个按钮。 码已用 backend 内置公钥离线复验:70 字节、payload 版本/类型正确、Ed25519 验签通过。 新增 .claude/agents/licensing-billing.md 并在 CLAUDE.md 路由表加一行。 关键文件地图按六个 PR 的实际落点写;核心契约含试用码格式、awdk_ Key、 解锁状态与两条互不替代的失效路径(宽限 vs 吊销)、entitlement 三段命名空间、 官网 API 摘要(权威指针指向官网仓 doc/desktop-contract.md)、两套计费口径不得合并。 已知地雷十一条,含「请先」被 api.js 掉线启发式误判、local-mode 与团队服务器的 成套差异、LocalModeAccessFilter 补 CSRF 防线的三条闸、多候选身份不猜、 免费额度只隐藏不删数据、权益失效不等于把人锁在外面。 核对其余领域文档,补两处过时描述与三处交叉指针: - sidebar-shell 的 login 页 tryAutoResume 直达已只对浏览器有效,桌面端启动链 改走 launch 页分流(PR-A 更新了路由那段,漏了 2026-07-31 那段的历史描述); - version-control 的 CloudAcceptDialog 条目仍写着「从云端接一个项目」「接到本地」 「去设置连接」,PR-E 已改为「从团队案件库取一份案卷」「取到本机」「去连一个」, 且多连接时有选择器(地雷 #31 已修)——这个入口正是邀请话术第 1 步指向的地方。 Spec 末尾追加「实现与 Spec 的偏差记录」30 条,分身份与解锁/权益与额度/计费/ 广场付费/安全/文案六组,每条一句话说明为什么改。 Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
改动面
商业化改造总 Spec(docs/superpowers/specs/2026-08-05-commercialization-redesign.md,随本 PR 入库)的桌面仓 PR-A:桌面端去登录 + 首启解锁门 + 权限清理 + e2e 全量更新。
后端
前端
桌面壳
契约变化
审查修复(三报告收尾)
验证状态
Generated with Claude Code