发布 0.2.1 并完善工具边界与安全性

This commit is contained in:
mid
2026-08-10 14:49:43 +08:00
parent aca004c513
commit 32b7cc827c
47 changed files with 681 additions and 172 deletions
+19 -10
View File
@@ -15,8 +15,10 @@ This file is mandatory for AI and coding agents working in this repository. Read
- Web Tools is an anonymous-access, self-hosted Vue 3 + TypeScript browser-local tools application with a zero-dependency Node.js static/configuration server.
- The default production port is `9000`. Port `8081` is only the local Vite development proxy target.
- The application is anonymous. Do not add login, accounts, favorites, sponsorship, analytics, telemetry, advertising, CDN assets, or a database.
- A deployment may place Cloudflare in front of the origin. The server's per-response CSP nonce exists only to support Cloudflare JavaScript Detections without `unsafe-inline`; it is not permission to add application analytics, telemetry, or remote tool processing.
- Tool inputs, keys, files, images, and results must remain inside the current browser tab. Do not send them to the Node server, a third-party API, or any remote service.
- `/setting` is a fixed, unlisted route for navigation management. It has no authentication and is not a security boundary. Anyone who can access the application can open it and change the globally shared navigation order.
- `/tools/setting` is the fixed, unlisted route for navigation management. It has no authentication and is not a security boundary. Anyone who can access the application can open it and change the globally shared navigation order.
- The first-run default category order is `encoding`, `checksum`, `crypto`, `formatting`, `image`; an existing saved navigation file keeps its custom order and is never reset by a release.
- The server persists only navigation configuration. Preserve `data/navigation.json` and the configured external data directory; writes must remain temporary-file plus atomic-replace operations.
- Multiple users and tabs may use every tool concurrently. Their calculation state must remain independent; only navigation order is globally shared.
@@ -34,14 +36,14 @@ This file is mandatory for AI and coding agents working in this repository. Read
## Stable tool behavior
- ASCII/Hex uses UTF-8. Hex input accepts continuous text or chunks separated by whitespace, English commas, or Chinese commas, with an optional `0x` prefix on each chunk. Invalid UTF-8 must fail rather than silently replace bytes.
- UTF-8 / Hex has the permanent tool ID `utf8-hex` and route `/tools/utf8-hex`. It uses strict UTF-8 conversion. Hex input accepts continuous text or chunks separated by whitespace, English commas, or Chinese commas, with an optional `0x` prefix on each chunk. Invalid UTF-8 must fail rather than silently replace bytes.
- Base64 supports standard and URL-safe input. Decoded output supports strict UTF-8, continuous Hex, and `0xNN, ...` byte arrays. Reject invalid characters, padding placement, lengths, and non-canonical trailing bits.
- AES-128-CMAC follows RFC 4493. The key is exactly 16 bytes of Hex and accepts continuous input or whitespace/comma/Chinese-comma-separated chunks with optional `0x` prefixes. Hex messages use the same parser.
- CRC supports BIN and multi-block Intel HEX, CRC-8/16/32/64 presets, and custom `Width`, `Poly`, `Init`, `XorOut`, `RefIn`, and `RefOut`. Combined data is ordered by address without filling gaps, and per-block results remain available.
- AES-CMAC accepts exactly 16, 24, or 32 key bytes for AES-128, AES-192, or AES-256, defaulting to 16 bytes. Never pad or truncate the key. Key and Hex-message input accepts continuous Hex or whitespace/comma/Chinese-comma-separated chunks with optional `0x` prefixes. The CMAC tag remains exactly 16 bytes for every key size. Preserve RFC 4493 AES-128 and NIST SP 800-38B AES-192/256 vectors.
- CRC supports BIN and multi-block Intel HEX, CRC-8/16/32/64 presets, and custom `Width`, `Poly`, `Init`, `XorOut`, `RefIn`, and `RefOut`. The Chinese UI labels `RefIn`/`RefOut` as input/output bit reversal; these flags do not reverse byte order or the complete input. Combined data is ordered by address without filling gaps, and per-block results remain available.
- Firmware Hash accepts Intel HEX and computes SHA-256 and SHA-512. Effective-data mode concatenates sorted blocks without gap filling. Block-header mode prepends exactly two binary uint32 values, `startAddress` and data-only `dataLength`, to every block. Both fields are four bytes; Big Endian is the default; total input is `Header1 || Data1 || Header2 || Data2 ...`. Never hash a textual Hex representation of the header.
- RSA allows 2048, 3072, and 4096-bit keys with public exponent 65537. Prefer Web Crypto; the node-forge fallback must be seeded from `crypto.getRandomValues`. Export public SPKI PEM, private PKCS#8 PEM, and separately copyable N/E continuous Hex or byte arrays.
- Secure random output comes only from `crypto.getRandomValues`, is limited to 1-65,536 bytes, and supports continuous Hex, spaced Hex, and byte arrays. Changing display format must not regenerate bytes.
- JSON/XML formatting, minification, validation, and syntax highlighting stay local. When highlighting limits are exceeded, render the complete result as plain text rather than truncating it.
- RSA allows 2048, 3072, and 4096-bit keys with public exponent 65537. Prefer Web Crypto; dynamically load the node-forge fallback only when needed, and seed it from `crypto.getRandomValues`. Export public SPKI PEM, private PKCS#8 PEM, and separately copyable N/E continuous Hex or byte arrays.
- Secure random output comes only from `crypto.getRandomValues`, defaults to 16 bytes, is limited to 1-65,536 bytes, and supports continuous Hex, spaced Hex, and byte arrays. Changing display format must not regenerate bytes. Missing or failed cryptographic sources must fail closed without a pseudorandom fallback.
- JSON/XML formatting, minification, validation, and syntax highlighting stay local. XML parser failures are identified by the browser parser-error namespace; a valid user element named `parsererror` must not be rejected. When highlighting limits are exceeded, render the complete result as plain text rather than truncating it.
- PNG/ICO processing stays local and must enforce both compressed-file and decoded-pixel limits before costly rendering or allocation.
## Intel HEX and asynchronous safety
@@ -49,6 +51,8 @@ This file is mandatory for AI and coding agents working in this repository. Read
- Treat every address, length, end-address, offset, and allocation calculation as checked uint32 arithmetic. JavaScript bitwise operators are signed 32-bit and must not be used as unchecked address arithmetic.
- Validate record syntax, byte counts, checksums, control-record lengths/addresses, EOF placement, extended addresses, and the `0xFFFFFFFF` boundary.
- Sort records by absolute address, merge contiguous records, deduplicate identical overlaps, and reject conflicting overlaps. Enforce record, block, and effective-byte limits before allocating combined buffers.
- The default Intel HEX effective-data allocation limit is 64 MiB (`DEFAULT_MAX_INTEL_HEX_BYTES`); keep it aligned with `MAX_FIRMWARE_FILE_SIZE` and the limits table in `README.zh-CN.md`.
- Navigation GET normalization and PUT writes are serialized within each Node process. Do not remove that lock without replacing it with an equally strong concurrency design.
- CRC and Firmware Hash may share the reviewed Intel HEX parser but must keep separate calculation logic, Worker protocols, and Vue state.
- File replacement, clear, mode change, option change, repeated generation, and component unmount can invalidate asynchronous work. Terminate obsolete Workers where possible and use monotonically increasing request/version IDs. A stale Worker, file read, image decode, or key-generation result must never replace current state.
- Clear the native file input value after handling a selection so choosing the same file again still emits a change event.
@@ -61,15 +65,16 @@ This file is mandatory for AI and coding agents working in this repository. Read
- Keep desktop controls compact. Use stable grid/flex constraints and allow controls to become full-width where appropriate on narrow screens.
- Prevent horizontal page overflow, clipped controls, nested scrolling accidents, text overlap, layout shifts, and unbounded result columns. Long Hex, hashes, filenames, and table cells require explicit wrapping or contained scrolling.
- Version information remains at the bottom of the sidebar and is read from `package.json`. Every page footer displays exactly `Copyright © mid All Rights Reserved.`
- Do not add a visible link to `/setting`, explanatory marketing copy, login UI, favorites, or sponsorship UI.
- Do not add a visible link to `/tools/setting`, explanatory marketing copy, login UI, favorites, or sponsorship UI.
- Every native `input`, `select`, and `textarea` must have a unique `id` and stable `name`. `TextEditor` requires an explicit `id` and uses it as the default `name`; preserve the existing implicit or explicit label association.
- Preserve the application icon contract under `public/`: `favicon.svg`, a 16/32/48-frame `favicon.ico`, `apple-touch-icon.png` at 180x180, `icon-192.png`, `icon-512.png`, `icon-maskable-512.png`, and `site.webmanifest`. Keep the icon visually aligned with the sidebar brand and keep the maskable artwork inside its safe zone.
- The manifest is metadata/install-ready only. Do not add a Service Worker, offline cache, install prompt, splash-screen bundle, Safari mask icon, legacy `browserconfig.xml`, redundant Apple sizes, or separate 16/32 PNG favicons unless requirements explicitly change.
- Preserve the share metadata contract: the single user-facing description is exactly `一个匿名访问、自托管的浏览器本地工具箱`, represented by the standard HTML description and the identical `og:description` compatibility field. Do not add a custom share image, other Open Graph or platform-specific metadata, platform crawlers, route-specific previews, tool lists, or user data. Sharing clients may fall back to the document title and existing favicon assets, but their final preview and cache behavior remain platform-controlled.
- For UI work, verify a wide desktop, an intermediate width around 801-1040 px, and mobile portrait around 390 x 844 in a real browser. Check direct routes, refresh, navigation, search, `/setting`, both themes, console errors, and network requests.
- For UI work, verify a wide desktop, an intermediate width around 801-1040 px, and mobile portrait around 390 x 844 in a real browser. Check direct routes, refresh, navigation, search, `/tools/setting`, both themes, console errors, and network requests.
## Adding a tool
1. Choose a permanent, unique kebab-case ID. Published IDs must not change because routes and saved navigation depend on them.
1. Choose a permanent, unique kebab-case ID. IDs must remain stable after publication because routes and saved navigation depend on them. The recorded pre-0.2.0 correction from `ascii-hex` to `utf8-hex` is the sole existing ID migration. `setting` is reserved by `/tools/setting` and cannot be used as a tool ID.
2. Add pure logic and normal, invalid, boundary, resource-limit, and known-vector tests.
3. Add one Vue component under `src/tools/` using shared components and responsive styles.
4. Add matching metadata to `shared/tool-catalog.json` and its default position to `shared/default-navigation.json`. Only change navigation `version: 1` for a schema migration, not for a new tool.
@@ -77,6 +82,7 @@ This file is mandatory for AI and coding agents working in this repository. Read
6. Verify that an old saved `navigation.json` retains its order and receives the missing tool after the Node process restarts and navigation is next loaded.
IDs must remain synchronized across the catalog, default navigation, icon map, and component registry. Existing catalog tests enforce this contract.
The `ascii-hex` ID is a legacy input accepted only while normalizing existing `navigation.json` files; it migrates in place to `utf8-hex`. Do not restore it as a catalog ID, component key, form-field prefix, or route.
## Deployment and release
@@ -85,6 +91,9 @@ IDs must remain synchronized across the catalog, default navigation, icon map, a
- The Windows update flow requires a clean `main` checkout and uses `git pull --ff-only`. Preserve external `C:\ProgramData\WebTools\data` state.
- Running `web-tools.ps1` without an action is an interactive user entry point and must keep the start/update/update-without-start/exit menu. Scheduled tasks and automation must pass an explicit `start` or `update` action so they never wait for input.
- New catalog data is loaded by the Node process at startup. Rebuilding `dist` alone is insufficient after catalog changes; restart the server and refresh already-open browser pages.
- Preserve the per-response 128-bit CSP nonce generated with `node:crypto`. Cloudflare parses the nonce from the response header for JavaScript Detections. Never replace it with a fixed nonce or `unsafe-inline`; keep HTML uncached/no-cache so a document and its nonce cannot become mismatched.
- Keep one-year immutable caching limited to fingerprinted files under `dist/assets/`. Stable filenames such as HTML, favicon assets, and `site.webmanifest` must use `no-cache` so a deployment can replace them safely.
- Browser navigation PUT requests carrying Fetch Metadata must be same-origin. Requests without `Sec-Fetch-Site` remain supported for non-browser administration, so document this as defense in depth and never as authentication.
- If a single EXE is later authorized, use Node.js SEA with embedded read-only web/catalog assets and an external writable data directory. Add per-architecture builds, asset-read abstraction, Windows smoke tests, replacement/update instructions, and optional Authenticode signing. Derive EXE version metadata from `package.json`; do not create another manually maintained version source. Do not commit generated executables.
For a release, synchronize these five tracked files: