feat: add local OneNote and ONEPKG reader

This commit is contained in:
2026-07-22 17:06:03 +02:00
commit f581cbdced
93 changed files with 14949 additions and 0 deletions

113
docs/SECURITY.md Normal file
View File

@@ -0,0 +1,113 @@
# Security model
## Trust boundary and local processing
Selected `.one` and `.onepkg` files are untrusted. The main thread checks the
source size, reads one file into an `ArrayBuffer`, transfers it to a dedicated
module worker, and receives serializable data-transfer objects. CAB entries are
extracted only into memory; archive paths are never written to the filesystem.
The worker is a fault-containment and responsiveness boundary, not a security
sandbox. A successful open keeps its worker session alive for page requests.
Clearing the file, choosing another file, or unmounting the app terminates that
worker; a failed open also terminates it. JavaScript garbage collection does
not promise immediate release or secure erasure.
The application does not:
- upload or transmit notebook bytes;
- use a backend, proxy, telemetry, analytics, remote fonts, or external content
fetching;
- persist source or derived content in LocalStorage, IndexedDB, Cache Storage,
cookies, or a service worker;
- execute notebook content or inject notebook HTML/SVG;
- use WebAssembly, a Rust runtime, or a native helper.
## Active default limits
The main thread rejects a source larger than 512 MiB before reading it. The
desktop section parser then applies these independent defaults:
| Resource | Default limit |
| ------------------------------------- | -------------------: |
| Section bytes | 512 MiB |
| File-node list fragments / nesting | 16,384 / 64 |
| File nodes | 1,000,000 |
| Objects | 500,000 |
| Properties per set / property nesting | 16,384 / 64 |
| Stream IDs | 1,000,000 |
| One property vector | 64 MiB |
| Object references | 1,000,000 |
| Content-graph depth | 256 |
| Pages per section | 100,000 |
| Diagnostics per section | 10,000 |
| Extracted text per section | 2,000,000 characters |
The CAB/package path applies these defaults:
| Resource | Default limit |
| ------------------------------- | -------------: |
| Cabinet input | 512 MiB |
| Folders / files | 1,024 / 10,000 |
| CFDATA blocks | 131,072 |
| CAB name bytes | 255 |
| Path characters / path segments | 4,096 / 64 |
| One extracted file | 256 MiB |
| One folder output | 512 MiB |
| Total folder output | 512 MiB |
| Total extracted entry bytes | 512 MiB |
| Folder compression ratio | 200:1 |
| LZX window | 8 MiB |
| LZX decode operations | 1,000,000,000 |
A CFDATA block may declare at most 32 KiB of output. Counts and offsets use
checked arithmetic and bounded readers. The CAB parser verifies supplied block
checksums, rejects overlapping/out-of-range data, rejects absolute/traversal,
empty, control-character, and case-insensitive duplicate paths, and refuses
multi-cabinet/spanning entries.
LZX checks its window, Huffman trees, block sizes, match ranges, output size,
and operation budget. CAB extraction checks cancellation and yields between
data blocks so the worker can process termination. Desktop OneStore traversal
checks fragment/reference cycles, nesting, object/property/reference counts,
and byte ranges.
## Rendering and links
DTO strings are rendered as React text nodes. Notebook HTML, active SVG,
scripts, attachment payloads, and automatic external navigation are not
rendered. Link activation is not implemented. If links are added, they require
explicit user action, scheme validation, and safe navigation attributes.
## Known gaps and roadmap
- There is no wall-clock deadline. Synchronous desktop `.one` parsing cannot
observe cooperative cancellation until control returns; terminating the
worker is the current hard stop.
- The package flow holds the source, decompressed folder buffers, extracted
entry slices, and parsed DTOs in memory at overlapping times. The byte/count
limits bound these individually but do not guarantee a low peak heap.
- Section text/page/diagnostic limits apply per contained section rather than
once to the complete package.
- CAB checksums detect accidental corruption but do not authenticate a package.
- Format coverage is narrow and has only the documented golden files. New
producer/version claims require licensed regression fixtures and malformed
variants.
- The worker boundary reduces UI impact but is not a substitute for browser and
operating-system isolation. Open especially sensitive files in a dedicated
browser profile if that risk matters.
Planned hardening includes an elapsed-time budget, cancellation checkpoints in
desktop OneStore graph traversal, aggregate package DTO/text budgets, lower
peak-memory extraction, expanded malformed-input/fuzz corpora, and additional
licensed OneNote export fixtures.
## Fixtures and vulnerability reporting
Never commit private notebooks. Fixture provenance and redistribution terms
must be recorded in `tests/fixtures/README.md`.
Report suspected parser vulnerabilities privately to the repository owner
through the Gitea instance before publishing malicious fixtures. Include the
application version, browser, smallest reproducible input, diagnostic, and
observed resource use. Do not attach sensitive notebooks.