Background
FEP-ef61 requires portable objects that reference external resources, such as media attachments, to include a digestMultibase property. The digest must be computed using SHA-256. The spec also says that the URI of an external resource should be a hashlink.
Hashlinks are defined by draft-sporny-hashlink-07, an expired Internet-Draft. The draft describes a broader format for cryptographic hyperlinks, including metadata-bearing hashlinks and legacy URL parameter encodings. FEP-ef61 only appears to need the simple hl:<resource-hash> form, where the resource hash is a multibase-encoded multihash.
There is an existing JavaScript implementation, digitalbazaar/hashlink, but it does not look like a good fit as a Fedify runtime dependency:
- the underlying hashlink specification is an expired draft, so we should avoid committing to more of the format than FEP-ef61 actually needs;
- the package predates Fedify's current runtime requirements and documents Node.js 8.3+/CommonJS-style usage;
- Fedify needs code that works consistently across Deno, Node.js, Bun, and browser-like WebCrypto environments;
- adding the package would require dependency updates for both Deno and Node.js/Bun, while the needed subset is small;
- Fedify already has multibase and multicodec helpers in
@fedify/vocab-runtime.
For this reason, Fedify should implement a small FEP-ef61-oriented helper layer instead of depending on digitalbazaar/hashlink.
Proposed work
Add helper functions in @fedify/vocab-runtime for the digest format needed by FEP-ef61 portable media.
The helpers should:
- compute a SHA-256 digest for a byte sequence;
- encode that digest as the
digestMultibase value expected by FEP-ef61;
- parse and validate
digestMultibase values;
- parse simple hashlink URIs of the form
hl:<resource-hash>;
- create simple hashlink URIs from a
digestMultibase value;
- verify that a byte sequence matches a given
digestMultibase value;
- verify that a byte sequence matches a simple
hl: URI;
- reject unsupported hash algorithms, malformed multibase values, malformed multihash values, and metadata-bearing hashlinks that are outside the initial scope.
The implementation should build on the existing multibase/multicodec support in @fedify/vocab-runtime instead of introducing a second encoding stack.
The intended API can be decided during implementation, but it could look roughly like:
computeDigestMultibase(bytes: Uint8Array): Promise<string>;
parseDigestMultibase(value: string): { algorithm: "sha2-256"; digest: Uint8Array };
parseHashlink(value: string | URL): { digestMultibase: string };
createHashlink(digestMultibase: string): string;
verifyDigestMultibase(bytes: Uint8Array, digestMultibase: string): Promise<boolean>;
verifyHashlink(bytes: Uint8Array, hashlink: string | URL): Promise<boolean>;
Scope
This issue is only about the digest and simple hashlink helper layer needed for FEP-ef61 portable media.
It does not include:
- full implementation of draft-sporny-hashlink-07;
- hashlink metadata parsing or serialization;
- legacy
?hl= URL parameter support;
- gateway media upload, serving, or deletion endpoints;
- access control for media;
- adding the
digestMultibase vocabulary property.
The digestMultibase vocabulary property is handled separately under #288.
Tests
Add regression tests for digest and hashlink helpers.
The tests should cover:
- computing a SHA-256
digestMultibase value from bytes;
- creating a simple
hl: URI from that digest;
- parsing a simple
hl: URI back to the same digest;
- verifying matching bytes against
digestMultibase;
- rejecting non-matching bytes;
- rejecting unsupported multihash algorithms;
- rejecting malformed multibase and multihash values;
- rejecting metadata-bearing hashlinks for now;
- confirming that the implementation works without network access.
This should be added as a sub-issue of #288.
Background
FEP-ef61 requires portable objects that reference external resources, such as media attachments, to include a
digestMultibaseproperty. The digest must be computed using SHA-256. The spec also says that the URI of an external resource should be a hashlink.Hashlinks are defined by draft-sporny-hashlink-07, an expired Internet-Draft. The draft describes a broader format for cryptographic hyperlinks, including metadata-bearing hashlinks and legacy URL parameter encodings. FEP-ef61 only appears to need the simple
hl:<resource-hash>form, where the resource hash is a multibase-encoded multihash.There is an existing JavaScript implementation, digitalbazaar/hashlink, but it does not look like a good fit as a Fedify runtime dependency:
@fedify/vocab-runtime.For this reason, Fedify should implement a small FEP-ef61-oriented helper layer instead of depending on
digitalbazaar/hashlink.Proposed work
Add helper functions in
@fedify/vocab-runtimefor the digest format needed by FEP-ef61 portable media.The helpers should:
digestMultibasevalue expected by FEP-ef61;digestMultibasevalues;hl:<resource-hash>;digestMultibasevalue;digestMultibasevalue;hl:URI;The implementation should build on the existing multibase/multicodec support in
@fedify/vocab-runtimeinstead of introducing a second encoding stack.The intended API can be decided during implementation, but it could look roughly like:
Scope
This issue is only about the digest and simple hashlink helper layer needed for FEP-ef61 portable media.
It does not include:
?hl=URL parameter support;digestMultibasevocabulary property.The
digestMultibasevocabulary property is handled separately under #288.Tests
Add regression tests for digest and hashlink helpers.
The tests should cover:
digestMultibasevalue from bytes;hl:URI from that digest;hl:URI back to the same digest;digestMultibase;This should be added as a sub-issue of #288.