@fedify/fedify 2.4.0-dev.2253 → 2.4.0-dev.2259

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 (110) hide show
  1. package/dist/{builder-DdUWFCwL.mjs → builder-CBNa1Uw2.mjs} +8 -2
  2. package/dist/compat/mod.d.cts +1 -1
  3. package/dist/compat/mod.d.ts +1 -1
  4. package/dist/compat/transformers.test.mjs +1 -1
  5. package/dist/{compound-proof-CcWDD5VB.mjs → compound-proof-CMPv4UK0.mjs} +20 -3
  6. package/dist/{context-CtI307_A.d.ts → context-7NyiqIcg.d.ts} +111 -2
  7. package/dist/{context-B6X-t8gI.d.cts → context-tsYPJ2Ew.d.cts} +111 -2
  8. package/dist/{deno-D9uhdIuD.mjs → deno-C8XaXmPB.mjs} +1 -1
  9. package/dist/{docloader-fbmPhCdS.mjs → docloader-CpdFLwAg.mjs} +2 -2
  10. package/dist/federation/builder.test.mjs +1 -1
  11. package/dist/federation/compound-fanout.test.mjs +3 -3
  12. package/dist/federation/handler-compound-proof.test.mjs +3 -3
  13. package/dist/federation/handler.test.mjs +76 -5
  14. package/dist/federation/hashlink-media.test.mjs +2 -2
  15. package/dist/federation/idempotency.test.mjs +2 -2
  16. package/dist/federation/inbox-report.test.d.mts +2 -0
  17. package/dist/federation/inbox-report.test.mjs +475 -0
  18. package/dist/federation/metrics.test.mjs +1 -1
  19. package/dist/federation/middleware.test.mjs +7 -7
  20. package/dist/federation/mod.cjs +1 -1
  21. package/dist/federation/mod.d.cts +4 -3
  22. package/dist/federation/mod.d.ts +4 -3
  23. package/dist/federation/mod.js +1 -1
  24. package/dist/federation/outgoing-proof.test.mjs +5 -5
  25. package/dist/federation/portable-actor.test.mjs +3 -3
  26. package/dist/federation/portable-chain.test.mjs +3 -3
  27. package/dist/federation/portable-collection.test.mjs +4 -4
  28. package/dist/federation/portable-delivery.test.mjs +2 -2
  29. package/dist/federation/portable-gateway-keys.test.mjs +4 -4
  30. package/dist/federation/portable-inbox.test.mjs +67 -6
  31. package/dist/federation/portable-parse-uri.test.mjs +1 -1
  32. package/dist/federation/portable-route-activity.test.mjs +2 -2
  33. package/dist/federation/portable.test.mjs +3 -3
  34. package/dist/federation/send.test.mjs +3 -3
  35. package/dist/federation/tasks/enqueue.test.mjs +1 -1
  36. package/dist/federation/tasks/tasks.test.mjs +2 -2
  37. package/dist/federation/temporal.test.mjs +1 -1
  38. package/dist/federation/webfinger.test.mjs +1 -1
  39. package/dist/{federation-B858-Ylk.cjs → federation-D6giSGUT.cjs} +524 -118
  40. package/dist/{http-CUyBaVsQ.mjs → http-BqSbUEiQ.mjs} +141 -98
  41. package/dist/{http-Bp0MKAK3.cjs → http-Cki-npuA.cjs} +456 -116
  42. package/dist/{http-BoGE-nk7.js → http-OMtKlbx1.js} +439 -117
  43. package/dist/{http-DGx0KOws.d.ts → key-C1nv7_jD.d.ts} +638 -229
  44. package/dist/{http-BrwKINQn.d.cts → key-DYxuyd-s.d.cts} +638 -229
  45. package/dist/{key-BlTaKABr.mjs → key-DecAtABm.mjs} +30 -3
  46. package/dist/{kv-cache-Dmqd7s2a.mjs → kv-cache-CWWlMv-s.mjs} +1 -1
  47. package/dist/{kv-cache-BnWemxH2.cjs → kv-cache-D73yVcE5.cjs} +1 -1
  48. package/dist/{kv-cache-DhMzUXEE.js → kv-cache-J0v3UbUn.js} +1 -1
  49. package/dist/{ld-Dx8r_qJU.mjs → ld-UsN-TIPh.mjs} +40 -5
  50. package/dist/{metrics-DFkZkLrO.mjs → metrics-DWCn4VXX.mjs} +2 -1
  51. package/dist/{middleware-DC018B4u.js → middleware-BqzfIlUO.js} +524 -118
  52. package/dist/{middleware-B0RRI88k.mjs → middleware-CkjwiEBd.mjs} +512 -127
  53. package/dist/{middleware-BNhF-Ayx.mjs → middleware-DHn2q0L1.mjs} +1 -1
  54. package/dist/{mod-C7_2j7VT.d.cts → mod-BojP2Bw3.d.cts} +1 -1
  55. package/dist/{mod-Cy9VNHVw.d.ts → mod-CavhAgLw.d.cts} +5 -253
  56. package/dist/{mod-DoTWIc7F.d.cts → mod-CtpF2BU5.d.ts} +5 -253
  57. package/dist/{mod-B8MI1mpi.d.ts → mod-DEZXwV6J.d.ts} +1 -1
  58. package/dist/{mod-DFL6IxYQ.d.cts → mod-Dw-nPxQh.d.cts} +1 -1
  59. package/dist/{mod-BhTaDR5H.d.ts → mod-Xj5P4s4d.d.ts} +1 -1
  60. package/dist/mod.cjs +4 -4
  61. package/dist/mod.d.cts +7 -7
  62. package/dist/mod.d.ts +7 -7
  63. package/dist/mod.js +4 -4
  64. package/dist/nodeinfo/handler.test.mjs +1 -1
  65. package/dist/{owner-B61jjp5K.mjs → owner-CEBn81LD.mjs} +3 -3
  66. package/dist/{portable-collection-DhEA_nWT.cjs → portable-collection-DqTUBKY7.cjs} +1 -1
  67. package/dist/{portable-collection-BnktjQ04.js → portable-collection-ZkUNjtb7.js} +1 -1
  68. package/dist/{portable-collection-CyBJDEzs.mjs → portable-collection-qFSYw4TG.mjs} +2 -2
  69. package/dist/{portable-key-CPN0QZSA.mjs → portable-key-LlMkP-vz.mjs} +1 -1
  70. package/dist/{proof-CZrjvoJ3.mjs → proof-BHRf_jMG.mjs} +142 -22
  71. package/dist/{send-enxOnmZo.mjs → send-DjG8DDU_.mjs} +3 -3
  72. package/dist/sig/compound-proof-discovery.test.mjs +1 -1
  73. package/dist/sig/compound-proof-producer.test.mjs +1 -1
  74. package/dist/sig/compound-proof-verification.test.mjs +19 -2
  75. package/dist/sig/compound-proof.test.mjs +2 -2
  76. package/dist/sig/http.test.mjs +2 -2
  77. package/dist/sig/key.test.mjs +1 -1
  78. package/dist/sig/ld.test.mjs +2 -2
  79. package/dist/sig/mitra-receive-interop.test.d.mts +2 -0
  80. package/dist/sig/mitra-receive-interop.test.mjs +260 -0
  81. package/dist/sig/mitra-send-interop.test.d.mts +2 -0
  82. package/dist/sig/mitra-send-interop.test.mjs +461 -0
  83. package/dist/sig/mod.cjs +2 -2
  84. package/dist/sig/mod.d.cts +2 -2
  85. package/dist/sig/mod.d.ts +2 -2
  86. package/dist/sig/mod.js +2 -2
  87. package/dist/sig/owner.test.mjs +1 -1
  88. package/dist/sig/portable-collection.test.mjs +1 -1
  89. package/dist/sig/portable-interop.test.d.mts +2 -0
  90. package/dist/sig/portable-interop.test.mjs +156 -0
  91. package/dist/sig/portable-key.test.mjs +6 -6
  92. package/dist/sig/proof.test.mjs +161 -3
  93. package/dist/sig/tootik-request-interop.test.d.mts +2 -0
  94. package/dist/sig/tootik-request-interop.test.mjs +190 -0
  95. package/dist/sig/tootik-send-interop.test.d.mts +2 -0
  96. package/dist/sig/tootik-send-interop.test.mjs +331 -0
  97. package/dist/sig/verification.test.d.mts +2 -0
  98. package/dist/sig/verification.test.mjs +310 -0
  99. package/dist/{temporal-CBVv0xRB.mjs → temporal-BRFH_dte.mjs} +1 -1
  100. package/dist/testing/kv.test.mjs +1 -1
  101. package/dist/testing/mod.d.mts +315 -28
  102. package/dist/utils/docloader.test.mjs +2 -2
  103. package/dist/utils/kv-cache.test.mjs +1 -1
  104. package/dist/utils/mod.cjs +1 -1
  105. package/dist/utils/mod.d.cts +1 -1
  106. package/dist/utils/mod.d.ts +1 -1
  107. package/dist/utils/mod.js +1 -1
  108. package/dist/verification-C3954hQh.mjs +5 -0
  109. package/dist/verification-Dpfcw8ml.mjs +105 -0
  110. package/package.json +6 -6
@@ -2,8 +2,9 @@ import { Temporal } from "temporal-polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
4
  import { c as isPortableActorDocument, d as isPortableUri, l as isPortableId, m as parseKeyIdString, s as isCompatibleKeyId } from "./portable-key-id-Ca30-hOa.mjs";
5
- import { n as version, t as name } from "./deno-D9uhdIuD.mjs";
6
- import { _ as recordKeyLookup, n as getDurationMs, t as classifyFetchError } from "./metrics-DFkZkLrO.mjs";
5
+ import { a as verificationObservation } from "./verification-Dpfcw8ml.mjs";
6
+ import { n as version, t as name } from "./deno-C8XaXmPB.mjs";
7
+ import { _ as recordKeyLookup, n as getDurationMs, t as classifyFetchError } from "./metrics-DWCn4VXX.mjs";
7
8
  import { n as attachKeyOwnerEvidence, t as MAX_PORTABLE_KEY_TTL } from "./key-owner-evidence-APB6NpSk.mjs";
8
9
  import { getLogger } from "@logtape/logtape";
9
10
  import { CryptographicKey, Multikey, Object as Object$1, isActor } from "@fedify/vocab";
@@ -898,12 +899,38 @@ async function fetchPortableActorKey(cacheKey, cls, options, onCachedUnavailable
898
899
  };
899
900
  }
900
901
  async function fetchKeyInternal(keyId, cls, options = {}) {
901
- return await fetchKeyWithResult(typeof keyId === "string" ? parseKeyIdOrThrow(keyId) : keyId, cls, options, (_cacheKey, _keyId, _keyCache, _logger) => {
902
+ return await fetchKeyWithResult(typeof keyId === "string" ? parseKeyIdOrThrow(keyId) : keyId, cls, options, async (_cacheKey, _keyId, _keyCache, _logger) => {
903
+ const check = options[verificationObservation]?.check;
904
+ if (check != null) try {
905
+ const result = await _keyCache?.getFetchError?.(_cacheKey);
906
+ if (result != null) check.reason = {
907
+ type: "keyFetchError",
908
+ keyId: new URL(_cacheKey.href),
909
+ result
910
+ };
911
+ } catch {}
902
912
  return {
903
913
  key: null,
904
914
  cached: true
905
915
  };
906
916
  }, async (error, cacheKey, keyId, keyCache, logger) => {
917
+ const check = options[verificationObservation]?.check;
918
+ if (check != null) {
919
+ let result;
920
+ try {
921
+ result = error instanceof FetchError && error.response != null ? {
922
+ status: error.response.status,
923
+ response: error.response.clone()
924
+ } : { error: error instanceof Error ? error : new Error(String(error)) };
925
+ } catch {
926
+ result = { error: error instanceof Error ? error : /* @__PURE__ */ new Error() };
927
+ }
928
+ check.reason = {
929
+ type: "keyFetchError",
930
+ keyId: new URL(cacheKey.href),
931
+ result
932
+ };
933
+ }
907
934
  logger.debug("Failed to fetch key {keyId}.", {
908
935
  keyId,
909
936
  error
@@ -1,7 +1,7 @@
1
1
  import { Temporal } from "temporal-polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { p as recordDocumentCache } from "./metrics-DFkZkLrO.mjs";
4
+ import { p as recordDocumentCache } from "./metrics-DWCn4VXX.mjs";
5
5
  import { getLogger } from "@logtape/logtape";
6
6
  import { preloadedContexts } from "@fedify/vocab-runtime";
7
7
  //#region src/utils/kv-cache.ts
@@ -1,5 +1,5 @@
1
1
  const { URLPattern } = require("urlpattern-polyfill");
2
- const require_http = require("./http-Bp0MKAK3.cjs");
2
+ const require_http = require("./http-Cki-npuA.cjs");
3
3
  let _logtape_logtape = require("@logtape/logtape");
4
4
  let _fedify_vocab_runtime = require("@fedify/vocab-runtime");
5
5
  let es_toolkit = require("es-toolkit");
@@ -1,6 +1,6 @@
1
1
  import { Temporal } from "temporal-polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
- import { G as validateCryptoKey, ot as recordDocumentCache, t as doubleKnock } from "./http-BoGE-nk7.js";
3
+ import { G as validateCryptoKey, ot as recordDocumentCache, t as doubleKnock } from "./http-OMtKlbx1.js";
4
4
  import { getLogger } from "@logtape/logtape";
5
5
  import { FetchError, UrlError, createActivityPubRequest, getRemoteDocument, logRequest, preloadedContexts, resolveDocumentLoaderTimeout, validatePublicUrl, withDocumentLoaderTimeout } from "@fedify/vocab-runtime";
6
6
  import { curry } from "es-toolkit";
@@ -1,9 +1,10 @@
1
1
  import "temporal-polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { n as version, t as name } from "./deno-D9uhdIuD.mjs";
5
- import { n as getDurationMs, r as getFederationMetrics, s as measureSignatureKeyFetch } from "./metrics-DFkZkLrO.mjs";
6
- import { c as validateCryptoKey, i as fetchKey, t as bypassKeyCacheReads } from "./key-BlTaKABr.mjs";
4
+ import { a as verificationObservation, i as triedKey, n as observeCheck, t as observeAttempt } from "./verification-Dpfcw8ml.mjs";
5
+ import { n as version, t as name } from "./deno-C8XaXmPB.mjs";
6
+ import { n as getDurationMs, r as getFederationMetrics, s as measureSignatureKeyFetch } from "./metrics-DWCn4VXX.mjs";
7
+ import { c as validateCryptoKey, i as fetchKey, t as bypassKeyCacheReads } from "./key-DecAtABm.mjs";
7
8
  import { getLogger } from "@logtape/logtape";
8
9
  import { Activity, CryptographicKey, Object as Object$1, getTypeId } from "@fedify/vocab";
9
10
  import { SpanStatusCode, trace } from "@opentelemetry/api";
@@ -450,6 +451,13 @@ function detachSignature(jsonLd) {
450
451
  */
451
452
  async function verifySignature(jsonLd, options = {}) {
452
453
  if (!hasSignature(jsonLd)) return null;
454
+ if (options[verificationObservation]?.attempt != null && options[verificationObservation]?.check == null) {
455
+ const declared = getLdSignatureObject(jsonLd)?.creator;
456
+ return await observeCheck(options, { mechanism: "linkedData" }, typeof declared === "string" ? declared : null, (observation) => verifySignature(jsonLd, {
457
+ ...options,
458
+ [verificationObservation]: observation
459
+ }));
460
+ }
453
461
  const sig = jsonLd.signature;
454
462
  let signature;
455
463
  try {
@@ -495,6 +503,7 @@ async function verifySignature(jsonLd, options = {}) {
495
503
  const encoder = new TextEncoder();
496
504
  const message = sigOptsHash + docHash;
497
505
  const messageBytes = encoder.encode(message);
506
+ triedKey(options, key);
498
507
  if (await crypto.subtle.verify("RSASSA-PKCS1-v1_5", key.publicKey, signature.slice(), messageBytes)) return key;
499
508
  if (cached) {
500
509
  logger.debug("Failed to verify with the cached key {keyId}; signature {signatureValue} is invalid. Retrying with the freshly fetched key...", {
@@ -506,6 +515,7 @@ async function verifySignature(jsonLd, options = {}) {
506
515
  keyCache: bypassKeyCacheReads(options.keyCache)
507
516
  }));
508
517
  if (key == null) return null;
518
+ triedKey(options, key);
509
519
  return await crypto.subtle.verify("RSASSA-PKCS1-v1_5", key.publicKey, signature.slice(), messageBytes) ? key : null;
510
520
  }
511
521
  logger.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}", {
@@ -559,6 +569,14 @@ async function verifyCompactJsonLd(jsonLd, options = {}) {
559
569
  return await verifyJsonLdInternal(jsonLd, options, false);
560
570
  }
561
571
  async function verifyJsonLdInternal(jsonLd, options, compact) {
572
+ if (options[verificationObservation]?.attempt == null) return await observeAttempt({
573
+ ...options,
574
+ [verificationObservation]: options[verificationObservation] ?? { attempts: [] }
575
+ }, "linkedData", (observation) => verifyJsonLdInternal(jsonLd, {
576
+ ...options,
577
+ [verificationObservation]: observation
578
+ }, compact), (value) => value);
579
+ const observation = options[verificationObservation];
562
580
  return await (options.tracerProvider ?? trace.getTracerProvider()).getTracer(name, version).startActiveSpan("ld_signatures.verify", async (span) => {
563
581
  const start = performance.now();
564
582
  let verified = false;
@@ -571,6 +589,8 @@ async function verifyJsonLdInternal(jsonLd, options, compact) {
571
589
  } : options;
572
590
  const compacted = compact ? hasSignature(jsonLd) ? await compactJsonLd(jsonLd, options.contextLoader) : jsonLd : jsonLd;
573
591
  const object = await Object$1.fromJsonLd(compacted, verificationOptions);
592
+ observation?.parsedObject?.(object);
593
+ if (observation?.subject != null) observation.subject.id = object.id == null ? null : new URL(object.id.href);
574
594
  if (object.id != null) span.setAttribute("activitypub.object.id", object.id.href);
575
595
  span.setAttribute("activitypub.object.type", getTypeId(object).href);
576
596
  const sig = getLdSignatureObject(jsonLd);
@@ -585,13 +605,21 @@ async function verifyJsonLdInternal(jsonLd, options, compact) {
585
605
  const attributions = new Set(object.attributionIds.map((uri) => uri.href));
586
606
  if (object instanceof Activity) for (const uri of object.actorIds) attributions.add(uri.href);
587
607
  const key = await verifySignature(compacted, verificationOptions);
588
- if (key == null) return false;
608
+ if (key == null) {
609
+ if (observation?.attempt != null && !hasLdSignatureProperty(jsonLd)) observation.attempt.reason = { type: "noSignature" };
610
+ return false;
611
+ }
589
612
  if (key.ownerId == null) {
613
+ if (observation?.attempt != null) observation.attempt.reason = { type: "missingOwner" };
590
614
  logger.debug("Key {keyId} has no owner.", { keyId: key.id?.href });
591
615
  return false;
592
616
  }
593
617
  attributions.delete(key.ownerId.href);
594
618
  if (attributions.size > 0) {
619
+ if (observation?.attempt != null) observation.attempt.reason = {
620
+ type: "uncoveredAttribution",
621
+ attributionIds: [...attributions].map((id) => new URL(id))
622
+ };
595
623
  logger.debug("Some attributions are not authenticated by the Linked Data Signatures: {attributions}.", { attributions: [...attributions] });
596
624
  return false;
597
625
  }
@@ -605,8 +633,15 @@ async function verifyJsonLdInternal(jsonLd, options, compact) {
605
633
  });
606
634
  throw error;
607
635
  } finally {
636
+ if (observation?.attempt?.reason != null) {
637
+ span.setAttribute("activitypub.verification.failure_reason", observation.attempt.reason.type);
638
+ span.setStatus({ code: SpanStatusCode.ERROR });
639
+ }
608
640
  const classified = threw ? "error" : verified ? "verified" : hasLdSignatureProperty(jsonLd) ? "rejected" : "missing";
609
- getFederationMetrics(options.meterProvider).recordSignatureVerificationDuration(getDurationMs(start), "linked_data", classified, { ldType: signatureType });
641
+ getFederationMetrics(options.meterProvider).recordSignatureVerificationDuration(getDurationMs(start), "linked_data", classified, {
642
+ ldType: signatureType,
643
+ verificationFailureReason: verified || threw ? void 0 : observation?.attempt?.reason?.type ?? (hasLdSignatureProperty(jsonLd) ? "signatureVerificationFailed" : "noSignature")
644
+ });
610
645
  span.end();
611
646
  }
612
647
  });
@@ -1,7 +1,7 @@
1
1
  import "temporal-polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { n as version, t as name } from "./deno-D9uhdIuD.mjs";
4
+ import { n as version, t as name } from "./deno-C8XaXmPB.mjs";
5
5
  import { metrics } from "@opentelemetry/api";
6
6
  import { FetchError } from "@fedify/vocab-runtime";
7
7
  //#region src/federation/metrics.ts
@@ -302,6 +302,7 @@ var FederationMetrics = class {
302
302
  };
303
303
  if (extra.algorithm != null) attributes["http_signatures.algorithm"] = extra.algorithm;
304
304
  if (extra.failureReason != null) attributes["http_signatures.failure_reason"] = extra.failureReason;
305
+ if (extra.verificationFailureReason != null) attributes["activitypub.verification.failure_reason"] = extra.verificationFailureReason;
305
306
  if (extra.ldType != null) attributes["ld_signatures.type"] = extra.ldType;
306
307
  if (extra.cryptosuite != null) attributes["object_integrity_proofs.cryptosuite"] = extra.cryptosuite;
307
308
  this.signatureVerificationDuration.record(durationMs, attributes);