Skip to content

Disclose complete typed-data signing requests - #114

Merged
HDauven merged 6 commits into
mainfrom
fix/wallet-approval-disclosure
Sep 15, 2026
Merged

HDauven merged 6 commits into
mainfrom
fix/wallet-approval-disclosure

Conversation

@HDauven

@HDauven HDauven commented Sep 13, 2026

Copy link
Copy Markdown
Member

Summary

Refs #113 and dusk-network/typed-data#4. Keep the bounded approval preview and add Full signing request (escaped JSON): native details plus a read-only, keyboard-scrollable textarea exposing full schema, strings, bytes, arrays, empty values and the trusted origin.

  • Both views use one JSON snapshot checked by the shared hasher against the pending digest. Serialization, mismatch or disclosure-budget failure disables Sign while keeping Reject available.
  • Neutralize Bidi_Control; visibly escape formatting controls/line separators and flag non-NFC text. Preserve original Unicode and literal escape spellings; never normalize or feed display substitutions into signing. The background still signs its captured original digest after lifecycle/context checks.
  • Disclose the implicit 32-zero-byte contract default and distinguish unused metadata from hashed inputs.

The full view has an approximate early construction-work budget and a strict 2 MiB final escaped-text limit (2,097,152 ASCII characters). Serialization and escaping may temporarily construct larger text before rejection; neither check is a peak-memory guarantee. These are local signer display limits, not new hash/verifier validity rules. Both checks remain in place. Pagination is deferred.

Current-main integration / attribution

#112 is merged; this PR now targets main. GitHub already retargeted the base. Commit 3b9c056ae500be9d906041bff0684d73dd826fa4 merges current main 254fbce8732166fff8c4ad74f54953ae80fc7baa into the reviewed disclosure history without rewriting it.

Current head: b0c26bca04975e87bcc4ae7920e431c08315f858. The two original disclosure commits (8800b497d4ac, 3b23298edf8c) and their attribution are preserved. The reviewed disclosure production files and their tests are unchanged. The follow-up only refreshes README's full-view description and wires the existing approval-renderer suite into CI. The original core unit-test/build job is byte-identical to main; a small ubuntu-24.04 renderer job in the same workflow uses Playwright's standard --with-deps setup. Both jobs retain the fork/draft safeguards, read-only permissions and existing pinned actions. No shared runner image/settings were changed.

The branch now inherits the published JSR 0.1.0-rc.0 via npm:@jsr/dusk__typed-data@0.1.0-rc.0, with current main's genuine registry lock/URL/integrity, fixture-access adaptation and recent discovery/RPC regressions. Fresh standalone installs work. Native npm publication is not a prerequisite. There is no additional npm dependency, RPC, key, signing or lifecycle change relative to current main.

Based on ichbindas's #113 review, acknowledged in the original commit; his earlier integration authorship/history remain preserved. #113's limitations predated #112 and were not integration regressions. Identical bounded previews are not digest collisions, and the hypothetical line-joined example was not demonstrated injection in the boxed Wallet DOM.

Fresh validation of the combined result

  • Registry-backed npm ci and full coverage: 679 tests /59 files. Chrome, Firefox and Tauri frontend builds pass.
  • Existing approval-renderer suite with the real renderer and only pending-request transport stubbed: 11/11, including keyboard expansion/scrolling, full-value/schema/origin equality, Unicode/markup handling and disabled-Sign/reject controls. The same command now runs in CI.
  • Fresh disposable production Chrome flow: 34/34, 14 actual signatures, no uncaught page errors. Real provider, permissions, approval UI, keys and signing; no signing mocks or transactions. Checks include original/full-view equality, NFC/NFD distinctions, accepted-but-undisclosable refusal, RC E_COMPLEXITY separately from E_POLICY_LIMIT, and profile/network/lock/disconnect cancellation.
  • All 14 signatures verify through a separately installed current-main Connect SDK tarball with the registry-loaded RC, the native JSR RC, and a fresh isolated locked/offline Rust build, with changed-context/message and bare-digest rejection controls. Native JSR types/runtime require no local library mapping or sloppy imports. The SDK tarball is a tested current-main build, not a claim of a new SDK publication.
  • Both installed library copies match all 76 official bridge tarball files. Frozen digest/tagged-message expectations and included BLS fixtures pass. The bridge's fixture/spec files are read as installed test data, not invented public exports.
  • Real-hasher direct-helper check accepts exactly 2,097,152 final characters and refuses boundary+1. This is a helper boundary check above the RPC JSON floor, not a claim that RPC policy accepts a 2 MiB request.
  • Four isolated source mutations independently detect missing digest binding (2 failures), normalization (1), missing escaping (1), and missing final-size enforcement (1); baseline/restored 41/41. Scoped author-side preflight found no remaining in-scope findings.

Executed current-head GitHub CI: 34990496437 passes on b0c26bca0497: 679 tests /59 files, 11 renderer tests, Chrome and Firefox builds. Both jobs and every step executed successfully. Both checked out 91bfd5278f30, GitHub's test merge of current main 254fbce8732166 and this head; its tree exactly equals the submitted candidate. The PR is non-draft and remains open/review-required, not merged.

Bootstrap history: 34987874463 passed 679 unit tests but could not launch Chromium without GLib; 34989895687 then exposed the core runner's lack of elevation permission. Only the renderer job moved to Ubuntu; the original core job is restored unchanged. No production/test/package files changed; the local renderer suite was rerun 11/11, and the other local evidence above applies to identical files. Failed and draft-skipped runs are not counted as passing.

The existing non-gating Codecov uploader reported that a token is required for protected-branch uploads; generated coverage/test success does not establish successful upload. Its authentication and fail_ci_if_error: false policy are unchanged.

The supplied re-review found no actionable disclosure regression; its standalone copied-function probes used stubbed hashing and are not counted as this integration evidence. Earlier 677-test/33-browser-case results are superseded by the fresh results above. Chrome signing coverage is not Firefox/Tauri signing or native-desktop E2E, and native BLS agreement is not independent encoder/security certification. Protocol v1 remains draft/unfrozen. Normal approving-review/conversation gates still apply; no merge or release is requested by this validation update.

Keep the bounded field preview alongside a lossless escaped JSON snapshot checked against the pending digest. Refuse approval when complete disclosure fails; expose formatting and normalization differences without changing signed input.

Based on ichbindas’s screen-versus-payload review in #113. Reuse the shared hasher, native JSON and native details/textarea controls; leave RPC, keys, signing and lifecycle unchanged.

Refs #113.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The construction budget must account for escaped representation size to prevent exceeding the stated 2 MiB bound.

Pull request overview

Adds a complete escaped-JSON typed-data signing disclosure with digest validation, Unicode safeguards, and fail-closed approval behavior.

Changes:

  • Adds full request disclosure and enhanced preview handling.
  • Enforces serialization, integrity, and disclosure-budget checks.
  • Adds UI, test, documentation, and changelog coverage.
File summaries
File Reviewed changes
tests/e2e/typed-data-preview.spec.js End-to-end disclosure, interaction, Unicode, and failure coverage
src/ui/notification/app.js Full disclosure UI and guarded approval controls
src/ui/notification.app.test.js Notification integration tests
src/shared/typedDataDisplay.test.js Serialization, budget, and Unicode tests
src/shared/typedDataDisplay.js Verified disclosure serialization and display safeguards
docs/provider-api.md Disclosure behavior and limits documentation
CHANGELOG.md Feature and fix release notes
Review details

Suppressed comments (1)

src/shared/typedDataDisplay.js:46

  • The construction budget is charged from the original string length here, but the serializer later expands every non-ASCII code unit to a six-character \\uXXXX escape (and JSON also expands some controls). A valid request containing several large non-ASCII strings can therefore build a final disclosure well over 2 MiB before the check on line 51 rejects it, defeating the stated construction bound and allowing unnecessary renderer allocation. Account for the escaped representation (or conservatively reserve its worst-case expansion) while serializing, retaining the final-size check as well.
    budget -= key.length + (typeof value === "string" ? value.length : 1) + 2 * parents.length;
  • Files reviewed: 7/7 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Distinguish the approximate early construction-work budget from the strict final escaped-text limit. Document that serialization can temporarily exceed the final limit and neither check guarantees peak memory. Retain both checks and all signing behavior unchanged.

Addresses the non-blocking resource-accounting review note on #114. Refs #113.
Base automatically changed from feat/wallet-shared-typed-data to main September 15, 2026 14:35
Inherit the published JSR RC, registry-backed lockfile and current integration/discovery fixes without rewriting the reviewed disclosure commits.
Run the existing isolated Playwright renderer suite in the existing CI job so disclosure approval, keyboard access and refusal checks execute on current-base revisions. Keep the draft/fork guards and existing dependency setup unchanged. Refresh the README to describe the implemented full escaped request view.

Refs #113.
@HDauven
HDauven marked this pull request as ready for review September 15, 2026 15:21
The first non-draft run passed all 679 unit tests but could not launch Chromium on the core runner because libglib-2.0.so.0 was absent. Use Playwright’s existing --with-deps installer rather than relying on preinstalled host libraries. The disclosure implementation and renderer assertions are unchanged.
The core runner lacks Chromium system libraries and cannot elevate to install them. Keep its original unit-test/build job byte-identical to main and run only the existing renderer suite on ubuntu-24.04, where Playwright can install its standard prerequisites. Retain the same fork/draft guard, read-only token, pinned actions and Node version; do not change the shared runner image or settings.
@HDauven
HDauven merged commit 1f05366 into main Sep 15, 2026
2 checks passed
@HDauven
HDauven deleted the fix/wallet-approval-disclosure branch September 15, 2026 17:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants