Skip to content

Add SHA-256 digest and hashlink helpers for portable media#935

Open
dahlia wants to merge 9 commits into
fedify-dev:mainfrom
dahlia:feat/fep-ef61/digest-multibase
Open

Add SHA-256 digest and hashlink helpers for portable media#935
dahlia wants to merge 9 commits into
fedify-dev:mainfrom
dahlia:feat/fep-ef61/digest-multibase

Conversation

@dahlia

@dahlia dahlia commented Jul 11, 2026

Copy link
Copy Markdown
Member

FEP-ef61 allows portable objects and their media to be available through more than one gateway. A media URL alone cannot establish that two gateways returned the same resource, or that a resource has remained unchanged after an object was signed. The FEP therefore requires external resources to carry a SHA-256 digestMultibase value and recommends hashlinks for their identifiers.

Fedify already exposes digestMultibase in its vocabulary types, but applications had no matching runtime support for producing or checking those values. Each application would otherwise need to assemble multihashes by hand, choose a multibase representation, parse hl: URIs, and reproduce the same validation rules. Besides duplicating subtle binary encoding code, that would make portable media behave differently across Deno, Node.js, Bun, and browser-like WebCrypto environments.

This PR puts that boundary in @fedify/vocab-runtime. The helpers use Web Crypto API for SHA-256 and build on Fedify's existing multibase and multicodec code, so they do not add a second encoding stack or a runtime dependency on digitalbazaar/hashlink. The Hashlink Internet-Draft is expired and describes more than FEP-ef61 needs, so the API deliberately supports only metadata-free hl: URIs. Metadata-bearing hashlinks and legacy ?hl= parameters are rejected instead of becoming accidental compatibility commitments.

Parsing is intentionally strict. A digest must contain a canonical multibase encoding of a canonical SHA-256 multihash with a 32-byte payload. Unsupported algorithms, overlong varints, incorrect padding, malformed lengths, and noncanonical encodings are rejected. This keeps equivalent digests from acquiring multiple accepted spellings and ensures that values created, parsed, serialized, and verified by different Fedify components agree exactly. Verification returns false for valid digests that do not match the supplied bytes, while malformed inputs remain programmer-visible TypeErrors.

The implementation and its public exports live in packages/vocab-runtime/src/digest.ts and packages/vocab-runtime/src/mod.ts. The regression coverage in packages/vocab-runtime/src/digest.test.ts includes the Hashlink draft's Hello World! vector, valid non-base58 multibase input, canonical padding, malformed multihashes, unsupported algorithms, metadata rejection, and matching and non-matching byte sequences. The portable-object section of docs/manual/vocab.md now shows how the digest and hashlink helpers fit the existing vocabulary properties, and CHANGES.md records the new API.

Closes #831.

Implement SHA-256 digestMultibase and metadata-free hashlink helpers in
vocab-runtime so FEP-ef61 media can be created and verified across
supported runtimes.  Validate canonical multibase and multihash
encodings, and document the public API.

Closes fedify-dev#831

Assisted-by: Codex:gpt-5.6-sol
@dahlia dahlia added this to the Fedify 2.4 milestone Jul 11, 2026
@dahlia dahlia self-assigned this Jul 11, 2026
@dahlia dahlia requested review from 2chanhaeng and sij411 as code owners July 11, 2026 04:40
@dahlia dahlia added the component/vocab Activity Vocabulary related label Jul 11, 2026
@dahlia dahlia added the activitypub/compliance Specification compliance label Jul 11, 2026
@netlify

netlify Bot commented Jul 11, 2026

Copy link
Copy Markdown

Deploy Preview for fedify-json-schema canceled.

Name Link
🔨 Latest commit fec3950
🔍 Latest deploy log https://app.netlify.com/projects/fedify-json-schema/deploys/6a5285c5a203b8000858a9f3

@dahlia

dahlia commented Jul 11, 2026

Copy link
Copy Markdown
Member Author

@codex review

@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: dbe451a2-604b-4b34-8ade-176d5e977ee6

📥 Commits

Reviewing files that changed from the base of the PR and between f3640b6 and fec3950.

📒 Files selected for processing (2)
  • packages/vocab-runtime/src/digest.test.ts
  • packages/vocab-runtime/src/digest.ts

📝 Walkthrough

Walkthrough

Added SHA-256 digestMultibase and simple hl: hashlink helpers, including computation, parsing, creation, verification, public exports, tests, and FEP-ef61 documentation.

Changes

Digest and hashlink helpers

Layer / File(s) Summary
Digest computation and validation
packages/vocab-runtime/src/digest.ts, packages/vocab-runtime/src/digest.test.ts
Adds SHA-256 digest generation, canonical multibase/multihash validation, parsed types, and malformed-input coverage.
Hashlink creation and verification
packages/vocab-runtime/src/digest.ts, packages/vocab-runtime/src/digest.test.ts
Adds simple hl: parsing and creation, digest/hashlink verification, and matching, mismatching, and unsupported-form tests.
Public exports and portable-object guidance
packages/vocab-runtime/src/mod.ts, docs/manual/vocab.md, CHANGES.md
Re-exports the new APIs and documents their portable-object usage, serialization, verification, and validation behavior.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Application
  participant computeDigestMultibase
  participant WebCrypto
  participant createHashlink
  participant verifyHashlink
  Application->>computeDigestMultibase: resource bytes
  computeDigestMultibase->>WebCrypto: SHA-256 digest request
  WebCrypto-->>computeDigestMultibase: raw digest bytes
  computeDigestMultibase-->>Application: digestMultibase
  Application->>createHashlink: digestMultibase
  createHashlink-->>Application: hl: hashlink
  Application->>verifyHashlink: resource bytes and hashlink
  verifyHashlink-->>Application: verification result
Loading

Suggested labels: runtime/node

Suggested reviewers: sij411, 2chanhaeng

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main addition: SHA-256 digest and hashlink helpers for portable media.
Description check ✅ Passed The description matches the changeset and explains the new runtime helpers, tests, docs, and changelog updates.
Linked Issues check ✅ Passed The implementation and tests satisfy #831 by adding compute, parse, create, verify, and strict rejection behavior for digestMultibase and simple hashlinks.
Out of Scope Changes check ✅ Passed The changes stay within the issue scope and only add the runtime helpers, tests, documentation, and changelog entries described in the PR.
Docstring Coverage ✅ Passed Docstring coverage is 85.71% which is sufficient. The required threshold is 80.00%.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces SHA-256 digestMultibase and simple hl: hashlink helpers in @fedify/vocab-runtime to support computing, parsing, creating, and verifying portable media resource digests as required by FEP-ef61. The feedback suggests optimizing memory usage in computeDigestMultibase and verifyDigestMultibase by avoiding unconditional bytes.slice() on the input Uint8Array unless the underlying buffer is a SharedArrayBuffer.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread packages/vocab-runtime/src/digest.ts
Comment thread packages/vocab-runtime/src/digest.ts
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Chef's kiss.

Reviewed commit: aa87660766

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@codecov

codecov Bot commented Jul 11, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.12230% with 4 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
packages/vocab-runtime/src/digest.ts 96.94% 1 Missing and 3 partials ⚠️
Files with missing lines Coverage Δ
packages/vocab-runtime/src/mod.ts 100.00% <100.00%> (ø)
packages/vocab-runtime/src/digest.ts 96.94% <96.94%> (ø)

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Pass ArrayBuffer-backed views directly to WebCrypto so hashing large
media does not allocate a full-size copy.  Copy only SharedArrayBuffer-
backed input, which WebCrypto cannot consume, and cover that fallback in
both digest helper paths.

fedify-dev#935 (comment)
fedify-dev#935 (comment)

Assisted-by: Codex:gpt-5.6-sol
@dahlia

dahlia commented Jul 11, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@dahlia

dahlia commented Jul 11, 2026

Copy link
Copy Markdown
Member Author

@codex review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces SHA-256 digestMultibase and simple hl: hashlink helpers in @fedify/vocab-runtime to compute, parse, create, and verify portable media resource digests as required by FEP-ef61. The changes include implementation, tests, and documentation updates. Feedback is provided to improve the robustness of toWebCryptoBytes by addressing cross-realm compatibility and avoiding redundant instantiation when standard ArrayBuffers are used.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread packages/vocab-runtime/src/digest.ts
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Can't wait for the next one!

Reviewed commit: 1813bc85b7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

ArrayBuffer instanceof checks depend on the current JavaScript realm and
could make ordinary media input incur a full copy.  Detect only shared
storage by its intrinsic tag so regular Uint8Array views pass through
unchanged while SharedArrayBuffer input remains Web Crypto-compatible.

fedify-dev#935 (comment)

Assisted-by: Codex:gpt-5.6-sol
@dahlia

dahlia commented Jul 11, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@dahlia

dahlia commented Jul 11, 2026

Copy link
Copy Markdown
Member Author

@codex review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces SHA-256 digestMultibase and simple hl: hashlink helpers to @fedify/vocab-runtime for computing, parsing, creating, and verifying portable media resource digests as required by FEP-ef61. It also adds comprehensive unit tests and documentation updates. The review feedback suggests two optimizations: simplifying the constant-time comparison loop in verifyDigestMultibase since digest lengths are guaranteed to be equal, and refactoring verifyHashlink to avoid redundant parsing of the digest multibase.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread packages/vocab-runtime/src/digest.ts Outdated
Comment thread packages/vocab-runtime/src/digest.ts

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/vocab-runtime/src/digest.ts`:
- Around line 28-31: Replace the `Object.prototype.toString` check and
conditional `bytes.slice()` with an unconditional copy into a fresh `Uint8Array`
before `crypto.subtle.digest`; use the existing digest input handling in
`digest.ts` to ensure subclasses and shared-backed buffers cannot pass through
unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: ff0432dc-fc83-4710-95d1-56862fb1e111

📥 Commits

Reviewing files that changed from the base of the PR and between 1813bc8 and 6674c5f.

📒 Files selected for processing (1)
  • packages/vocab-runtime/src/digest.ts

Comment thread packages/vocab-runtime/src/digest.ts Outdated
dahlia added 2 commits July 11, 2026 14:14
String tags and typed-array slice methods can be overridden, so neither
reliably identifies or copies shared storage.  Use the native ArrayBuffer
byte-length getter as a realm-independent brand check and copy shared
input through the base Uint8Array constructor.

fedify-dev#935 (comment)

Assisted-by: Codex:gpt-5.6-sol
SHA-256 parsing and hashing guarantee equal 32-byte digests, so the
constant-time comparison does not need fallback indexing.  Separate
hashlink syntax extraction from digest validation so verification
performs the relatively expensive multibase parsing only once.

fedify-dev#935 (comment)
fedify-dev#935 (comment)

Assisted-by: Codex:gpt-5.6-sol
@dahlia

dahlia commented Jul 11, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@dahlia

dahlia commented Jul 11, 2026

Copy link
Copy Markdown
Member Author

@codex review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces SHA-256 digestMultibase and simple hl: hashlink helpers to compute, parse, create, and verify portable media resource digests as required by FEP-ef61. Feedback focuses on improving the robustness and simplicity of the SharedArrayBuffer handling in packages/vocab-runtime/src/digest.ts. Specifically, it is recommended to remove the module-level descriptor lookup to prevent potential runtime crashes, and to simplify toWebCryptoBytes using instanceof SharedArrayBuffer while safely copying the buffer with .slice() for Web Crypto API compatibility.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread packages/vocab-runtime/src/digest.ts Outdated
Comment thread packages/vocab-runtime/src/digest.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f3640b6041

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/vocab-runtime/src/digest.ts Outdated
dahlia added 2 commits July 11, 2026 14:24
Some JavaScript hosts may not expose the standard ArrayBuffer byte-length
getter as expected.  Treat a missing getter as an unknown buffer brand
and take the safe copy path instead of failing while loading the module.

fedify-dev#935 (comment)

Assisted-by: Codex:gpt-5.6-sol
JavaScript's end anchor can match before a final line terminator, which
allowed non-URI hashlink strings to reach digest validation without the
suffix.  Exclude every ECMAScript line terminator and require the match
to consume the entire input.

fedify-dev#935 (comment)

Assisted-by: Codex:gpt-5.6-sol
@dahlia

dahlia commented Jul 11, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@dahlia

dahlia commented Jul 11, 2026

Copy link
Copy Markdown
Member Author

@codex review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces SHA-256 digestMultibase and simple hl: hashlink helpers in @fedify/vocab-runtime to support portable media resource digests as required by FEP-ef61. It includes implementation, comprehensive unit tests, and updated documentation. Feedback on the implementation suggests adding a safety check for encodingFromBaseData returning null/undefined to prevent generic errors, removing a redundant regex match length check, and using a more robust cross-realm check for URL objects instead of instanceof.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread packages/vocab-runtime/src/digest.ts
Comment thread packages/vocab-runtime/src/digest.ts
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🎉

Reviewed commit: ba422f5354

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

URL instanceof checks depend on the current JavaScript realm.  Distinguish
the string union member directly so URL objects from another realm still
provide their href while strict whole-input hashlink validation remains.

fedify-dev#935 (comment)

Assisted-by: Codex:gpt-5.6-sol
@dahlia

dahlia commented Jul 11, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@dahlia

dahlia commented Jul 11, 2026

Copy link
Copy Markdown
Member Author

@codex review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces SHA-256 digestMultibase and simple hl: hashlink helpers to compute, parse, create, and verify portable media resource digests as required by FEP-ef61. It includes the implementation in packages/vocab-runtime/src/digest.ts, exports in mod.ts, comprehensive unit tests in digest.test.ts, updated documentation in docs/manual/vocab.md, and changelog updates in CHANGES.md. There are no review comments, and I have no additional feedback to provide.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🎉

Reviewed commit: 4815b9d6b7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/vocab-runtime/src/digest.ts
Comment thread packages/vocab-runtime/src/digest.ts
Comment thread packages/vocab-runtime/src/digest.ts
A supported SHA-256 multihash is exactly 34 bytes, and base2 produces its
longest supported representation at 273 characters including the prefix.
Reject longer input before decoding so malformed values cannot consume
resources disproportionate to any valid digest.

fedify-dev#935 (comment)

Assisted-by: Codex:gpt-5.6-sol
@dahlia

dahlia commented Jul 11, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@dahlia

dahlia commented Jul 11, 2026

Copy link
Copy Markdown
Member Author

@codex review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces SHA-256 digestMultibase and simple hl: hashlink helpers in @fedify/vocab-runtime to support FEP-ef61, along with corresponding documentation and unit tests. The review feedback points out a redundant length check in extractDigestMultibase since the regular expression is already anchored with ^ and $, which can be simplified.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread packages/vocab-runtime/src/digest.ts
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 👍

Reviewed commit: fec3950e5e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@dahlia dahlia requested a review from 2chanhaeng July 11, 2026 18:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

activitypub/compliance Specification compliance component/vocab Activity Vocabulary related

Development

Successfully merging this pull request may close these issues.

SHA-256 digestMultibase helpers for portable media

2 participants