Files
Commilitia-Drop/.env.example
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

52 lines
2.9 KiB
Bash
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.
# dev 模式(本机开发,brief 实施原则 5)
# 二者必须同时设置;后端启动期校验,缺一即 panic
CDROP_AUTH_MODE=dev
CDROP_DEV_TOKEN=replace-with-32-byte-random-base64
# prod 模式所需(填入你的 OIDC provider,如自建 Casdoor / Keycloak
# CDROP_AUTH_MODE=prod
# CDROP_OIDC_AUTHORIZE_URL=https://your-idp.example/login/oauth/authorize
# CDROP_OIDC_TOKEN_URL=https://your-idp.example/api/login/oauth/access_token
# CDROP_OIDC_JWKS_URL=https://your-idp.example/.well-known/jwks
# CDROP_OIDC_ISSUER=https://your-idp.example/
# prod 强制非空:填你的 OAuth client_id(多值逗号分隔,web + 桌面端共用时填同一个)
# CDROP_OIDC_AUDIENCE=your-client-id
# CDROP_OIDC_CLIENT_ID=your-client-id
# CDROP_OIDC_REDIRECT_URI=https://your-domain.example/oauth/callback
# CDROP_OIDC_SCOPES=openid profile email
# prod 强制非空:浏览器免重登会话的 refresh_token 落盘加密密钥(任意长度高熵串,
# 内部 SHA-256 派生为 32 字节 AES-256 密钥)。留空则 prod 启动期校验失败、拒启动。
# CDROP_SESSION_SECRET=
# CDROP_HS256_SECRET=
# CDROP_TURN_URL=stun:your-stun.example:3478
# 可选:Web PushVAPID)推送通知。用 `just vapid-keygen` 生成一对密钥;二者须同时
# 设置(半对即启动期校验失败),都留空则推送惰性关闭、不阻塞启动。生成后固定不变
# ——更换会使所有既有浏览器订阅失效。
# CDROP_VAPID_PUBLIC_KEY=
# CDROP_VAPID_PRIVATE_KEY=
# CDROP_VAPID_SUBJECT=mailto:you@your-domain.example
# 可选:扫码登录(QR)与 cdrop 自签会话。SESSION_SECRET 已设时默认开启;下列均有默认值,
# 不配即用默认,各项可单独调整 / 关闭对应行为。
# CDROP_QR_LOGIN_ENABLED=true # 关闭则 /api/auth/qr/* 返回 503
# 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_STEP_UP_ENABLED=false # 批准扫码设备等敏感动作要求 provider 再认证
# CDROP_STEP_UP_MAX_AGE_SECONDS=300 # step-up 的 auth_time 新鲜度窗口(秒)
# CDROP_ACCOUNT_MATCH_CLAIM=email # 写入 accounts.match_key 的 JWT claim
# 通用
CDROP_DB_PATH=./cdrop.db
CDROP_LISTEN=:8080
# Device row max age (sliding via auth-middleware UPSERT and SSE keepalive).
# Bound by brief §2 refresh_token sliding window (196h ≈ 8 days). Default 196.
CDROP_DEVICE_TTL_HOURS=196
# Cloudflare Realtime TURN(可选;不配则 /api/calls/credentials 返回 STUN-only fallback)。
# 申请:dash.cloudflare.com → Realtime → TURN → "Create TURN App",拿到 Key ID 与 API Token。
# CDROP_CF_TURN_KEY_ID=
# CDROP_CF_TURN_API_TOKEN=