@fedify/fedify 2.4.0-pr.936.41 → 2.5.0-dev.2271

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 +50 -39
  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-DonuxRl_.mjs → builder-Bda6LK7A.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-B-9mXxFW.mjs +989 -0
  30. package/dist/{context-Zii1f5xS.d.ts → context-7NyiqIcg.d.ts} +1600 -25
  31. package/dist/{context-BJXxPElm.mjs → context-8Tu9kea0.mjs} +21 -63
  32. package/dist/{context-lxX6I7as.d.cts → context-tsYPJ2Ew.d.cts} +1600 -25
  33. package/dist/{deno-BHzKn9Ig.mjs → deno-oR5aJKpU.mjs} +1 -1
  34. package/dist/dist-DJQM4u7i.mjs +189 -0
  35. package/dist/docloader-DBoYbvYW.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 +385 -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 -261
  58. package/dist/federation/mod.d.cts +5 -5
  59. package/dist/federation/mod.d.ts +5 -5
  60. package/dist/federation/mod.js +279 -1
  61. package/dist/federation/mq.test.mjs +123 -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 +42 -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-FrSMAYEx.cjs → federation-CkZiAcWY.cjs} +8640 -3722
  92. package/dist/http-B5JT115n.cjs +10630 -0
  93. package/dist/http-DydWCB7R.js +6527 -0
  94. package/dist/{http-CPVMUgsW.mjs → http-siciWkmx.mjs} +397 -168
  95. package/dist/key-BspPiXqn.mjs +951 -0
  96. package/dist/key-C1nv7_jD.d.ts +1125 -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-KyGqJqSp.mjs → kv-cache-BF1hnW65.mjs} +1 -1
  104. package/dist/{kv-cache-5bnX3-Jq.js → kv-cache-CTQr1tbn.js} +54 -16
  105. package/dist/{kv-cache-DQ29C4XL.cjs → kv-cache-DCac1nEU.cjs} +55 -19
  106. package/dist/{ld-Cj9F_5AP.mjs → ld-CzaP-hJl.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-DMk-nTxI.mjs → metrics-CYg9yxBL.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-Y-kpsp6S.js → middleware-CsDDXKuL.js} +5493 -1103
  113. package/dist/{middleware-CvwTUgnP.mjs → middleware-D7_LO-Vs.mjs} +3157 -272
  114. package/dist/{middleware-CEctxBN6.mjs → middleware-DWjrfpcz.mjs} +1 -1
  115. package/dist/{mod-gOlPDuT8.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-BtEaIEcD.d.cts → mod-DEZXwV6J.d.ts} +10 -4
  119. package/dist/{mod-UMmveiO0.d.ts → mod-Dw-nPxQh.d.cts} +10 -4
  120. package/dist/{mod-DLc2Ot6f.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 +9 -9
  125. package/dist/{mq-llHKivST.mjs → mq-Dm1Wmtm-.mjs} +6 -0
  126. package/dist/nodeinfo/client.test.mjs +139 -4
  127. package/dist/nodeinfo/handler.test.mjs +5 -5
  128. package/dist/nodeinfo/mod.cjs +1 -1
  129. package/dist/nodeinfo/mod.d.cts +1 -1
  130. package/dist/nodeinfo/mod.d.ts +1 -1
  131. package/dist/nodeinfo/mod.js +1 -1
  132. package/dist/nodeinfo/types.test.mjs +4 -4
  133. package/dist/otel/exporter.test.mjs +3 -3
  134. package/dist/otel/mod.cjs +0 -1
  135. package/dist/otel/mod.d.cts +1 -1
  136. package/dist/otel/mod.d.ts +1 -1
  137. package/dist/{outgoing-jsonld-URuqsICz.mjs → outgoing-jsonld-4IJqPYos.mjs} +12 -10
  138. package/dist/{owner-DEvZuyOE.d.cts → owner-BF0L9cMt.d.cts} +11 -0
  139. package/dist/{owner-CnngXDNJ.d.ts → owner-BSzr5-I8.d.ts} +11 -0
  140. package/dist/owner-DYgfTFHy.mjs +267 -0
  141. package/dist/portable-collection-BpsVsRov.js +670 -0
  142. package/dist/portable-collection-C74P1vtC.mjs +418 -0
  143. package/dist/portable-collection-DZd2bm7M.cjs +686 -0
  144. package/dist/portable-key-BIMLrAP4.mjs +549 -0
  145. package/dist/portable-key-id-Ca30-hOa.mjs +248 -0
  146. package/dist/proof-Dxy6ByqI.mjs +1299 -0
  147. package/dist/{public-audience-Cr5MsnMq.mjs → public-audience--klBIOk1.mjs} +15 -10
  148. package/dist/router-u5O5KCQr.mjs +156 -0
  149. package/dist/runtime/mod.cjs +1 -1
  150. package/dist/runtime/mod.js +1 -1
  151. package/dist/secured-document-CxzZZ9nL.mjs +35 -0
  152. package/dist/send-C4dDpAxm.mjs +495 -0
  153. package/dist/sig/accept.test.mjs +1 -1
  154. package/dist/sig/compound-proof-discovery.test.d.mts +2 -0
  155. package/dist/sig/compound-proof-discovery.test.mjs +331 -0
  156. package/dist/sig/compound-proof-producer.test.d.mts +2 -0
  157. package/dist/sig/compound-proof-producer.test.mjs +107 -0
  158. package/dist/sig/compound-proof-verification.test.d.mts +2 -0
  159. package/dist/sig/compound-proof-verification.test.mjs +833 -0
  160. package/dist/sig/compound-proof.test.d.mts +2 -0
  161. package/dist/sig/compound-proof.test.mjs +411 -0
  162. package/dist/sig/http.test.mjs +702 -31
  163. package/dist/sig/key-owner-evidence.test.d.mts +2 -0
  164. package/dist/sig/key-owner-evidence.test.mjs +100 -0
  165. package/dist/sig/key.test.mjs +220 -8
  166. package/dist/sig/ld.test.mjs +65 -7
  167. package/dist/sig/mitra-receive-interop.test.d.mts +2 -0
  168. package/dist/sig/mitra-receive-interop.test.mjs +260 -0
  169. package/dist/sig/mitra-send-interop.test.d.mts +2 -0
  170. package/dist/sig/mitra-send-interop.test.mjs +461 -0
  171. package/dist/sig/mod.cjs +18 -16
  172. package/dist/sig/mod.d.cts +4 -4
  173. package/dist/sig/mod.d.ts +4 -4
  174. package/dist/sig/mod.js +3 -3
  175. package/dist/sig/owner.test.mjs +108 -9
  176. package/dist/sig/portable-collection.test.d.mts +2 -0
  177. package/dist/sig/portable-collection.test.mjs +697 -0
  178. package/dist/sig/portable-interop.test.d.mts +2 -0
  179. package/dist/sig/portable-interop.test.mjs +156 -0
  180. package/dist/sig/portable-key-id.test.d.mts +2 -0
  181. package/dist/sig/portable-key-id.test.mjs +67 -0
  182. package/dist/sig/portable-key.test.d.mts +2 -0
  183. package/dist/sig/portable-key.test.mjs +1439 -0
  184. package/dist/sig/proof.test.mjs +1753 -16
  185. package/dist/sig/tootik-request-interop.test.d.mts +2 -0
  186. package/dist/sig/tootik-request-interop.test.mjs +190 -0
  187. package/dist/sig/tootik-send-interop.test.d.mts +2 -0
  188. package/dist/sig/tootik-send-interop.test.mjs +331 -0
  189. package/dist/sig/verification.test.d.mts +2 -0
  190. package/dist/sig/verification.test.mjs +310 -0
  191. package/dist/std__assert-DvMDRPes.mjs +8 -0
  192. package/dist/{testing-CO7ftO8A.mjs → tasks-IG3pHfvZ.mjs} +2 -2
  193. package/dist/{temporal-fsXO5IvD.mjs → temporal-D0KJI4NF.mjs} +3 -3
  194. package/dist/testing/context.test.d.mts +2 -0
  195. package/dist/testing/context.test.mjs +19 -0
  196. package/dist/testing/kv.test.d.mts +2 -0
  197. package/dist/testing/kv.test.mjs +101 -0
  198. package/dist/testing/mod.d.mts +1617 -48
  199. package/dist/testing/mod.mjs +6 -3
  200. package/dist/testing-t8xDeJZ5.mjs +8 -0
  201. package/dist/{transformers-DGwl-hD1.cjs → transformers-BalCrSsr.cjs} +0 -1
  202. package/dist/{types-DC1pNgJA.js → types-_S2_MeLF.js} +144 -8
  203. package/dist/{types-CPym83zc.cjs → types-poIao40f.cjs} +160 -7
  204. package/dist/utils/docloader.test.mjs +530 -8
  205. package/dist/utils/kv-cache.test.mjs +2 -2
  206. package/dist/utils/mod.cjs +1 -1
  207. package/dist/utils/mod.d.cts +1 -1
  208. package/dist/utils/mod.d.ts +1 -1
  209. package/dist/utils/mod.js +1 -1
  210. package/dist/verification-C3954hQh.mjs +5 -0
  211. package/dist/verification-Dpfcw8ml.mjs +105 -0
  212. package/dist/vocab/cjs.test.mjs +1 -1
  213. package/package.json +8 -8
  214. package/dist/assert_rejects-EgstcQy5.mjs +0 -82
  215. package/dist/docloader-e1khNUKy.mjs +0 -49
  216. package/dist/http-CsmQ-BQ4.js +0 -2483
  217. package/dist/http-VyDTd4G3.d.cts +0 -553
  218. package/dist/http-hlIjmewS.cjs +0 -2694
  219. package/dist/http-lf8Hsd91.d.ts +0 -553
  220. package/dist/key-DfPsX8hv.mjs +0 -453
  221. package/dist/keycache-_DHqz5z_.mjs +0 -97
  222. package/dist/metrics-CoUJLQhZ.d.cts +0 -276
  223. package/dist/metrics-Dc4jR-IC.d.ts +0 -276
  224. package/dist/mod-B0hW12_O.d.cts +0 -307
  225. package/dist/mod-COIAjwRS.d.ts +0 -307
  226. package/dist/owner-Br9YYzn_.mjs +0 -120
  227. package/dist/proof-B4ngoaNQ.mjs +0 -316
  228. package/dist/proof-B6E0XUXJ.js +0 -1415
  229. package/dist/proof-NN4xCQGL.cjs +0 -1562
  230. package/dist/send-CxHKUNzv.mjs +0 -239
  231. package/dist/std__assert-B2NnY9bq.mjs +0 -79
  232. package/dist/temporal-polyfill-BCdTHexd.cjs +0 -3565
  233. /package/dist/{accept-8PiolDP7.mjs → accept-CPVqki78.mjs} +0 -0
  234. /package/dist/{activity-listener-BtTSxZWA.mjs → activity-listener-C-BSbKI7.mjs} +0 -0
  235. /package/dist/{client-CAM_bQXx.d.cts → client-D-XP_Ccb.d.cts} +0 -0
  236. /package/dist/{client-CSddvgWN.d.ts → client-D-XP_Ccb.d.ts} +0 -0
  237. /package/dist/{keys-Dbyd7bhl.mjs → keys-DIJNHW-Y.mjs} +0 -0
  238. /package/dist/{kv-CXBAok3k.mjs → kv-DCHkaJ9-.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-CPVMUgsW.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-Cj9F_5AP.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-CvwTUgnP.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-BspPiXqn.mjs";
14
+ import { a as compactJsonLd, p as signJsonLd } from "../ld-CzaP-hJl.mjs";
15
+ import { a as signObject } from "../proof-Dxy6ByqI.mjs";
16
+ import { l as signRequest } from "../http-siciWkmx.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-D7_LO-Vs.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",
@@ -497,6 +500,119 @@ test("handleObject()", async () => {
497
500
  assertEquals(onNotFoundCalled, null);
498
501
  assertEquals(onUnauthorizedCalled, null);
499
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
+ });
500
616
  test("handleCollection()", async () => {
501
617
  let context = createRequestContext({
502
618
  federation: createFederation({ kv: new MemoryKvStore() }),
@@ -1126,6 +1242,67 @@ test("handleCollection() records not_found collection metrics", async () => {
1126
1242
  assertEquals(durations[0].attributes["activitypub.collection.result"], "not_found");
1127
1243
  assertEquals(recorder.getMeasurements("activitypub.collection.page.items").length, 0);
1128
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
+ });
1129
1306
  test("handleInbox()", async () => {
1130
1307
  const activity = new Create({
1131
1308
  id: new URL("https://example.com/activities/1"),
@@ -2748,6 +2925,73 @@ test("handleOutbox()", async () => {
2748
2925
  assertEquals(response.status, 500);
2749
2926
  assertEquals(onErrorCalled, true);
2750
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
+ });
2751
2995
  test("handleInbox() preserves the raw signed payload for inboxContextFactory", async () => {
2752
2996
  const federation = createFederation({ kv: new MemoryKvStore() });
2753
2997
  const remoteContextUrl = "https://remote.example/contexts/ext";
@@ -4243,7 +4487,11 @@ test("handleInbox() nonce replay prevention", async () => {
4243
4487
  if (identifier !== "someone") return null;
4244
4488
  return new Person({ name: "Someone" });
4245
4489
  };
4490
+ let report;
4246
4491
  const response = await handleInbox(signedRequest, {
4492
+ inboxRequestFinishedHandler: (_ctx, value) => {
4493
+ report = value;
4494
+ },
4247
4495
  recipient: "someone",
4248
4496
  context,
4249
4497
  inboxContextFactory(_activity) {
@@ -4271,6 +4519,12 @@ test("handleInbox() nonce replay prevention", async () => {
4271
4519
  }
4272
4520
  });
4273
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");
4274
4528
  const acceptSig = response.headers.get("Accept-Signature");
4275
4529
  assert(acceptSig != null, "Must emit fresh Accept-Signature challenge");
4276
4530
  const parsed = parseAcceptSignature(acceptSig);
@@ -4573,5 +4827,121 @@ test("handleInbox() challenge policy enabled + unverifiedActivityHandler throws
4573
4827
  assertEquals(response.headers.get("Cache-Control"), "no-store", "Cache-Control: no-store must be set for challenge-response");
4574
4828
  assertEquals(response.headers.get("Vary"), "Accept, Signature", "Vary header must include Accept and Signature");
4575
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
+ });
4576
4946
  //#endregion
4577
4947
  export {};
@@ -0,0 +1,2 @@
1
+ import { Temporal } from "temporal-polyfill";
2
+ import { URLPattern } from "urlpattern-polyfill";