@fedify/vocab-runtime 2.4.0-dev.1655 → 2.4.0-pr.934.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/deno.json +1 -1
  2. package/dist/{docloader-C_dir7Xb.d.ts → docloader-DnUMWHaJ.d.cts} +0 -2
  3. package/dist/{docloader-D2DTRiyA.d.cts → docloader-xRGn1azD.d.ts} +0 -2
  4. package/dist/internal/jsonld-cache.cjs +1 -1
  5. package/dist/internal/jsonld-cache.d.cts +1 -1
  6. package/dist/internal/jsonld-cache.d.ts +1 -1
  7. package/dist/internal/jsonld-cache.js +1 -1
  8. package/dist/mod.cjs +8 -159
  9. package/dist/mod.d.cts +2 -91
  10. package/dist/mod.d.ts +2 -91
  11. package/dist/mod.js +9 -152
  12. package/dist/tests/decimal.test.cjs +5 -6
  13. package/dist/tests/decimal.test.mjs +5 -6
  14. package/dist/tests/{docloader-DVVWmXLI.cjs → docloader-BFedvemb.cjs} +6 -12
  15. package/dist/tests/{docloader-HbEvzi-t.mjs → docloader-Xi61Le8w.mjs} +6 -12
  16. package/dist/tests/docloader.test.cjs +3 -3
  17. package/dist/tests/docloader.test.mjs +3 -3
  18. package/dist/tests/jsonld-cache.test.cjs +1 -1
  19. package/dist/tests/jsonld-cache.test.mjs +1 -1
  20. package/dist/tests/{key-Drbw_2tw.mjs → key-CDGDH_vC.mjs} +1 -1
  21. package/dist/tests/{key-BcOWDLMm.cjs → key-_wXwomh_.cjs} +1 -1
  22. package/dist/tests/key.test.cjs +2 -2
  23. package/dist/tests/key.test.mjs +2 -2
  24. package/dist/tests/langstr.test.cjs +1 -1
  25. package/dist/tests/langstr.test.mjs +1 -1
  26. package/dist/tests/multibase/multibase.test.cjs +1 -1
  27. package/dist/tests/multibase/multibase.test.mjs +1 -1
  28. package/dist/tests/{multibase-Cluwl8OM.mjs → multibase-B4bvakyA.mjs} +1 -12
  29. package/dist/tests/{multibase-DcDQDNnI.cjs → multibase-Bz_UUDtL.cjs} +0 -17
  30. package/dist/tests/{request-B6s_F7bi.mjs → request-BOS-hNaf.mjs} +1 -1
  31. package/dist/tests/{request-DvEyU5Zf.cjs → request-cCPgOxYG.cjs} +1 -1
  32. package/dist/tests/request.test.cjs +1 -1
  33. package/dist/tests/request.test.mjs +1 -1
  34. package/dist/tests/{url-CsOV_B_P.cjs → url-BvjYQdxL.cjs} +0 -26
  35. package/dist/tests/{url-Du7RQQgP.mjs → url-a2D8NAgh.mjs} +1 -15
  36. package/dist/tests/url.test.cjs +1 -18
  37. package/dist/tests/url.test.mjs +1 -18
  38. package/dist/{url-DD4F0ULf.cjs → url-Ck3dGEwH.cjs} +0 -26
  39. package/dist/{url-DGVbSVVi.js → url-m1YxGNZ0.js} +1 -15
  40. package/package.json +1 -1
  41. package/src/contexts/security-data-integrity-v1.json +4 -0
  42. package/src/contexts.ts +0 -2
  43. package/src/docloader.ts +0 -2
  44. package/src/mod.ts +0 -12
  45. package/src/url.test.ts +0 -23
  46. package/src/url.ts +0 -23
  47. package/dist/tests/digest-BJlumPNJ.mjs +0 -140
  48. package/dist/tests/digest-DLwUyHCK.cjs +0 -175
  49. package/dist/tests/digest.test.cjs +0 -103
  50. package/dist/tests/digest.test.d.cts +0 -1
  51. package/dist/tests/digest.test.d.mts +0 -1
  52. package/dist/tests/digest.test.mjs +0 -103
  53. package/src/contexts/fep-ef61.json +0 -10
  54. package/src/digest.test.ts +0 -220
  55. package/src/digest.ts +0 -229
  56. /package/dist/tests/{langstr-BOQHfJDr.cjs → langstr-CbAxaeEZ.cjs} +0 -0
  57. /package/dist/tests/{langstr-DDLc4833.mjs → langstr-Di5AvKpB.mjs} +0 -0
@@ -1,103 +0,0 @@
1
- require("./chunk-C2EiDwsr.cjs");
2
- const require_multicodec = require("./multicodec-CxGVGa91.cjs");
3
- const require_multibase = require("./multibase-DcDQDNnI.cjs");
4
- const require_digest = require("./digest-DLwUyHCK.cjs");
5
- let node_test = require("node:test");
6
- let node_assert_strict = require("node:assert/strict");
7
- //#region src/digest.test.ts
8
- const encoder = new TextEncoder();
9
- const decoder = new TextDecoder();
10
- const bytes = encoder.encode("Hello World!");
11
- const digestMultibase = "zQmWvQxTqbG2Z9HPJgG57jjwR154cKhbtJenbyYTWkjgF3e";
12
- const hashlink = `hl:${digestMultibase}`;
13
- (0, node_test.test)("computeDigestMultibase() computes a SHA-256 multihash", async () => {
14
- (0, node_assert_strict.equal)(await require_digest.computeDigestMultibase(bytes), digestMultibase);
15
- const parsed = require_digest.parseDigestMultibase(digestMultibase);
16
- (0, node_assert_strict.equal)(parsed.algorithm, "sha2-256");
17
- (0, node_assert_strict.deepStrictEqual)(parsed.digest, new Uint8Array(await crypto.subtle.digest("SHA-256", bytes)));
18
- });
19
- (0, node_test.test)("digest helpers accept SharedArrayBuffer-backed bytes", async () => {
20
- const sharedBytes = new Uint8Array(new SharedArrayBuffer(bytes.length));
21
- sharedBytes.set(bytes);
22
- Object.defineProperty(sharedBytes, "slice", { value: () => {
23
- throw new Error("Shared input must not be copied with slice().");
24
- } });
25
- (0, node_assert_strict.equal)(await require_digest.computeDigestMultibase(sharedBytes), digestMultibase);
26
- (0, node_assert_strict.equal)(await require_digest.verifyDigestMultibase(sharedBytes, digestMultibase), true);
27
- });
28
- (0, node_test.test)("digest helpers ignore spoofed shared buffer tags", async () => {
29
- const taggedBytes = bytes.slice();
30
- Object.defineProperty(taggedBytes.buffer, Symbol.toStringTag, { value: "SharedArrayBuffer" });
31
- Object.defineProperty(taggedBytes, "slice", { value: () => {
32
- throw new Error("ArrayBuffer input must not be copied.");
33
- } });
34
- (0, node_assert_strict.equal)(await require_digest.computeDigestMultibase(taggedBytes), digestMultibase);
35
- (0, node_assert_strict.equal)(await require_digest.verifyDigestMultibase(taggedBytes, digestMultibase), true);
36
- });
37
- (0, node_test.test)("createHashlink() and parseHashlink() round-trip simple hashlinks", () => {
38
- (0, node_assert_strict.equal)(require_digest.createHashlink(digestMultibase), hashlink);
39
- (0, node_assert_strict.deepStrictEqual)(require_digest.parseHashlink(hashlink), { digestMultibase });
40
- (0, node_assert_strict.deepStrictEqual)(require_digest.parseHashlink(new URL(hashlink)), { digestMultibase });
41
- const base64DigestMultibase = decoder.decode(require_multibase.encodeMultibase("base64", require_multicodec.addMulticodecPrefix(18, require_multicodec.addMulticodecPrefix(32, new Uint8Array(32).fill(255)))));
42
- const base64Hashlink = require_digest.createHashlink(base64DigestMultibase);
43
- (0, node_assert_strict.equal)(base64Hashlink, "hl:mEiD//////////////////////////////////////////w");
44
- (0, node_assert_strict.deepStrictEqual)(require_digest.parseHashlink(base64Hashlink), { digestMultibase: base64DigestMultibase });
45
- (0, node_assert_strict.deepStrictEqual)(require_digest.parseHashlink(new URL(base64Hashlink)), { digestMultibase: base64DigestMultibase });
46
- });
47
- (0, node_test.test)("digest and hashlink verification accepts matching bytes", async () => {
48
- (0, node_assert_strict.equal)(await require_digest.verifyDigestMultibase(bytes, digestMultibase), true);
49
- (0, node_assert_strict.equal)(await require_digest.verifyHashlink(bytes, hashlink), true);
50
- (0, node_assert_strict.equal)(await require_digest.verifyHashlink(bytes, new URL(hashlink)), true);
51
- });
52
- (0, node_test.test)("digest and hashlink verification rejects non-matching bytes", async () => {
53
- const different = encoder.encode("Hello World?");
54
- (0, node_assert_strict.equal)(await require_digest.verifyDigestMultibase(different, digestMultibase), false);
55
- (0, node_assert_strict.equal)(await require_digest.verifyHashlink(different, hashlink), false);
56
- });
57
- (0, node_test.test)("parseDigestMultibase() rejects unsupported algorithms", () => {
58
- const sha1Multihash = require_multicodec.addMulticodecPrefix(17, require_multicodec.addMulticodecPrefix(20, new Uint8Array(20)));
59
- const value = decoder.decode(require_multibase.encodeMultibase("base58btc", sha1Multihash));
60
- (0, node_assert_strict.throws)(() => require_digest.parseDigestMultibase(value), /* @__PURE__ */ new TypeError("Unsupported digest algorithm: 0x11"));
61
- });
62
- (0, node_test.test)("parseDigestMultibase() rejects malformed values", async () => {
63
- (0, node_assert_strict.throws)(() => require_digest.parseDigestMultibase("not-multibase"), /* @__PURE__ */ new TypeError("Invalid digestMultibase encoding."));
64
- const missingLength = decoder.decode(require_multibase.encodeMultibase("base58btc", Uint8Array.of(18)));
65
- (0, node_assert_strict.throws)(() => require_digest.parseDigestMultibase(missingLength), /* @__PURE__ */ new TypeError("Invalid digestMultibase multihash."));
66
- const multihash = require_multicodec.addMulticodecPrefix(18, require_multicodec.addMulticodecPrefix(32, new Uint8Array(32)));
67
- const base2 = decoder.decode(require_multibase.encodeMultibase("base2", multihash));
68
- (0, node_assert_strict.equal)(base2.length, 273);
69
- (0, node_assert_strict.deepStrictEqual)(require_digest.parseDigestMultibase(base2).digest, new Uint8Array(32));
70
- (0, node_assert_strict.throws)(() => require_digest.parseDigestMultibase(`${base2}0`), /* @__PURE__ */ new TypeError("Invalid digestMultibase encoding."));
71
- const padded = decoder.decode(require_multibase.encodeMultibase("base64pad", multihash));
72
- (0, node_assert_strict.equal)(padded.endsWith("=="), true);
73
- (0, node_assert_strict.deepStrictEqual)(require_digest.parseDigestMultibase(padded).digest, new Uint8Array(32));
74
- (0, node_assert_strict.throws)(() => require_digest.parseDigestMultibase(padded.slice(0, -1)), /* @__PURE__ */ new TypeError("Invalid digestMultibase encoding."));
75
- (0, node_assert_strict.throws)(() => require_digest.createHashlink(`${padded}=`), /* @__PURE__ */ new TypeError("Invalid digestMultibase encoding."));
76
- const overlongAlgorithm = decoder.decode(require_multibase.encodeMultibase("base58btc", Uint8Array.of(146, 0, 32, ...new Uint8Array(32))));
77
- (0, node_assert_strict.throws)(() => require_digest.parseDigestMultibase(overlongAlgorithm), /* @__PURE__ */ new TypeError("Invalid digestMultibase multihash."));
78
- const overlongLength = decoder.decode(require_multibase.encodeMultibase("base58btc", Uint8Array.of(18, 160, 0, ...new Uint8Array(32))));
79
- (0, node_assert_strict.throws)(() => require_digest.parseDigestMultibase(overlongLength), /* @__PURE__ */ new TypeError("Invalid digestMultibase multihash."));
80
- const shortDigest = decoder.decode(require_multibase.encodeMultibase("base58btc", require_multicodec.addMulticodecPrefix(18, require_multicodec.addMulticodecPrefix(31, new Uint8Array(31)))));
81
- (0, node_assert_strict.throws)(() => require_digest.parseDigestMultibase(shortDigest), /* @__PURE__ */ new TypeError("Invalid SHA-256 digest length."));
82
- await (0, node_assert_strict.rejects)(() => require_digest.verifyDigestMultibase(bytes, shortDigest), /* @__PURE__ */ new TypeError("Invalid SHA-256 digest length."));
83
- });
84
- (0, node_test.test)("simple hashlink helpers reject metadata and malformed forms", async () => {
85
- for (const terminator of [
86
- "\n",
87
- "\r",
88
- "\r\n",
89
- "\u2028",
90
- "\u2029"
91
- ]) {
92
- const malformedHashlink = `${hashlink}${terminator}`;
93
- (0, node_assert_strict.throws)(() => require_digest.parseHashlink(malformedHashlink), /* @__PURE__ */ new TypeError("Invalid simple hashlink."));
94
- await (0, node_assert_strict.rejects)(() => require_digest.verifyHashlink(bytes, malformedHashlink), /* @__PURE__ */ new TypeError("Invalid simple hashlink."));
95
- }
96
- (0, node_assert_strict.throws)(() => require_digest.parseHashlink(`${hashlink}:zmetadata`), /* @__PURE__ */ new TypeError("Invalid simple hashlink."));
97
- await (0, node_assert_strict.rejects)(() => require_digest.verifyHashlink(bytes, `${hashlink}:zmetadata`), /* @__PURE__ */ new TypeError("Invalid simple hashlink."));
98
- (0, node_assert_strict.throws)(() => require_digest.parseHashlink(`https://example.com/file?hl=${digestMultibase}`), /* @__PURE__ */ new TypeError("Invalid simple hashlink."));
99
- (0, node_assert_strict.throws)(() => require_digest.parseHashlink("hl:not-multibase"), /* @__PURE__ */ new TypeError("Invalid digestMultibase encoding."));
100
- await (0, node_assert_strict.rejects)(() => require_digest.verifyHashlink(bytes, "hl:not-multibase"), /* @__PURE__ */ new TypeError("Invalid digestMultibase encoding."));
101
- (0, node_assert_strict.throws)(() => require_digest.createHashlink("not-multibase"), /* @__PURE__ */ new TypeError("Invalid digestMultibase encoding."));
102
- });
103
- //#endregion
@@ -1 +0,0 @@
1
- export { };
@@ -1 +0,0 @@
1
- export { };
@@ -1,103 +0,0 @@
1
- import { t as addMulticodecPrefix } from "./multicodec-CyFp54fI.mjs";
2
- import { n as encodeMultibase } from "./multibase-Cluwl8OM.mjs";
3
- import { a as verifyDigestMultibase, i as parseHashlink, n as createHashlink, o as verifyHashlink, r as parseDigestMultibase, t as computeDigestMultibase } from "./digest-BJlumPNJ.mjs";
4
- import { test } from "node:test";
5
- import { deepStrictEqual, equal, rejects, throws } from "node:assert/strict";
6
- //#region src/digest.test.ts
7
- const encoder = new TextEncoder();
8
- const decoder = new TextDecoder();
9
- const bytes = encoder.encode("Hello World!");
10
- const digestMultibase = "zQmWvQxTqbG2Z9HPJgG57jjwR154cKhbtJenbyYTWkjgF3e";
11
- const hashlink = `hl:${digestMultibase}`;
12
- test("computeDigestMultibase() computes a SHA-256 multihash", async () => {
13
- equal(await computeDigestMultibase(bytes), digestMultibase);
14
- const parsed = parseDigestMultibase(digestMultibase);
15
- equal(parsed.algorithm, "sha2-256");
16
- deepStrictEqual(parsed.digest, new Uint8Array(await crypto.subtle.digest("SHA-256", bytes)));
17
- });
18
- test("digest helpers accept SharedArrayBuffer-backed bytes", async () => {
19
- const sharedBytes = new Uint8Array(new SharedArrayBuffer(bytes.length));
20
- sharedBytes.set(bytes);
21
- Object.defineProperty(sharedBytes, "slice", { value: () => {
22
- throw new Error("Shared input must not be copied with slice().");
23
- } });
24
- equal(await computeDigestMultibase(sharedBytes), digestMultibase);
25
- equal(await verifyDigestMultibase(sharedBytes, digestMultibase), true);
26
- });
27
- test("digest helpers ignore spoofed shared buffer tags", async () => {
28
- const taggedBytes = bytes.slice();
29
- Object.defineProperty(taggedBytes.buffer, Symbol.toStringTag, { value: "SharedArrayBuffer" });
30
- Object.defineProperty(taggedBytes, "slice", { value: () => {
31
- throw new Error("ArrayBuffer input must not be copied.");
32
- } });
33
- equal(await computeDigestMultibase(taggedBytes), digestMultibase);
34
- equal(await verifyDigestMultibase(taggedBytes, digestMultibase), true);
35
- });
36
- test("createHashlink() and parseHashlink() round-trip simple hashlinks", () => {
37
- equal(createHashlink(digestMultibase), hashlink);
38
- deepStrictEqual(parseHashlink(hashlink), { digestMultibase });
39
- deepStrictEqual(parseHashlink(new URL(hashlink)), { digestMultibase });
40
- const base64DigestMultibase = decoder.decode(encodeMultibase("base64", addMulticodecPrefix(18, addMulticodecPrefix(32, new Uint8Array(32).fill(255)))));
41
- const base64Hashlink = createHashlink(base64DigestMultibase);
42
- equal(base64Hashlink, "hl:mEiD//////////////////////////////////////////w");
43
- deepStrictEqual(parseHashlink(base64Hashlink), { digestMultibase: base64DigestMultibase });
44
- deepStrictEqual(parseHashlink(new URL(base64Hashlink)), { digestMultibase: base64DigestMultibase });
45
- });
46
- test("digest and hashlink verification accepts matching bytes", async () => {
47
- equal(await verifyDigestMultibase(bytes, digestMultibase), true);
48
- equal(await verifyHashlink(bytes, hashlink), true);
49
- equal(await verifyHashlink(bytes, new URL(hashlink)), true);
50
- });
51
- test("digest and hashlink verification rejects non-matching bytes", async () => {
52
- const different = encoder.encode("Hello World?");
53
- equal(await verifyDigestMultibase(different, digestMultibase), false);
54
- equal(await verifyHashlink(different, hashlink), false);
55
- });
56
- test("parseDigestMultibase() rejects unsupported algorithms", () => {
57
- const sha1Multihash = addMulticodecPrefix(17, addMulticodecPrefix(20, new Uint8Array(20)));
58
- const value = decoder.decode(encodeMultibase("base58btc", sha1Multihash));
59
- throws(() => parseDigestMultibase(value), /* @__PURE__ */ new TypeError("Unsupported digest algorithm: 0x11"));
60
- });
61
- test("parseDigestMultibase() rejects malformed values", async () => {
62
- throws(() => parseDigestMultibase("not-multibase"), /* @__PURE__ */ new TypeError("Invalid digestMultibase encoding."));
63
- const missingLength = decoder.decode(encodeMultibase("base58btc", Uint8Array.of(18)));
64
- throws(() => parseDigestMultibase(missingLength), /* @__PURE__ */ new TypeError("Invalid digestMultibase multihash."));
65
- const multihash = addMulticodecPrefix(18, addMulticodecPrefix(32, new Uint8Array(32)));
66
- const base2 = decoder.decode(encodeMultibase("base2", multihash));
67
- equal(base2.length, 273);
68
- deepStrictEqual(parseDigestMultibase(base2).digest, new Uint8Array(32));
69
- throws(() => parseDigestMultibase(`${base2}0`), /* @__PURE__ */ new TypeError("Invalid digestMultibase encoding."));
70
- const padded = decoder.decode(encodeMultibase("base64pad", multihash));
71
- equal(padded.endsWith("=="), true);
72
- deepStrictEqual(parseDigestMultibase(padded).digest, new Uint8Array(32));
73
- throws(() => parseDigestMultibase(padded.slice(0, -1)), /* @__PURE__ */ new TypeError("Invalid digestMultibase encoding."));
74
- throws(() => createHashlink(`${padded}=`), /* @__PURE__ */ new TypeError("Invalid digestMultibase encoding."));
75
- const overlongAlgorithm = decoder.decode(encodeMultibase("base58btc", Uint8Array.of(146, 0, 32, ...new Uint8Array(32))));
76
- throws(() => parseDigestMultibase(overlongAlgorithm), /* @__PURE__ */ new TypeError("Invalid digestMultibase multihash."));
77
- const overlongLength = decoder.decode(encodeMultibase("base58btc", Uint8Array.of(18, 160, 0, ...new Uint8Array(32))));
78
- throws(() => parseDigestMultibase(overlongLength), /* @__PURE__ */ new TypeError("Invalid digestMultibase multihash."));
79
- const shortDigest = decoder.decode(encodeMultibase("base58btc", addMulticodecPrefix(18, addMulticodecPrefix(31, new Uint8Array(31)))));
80
- throws(() => parseDigestMultibase(shortDigest), /* @__PURE__ */ new TypeError("Invalid SHA-256 digest length."));
81
- await rejects(() => verifyDigestMultibase(bytes, shortDigest), /* @__PURE__ */ new TypeError("Invalid SHA-256 digest length."));
82
- });
83
- test("simple hashlink helpers reject metadata and malformed forms", async () => {
84
- for (const terminator of [
85
- "\n",
86
- "\r",
87
- "\r\n",
88
- "\u2028",
89
- "\u2029"
90
- ]) {
91
- const malformedHashlink = `${hashlink}${terminator}`;
92
- throws(() => parseHashlink(malformedHashlink), /* @__PURE__ */ new TypeError("Invalid simple hashlink."));
93
- await rejects(() => verifyHashlink(bytes, malformedHashlink), /* @__PURE__ */ new TypeError("Invalid simple hashlink."));
94
- }
95
- throws(() => parseHashlink(`${hashlink}:zmetadata`), /* @__PURE__ */ new TypeError("Invalid simple hashlink."));
96
- await rejects(() => verifyHashlink(bytes, `${hashlink}:zmetadata`), /* @__PURE__ */ new TypeError("Invalid simple hashlink."));
97
- throws(() => parseHashlink(`https://example.com/file?hl=${digestMultibase}`), /* @__PURE__ */ new TypeError("Invalid simple hashlink."));
98
- throws(() => parseHashlink("hl:not-multibase"), /* @__PURE__ */ new TypeError("Invalid digestMultibase encoding."));
99
- await rejects(() => verifyHashlink(bytes, "hl:not-multibase"), /* @__PURE__ */ new TypeError("Invalid digestMultibase encoding."));
100
- throws(() => createHashlink("not-multibase"), /* @__PURE__ */ new TypeError("Invalid digestMultibase encoding."));
101
- });
102
- //#endregion
103
- export {};
@@ -1,10 +0,0 @@
1
- {
2
- "@context": {
3
- "gateways": {
4
- "@id": "https://w3id.org/fep/ef61/gateways",
5
- "@type": "@id",
6
- "@container": "@list"
7
- },
8
- "digestMultibase": "https://www.w3.org/ns/credentials/v2#digestMultibase"
9
- }
10
- }
@@ -1,220 +0,0 @@
1
- import { deepStrictEqual, equal, rejects, throws } from "node:assert/strict";
2
- import { test } from "node:test";
3
- import { addMulticodecPrefix } from "./internal/multicodec.ts";
4
- import { encodeMultibase } from "./multibase/mod.ts";
5
- import {
6
- computeDigestMultibase,
7
- createHashlink,
8
- parseDigestMultibase,
9
- parseHashlink,
10
- verifyDigestMultibase,
11
- verifyHashlink,
12
- } from "./digest.ts";
13
-
14
- const encoder = new TextEncoder();
15
- const decoder = new TextDecoder();
16
- const bytes = encoder.encode("Hello World!");
17
- // Test vector from draft-sporny-hashlink-07, appendix B.1.
18
- const digestMultibase = "zQmWvQxTqbG2Z9HPJgG57jjwR154cKhbtJenbyYTWkjgF3e";
19
- const hashlink = `hl:${digestMultibase}`;
20
-
21
- test("computeDigestMultibase() computes a SHA-256 multihash", async () => {
22
- equal(await computeDigestMultibase(bytes), digestMultibase);
23
- const parsed = parseDigestMultibase(digestMultibase);
24
- equal(parsed.algorithm, "sha2-256");
25
- deepStrictEqual(
26
- parsed.digest,
27
- new Uint8Array(await crypto.subtle.digest("SHA-256", bytes)),
28
- );
29
- });
30
-
31
- test("digest helpers accept SharedArrayBuffer-backed bytes", async () => {
32
- const sharedBytes = new Uint8Array(new SharedArrayBuffer(bytes.length));
33
- sharedBytes.set(bytes);
34
- Object.defineProperty(sharedBytes, "slice", {
35
- value: () => {
36
- throw new Error("Shared input must not be copied with slice().");
37
- },
38
- });
39
- equal(await computeDigestMultibase(sharedBytes), digestMultibase);
40
- equal(await verifyDigestMultibase(sharedBytes, digestMultibase), true);
41
- });
42
-
43
- test("digest helpers ignore spoofed shared buffer tags", async () => {
44
- const taggedBytes = bytes.slice();
45
- Object.defineProperty(taggedBytes.buffer, Symbol.toStringTag, {
46
- value: "SharedArrayBuffer",
47
- });
48
- Object.defineProperty(taggedBytes, "slice", {
49
- value: () => {
50
- throw new Error("ArrayBuffer input must not be copied.");
51
- },
52
- });
53
- equal(await computeDigestMultibase(taggedBytes), digestMultibase);
54
- equal(await verifyDigestMultibase(taggedBytes, digestMultibase), true);
55
- });
56
-
57
- test("createHashlink() and parseHashlink() round-trip simple hashlinks", () => {
58
- equal(createHashlink(digestMultibase), hashlink);
59
- deepStrictEqual(parseHashlink(hashlink), { digestMultibase });
60
- deepStrictEqual(parseHashlink(new URL(hashlink)), { digestMultibase });
61
-
62
- const base64DigestMultibase = decoder.decode(
63
- encodeMultibase(
64
- "base64",
65
- addMulticodecPrefix(
66
- 0x12,
67
- addMulticodecPrefix(32, new Uint8Array(32).fill(0xff)),
68
- ),
69
- ),
70
- );
71
- const base64Hashlink = createHashlink(base64DigestMultibase);
72
- equal(
73
- base64Hashlink,
74
- "hl:mEiD//////////////////////////////////////////w",
75
- );
76
- deepStrictEqual(parseHashlink(base64Hashlink), {
77
- digestMultibase: base64DigestMultibase,
78
- });
79
- deepStrictEqual(parseHashlink(new URL(base64Hashlink)), {
80
- digestMultibase: base64DigestMultibase,
81
- });
82
- });
83
-
84
- test("digest and hashlink verification accepts matching bytes", async () => {
85
- equal(await verifyDigestMultibase(bytes, digestMultibase), true);
86
- equal(await verifyHashlink(bytes, hashlink), true);
87
- equal(await verifyHashlink(bytes, new URL(hashlink)), true);
88
- });
89
-
90
- test("digest and hashlink verification rejects non-matching bytes", async () => {
91
- const different = encoder.encode("Hello World?");
92
- equal(await verifyDigestMultibase(different, digestMultibase), false);
93
- equal(await verifyHashlink(different, hashlink), false);
94
- });
95
-
96
- test("parseDigestMultibase() rejects unsupported algorithms", () => {
97
- const sha1Multihash = addMulticodecPrefix(
98
- 0x11,
99
- addMulticodecPrefix(20, new Uint8Array(20)),
100
- );
101
- const value = decoder.decode(encodeMultibase("base58btc", sha1Multihash));
102
- throws(
103
- () => parseDigestMultibase(value),
104
- new TypeError("Unsupported digest algorithm: 0x11"),
105
- );
106
- });
107
-
108
- test("parseDigestMultibase() rejects malformed values", async () => {
109
- throws(
110
- () => parseDigestMultibase("not-multibase"),
111
- new TypeError("Invalid digestMultibase encoding."),
112
- );
113
-
114
- const missingLength = decoder.decode(
115
- encodeMultibase("base58btc", Uint8Array.of(0x12)),
116
- );
117
- throws(
118
- () => parseDigestMultibase(missingLength),
119
- new TypeError("Invalid digestMultibase multihash."),
120
- );
121
-
122
- const multihash = addMulticodecPrefix(
123
- 0x12,
124
- addMulticodecPrefix(32, new Uint8Array(32)),
125
- );
126
- const base2 = decoder.decode(encodeMultibase("base2", multihash));
127
- equal(base2.length, 273);
128
- deepStrictEqual(parseDigestMultibase(base2).digest, new Uint8Array(32));
129
- throws(
130
- () => parseDigestMultibase(`${base2}0`),
131
- new TypeError("Invalid digestMultibase encoding."),
132
- );
133
-
134
- const padded = decoder.decode(encodeMultibase("base64pad", multihash));
135
- equal(padded.endsWith("=="), true);
136
- deepStrictEqual(parseDigestMultibase(padded).digest, new Uint8Array(32));
137
- throws(
138
- () => parseDigestMultibase(padded.slice(0, -1)),
139
- new TypeError("Invalid digestMultibase encoding."),
140
- );
141
- throws(
142
- () => createHashlink(`${padded}=`),
143
- new TypeError("Invalid digestMultibase encoding."),
144
- );
145
-
146
- const overlongAlgorithm = decoder.decode(
147
- encodeMultibase(
148
- "base58btc",
149
- Uint8Array.of(0x92, 0x00, 0x20, ...new Uint8Array(32)),
150
- ),
151
- );
152
- throws(
153
- () => parseDigestMultibase(overlongAlgorithm),
154
- new TypeError("Invalid digestMultibase multihash."),
155
- );
156
-
157
- const overlongLength = decoder.decode(
158
- encodeMultibase(
159
- "base58btc",
160
- Uint8Array.of(0x12, 0xa0, 0x00, ...new Uint8Array(32)),
161
- ),
162
- );
163
- throws(
164
- () => parseDigestMultibase(overlongLength),
165
- new TypeError("Invalid digestMultibase multihash."),
166
- );
167
-
168
- const shortDigest = decoder.decode(
169
- encodeMultibase(
170
- "base58btc",
171
- addMulticodecPrefix(0x12, addMulticodecPrefix(31, new Uint8Array(31))),
172
- ),
173
- );
174
- throws(
175
- () => parseDigestMultibase(shortDigest),
176
- new TypeError("Invalid SHA-256 digest length."),
177
- );
178
- await rejects(
179
- () => verifyDigestMultibase(bytes, shortDigest),
180
- new TypeError("Invalid SHA-256 digest length."),
181
- );
182
- });
183
-
184
- test("simple hashlink helpers reject metadata and malformed forms", async () => {
185
- for (const terminator of ["\n", "\r", "\r\n", "\u2028", "\u2029"]) {
186
- const malformedHashlink = `${hashlink}${terminator}`;
187
- throws(
188
- () => parseHashlink(malformedHashlink),
189
- new TypeError("Invalid simple hashlink."),
190
- );
191
- await rejects(
192
- () => verifyHashlink(bytes, malformedHashlink),
193
- new TypeError("Invalid simple hashlink."),
194
- );
195
- }
196
- throws(
197
- () => parseHashlink(`${hashlink}:zmetadata`),
198
- new TypeError("Invalid simple hashlink."),
199
- );
200
- await rejects(
201
- () => verifyHashlink(bytes, `${hashlink}:zmetadata`),
202
- new TypeError("Invalid simple hashlink."),
203
- );
204
- throws(
205
- () => parseHashlink(`https://example.com/file?hl=${digestMultibase}`),
206
- new TypeError("Invalid simple hashlink."),
207
- );
208
- throws(
209
- () => parseHashlink("hl:not-multibase"),
210
- new TypeError("Invalid digestMultibase encoding."),
211
- );
212
- await rejects(
213
- () => verifyHashlink(bytes, "hl:not-multibase"),
214
- new TypeError("Invalid digestMultibase encoding."),
215
- );
216
- throws(
217
- () => createHashlink("not-multibase"),
218
- new TypeError("Invalid digestMultibase encoding."),
219
- );
220
- });
package/src/digest.ts DELETED
@@ -1,229 +0,0 @@
1
- import {
2
- addMulticodecPrefix,
3
- getMulticodecPrefix,
4
- } from "./internal/multicodec.ts";
5
- import {
6
- decodeMultibase,
7
- encodeMultibase,
8
- encodingFromBaseData,
9
- } from "./multibase/mod.ts";
10
-
11
- const SHA2_256_MULTIHASH_CODE = 0x12;
12
- const SHA2_256_DIGEST_LENGTH = 32;
13
- const MAX_DIGEST_MULTIBASE_LENGTH = 1 + (SHA2_256_DIGEST_LENGTH + 2) * 8;
14
- const textDecoder = new TextDecoder();
15
- const getArrayBufferByteLength = Object.getOwnPropertyDescriptor(
16
- ArrayBuffer.prototype,
17
- "byteLength",
18
- )?.get;
19
-
20
- function isCanonicalVarintPrefix(
21
- data: Uint8Array,
22
- prefix: ReturnType<typeof getMulticodecPrefix>,
23
- ): boolean {
24
- const canonical = addMulticodecPrefix(prefix.code, new Uint8Array());
25
- if (canonical.length !== prefix.prefixLength) return false;
26
- for (let i = 0; i < canonical.length; i++) {
27
- if (data[i] !== canonical[i]) return false;
28
- }
29
- return true;
30
- }
31
-
32
- function toWebCryptoBytes(bytes: Uint8Array): Uint8Array<ArrayBuffer> {
33
- if (getArrayBufferByteLength != null) {
34
- try {
35
- getArrayBufferByteLength.call(bytes.buffer);
36
- return bytes as Uint8Array<ArrayBuffer>;
37
- } catch {
38
- // SharedArrayBuffer input needs to be copied for Web Crypto.
39
- }
40
- }
41
- return new Uint8Array(bytes);
42
- }
43
-
44
- /**
45
- * A parsed SHA-256 resource digest.
46
- *
47
- * @since 2.4.0
48
- */
49
- export interface ParsedDigestMultibase {
50
- /** The multihash algorithm represented by the digest. */
51
- readonly algorithm: "sha2-256";
52
-
53
- /** The raw 32-byte SHA-256 digest. */
54
- readonly digest: Uint8Array;
55
- }
56
-
57
- /**
58
- * A parsed simple hashlink.
59
- *
60
- * @since 2.4.0
61
- */
62
- export interface ParsedHashlink {
63
- /** The multibase-encoded multihash carried by the hashlink. */
64
- readonly digestMultibase: string;
65
- }
66
-
67
- /**
68
- * Computes the SHA-256 digest of a byte sequence and encodes it as a
69
- * base58-btc multibase multihash suitable for FEP-ef61's
70
- * `digestMultibase` property.
71
- *
72
- * @param bytes The bytes to digest.
73
- * @returns The base58-btc multibase-encoded SHA-256 multihash.
74
- * @since 2.4.0
75
- */
76
- export async function computeDigestMultibase(
77
- bytes: Uint8Array,
78
- ): Promise<string> {
79
- const digest = new Uint8Array(
80
- await crypto.subtle.digest("SHA-256", toWebCryptoBytes(bytes)),
81
- );
82
- const lengthAndDigest = addMulticodecPrefix(digest.length, digest);
83
- const multihash = addMulticodecPrefix(
84
- SHA2_256_MULTIHASH_CODE,
85
- lengthAndDigest,
86
- );
87
- return textDecoder.decode(encodeMultibase("base58btc", multihash));
88
- }
89
-
90
- /**
91
- * Parses and validates a SHA-256 `digestMultibase` value.
92
- *
93
- * @param value The multibase-encoded multihash to parse.
94
- * @returns The digest algorithm and raw digest bytes.
95
- * @throws {TypeError} If the value is malformed or uses an unsupported hash
96
- * algorithm.
97
- * @since 2.4.0
98
- */
99
- export function parseDigestMultibase(value: string): ParsedDigestMultibase {
100
- if (value.length > MAX_DIGEST_MULTIBASE_LENGTH) {
101
- throw new TypeError("Invalid digestMultibase encoding.");
102
- }
103
- let multihash: Uint8Array;
104
- try {
105
- multihash = decodeMultibase(value);
106
- } catch (error) {
107
- throw new TypeError("Invalid digestMultibase encoding.", { cause: error });
108
- }
109
- const encoding = encodingFromBaseData(value);
110
- const canonicalValue = textDecoder.decode(
111
- encodeMultibase(encoding.name, multihash),
112
- );
113
- if (value !== canonicalValue) {
114
- throw new TypeError("Invalid digestMultibase encoding.");
115
- }
116
-
117
- let algorithmPrefix: ReturnType<typeof getMulticodecPrefix>;
118
- try {
119
- algorithmPrefix = getMulticodecPrefix(multihash);
120
- } catch (error) {
121
- throw new TypeError("Invalid digestMultibase multihash.", { cause: error });
122
- }
123
- if (!isCanonicalVarintPrefix(multihash, algorithmPrefix)) {
124
- throw new TypeError("Invalid digestMultibase multihash.");
125
- }
126
- if (algorithmPrefix.code !== SHA2_256_MULTIHASH_CODE) {
127
- throw new TypeError(
128
- `Unsupported digest algorithm: 0x${algorithmPrefix.code.toString(16)}`,
129
- );
130
- }
131
-
132
- const lengthAndDigest = multihash.subarray(algorithmPrefix.prefixLength);
133
- let lengthPrefix: ReturnType<typeof getMulticodecPrefix>;
134
- try {
135
- lengthPrefix = getMulticodecPrefix(lengthAndDigest);
136
- } catch (error) {
137
- throw new TypeError("Invalid digestMultibase multihash.", { cause: error });
138
- }
139
- if (!isCanonicalVarintPrefix(lengthAndDigest, lengthPrefix)) {
140
- throw new TypeError("Invalid digestMultibase multihash.");
141
- }
142
- const digest = lengthAndDigest.slice(lengthPrefix.prefixLength);
143
- if (
144
- lengthPrefix.code !== SHA2_256_DIGEST_LENGTH ||
145
- digest.length !== SHA2_256_DIGEST_LENGTH
146
- ) {
147
- throw new TypeError("Invalid SHA-256 digest length.");
148
- }
149
- return { algorithm: "sha2-256", digest };
150
- }
151
-
152
- function extractDigestMultibase(value: string | URL): string {
153
- const hashlink = typeof value === "string" ? value : value.href;
154
- const match = /^hl:([^:\r\n\u2028\u2029]+)$/i.exec(hashlink);
155
- if (match == null || match[0].length !== hashlink.length) {
156
- throw new TypeError("Invalid simple hashlink.");
157
- }
158
- return match[1];
159
- }
160
-
161
- /**
162
- * Parses a metadata-free `hl:` hashlink and validates its resource digest.
163
- *
164
- * @param value The simple hashlink to parse.
165
- * @returns The `digestMultibase` value carried by the hashlink.
166
- * @throws {TypeError} If the hashlink is malformed, contains metadata, or
167
- * carries an invalid or unsupported digest.
168
- * @since 2.4.0
169
- */
170
- export function parseHashlink(value: string | URL): ParsedHashlink {
171
- const digestMultibase = extractDigestMultibase(value);
172
- parseDigestMultibase(digestMultibase);
173
- return { digestMultibase };
174
- }
175
-
176
- /**
177
- * Creates a metadata-free `hl:` hashlink from a `digestMultibase` value.
178
- *
179
- * @param digestMultibase The SHA-256 multibase multihash to embed.
180
- * @returns The simple hashlink.
181
- * @throws {TypeError} If the digest is malformed or unsupported.
182
- * @since 2.4.0
183
- */
184
- export function createHashlink(digestMultibase: string): string {
185
- parseDigestMultibase(digestMultibase);
186
- return `hl:${digestMultibase}`;
187
- }
188
-
189
- /**
190
- * Verifies that bytes match a SHA-256 `digestMultibase` value.
191
- *
192
- * @param bytes The bytes to verify.
193
- * @param digestMultibase The expected digest.
194
- * @returns Whether the bytes match the digest.
195
- * @throws {TypeError} If the digest is malformed or unsupported.
196
- * @since 2.4.0
197
- */
198
- export async function verifyDigestMultibase(
199
- bytes: Uint8Array,
200
- digestMultibase: string,
201
- ): Promise<boolean> {
202
- const expected = parseDigestMultibase(digestMultibase).digest;
203
- const actual = new Uint8Array(
204
- await crypto.subtle.digest("SHA-256", toWebCryptoBytes(bytes)),
205
- );
206
- if (expected.length !== actual.length) return false;
207
- let difference = 0;
208
- for (let i = 0; i < expected.length; i++) {
209
- difference |= expected[i] ^ actual[i];
210
- }
211
- return difference === 0;
212
- }
213
-
214
- /**
215
- * Verifies that bytes match the resource digest in a simple hashlink.
216
- *
217
- * @param bytes The bytes to verify.
218
- * @param hashlink The simple hashlink containing the expected digest.
219
- * @returns Whether the bytes match the hashlink digest.
220
- * @throws {TypeError} If the hashlink or digest is malformed or unsupported.
221
- * @since 2.4.0
222
- */
223
- export async function verifyHashlink(
224
- bytes: Uint8Array,
225
- hashlink: string | URL,
226
- ): Promise<boolean> {
227
- const digestMultibase = extractDigestMultibase(hashlink);
228
- return await verifyDigestMultibase(bytes, digestMultibase);
229
- }