@fedify/fedify 2.4.0-pr.934.40 → 2.4.0

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 (244) hide show
  1. package/README.md +48 -40
  2. package/dist/{assert-CJ1KXcvv.mjs → assert-D1Eafmd_.mjs} +1 -1
  3. package/dist/{assert_equals-BV7oLMxm.mjs → assert_equals-Z6IcEbWU.mjs} +2 -28
  4. package/dist/assert_exists-cffSpJ7X.mjs +28 -0
  5. package/dist/assert_false-CPdRnc3E.mjs +23 -0
  6. package/dist/assert_greater_or_equal-BlafOF4-.mjs +31 -0
  7. package/dist/{assert_instance_of-Q9KTBnrf.mjs → assert_instance_of-mrXWWNY-.mjs} +1 -1
  8. package/dist/{assert_not_equals-EPJPoxuf.mjs → assert_not_equals-CpPK2t89.mjs} +2 -1
  9. package/dist/assert_rejects-CTptdYck.mjs +39 -0
  10. package/dist/{assert_strict_equals-Ec20AUwa.mjs → assert_strict_equals-CYvBmkpC.mjs} +2 -1
  11. package/dist/{assert_throws-NiFfqbnH.mjs → assert_throws-BYITOvPO.mjs} +2 -1
  12. package/dist/assertion_error-B-cx0fFA.mjs +31 -0
  13. package/dist/audience-CHQ-FlLD.mjs +95 -0
  14. package/dist/{builder-BBPwtB2v.mjs → builder-lJDh222H.mjs} +169 -14
  15. package/dist/{circuit-breaker-CBGyz5F7.mjs → circuit-breaker-XJ53md4S.mjs} +224 -17
  16. package/dist/circuit-breaker-test-utils-DW6YC_Pe.mjs +14 -0
  17. package/dist/{client-CjF5IYQS.mjs → client-CEnNz8O7.mjs} +144 -8
  18. package/dist/{codec-BBga-FWI.mjs → codec-C6rTrpIp.mjs} +26 -3
  19. package/dist/{collection-BIhlldqK.mjs → collection-CnnP1UAv.mjs} +1 -1
  20. package/dist/compat/mod.cjs +1 -1
  21. package/dist/compat/mod.d.cts +1 -1
  22. package/dist/compat/mod.d.ts +1 -1
  23. package/dist/compat/mod.js +1 -1
  24. package/dist/compat/outgoing-jsonld.test.mjs +71 -3
  25. package/dist/compat/public-audience.test.mjs +14 -5
  26. package/dist/compat/secured-document.test.d.mts +2 -0
  27. package/dist/compat/secured-document.test.mjs +58 -0
  28. package/dist/compat/transformers.test.mjs +5 -5
  29. package/dist/compound-proof-zAjqsHiN.mjs +989 -0
  30. package/dist/{context-Cjnr0ig1.d.ts → context-7NyiqIcg.d.ts} +1600 -25
  31. package/dist/{context-BJXxPElm.mjs → context-8Tu9kea0.mjs} +21 -63
  32. package/dist/{context-C05Rgxmu.d.cts → context-tsYPJ2Ew.d.cts} +1600 -25
  33. package/dist/{deno-D3c0o_N0.mjs → deno-D8wr4ikF.mjs} +1 -1
  34. package/dist/dist-DJQM4u7i.mjs +189 -0
  35. package/dist/docloader-TCvsU9vF.mjs +87 -0
  36. package/dist/{esm-yYQfPhIY.mjs → esm-BHXXx4Wx.mjs} +13 -6
  37. package/dist/federation/audience.test.d.mts +2 -0
  38. package/dist/federation/audience.test.mjs +130 -0
  39. package/dist/federation/builder.test.mjs +54 -5
  40. package/dist/federation/circuit-breaker.test.mjs +838 -7
  41. package/dist/federation/collection.test.mjs +3 -3
  42. package/dist/federation/compound-fanout.test.d.mts +2 -0
  43. package/dist/federation/compound-fanout.test.mjs +228 -0
  44. package/dist/federation/handler-compound-proof.test.d.mts +2 -0
  45. package/dist/federation/handler-compound-proof.test.mjs +384 -0
  46. package/dist/federation/handler.test.mjs +387 -15
  47. package/dist/federation/hashlink-media.test.d.mts +2 -0
  48. package/dist/federation/hashlink-media.test.mjs +422 -0
  49. package/dist/federation/idempotency.test.mjs +6 -6
  50. package/dist/federation/inbox-report.test.d.mts +2 -0
  51. package/dist/federation/inbox-report.test.mjs +475 -0
  52. package/dist/federation/inbox.test.mjs +3 -3
  53. package/dist/federation/keycache.test.mjs +215 -14
  54. package/dist/federation/kv.test.mjs +3 -3
  55. package/dist/federation/metrics.test.mjs +5 -5
  56. package/dist/federation/middleware.test.mjs +967 -35
  57. package/dist/federation/mod.cjs +18 -540
  58. package/dist/federation/mod.d.cts +5 -5
  59. package/dist/federation/mod.d.ts +5 -5
  60. package/dist/federation/mod.js +1 -1
  61. package/dist/federation/mq.test.mjs +104 -47
  62. package/dist/federation/negotiation.test.mjs +4 -4
  63. package/dist/federation/outgoing-proof.test.d.mts +2 -0
  64. package/dist/federation/outgoing-proof.test.mjs +931 -0
  65. package/dist/federation/portable-actor.test.d.mts +2 -0
  66. package/dist/federation/portable-actor.test.mjs +496 -0
  67. package/dist/federation/portable-chain.test.d.mts +2 -0
  68. package/dist/federation/portable-chain.test.mjs +370 -0
  69. package/dist/federation/portable-collection.test.d.mts +2 -0
  70. package/dist/federation/portable-collection.test.mjs +832 -0
  71. package/dist/federation/portable-delivery.test.d.mts +2 -0
  72. package/dist/federation/portable-delivery.test.mjs +746 -0
  73. package/dist/federation/portable-gateway-keys.test.d.mts +2 -0
  74. package/dist/federation/portable-gateway-keys.test.mjs +686 -0
  75. package/dist/federation/portable-inbox.test.d.mts +2 -0
  76. package/dist/federation/portable-inbox.test.mjs +1535 -0
  77. package/dist/federation/portable-parse-uri.test.d.mts +2 -0
  78. package/dist/federation/portable-parse-uri.test.mjs +348 -0
  79. package/dist/federation/portable-route-activity.test.d.mts +2 -0
  80. package/dist/federation/portable-route-activity.test.mjs +259 -0
  81. package/dist/federation/portable.test.d.mts +2 -0
  82. package/dist/federation/portable.test.mjs +1072 -0
  83. package/dist/federation/retry.test.mjs +4 -3
  84. package/dist/federation/router.test.mjs +9 -159
  85. package/dist/federation/send.test.mjs +245 -27
  86. package/dist/federation/tasks/codec.test.mjs +4 -4
  87. package/dist/federation/tasks/enqueue.test.mjs +5 -4
  88. package/dist/federation/tasks/tasks.test.mjs +7 -6
  89. package/dist/federation/temporal.test.mjs +4 -4
  90. package/dist/federation/webfinger.test.mjs +275 -12
  91. package/dist/{middleware-BW7WQltk.cjs → federation-Dfl-i7Jt.cjs} +6098 -895
  92. package/dist/{http-Dm0JAUa_.mjs → http-BAgKAAGY.mjs} +397 -168
  93. package/dist/http-CYO4wjB5.cjs +10630 -0
  94. package/dist/http-RW_i_Nkq.js +6527 -0
  95. package/dist/key-C1nv7_jD.d.ts +1125 -0
  96. package/dist/key-D979vduq.mjs +951 -0
  97. package/dist/key-DYxuyd-s.d.cts +1125 -0
  98. package/dist/key-owner-evidence-APB6NpSk.mjs +108 -0
  99. package/dist/keycache-Da8A8mZa.mjs +200 -0
  100. package/dist/{kv-D6hNiMTK.d.ts → kv-B2mzK5tl.d.cts} +3 -2
  101. package/dist/{kv-gJ8LYbxX.d.cts → kv-B2mzK5tl.d.ts} +3 -2
  102. package/dist/kv-DBRWVx3Q.mjs +104 -0
  103. package/dist/{kv-cache-BxUZRBC2.js → kv-cache-Cqfdytdd.js} +54 -16
  104. package/dist/{kv-cache-B7H7lZ84.mjs → kv-cache-Gh05Xv-P.mjs} +1 -1
  105. package/dist/{kv-cache-D-hbjJAD.cjs → kv-cache-zd0dNGxi.cjs} +55 -19
  106. package/dist/{ld-DAPAVL_7.mjs → ld-wmqC-95l.mjs} +44 -12
  107. package/dist/map-local-context-conflict-DOYEEJ3u.mjs +204 -0
  108. package/dist/map-local-create-note-B0SeXJms.mjs +214 -0
  109. package/dist/{metrics-BMaatuZi.mjs → metrics-DPdi_XK7.mjs} +3 -2
  110. package/dist/metrics-DVKYY6K1.d.cts +36 -0
  111. package/dist/metrics-DoRtI0qU.d.ts +36 -0
  112. package/dist/{middleware-O2LHXFEk.mjs → middleware-CqQ5Qahj.mjs} +3155 -269
  113. package/dist/{middleware-CfZR_riY.js → middleware-DbCI_eni.js} +5527 -865
  114. package/dist/{middleware-DfPBAh9L.mjs → middleware-DjEMIAP5.mjs} +1 -1
  115. package/dist/{mod-DdONo-ep.d.cts → mod-BojP2Bw3.d.cts} +1 -1
  116. package/dist/mod-CavhAgLw.d.cts +320 -0
  117. package/dist/mod-CtpF2BU5.d.ts +320 -0
  118. package/dist/{mod-CNef4in0.d.ts → mod-DEZXwV6J.d.ts} +9 -3
  119. package/dist/{mod-BrpVsSfY.d.cts → mod-Dw-nPxQh.d.cts} +9 -3
  120. package/dist/{mod-BsCE5Ihq.d.ts → mod-Xj5P4s4d.d.ts} +1 -1
  121. package/dist/mod.cjs +40 -39
  122. package/dist/mod.d.cts +10 -11
  123. package/dist/mod.d.ts +10 -11
  124. package/dist/mod.js +8 -8
  125. package/dist/nodeinfo/client.test.mjs +139 -4
  126. package/dist/nodeinfo/handler.test.mjs +5 -5
  127. package/dist/nodeinfo/mod.cjs +1 -1
  128. package/dist/nodeinfo/mod.d.cts +1 -1
  129. package/dist/nodeinfo/mod.d.ts +1 -1
  130. package/dist/nodeinfo/mod.js +1 -1
  131. package/dist/nodeinfo/types.test.mjs +4 -4
  132. package/dist/otel/exporter.test.mjs +3 -3
  133. package/dist/otel/mod.cjs +0 -1
  134. package/dist/otel/mod.d.cts +1 -1
  135. package/dist/otel/mod.d.ts +1 -1
  136. package/dist/{outgoing-jsonld-URuqsICz.mjs → outgoing-jsonld-4IJqPYos.mjs} +12 -10
  137. package/dist/{owner-DEvZuyOE.d.cts → owner-BF0L9cMt.d.cts} +11 -0
  138. package/dist/{owner-CnngXDNJ.d.ts → owner-BSzr5-I8.d.ts} +11 -0
  139. package/dist/owner-BfygwLNy.mjs +267 -0
  140. package/dist/portable-collection-DSrR0BSV.js +670 -0
  141. package/dist/portable-collection-L8jCHlci.cjs +686 -0
  142. package/dist/portable-collection-idA006Sj.mjs +418 -0
  143. package/dist/portable-key-CA6u-dST.mjs +549 -0
  144. package/dist/portable-key-id-Ca30-hOa.mjs +248 -0
  145. package/dist/proof-DeC9pb6t.mjs +1299 -0
  146. package/dist/{public-audience-Cr5MsnMq.mjs → public-audience--klBIOk1.mjs} +15 -10
  147. package/dist/router-u5O5KCQr.mjs +156 -0
  148. package/dist/runtime/mod.cjs +1 -1
  149. package/dist/runtime/mod.js +1 -1
  150. package/dist/secured-document-CxzZZ9nL.mjs +35 -0
  151. package/dist/send-1tcGhW1h.mjs +495 -0
  152. package/dist/sig/accept.test.mjs +1 -1
  153. package/dist/sig/compound-proof-discovery.test.d.mts +2 -0
  154. package/dist/sig/compound-proof-discovery.test.mjs +331 -0
  155. package/dist/sig/compound-proof-producer.test.d.mts +2 -0
  156. package/dist/sig/compound-proof-producer.test.mjs +107 -0
  157. package/dist/sig/compound-proof-verification.test.d.mts +2 -0
  158. package/dist/sig/compound-proof-verification.test.mjs +833 -0
  159. package/dist/sig/compound-proof.test.d.mts +2 -0
  160. package/dist/sig/compound-proof.test.mjs +411 -0
  161. package/dist/sig/http.test.mjs +702 -31
  162. package/dist/sig/key-owner-evidence.test.d.mts +2 -0
  163. package/dist/sig/key-owner-evidence.test.mjs +100 -0
  164. package/dist/sig/key.test.mjs +220 -8
  165. package/dist/sig/ld.test.mjs +65 -7
  166. package/dist/sig/mitra-receive-interop.test.d.mts +2 -0
  167. package/dist/sig/mitra-receive-interop.test.mjs +260 -0
  168. package/dist/sig/mitra-send-interop.test.d.mts +2 -0
  169. package/dist/sig/mitra-send-interop.test.mjs +461 -0
  170. package/dist/sig/mod.cjs +18 -16
  171. package/dist/sig/mod.d.cts +4 -4
  172. package/dist/sig/mod.d.ts +4 -4
  173. package/dist/sig/mod.js +3 -3
  174. package/dist/sig/owner.test.mjs +108 -9
  175. package/dist/sig/portable-collection.test.d.mts +2 -0
  176. package/dist/sig/portable-collection.test.mjs +697 -0
  177. package/dist/sig/portable-interop.test.d.mts +2 -0
  178. package/dist/sig/portable-interop.test.mjs +156 -0
  179. package/dist/sig/portable-key-id.test.d.mts +2 -0
  180. package/dist/sig/portable-key-id.test.mjs +67 -0
  181. package/dist/sig/portable-key.test.d.mts +2 -0
  182. package/dist/sig/portable-key.test.mjs +1439 -0
  183. package/dist/sig/proof.test.mjs +1753 -16
  184. package/dist/sig/tootik-request-interop.test.d.mts +2 -0
  185. package/dist/sig/tootik-request-interop.test.mjs +190 -0
  186. package/dist/sig/tootik-send-interop.test.d.mts +2 -0
  187. package/dist/sig/tootik-send-interop.test.mjs +331 -0
  188. package/dist/sig/verification.test.d.mts +2 -0
  189. package/dist/sig/verification.test.mjs +310 -0
  190. package/dist/std__assert-DvMDRPes.mjs +8 -0
  191. package/dist/{testing-CO7ftO8A.mjs → tasks-IG3pHfvZ.mjs} +2 -2
  192. package/dist/{temporal-yE5EcfNX.mjs → temporal-DA7r1fm3.mjs} +3 -3
  193. package/dist/testing/context.test.d.mts +2 -0
  194. package/dist/testing/context.test.mjs +19 -0
  195. package/dist/testing/kv.test.d.mts +2 -0
  196. package/dist/testing/kv.test.mjs +101 -0
  197. package/dist/testing/mod.d.mts +1604 -48
  198. package/dist/testing/mod.mjs +6 -3
  199. package/dist/testing-t8xDeJZ5.mjs +8 -0
  200. package/dist/{transformers-DGwl-hD1.cjs → transformers-BalCrSsr.cjs} +0 -1
  201. package/dist/{types-DC1pNgJA.js → types-_S2_MeLF.js} +144 -8
  202. package/dist/{types-CPym83zc.cjs → types-poIao40f.cjs} +160 -7
  203. package/dist/utils/docloader.test.mjs +530 -8
  204. package/dist/utils/kv-cache.test.mjs +2 -2
  205. package/dist/utils/mod.cjs +1 -1
  206. package/dist/utils/mod.d.cts +1 -1
  207. package/dist/utils/mod.d.ts +1 -1
  208. package/dist/utils/mod.js +1 -1
  209. package/dist/verification-C3954hQh.mjs +5 -0
  210. package/dist/verification-Dpfcw8ml.mjs +105 -0
  211. package/dist/vocab/cjs.test.mjs +1 -1
  212. package/package.json +9 -9
  213. package/dist/assert_rejects-EgstcQy5.mjs +0 -82
  214. package/dist/docloader-BCecHIxU.mjs +0 -49
  215. package/dist/http-Ctb_KhZ8.js +0 -2483
  216. package/dist/http-VyDTd4G3.d.cts +0 -553
  217. package/dist/http-jr0TkgZe.cjs +0 -2694
  218. package/dist/http-lf8Hsd91.d.ts +0 -553
  219. package/dist/key-C_gNKtxm.mjs +0 -453
  220. package/dist/keycache-_DHqz5z_.mjs +0 -97
  221. package/dist/metrics-DN13mCAw.d.cts +0 -294
  222. package/dist/metrics-v_e0n5GQ.d.ts +0 -294
  223. package/dist/mod-B0hW12_O.d.cts +0 -307
  224. package/dist/mod-COIAjwRS.d.ts +0 -307
  225. package/dist/owner-Dcx-czqn.mjs +0 -120
  226. package/dist/proof-BkAxvrjt.mjs +0 -316
  227. package/dist/proof-D-H_PnJW.js +0 -1415
  228. package/dist/proof-NY0D8Oux.cjs +0 -1562
  229. package/dist/send-D_j7E-oC.mjs +0 -239
  230. package/dist/std__assert-B2NnY9bq.mjs +0 -79
  231. package/dist/temporal-polyfill-BCdTHexd.cjs +0 -3565
  232. /package/dist/{accept-8PiolDP7.mjs → accept-CPVqki78.mjs} +0 -0
  233. /package/dist/{activity-listener-BtTSxZWA.mjs → activity-listener-C-BSbKI7.mjs} +0 -0
  234. /package/dist/{client-CAM_bQXx.d.cts → client-D-XP_Ccb.d.cts} +0 -0
  235. /package/dist/{client-CSddvgWN.d.ts → client-D-XP_Ccb.d.ts} +0 -0
  236. /package/dist/{keys-Dbyd7bhl.mjs → keys-DIJNHW-Y.mjs} +0 -0
  237. /package/dist/{kv-CXBAok3k.mjs → kv-DCHkaJ9-.mjs} +0 -0
  238. /package/dist/{mq-Bo7Etgh6.mjs → mq-Dm1Wmtm-.mjs} +0 -0
  239. /package/dist/{negotiation-RuwrPFqi.mjs → negotiation-CCocWT_N.mjs} +0 -0
  240. /package/dist/{retry-DgFqeS5k.mjs → retry-zX5xw5e0.mjs} +0 -0
  241. /package/dist/{chunk-D5IdezsZ.js → rolldown-runtime-BC-Eo5Mj.js} +0 -0
  242. /package/dist/{chunk-Czpeue4M.cjs → rolldown-runtime-Dmm3t92W.cjs} +0 -0
  243. /package/dist/{transformers-DXze6FUB.js → transformers-DAtXl_Kc.js} +0 -0
  244. /package/dist/{types-CrtdVuDP.mjs → types-DE_LV1JB.mjs} +0 -0
@@ -1,22 +1,25 @@
1
1
  import { Temporal } from "temporal-polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { n as createOutboxContext, r as createRequestContext, t as createInboxContext } from "../context-BJXxPElm.mjs";
5
- import { t as MemoryKvStore } from "../kv-CXBAok3k.mjs";
6
- import { t as assertEquals } from "../assert_equals-BV7oLMxm.mjs";
7
- import "../std__assert-B2NnY9bq.mjs";
8
- import { n as assertGreaterOrEqual, t as assertRejects } from "../assert_rejects-EgstcQy5.mjs";
9
- import { t as assertInstanceOf } from "../assert_instance_of-Q9KTBnrf.mjs";
10
- import { t as assert } from "../assert-CJ1KXcvv.mjs";
11
- import { r as parseAcceptSignature } from "../accept-8PiolDP7.mjs";
12
- import { s as signRequest } from "../http-Dm0JAUa_.mjs";
13
- import { a as rsaPrivateKey3, c as rsaPublicKey3, s as rsaPublicKey2 } from "../keys-Dbyd7bhl.mjs";
14
- import { a as compactJsonLd, p as signJsonLd } from "../ld-DAPAVL_7.mjs";
15
- import { c as handleActor, d as handleInbox, f as handleObject, h as respondWithObjectIfAcceptable, l as handleCollection, m as respondWithObject, o as createFederation, p as handleOutbox, u as handleCustomCollection } from "../middleware-O2LHXFEk.mjs";
16
- import { t as ActivityListenerSet } from "../activity-listener-BtTSxZWA.mjs";
17
- import { Activity, Create, Note, Person, Tombstone } from "@fedify/vocab";
4
+ import { n as createOutboxContext, r as createRequestContext, t as createInboxContext } from "../context-8Tu9kea0.mjs";
5
+ import { t as MemoryKvStore } from "../kv-DCHkaJ9-.mjs";
6
+ import { t as assertEquals } from "../assert_equals-Z6IcEbWU.mjs";
7
+ import { t as assertGreaterOrEqual } from "../assert_greater_or_equal-BlafOF4-.mjs";
8
+ import { t as assertInstanceOf } from "../assert_instance_of-mrXWWNY-.mjs";
9
+ import "../std__assert-DvMDRPes.mjs";
10
+ import { t as assertRejects } from "../assert_rejects-CTptdYck.mjs";
11
+ import { t as assert } from "../assert-D1Eafmd_.mjs";
12
+ import { r as parseAcceptSignature } from "../accept-CPVqki78.mjs";
13
+ import { o as generateCryptoKeyPair } from "../key-D979vduq.mjs";
14
+ import { a as compactJsonLd, p as signJsonLd } from "../ld-wmqC-95l.mjs";
15
+ import { a as signObject } from "../proof-DeC9pb6t.mjs";
16
+ import { l as signRequest } from "../http-BAgKAAGY.mjs";
17
+ import { a as rsaPrivateKey3, c as rsaPublicKey3, s as rsaPublicKey2 } from "../keys-DIJNHW-Y.mjs";
18
+ import { d as handleCustomCollection, f as handleInbox, g as respondWithObjectIfAcceptable, h as respondWithObject, l as handleActor, m as handleOutbox, o as createFederation, p as handleObject, u as handleCollection } from "../middleware-CqQ5Qahj.mjs";
19
+ import { t as ActivityListenerSet } from "../activity-listener-C-BSbKI7.mjs";
20
+ import { Activity, Create, CryptographicKey, Multikey, Note, Person, Tombstone } from "@fedify/vocab";
21
+ import { FetchError, parseIri } from "@fedify/vocab-runtime";
18
22
  import { createTestMeterProvider, createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
19
- import { FetchError } from "@fedify/vocab-runtime";
20
23
  //#region src/federation/handler.test.ts
21
24
  const QUOTE_CONTEXT_TERMS = {
22
25
  QuoteAuthorization: "https://w3id.org/fep/044f#QuoteAuthorization",
@@ -106,6 +109,7 @@ test("handleActor()", async () => {
106
109
  assertEquals(await response.json(), {
107
110
  "@context": [
108
111
  "https://www.w3.org/ns/activitystreams",
112
+ "https://w3id.org/fep/ef61",
109
113
  "https://w3id.org/security/v1",
110
114
  "https://w3id.org/security/data-integrity/v1",
111
115
  "https://www.w3.org/ns/did/v1",
@@ -195,6 +199,7 @@ test("handleActor()", async () => {
195
199
  assertEquals(await response.json(), {
196
200
  "@context": [
197
201
  "https://www.w3.org/ns/activitystreams",
202
+ "https://w3id.org/fep/ef61",
198
203
  "https://w3id.org/security/v1",
199
204
  "https://w3id.org/security/data-integrity/v1",
200
205
  "https://www.w3.org/ns/did/v1",
@@ -495,6 +500,119 @@ test("handleObject()", async () => {
495
500
  assertEquals(onNotFoundCalled, null);
496
501
  assertEquals(onUnauthorizedCalled, null);
497
502
  });
503
+ test("handleObject() with a tombstone", async () => {
504
+ const federation = createFederation({ kv: new MemoryKvStore() });
505
+ const url = new URL("https://example.com/users/someone/notes/123");
506
+ let context = createRequestContext({
507
+ federation,
508
+ data: void 0,
509
+ url,
510
+ request: new Request(url, { headers: { Accept: "application/activity+json" } })
511
+ });
512
+ const objectDispatcher = (_ctx, values) => {
513
+ if (values.id !== "123") return null;
514
+ return new Tombstone({
515
+ id: new URL(`https://example.com/users/${values.identifier}/notes/${values.id}`),
516
+ formerType: Note,
517
+ deleted: Temporal.Instant.from("2024-01-15T00:00:00Z")
518
+ });
519
+ };
520
+ let onNotFoundCalled = null;
521
+ const onNotFound = (request) => {
522
+ onNotFoundCalled = request;
523
+ return new Response("Not found", { status: 404 });
524
+ };
525
+ let onUnauthorizedCalled = null;
526
+ const onUnauthorized = (request) => {
527
+ onUnauthorizedCalled = request;
528
+ return new Response("Unauthorized", { status: 401 });
529
+ };
530
+ let response = await handleObject(context.request, {
531
+ context,
532
+ values: {
533
+ identifier: "someone",
534
+ id: "123"
535
+ },
536
+ objectDispatcher,
537
+ onNotFound,
538
+ onUnauthorized
539
+ });
540
+ assertEquals(response.status, 410);
541
+ assertEquals(response.headers.get("Content-Type"), "application/activity+json");
542
+ assertEquals(response.headers.get("Vary"), "Accept");
543
+ const body = await response.json();
544
+ assertEquals(body.id, "https://example.com/users/someone/notes/123");
545
+ assertEquals(body.type, "Tombstone");
546
+ assertEquals(body.formerType, "as:Note");
547
+ assertEquals(body.deleted, "2024-01-15T00:00:00Z");
548
+ assertEquals(onNotFoundCalled, null);
549
+ assertEquals(onUnauthorizedCalled, null);
550
+ response = await handleObject(context.request, {
551
+ context,
552
+ values: {
553
+ identifier: "someone",
554
+ id: "456"
555
+ },
556
+ objectDispatcher,
557
+ onNotFound,
558
+ onUnauthorized
559
+ });
560
+ assertEquals(response.status, 404);
561
+ assertEquals(onNotFoundCalled, context.request);
562
+ assertEquals(onUnauthorizedCalled, null);
563
+ onNotFoundCalled = null;
564
+ let authorized = false;
565
+ const authorizePredicate = () => authorized;
566
+ response = await handleObject(context.request, {
567
+ context,
568
+ values: {
569
+ identifier: "someone",
570
+ id: "123"
571
+ },
572
+ objectDispatcher,
573
+ authorizePredicate,
574
+ onNotFound,
575
+ onUnauthorized
576
+ });
577
+ assertEquals(response.status, 401);
578
+ assertEquals(onNotFoundCalled, null);
579
+ assertEquals(onUnauthorizedCalled, context.request);
580
+ onUnauthorizedCalled = null;
581
+ authorized = true;
582
+ response = await handleObject(context.request, {
583
+ context,
584
+ values: {
585
+ identifier: "someone",
586
+ id: "123"
587
+ },
588
+ objectDispatcher,
589
+ authorizePredicate,
590
+ onNotFound,
591
+ onUnauthorized
592
+ });
593
+ assertEquals(response.status, 410);
594
+ assertEquals(onUnauthorizedCalled, null);
595
+ context = createRequestContext({
596
+ ...context,
597
+ request: new Request(url, {
598
+ method: "HEAD",
599
+ headers: { Accept: "application/activity+json" }
600
+ })
601
+ });
602
+ response = await handleObject(context.request, {
603
+ context,
604
+ values: {
605
+ identifier: "someone",
606
+ id: "123"
607
+ },
608
+ objectDispatcher,
609
+ onNotFound,
610
+ onUnauthorized
611
+ });
612
+ assertEquals(response.status, 410);
613
+ assertEquals(response.headers.get("Content-Type"), "application/activity+json");
614
+ assertEquals(response.body, null);
615
+ });
498
616
  test("handleCollection()", async () => {
499
617
  let context = createRequestContext({
500
618
  federation: createFederation({ kv: new MemoryKvStore() }),
@@ -1124,6 +1242,67 @@ test("handleCollection() records not_found collection metrics", async () => {
1124
1242
  assertEquals(durations[0].attributes["activitypub.collection.result"], "not_found");
1125
1243
  assertEquals(recorder.getMeasurements("activitypub.collection.page.items").length, 0);
1126
1244
  });
1245
+ test("handleInbox() reports dispatch context errors before a failing error hook", async () => {
1246
+ const kv = new MemoryKvStore();
1247
+ const federation = createFederation({ kv });
1248
+ const request = await signRequest(new Request("https://example.com/inbox", {
1249
+ method: "POST",
1250
+ body: JSON.stringify(await new Create({ actor: rsaPublicKey3.ownerId }).toJsonLd({ contextLoader: mockDocumentLoader }))
1251
+ }), rsaPrivateKey3, rsaPublicKey3.id);
1252
+ const context = createRequestContext({
1253
+ federation,
1254
+ request,
1255
+ url: new URL(request.url),
1256
+ data: void 0,
1257
+ documentLoader: mockDocumentLoader,
1258
+ contextLoader: mockDocumentLoader
1259
+ });
1260
+ const error = /* @__PURE__ */ new Error("Cannot create dispatch context");
1261
+ const reports = [];
1262
+ const listeners = new ActivityListenerSet();
1263
+ let listenerCalled = false;
1264
+ listeners.add(Create, () => {
1265
+ listenerCalled = true;
1266
+ });
1267
+ let errorHookCalled = false;
1268
+ assertEquals((await handleInbox(request, {
1269
+ context,
1270
+ recipient: null,
1271
+ kv,
1272
+ kvPrefixes: {
1273
+ activityIdempotence: ["activity"],
1274
+ publicKey: ["key"],
1275
+ acceptSignatureNonce: ["nonce"]
1276
+ },
1277
+ actorDispatcher: () => new Person({}),
1278
+ inboxListeners: listeners,
1279
+ inboxContextFactory: () => {
1280
+ throw error;
1281
+ },
1282
+ inboxErrorHandler: (_ctx, value) => {
1283
+ assertEquals(value, error);
1284
+ errorHookCalled = true;
1285
+ throw new Error("Error hook failed");
1286
+ },
1287
+ inboxRequestFinishedHandler: (_ctx, report) => {
1288
+ reports.push(report);
1289
+ },
1290
+ onNotFound: () => new Response(null, { status: 404 }),
1291
+ signatureTimeWindow: false,
1292
+ skipSignatureVerification: false
1293
+ })).status, 500);
1294
+ assertEquals(listenerCalled, false);
1295
+ assertEquals(errorHookCalled, true);
1296
+ assertEquals(reports.length, 1);
1297
+ assertEquals(reports[0].authentication.status, "verified");
1298
+ assertEquals(reports[0].outcome, {
1299
+ type: "response",
1300
+ status: 500,
1301
+ disposition: "failed",
1302
+ reason: "listenerError",
1303
+ error
1304
+ });
1305
+ });
1127
1306
  test("handleInbox()", async () => {
1128
1307
  const activity = new Create({
1129
1308
  id: new URL("https://example.com/activities/1"),
@@ -2746,6 +2925,73 @@ test("handleOutbox()", async () => {
2746
2925
  assertEquals(response.status, 500);
2747
2926
  assertEquals(onErrorCalled, true);
2748
2927
  });
2928
+ test("handleOutbox() matches portable actors by their canonical IDs", async () => {
2929
+ const federation = createFederation({ kv: new MemoryKvStore() });
2930
+ const actorId = "ap+ef61://did:key:z6MkAlice/users/someone";
2931
+ const actorDispatcher = (_ctx, identifier) => {
2932
+ if (identifier !== "someone") return null;
2933
+ return new Person({
2934
+ id: parseIri(actorId),
2935
+ name: "Someone"
2936
+ });
2937
+ };
2938
+ const post = async (actor) => {
2939
+ const request = new Request("https://example.com/users/someone/outbox", {
2940
+ method: "POST",
2941
+ body: JSON.stringify({
2942
+ "@context": "https://www.w3.org/ns/activitystreams",
2943
+ type: "Create",
2944
+ id: "https://example.com/activities/1",
2945
+ actor,
2946
+ object: {
2947
+ type: "Note",
2948
+ content: "Hello, world!"
2949
+ }
2950
+ })
2951
+ });
2952
+ const context = createRequestContext({
2953
+ federation,
2954
+ request,
2955
+ url: new URL(request.url),
2956
+ data: void 0
2957
+ });
2958
+ const seen = [];
2959
+ const listeners = new ActivityListenerSet();
2960
+ listeners.add(Activity, (_ctx, activity) => {
2961
+ seen.push(activity.id.href);
2962
+ });
2963
+ return [(await handleOutbox(request, {
2964
+ identifier: "someone",
2965
+ context,
2966
+ outboxContextFactory(identifier) {
2967
+ return createOutboxContext({
2968
+ ...context,
2969
+ clone: void 0,
2970
+ identifier
2971
+ });
2972
+ },
2973
+ actorDispatcher,
2974
+ outboxListeners: listeners,
2975
+ onNotFound: () => new Response("Not found", { status: 404 }),
2976
+ onUnauthorized: () => new Response("Unauthorized", { status: 401 })
2977
+ })).status, seen.length];
2978
+ };
2979
+ for (const actor of [
2980
+ actorId,
2981
+ "ap://did:key:z6MkAlice/users/someone",
2982
+ "ap+ef61://did%3Akey%3Az6MkAlice/users/someone",
2983
+ "ap://did:key:z6MkAlice/users/someone?@gateway=https%3A%2F%2Fserver1.example&@gateway=https%3A%2F%2Fserver2.example",
2984
+ "https://server2.example/.well-known/apgateway/did:key:z6MkAlice/users/someone"
2985
+ ]) assertEquals(await post(actor), [202, 1], actor);
2986
+ for (const actor of [
2987
+ "ap://did:key:z6MkBob/users/someone",
2988
+ "ap://did:key:z6MkAlice/users/other?@gateway=https%3A%2F%2Fserver1.example",
2989
+ "ap://did:key:z6MkAlice/users/someone#main-key",
2990
+ "https://server1.example/.well-known/apgateway/did:key:z6MkAlice/users/someone?@gateway=https%3A%2F%2Fserver1.example",
2991
+ "https://example.com/users/someone",
2992
+ [actorId, "ap://did:key:z6MkAlice/users/other"]
2993
+ ]) assertEquals(await post(actor), [400, 0], String(actor));
2994
+ });
2749
2995
  test("handleInbox() preserves the raw signed payload for inboxContextFactory", async () => {
2750
2996
  const federation = createFederation({ kv: new MemoryKvStore() });
2751
2997
  const remoteContextUrl = "https://remote.example/contexts/ext";
@@ -4241,7 +4487,11 @@ test("handleInbox() nonce replay prevention", async () => {
4241
4487
  if (identifier !== "someone") return null;
4242
4488
  return new Person({ name: "Someone" });
4243
4489
  };
4490
+ let report;
4244
4491
  const response = await handleInbox(signedRequest, {
4492
+ inboxRequestFinishedHandler: (_ctx, value) => {
4493
+ report = value;
4494
+ },
4245
4495
  recipient: "someone",
4246
4496
  context,
4247
4497
  inboxContextFactory(_activity) {
@@ -4269,6 +4519,12 @@ test("handleInbox() nonce replay prevention", async () => {
4269
4519
  }
4270
4520
  });
4271
4521
  assertEquals(response.status, 401);
4522
+ assert(report != null);
4523
+ assertEquals(report.authentication, {
4524
+ status: "rejected",
4525
+ reason: { type: "invalidNonce" }
4526
+ });
4527
+ assertEquals(report.attempts.at(-1)?.status, "verified");
4272
4528
  const acceptSig = response.headers.get("Accept-Signature");
4273
4529
  assert(acceptSig != null, "Must emit fresh Accept-Signature challenge");
4274
4530
  const parsed = parseAcceptSignature(acceptSig);
@@ -4571,5 +4827,121 @@ test("handleInbox() challenge policy enabled + unverifiedActivityHandler throws
4571
4827
  assertEquals(response.headers.get("Cache-Control"), "no-store", "Cache-Control: no-store must be set for challenge-response");
4572
4828
  assertEquals(response.headers.get("Vary"), "Accept, Signature", "Vary header must include Accept and Signature");
4573
4829
  });
4830
+ test("handleInbox() rejects forged key ownership", async () => {
4831
+ const impersonated = "https://example.com/person2";
4832
+ const attackerKeyId = new URL("https://attacker.example/key");
4833
+ const attackerMultikeyId = new URL("https://attacker.example/multikey");
4834
+ const { privateKey, publicKey } = await generateCryptoKeyPair("RSASSA-PKCS1-v1_5");
4835
+ const forgedKeyDocument = await new CryptographicKey({
4836
+ id: attackerKeyId,
4837
+ owner: new URL(impersonated),
4838
+ publicKey
4839
+ }).toJsonLd({ contextLoader: mockDocumentLoader });
4840
+ const ed25519 = await generateCryptoKeyPair("Ed25519");
4841
+ const forgedMultikeyDocument = await new Multikey({
4842
+ id: attackerMultikeyId,
4843
+ controller: new URL(impersonated),
4844
+ publicKey: ed25519.publicKey
4845
+ }).toJsonLd({ contextLoader: mockDocumentLoader });
4846
+ const documentLoader = (resource) => {
4847
+ if (resource === attackerKeyId.href) return Promise.resolve({
4848
+ contextUrl: null,
4849
+ documentUrl: resource,
4850
+ document: forgedKeyDocument
4851
+ });
4852
+ if (resource === attackerMultikeyId.href) return Promise.resolve({
4853
+ contextUrl: null,
4854
+ documentUrl: resource,
4855
+ document: forgedMultikeyDocument
4856
+ });
4857
+ return mockDocumentLoader(resource);
4858
+ };
4859
+ const federation = createFederation({ kv: new MemoryKvStore() });
4860
+ const inboxOptions = {
4861
+ kv: new MemoryKvStore(),
4862
+ kvPrefixes: {
4863
+ activityIdempotence: ["_fedify", "activityIdempotence"],
4864
+ publicKey: ["_fedify", "publicKey"],
4865
+ acceptSignatureNonce: ["_fedify", "acceptSignatureNonce"]
4866
+ },
4867
+ actorDispatcher: ((_ctx, identifier) => identifier === "someone" ? new Person({ name: "Someone" }) : null),
4868
+ inboxListeners: new ActivityListenerSet(),
4869
+ onNotFound: () => new Response("Not found", { status: 404 }),
4870
+ signatureTimeWindow: { minutes: 5 },
4871
+ skipSignatureVerification: false
4872
+ };
4873
+ const handle = async (request) => {
4874
+ const context = createRequestContext({
4875
+ federation,
4876
+ request,
4877
+ url: new URL(request.url),
4878
+ data: void 0,
4879
+ documentLoader,
4880
+ contextLoader: mockDocumentLoader
4881
+ });
4882
+ return await handleInbox(request, {
4883
+ recipient: null,
4884
+ context,
4885
+ inboxContextFactory(_activity) {
4886
+ return createInboxContext({
4887
+ ...context,
4888
+ clone: void 0
4889
+ });
4890
+ },
4891
+ ...inboxOptions
4892
+ });
4893
+ };
4894
+ const activity = {
4895
+ "@context": [
4896
+ "https://www.w3.org/ns/activitystreams",
4897
+ "https://w3id.org/identity/v1",
4898
+ "https://w3id.org/security/v1",
4899
+ "https://w3id.org/security/data-integrity/v1"
4900
+ ],
4901
+ id: "https://attacker.example/activities/1",
4902
+ type: "Create",
4903
+ actor: impersonated,
4904
+ object: {
4905
+ id: "https://attacker.example/notes/1",
4906
+ type: "Note",
4907
+ attributedTo: impersonated,
4908
+ content: "Hello World!"
4909
+ }
4910
+ };
4911
+ const httpSignedResponse = await handle(await signRequest(new Request("https://example.com/", {
4912
+ method: "POST",
4913
+ body: JSON.stringify(activity)
4914
+ }), privateKey, attackerKeyId));
4915
+ const ldSignedResponse = await handle(new Request("https://example.com/", {
4916
+ method: "POST",
4917
+ body: JSON.stringify(await signJsonLd(activity, privateKey, attackerKeyId, { contextLoader: mockDocumentLoader }))
4918
+ }));
4919
+ const signedObject = await signObject(await Create.fromJsonLd(activity, {
4920
+ documentLoader,
4921
+ contextLoader: mockDocumentLoader
4922
+ }), ed25519.privateKey, attackerMultikeyId, {
4923
+ documentLoader,
4924
+ contextLoader: mockDocumentLoader,
4925
+ context: ["https://www.w3.org/ns/activitystreams", "https://w3id.org/security/data-integrity/v1"]
4926
+ });
4927
+ const proofSignedResponse = await handle(new Request("https://example.com/", {
4928
+ method: "POST",
4929
+ body: JSON.stringify(await signedObject.toJsonLd({
4930
+ format: "compact",
4931
+ contextLoader: mockDocumentLoader,
4932
+ context: ["https://www.w3.org/ns/activitystreams", "https://w3id.org/security/data-integrity/v1"]
4933
+ }))
4934
+ }));
4935
+ assertEquals([
4936
+ httpSignedResponse.status,
4937
+ ldSignedResponse.status,
4938
+ proofSignedResponse.status
4939
+ ], [
4940
+ 401,
4941
+ 401,
4942
+ 401
4943
+ ]);
4944
+ assertEquals(await httpSignedResponse.text(), "Failed to verify the request signature.");
4945
+ });
4574
4946
  //#endregion
4575
4947
  export {};
@@ -0,0 +1,2 @@
1
+ import { Temporal } from "temporal-polyfill";
2
+ import { URLPattern } from "urlpattern-polyfill";