release: prepare OneNote Tools 0.2.0

This commit is contained in:
2026-07-22 20:17:09 +02:00
parent edb19bfcc8
commit 41cffdc5d9
19 changed files with 423 additions and 234 deletions

View File

@@ -1,5 +1,34 @@
# Changelog # Changelog
## 0.2.0 - 2026-07-22
- Open unfragmented FSSHTTPB package-store `.one` sections through the same
bounded page/content model as desktop revision stores.
- Interpret desktop and FSSHTTPB `.onetoc2` stores into authored section-group,
section, page, and subpage trees, with identity fallback and deterministic
handling of missing, duplicate, cyclic, and unlisted entries.
- Add complete-set CAB extraction for multi-cabinet packages, including split
CFDATA blocks, spanning files, codec continuity, link validation, aggregate
limits, and browser selection of one `.onepkg` plus its `.cab` companions.
- Add native MSZIP and Quantum decoding alongside uncompressed and LZX CAB
support.
- Parse and render structured outlines, rich-text formatting and safe links,
tables, signature/header-validated PNG/JPEG images, decoded ink, layout hints,
and declared embedded attachments.
- Add local structured JSON, text, Markdown, inert HTML, and deterministic
static notebook ZIP exports with diagnostics, unsupported-content summaries,
normalized resource names, and bounded output.
- Add independent parser, image-preview, display, TOC, cabinet-set, and export
resource budgets. Oversized images remain explicitly downloadable but are
not copied or decoded for automatic preview.
- Verify the implementation against the redistributable OneNote golden corpus,
a licensed five-part libmspack fixture, adversarial malformed inputs, and two
private `.onepkg` files without committing their bytes.
Known unsupported areas remain fragmented FSSHTTPB data-element reconstruction,
equations, audio/video, pixel-perfect page placement, and untested OneNote
producer variants.
## 0.1.0 - 2026-07-22 ## 0.1.0 - 2026-07-22
- Add a standalone React/Vite reader integrated with Toolbox SDK 0.1.1, - Add a standalone React/Vite reader integrated with Toolbox SDK 0.1.1,
@@ -8,21 +37,17 @@
- Add a worker-hosted native TypeScript parser for a desktop OneNote - Add a worker-hosted native TypeScript parser for a desktop OneNote
revision-store subset: bounded file-node and object-space traversal, revision-store subset: bounded file-node and object-space traversal,
property sets, page metadata, titles, timestamps, levels, and plain text. property sets, page metadata, titles, timestamps, levels, and plain text.
- Add bounded FSSHTTPB packaging, storage-index/cell/revision/object-group - Add in-memory CAB enumeration and extraction for uncompressed and LZX
parsing and open unfragmented package-store `.one` sections through the same folders, including checksums, strict paths, explicit resource limits, and
content model. cooperative cancellation between data blocks.
- Add in-memory CAB enumeration and extraction for uncompressed, MSZIP,
Quantum, and LZX folders, including checksums, strict paths, explicit
resource limits, and cooperative cancellation between data blocks.
- Open contained `.one` sections independently and expose package entries, - Open contained `.one` sections independently and expose package entries,
section/page navigation, partial failures, and structured diagnostics. section/page navigation, partial failures, and structured diagnostics.
- Verify a Joplin `.one` golden with three pages and a Joplin LZX `0x1203` - Verify a Joplin `.one` golden with three pages and a Joplin LZX `0x1203`
`.onepkg` golden with seven entries, five sections, and seven pages. Also `.onepkg` golden with seven entries, five sections, and seven pages. Also
verify rust-cab uncompressed, MSZIP, and LZX `0x1303` fixtures plus a verify rust-cab uncompressed and LZX `0x1303` fixtures.
generated two-block MSZIP dictionary-chain fixture and pinned Quantum
single-/multi-frame payloads.
- Add deterministic static release packaging, SHA-256 sidecars, pinned-source - Add deterministic static release packaging, SHA-256 sidecars, pinned-source
provenance, fixture licensing, and security/support documentation. provenance, fixture licensing, and security/support documentation.
Known unsupported areas include fragmented FSSHTTPB data-element Known unsupported areas are FSSHTTP-packaged `.one`, MSZIP and Quantum CAB
reconstruction and untested OneNote producer variants. extraction, multi-cabinet archives, `.onetoc2` hierarchy/order interpretation,
visual content, attachments, layout/format fidelity, links, and exports.

10
LICENSE
View File

@@ -1,4 +1,8 @@
SPDX-License-Identifier: MPL-2.0 SPDX-License-Identifier: MPL-2.0 AND LGPL-2.1-only
OneNote Tools is licensed under the Mozilla Public License, version 2.0. OneNote Tools is primarily licensed under the Mozilla Public License, version
The complete, unmodified licence text is provided in LICENSES/MPL-2.0.txt. 2.0. The adapted multi-cabinet implementation in
src/onenote/onepkg/cabinet-set.ts is LGPL-2.1-only. Complete, unmodified licence
texts are provided in LICENSES/MPL-2.0.txt and
LICENSES/libmspack-LGPL-2.1.txt. Other adapted and third-party material remains
under the terms recorded in THIRD_PARTY_NOTICES.md.

View File

@@ -1,53 +1,61 @@
# OneNote Tools # OneNote Tools
OneNote Tools is a standalone, local-first browser reader for a tested subset OneNote Tools is a standalone, local-first browser reader and exporter for a
of Microsoft OneNote `.one` sections and CAB-based `.onepkg` packages. The tested subset of Microsoft OneNote `.one` sections and CAB-based `.onepkg`
parser is native TypeScript, runs in a dedicated module worker, and never packages. Its native TypeScript parser runs in a dedicated module worker; the
uploads or persists the selected notebook. selected notebook is neither uploaded nor persisted.
It is also an independent application in the add·ideas Toolbox contract: the It is also an independent application in the add·ideas Toolbox contract. The
source uses the Toolbox SDK shell and manifest, builds with Vite `base: './'`, source uses the Toolbox SDK shell and manifest, builds with Vite `base: './'`,
and is delivered to Toolbox Portal as an already-built, checksummed static ZIP. and is delivered to Toolbox Portal as a checksummed static ZIP.
## What version 0.1.0 can open ## What version 0.2.0 supports
- Desktop revision-store `.one` sections from the tested OneNote family. The - Desktop revision-store and unfragmented FSSHTTPB package-store `.one`
reader exposes section/page names, stable page IDs, created and updated sections from the tested producer families.
timestamps when present, page level, and readable plain text. - Complete single- or multi-cabinet `.onepkg` sets using uncompressed, MSZIP,
- Unfragmented FSSHTTPB-packaged `.one` sections matching the tested Joplin Quantum, or LZX CAB folders. Split packages can be selected as one `.onepkg`
family. Package cells, revision chains, object groups, and resolved object file together with all of its `.cab` companions, in any selection order.
and page-space references feed the same bounded content reader. - Desktop and FSSHTTPB `.onetoc2` stores inside packages. Section groups,
- Single-cabinet `.onepkg` files whose CAB folders are uncompressed, MSZIP, authored section order, recycle-bin filtering, pages, and subpages are
Quantum, or LZX compressed. Each contained supported `.one` section is presented as a notebook tree; unresolved entries retain a deterministic
parsed independently, so one unsupported section does not hide sections that fallback rather than hiding readable sections.
did parse. - Structured page content: outlines and layout hints, rich-text runs, safe
- Package entries, safe normalized paths, uncompressed sizes, compression links, tables, PNG/JPEG images, decoded ink strokes, and declared embedded
metadata, section/page navigation, and structured diagnostics. attachments. Resource bytes remain lazy until previewed, explicitly
downloaded, or included in an explicit export.
- Local exports as structured JSON, plain text, Markdown, inert semantic HTML,
or a deterministic static notebook ZIP. Exports retain parser diagnostics
and unsupported-content summaries; they do not create or modify OneNote
files.
The golden tests parse a real Joplin desktop `.one` file with three pages, an The redistributable golden corpus covers desktop and unfragmented FSSHTTPB
unfragmented 17,197-byte Joplin FSSHTTPB `.one` file with one page, and a real sections, a real LZX `.onepkg`, all four CAB compression modes, a five-part
Joplin `.onepkg` with seven entries, five sections, and seven pages. LZX spanning CAB set, TOC hierarchy behavior, rich content, resources, and every
`0x1203` and `0x1303`, uncompressed CAB, one- and two-block MSZIP data, and export format. The generic MSZIP, Quantum, and multi-cabinet fixtures establish
single- and multi-frame Quantum data are covered by fixtures. The MSZIP and CAB behavior; they are not claims about every OneNote producer.
Quantum fixtures are CAB-level evidence, not a claim about a particular
OneNote `.onepkg` producer.
This is a structural reader, not a full-fidelity OneNote renderer. Images, This remains a deliberately bounded compatibility subset. Fragmented FSSHTTPB
tables, ink, embedded files, layout, formatting, links, and exports are not data-element reconstruction, equations, audio/video, and untested producer
rendered. Fragmented FSSHTTPB data elements and some producer variants remain variants are not supported. Visual placement is approximate rather than a
unsupported. See pixel-perfect OneNote layout. See [format support](docs/FORMAT_SUPPORT.md) for
[format support](docs/FORMAT_SUPPORT.md) for the precise matrix. the precise matrix.
There is no Rust/Wasm runtime, server, proxy, upload, telemetry, or notebook There is no Rust/Wasm runtime, notebook-processing application backend, upload
storage. All parsing and CAB/LZX/MSZIP/Quantum decompression is ordinary proxy, telemetry, or notebook storage. All parsing and CAB decompression is
browser JavaScript produced from the TypeScript source. ordinary browser JavaScript produced from the TypeScript source.
## Use ## Use
Run the static build or open it through Toolbox Portal, then drop or choose one Run the static build or open it through Toolbox Portal, then:
local `.one` or `.onepkg` file. Use **Clear file** to terminate the current
worker and release application references. Browser garbage collection does not - choose one local `.one` file; or
provide a secure-erasure guarantee. - choose one `.onepkg` file and, for a split package, all linked `.cab` parts
in the same file-picker action.
Use **Clear file** to terminate the current worker and release application
references. Browser garbage collection does not provide a secure-erasure
guarantee.
## Development ## Development
@@ -72,7 +80,7 @@ supplied through the SDK's `?toolbox=` context mechanism. The app uses the SDK
```sh ```sh
npm run release:artifact npm run release:artifact
(cd release && sha256sum -c onenote-tools-0.1.0.sha256) (cd release && sha256sum -c onenote-tools-0.2.0.sha256)
``` ```
The ZIP root contains the built static app and manifest plus the changelog, The ZIP root contains the built static app and manifest plus the changelog,
@@ -95,7 +103,7 @@ into the portal React tree.
## Licence ## Licence
OneNote Tools is licensed under MPL-2.0. The complete licence is in OneNote Tools is primarily MPL-2.0; the adapted multi-cabinet module is
[`LICENSES/MPL-2.0.txt`](LICENSES/MPL-2.0.txt). Adapted and third-party material LGPL-2.1-only. The complete licence texts are in [`LICENSES/`](LICENSES/), and
remains under the terms recorded in adapted/third-party material remains under the terms recorded in
[`THIRD_PARTY_NOTICES.md`](THIRD_PARTY_NOTICES.md). [`THIRD_PARTY_NOTICES.md`](THIRD_PARTY_NOTICES.md).

View File

@@ -1,8 +1,8 @@
# Corresponding source # Corresponding source
The corresponding source for OneNote Tools 0.1.0 is the `v0.1.0` tag: The corresponding source for OneNote Tools 0.2.0 is the `v0.2.0` tag:
https://git.add-ideas.de/zemion/onenote-tools/src/tag/v0.1.0 https://git.add-ideas.de/zemion/onenote-tools/src/tag/v0.2.0
Build the release from that tag with Node.js 22 or newer: Build the release from that tag with Node.js 22 or newer:

View File

@@ -28,6 +28,17 @@ modules, pinned at `04a6db2aa7bd487a89c559631d79d1b384139f50`. Its adapted
modules carry provenance headers and its licence is in modules carry provenance headers and its licence is in
`LICENSES/compcol-MIT.txt`. `LICENSES/compcol-MIT.txt`.
Multi-cabinet chain construction, split CFDATA handling, and spanning-file
semantics adapt libmspack's LGPL-2.1-only CAB decompressor, pinned at
`55d501976171397ccd5d5a7a1ca7da065b1d9a06`. The adapted module carries its
copyright/provenance header and the complete licence is in
`LICENSES/libmspack-LGPL-2.1.txt`.
`one2html` (MIT), pinned at
`59930ad309004030f812790c6749efe4265bb6bd`, was inspected as a behavioral
reference for rich-content rendering. No one2html source, template, stylesheet,
binary, or runtime dependency is shipped in this application.
MSZIP raw DEFLATE decoding uses fflate 0.8.3 (MIT). Its complete installed MSZIP raw DEFLATE decoding uses fflate 0.8.3 (MIT). Its complete installed
licence text is included in the generated runtime licence bundle. licence text is included in the generated runtime licence bundle.
@@ -49,5 +60,6 @@ The encoded fixture bytes are excluded from `dist` and the release ZIP. The
release retains the fixture provenance document and AGPL text so these notices release retains the fixture provenance document and AGPL text so these notices
remain complete. remain complete.
The remaining npm packages are build and test tooling and are not shipped as Vite and the remaining npm packages are build/test tooling rather than runtime
runtime modules in the static application. modules. Vite's optional modulepreload runtime polyfill is explicitly disabled
for this baseline-browser build.

View File

@@ -1,20 +1,27 @@
# Format support # Format support
## Version 0.1.0 support matrix ## Version 0.2.0 support matrix
| Input or feature | Status | Tested evidence and boundary | | Input or feature | Status | Tested evidence and boundary |
| ---------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------- | | -------------------------------- | -------------------- | ---------------------------------------------------------------------------------------------------- |
| Desktop revision-store `.one` | Supported subset | Real 34,904-byte Joplin golden; three pages | | Desktop revision-store `.one` | Supported subset | Real 34,904-byte Joplin golden; three pages and rich content |
| FSSHTTPB-packaged `.one` | Supported subset | Licensed 17,197-byte Joplin golden; one page; unfragmented data elements | | FSSHTTPB package-store `.one` | Supported subset | Licensed 17,197-byte Joplin golden; one page; unfragmented data elements |
| Unknown/legacy `.one` variants | Unsupported | File type and format GUIDs are validated before traversal | | Unknown/legacy `.one` variants | Unsupported | File type and format GUIDs are validated before traversal |
| `.onepkg`, single CAB, LZX | Supported subset | Real Joplin package: LZX `0x1203`, three CFDATA blocks, seven entries, five sections, seven pages | | `.onepkg`, one CAB | Supported subset | Real Joplin LZX package; generated/pinned none, MSZIP, Quantum, and LZX codec fixtures |
| CAB LZX `0x1303` | Supported extraction | Byte-for-byte rust-cab MIT unit fixture, two text entries | | `.onepkg`, complete CAB set | Supported extraction | Licensed five-part libmspack set plus split-block, spanning-file, ordering, and malformed-set tests |
| CAB without compression | Supported extraction | Byte-for-byte rust-cab MIT unit fixture | | Missing/inconsistent CAB parts | Rejected | Set ID, indexes, previous/next names, compression, split blocks, and spanning records must agree |
| CAB MSZIP | Supported extraction | rust-cab single-block fixture plus a generated two-block dictionary-chain fixture | | CAB without compression | Supported extraction | Byte-for-byte rust-cab fixture |
| CAB Quantum | Supported extraction | Pinned compcol qtm.txt payload, generated one-folder CAB, and two-frame state/sentinel tests | | CAB MSZIP | Supported extraction | rust-cab single block plus generated two-block dictionary-chain fixture |
| Multi-cabinet CAB / spanning files | Unsupported | Header flags and spanning folder indexes are rejected | | CAB Quantum | Supported extraction | Pinned compcol payloads and generated CAB integration fixture |
| `.onetoc2` package entries | Listed only | Files are identified, but notebook hierarchy and section order are not interpreted | | CAB LZX | Supported extraction | Real OneNote `0x1203` package and rust-cab `0x1303` fixture |
| Standalone `.onetoc2` | Unsupported in the app | The picker accepts only `.one` and `.onepkg` | | `.onetoc2` inside a package | Supported subset | Desktop golden/hierarchy tests; FSSHTTPB dispatch uses a mocked shared-store seam, not a real golden |
| Standalone `.onetoc2` in the app | Not selectable | The picker accepts `.one`, or `.onepkg` together with `.cab` companions |
| Rich text and layout hints | Supported subset | Run formatting, paragraph properties, safe links, and bounded layout metadata |
| Tables | Supported subset | Rows, cells, nested blocks, column widths, locks, borders, and cell backgrounds |
| Images | Supported subset | Lazy, signature/header-validated PNG and JPEG resources; unsafe images stay downloadable only |
| Ink | Supported subset | Bounded delta decoding, strokes, colors, width/height, transparency, and SVG display/export |
| Embedded attachments | Supported subset | `ATTACHMENT_DECLARATION`/file-data resources remain inert until explicit download |
| Export | Supported subset | JSON, text, Markdown, inert HTML, and deterministic static notebook ZIP |
“Supported subset” is intentionally narrower than “all files with this “Supported subset” is intentionally narrower than “all files with this
extension.” A successful open requires the tested desktop or FSSHTTPB OneStore extension.” A successful open requires the tested desktop or FSSHTTPB OneStore
@@ -22,6 +29,8 @@ structures and content graph nodes. Malformed offsets, counts, references, CAB
checksums, paths, compressed data, and unsupported variants produce bounded checksums, paths, compressed data, and unsupported variants produce bounded
diagnostics or a controlled failure. diagnostics or a controlled failure.
## OneStore and package boundaries
FSSHTTPB support covers the OneStore packaging envelope, Storage Index and FSSHTTPB support covers the OneStore packaging envelope, Storage Index and
Storage Manifest, header/data-root cells, bounded revision chains, Object Group Storage Manifest, header/data-root cells, bounded revision chains, Object Group
partitions, resolved object/page-space references, and available Object Data partitions, resolved object/page-space references, and available Object Data
@@ -31,49 +40,68 @@ the store adapter rejects packages containing fragment records with a
controlled `UNSUPPORTED_FORMAT` error. Excluded object data cannot be controlled `UNSUPPORTED_FORMAT` error. Excluded object data cannot be
reconstructed from a standalone file and is likewise unsupported. reconstructed from a standalone file and is likewise unsupported.
For a split package, the browser must receive the `.onepkg` and every linked
`.cab` companion in one selection. The extractor validates a complete,
uniquely indexed cabinet chain before decoding. It reassembles split CFDATA
blocks, preserves codec state across cabinets, and reconciles the CAB
`continued from previous`, `continued to next`, and `continued both` file
records. Partial sets are not opened heuristically.
The default LZX limit accepts CAB window sizes through 8 MiB, but compatibility The default LZX limit accepts CAB window sizes through 8 MiB, but compatibility
claims are fixture-backed only for window bits 18 (`0x1203`) and 19 (`0x1303`). claims are fixture-backed only for window bits 18 (`0x1203`) and 19 (`0x1303`).
MSZIP validates the `CK` prefix, limits each compressed block to 32 KiB + 12, MSZIP validates the `CK` prefix, limits each compressed block to 32 KiB + 12,
decodes into a fixed-size output buffer, requires the declared output length, decodes into a fixed-size output buffer, requires the declared output length,
and carries at most 32 KiB of history between blocks in one folder. The MSZIP and carries at most 32 KiB of history between blocks in one logical folder.
tests establish CAB extraction behavior; no redistributable MSZIP-compressed
OneNote export is currently present, so they do not establish producer-specific
`.onepkg` compatibility.
Quantum validates level/window metadata, bounds its window to 2 MiB by default, Quantum validates level/window metadata, bounds its window to 2 MiB by default,
requires full 32 KiB intermediate frames, preserves its arithmetic models and requires full 32 KiB intermediate frames, preserves its arithmetic models and
LZ window across frames, and injects exactly one `0xFF` CAB block sentinel. LZ window across frames/cabinets, and injects exactly one `0xFF` CAB block
Trailer padding is limited to the documented 0..4 zero bytes; match, frame, sentinel. Trailer, match, frame, output, operation, and cancellation bounds are
output, operation, and cancellation bounds are enforced. Its tests likewise enforced.
establish CAB extraction behavior only: no redistributable Quantum-compressed
OneNote export is currently present.
Trailing CAB data is ignored with a warning. Reserved CAB areas are bounded and Trailing CAB data is ignored with a warning. Reserved CAB areas are bounded and
skipped. CAB names are decoded as strict UTF-8; unmarked valid UTF-8 receives a skipped. CAB names are decoded as strict UTF-8; unmarked valid UTF-8 receives a
warning, while invalid non-ASCII legacy-code-page names are rejected rather warning, while invalid non-ASCII legacy-code-page names are rejected rather
than guessed. than guessed.
## Extracted OneNote data ## Notebook and page model
The supported section paths currently return: Supported `.onetoc2` stores provide authored section order, nested section
groups, display names, identities, and colors. Exact normalized paths take
precedence; same-directory file identity is a guarded fallback. Recycle-bin
entries are omitted, duplicate/cyclic references are diagnosed, and readable
sections not reachable from a TOC are appended deterministically. Page levels
are interpreted as a page/subpage tree.
- section display name; The supported section path returns:
- page ID, title, created/updated timestamp when available, and page level;
- visible Unicode/extended-ASCII rich text as plain text and a text preview;
- diagnostics tied to an offset, structure, or page where available.
It does not preserve visual position, rich-text formatting, list formatting, - section/page identities, names, timestamps, page levels, and diagnostics;
tables, images, ink, equations, embedded files, audio/video, active links, - outlines and recursively nested content blocks;
page versions/conflicts, or exports. Unsupported content objects remain visible - rich-text runs with bold, italic, underline, strikeout, super/subscript,
as diagnostics instead of being silently presented as parsed. font, size, foreground/highlight color, paragraph alignment/spacing, and
allow-listed `http`, `https`, and `mailto` links;
- tables, lazy PNG/JPEG images, embedded-file declarations, and decoded ink;
- bounded layout hints such as offsets, maximum dimensions, and alignment.
Within a supported `.onepkg`, each `.one` entry is parsed independently. This is not a pixel-perfect OneNote renderer. Equations, audio/video, page
Malformed or unsupported sections are marked failed/unsupported while other versions/conflicts, and producer-specific structures outside the golden corpus
sections remain available. Package navigation is temporary normalized-path are not represented. Encountered unsupported object kinds remain visible as
order until `.onetoc2` interpretation is implemented. diagnostics. Active notebook HTML/SVG is never injected.
## Export
All exports are created inside the existing local parser worker. They include a
versioned parser/support manifest, the readable page hierarchy, diagnostics,
and unsupported-content summaries. The static ZIP contains inert semantic HTML
plus JSON, text, Markdown, warnings, and bounded resources. Resource names are
normalized, potentially active attachment suffixes are neutralized, and only
validated image types may be embedded for automatic display.
Export is a representation of the parser-supported subset, not a round trip:
it neither emits `.one`/`.onepkg` nor promises full OneNote visual fidelity.
## Test fixtures ## Test fixtures
The exact hashes, source revisions, licences, expected page names, and CAB The exact hashes, source revisions, licences, expected content, and CAB
structures are recorded in structures are recorded in
[`tests/fixtures/README.md`](../tests/fixtures/README.md). Tests use no private [`tests/fixtures/README.md`](../tests/fixtures/README.md). Tests use no private
notebooks and do not treat a synthetic archive as proof of Microsoft OneNote notebooks and do not treat a synthetic archive as proof of Microsoft OneNote

View File

@@ -3,32 +3,42 @@
The desktop `.one` reader adapts selected structures from the pinned The desktop `.one` reader adapts selected structures from the pinned
`onenote.rs` implementation. It is not a line-for-line or complete port. `onenote.rs` implementation. It is not a line-for-line or complete port.
| TypeScript module | Upstream path(s) | Revision | Port scope and deviations | | TypeScript module | Upstream path(s) | Revision | Port scope and deviations |
| ---------------------------------------- | ------------------------------------------------------------------------------------------------ | ----------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | | ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `src/onenote/onestore/file-node.ts` | `onestore/desktop/file_structure/file_node_list_fragment.rs`, `file_node/*`, chunk references | `onenote.rs@5138a39a3f4e72b840932f9872fecde52fa9da60` | Selected; immutable byte input, strict range checks, fragment/child cycle detection, and depth/count limits | | `src/onenote/onestore/file-node.ts` | `onestore/desktop/file_structure/file_node_list_fragment.rs`, `file_node/*`, chunk references | `onenote.rs@5138a39a3f4e72b840932f9872fecde52fa9da60` | Selected; immutable byte input, strict range checks, fragment/child cycle detection, and depth/count limits |
| `src/onenote/onestore/property-set.ts` | `onestore/shared/{object_prop_set,prop_set,property,object_stream_header}.rs` | same | Substantial; bounded vectors/counts/nesting and serializable discriminated unions | | `src/onenote/onestore/property-set.ts` | `onestore/shared/{object_prop_set,prop_set,property,object_stream_header}.rs` | same | Substantial; bounded vectors/counts/nesting and serializable discriminated unions |
| `src/onenote/onestore/desktop-store.ts` | `onestore/desktop/{file_node,file_structure,objects}/*` | same | Selected desktop section path; explicit missing-reference errors; file-data/attachment payloads skipped with diagnostics | | `src/onenote/onestore/desktop-store.ts` | `onestore/desktop/{file_node,file_structure,objects}/*` | same | Selected desktop section/TOC paths; explicit missing-reference errors; bounded file-data references |
| `src/onenote/fsshttpb/*` | `fsshttpb/{data,data_element,packaging}.rs` | same | Native bounded package/header/data-element records, checked compact integers, zero-copy BLOB ranges; fragment records parsed but not assembled | | `src/onenote/onestore/file-data.ts` | `onestore/desktop/{file_node/shared,objects/file_data_store}.rs` | same | Bounded zero-copy file-data payload ranges, checked declarations, and explicit external/invalid availability |
| `src/onenote/onestore/fsshttp-store.ts` | `onestore/fsshttpb/{header,mapping_table,object,object_space,revision,revision_role}.rs` | same | Unfragmented package-store adapter; bounded/cycle-checked revision chains, newest-revision precedence, resolved positional reference arrays | | `src/onenote/onestore/types.ts` | `onestore/desktop/common/*`, `onestore/shared/*`, and desktop object modules | same | Serializable structural records used across desktop and FSSHTTPB adapters |
| `src/onenote/one/{constants,section}.ts` | `one/property*`, `one/property_set/*`, `onenote/{section,page,page_series,outline,rich_text}.rs` | same | Page metadata, titles, and plain text only; bounded graph traversal; visual/embedded content diagnosed | | `src/onenote/fsshttpb/*` | `fsshttpb/{data,data_element,packaging}.rs` | same | Native bounded package/header/data-element records, checked compact integers, zero-copy BLOB ranges; fragment records parsed but not assembled |
| `src/onenote/onestore/fsshttp-store.ts` | `onestore/fsshttpb/{header,mapping_table,object,object_space,revision,revision_role}.rs` | same | Unfragmented package-store adapter; bounded/cycle-checked revision chains, newest-revision precedence, resolved positional reference arrays |
| `src/onenote/one/{constants,section,content}.ts` | `one/property*`, `one/property_set/*`, `onenote/{section,page,page_series,outline,rich_text,table,image,embedded_file,ink}.rs` | same | Page metadata plus bounded recursive rich text, tables, resources, layout hints, and decoded ink in an inert browser DTO |
| `src/onenote/one/property-access.ts` | `one/property/{simple,object_reference}.rs` | same | Typed property access and resolved/compact reference validation without coercion |
| `src/onenote/one/section-content.ts` | `onenote/{section,page_series,page}.rs` | same | Worker-retained page/content/resource model with bounded diagnostics and timestamps |
| `src/onenote/parser/parse-toc.ts` | `one/property_set/toc_container.rs` and desktop/FSSHTTP OneStore readers | same | Desktop/FSSHTTP TOC content, names, identities, ordering, colors, nesting, and bounded diagnostics |
The browser-native package path has separate MIT provenance: The browser-native package path has separate upstream provenance:
| TypeScript module | Upstream path(s) | Revision and selected licence | Port scope and deviations | | TypeScript module | Upstream path(s) | Revision and selected licence | Port scope and deviations |
| ------------------------------------------------------------------------ | ------------------------------------------------------ | --------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ------------------------------------------------------------------------ | ------------------------------------------------------ | --------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `src/onenote/onepkg/{cabinet,checksum}.ts` | rust-cab `src/{cabinet,folder,file,ctype,checksum}.rs` | `c5839f5fdfa4c4e7cc9b22f570c79c96af0560e2`, MIT | CAB reading/checksum adapted for immutable browser bytes, strict normalized paths, checked ranges/checksums, whole-folder extraction, explicit limits, and cancellation/yield hooks; writers are not ported | | `src/onenote/onepkg/{cabinet,checksum}.ts` | rust-cab `src/{cabinet,folder,file,ctype,checksum}.rs` | `c5839f5fdfa4c4e7cc9b22f570c79c96af0560e2`, MIT | CAB reading/checksum adapted for immutable browser bytes, strict normalized paths, checked ranges/checksums, whole-folder extraction, explicit limits, and cancellation/yield hooks; writers are not ported |
| `src/onenote/onepkg/cabinet-set.ts` | libmspack `mspack/cabd.c` | `55d501976171397ccd5d5a7a1ca7da065b1d9a06`, LGPL-2.1-only | Complete named-set validation, split CFDATA reassembly, codec continuity, spanning-file reconciliation, aggregate limits, and immutable browser inputs |
| `src/onenote/onepkg/mszip/decoder.ts` | rust-cab `src/mszip.rs`; fflate raw DEFLATE | rust-cab revision above; fflate 0.8.3, MIT | `CK` framing and persistent 32 KiB folder history follow rust-cab; raw DEFLATE uses fflate with a caller-owned bounded buffer and strict declared-size checks | | `src/onenote/onepkg/mszip/decoder.ts` | rust-cab `src/mszip.rs`; fflate raw DEFLATE | rust-cab revision above; fflate 0.8.3, MIT | `CK` framing and persistent 32 KiB folder history follow rust-cab; raw DEFLATE uses fflate with a caller-owned bounded buffer and strict declared-size checks |
| `src/onenote/onepkg/quantum/{bit-reader,budget,decoder,model,tables}.ts` | compcol `src/quantum/{bits,decoder,model,tables}.rs` | `04a6db2aa7bd487a89c559631d79d1b384139f50`, MIT | Native TypeScript arithmetic/model/LZ decoder; fixed CAB output, 2 MiB maximum window, strict match/frame/trailer checks, two-block lookahead, operation budget, and cancellation checkpoints | | `src/onenote/onepkg/quantum/{bit-reader,budget,decoder,model,tables}.ts` | compcol `src/quantum/{bits,decoder,model,tables}.rs` | `04a6db2aa7bd487a89c559631d79d1b384139f50`, MIT | Native TypeScript arithmetic/model/LZ decoder; fixed CAB output, 2 MiB maximum window, strict match/frame/trailer checks, two-block lookahead, operation budget, and cancellation checkpoints |
| `src/onenote/onepkg/lzx/{bit-reader,huffman,decoder}.ts` | lzxd 0.2.5 `src/{bitstream,tree,block,window,lib}.rs` | `4748e43594e3e30cff2ace3a6ad7a376c9816fdd`, MIT option of MIT OR Apache-2.0 | Directly translated core with typed arrays, CAB CFDATA boundaries, persistent folder state, strict malformed-stream errors, and operation/window/cancellation limits; delta reference data is omitted | | `src/onenote/onepkg/lzx/{bit-reader,huffman,decoder}.ts` | lzxd 0.2.5 `src/{bitstream,tree,block,window,lib}.rs` | `4748e43594e3e30cff2ace3a6ad7a376c9816fdd`, MIT option of MIT OR Apache-2.0 | Directly translated core with typed arrays, CAB CFDATA boundaries, persistent folder state, strict malformed-stream errors, and operation/window/cancellation limits; delta reference data is omitted |
The bounded binary readers, format detection, parser limits/error model, path The bounded binary readers, format detection, parser limits/error model, path
policy, worker protocol/DTOs, package-to-section boundary, and application UI policy, package TOC-to-section hierarchy, worker protocol/DTOs, safe image
are original TypeScript implementations guided by the normative specifications inspection, export serializers/ZIP writer, and React application UI are original
and project requirements. TypeScript implementations guided by the normative specifications and project
requirements. The pinned `one2html` renderer informed expected visual semantics
for rich text, tables, images, attachments, and ink; its Rust/templates/CSS were
not copied or shipped.
Files adapted from `onenote.rs` carry an MPL-2.0 notice, SPDX identifier, Files adapted from `onenote.rs` carry an MPL-2.0 notice, SPDX identifier,
upstream path/revision, and deviations. Files adapted from rust-cab, compcol, upstream path/revision, and deviations. Files adapted from rust-cab, compcol,
or lzxd carry their MIT provenance, copyright notice, exact revision, and deviations. or lzxd carry their MIT provenance, copyright notice, exact revision, and
deviations. The multi-cabinet module carries libmspack's LGPL-2.1-only notice.
Licence texts are reproduced in `LICENSES/` and included in the release ZIP. Licence texts are reproduced in `LICENSES/` and included in the release ZIP.
Focused tests cover successful pinned fixtures plus malformed bounds, Focused tests cover successful pinned fixtures plus malformed bounds,

View File

@@ -1,18 +1,20 @@
# Specifications and pinned references # Specifications and pinned references
Version 0.1.0 records these immutable implementation revisions: Version 0.2.0 records these immutable implementation revisions:
| Repository | Exact revision | Use | | Repository | Exact revision | Use |
| ---------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ | ---------------------------------------------------------------------------------- | | ---------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ | --------------------------------------------------------------------------------------------- |
| [`toolbox-sdk`](https://git.add-ideas.de/zemion/toolbox-sdk/src/commit/5e206baf42dfae5a00f2743fb2cc501bb12d9b7a) | `5e206baf42dfae5a00f2743fb2cc501bb12d9b7a` | App contract, React shell, manifest schema/testkit, and nested-path behavior | | [`toolbox-sdk`](https://git.add-ideas.de/zemion/toolbox-sdk/src/commit/5e206baf42dfae5a00f2743fb2cc501bb12d9b7a) | `5e206baf42dfae5a00f2743fb2cc501bb12d9b7a` | App contract, React shell, manifest schema/testkit, and nested-path behavior |
| [`toolbox-portal`](https://git.add-ideas.de/zemion/toolbox-portal/src/commit/5d2e466ad61e36a0e2be2a2d8459b1a127f53f11) | `5d2e466ad61e36a0e2be2a2d8459b1a127f53f11` | Reviewed ZIP shape, exact checksum lock, and independent-app assembly model | | [`toolbox-portal`](https://git.add-ideas.de/zemion/toolbox-portal/src/commit/d46f1b61fb85a18299b6b8af2148dcd991ef6b05) | `d46f1b61fb85a18299b6b8af2148dcd991ef6b05` | Reviewed ZIP shape, exact checksum lock, independent-app assembly, and nginx deployment model |
| [`onenote.rs`](https://github.com/msiemens/onenote.rs/tree/5138a39a3f4e72b840932f9872fecde52fa9da60) | `5138a39a3f4e72b840932f9872fecde52fa9da60` | Selected desktop/FSSHTTPB OneStore and MS-ONE structures adapted into TypeScript | | [`onenote.rs`](https://github.com/msiemens/onenote.rs/tree/5138a39a3f4e72b840932f9872fecde52fa9da60) | `5138a39a3f4e72b840932f9872fecde52fa9da60` | Selected desktop/FSSHTTPB OneStore and MS-ONE structures adapted into TypeScript |
| [`rust-cab`](https://github.com/mdsteele/rust-cab/tree/c5839f5fdfa4c4e7cc9b22f570c79c96af0560e2) | `c5839f5fdfa4c4e7cc9b22f570c79c96af0560e2` | CAB structures, checksum, enumeration/extraction, MSZIP history, and unit fixtures | | [`rust-cab`](https://github.com/mdsteele/rust-cab/tree/c5839f5fdfa4c4e7cc9b22f570c79c96af0560e2) | `c5839f5fdfa4c4e7cc9b22f570c79c96af0560e2` | CAB structures, checksum, enumeration/extraction, MSZIP history, and unit fixtures |
| [`compcol`](https://github.com/KarpelesLab/compcol/tree/04a6db2aa7bd487a89c559631d79d1b384139f50) | `04a6db2aa7bd487a89c559631d79d1b384139f50` | Quantum bit reader, arithmetic models, LZ window, CAB sentinel behavior, and tests | | [`compcol`](https://github.com/KarpelesLab/compcol/tree/04a6db2aa7bd487a89c559631d79d1b384139f50) | `04a6db2aa7bd487a89c559631d79d1b384139f50` | Quantum bit reader, arithmetic models, LZ window, CAB sentinel behavior, and tests |
| [`lzxd` 0.2.5](https://github.com/Lonami/lzxd/tree/4748e43594e3e30cff2ace3a6ad7a376c9816fdd) | `4748e43594e3e30cff2ace3a6ad7a376c9816fdd` | LZX bitstream, Huffman, block/window, match, and E8 logic adapted into TypeScript | | [`lzxd` 0.2.5](https://github.com/Lonami/lzxd/tree/4748e43594e3e30cff2ace3a6ad7a376c9816fdd) | `4748e43594e3e30cff2ace3a6ad7a376c9816fdd` | LZX bitstream, Huffman, block/window, match, and E8 logic adapted into TypeScript |
| [`libmspack`](https://github.com/kyz/libmspack/tree/55d501976171397ccd5d5a7a1ca7da065b1d9a06) | `55d501976171397ccd5d5a7a1ca7da065b1d9a06` | Multi-cabinet chain, split CFDATA, spanning-file semantics, and licensed fixtures |
| [`one2html`](https://github.com/msiemens/one2html/tree/59930ad309004030f812790c6749efe4265bb6bd) | `59930ad309004030f812790c6749efe4265bb6bd` | Behavioral reference for rich text, tables, images, attachments, ink, and HTML rendering |
The SDK and Portal revisions were inspected from the local repositories. The The SDK and Portal revisions were inspected from the local repositories. Every
four parser references were cloned and reviewed at the hashes above; a branch parser/renderer reference was cloned and reviewed at the hash above; a branch
name or package version alone is not used as provenance. Source-level mappings name or package version alone is not used as provenance. Source-level mappings
and behavioural deviations are in [PORTING.md](PORTING.md). and behavioural deviations are in [PORTING.md](PORTING.md).
@@ -50,5 +52,6 @@ The Microsoft documents are linked rather than copied. Their published pages
can change independently; the source references and golden bytes remain pinned can change independently; the source references and golden bytes remain pinned
for reproducibility. for reproducibility.
`one2html` is deliberately not pinned or inspected because visual HTML The `one2html` renderer is a behavioral reference only: no Rust, Askama
rendering is outside this release. template, stylesheet, or generated HTML is shipped or executed by this
application.

View File

@@ -2,119 +2,172 @@
## Trust boundary and local processing ## Trust boundary and local processing
Selected `.one` and `.onepkg` files are untrusted. The main thread checks the Selected `.one`, `.onepkg`, and companion `.cab` files are untrusted. The main
source size, reads one file into an `ArrayBuffer`, transfers it to a dedicated thread validates the selection and combined size, reads the files into
module worker, and receives serializable data-transfer objects. CAB entries are `ArrayBuffer`s, and transfers them to a dedicated module worker. CAB entries
extracted only into memory; archive paths are never written to the filesystem. 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 The worker is a fault-containment and responsiveness boundary, not a security
sandbox. A successful open keeps its worker session alive for page requests. sandbox. A successful open keeps its session alive for page/resource/export
Clearing the file, choosing another file, or unmounting the app terminates that requests. Clearing the file, choosing another file, or unmounting the app
worker; a failed open also terminates it. JavaScript garbage collection does terminates that worker; a failed open also terminates it. JavaScript garbage
not promise immediate release or secure erasure. collection does not promise immediate release or secure erasure.
The application does not: The application does not:
- upload or transmit notebook bytes; - upload or transmit notebook bytes;
- use a backend, proxy, telemetry, analytics, remote fonts, or external content - use a notebook-processing application backend, upload proxy, telemetry,
fetching; analytics, remote fonts, or notebook-referenced external content fetching;
the optional same-origin Toolbox catalogue/manifest is application chrome
and receives no notebook data;
- persist source or derived content in LocalStorage, IndexedDB, Cache Storage, - persist source or derived content in LocalStorage, IndexedDB, Cache Storage,
cookies, or a service worker; cookies, or a service worker;
- execute notebook content or inject notebook HTML/SVG; - execute notebook content or inject notebook HTML/SVG;
- use WebAssembly, a Rust runtime, or a native helper. - use WebAssembly, a Rust runtime, or a native helper.
## Active default limits ## Active parser defaults
The main thread rejects a source larger than 512 MiB before reading it. The The main thread accepts one `.one`, or one `.onepkg` plus its `.cab`
OneStore section parsers then apply these independent defaults: companions. It permits at most 256 selected parts, 512 MiB per file, and 512 MiB
combined before reading.
| Resource | Default limit | The OneStore parser applies these independent defaults per section/store:
| ------------------------------------- | -------------------: |
| 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 |
| FSSHTTPB revision-chain entries | 16,384 |
| 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 |
| ------------------------------------------------ | -------------------------: |
| Section bytes | 512 MiB |
| Transaction fragments / entries | 16,384 / 1,000,000 |
| 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 |
| FSSHTTPB revision-chain entries | 16,384 |
| One property vector | 64 MiB |
| Desktop object-reference vector | 1,000,000 per vector |
| FSSHTTPB ExGUID/CellID references | 1,000,000 aggregate |
| Nested PropertySets per ObjectPropSet | 1,000,000 aggregate |
| File-data objects / one payload / total payloads | 10,000 / 256 MiB / 512 MiB |
| Content-graph depth | 256 |
| Content blocks / text runs / table cells | 100,000 each |
| Decoded ink points | 100,000 |
| Pages | 10,000 |
| Diagnostics | 10,000 |
| Retained rich/extracted text | 2,000,000 UTF-16 units |
| Resource | Default limit | Images are automatically previewable only when a bounded PNG IHDR or JPEG
| ------------------------------- | -------------: | marker/SOF inspection succeeds. The compressed payload must be at most 32 MiB,
| Cabinet input | 512 MiB | each dimension at most 16,384 pixels, and the image at most 67,108,864 pixels.
| Folders / files | 1,024 / 10,000 | JPEG inspection reads at most 1 MiB of markers and 4,096 marker records. Images
| CFDATA blocks | 131,072 | outside those limits stay inert and are available only through an explicit
| CAB name bytes | 255 | download action.
| Path characters / path segments | 4,096 / 64 |
| One extracted file | 256 MiB | The CAB/package path applies these defaults across a complete cabinet set:
| One folder output | 512 MiB |
| Total folder output | 512 MiB | | Resource | Default limit |
| Total extracted entry bytes | 512 MiB | | ------------------------------------------- | -----------------: |
| Folder compression ratio | 200:1 | | One cabinet / complete set input | 512 MiB / 512 MiB |
| One MSZIP compressed block | 32 KiB + 12 B | | Cabinet parts | 256 |
| Quantum window | 2 MiB | | Folder segments / files | 1,024 / 10,000 |
| LZX window | 8 MiB | | CFDATA fragments | 131,072 |
| LZX/Quantum decode operations | 1,000,000,000 | | CAB name bytes | 255 |
| Path characters / path segments | 4,096 / 64 |
| TOC construction operations / diagnostics | 1,000,000 / 10,000 |
| One extracted file | 256 MiB |
| One logical folder output | 512 MiB |
| Total folder output / extracted entry bytes | 512 MiB / 512 MiB |
| Logical-folder compression ratio | 200:1 |
| One MSZIP compressed block | 32 KiB + 12 B |
| Quantum window | 2 MiB |
| LZX window | 8 MiB |
| LZX/Quantum decode operations | 1,000,000,000 |
A CFDATA block may declare at most 32 KiB of output. Counts and offsets use 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 checked arithmetic and bounded readers. The CAB parser verifies supplied block
checksums, rejects overlapping/out-of-range data, rejects absolute/traversal, checksums; rejects overlapping/out-of-range data, traversal/absolute/control or
empty, control-character, and case-insensitive duplicate paths, and refuses case-insensitive duplicate paths; and validates a complete cabinet set before
multi-cabinet/spanning entries. decoding. Set IDs, indexes, links, compression, split blocks, and spanning-file
records must agree. Reserve areas are private to each cabinet/folder and are
validated locally rather than compared across parts.
MSZIP checks its `CK` framing and raw DEFLATE data, writes into a fixed caller MSZIP checks `CK` framing and raw DEFLATE data, writes into a fixed caller
buffer with one overflow-detection byte, requires the exact declared output buffer with overflow detection, requires the declared output size, and keeps at
size, and retains no more than 32 KiB of history. LZX checks its window, Huffman most 32 KiB of logical-folder history. LZX and Quantum validate their windows,
trees, block sizes, match ranges, output size, and operation budget. CAB trees/models, blocks/frames, matches, output, trailer, and operation budgets.
Quantum limits its window, model scans, arithmetic renormalisation, matches, Codec state is preserved across continued cabinet segments. Extraction checks
frame/output boundaries, operation count, and trailer padding. It queues at cancellation between data blocks and periodically yields to the worker loop.
most the current and next compressed block so a synthetic `0xFF` sentinel can
be consumed without buffering a complete folder. CAB extraction checks Desktop OneStore traversal checks fragment/reference cycles, nesting,
cancellation during Quantum work and yields between data blocks so the worker object/property/reference counts, and byte ranges. FSSHTTPB parsing bounds every
can process termination. Desktop OneStore traversal checks fragment/reference declared stream body and compact integer, rejects invalid end markers and
cycles, nesting, object/property/reference counts, and byte ranges. FSSHTTPB non-zero package tails, checks aggregate reference/mapping counts and revision
parsing bounds every declared stream body and compact integer, rejects invalid cycles, and retains BLOB payloads as bounded source ranges. Fragment records
end markers and non-zero package tails, checks mapping/reference counts and are range-checked, but packages containing them are rejected because
revision cycles, and retains BLOB payloads as bounded source ranges. Fragment
records are range-checked, but packages containing them are rejected because
fragmented-element reconstruction is not implemented. fragmented-element reconstruction is not implemented.
## Rendering and links ## Display and export budgets
DTO strings are rendered as React text nodes. Notebook HTML, active SVG, Parser DTOs are projected through a smaller page-display budget before React
scripts, attachment payloads, and automatic external navigation are not creates nodes: 5,000 blocks, depth 64, 10,000 text runs, 500,000 displayed text
rendered. Link activation is not implemented. If links are added, they require units, 2,000 table rows, 5,000 table cells, 256 columns, 10,000 ink strokes,
explicit user action, scheme validation, and safe navigation attributes. 50,000 ink points, and 4,096 characters per metadata label. Exceeding a display
budget produces an explicit truncation notice. Newlines remain inside text
nodes instead of multiplying DOM elements.
## Known gaps and roadmap Navigation and inspectors separately expose at most 250 page links, 500
notebook nodes at depth 16, 200 package entries per page, and 100 diagnostics
per page. Titles, previews, package paths, diagnostic fields, and panel labels
are length-bounded; pagination/truncation remains explicit in the UI.
- There is no wall-clock deadline. Synchronous OneStore `.one` parsing cannot Export planning independently permits at most 10,000 sections, 100,000 pages,
observe cooperative cancellation until control returns; terminating the 1,000,000 blocks, depth 256, 100,000 diagnostics, 8,000,000 text units, and
worker is the current hard stop. 500,000 ink points. One resource and all resources are capped at 64 MiB; one
- The package flow holds the source, decompressed folder buffers, extracted standalone output or all uncompressed static-ZIP members are capped at 128 MiB.
entry slices, and parsed DTOs in memory at overlapping times. The byte/count Planning accounts for metadata and projected UTF-8 output before serialization,
limits bound these individually but do not guarantee a low peak heap. then verifies actual encoded/member sizes. Resource views remain zero-copy until
- Section text/page/diagnostic limits apply per contained section rather than the bounded serializer needs bytes.
once to the complete package.
## Rendering, links, and downloads
DTO strings are rendered as React text nodes. Notebook HTML, scripts, active
SVG, and attachment payloads are never injected. Only parsed ink coordinates
generate application-owned SVG path attributes. Hyperlinks require an explicit
click, are limited to `http`, `https`, or `mailto`, and use
`rel="noopener noreferrer"`.
Automatic image requests carry a distinct preview intent. The worker rejects a
non-image, unapproved media type, unsafe dimensions, or oversized payload before
allocating/copying its bytes to the main thread. Approved image bytes may cross
for automatic preview; attachment bytes and rejected image bytes cross only
after the user presses a download button.
Static export HTML is inert, contains no script or external fetch, escapes all
text/attributes, embeds only images that pass the same inspector, and
neutralizes potentially active attachment suffixes. Exports represent the
supported reader model; they do not write OneNote files.
## Known gaps
- There is no wall-clock deadline. Synchronous OneStore graph parsing cannot
observe cancellation until control returns; terminating the worker is the
current hard stop.
- Package opening can hold source cabinets, decompressed logical folders,
extracted entry views, and parsed DTOs at overlapping times. Byte/count limits
bound them, but do not guarantee a low peak heap.
- Section content limits apply per contained section rather than once to the
complete `.onepkg`; cabinet/TOC limits are aggregate for the package set.
- CAB checksums detect accidental corruption but do not authenticate a package. - CAB checksums detect accidental corruption but do not authenticate a package.
- Format coverage is narrow and has only the documented golden files. New - Format coverage is limited to the documented golden files and structures.
producer/version claims require licensed regression fixtures and malformed New producer/version claims require licensed regression fixtures and malformed
variants. variants.
- The worker boundary reduces UI impact but is not a substitute for browser and - The worker boundary reduces UI impact but is not a substitute for browser and
operating-system isolation. Open especially sensitive files in a dedicated operating-system isolation. Open especially sensitive files in a dedicated
browser profile if that risk matters. browser profile if that risk matters.
Planned hardening includes an elapsed-time budget, cancellation checkpoints in Planned hardening includes elapsed-time budgets, more cancellation checkpoints,
desktop OneStore graph traversal, aggregate package DTO/text budgets, lower lower-peak-memory extraction, expanded malformed-input/fuzz corpora, fragmented
peak-memory extraction, expanded malformed-input/fuzz corpora, and additional FSSHTTP reconstruction, and additional licensed OneNote producer fixtures.
licensed OneNote export fixtures.
## Fixtures and vulnerability reporting ## Fixtures and vulnerability reporting

6
package-lock.json generated
View File

@@ -1,13 +1,13 @@
{ {
"name": "onenote-tools", "name": "onenote-tools",
"version": "0.1.0", "version": "0.2.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "onenote-tools", "name": "onenote-tools",
"version": "0.1.0", "version": "0.2.0",
"license": "MPL-2.0", "license": "MPL-2.0 AND LGPL-2.1-only",
"dependencies": { "dependencies": {
"@add-ideas/toolbox-contract": "0.1.1", "@add-ideas/toolbox-contract": "0.1.1",
"@add-ideas/toolbox-shell-react": "0.1.1", "@add-ideas/toolbox-shell-react": "0.1.1",

View File

@@ -1,8 +1,8 @@
{ {
"name": "onenote-tools", "name": "onenote-tools",
"version": "0.1.0", "version": "0.2.0",
"description": "A local-first browser workspace for native OneNote parsing.", "description": "A local-first browser reader and exporter for OneNote files.",
"license": "MPL-2.0", "license": "MPL-2.0 AND LGPL-2.1-only",
"private": true, "private": true,
"type": "module", "type": "module",
"engines": { "engines": {

View File

@@ -3,11 +3,22 @@
"schemaVersion": 1, "schemaVersion": 1,
"id": "de.add-ideas.onenote-tools", "id": "de.add-ideas.onenote-tools",
"name": "OneNote Tools", "name": "OneNote Tools",
"description": "Local-first reader for tested desktop revision-store .one sections and LZX .onepkg packages; other OneNote formats are not implemented.", "description": "Local-first reader and exporter for tested .one and .onepkg variants, with notebook trees, rich content, and split CAB package support.",
"entry": "./", "entry": "./",
"icon": "./favicon.svg", "icon": "./favicon.svg",
"categories": ["documents", "onenote"], "categories": ["documents", "onenote"],
"tags": ["local", "read-only", "one", "onepkg", "cab", "lzx"], "tags": [
"local",
"read-only",
"one",
"onepkg",
"cab",
"lzx",
"mszip",
"quantum",
"fsshttp",
"export"
],
"integration": { "integration": {
"contextVersion": 1, "contextVersion": 1,
"launchModes": ["navigate", "new-tab"], "launchModes": ["navigate", "new-tab"],
@@ -27,7 +38,7 @@
}, },
"source": { "source": {
"repository": "https://git.add-ideas.de/zemion/onenote-tools", "repository": "https://git.add-ideas.de/zemion/onenote-tools",
"license": "MPL-2.0" "license": "MPL-2.0 AND LGPL-2.1-only"
}, },
"version": "0.1.0" "version": "0.2.0"
} }

View File

@@ -13,20 +13,27 @@ export function HelpDialog({ onClose }: HelpDialogProps) {
> >
<h2 id="help-title">About OneNote Tools</h2> <h2 id="help-title">About OneNote Tools</h2>
<p> <p>
Read the tested desktop revision-store .one subset and single-cabinet Open tested desktop and unfragmented FSSHTTPB OneNote sections or
LZX or uncompressed .onepkg packages with a native TypeScript parser. complete single- and multi-cabinet .onepkg sets with a native
Unsupported content remains visible as diagnostics instead of being TypeScript parser. For a split package, select its .onepkg and all
silently discarded. linked .cab files together.
</p> </p>
<p> <p>
FSSHTTP sections, MSZIP and Quantum packages, multi-cabinet archives, Notebook trees, rich text, safe links, tables, PNG/JPEG images, ink,
notebook TOC ordering, visual fidelity, attachments, and export are attachments, and local JSON, text, Markdown, HTML, or static ZIP
not supported in this release. exports are supported within documented safety and format limits.
Encountered unsupported object kinds remain visible as diagnostics.
</p> </p>
<p> <p>
Nothing is uploaded, persisted, or sent to telemetry. Closing or Fragmented FSSHTTPB data, equations, audio/video, exact OneNote page
clearing releases application references and terminates the worker; placement, and untested producer variants remain unsupported. Exports
this is not a secure-erasure guarantee. preserve readable content but do not create OneNote files.
</p>
<p>
Nothing is uploaded or sent to telemetry, and the app stores no
notebook data unless you explicitly download a resource or create an
export. Closing or clearing releases application references and
terminates the worker; this is not a secure-erasure guarantee.
</p> </p>
<button type="button" onClick={onClose}> <button type="button" onClick={onClose}>
Close Close

View File

@@ -529,6 +529,15 @@ p {
background: #f5eff8; background: #f5eff8;
} }
.render-limit-notice {
margin: 1rem 0 0;
border-left: 0.2rem solid #b18124;
padding: 0.7rem 0.85rem;
color: #66552f;
background: #fbf4e6;
font-size: 0.85rem;
}
.package-inspector, .package-inspector,
.diagnostics { .diagnostics {
padding: 1.25rem; padding: 1.25rem;

View File

@@ -1,11 +1,22 @@
{ {
"id": "de.add-ideas.onenote-tools", "id": "de.add-ideas.onenote-tools",
"name": "OneNote Tools", "name": "OneNote Tools",
"description": "Local-first reader for tested desktop revision-store .one sections and LZX .onepkg packages; other OneNote formats are not implemented.", "description": "Local-first reader and exporter for tested .one and .onepkg variants, with notebook trees, rich content, and split CAB package support.",
"entry": "./", "entry": "./",
"icon": "./favicon.svg", "icon": "./favicon.svg",
"categories": ["documents", "onenote"], "categories": ["documents", "onenote"],
"tags": ["local", "read-only", "one", "onepkg", "cab", "lzx"], "tags": [
"local",
"read-only",
"one",
"onepkg",
"cab",
"lzx",
"mszip",
"quantum",
"fsshttp",
"export"
],
"integration": { "integration": {
"contextVersion": 1, "contextVersion": 1,
"launchModes": ["navigate", "new-tab"], "launchModes": ["navigate", "new-tab"],
@@ -25,6 +36,6 @@
}, },
"source": { "source": {
"repository": "https://git.add-ideas.de/zemion/onenote-tools", "repository": "https://git.add-ideas.de/zemion/onenote-tools",
"license": "MPL-2.0" "license": "MPL-2.0 AND LGPL-2.1-only"
} }
} }

View File

@@ -10,7 +10,8 @@ describe('toolbox manifest', () => {
}); });
it('does not advertise unimplemented format support', () => { it('does not advertise unimplemented format support', () => {
expect(toolboxApp.description).toContain('not implemented'); expect(toolboxApp.description).toContain('tested');
expect(toolboxApp.description).not.toContain('all OneNote');
expect(toolboxApp.privacy).toEqual( expect(toolboxApp.privacy).toEqual(
expect.objectContaining({ expect.objectContaining({
processing: 'local', processing: 'local',

View File

@@ -1 +1 @@
export const APP_VERSION = '0.1.0'; export const APP_VERSION = '0.2.0';

View File

@@ -17,7 +17,8 @@ and does not change the underlying file's licence.
`7c43e85e2169b4bc3236db73a24c8f20d5c284b74563c07baf1406887d20eb5e`. `7c43e85e2169b4bc3236db73a24c8f20d5c284b74563c07baf1406887d20eb5e`.
- Golden expectation: desktop OneStore section with three pages — `Test`, - Golden expectation: desktop OneStore section with three pages — `Test`,
`Another page`, and `Page 3` — plus readable text/timestamps and diagnostics `Another page`, and `Page 3` — plus readable text/timestamps and diagnostics
for image, table, and ink content. plus structured rich text, a PNG resource, a table, and 1,316 decoded ink
points across 11 ink blocks.
## `joplin-test.onepkg.base64` ## `joplin-test.onepkg.base64`
@@ -33,7 +34,8 @@ and does not change the underlying file's licence.
and nested paths, five `.one` sections, and two `.onetoc2` entries. and nested paths, five `.one` sections, and two `.onetoc2` entries.
- Parser expectation: all five sections parse, producing seven pages in total: - Parser expectation: all five sections parse, producing seven pages in total:
`Page 1`, `Page 2`, `Test`, `Test page`, `Testing…`, `A test`, and `Page 1`, `Page 2`, `Test`, `Test page`, `Testing…`, `A test`, and
`Tuesday, January 13, 2026`. `Tuesday, January 13, 2026`; the contained TOCs provide interpreted notebook
ordering rather than normalized-path-only navigation.
Tests verify the package hash, all seven paths, the native `.one` magic for Tests verify the package hash, all seven paths, the native `.one` magic for
every section, section parse statuses, and representative title/text output. every section, section parse statuses, and representative title/text output.

View File

@@ -5,6 +5,11 @@ import { defineConfig } from 'vite';
export default defineConfig({ export default defineConfig({
base: './', base: './',
plugins: [react()], plugins: [react()],
build: {
// Baseline browsers support modulepreload natively. Avoid shipping Vite's
// injected runtime polyfill (and an otherwise unnecessary runtime notice).
modulePreload: { polyfill: false },
},
test: { test: {
environment: 'jsdom', environment: 'jsdom',
setupFiles: './src/test/setup.ts', setupFiles: './src/test/setup.ts',