Files
story-edit-web/web/README.md
邓雨鹏 90402c4a17 security: 每人一把口令(口令即身份) + 随机会话token + 无配置拒绝启动 + 爆破节流
- STORY_WEB_PASSWORD(默认story) 废弃 → STORY_WEB_USERS=名字1:口令1,名字2:口令2;
  未配置/口令<8位/口令或用户名重复 → 启动即退出,杜绝弱默认口令裸奔
- cookie 不再存口令原文:登录发 secrets.token_urlsafe(32) 随机token,
  会话存 SQLite sessions 表(30天);登出删token;从 USERS 移除某人=吊销其全部会话
- updated_by 改由服务端按会话身份填写,前端自报 by 不再可信;登录框去掉昵称字段
- 登录失败全局递增节流(最多sleep 5s),口令比较用 secrets.compare_digest
- Dockerfile/compose 移除一切口令默认值;compose 未设 STORY_WEB_USERS 直接报错
- 顺手修 playtest.js 走位/动画/out_ref 行未转义的存储型XSS(esc补齐)
2026-06-10 17:34:50 +08:00

3.9 KiB
Raw Blame History

Story 事件协作 Web 编辑器M5

设计:docs/plans/2026-06-06-story-event-pipeline-design.md§5.1/§6, D1D4/D8 计划:docs/plans/2026-06-08-story-event-M5-web-editor-plan.md

少数人各凭专属口令(口令即身份,改动自动署名)在网页里审校/编辑剧情事件 → 静态校验 + 剧本试走(零引擎)→ 一键编译 所有 confirmed 事件成 .events.json + .i18n.tsv 打包下载。校验/编译走 ir_core,与 CLI ir_compile.py)逐字节同口径。

起服务

cd tools/event_authoring/web
pip install -r requirements.txt
# Windows PowerShell: $env:STORY_WEB_USERS="bia:口令A,ljl:口令B"
set STORY_WEB_USERS=bia:口令A,ljl:口令B   # 必填;未配置则拒绝启动
uvicorn app:app --host 0.0.0.0 --port 8787

浏览器打开 http://<host>:8787,输入自己的专属口令进入(服务端按口令认人, updated_by 自动署名;口令要求 ≥8 位且互不相同cookie 只存随机会话 token 不存口令; 从 STORY_WEB_USERS 移除某人即吊销其所有会话)。

用法

  1. 导入 IR:右上「导入 IR」粘贴单个或数组形式的 IR JSONsamples/*.ir.json)。
  2. 审校/编辑:左栏选事件 → 中栏分支树 → 点节点在右栏改文案/增删节点/下拉改分支/角色表/点位下拉。
  3. 校验:与 CLI 同口径(断链、选项无兜底、未登记 kind、未声明角色、点位缺失、out_ref 失效…)。
  4. 试走:从首节点走,点选项/掷随机/手选战斗胜负,实时累计银两/道具/友好度账面与结局。
  5. 确认/丢弃改事件状态pending/confirmed/discarded
  6. 导出 confirmed:编译所有 confirmed → story_export.zip;任一 confirmed 校验不过则整体拒绝。

导出后把 {group}.events.json 放进 Assets/StreamingAssets/Story/Config/(或 Qiyu/ 子目录), {group}.i18n.tsv 的韩文翻译合并进 Assets/StreamingAssets/i18n/ko.tsv

数据

  • 事件存 SQLite story_events.db(本目录,已 gitignore末次写入生效不做锁
  • 词典 ../ir_dictionary.json、点位集 Assets/StreamingAssets/Story/PointSets/*.points.json 只读引用。

Docker 部署M6

单容器FastAPI + 静态前端 + SQLite + 纯 Python 编译器)。构建上下文是 tools/event_authoring(需含 ir_core/ir_dictionary.json/web)。

cd tools/event_authoring/web
STORY_WEB_USERS="bia:口令A,ljl:口令B" docker compose up -d --build
# 或不用 compose
#   docker build -f web/Dockerfile -t story-event-web ..
#   docker run -d -p 8787:8787 -e STORY_WEB_USERS="bia:口令A,ljl:口令B" \
#     -v "$PWD/web/data:/data" \
#     -v "$PWD/Assets/StreamingAssets/Story/PointSets:/pointsets:ro" story-event-web
  • ./data:/dataSQLite 持久化,容器重建不丢事件,勿删 …/PointSets:/pointsets:ro(开发侧点位集只读;缺失时坐标校验降级为警告)。
  • 环境变量STORY_WEB_USERS(必填,名字1:口令1,名字2:口令2,未配置拒绝启动)、 STORY_WEB_PORT(宿主端口,默认 8787STORY_DB_PATH(默认 /data/story_events.db)、STORY_POINTSETS_DIR(默认 /pointsets)、 可选 TZ=Asia/Shanghai(否则 updated_at 按 UTC 显示)。
  • NAS + VPSNAS 跑容器VPS 用反代/frp/Cloudflare Tunnel 把 8787 映射出去。点位集更新只需 同步文件到 NAS 的 /pointsets 卷路径,无需重建镜像。备份=拷 data/story_events.db

API鉴权后

POST /api/login · GET /api/dictionary · GET /api/pointsets · POST /api/import · GET /api/events?status= · GET /api/events/{group} · PUT /api/events/{group} · POST /api/events/{group}/status · POST /api/validate · POST /api/export

非目标(见设计)

容器化部署M6、多人账号/并发锁、手拖画布、引擎侧新语义、把坐标嵌进 events.json。