Files
Commilitia-Drop/docker/compose.snippet.yaml
T
admin 90a3790a98 扫码登录:cdrop 自签会话原语 + 薄账户层 + 受限访客 + 2FA step-up
身份仍源自 OAuth provider(user_id = OIDC sub),cdrop 在其上自维护一薄层:
自签会话令牌 + accounts 表,并新增扫码快速登录。实施蓝本见 AUTH.md。

后端 · 自签会话原语
- web_sessions 加 kind/scope/granted_by 列(bootstrap 幂等迁移);既有 oidc
  会话行为不变,新增 self(滑动续期)/ guest(受限·不续)两类
- cdrop 自签 HS256 会话 access token,密钥派生自 SESSION_SECRET,与落盘 AES、
  shortcut HS256 三密钥域隔离;jwtauth.verifySelfToken 无状态校验、靠 typ 区分
- requireFullSession 守卫:guest 会话不得改账号 / 再批准设备 / 签长效 token
- /auth/refresh 按 kind 分流:self/guest 纯自签、不触 IdP

后端 · 扫码登录(internal/httpapi/qr.go)
- qr/start・status・request・approve・deny 五端点 + login_requests 表 + reaper
- 三密钥分离:QR 仅含批准信息,会话只投递给持私有 poll_secret 的原设备
  (偷拍 QR 者无 poll_secret 领不到会话、未登录批不了准)
- 会话在新设备侧领取(cookie 不经手机)、单次消费、短 TTL

后端 · 薄账户层与 2FA step-up
- accounts 表(键 sub,不含任何凭证):exchange/refresh upsert match_key /
  显示名 / 头像 / roles,供显示与未来管理员开启迁移标记时跨源关联
- step-up(默认关):开启后 qr/approve 要求新鲜 prompt=login 授权码,后端就地
  换 id_token、JWKS 验签 + auth_time 窗口 + sub 匹配,provider 2FA 于此往返强制

前端(web/)
- 显码页 /link/new + 批准页 /link + net/qr.ts,对齐 Theme B、复用 AuthShell
  与聚珍排版管线、零新全局样式
- step-up 再认证流:批准前跑 prompt=login PKCE,回调分叉(不消费一次性 code、
  独立 state key)后带 step_up_code/verifier 调 approve
- 三语 i18n qr.*;新增 qrcode 依赖

修复 · clipboard sweeper(早已提交的损坏)
- ClearExpiredClipboards 因 clipboard.sql 全角注释触发 sqlc 1.31 多字节偏移
  bug,生成 SQL 被截断为「UPDATE clipboard_state SET content =」,sweeper 运行
  期报「incomplete input」、过期剪贴板内容从未清除(短 TTL 暴露保护失效)
- 注释改纯 ASCII 并加 bug 警告,重生成得完整 SQL;prod 已验证 sweeper 由 ERROR
  转为正常清理(cleared count=1)

构建
- .dockerignore:排除本地 node_modules 等,避免宿主原生二进制污染镜像内 vite 构建
- Dockerfile.base:GOPROXY 改为可经 --build-arg 覆盖(默认仍官方代理,受限网络
  构建时传区域镜像即可,仓库不固化区域值)

文档
- 新增 AUTH.md(账户与登录实施蓝本);README 特性;.env.example /
  compose.snippet 增配置项(QR / 自签会话 TTL / step-up / match_claim)

测试
- 自签 token 密钥域隔离、扫码端到端(领取 / 单次 / poll_secret 校验 / deny /
  step-up 门)、extractIdentity、web_sessions 升级迁移
2026-06-21 22:43:36 +08:00

55 lines
3.1 KiB
YAML
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.
# cdrop 在你的 docker-compose.yaml 中的服务条目片段。
# NN 由你决定(与既有服务区分的编号 / 名称);your-proxy-network 换成你的反代所在网络。
#
# 不显式 ports —— 走内部网络,反代(如 Caddy)通过 NN-cdrop:8080 访问。
# 持久化挂一个目录到 /data,里面只有 cdrop.dbSQLite WAL)。
NN-cdrop:
image: cdrop:latest
container_name: NN-cdrop
restart: unless-stopped
networks: [your-proxy-network]
ports: []
volumes:
- ./NN-cdrop/data:/data
environment:
# M13 首轮 dev 模式(验证 Caddy / H3 管道),稳定后切 prod 见下方注释
CDROP_AUTH_MODE: dev
CDROP_DEV_TOKEN: REPLACE_WITH_RANDOM_HEX64
CDROP_DB_PATH: /data/cdrop.db
CDROP_LISTEN: ":8080"
CDROP_DEVICE_TTL_HOURS: "196"
# ---- prod 切换时启用以下,并把 CDROP_AUTH_MODE 改成 prod、删掉 DEV_TOKEN ----
# CDROP_OIDC_AUTHORIZE_URL: https://your-idp.example/login/oauth/authorize
# CDROP_OIDC_TOKEN_URL: https://your-idp.example/api/login/oauth/access_token
# JWKS 可走 IdP 内网地址省一跳;也可用公网 https。
# CDROP_OIDC_JWKS_URL: https://your-idp.example/.well-known/jwks
# CDROP_OIDC_ISSUER: https://your-idp.example/
# prod 强制非空(空则跳过 audience 校验 = 同 JWKS 其他应用可冒充)
# CDROP_OIDC_AUDIENCE: <你的 OAuth client_id>
# CDROP_OIDC_CLIENT_ID: <你的 OAuth client_id>
# CDROP_OIDC_REDIRECT_URI: https://your-domain.example/oauth/callback
# CDROP_OIDC_SCOPES: "openid profile email"
# prod 强制非空:浏览器免重登会话 refresh_token 落盘加密密钥(SHA-256 派生 AES-256
# CDROP_SESSION_SECRET: REPLACE_WITH_RANDOM_HEX64
# CDROP_HS256_SECRET: REPLACE_WITH_RANDOM_HEX64
# ---- 可选:Web Push(VAPID)推送通知(不配则推送惰性关闭)----
# 用 `just vapid-keygen` 生成一对,二者须同时设置(半对即拒启动)
# CDROP_VAPID_PUBLIC_KEY: <just vapid-keygen 输出>
# CDROP_VAPID_PRIVATE_KEY: <just vapid-keygen 输出>
# ---- 可选:扫码登录(QR)与 cdrop 自签会话(SESSION_SECRET 已设时默认开启)----
# 均有默认值;下列按需覆盖。关 QR_LOGIN_ENABLED 则 /api/auth/qr/* 返回 503。
# CDROP_QR_LOGIN_ENABLED: "true"
# CDROP_QR_REQUEST_TTL_SECONDS: "120" # 二维码 / 登录请求有效期
# CDROP_QR_GUEST_TTL_SECONDS: "3600" # 仅此次(受限访客)会话 TTL
# CDROP_QR_PERSIST_TTL_HOURS: "168" # 信任此设备(持久)会话 TTL
# CDROP_SESSION_TOKEN_TTL_SECONDS: "900" # cdrop 自签 access token TTL
# CDROP_ACCOUNT_MATCH_CLAIM: "email" # 写入 accounts.match_key 的 claim
# ---- 可选:Cloudflare Realtime TURN over TLS(不配则前端 STUN-only 兜底)----
# CDROP_CF_TURN_KEY_ID: <dash.cloudflare.com → Realtime → TURN App>
# CDROP_CF_TURN_API_TOKEN: <同 App 派发的 API Token>