feat: add local OneNote and ONEPKG reader
This commit is contained in:
113
docs/SECURITY.md
Normal file
113
docs/SECURITY.md
Normal 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.
|
||||
Reference in New Issue
Block a user