Files
WebTools/README.zh-CN.md
T

28 KiB
Raw Blame History

Web Tools

English

一个匿名访问、自托管的浏览器本地工具箱。支持多人同时使用;除全局导航顺序外,文本、密钥、文件、图片和计算结果均只存在于各自浏览器中,不会发送到服务端。

当前应用版本:0.2.1。

内置工具

  • UTF-8 与 Hex 互转,固定路径为 /tools/utf8-hex
  • Base64 与 Base64 URL 编码、解码,解码结果支持 UTF-8、连续 Hex 和代码字节数组
  • AES-CMAC,支持 AES-128、AES-192 和 AES-256 密钥
  • CRC-8/16/32/64 预设与自定义参数,支持 BIN 和多 block Intel HEX
  • 固件 SHA-256 / SHA-512,支持 Intel HEX 有效数据和带地址/长度的 Block 校验头
  • RSA 2048/3072/4096 位密钥对,导出 PEM,以及可分别复制的 N/E Hex 或代码字节数组
  • 密码学安全随机数,默认 16 字节,支持连续 Hex、空格 Hex 和代码字节数组
  • JSON 格式化、压缩、校验和语法着色
  • XML 格式化、压缩、校验和语法着色
  • PNG 转多尺寸 ICO

首次部署且尚未保存过自定义配置时,默认分类顺序为“编码转换 → 校验计算 → 加密计算 → 格式化 → 图像处理”。已有 data/navigation.json 会保留用户排序,不会因升级被默认顺序覆盖。

交付物与源码

容器交付 ZIP 同时包含源码、测试、生产构建结果和部署文件,不是只有压缩后的网页。主要目录如下:

src/                         Vue 3 前端源码
  components/                所有工具共用的 UI 组件
  lib/                       可测试的纯计算与浏览器辅助逻辑
  tools/                     每个工具一个独立 Vue 组件
  workers/                   大文件计算使用的浏览器后台线程
  views/SettingView.vue      /tools/setting 工具管理页
server/                      零依赖 Node.js 静态服务和导航配置 API
shared/tool-catalog.json     工具与分类的权威元数据目录
shared/default-navigation.json  新部署的默认分类和工具顺序
tests/                       Vitest 单元测试
dist/                        npm run build 生成的生产前端
public/                      浏览器图标和 Web App Manifest
Dockerfile                   多阶段容器构建
docker-compose.yml           默认部署配置
THIRD_PARTY_NOTICES.md       第三方依赖许可说明
CHANGELOG.md                 版本变更、修复和验证记录

交付包不包含 node_modules。Docker 首次构建需要访问 Node 镜像仓库和 npm 软件源;若环境完全离线,应另外交付 Docker 镜像 tar。

架构约束

  • Vue 3、TypeScript、Vite 前端;Node.js 标准库服务端;不引入数据库。
  • 工具组件彼此独立并懒加载,公共交互使用 ToolPage、ModeTabs、TextEditor 和 src/styles.css 中的现有样式。
  • 工具的计算、解析和文件生成逻辑放在 src/lib/,Vue 组件只负责状态与交互。
  • 大文件或长时间计算必须放入 src/workers/ 的 Web Worker,避免阻塞页面交互;Worker 仍只在浏览器本地处理数据。
  • 路由和左侧导航由工具目录自动生成,增加普通工具时不得手工新增路由。
  • 工具输入只在浏览器内存中处理,不得发送给服务端、遥测服务或第三方接口。
  • 服务端只持久化导航顺序,文件为 /data/navigation.json,写入采用临时文件和原子替换。
  • /tools/setting 是固定但不公开显示的管理入口;项目没有登录、收藏、赞助或用户系统。
  • 页面必须保持统一 UI,并兼容桌面端和移动端竖屏。
  • 浏览器图标与左侧品牌标记保持一致。favicon.svg 是现代浏览器主图标,favicon.ico 内含 16/32/48 像素回退图,另提供 180 像素 Apple 图标、192/512 像素 Web App 图标和 512 像素 maskable 图标。

site.webmanifest 只提供应用名称、颜色和图标元数据,便于浏览器添加到主屏幕。项目不注册 Service Worker,不启用离线缓存、安装提示或启动画面,避免部署更新后继续加载过期构建。

页面只提供统一介绍“一个匿名访问、自托管的浏览器本地工具箱”,同时写入标准 HTML description 和同文的 og:description,以兼容不同分享客户端;不设置自定义分享图片、其他 Open Graph 或平台专用字段,也不增加平台抓取器。分享平台可以回退使用页面标题和现有 favicon,但最终展示及缓存刷新时机由平台决定。

核心功能契约

以下行为属于已经发布的兼容性约束。修改时必须同步实现、页面提示、自动化测试和本文档,不能只调整界面文案。

  • UTF-8 / Hex 工具的固定 ID 为 utf8-hex,路径为 /tools/utf8-hex。它按 UTF-8 字节转换文本;Hex 输入接受连续形式,或以空白、英文逗号、中文逗号分隔的片段,并允许每个片段使用可选的 0x 前缀。无效 UTF-8 字节必须报错,不能静默替换字符。
  • Base64 支持标准和 URL-safe 形式;解码结果可显示为严格 UTF-8、连续 Hex 或 0x48, 0x9F, ... 字节数组。无效字符、错误填充和非规范编码必须报错。
  • AES-CMAC 密钥长度可选 128、192 或 256 位,默认 128 位,并分别严格要求 16、24 或 32 字节;不自动补零或截断。密钥和 Hex 消息接受连续 Hex,或空格、换行、英文/中文逗号分隔,并允许片段使用可选的 0x 前缀。CMAC 标签始终为 128 位;AES-128 向量遵循 RFC 4493,AES-192/256 向量遵循 NIST SP 800-38B。
  • CRC 支持 BIN 和多 block Intel HEX,提供 CRC-8/16/32/64 预设,并允许自定义 Width、Poly、Init、XorOut、RefIn 和 RefOut。RefIn/RefOut 在页面中标为输入/输出位反转,不表示字节顺序或整个数据倒序。总 CRC 对按地址升序拼接的有效数据计算,不填充地址空洞,同时输出每个 block 的结果。
  • 固件 Hash 只接受 Intel HEX,输出 SHA-256 和 SHA-512。“有效数据”与“Block 校验头”模式的确切字节流见“固件 Hash 固定语义”;默认校验头字节序为 Big Endian。
  • RSA 只允许 2048、3072、4096 位密钥,公钥指数固定为 65537。优先使用 Web Crypto,只有本地提供者不可用或失败时才动态加载 node-forge 回退,其随机种子仍只来自 crypto.getRandomValues;公钥为 SPKI PEM,私钥为 PKCS#8 PEM,N/E 可分别显示为连续 Hex 或代码字节数组。
  • 安全随机数必须来自浏览器 crypto.getRandomValues,默认 16 字节,允许长度为 1 至 65,536 字节,支持连续 Hex、空格 Hex 和代码字节数组;切换显示格式不得重新生成随机数据。安全随机源不可用或抛错时直接失败,不使用普通伪随机回退。
  • JSON/XML 的格式化、压缩和校验均在浏览器本地完成。合法 XML 可以使用 parsererror 作为元素名;只把浏览器专用解析错误命名空间中的节点视为解析失败。语法着色超过资源限制时只能降级为完整纯文本,不能截断结果。
  • 文件选择、文件更换、清空、模式切换和组件卸载都可能使异步任务失效。旧 Worker、旧图像解码和旧密钥生成结果不得覆盖当前输入或已清空状态。

多人使用与状态边界

  • 每个浏览器标签页拥有独立的 Vue 组件状态、文件对象、图像对象和 Web Worker。不同用户、浏览器或标签页不会共享工具输入与结果。
  • CRC、固件 Hash、RSA、AES-CMAC、随机数、PNG/ICO、编码转换和格式化都在浏览器中执行;服务端没有工具计算接口。
  • /tools/setting 保存的是所有访问者共享的导航配置。同一服务进程会按进入导航操作队列的顺序串行处理读写,最后排队的保存生效;不提供版本冲突合并。
  • 旧导航配置中的历史工具 ID ascii-hex 会在读取时原位迁移为 utf8-hex,保留原分类和排序;新配置和应用路由只使用 utf8-hex。
  • 原子替换保证读取者看到完整的旧配置或新配置,不会看到写到一半的 JSON;它不保证保留多个用户各自的排序修改。
  • 已打开的页面不会实时接收其他用户保存的新顺序,刷新或重新打开后才会读取。
  • 深浅主题保存在当前浏览器同源 localStorage 中;系统剪贴板由操作系统管理。这两项不会改变工具计算结果。

资源限制

限制用于避免异常文件、解压后超大图像或高密度语法 token 长时间占用浏览器。修改这些数值时必须同步源码常量、测试和本文档。

功能 当前限制 超限行为
CRC 固件文件 最大 64 MiB 选择时拒绝,不保留旧文件结果
Intel HEX 非空记录 最多 500,000 条 Worker 停止解析并显示错误
Intel HEX 数据块 最多 1,024 个 block Worker 停止解析并显示错误
Intel HEX 合并后的有效数据 最大 64 MiB 合并分配前拒绝,Worker 停止解析并显示错误
固件 Hash 文件及有效数据 文件最大 64 MiB,有效数据最大 64 MiB 选择或计算时拒绝
PNG 压缩文件 最大 32 MiB 创建预览前拒绝
PNG 尺寸 单边最大 16,384 像素,总计最大 32,000,000 像素 浏览器解码前拒绝
安全随机数 默认 16 字节,每次 1 至 65,536 字节 拒绝无效长度或不安全回退
JSON/XML 语法着色 最大 100,000 字符且不超过 10,000 个 token 结果仍完整显示,但降级为纯文本以减少 DOM 节点
导航配置请求体 最大 64 KiB 服务端返回 400

Docker Compose 部署

要求 Linux AMD64/ARM64、Docker Engine 24+、Docker Compose v2。

docker compose up -d --build

默认访问地址:http://服务器地址:9000

自定义宿主机端口时,在项目根目录创建 .env(可从 .env.example 复制),例如改为 9100:

WEB_TOOLS_PORT=9100

然后正常启动:

docker compose up -d --build

检查状态:

docker compose ps
docker compose logs --tail=100 web-tools

停止服务:

docker compose down

导航配置保存在 Docker 卷 web-tools-data 中的 /data/navigation.json。全新部署且从未保存过排序时,应用直接使用内置默认配置,该文件可能尚不存在;首次保存后会创建。删除或重建容器不会丢失已有配置,执行 docker compose down -v 才会删除该卷。

健康检查地址:http://服务器地址:9000/healthz

Cloudflare 反向代理与 CSP

服务端在每个响应的 Content-Security-Policy 中放入独立的 128 位密码学随机 nonce。Cloudflare JavaScript Detections 会从源站 CSP 响应头读取该 nonce,并把它加到代理注入的脚本上,因此 Bot Fight Mode 可在不启用 'unsafe-inline' 的情况下与严格 CSP 共存。不得把 nonce 改为固定值,也不得为消除控制台提示而放开 'unsafe-inline'。

项目自身不添加 Web Analytics、遥测或第三方脚本。Cloudflare Web Analytics 是部署层可选的浏览器 RUM,不是 CDN、WAF、DDoS 或 Bot 防护的必要条件;默认保持关闭时,Cloudflare 边缘流量统计仍然可用。若未来明确启用 Web Analytics,必须单独评审 CSP 外部脚本来源和“无统计/无遥测”文档契约。

Windows Server 部署(不使用 Docker)

要求安装 Git、Node.js 22.12.0 或更高版本,并使用 PowerShell 5.1 或更高版本。以下示例假设项目位于 C:\Services\WebTools。

首次克隆后安装依赖并构建:

Set-Location C:\Services\WebTools
npm.cmd ci --include=dev
npm.cmd run build

生产构建成功后,使用项目根目录的统一脚本启动:

powershell.exe -NoProfile -ExecutionPolicy Bypass -File .\web-tools.ps1 start

默认监听 0.0.0.0:9000,导航配置保存在 C:\ProgramData\WebTools\data\navigation.json。可以通过参数覆盖:

powershell.exe -NoProfile -ExecutionPolicy Bypass -File .\web-tools.ps1 start `
  -ListenAddress 127.0.0.1 `
  -Port 9100 `
  -DataDir C:\ProgramData\WebTools\data

不带操作参数运行 web-tools.ps1 时会显示交互菜单:

[1] Start current build (no update)
[2] Update from Git, rebuild, and start
[3] Update from Git and rebuild only
[0] Exit

日常双击或使用“使用 PowerShell 运行”打开脚本后,需要更新代码时选择 2;1 只启动磁盘上已有的 dist,不会拉取代码或重新构建。计划任务、快捷方式和自动化仍应显式传入 start、update 或 update -NoStart,不会进入菜单等待输入。

脚本不会自动修改 Windows 防火墙。需要从局域网访问默认端口时,可由管理员仅对专用网络配置入站规则:

New-NetFirewallRule -DisplayName 'Web Tools 9000' -Direction Inbound -Action Allow `
  -Protocol TCP -LocalPort 9000 -Profile Private

只允许本机或由反向代理访问时,使用 -ListenAddress 127.0.0.1,无需开放该端口。

从 Git main 分支更新时,先在运行窗口按 Ctrl+C 停止服务,再执行:

powershell.exe -NoProfile -ExecutionPolicy Bypass -File .\web-tools.ps1 update

更新脚本只接受干净的 Git 工作区和当前 main 分支,使用 git pull --ff-only origin main 避免隐式合并。随后执行 npm ci --include=dev、生产构建并自动重新启动服务。npm ci 会先删除现有 node_modules 再按 package-lock.json 完整重建,不需要手工删除旧依赖。只更新和构建、不立即启动时增加 -NoStart。

脚本不会读取、覆盖或删除 C:\ProgramData\WebTools\data。PowerShell 窗口关闭后前台服务会停止;如使用 Windows 计划任务,应让任务执行 web-tools.ps1 start,更新时停止任务、运行 web-tools.ps1 update -NoStart,然后重新启动任务。

Windows 单 EXE 交付状态

当前版本不交付 Windows 单 EXE。正式支持的部署方式仍是 Docker,或 Windows 上的 Node.js、Git 与 web-tools.ps1。对于自用 Windows Server,现有脚本更容易检查、更新和排障,因此单 EXE 不是必要条件。

若后续明确需要把程序交付给没有 Node.js 环境的 Windows 用户,建议采用 Node.js Single Executable Application(SEA),不要为本项目引入 Electron。实现时至少需要:

  1. 增加专用的 EXE 启动入口,并把生产 dist/、工具目录和默认导航配置作为只读资源嵌入。
  2. 抽象静态资源读取方式,使 Node 服务既能读取开发时的文件系统,也能读取 EXE 内嵌资源。
  3. 增加 SEA 配置、注入工具(通常为 postject)、build:exe 脚本以及 Windows x64/ARM64 分架构构建。
  4. 继续把 navigation.json 放在 EXE 外部的可写数据目录,默认使用 C:\ProgramData\WebTools\data,升级 EXE 时不得覆盖它。
  5. 增加 Windows Server 启动、端口、静态资源、/tools/setting、更新替换和杀毒软件兼容性冒烟测试。
  6. 正式对外分发时补充 EXE 图标/版本资源,并考虑 Authenticode 代码签名;未签名程序可能触发 SmartScreen 警告。

这项改造对源码体积影响不大,通常只是数十 KB 级的入口、资源适配和构建脚本,并增加少量开发依赖;真正明显的是发布产物。每个架构的 EXE 会包含 Node.js 运行时,常见为约 60-100 MB 未压缩、约 30-60 MB 压缩,具体随 Node 版本和资源大小变化。EXE 和中间产物必须保持在 .gitignore 或发布目录中,不提交到 Git,因此仓库不会明显膨胀;增加的主要成本是分架构构建、签名、测试和更新维护。

启动故障排查

  • ENOENT ... dist\\index.html:当前目录只有源码或尚未生成生产前端。先执行 npm.cmd ci --include=dev 和 npm.cmd run build,再启动服务;直接执行 node server\\index.mjs 不会替代构建步骤。
  • 页面能打开但左侧没有新工具:仅重新构建 dist 不会更新已经运行的 Node 进程。停止旧进程后重新启动,并在浏览器执行一次强制刷新(Ctrl+F5)。
  • 新工具仍未出现:确认服务输出的 Navigation config 路径与实际数据目录一致。旧的 navigation.json 会保留用户排序,只在服务重启后首次读取 API 时补入新工具。
  • 关闭 PowerShell 窗口后服务消失:前台启动是预期行为。需要长期运行时使用 Windows 计划任务或服务管理器,让任务执行 web-tools.ps1 start,不要依赖打开的交互窗口。

工具管理

管理入口不显示在页面中,直接访问:

http://服务器地址:9000/tools/setting

可以调整分类顺序、分类内工具顺序及工具所属分类。保存时采用同目录临时文件和原子替换。

导出配置(至少保存过一次排序后执行):

docker compose cp web-tools:/data/navigation.json ./navigation.json

导入配置:

docker compose cp ./navigation.json web-tools:/data/navigation.json
docker compose restart web-tools

升级应用前建议导出该文件。新版本增加工具时,服务端会保留已有顺序,并把缺少的新工具追加到其默认分类。

离线镜像

若交付目录包含 personal-web-tools-0.2.1-amd64.tar,可直接导入:

docker load -i personal-web-tools-0.2.1-amd64.tar
docker compose up -d --no-build

当前源码 ZIP 本身不是 Docker 镜像 tar。

本地开发

要求 Node.js 22.12.0 或更高版本。首次安装使用锁定依赖:

npm ci

终端一运行开发配置服务。这里的 8081 仅用于 Vite 开发代理,不是生产默认端口。PowerShell:

$env:PORT = '8081'
$env:DATA_DIR = (Join-Path (Get-Location) 'data')
node .\server\index.mjs

Bash:

PORT=8081 DATA_DIR=./data node server/index.mjs

终端二运行 Vite;/api 和 /healthz 会代理到 127.0.0.1:8081:

npm run dev

生产模式本地运行:

npm run build
npm start

生产服务默认监听 0.0.0.0:9000。

新增工具或修改 shared/tool-catalog.json、shared/default-navigation.json 后,不能只执行 npm run build。Node 服务会在启动时加载工具目录;必须先停止旧进程,再重新执行 npm start(Windows Server 使用 web-tools.ps1 start,Docker 使用 docker compose up -d --build)。服务重启后,已打开的浏览器页面还需要刷新,才会重新读取导航 API;已有 data/navigation.json 不会被覆盖,只会自动补入缺少的新工具。

完整工程检查:

npm run check
npm audit --audit-level=low

npm run check 会依次运行全部 Vitest 测试、TypeScript/Vue 类型检查和生产构建。服务端测试使用随机本地端口验证 SPA 直达路由、静态资源 404 与缓存策略、导航 API、请求大小限制及跨源浏览器写入拦截。

自动化测试还覆盖标准算法向量、Base64 规范性、Intel HEX 记录与 block 边界、固件 Hash 与大小端 Block 头向量、PNG 头部与像素限制、导航排序纯函数、目录/图标/懒加载组件一致性,以及原子写入失败后的临时文件清理。

增加工具

固件 Hash 固定语义

固件 Hash 与 CRC 共用经过校验的 Intel HEX 解析器,但使用独立纯逻辑、Worker 和 Vue 页面。解析器处理扩展段/线性地址,将数据按 32 位绝对地址排序,合并连续记录,去重内容一致的重叠记录,并拒绝冲突或越过 0xFFFFFFFF 的数据。记录文本、记录校验和、EOF 和启动地址不参与 Hash。

摘要计算优先使用浏览器原生 Web Crypto;通过普通 HTTP 局域网地址访问而无法使用 SubtleCrypto 时,自动回退到项目内已有的 node-forge SHA-256/SHA-512 实现。两条路径都在 Web Worker 中本地处理,不会把固件数据发送到服务端。

“有效数据”模式的总输入为所有 block 数据按地址升序直接拼接,不填充地址空洞。“Block 校验头”模式在每个 block 前加入 8 个二进制字节:

uint32 startAddress
uint32 dataLength

默认使用 Big Endian,可以显式切换 Little Endian。两个字段始终为 4 字节;dataLength 只表示该 block 的有效数据字节数,不包含 8 字节校验头。总输入严格为 Header1 || Data1 || Header2 || Data2 ...,同时输出总 SHA-256/SHA-512 和每个 block 的独立摘要。不得把固定宽度 Hex 文本误作为 ASCII 字符加入 Hash,也不得隐式使用运行设备的原生端序。

1. 先定义稳定标识

为工具选择永久的 kebab-case id,例如 url-encode。已发布工具的 id 不应修改,因为路由、懒加载映射和用户保存的导航配置都依赖它。

确定工具所属分类。新增分类时,需要同时更新:

  • shared/tool-catalog.json 中的 categories
  • shared/default-navigation.json 中的 categories

仅新增工具时,分类配置版本仍保持 version: 1,不要因为工具数量变化而升级配置格式版本。

2. 编写独立计算逻辑

将编码、解析、加密、校验或文件生成逻辑放入 src/lib/。优先使用浏览器标准 API或经过验证的现有依赖,不在 Vue 组件中堆积算法实现。

在 tests/ 添加正常输入、边界输入、无效输入和已知测试向量。涉及字节的工具必须明确 UTF-8、Hex、Base64、换行及分隔符语义,避免隐式改变数据。

文件或高开销工具还必须定义文件大小、记录数量、图像尺寸或输出 DOM 数量等资源上限。异步工具在清空、更换输入或卸载后必须忽略旧任务结果;计算量较大的文件解析与 CRC 计算放入 Web Worker。

3. 编写统一的工具页面

在 src/tools/ 新增一个 Vue 组件,并参考现有 Base64Tool.vue 或与需求最接近的工具。

  • 页面外层使用 ToolPage。
  • 文本输入输出优先使用 TextEditor。
  • 模式切换使用 ModeTabs。
  • 操作按钮使用 Lucide 图标和现有 action-button 类。
  • 必须提供清空、错误提示和必要的复制/粘贴操作。
  • 不增加登录、收藏、赞助、遥测、外部网络请求或独立视觉风格。
  • 在窄屏下确认控件不溢出、不重叠,文字不会遮挡。

4. 登记工具元数据

在 shared/tool-catalog.json 的 tools 中增加:

{
  "id": "url-encode",
  "title": "URL 编解码",
  "category": "encoding",
  "description": "编码和解码 URL 组件。",
  "icon": "Link"
}

id 必须唯一,category 必须存在。icon 使用 Lucide Vue 图标名称。

在 shared/default-navigation.json 的目标分类工具数组中加入相同 id,位置即新部署的默认显示顺序。

5. 注册图标与懒加载组件

在 src/tools/registry.ts 中完成三件事:

  1. 从 @lucide/vue 导入目录中填写的图标。
  2. 把图标加入 iconComponents。
  3. 把工具 id 和 defineAsyncComponent(() => import(...)) 加入 toolComponents。

工具目录、默认导航和注册表中的 id 必须完全一致。路由会从注册表自动生成,不需要修改 src/router.ts。

现有自动化测试会校验目录分类、工具 ID、图标注册和懒加载组件映射。新增工具后若漏改任一处,npm test 或应用启动会直接报错。

6. 验证兼容性

npm run check
npm audit --audit-level=low

还应在真实浏览器中检查:

  • 新工具的默认路径 /tools/<id> 可以直接打开和刷新。
  • 左侧导航、搜索和 /tools/setting 正常显示新工具。
  • 已保存的旧 navigation.json 在服务重启并首次读取后会自动补入新工具;仅重新构建 dist 不会刷新已经运行的 Node 进程。
  • 桌面端和约 390 x 844 的移动端竖屏布局正常。
  • 浏览器控制台无错误,工具内容没有发往服务端。

AI 接手清单

后续由 AI 增加或修改工具时,应先阅读本文件,然后依次检查:

  1. shared/tool-catalog.json 和 shared/default-navigation.json
  2. src/tools/registry.ts
  3. 与目标功能最接近的 src/tools/*.vue
  4. src/components/ToolPage.vue、TextEditor.vue、ModeTabs.vue
  5. 相关 src/lib/ 和 tests/
  6. server/navigation.mjs 中的导航兼容逻辑

AI 不应仅修改 dist/;必须修改源码并重新构建。不得覆盖或删除用户的 data/navigation.json。发现工作区已有未说明的改动时应保留并兼容,不得擅自回退。

处理多人访问、文件工具或异步计算时,还必须检查本文档中的“多人使用与状态边界”和“资源限制”,避免重新引入共享状态、旧任务覆盖新输入或无上限解析。

完成任务后至少报告:修改内容、关键数据格式选择,以及实际执行的测试和构建结果。只有在任务要求制作发布包时,才需要报告容器包/ZIP 路径及 SHA-256。涉及 UI 的改动还要进行桌面、中间宽度和移动端浏览器验收。

版本与发布

应用版本的唯一权威来源是 package.json。package-lock.json 记录完整依赖树、下载地址和完整性摘要,供 npm ci 复现安装;其中项目自身的版本会在文件顶部和 packages[""] 中各出现一次,其余 version 都是第三方依赖版本,不应手工统一修改。

使用 npm version patch --no-git-tag-version(或按兼容性选择 minor/major)可以同步更新 package.json 与 package-lock.json。按当前工程结构,一次完整版本发布需要更新以下 5 个已跟踪文件:

  1. package.json
  2. package-lock.json
  3. docker-compose.yml 中的镜像标签
  4. README.zh-CN.md 中的当前版本和离线镜像文件名
  5. CHANGELOG.md

README.md 不硬编码版本号,而是指向 package.json,因此无需为每次版本升级修改。AppSidebar.vue 构建时直接读取 package.json,无需手工改其中的版本字符串。发布新版本时:

  1. 先更新版本号,再同步镜像标签、本文档和 CHANGELOG.md。
  2. 运行 npm run check 和 npm audit --audit-level=low。
  3. 重新生成未跟踪的 dist/ 生产构建。
  4. 重新制作源码/容器部署 ZIP,以及任务要求的可选 Docker 镜像 tar,并生成 SHA-256。
  5. 检查发布包不包含 node_modules、运行数据、令牌、.env 或其他本机文件。

版本号固定显示在左侧导航底部;版权信息 Copyright © mid All Rights Reserved. 固定显示在所有页面底部。第三方许可保留在 THIRD_PARTY_NOTICES.md。

安全边界

  • 应用代码无登录、无统计、无遥测、无 CDN 资产和第三方网络请求;部署时可在外层使用 Cloudflare 反向代理。
  • /tools/setting 是固定但不显示的入口,不构成身份认证;直接公开到互联网时任何访问者都可能修改排序。
  • 工具内容仅在浏览器内存中处理,默认不会持久化。
  • 容器以非 root 用户运行,根文件系统只读,全部 Linux capabilities 已移除。
  • 服务端只接受不超过 64 KiB 的导航 JSON 配置。
  • 服务端只提供静态文件、GET/PUT /api/navigation 和 GET /healthz。
  • 只有无扩展名且明确请求 HTML 的前端路由会回退到 index.html;缺失的 JS、CSS 和其他资源返回 404。
  • 浏览器发起的导航配置写入只接受 Sec-Fetch-Site: same-origin;缺少该请求头的非浏览器客户端仍可写入,因此这项检查不能替代身份认证或外层访问控制。
  • JSON API 响应使用 Cache-Control: no-store,避免浏览器缓存导航和健康状态。
  • 只有文件名带构建指纹的 dist/assets/ 资源使用一年 immutable 缓存;HTML、favicon、Manifest 和其他稳定文件名资源使用 no-cache,更新后会重新验证。
  • 安全响应头禁止第三方脚本、跨站嵌入、摄像头、麦克风和定位权限;每个响应的 CSP 使用独立 128 位 nonce 兼容 Cloudflare JavaScript Detections,不允许 'unsafe-inline'。