@fedify/fedify 2.2.0-pr.710.24 → 2.2.0-pr.715.27
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.
- package/dist/{builder-CKJTVRhn.mjs → builder-DQtY9nHQ.mjs} +3 -3
- package/dist/compat/transformers.test.mjs +2 -2
- package/dist/{deno-cvysscWX.mjs → deno-_fgAC2zJ.mjs} +1 -1
- package/dist/{docloader-BuEazLeK.mjs → docloader-vRYuv1jI.mjs} +2 -2
- package/dist/federation/builder.test.mjs +2 -2
- package/dist/federation/collection.test.mjs +1 -1
- package/dist/federation/handler.test.mjs +4 -4
- package/dist/federation/idempotency.test.mjs +3 -3
- package/dist/federation/inbox.test.mjs +1 -1
- package/dist/federation/keycache.test.mjs +2 -2
- package/dist/federation/kv.test.mjs +1 -1
- package/dist/federation/middleware.test.mjs +7 -17
- package/dist/federation/mod.cjs +1 -1
- package/dist/federation/mod.js +1 -1
- package/dist/federation/negotiation.test.mjs +1 -1
- package/dist/federation/retry.test.mjs +1 -1
- package/dist/federation/send.test.mjs +3 -3
- package/dist/federation/webfinger.test.mjs +2 -2
- package/dist/{http-Dy22pK-t.mjs → http-C8rif6ld.mjs} +2 -2
- package/dist/{http-BJ7XtRRp.cjs → http-R-epZzZQ.cjs} +1 -1
- package/dist/{http-B0Tu7TW-.js → http-s3HaFg5o.js} +1 -1
- package/dist/{key-DXBoO6CC.mjs → key-Ce0SDXK2.mjs} +1 -1
- package/dist/{kv-cache-x4KOTSSC.cjs → kv-cache-Btpmwlb5.cjs} +1 -1
- package/dist/{kv-cache-Bxbq9e39.js → kv-cache-ChSAw77q.js} +1 -1
- package/dist/{ld-BW_1mHgq.mjs → ld-BsDP9tTM.mjs} +2 -2
- package/dist/{middleware-COjNuA6A.js → middleware-C4ymcV-E.js} +3 -4
- package/dist/{middleware-CRFf7Wb6.cjs → middleware-CXG1M9Om.cjs} +1 -1
- package/dist/{middleware-BdpMBegR.mjs → middleware-DFQeBAbL.mjs} +1 -1
- package/dist/{middleware-Bu0zxHoX.mjs → middleware-DtEWmK1Y.mjs} +15 -17
- package/dist/{middleware-QpqLtpW9.cjs → middleware-vUbXbazq.cjs} +4 -5
- package/dist/mod.cjs +4 -4
- package/dist/mod.js +4 -4
- package/dist/nodeinfo/client.test.mjs +1 -1
- package/dist/nodeinfo/handler.test.mjs +2 -2
- package/dist/nodeinfo/types.test.mjs +1 -1
- package/dist/otel/exporter.test.mjs +1 -1
- package/dist/{owner-CBdNJRwZ.mjs → owner-CTfDotXM.mjs} +2 -2
- package/dist/{proof-B__J6A1_.cjs → proof-3RPJLWOU.cjs} +38 -221
- package/dist/{proof-7MA0dp2c.mjs → proof-UdlPVu_P.mjs} +31 -36
- package/dist/{proof-Bfx0NdYz.js → proof-qQIVjzlw.js} +41 -218
- package/dist/{send-9BckNAN-.mjs → send-kudDOImz.mjs} +2 -2
- package/dist/sig/http.test.mjs +2 -2
- package/dist/sig/key.test.mjs +1 -1
- package/dist/sig/ld.test.mjs +2 -2
- package/dist/sig/mod.cjs +2 -2
- package/dist/sig/mod.js +2 -2
- package/dist/sig/owner.test.mjs +1 -1
- package/dist/sig/proof.test.mjs +2 -60
- package/dist/utils/docloader.test.mjs +2 -2
- package/dist/utils/mod.cjs +1 -1
- package/dist/utils/mod.js +1 -1
- package/package.json +5 -5
- package/dist/compat/public-audience.test.d.mts +0 -2
- package/dist/compat/public-audience.test.mjs +0 -162
- package/dist/public-audience-5WWE-JTr.mjs +0 -181
- /package/dist/{activity-listener-CFzUqoCS.mjs → activity-listener-Ck3JZ_hR.mjs} +0 -0
- /package/dist/{client-DVu6Fmom.mjs → client-DEpOVgY1.mjs} +0 -0
- /package/dist/{collection-BQRKGS7L.mjs → collection-BD6-SZ6O.mjs} +0 -0
- /package/dist/{keycache-C2t1kvP5.mjs → keycache-CCSwkQcY.mjs} +0 -0
- /package/dist/{kv-C-TG81Sv.mjs → kv-tL2TOE9X.mjs} +0 -0
- /package/dist/{negotiation-xb0QR3u_.mjs → negotiation-DnsfFF8I.mjs} +0 -0
- /package/dist/{retry-CJL0poaU.mjs → retry-B_E3V_Dx.mjs} +0 -0
- /package/dist/{types-CGUnLkU3.mjs → types-DCP0WLdt.mjs} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const { Temporal } = require("@js-temporal/polyfill");
|
|
2
2
|
const { URLPattern } = require("urlpattern-polyfill");
|
|
3
3
|
const require_chunk = require("./chunk-DDcVe30Y.cjs");
|
|
4
|
-
const require_http = require("./http-
|
|
4
|
+
const require_http = require("./http-R-epZzZQ.cjs");
|
|
5
5
|
let _logtape_logtape = require("@logtape/logtape");
|
|
6
6
|
let _fedify_vocab = require("@fedify/vocab");
|
|
7
7
|
let _opentelemetry_api = require("@opentelemetry/api");
|
|
@@ -13,7 +13,7 @@ _fedify_vocab_runtime_jsonld = require_chunk.__toESM(_fedify_vocab_runtime_jsonl
|
|
|
13
13
|
let json_canon = require("json-canon");
|
|
14
14
|
json_canon = require_chunk.__toESM(json_canon);
|
|
15
15
|
//#region src/sig/ld.ts
|
|
16
|
-
const logger$
|
|
16
|
+
const logger$1 = (0, _logtape_logtape.getLogger)([
|
|
17
17
|
"fedify",
|
|
18
18
|
"sig",
|
|
19
19
|
"ld"
|
|
@@ -161,7 +161,7 @@ async function verifySignature(jsonLd, options = {}) {
|
|
|
161
161
|
try {
|
|
162
162
|
signature = (0, byte_encodings_base64.decodeBase64)(sig.signatureValue);
|
|
163
163
|
} catch (error) {
|
|
164
|
-
logger$
|
|
164
|
+
logger$1.debug("Failed to verify; invalid base64 signatureValue: {signatureValue}", {
|
|
165
165
|
...sig,
|
|
166
166
|
error
|
|
167
167
|
});
|
|
@@ -180,7 +180,7 @@ async function verifySignature(jsonLd, options = {}) {
|
|
|
180
180
|
try {
|
|
181
181
|
sigOptsHash = await hashJsonLd(sigOpts, options.contextLoader);
|
|
182
182
|
} catch (error) {
|
|
183
|
-
logger$
|
|
183
|
+
logger$1.warn("Failed to verify; failed to hash the signature options: {signatureOptions}\n{error}", {
|
|
184
184
|
signatureOptions: sigOpts,
|
|
185
185
|
error
|
|
186
186
|
});
|
|
@@ -192,7 +192,7 @@ async function verifySignature(jsonLd, options = {}) {
|
|
|
192
192
|
try {
|
|
193
193
|
docHash = await hashJsonLd(document, options.contextLoader);
|
|
194
194
|
} catch (error) {
|
|
195
|
-
logger$
|
|
195
|
+
logger$1.warn("Failed to verify; failed to hash the document: {document}\n{error}", {
|
|
196
196
|
document,
|
|
197
197
|
error
|
|
198
198
|
});
|
|
@@ -203,7 +203,7 @@ async function verifySignature(jsonLd, options = {}) {
|
|
|
203
203
|
const messageBytes = encoder.encode(message);
|
|
204
204
|
if (await crypto.subtle.verify("RSASSA-PKCS1-v1_5", key.publicKey, signature.slice(), messageBytes)) return key;
|
|
205
205
|
if (cached) {
|
|
206
|
-
logger$
|
|
206
|
+
logger$1.debug("Failed to verify with the cached key {keyId}; signature {signatureValue} is invalid. Retrying with the freshly fetched key...", {
|
|
207
207
|
keyId: sig.creator,
|
|
208
208
|
...sig
|
|
209
209
|
});
|
|
@@ -217,7 +217,7 @@ async function verifySignature(jsonLd, options = {}) {
|
|
|
217
217
|
if (key == null) return null;
|
|
218
218
|
return await crypto.subtle.verify("RSASSA-PKCS1-v1_5", key.publicKey, signature.slice(), messageBytes) ? key : null;
|
|
219
219
|
}
|
|
220
|
-
logger$
|
|
220
|
+
logger$1.debug("Failed to verify with the fetched key {keyId}; signature {signatureValue} is invalid. Check if the key is correct or if the signed message is correct. The message to sign is:\n{message}", {
|
|
221
221
|
keyId: sig.creator,
|
|
222
222
|
...sig,
|
|
223
223
|
message
|
|
@@ -249,12 +249,12 @@ async function verifyJsonLd(jsonLd, options = {}) {
|
|
|
249
249
|
const key = await verifySignature(jsonLd, options);
|
|
250
250
|
if (key == null) return false;
|
|
251
251
|
if (key.ownerId == null) {
|
|
252
|
-
logger$
|
|
252
|
+
logger$1.debug("Key {keyId} has no owner.", { keyId: key.id?.href });
|
|
253
253
|
return false;
|
|
254
254
|
}
|
|
255
255
|
attributions.delete(key.ownerId.href);
|
|
256
256
|
if (attributions.size > 0) {
|
|
257
|
-
logger$
|
|
257
|
+
logger$1.debug("Some attributions are not authenticated by the Linked Data Signatures: {attributions}.", { attributions: [...attributions] });
|
|
258
258
|
return false;
|
|
259
259
|
}
|
|
260
260
|
return true;
|
|
@@ -389,179 +389,6 @@ async function getKeyOwner(keyId, options) {
|
|
|
389
389
|
return null;
|
|
390
390
|
}
|
|
391
391
|
//#endregion
|
|
392
|
-
//#region src/compat/public-audience.ts
|
|
393
|
-
const logger$1 = (0, _logtape_logtape.getLogger)([
|
|
394
|
-
"fedify",
|
|
395
|
-
"compat",
|
|
396
|
-
"public-audience"
|
|
397
|
-
]);
|
|
398
|
-
const PUBLIC_ADDRESSING_FIELDS = new Set([
|
|
399
|
-
"to",
|
|
400
|
-
"cc",
|
|
401
|
-
"bto",
|
|
402
|
-
"bcc",
|
|
403
|
-
"audience"
|
|
404
|
-
]);
|
|
405
|
-
const preloadedOnlyDocumentLoader = (url) => {
|
|
406
|
-
if (url in _fedify_vocab_runtime.preloadedContexts) return Promise.resolve({
|
|
407
|
-
contextUrl: null,
|
|
408
|
-
documentUrl: url,
|
|
409
|
-
document: _fedify_vocab_runtime.preloadedContexts[url]
|
|
410
|
-
});
|
|
411
|
-
return Promise.reject(/* @__PURE__ */ new Error("Refusing to fetch a non-preloaded JSON-LD context: " + url));
|
|
412
|
-
};
|
|
413
|
-
const AS_CONTEXT_URL = "https://www.w3.org/ns/activitystreams";
|
|
414
|
-
const MAX_TRAVERSAL_DEPTH = 64;
|
|
415
|
-
const KNOWN_SAFE_CONTEXT_URLS = new Set(Object.keys(_fedify_vocab_runtime.preloadedContexts));
|
|
416
|
-
function hasPublicCurieInAddressing(value, parentKey, depth = 0) {
|
|
417
|
-
if (typeof value === "string") return parentKey != null && PUBLIC_ADDRESSING_FIELDS.has(parentKey) && (value === "as:Public" || value === "Public");
|
|
418
|
-
if (depth >= MAX_TRAVERSAL_DEPTH) return false;
|
|
419
|
-
if (Array.isArray(value)) return value.some((item) => hasPublicCurieInAddressing(item, parentKey, depth + 1));
|
|
420
|
-
if (typeof value !== "object" || value == null) return false;
|
|
421
|
-
const record = value;
|
|
422
|
-
for (const key of Object.keys(record)) {
|
|
423
|
-
if (key === "@context") continue;
|
|
424
|
-
if (hasPublicCurieInAddressing(record[key], key, depth + 1)) return true;
|
|
425
|
-
}
|
|
426
|
-
return false;
|
|
427
|
-
}
|
|
428
|
-
function rewritePublicAudience(value, parentKey, depth = 0) {
|
|
429
|
-
if (typeof value === "string" && parentKey != null && PUBLIC_ADDRESSING_FIELDS.has(parentKey) && (value === "as:Public" || value === "Public")) return _fedify_vocab.PUBLIC_COLLECTION.href;
|
|
430
|
-
if (depth >= MAX_TRAVERSAL_DEPTH) return value;
|
|
431
|
-
if (Array.isArray(value)) {
|
|
432
|
-
let changed = false;
|
|
433
|
-
const mapped = value.map((item) => {
|
|
434
|
-
const rewritten = rewritePublicAudience(item, parentKey, depth + 1);
|
|
435
|
-
if (rewritten !== item) changed = true;
|
|
436
|
-
return rewritten;
|
|
437
|
-
});
|
|
438
|
-
return changed ? mapped : value;
|
|
439
|
-
}
|
|
440
|
-
if (typeof value !== "object" || value == null) return value;
|
|
441
|
-
const record = value;
|
|
442
|
-
let changed = false;
|
|
443
|
-
const normalized = {};
|
|
444
|
-
for (const key of Object.keys(record)) {
|
|
445
|
-
const rewritten = key === "@context" ? record[key] : rewritePublicAudience(record[key], key, depth + 1);
|
|
446
|
-
if (rewritten !== record[key]) changed = true;
|
|
447
|
-
normalized[key] = rewritten;
|
|
448
|
-
}
|
|
449
|
-
return changed ? normalized : value;
|
|
450
|
-
}
|
|
451
|
-
/**
|
|
452
|
-
* Reports whether `value` carries an `@context` property anywhere inside
|
|
453
|
-
* its subtree (not counting the value itself). A nested `@context` can
|
|
454
|
-
* introduce a local term-definition scope that redefines `as:` or `Public`
|
|
455
|
-
* even when the top-level `@context` is safe, so the fast path must defer
|
|
456
|
-
* to the URDNA2015 equivalence check whenever one is present.
|
|
457
|
-
*/
|
|
458
|
-
function hasNestedContext(value, depth = 0) {
|
|
459
|
-
if (depth >= MAX_TRAVERSAL_DEPTH) return true;
|
|
460
|
-
if (Array.isArray(value)) return value.some((item) => hasNestedContext(item, depth + 1));
|
|
461
|
-
if (typeof value !== "object" || value == null) return false;
|
|
462
|
-
const record = value;
|
|
463
|
-
for (const key of Object.keys(record)) {
|
|
464
|
-
if (key === "@context") return true;
|
|
465
|
-
if (hasNestedContext(record[key], depth + 1)) return true;
|
|
466
|
-
}
|
|
467
|
-
return false;
|
|
468
|
-
}
|
|
469
|
-
/**
|
|
470
|
-
* Checks whether the `@context` of a JSON-LD document is guaranteed not
|
|
471
|
-
* to redefine the `as:` prefix or the bare `Public` term. Only documents
|
|
472
|
-
* whose `@context` is a string, or an array of strings, drawn from Fedify's
|
|
473
|
-
* preloaded context set AND including the ActivityStreams URL qualify,
|
|
474
|
-
* AND no nested subtree carries its own `@context` that might redefine
|
|
475
|
-
* those terms within a local scope. When all of that holds the rewrite
|
|
476
|
-
* is provably semantics-preserving and the URDNA2015 equivalence check
|
|
477
|
-
* can be skipped. Any other shape (unknown external URLs, inline
|
|
478
|
-
* objects at the top level, nested `@context` blocks) is treated as
|
|
479
|
-
* potentially unsafe.
|
|
480
|
-
*/
|
|
481
|
-
function hasKnownSafeContext(jsonLd) {
|
|
482
|
-
if (typeof jsonLd !== "object" || jsonLd == null) return false;
|
|
483
|
-
const record = jsonLd;
|
|
484
|
-
if (!Object.hasOwn(record, "@context")) return false;
|
|
485
|
-
const ctx = record["@context"];
|
|
486
|
-
const entries = typeof ctx === "string" ? [ctx] : Array.isArray(ctx) ? ctx : null;
|
|
487
|
-
if (entries == null || entries.length === 0) return false;
|
|
488
|
-
let hasAs = false;
|
|
489
|
-
for (const entry of entries) {
|
|
490
|
-
if (typeof entry !== "string") return false;
|
|
491
|
-
if (!KNOWN_SAFE_CONTEXT_URLS.has(entry)) return false;
|
|
492
|
-
if (entry === AS_CONTEXT_URL) hasAs = true;
|
|
493
|
-
}
|
|
494
|
-
if (!hasAs) return false;
|
|
495
|
-
for (const key of Object.keys(record)) {
|
|
496
|
-
if (key === "@context") continue;
|
|
497
|
-
if (hasNestedContext(record[key])) return false;
|
|
498
|
-
}
|
|
499
|
-
return true;
|
|
500
|
-
}
|
|
501
|
-
/**
|
|
502
|
-
* Rewrites the compact `as:Public` / `Public` CURIE appearing in activity
|
|
503
|
-
* addressing fields (`to`, `cc`, `bto`, `bcc`, `audience`) to the fully
|
|
504
|
-
* expanded `https://www.w3.org/ns/activitystreams#Public` URI.
|
|
505
|
-
*
|
|
506
|
-
* Several ActivityPub implementations, Lemmy among them, match these
|
|
507
|
-
* fields as plain URLs without running JSON-LD expansion, and silently
|
|
508
|
-
* drop activities whose public addressing appears in CURIE form. This
|
|
509
|
-
* helper works around that gap.
|
|
510
|
-
*
|
|
511
|
-
* For documents whose `@context` is drawn entirely from Fedify's
|
|
512
|
-
* preloaded context set and includes the ActivityStreams URL, the
|
|
513
|
-
* rewrite is applied directly: the content of every preloaded non-AS
|
|
514
|
-
* context is known not to redefine the `as:` prefix or the bare `Public`
|
|
515
|
-
* term, so the semantics are preserved by construction. Any other
|
|
516
|
-
* shape (an inline object, an unknown external URL, and so on) is
|
|
517
|
-
* treated as potentially unsafe and gated on a JSON-LD equivalence
|
|
518
|
-
* check; both forms are canonicalized with URDNA2015 and the resulting
|
|
519
|
-
* N-Quads are compared. When they differ, the original document is
|
|
520
|
-
* returned unchanged. Canonicalization failures also fall back to the
|
|
521
|
-
* original document.
|
|
522
|
-
*
|
|
523
|
-
* When no `contextLoader` is supplied the helper falls back to an
|
|
524
|
-
* internal loader that resolves only the URLs in Fedify's
|
|
525
|
-
* preloaded-contexts set and rejects every other URL without issuing a
|
|
526
|
-
* network request. That behaviour is deliberately narrower than
|
|
527
|
-
* `@fedify/vocab-runtime`'s `getDocumentLoader()`, which after its
|
|
528
|
-
* `validatePublicUrl` check will happily fetch non-preloaded URLs: the
|
|
529
|
-
* helper is reached from verification paths (`verifyProof()` /
|
|
530
|
-
* `verifyObject()`) that operate on inbound, potentially adversarial
|
|
531
|
-
* JSON-LD, and a default loader that fetches attacker-supplied
|
|
532
|
-
* `@context` URLs on the caller's behalf would be an SSRF vector.
|
|
533
|
-
* Canonicalization failures against the restricted loader fall back to
|
|
534
|
-
* the original document, same as any other canonicalization error.
|
|
535
|
-
* Callers that genuinely need the remote-fetch loader (for example
|
|
536
|
-
* applications that sign local JSON-LD against a custom vocabulary)
|
|
537
|
-
* should pass a `contextLoader` explicitly.
|
|
538
|
-
*
|
|
539
|
-
* Must be called before any signing step that canonicalizes the
|
|
540
|
-
* compact form byte-for-byte (for example, Object Integrity Proofs
|
|
541
|
-
* using the `eddsa-jcs-2022` cryptosuite), so the signed payload
|
|
542
|
-
* matches what is sent on the wire.
|
|
543
|
-
*/
|
|
544
|
-
async function normalizePublicAudience(jsonLd, contextLoader) {
|
|
545
|
-
if (!hasPublicCurieInAddressing(jsonLd)) return jsonLd;
|
|
546
|
-
const normalized = rewritePublicAudience(jsonLd);
|
|
547
|
-
if (hasKnownSafeContext(jsonLd)) return normalized;
|
|
548
|
-
const loader = contextLoader ?? preloadedOnlyDocumentLoader;
|
|
549
|
-
try {
|
|
550
|
-
const [before, after] = await Promise.all([_fedify_vocab_runtime_jsonld.default.canonize(jsonLd, {
|
|
551
|
-
format: "application/n-quads",
|
|
552
|
-
documentLoader: loader
|
|
553
|
-
}), _fedify_vocab_runtime_jsonld.default.canonize(normalized, {
|
|
554
|
-
format: "application/n-quads",
|
|
555
|
-
documentLoader: loader
|
|
556
|
-
})]);
|
|
557
|
-
if (before === after) return normalized;
|
|
558
|
-
logger$1.warn("Expanding the public audience CURIE to its full URI would change the canonical form of the activity; sending the activity as is. This usually means the active JSON-LD context redefines the `as:` prefix or the bare `Public` term.");
|
|
559
|
-
} catch (error) {
|
|
560
|
-
logger$1.debug("Failed to verify public audience normalization equivalence via JSON-LD canonicalization; sending the activity as is.\n{error}", { error });
|
|
561
|
-
}
|
|
562
|
-
return jsonLd;
|
|
563
|
-
}
|
|
564
|
-
//#endregion
|
|
565
392
|
//#region src/sig/proof.ts
|
|
566
393
|
const logger = (0, _logtape_logtape.getLogger)([
|
|
567
394
|
"fedify",
|
|
@@ -610,12 +437,11 @@ function hasProofLike(jsonLd) {
|
|
|
610
437
|
async function createProof(object, privateKey, keyId, { contextLoader, context, created } = {}) {
|
|
611
438
|
require_http.validateCryptoKey(privateKey, "private");
|
|
612
439
|
if (privateKey.algorithm.name !== "Ed25519") throw new TypeError("Unsupported algorithm: " + privateKey.algorithm.name);
|
|
613
|
-
|
|
440
|
+
const compactMsg = await object.clone({ proofs: [] }).toJsonLd({
|
|
614
441
|
format: "compact",
|
|
615
442
|
contextLoader,
|
|
616
443
|
context
|
|
617
444
|
});
|
|
618
|
-
compactMsg = await normalizePublicAudience(compactMsg, contextLoader);
|
|
619
445
|
const msgCanon = (0, json_canon.default)(compactMsg);
|
|
620
446
|
const encoder = new TextEncoder();
|
|
621
447
|
const msgBytes = encoder.encode(msgCanon);
|
|
@@ -710,25 +536,27 @@ async function verifyProof(jsonLd, proof, options = {}) {
|
|
|
710
536
|
});
|
|
711
537
|
}
|
|
712
538
|
async function verifyProofInternal(jsonLd, proof, options) {
|
|
713
|
-
if (typeof jsonLd !== "object" ||
|
|
539
|
+
if (typeof jsonLd !== "object" || proof.cryptosuite !== "eddsa-jcs-2022" || proof.verificationMethodId == null || proof.proofPurpose !== "assertionMethod" || proof.proofValue == null || proof.created == null) return null;
|
|
714
540
|
const publicKeyPromise = require_http.fetchKey(proof.verificationMethodId, _fedify_vocab.Multikey, options);
|
|
715
|
-
const
|
|
541
|
+
const proofCanon = (0, json_canon.default)({
|
|
716
542
|
"@context": jsonLd["@context"],
|
|
717
543
|
type: "DataIntegrityProof",
|
|
718
544
|
cryptosuite: proof.cryptosuite,
|
|
719
545
|
verificationMethod: proof.verificationMethodId.href,
|
|
720
546
|
proofPurpose: proof.proofPurpose,
|
|
721
547
|
created: proof.created.toString()
|
|
722
|
-
};
|
|
548
|
+
});
|
|
723
549
|
const encoder = new TextEncoder();
|
|
724
|
-
const proofBytes = encoder.encode(
|
|
550
|
+
const proofBytes = encoder.encode(proofCanon);
|
|
725
551
|
const proofDigest = await crypto.subtle.digest("SHA-256", proofBytes);
|
|
726
552
|
const msg = { ...jsonLd };
|
|
727
553
|
if ("proof" in msg) delete msg.proof;
|
|
728
|
-
|
|
729
|
-
const
|
|
730
|
-
const
|
|
731
|
-
|
|
554
|
+
const msgCanon = (0, json_canon.default)(msg);
|
|
555
|
+
const msgBytes = encoder.encode(msgCanon);
|
|
556
|
+
const msgDigest = await crypto.subtle.digest("SHA-256", msgBytes);
|
|
557
|
+
const digest = new Uint8Array(proofDigest.byteLength + msgDigest.byteLength);
|
|
558
|
+
digest.set(new Uint8Array(proofDigest), 0);
|
|
559
|
+
digest.set(new Uint8Array(msgDigest), proofDigest.byteLength);
|
|
732
560
|
let fetchedKey;
|
|
733
561
|
try {
|
|
734
562
|
fetchedKey = await publicKeyPromise;
|
|
@@ -757,7 +585,7 @@ async function verifyProofInternal(jsonLd, proof, options) {
|
|
|
757
585
|
return await verifyProof(jsonLd, proof, {
|
|
758
586
|
...options,
|
|
759
587
|
keyCache: {
|
|
760
|
-
get: () => Promise.resolve(
|
|
588
|
+
get: () => Promise.resolve(null),
|
|
761
589
|
set: async (keyId, key) => await options.keyCache?.set(keyId, key)
|
|
762
590
|
}
|
|
763
591
|
});
|
|
@@ -768,32 +596,27 @@ async function verifyProofInternal(jsonLd, proof, options) {
|
|
|
768
596
|
});
|
|
769
597
|
return null;
|
|
770
598
|
}
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
599
|
+
if (!await crypto.subtle.verify("Ed25519", publicKey.publicKey, proof.proofValue.slice(), digest)) {
|
|
600
|
+
if (fetchedKey.cached) {
|
|
601
|
+
logger.debug("Failed to verify the proof with the cached key {keyId}; retrying with the freshly fetched key...", {
|
|
602
|
+
keyId: proof.verificationMethodId.href,
|
|
603
|
+
proof
|
|
604
|
+
});
|
|
605
|
+
return await verifyProof(jsonLd, proof, {
|
|
606
|
+
...options,
|
|
607
|
+
keyCache: {
|
|
608
|
+
get: () => Promise.resolve(void 0),
|
|
609
|
+
set: async (keyId, key) => await options.keyCache?.set(keyId, key)
|
|
610
|
+
}
|
|
611
|
+
});
|
|
612
|
+
}
|
|
613
|
+
logger.debug("Failed to verify the proof with the fetched key {keyId}:\n{proof}", {
|
|
781
614
|
keyId: proof.verificationMethodId.href,
|
|
782
615
|
proof
|
|
783
616
|
});
|
|
784
|
-
return
|
|
785
|
-
...options,
|
|
786
|
-
keyCache: {
|
|
787
|
-
get: () => Promise.resolve(void 0),
|
|
788
|
-
set: async (keyId, key) => await options.keyCache?.set(keyId, key)
|
|
789
|
-
}
|
|
790
|
-
});
|
|
617
|
+
return null;
|
|
791
618
|
}
|
|
792
|
-
|
|
793
|
-
keyId: proof.verificationMethodId.href,
|
|
794
|
-
proof
|
|
795
|
-
});
|
|
796
|
-
return null;
|
|
619
|
+
return publicKey;
|
|
797
620
|
}
|
|
798
621
|
/**
|
|
799
622
|
* Verifies the given object. It will verify all the proofs in the object,
|
|
@@ -882,12 +705,6 @@ Object.defineProperty(exports, "hasSignatureLike", {
|
|
|
882
705
|
return hasSignatureLike;
|
|
883
706
|
}
|
|
884
707
|
});
|
|
885
|
-
Object.defineProperty(exports, "normalizePublicAudience", {
|
|
886
|
-
enumerable: true,
|
|
887
|
-
get: function() {
|
|
888
|
-
return normalizePublicAudience;
|
|
889
|
-
}
|
|
890
|
-
});
|
|
891
708
|
Object.defineProperty(exports, "signJsonLd", {
|
|
892
709
|
enumerable: true,
|
|
893
710
|
get: function() {
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { Temporal } from "@js-temporal/polyfill";
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { n as version, t as name } from "./deno-
|
|
5
|
-
import { n as fetchKey, o as validateCryptoKey } from "./key-
|
|
6
|
-
import { t as normalizePublicAudience } from "./public-audience-5WWE-JTr.mjs";
|
|
4
|
+
import { n as version, t as name } from "./deno-_fgAC2zJ.mjs";
|
|
5
|
+
import { n as fetchKey, o as validateCryptoKey } from "./key-Ce0SDXK2.mjs";
|
|
7
6
|
import { Activity, DataIntegrityProof, Multikey, getTypeId } from "@fedify/vocab";
|
|
8
7
|
import { SpanStatusCode, trace } from "@opentelemetry/api";
|
|
9
8
|
import { getLogger } from "@logtape/logtape";
|
|
@@ -57,12 +56,11 @@ function hasProofLike(jsonLd) {
|
|
|
57
56
|
async function createProof(object, privateKey, keyId, { contextLoader, context, created } = {}) {
|
|
58
57
|
validateCryptoKey(privateKey, "private");
|
|
59
58
|
if (privateKey.algorithm.name !== "Ed25519") throw new TypeError("Unsupported algorithm: " + privateKey.algorithm.name);
|
|
60
|
-
|
|
59
|
+
const compactMsg = await object.clone({ proofs: [] }).toJsonLd({
|
|
61
60
|
format: "compact",
|
|
62
61
|
contextLoader,
|
|
63
62
|
context
|
|
64
63
|
});
|
|
65
|
-
compactMsg = await normalizePublicAudience(compactMsg, contextLoader);
|
|
66
64
|
const msgCanon = serialize(compactMsg);
|
|
67
65
|
const encoder = new TextEncoder();
|
|
68
66
|
const msgBytes = encoder.encode(msgCanon);
|
|
@@ -157,25 +155,27 @@ async function verifyProof(jsonLd, proof, options = {}) {
|
|
|
157
155
|
});
|
|
158
156
|
}
|
|
159
157
|
async function verifyProofInternal(jsonLd, proof, options) {
|
|
160
|
-
if (typeof jsonLd !== "object" ||
|
|
158
|
+
if (typeof jsonLd !== "object" || proof.cryptosuite !== "eddsa-jcs-2022" || proof.verificationMethodId == null || proof.proofPurpose !== "assertionMethod" || proof.proofValue == null || proof.created == null) return null;
|
|
161
159
|
const publicKeyPromise = fetchKey(proof.verificationMethodId, Multikey, options);
|
|
162
|
-
const
|
|
160
|
+
const proofCanon = serialize({
|
|
163
161
|
"@context": jsonLd["@context"],
|
|
164
162
|
type: "DataIntegrityProof",
|
|
165
163
|
cryptosuite: proof.cryptosuite,
|
|
166
164
|
verificationMethod: proof.verificationMethodId.href,
|
|
167
165
|
proofPurpose: proof.proofPurpose,
|
|
168
166
|
created: proof.created.toString()
|
|
169
|
-
};
|
|
167
|
+
});
|
|
170
168
|
const encoder = new TextEncoder();
|
|
171
|
-
const proofBytes = encoder.encode(
|
|
169
|
+
const proofBytes = encoder.encode(proofCanon);
|
|
172
170
|
const proofDigest = await crypto.subtle.digest("SHA-256", proofBytes);
|
|
173
171
|
const msg = { ...jsonLd };
|
|
174
172
|
if ("proof" in msg) delete msg.proof;
|
|
175
|
-
|
|
176
|
-
const
|
|
177
|
-
const
|
|
178
|
-
|
|
173
|
+
const msgCanon = serialize(msg);
|
|
174
|
+
const msgBytes = encoder.encode(msgCanon);
|
|
175
|
+
const msgDigest = await crypto.subtle.digest("SHA-256", msgBytes);
|
|
176
|
+
const digest = new Uint8Array(proofDigest.byteLength + msgDigest.byteLength);
|
|
177
|
+
digest.set(new Uint8Array(proofDigest), 0);
|
|
178
|
+
digest.set(new Uint8Array(msgDigest), proofDigest.byteLength);
|
|
179
179
|
let fetchedKey;
|
|
180
180
|
try {
|
|
181
181
|
fetchedKey = await publicKeyPromise;
|
|
@@ -204,7 +204,7 @@ async function verifyProofInternal(jsonLd, proof, options) {
|
|
|
204
204
|
return await verifyProof(jsonLd, proof, {
|
|
205
205
|
...options,
|
|
206
206
|
keyCache: {
|
|
207
|
-
get: () => Promise.resolve(
|
|
207
|
+
get: () => Promise.resolve(null),
|
|
208
208
|
set: async (keyId, key) => await options.keyCache?.set(keyId, key)
|
|
209
209
|
}
|
|
210
210
|
});
|
|
@@ -215,32 +215,27 @@ async function verifyProofInternal(jsonLd, proof, options) {
|
|
|
215
215
|
});
|
|
216
216
|
return null;
|
|
217
217
|
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
218
|
+
if (!await crypto.subtle.verify("Ed25519", publicKey.publicKey, proof.proofValue.slice(), digest)) {
|
|
219
|
+
if (fetchedKey.cached) {
|
|
220
|
+
logger.debug("Failed to verify the proof with the cached key {keyId}; retrying with the freshly fetched key...", {
|
|
221
|
+
keyId: proof.verificationMethodId.href,
|
|
222
|
+
proof
|
|
223
|
+
});
|
|
224
|
+
return await verifyProof(jsonLd, proof, {
|
|
225
|
+
...options,
|
|
226
|
+
keyCache: {
|
|
227
|
+
get: () => Promise.resolve(void 0),
|
|
228
|
+
set: async (keyId, key) => await options.keyCache?.set(keyId, key)
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
logger.debug("Failed to verify the proof with the fetched key {keyId}:\n{proof}", {
|
|
228
233
|
keyId: proof.verificationMethodId.href,
|
|
229
234
|
proof
|
|
230
235
|
});
|
|
231
|
-
return
|
|
232
|
-
...options,
|
|
233
|
-
keyCache: {
|
|
234
|
-
get: () => Promise.resolve(void 0),
|
|
235
|
-
set: async (keyId, key) => await options.keyCache?.set(keyId, key)
|
|
236
|
-
}
|
|
237
|
-
});
|
|
236
|
+
return null;
|
|
238
237
|
}
|
|
239
|
-
|
|
240
|
-
keyId: proof.verificationMethodId.href,
|
|
241
|
-
proof
|
|
242
|
-
});
|
|
243
|
-
return null;
|
|
238
|
+
return publicKey;
|
|
244
239
|
}
|
|
245
240
|
/**
|
|
246
241
|
* Verifies the given object. It will verify all the proofs in the object,
|