@fedify/fedify 1.10.9 → 1.10.11

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 (121) hide show
  1. package/dist/{actor-DSmY7of0.cjs → actor--xTQfY8h.cjs} +187 -187
  2. package/dist/{actor-CMBXPdjk.js → actor-B7XRaa54.js} +187 -187
  3. package/dist/{actor-z4bjwAPy.mjs → actor-CTpwJ1pI.mjs} +1 -1
  4. package/dist/{authdocloader-C7iVUcxr.mjs → authdocloader-DJ-h-WMy.mjs} +3 -3
  5. package/dist/{authdocloader-YXazGK4I.cjs → authdocloader-DMkkNwRc.cjs} +3 -3
  6. package/dist/{authdocloader-B4QKchy5.js → authdocloader-_h7VKnUP.js} +3 -3
  7. package/dist/{builder-C3PFAtTV.mjs → builder-Dx_LGmTI.mjs} +4 -4
  8. package/dist/{client-C-xdpu6M.mjs → client-DDy3-85E.mjs} +1 -1
  9. package/dist/compat/mod.cjs +1 -1
  10. package/dist/compat/mod.d.cts +1 -1
  11. package/dist/compat/mod.d.ts +1 -1
  12. package/dist/compat/transformers.test.mjs +3 -3
  13. package/dist/{context-BzSr5FCW.d.cts → context-CC4UrGc5.d.cts} +48 -6
  14. package/dist/{context-CyacVopT.d.ts → context-xfiK4xM5.d.ts} +48 -6
  15. package/dist/{docloader-DXUkyjIx.js → docloader-Ca6-eCr_.js} +121 -13
  16. package/dist/{docloader-9cG6ESUw.cjs → docloader-CvMstYam.cjs} +121 -13
  17. package/dist/{esm-Bfj-SwEx.mjs → esm-CzaH6D4W.mjs} +1 -1
  18. package/dist/federation/builder.test.mjs +3 -3
  19. package/dist/federation/collection.test.mjs +1 -1
  20. package/dist/federation/handler.test.mjs +1362 -46
  21. package/dist/federation/idempotency.test.mjs +5 -5
  22. package/dist/federation/inbox.test.mjs +3 -3
  23. package/dist/federation/keycache.test.mjs +3 -3
  24. package/dist/federation/kv.test.mjs +1 -1
  25. package/dist/federation/middleware.test.mjs +1586 -82
  26. package/dist/federation/mod.cjs +2 -2
  27. package/dist/federation/mod.d.cts +1 -1
  28. package/dist/federation/mod.d.ts +1 -1
  29. package/dist/federation/mod.js +1 -1
  30. package/dist/federation/mq.test.mjs +3 -3
  31. package/dist/federation/retry.test.mjs +2 -2
  32. package/dist/federation/router.test.mjs +2 -2
  33. package/dist/federation/send.test.mjs +8 -8
  34. package/dist/federation/temporal.test.d.mts +2 -0
  35. package/dist/federation/temporal.test.mjs +71 -0
  36. package/dist/{http-LjaXmp2m.cjs → http-B3o3SOXX.cjs} +3 -3
  37. package/dist/{http-CuloN7xQ.js → http-Bku28NB8.js} +3 -3
  38. package/dist/{http-D5CDiVKf.mjs → http-CiqAQGRx.mjs} +2 -2
  39. package/dist/{inbox-D0Mzd940.mjs → inbox-D3RCgSiJ.mjs} +7 -4
  40. package/dist/{key-B22mXs2u.cjs → key-BbdUjmdf.cjs} +2 -2
  41. package/dist/{key-B5QN42gR.mjs → key-C15RK-kf.mjs} +1 -1
  42. package/dist/{key-D1PkkNK-.js → key-CJU1QxP2.js} +2 -2
  43. package/dist/{key-CXkrXfz6.cjs → key-ClgfrNJf.cjs} +1 -1
  44. package/dist/{key-Dnc1ekhA.mjs → key-LJoRzwG2.mjs} +2 -2
  45. package/dist/{keycache-DwDRFAp7.mjs → keycache-BCuiTm4y.mjs} +1 -1
  46. package/dist/{keys-C4Ms2Cy-.mjs → keys-wZip1i2J.mjs} +1 -1
  47. package/dist/ld-BO_vEkla.mjs +548 -0
  48. package/dist/{lookup-D0d32cZH.cjs → lookup-Cs7LHObN.cjs} +1 -1
  49. package/dist/{lookup-B8rOR_1a.js → lookup-DRzvxZ-l.js} +1 -1
  50. package/dist/{lookup-Br7I7sqm.mjs → lookup-FvsTNqW8.mjs} +1 -1
  51. package/dist/{middleware-BlsPkr2X.mjs → middleware-Cdb7LDeG.mjs} +1 -1
  52. package/dist/{middleware-BbgpZrsX.mjs → middleware-CzjJsU2k.mjs} +320 -87
  53. package/dist/{middleware-0yq2uipZ.cjs → middleware-Dn5HfxXi.cjs} +411 -85
  54. package/dist/{middleware-CYNQWJ-D.js → middleware-DoM0y4tG.js} +408 -83
  55. package/dist/{middleware-BRXIidLb.cjs → middleware-SfuiAsBu.cjs} +1 -1
  56. package/dist/mod.cjs +10 -10
  57. package/dist/mod.d.cts +1 -1
  58. package/dist/mod.d.ts +1 -1
  59. package/dist/mod.js +9 -9
  60. package/dist/nodeinfo/client.test.mjs +3 -3
  61. package/dist/nodeinfo/handler.test.mjs +2 -2
  62. package/dist/nodeinfo/mod.cjs +1 -1
  63. package/dist/nodeinfo/mod.js +1 -1
  64. package/dist/nodeinfo/semver.test.mjs +1 -1
  65. package/dist/nodeinfo/types.test.mjs +1 -1
  66. package/dist/otel/exporter.test.mjs +1 -1
  67. package/dist/otel/mod.cjs +1 -1
  68. package/dist/{owner-D32qC-wF.mjs → owner-BRgVUFTA.mjs} +3 -3
  69. package/dist/{proof-u5ivh_eA.js → proof-BL5RXXp2.js} +300 -6
  70. package/dist/{proof-DE2Z0_uv.cjs → proof-BPEkbKl1.cjs} +347 -5
  71. package/dist/{proof-B67QOiuS.mjs → proof-De_2gCxi.mjs} +2 -2
  72. package/dist/runtime/authdocloader.test.mjs +6 -6
  73. package/dist/runtime/docloader.test.mjs +4 -4
  74. package/dist/runtime/key.test.mjs +3 -3
  75. package/dist/runtime/langstr.test.mjs +2 -2
  76. package/dist/runtime/link.test.mjs +2 -2
  77. package/dist/runtime/mod.cjs +3 -3
  78. package/dist/runtime/mod.js +3 -3
  79. package/dist/runtime/multibase/multibase.test.mjs +2 -2
  80. package/dist/runtime/url.test.mjs +53 -2
  81. package/dist/{send-7RGxOhrY.mjs → send-C7irF8CJ.mjs} +2 -2
  82. package/dist/sig/http.test.mjs +6 -6
  83. package/dist/sig/key.test.mjs +4 -4
  84. package/dist/sig/ld.test.mjs +561 -5
  85. package/dist/sig/mod.cjs +3 -3
  86. package/dist/sig/mod.js +3 -3
  87. package/dist/sig/owner.test.mjs +6 -6
  88. package/dist/sig/proof.test.mjs +4 -4
  89. package/dist/temporal-CtvhWksK.mjs +95 -0
  90. package/dist/testing/docloader.test.mjs +1 -1
  91. package/dist/testing/mod.d.mts +48 -6
  92. package/dist/testing/mod.mjs +1 -1
  93. package/dist/{testing-zWgaXBJW.mjs → testing-DskvUSfh.mjs} +2 -2
  94. package/dist/{transformers-BdbEtUZU.cjs → transformers-BbJsnOaL.cjs} +1 -1
  95. package/dist/{types-6_pWuZfK.js → types-B-GUdtNR.js} +1 -1
  96. package/dist/{types-ec4G8nGs.cjs → types-BWNGBD9D.cjs} +1 -1
  97. package/dist/vocab/actor.test.mjs +4 -4
  98. package/dist/vocab/cjs.test.mjs +1 -1
  99. package/dist/vocab/lookup.test.mjs +5 -5
  100. package/dist/vocab/mod.cjs +3 -3
  101. package/dist/vocab/mod.js +3 -3
  102. package/dist/vocab/type.test.mjs +2 -2
  103. package/dist/vocab/vocab.test.mjs +3 -3
  104. package/dist/{vocab-C60RNInZ.mjs → vocab-C0yDmtpE.mjs} +306 -198
  105. package/dist/webfinger/handler.test.mjs +3 -3
  106. package/dist/webfinger/lookup.test.mjs +3 -3
  107. package/dist/webfinger/mod.cjs +1 -1
  108. package/dist/webfinger/mod.js +1 -1
  109. package/dist/x/cfworkers.cjs +1 -1
  110. package/dist/x/cfworkers.test.mjs +1 -1
  111. package/dist/x/hono.cjs +1 -1
  112. package/dist/x/hono.d.cts +1 -1
  113. package/dist/x/hono.d.ts +1 -1
  114. package/dist/x/sveltekit.cjs +1 -1
  115. package/dist/x/sveltekit.d.cts +1 -1
  116. package/dist/x/sveltekit.d.ts +1 -1
  117. package/package.json +1 -1
  118. package/dist/ld-BJ8BZLC8.mjs +0 -254
  119. /package/dist/{denokv-NJPMXyK0.mjs → denokv-B0ZRIDsH.mjs} +0 -0
  120. /package/dist/{otel-0v4Zy01l.mjs → otel-D00WjYJ1.mjs} +0 -0
  121. /package/dist/{retry-Ddbq3AcK.mjs → retry-B_E3V_Dx.mjs} +0 -0
@@ -1,18 +1,19 @@
1
1
  import "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { C as Person, _ as Note, o as Create } from "../vocab-C60RNInZ.mjs";
5
- import { a as mockDocumentLoader, i as createRequestContext, r as createInboxContext, t as test } from "../testing-zWgaXBJW.mjs";
4
+ import { C as Person, _ as Note, o as Create } from "../vocab-C0yDmtpE.mjs";
5
+ import { a as mockDocumentLoader, i as createRequestContext, r as createInboxContext, t as test } from "../testing-DskvUSfh.mjs";
6
6
  import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
7
7
  import "../std__assert-2v7gYiZp.mjs";
8
- import { n as assertFalse } from "../assert_rejects-CJC9ThS-.mjs";
8
+ import { n as assertFalse, t as assertRejects } from "../assert_rejects-CJC9ThS-.mjs";
9
9
  import { t as assert } from "../assert-DikXweDx.mjs";
10
10
  import { t as MemoryKvStore } from "../kv-OuT2IU64.mjs";
11
- import { a as createFederation, c as handleCollection, d as handleObject, f as respondWithObject, l as handleCustomCollection, o as acceptsJsonLd, p as respondWithObjectIfAcceptable, s as handleActor, u as handleInbox } from "../middleware-BbgpZrsX.mjs";
12
- import { s as signRequest } from "../http-D5CDiVKf.mjs";
13
- import { t as InboxListenerSet } from "../inbox-D0Mzd940.mjs";
14
- import { t as createTestTracerProvider } from "../otel-0v4Zy01l.mjs";
15
- import { a as rsaPrivateKey3, c as rsaPublicKey3, s as rsaPublicKey2 } from "../keys-C4Ms2Cy-.mjs";
11
+ import { a as createFederation, c as handleCollection, d as handleObject, f as respondWithObject, l as handleCustomCollection, o as acceptsJsonLd, p as respondWithObjectIfAcceptable, s as handleActor, u as handleInbox } from "../middleware-CzjJsU2k.mjs";
12
+ import { s as signRequest } from "../http-CiqAQGRx.mjs";
13
+ import { a as compactJsonLd, f as signJsonLd } from "../ld-BO_vEkla.mjs";
14
+ import { t as InboxListenerSet } from "../inbox-D3RCgSiJ.mjs";
15
+ import { t as createTestTracerProvider } from "../otel-D00WjYJ1.mjs";
16
+ import { a as rsaPrivateKey3, c as rsaPublicKey3, s as rsaPublicKey2 } from "../keys-wZip1i2J.mjs";
16
17
  //#region src/federation/handler.test.ts
17
18
  test("acceptsJsonLd()", () => {
18
19
  assert(acceptsJsonLd(new Request("https://example.com/", { headers: { Accept: "application/activity+json" } })));
@@ -967,6 +968,11 @@ test("handleInbox()", async () => {
967
968
  if (identifier !== "someone") return null;
968
969
  return new Person({ name: "Someone" });
969
970
  };
971
+ const restrictiveContextLoader = async (resource) => {
972
+ const url = new URL(resource).href;
973
+ if (url === "https://www.w3.org/ns/activitystreams" || url === "https://w3id.org/identity/v1") return await mockDocumentLoader(url);
974
+ throw new Error(`Unexpected context: ${url}`);
975
+ };
970
976
  const inboxOptions = {
971
977
  kv: new MemoryKvStore(),
972
978
  kvPrefixes: {
@@ -1035,6 +1041,49 @@ test("handleInbox()", async () => {
1035
1041
  });
1036
1042
  assertEquals(onNotFoundCalled, null);
1037
1043
  assertEquals(response.status, 401);
1044
+ const malformedProofCreatedRequest = new Request("https://example.com/", {
1045
+ method: "POST",
1046
+ body: JSON.stringify({
1047
+ "@context": ["https://www.w3.org/ns/activitystreams", "https://w3id.org/security/data-integrity/v1"],
1048
+ id: "https://example.com/activities/invalid-proof-created",
1049
+ type: "Create",
1050
+ actor: "https://example.com/person2",
1051
+ object: {
1052
+ id: "https://example.com/notes/invalid-proof-created",
1053
+ type: "Note",
1054
+ attributedTo: "https://example.com/person2",
1055
+ content: "Hello, world!"
1056
+ },
1057
+ proof: {
1058
+ type: "DataIntegrityProof",
1059
+ cryptosuite: "eddsa-jcs-2022",
1060
+ verificationMethod: "https://example.com/person2#main-key",
1061
+ proofPurpose: "assertionMethod",
1062
+ created: { "@value": "not-a-date" },
1063
+ proofValue: "zLaewdp4H9kqtwyrLatK4cjY5oRHwVcw4gibPSUDYDMhi4M49v8pcYk3ZB6D69dNpAPbUmY8ocuJ3m9KhKJEEg7z"
1064
+ }
1065
+ })
1066
+ });
1067
+ const malformedProofCreatedContext = createRequestContext({
1068
+ federation,
1069
+ request: malformedProofCreatedRequest,
1070
+ url: new URL(malformedProofCreatedRequest.url),
1071
+ data: void 0,
1072
+ documentLoader: mockDocumentLoader,
1073
+ contextLoader: mockDocumentLoader
1074
+ });
1075
+ response = await handleInbox(malformedProofCreatedRequest, {
1076
+ recipient: null,
1077
+ context: malformedProofCreatedContext,
1078
+ inboxContextFactory(_activity) {
1079
+ return createInboxContext({
1080
+ ...malformedProofCreatedContext,
1081
+ clone: void 0
1082
+ });
1083
+ },
1084
+ ...inboxOptions
1085
+ });
1086
+ assertEquals([response.status, await response.text()], [400, "Invalid activity."]);
1038
1087
  onNotFoundCalled = null;
1039
1088
  const signedRequest = await signRequest(unsignedRequest.clone(), rsaPrivateKey3, rsaPublicKey3.id);
1040
1089
  const signedContext = createRequestContext({
@@ -1057,85 +1106,1352 @@ test("handleInbox()", async () => {
1057
1106
  });
1058
1107
  assertEquals(onNotFoundCalled, null);
1059
1108
  assertEquals([response.status, await response.text()], [202, ""]);
1060
- response = await handleInbox(signedRequest, {
1061
- recipient: "someone",
1062
- context: signedContext,
1109
+ const ldSignedRequest = new Request("https://example.com/", {
1110
+ method: "POST",
1111
+ body: JSON.stringify(await signJsonLd({
1112
+ "@context": [
1113
+ "https://www.w3.org/ns/activitystreams",
1114
+ "https://w3id.org/identity/v1",
1115
+ "https://w3id.org/security/v1",
1116
+ "https://w3id.org/security/data-integrity/v1"
1117
+ ],
1118
+ id: "https://example.com/activities/ld-signed",
1119
+ type: "Create",
1120
+ actor: "https://example.com/person2",
1121
+ object: {
1122
+ id: "https://example.com/notes/ld-signed",
1123
+ type: "Note",
1124
+ attributedTo: "https://example.com/person2",
1125
+ content: "Hello, world!"
1126
+ }
1127
+ }, rsaPrivateKey3, rsaPublicKey3.id, { contextLoader: mockDocumentLoader }))
1128
+ });
1129
+ const ldSignedContext = createRequestContext({
1130
+ federation,
1131
+ request: ldSignedRequest,
1132
+ url: new URL(ldSignedRequest.url),
1133
+ data: void 0,
1134
+ documentLoader: mockDocumentLoader,
1135
+ contextLoader: restrictiveContextLoader
1136
+ });
1137
+ response = await handleInbox(ldSignedRequest, {
1138
+ recipient: null,
1139
+ context: ldSignedContext,
1063
1140
  inboxContextFactory(_activity) {
1064
1141
  return createInboxContext({
1065
- ...unsignedContext,
1066
- clone: void 0,
1067
- recipient: "someone"
1142
+ ...ldSignedContext,
1143
+ clone: void 0
1068
1144
  });
1069
1145
  },
1070
1146
  ...inboxOptions
1071
1147
  });
1072
1148
  assertEquals(onNotFoundCalled, null);
1073
1149
  assertEquals([response.status, await response.text()], [202, ""]);
1074
- response = await handleInbox(unsignedRequest, {
1150
+ const remoteContextUrl = "https://remote.example/contexts/ext";
1151
+ let failRemoteContextOnce = true;
1152
+ const flakyContextLoader = async (resource) => {
1153
+ const url = new URL(resource).href;
1154
+ if (url === remoteContextUrl) {
1155
+ if (failRemoteContextOnce) {
1156
+ failRemoteContextOnce = false;
1157
+ throw new Error(`Unexpected context: ${url}`);
1158
+ }
1159
+ return {
1160
+ contextUrl: null,
1161
+ documentUrl: url,
1162
+ document: { "@context": { ext: "https://example.com/ext" } }
1163
+ };
1164
+ }
1165
+ return await mockDocumentLoader(url);
1166
+ };
1167
+ const httpSignedLdBody = {
1168
+ "@context": [remoteContextUrl, "https://www.w3.org/ns/activitystreams"],
1169
+ id: "https://example.com/activities/http-signed-ld",
1170
+ type: "Create",
1171
+ actor: "https://example.com/person2",
1172
+ ext: "preserve-me",
1173
+ object: {
1174
+ id: "https://example.com/notes/http-signed-ld",
1175
+ type: "Note",
1176
+ attributedTo: "https://example.com/person2",
1177
+ content: "Hello, world!"
1178
+ },
1179
+ signature: {
1180
+ type: "RsaSignature2017",
1181
+ creator: rsaPublicKey3.id.href,
1182
+ created: "2024-01-01T00:00:00Z",
1183
+ signatureValue: "bogus"
1184
+ }
1185
+ };
1186
+ const httpSignedLdRequest = await signRequest(new Request("https://example.com/", {
1187
+ method: "POST",
1188
+ body: JSON.stringify(httpSignedLdBody)
1189
+ }), rsaPrivateKey3, rsaPublicKey3.id);
1190
+ const httpSignedLdContext = createRequestContext({
1191
+ federation,
1192
+ request: httpSignedLdRequest,
1193
+ url: new URL(httpSignedLdRequest.url),
1194
+ data: void 0,
1195
+ documentLoader: mockDocumentLoader,
1196
+ contextLoader: flakyContextLoader
1197
+ });
1198
+ response = await handleInbox(httpSignedLdRequest, {
1075
1199
  recipient: null,
1076
- context: unsignedContext,
1200
+ context: httpSignedLdContext,
1077
1201
  inboxContextFactory(_activity) {
1078
1202
  return createInboxContext({
1079
- ...unsignedContext,
1203
+ ...httpSignedLdContext,
1080
1204
  clone: void 0
1081
1205
  });
1082
1206
  },
1083
- ...inboxOptions,
1084
- skipSignatureVerification: true
1207
+ ...inboxOptions
1085
1208
  });
1086
1209
  assertEquals(onNotFoundCalled, null);
1087
- assertEquals(response.status, 202);
1088
- response = await handleInbox(unsignedRequest, {
1089
- recipient: "someone",
1090
- context: unsignedContext,
1210
+ assertEquals([response.status, await response.text()], [202, ""]);
1211
+ const ldSignedOnlyBody = await signJsonLd({
1212
+ "@context": [remoteContextUrl, "https://www.w3.org/ns/activitystreams"],
1213
+ id: "https://example.com/activities/ld-only-transient",
1214
+ type: "Create",
1215
+ actor: "https://example.com/person2",
1216
+ ext: "preserve-me",
1217
+ object: {
1218
+ id: "https://example.com/notes/ld-only-transient",
1219
+ type: "Note",
1220
+ attributedTo: "https://example.com/person2",
1221
+ content: "Hello, world!"
1222
+ }
1223
+ }, rsaPrivateKey3, rsaPublicKey3.id, { contextLoader: async (resource) => {
1224
+ const url = new URL(resource).href;
1225
+ if (url === remoteContextUrl) return {
1226
+ contextUrl: null,
1227
+ documentUrl: url,
1228
+ document: { "@context": { ext: "https://example.com/ext" } }
1229
+ };
1230
+ return await mockDocumentLoader(url);
1231
+ } });
1232
+ const malformedTemporalLdSignedBody = await signJsonLd({
1233
+ "@context": "https://www.w3.org/ns/activitystreams",
1234
+ id: "https://example.com/activities/ld-only-invalid-published",
1235
+ type: "Create",
1236
+ actor: "https://example.com/person2",
1237
+ published: { "@value": "not-a-date" },
1238
+ object: {
1239
+ id: "https://example.com/notes/ld-only-invalid-published",
1240
+ type: "Note",
1241
+ attributedTo: "https://example.com/person2",
1242
+ content: "Hello, world!"
1243
+ }
1244
+ }, rsaPrivateKey3, rsaPublicKey3.id, { contextLoader: mockDocumentLoader });
1245
+ const malformedTemporalLdSignedRequest = new Request("https://example.com/", {
1246
+ method: "POST",
1247
+ body: JSON.stringify(malformedTemporalLdSignedBody)
1248
+ });
1249
+ const malformedTemporalLdSignedContext = createRequestContext({
1250
+ federation,
1251
+ request: malformedTemporalLdSignedRequest,
1252
+ url: new URL(malformedTemporalLdSignedRequest.url),
1253
+ data: void 0,
1254
+ documentLoader: mockDocumentLoader,
1255
+ contextLoader: mockDocumentLoader
1256
+ });
1257
+ response = await handleInbox(malformedTemporalLdSignedRequest, {
1258
+ recipient: null,
1259
+ context: malformedTemporalLdSignedContext,
1091
1260
  inboxContextFactory(_activity) {
1092
1261
  return createInboxContext({
1093
- ...unsignedContext,
1094
- clone: void 0,
1095
- recipient: "someone"
1262
+ ...malformedTemporalLdSignedContext,
1263
+ clone: void 0
1096
1264
  });
1097
1265
  },
1098
- ...inboxOptions,
1099
- skipSignatureVerification: true
1266
+ ...inboxOptions
1100
1267
  });
1101
- assertEquals(onNotFoundCalled, null);
1102
- assertEquals(response.status, 202);
1103
- const signedInvalidRequest = await signRequest(new Request("https://example.com/", {
1268
+ assertEquals([response.status, await response.text()], [400, "Invalid activity."]);
1269
+ const malformedClosedLdSignedBody = await signJsonLd({
1270
+ "@context": "https://www.w3.org/ns/activitystreams",
1271
+ id: "https://example.com/questions/ld-only-invalid-closed",
1272
+ type: "Question",
1273
+ closed: "2024-02-31T00:00:00Z"
1274
+ }, rsaPrivateKey3, rsaPublicKey3.id, { contextLoader: mockDocumentLoader });
1275
+ const malformedClosedLdSignedRequest = new Request("https://example.com/", {
1276
+ method: "POST",
1277
+ body: JSON.stringify(malformedClosedLdSignedBody)
1278
+ });
1279
+ const malformedClosedLdSignedContext = createRequestContext({
1280
+ federation,
1281
+ request: malformedClosedLdSignedRequest,
1282
+ url: new URL(malformedClosedLdSignedRequest.url),
1283
+ data: void 0,
1284
+ documentLoader: mockDocumentLoader,
1285
+ contextLoader: mockDocumentLoader
1286
+ });
1287
+ response = await handleInbox(malformedClosedLdSignedRequest, {
1288
+ recipient: null,
1289
+ context: malformedClosedLdSignedContext,
1290
+ inboxContextFactory(_activity) {
1291
+ return createInboxContext({
1292
+ ...malformedClosedLdSignedContext,
1293
+ clone: void 0
1294
+ });
1295
+ },
1296
+ ...inboxOptions
1297
+ });
1298
+ assertEquals([response.status, await response.text()], [400, "Invalid activity."]);
1299
+ const malformedIriHttpSignedRequest = await signRequest(new Request("https://example.com/", {
1104
1300
  method: "POST",
1105
1301
  body: JSON.stringify({
1106
- "@context": [
1107
- "https://www.w3.org/ns/activitystreams",
1108
- true,
1109
- 23
1110
- ],
1302
+ "@context": "https://www.w3.org/ns/activitystreams",
1303
+ id: "http://[",
1111
1304
  type: "Create",
1305
+ actor: "https://example.com/person2",
1112
1306
  object: {
1307
+ id: "https://example.com/notes/http-signed-invalid-iri",
1113
1308
  type: "Note",
1309
+ attributedTo: "https://example.com/person2",
1114
1310
  content: "Hello, world!"
1115
- },
1116
- actor: "https://example.com/users/alice"
1311
+ }
1117
1312
  })
1118
1313
  }), rsaPrivateKey3, rsaPublicKey3.id);
1119
- const signedInvalidContext = createRequestContext({
1314
+ const malformedIriHttpSignedContext = createRequestContext({
1120
1315
  federation,
1121
- request: signedInvalidRequest,
1122
- url: new URL(signedInvalidRequest.url),
1316
+ request: malformedIriHttpSignedRequest,
1317
+ url: new URL(malformedIriHttpSignedRequest.url),
1123
1318
  data: void 0,
1124
- documentLoader: mockDocumentLoader
1319
+ documentLoader: mockDocumentLoader,
1320
+ contextLoader: mockDocumentLoader
1125
1321
  });
1126
- response = await handleInbox(signedInvalidRequest, {
1322
+ response = await handleInbox(malformedIriHttpSignedRequest, {
1127
1323
  recipient: null,
1128
- context: signedContext,
1324
+ context: malformedIriHttpSignedContext,
1129
1325
  inboxContextFactory(_activity) {
1130
1326
  return createInboxContext({
1131
- ...signedInvalidContext,
1327
+ ...malformedIriHttpSignedContext,
1328
+ clone: void 0
1329
+ });
1330
+ },
1331
+ ...inboxOptions
1332
+ });
1333
+ assertEquals([response.status, await response.text()], [400, "Invalid activity."]);
1334
+ const ldSignedOnlyRequest = new Request("https://example.com/", {
1335
+ method: "POST",
1336
+ body: JSON.stringify(ldSignedOnlyBody)
1337
+ });
1338
+ const ldSignedOnlyContext = createRequestContext({
1339
+ federation,
1340
+ request: ldSignedOnlyRequest,
1341
+ url: new URL(ldSignedOnlyRequest.url),
1342
+ data: void 0,
1343
+ documentLoader: mockDocumentLoader,
1344
+ contextLoader: async (resource) => {
1345
+ const url = new URL(resource).href;
1346
+ if (url === remoteContextUrl) throw new Error(`Unexpected context: ${url}`);
1347
+ return await mockDocumentLoader(url);
1348
+ }
1349
+ });
1350
+ await assertRejects(() => handleInbox(ldSignedOnlyRequest, {
1351
+ recipient: null,
1352
+ context: ldSignedOnlyContext,
1353
+ inboxContextFactory(_activity) {
1354
+ return createInboxContext({
1355
+ ...ldSignedOnlyContext,
1356
+ clone: void 0
1357
+ });
1358
+ },
1359
+ ...inboxOptions
1360
+ }), Error);
1361
+ failRemoteContextOnce = true;
1362
+ const invalidHttpFallbackRequest = new Request("https://example.com/", {
1363
+ method: "POST",
1364
+ body: JSON.stringify(ldSignedOnlyBody),
1365
+ headers: { Signature: "bogus" }
1366
+ });
1367
+ const invalidHttpFallbackContext = createRequestContext({
1368
+ federation,
1369
+ request: invalidHttpFallbackRequest,
1370
+ url: new URL(invalidHttpFallbackRequest.url),
1371
+ data: void 0,
1372
+ documentLoader: mockDocumentLoader,
1373
+ contextLoader: flakyContextLoader
1374
+ });
1375
+ await assertRejects(() => handleInbox(invalidHttpFallbackRequest, {
1376
+ recipient: null,
1377
+ context: invalidHttpFallbackContext,
1378
+ inboxContextFactory(_activity) {
1379
+ return createInboxContext({
1380
+ ...invalidHttpFallbackContext,
1381
+ clone: void 0
1382
+ });
1383
+ },
1384
+ ...inboxOptions
1385
+ }), Error);
1386
+ const transientKeyContextUrl = "https://remote.example/contexts/key";
1387
+ const transientCreatorUrl = "https://remote.example/keys/transient#main-key";
1388
+ const verificationFailureLdSignedBody = await signJsonLd({
1389
+ "@context": "https://www.w3.org/ns/activitystreams",
1390
+ id: "https://example.com/activities/ld-key-fetch-transient",
1391
+ type: "Create",
1392
+ actor: "https://example.com/person2",
1393
+ object: {
1394
+ id: "https://example.com/notes/ld-key-fetch-transient",
1395
+ type: "Note",
1396
+ attributedTo: "https://example.com/person2",
1397
+ content: "Hello, world!"
1398
+ }
1399
+ }, rsaPrivateKey3, new URL(transientCreatorUrl), { contextLoader: mockDocumentLoader });
1400
+ const verificationFailureLdSignedRequest = new Request("https://example.com/", {
1401
+ method: "POST",
1402
+ body: JSON.stringify(verificationFailureLdSignedBody),
1403
+ headers: { Signature: "bogus" }
1404
+ });
1405
+ const verificationFailureLdSignedContext = createRequestContext({
1406
+ federation,
1407
+ request: verificationFailureLdSignedRequest,
1408
+ url: new URL(verificationFailureLdSignedRequest.url),
1409
+ data: void 0,
1410
+ documentLoader: async (resource) => {
1411
+ if (resource === transientCreatorUrl) return {
1412
+ contextUrl: null,
1413
+ documentUrl: resource,
1414
+ document: {
1415
+ "@context": [transientKeyContextUrl],
1416
+ id: resource
1417
+ }
1418
+ };
1419
+ return await mockDocumentLoader(new URL(resource).href);
1420
+ },
1421
+ contextLoader: async (resource) => {
1422
+ if (resource === transientKeyContextUrl) throw new Error(`Transient key context failure: ${resource}`);
1423
+ return await mockDocumentLoader(new URL(resource).href);
1424
+ }
1425
+ });
1426
+ response = await handleInbox(verificationFailureLdSignedRequest, {
1427
+ recipient: null,
1428
+ context: verificationFailureLdSignedContext,
1429
+ inboxContextFactory(_activity) {
1430
+ return createInboxContext({
1431
+ ...verificationFailureLdSignedContext,
1432
+ clone: void 0
1433
+ });
1434
+ },
1435
+ ...inboxOptions
1436
+ });
1437
+ assertEquals([response.status, await response.text()], [401, "Failed to verify the request signature."]);
1438
+ failRemoteContextOnce = true;
1439
+ const deferredMalformedTemporalLdSignedBody = await signJsonLd({
1440
+ "@context": [remoteContextUrl, "https://www.w3.org/ns/activitystreams"],
1441
+ id: "https://example.com/activities/deferred-invalid-published",
1442
+ type: "Create",
1443
+ actor: "https://example.com/person2",
1444
+ ext: "preserve-me",
1445
+ published: { "@value": "not-a-date" },
1446
+ object: {
1447
+ id: "https://example.com/notes/deferred-invalid-published",
1448
+ type: "Note",
1449
+ attributedTo: "https://example.com/person2",
1450
+ content: "Hello, world!"
1451
+ }
1452
+ }, rsaPrivateKey3, rsaPublicKey3.id, { contextLoader: async (resource) => {
1453
+ const url = new URL(resource).href;
1454
+ if (url === remoteContextUrl) return {
1455
+ contextUrl: null,
1456
+ documentUrl: url,
1457
+ document: { "@context": { ext: "https://example.com/ext" } }
1458
+ };
1459
+ return await mockDocumentLoader(url);
1460
+ } });
1461
+ const deferredMalformedTemporalLdSignedRequest = new Request("https://example.com/", {
1462
+ method: "POST",
1463
+ body: JSON.stringify(deferredMalformedTemporalLdSignedBody),
1464
+ headers: { Signature: "bogus" }
1465
+ });
1466
+ const deferredMalformedTemporalLdSignedContext = createRequestContext({
1467
+ federation,
1468
+ request: deferredMalformedTemporalLdSignedRequest,
1469
+ url: new URL(deferredMalformedTemporalLdSignedRequest.url),
1470
+ data: void 0,
1471
+ documentLoader: mockDocumentLoader,
1472
+ contextLoader: flakyContextLoader
1473
+ });
1474
+ response = await handleInbox(deferredMalformedTemporalLdSignedRequest, {
1475
+ recipient: null,
1476
+ context: deferredMalformedTemporalLdSignedContext,
1477
+ inboxContextFactory(_activity) {
1478
+ return createInboxContext({
1479
+ ...deferredMalformedTemporalLdSignedContext,
1480
+ clone: void 0
1481
+ });
1482
+ },
1483
+ ...inboxOptions
1484
+ });
1485
+ assertEquals([response.status, await response.text()], [400, "Invalid activity."]);
1486
+ const malformedLdSignedRequest = new Request("https://example.com/", {
1487
+ method: "POST",
1488
+ body: JSON.stringify({
1489
+ ...ldSignedOnlyBody,
1490
+ "@context": ["not a url", "https://www.w3.org/ns/activitystreams"]
1491
+ })
1492
+ });
1493
+ const malformedLdSignedContext = createRequestContext({
1494
+ federation,
1495
+ request: malformedLdSignedRequest,
1496
+ url: new URL(malformedLdSignedRequest.url),
1497
+ data: void 0,
1498
+ documentLoader: mockDocumentLoader,
1499
+ contextLoader: mockDocumentLoader
1500
+ });
1501
+ response = await handleInbox(malformedLdSignedRequest, {
1502
+ recipient: null,
1503
+ context: malformedLdSignedContext,
1504
+ inboxContextFactory(_activity) {
1505
+ return createInboxContext({
1506
+ ...malformedLdSignedContext,
1507
+ clone: void 0
1508
+ });
1509
+ },
1510
+ ...inboxOptions
1511
+ });
1512
+ assertEquals([response.status, await response.text()], [400, "Invalid JSON-LD."]);
1513
+ const dualSignedInvalidCreatorRequest = await signRequest(new Request("https://example.com/", {
1514
+ method: "POST",
1515
+ body: JSON.stringify({
1516
+ ...httpSignedLdBody,
1517
+ signature: {
1518
+ ...httpSignedLdBody.signature,
1519
+ creator: "not a url"
1520
+ }
1521
+ })
1522
+ }), rsaPrivateKey3, rsaPublicKey3.id);
1523
+ const dualSignedInvalidCreatorContext = createRequestContext({
1524
+ federation,
1525
+ request: dualSignedInvalidCreatorRequest,
1526
+ url: new URL(dualSignedInvalidCreatorRequest.url),
1527
+ data: void 0,
1528
+ documentLoader: mockDocumentLoader,
1529
+ contextLoader: flakyContextLoader
1530
+ });
1531
+ response = await handleInbox(dualSignedInvalidCreatorRequest, {
1532
+ recipient: null,
1533
+ context: dualSignedInvalidCreatorContext,
1534
+ inboxContextFactory(_activity) {
1535
+ return createInboxContext({
1536
+ ...dualSignedInvalidCreatorContext,
1132
1537
  clone: void 0
1133
1538
  });
1134
1539
  },
1135
1540
  ...inboxOptions
1136
1541
  });
1137
1542
  assertEquals(onNotFoundCalled, null);
1138
- assertEquals(response.status, 400);
1543
+ assertEquals([response.status, await response.text()], [202, ""]);
1544
+ const invalidUrlHttpSignedRequest = await signRequest(new Request("https://example.com/", {
1545
+ method: "POST",
1546
+ body: JSON.stringify({
1547
+ "@context": [remoteContextUrl, "https://www.w3.org/ns/activitystreams"],
1548
+ id: "https://example.com/activities/http-signed-invalid-context",
1549
+ type: "Create",
1550
+ actor: "https://example.com/person2",
1551
+ ext: "preserve-me",
1552
+ object: {
1553
+ id: "https://example.com/notes/http-signed-invalid-context",
1554
+ type: "Note",
1555
+ attributedTo: "https://example.com/person2",
1556
+ content: "Hello, world!"
1557
+ }
1558
+ })
1559
+ }), rsaPrivateKey3, rsaPublicKey3.id);
1560
+ const invalidUrlHttpSignedContext = createRequestContext({
1561
+ federation,
1562
+ request: invalidUrlHttpSignedRequest,
1563
+ url: new URL(invalidUrlHttpSignedRequest.url),
1564
+ data: void 0,
1565
+ documentLoader: mockDocumentLoader,
1566
+ contextLoader: async (resource) => {
1567
+ const url = new URL(resource).href;
1568
+ if (url === remoteContextUrl) {
1569
+ const error = /* @__PURE__ */ new Error(`Transient remote context failure: ${url}`);
1570
+ error.name = "jsonld.InvalidUrl";
1571
+ error.details = {
1572
+ code: "loading remote context failed",
1573
+ url
1574
+ };
1575
+ throw error;
1576
+ }
1577
+ return await mockDocumentLoader(url);
1578
+ }
1579
+ });
1580
+ await assertRejects(() => handleInbox(invalidUrlHttpSignedRequest, {
1581
+ recipient: null,
1582
+ context: invalidUrlHttpSignedContext,
1583
+ inboxContextFactory(_activity) {
1584
+ return createInboxContext({
1585
+ ...invalidUrlHttpSignedContext,
1586
+ clone: void 0
1587
+ });
1588
+ },
1589
+ ...inboxOptions
1590
+ }), Error);
1591
+ const opaqueContextIdHttpSignedRequest = await signRequest(new Request("https://example.com/", {
1592
+ method: "POST",
1593
+ body: JSON.stringify({
1594
+ "@context": ["app-context", "https://www.w3.org/ns/activitystreams"],
1595
+ id: "https://example.com/activities/http-signed-opaque-context",
1596
+ type: "Create",
1597
+ actor: "https://example.com/person2",
1598
+ object: {
1599
+ id: "https://example.com/notes/http-signed-opaque-context",
1600
+ type: "Note",
1601
+ attributedTo: "https://example.com/person2",
1602
+ content: "Hello, world!"
1603
+ }
1604
+ })
1605
+ }), rsaPrivateKey3, rsaPublicKey3.id);
1606
+ const opaqueContextIdHttpSignedContext = createRequestContext({
1607
+ federation,
1608
+ request: opaqueContextIdHttpSignedRequest,
1609
+ url: new URL(opaqueContextIdHttpSignedRequest.url),
1610
+ data: void 0,
1611
+ documentLoader: mockDocumentLoader,
1612
+ contextLoader: async (resource) => {
1613
+ if (resource === "app-context") {
1614
+ const error = /* @__PURE__ */ new Error(`Opaque context backend is unavailable: ${resource}`);
1615
+ error.name = "jsonld.InvalidUrl";
1616
+ error.details = {
1617
+ code: "loading remote context failed",
1618
+ url: resource
1619
+ };
1620
+ throw error;
1621
+ }
1622
+ return await mockDocumentLoader(new URL(resource).href);
1623
+ }
1624
+ });
1625
+ await assertRejects(() => handleInbox(opaqueContextIdHttpSignedRequest, {
1626
+ recipient: null,
1627
+ context: opaqueContextIdHttpSignedContext,
1628
+ inboxContextFactory(_activity) {
1629
+ return createInboxContext({
1630
+ ...opaqueContextIdHttpSignedContext,
1631
+ clone: void 0
1632
+ });
1633
+ },
1634
+ ...inboxOptions
1635
+ }), Error);
1636
+ const opaqueContextTypeErrorHttpSignedRequest = await signRequest(new Request("https://example.com/", {
1637
+ method: "POST",
1638
+ body: JSON.stringify({
1639
+ "@context": ["app:context", "https://www.w3.org/ns/activitystreams"],
1640
+ id: "https://example.com/activities/http-signed-opaque-typeerror",
1641
+ type: "Create",
1642
+ actor: "https://example.com/person2",
1643
+ object: {
1644
+ id: "https://example.com/notes/http-signed-opaque-typeerror",
1645
+ type: "Note",
1646
+ attributedTo: "https://example.com/person2",
1647
+ content: "Hello, world!"
1648
+ }
1649
+ })
1650
+ }), rsaPrivateKey3, rsaPublicKey3.id);
1651
+ const opaqueContextTypeErrorHttpSignedContext = createRequestContext({
1652
+ federation,
1653
+ request: opaqueContextTypeErrorHttpSignedRequest,
1654
+ url: new URL(opaqueContextTypeErrorHttpSignedRequest.url),
1655
+ data: void 0,
1656
+ documentLoader: mockDocumentLoader,
1657
+ contextLoader: async (resource) => {
1658
+ if (resource === "app:context") throw new TypeError(`Invalid URL: ${resource}`);
1659
+ return await mockDocumentLoader(new URL(resource).href);
1660
+ }
1661
+ });
1662
+ await assertRejects(() => handleInbox(opaqueContextTypeErrorHttpSignedRequest, {
1663
+ recipient: null,
1664
+ context: opaqueContextTypeErrorHttpSignedContext,
1665
+ inboxContextFactory(_activity) {
1666
+ return createInboxContext({
1667
+ ...opaqueContextTypeErrorHttpSignedContext,
1668
+ clone: void 0
1669
+ });
1670
+ },
1671
+ ...inboxOptions
1672
+ }), Error);
1673
+ const networkPathContextHttpSignedRequest = await signRequest(new Request("https://example.com/", {
1674
+ method: "POST",
1675
+ body: JSON.stringify({
1676
+ "@context": ["//cdn.example/ctx", "https://www.w3.org/ns/activitystreams"],
1677
+ id: "https://example.com/activities/http-signed-network-path-context",
1678
+ type: "Create",
1679
+ actor: "https://example.com/person2",
1680
+ object: {
1681
+ id: "https://example.com/notes/http-signed-network-path-context",
1682
+ type: "Note",
1683
+ attributedTo: "https://example.com/person2",
1684
+ content: "Hello, world!"
1685
+ }
1686
+ })
1687
+ }), rsaPrivateKey3, rsaPublicKey3.id);
1688
+ const networkPathContextHttpSignedContext = createRequestContext({
1689
+ federation,
1690
+ request: networkPathContextHttpSignedRequest,
1691
+ url: new URL(networkPathContextHttpSignedRequest.url),
1692
+ data: void 0,
1693
+ documentLoader: mockDocumentLoader,
1694
+ contextLoader: async (resource) => {
1695
+ if (resource === "//cdn.example/ctx") {
1696
+ const error = /* @__PURE__ */ new Error(`Network-path context backend is unavailable: ${resource}`);
1697
+ error.name = "jsonld.InvalidUrl";
1698
+ error.details = {
1699
+ code: "loading remote context failed",
1700
+ url: resource
1701
+ };
1702
+ throw error;
1703
+ }
1704
+ return await mockDocumentLoader(new URL(resource).href);
1705
+ }
1706
+ });
1707
+ await assertRejects(() => handleInbox(networkPathContextHttpSignedRequest, {
1708
+ recipient: null,
1709
+ context: networkPathContextHttpSignedContext,
1710
+ inboxContextFactory(_activity) {
1711
+ return createInboxContext({
1712
+ ...networkPathContextHttpSignedContext,
1713
+ clone: void 0
1714
+ });
1715
+ },
1716
+ ...inboxOptions
1717
+ }), Error);
1718
+ const malformedNetworkPathContextHttpSignedRequest = await signRequest(new Request("https://example.com/", {
1719
+ method: "POST",
1720
+ body: JSON.stringify({
1721
+ "@context": ["//[", "https://www.w3.org/ns/activitystreams"],
1722
+ id: "https://example.com/activities/http-signed-malformed-network-path-context",
1723
+ type: "Create",
1724
+ actor: "https://example.com/person2",
1725
+ object: {
1726
+ id: "https://example.com/notes/http-signed-malformed-network-path-context",
1727
+ type: "Note",
1728
+ attributedTo: "https://example.com/person2",
1729
+ content: "Hello, world!"
1730
+ }
1731
+ })
1732
+ }), rsaPrivateKey3, rsaPublicKey3.id);
1733
+ const malformedNetworkPathContextHttpSignedContext = createRequestContext({
1734
+ federation,
1735
+ request: malformedNetworkPathContextHttpSignedRequest,
1736
+ url: new URL(malformedNetworkPathContextHttpSignedRequest.url),
1737
+ data: void 0,
1738
+ documentLoader: mockDocumentLoader,
1739
+ contextLoader: async (resource) => {
1740
+ if (resource === "//[") {
1741
+ const error = /* @__PURE__ */ new Error(`Malformed network-path context: ${resource}`);
1742
+ error.name = "jsonld.InvalidUrl";
1743
+ error.details = {
1744
+ code: "loading remote context failed",
1745
+ url: resource
1746
+ };
1747
+ throw error;
1748
+ }
1749
+ return await mockDocumentLoader(new URL(resource).href);
1750
+ }
1751
+ });
1752
+ response = await handleInbox(malformedNetworkPathContextHttpSignedRequest, {
1753
+ recipient: null,
1754
+ context: malformedNetworkPathContextHttpSignedContext,
1755
+ inboxContextFactory(_activity) {
1756
+ return createInboxContext({
1757
+ ...malformedNetworkPathContextHttpSignedContext,
1758
+ clone: void 0
1759
+ });
1760
+ },
1761
+ ...inboxOptions
1762
+ });
1763
+ assertEquals(response.status, 400);
1764
+ const malformedUrlLikeContextHttpSignedRequest = await signRequest(new Request("https://example.com/", {
1765
+ method: "POST",
1766
+ body: JSON.stringify({
1767
+ "@context": ["http://[", "https://www.w3.org/ns/activitystreams"],
1768
+ id: "https://example.com/activities/http-signed-malformed-url-like-context",
1769
+ type: "Create",
1770
+ actor: "https://example.com/person2",
1771
+ object: {
1772
+ id: "https://example.com/notes/http-signed-malformed-url-like-context",
1773
+ type: "Note",
1774
+ attributedTo: "https://example.com/person2",
1775
+ content: "Hello, world!"
1776
+ }
1777
+ })
1778
+ }), rsaPrivateKey3, rsaPublicKey3.id);
1779
+ const malformedUrlLikeContextHttpSignedContext = createRequestContext({
1780
+ federation,
1781
+ request: malformedUrlLikeContextHttpSignedRequest,
1782
+ url: new URL(malformedUrlLikeContextHttpSignedRequest.url),
1783
+ data: void 0,
1784
+ documentLoader: mockDocumentLoader,
1785
+ contextLoader: async (resource) => {
1786
+ if (resource === "http://[") {
1787
+ const error = /* @__PURE__ */ new Error(`Invalid remote context URL: ${resource}`);
1788
+ error.name = "jsonld.InvalidUrl";
1789
+ error.details = {
1790
+ code: "loading remote context failed",
1791
+ url: resource
1792
+ };
1793
+ throw error;
1794
+ }
1795
+ return await mockDocumentLoader(new URL(resource).href);
1796
+ }
1797
+ });
1798
+ response = await handleInbox(malformedUrlLikeContextHttpSignedRequest, {
1799
+ recipient: null,
1800
+ context: malformedUrlLikeContextHttpSignedContext,
1801
+ inboxContextFactory(_activity) {
1802
+ return createInboxContext({
1803
+ ...malformedUrlLikeContextHttpSignedContext,
1804
+ clone: void 0
1805
+ });
1806
+ },
1807
+ ...inboxOptions
1808
+ });
1809
+ assertEquals(response.status, 400);
1810
+ const malformedContextUrlHttpSignedRequest = await signRequest(new Request("https://example.com/", {
1811
+ method: "POST",
1812
+ body: JSON.stringify({
1813
+ "@context": ["not a url", "https://www.w3.org/ns/activitystreams"],
1814
+ id: "https://example.com/activities/http-signed-malformed-context",
1815
+ type: "Create",
1816
+ actor: "https://example.com/person2",
1817
+ object: {
1818
+ id: "https://example.com/notes/http-signed-malformed-context",
1819
+ type: "Note",
1820
+ attributedTo: "https://example.com/person2",
1821
+ content: "Hello, world!"
1822
+ }
1823
+ })
1824
+ }), rsaPrivateKey3, rsaPublicKey3.id);
1825
+ const malformedContextUrlHttpSignedContext = createRequestContext({
1826
+ federation,
1827
+ request: malformedContextUrlHttpSignedRequest,
1828
+ url: new URL(malformedContextUrlHttpSignedRequest.url),
1829
+ data: void 0,
1830
+ documentLoader: mockDocumentLoader,
1831
+ contextLoader: async (resource) => {
1832
+ if (resource === "not a url") {
1833
+ const error = /* @__PURE__ */ new Error(`Invalid remote context URL: ${resource}`);
1834
+ error.name = "jsonld.InvalidUrl";
1835
+ error.details = {
1836
+ code: "loading remote context failed",
1837
+ url: resource
1838
+ };
1839
+ throw error;
1840
+ }
1841
+ return await mockDocumentLoader(new URL(resource).href);
1842
+ }
1843
+ });
1844
+ response = await handleInbox(malformedContextUrlHttpSignedRequest, {
1845
+ recipient: null,
1846
+ context: malformedContextUrlHttpSignedContext,
1847
+ inboxContextFactory(_activity) {
1848
+ return createInboxContext({
1849
+ ...malformedContextUrlHttpSignedContext,
1850
+ clone: void 0
1851
+ });
1852
+ },
1853
+ ...inboxOptions
1854
+ });
1855
+ assertEquals(response.status, 400);
1856
+ const invalidRemoteContextHttpSignedRequest = await signRequest(new Request("https://example.com/", {
1857
+ method: "POST",
1858
+ body: JSON.stringify({
1859
+ "@context": [remoteContextUrl, "https://www.w3.org/ns/activitystreams"],
1860
+ id: "https://example.com/activities/http-signed-invalid-remote-context",
1861
+ type: "Create",
1862
+ actor: "https://example.com/person2",
1863
+ object: {
1864
+ id: "https://example.com/notes/http-signed-invalid-remote-context",
1865
+ type: "Note",
1866
+ attributedTo: "https://example.com/person2",
1867
+ content: "Hello, world!"
1868
+ }
1869
+ })
1870
+ }), rsaPrivateKey3, rsaPublicKey3.id);
1871
+ const invalidRemoteContextHttpSignedContext = createRequestContext({
1872
+ federation,
1873
+ request: invalidRemoteContextHttpSignedRequest,
1874
+ url: new URL(invalidRemoteContextHttpSignedRequest.url),
1875
+ data: void 0,
1876
+ documentLoader: mockDocumentLoader,
1877
+ contextLoader: async (resource) => {
1878
+ const url = new URL(resource).href;
1879
+ if (url === remoteContextUrl) return {
1880
+ contextUrl: null,
1881
+ documentUrl: url,
1882
+ document: [
1883
+ "not",
1884
+ "an",
1885
+ "object"
1886
+ ]
1887
+ };
1888
+ return await mockDocumentLoader(url);
1889
+ }
1890
+ });
1891
+ response = await handleInbox(invalidRemoteContextHttpSignedRequest, {
1892
+ recipient: null,
1893
+ context: invalidRemoteContextHttpSignedContext,
1894
+ inboxContextFactory(_activity) {
1895
+ return createInboxContext({
1896
+ ...invalidRemoteContextHttpSignedContext,
1897
+ clone: void 0
1898
+ });
1899
+ },
1900
+ ...inboxOptions
1901
+ });
1902
+ assertEquals(response.status, 400);
1903
+ const invalidUrlAbsoluteContextHttpSignedRequest = await signRequest(new Request("https://example.com/", {
1904
+ method: "POST",
1905
+ body: JSON.stringify({
1906
+ "@context": [remoteContextUrl, "https://www.w3.org/ns/activitystreams"],
1907
+ id: "https://example.com/activities/http-signed-invalid-url-context",
1908
+ type: "Create",
1909
+ actor: "https://example.com/person2",
1910
+ ext: "preserve-me",
1911
+ object: {
1912
+ id: "https://example.com/notes/http-signed-invalid-url-context",
1913
+ type: "Note",
1914
+ attributedTo: "https://example.com/person2",
1915
+ content: "Hello, world!"
1916
+ }
1917
+ })
1918
+ }), rsaPrivateKey3, rsaPublicKey3.id);
1919
+ const invalidUrlAbsoluteContextHttpSignedContext = createRequestContext({
1920
+ federation,
1921
+ request: invalidUrlAbsoluteContextHttpSignedRequest,
1922
+ url: new URL(invalidUrlAbsoluteContextHttpSignedRequest.url),
1923
+ data: void 0,
1924
+ documentLoader: mockDocumentLoader,
1925
+ contextLoader: async (resource) => {
1926
+ const url = new URL(resource).href;
1927
+ if (url === remoteContextUrl) throw new TypeError(`Invalid URL: ${url}`);
1928
+ return await mockDocumentLoader(url);
1929
+ }
1930
+ });
1931
+ await assertRejects(() => handleInbox(invalidUrlAbsoluteContextHttpSignedRequest, {
1932
+ recipient: null,
1933
+ context: invalidUrlAbsoluteContextHttpSignedContext,
1934
+ inboxContextFactory(_activity) {
1935
+ return createInboxContext({
1936
+ ...invalidUrlAbsoluteContextHttpSignedContext,
1937
+ clone: void 0
1938
+ });
1939
+ },
1940
+ ...inboxOptions
1941
+ }), Error);
1942
+ const typeErrorHttpSignedRequest = await signRequest(new Request("https://example.com/", {
1943
+ method: "POST",
1944
+ body: JSON.stringify({
1945
+ "@context": [remoteContextUrl, "https://www.w3.org/ns/activitystreams"],
1946
+ id: "https://example.com/activities/http-signed-typeerror-context",
1947
+ type: "Create",
1948
+ actor: "https://example.com/person2",
1949
+ ext: "preserve-me",
1950
+ object: {
1951
+ id: "https://example.com/notes/http-signed-typeerror-context",
1952
+ type: "Note",
1953
+ attributedTo: "https://example.com/person2",
1954
+ content: "Hello, world!"
1955
+ }
1956
+ })
1957
+ }), rsaPrivateKey3, rsaPublicKey3.id);
1958
+ const typeErrorHttpSignedContext = createRequestContext({
1959
+ federation,
1960
+ request: typeErrorHttpSignedRequest,
1961
+ url: new URL(typeErrorHttpSignedRequest.url),
1962
+ data: void 0,
1963
+ documentLoader: mockDocumentLoader,
1964
+ contextLoader: async (resource) => {
1965
+ const url = new URL(resource).href;
1966
+ if (url === remoteContextUrl) throw new TypeError(`The remote context host timed out: ${url}`);
1967
+ return await mockDocumentLoader(url);
1968
+ }
1969
+ });
1970
+ await assertRejects(() => handleInbox(typeErrorHttpSignedRequest, {
1971
+ recipient: null,
1972
+ context: typeErrorHttpSignedContext,
1973
+ inboxContextFactory(_activity) {
1974
+ return createInboxContext({
1975
+ ...typeErrorHttpSignedContext,
1976
+ clone: void 0
1977
+ });
1978
+ },
1979
+ ...inboxOptions
1980
+ }), Error);
1981
+ const rangeErrorHttpSignedRequest = await signRequest(new Request("https://example.com/", {
1982
+ method: "POST",
1983
+ body: JSON.stringify({
1984
+ "@context": [remoteContextUrl, "https://www.w3.org/ns/activitystreams"],
1985
+ id: "https://example.com/activities/http-signed-rangeerror-context",
1986
+ type: "Create",
1987
+ actor: "https://example.com/person2",
1988
+ ext: "preserve-me",
1989
+ object: {
1990
+ id: "https://example.com/notes/http-signed-rangeerror-context",
1991
+ type: "Note",
1992
+ attributedTo: "https://example.com/person2",
1993
+ content: "Hello, world!"
1994
+ }
1995
+ })
1996
+ }), rsaPrivateKey3, rsaPublicKey3.id);
1997
+ const rangeErrorHttpSignedContext = createRequestContext({
1998
+ federation,
1999
+ request: rangeErrorHttpSignedRequest,
2000
+ url: new URL(rangeErrorHttpSignedRequest.url),
2001
+ data: void 0,
2002
+ documentLoader: mockDocumentLoader,
2003
+ contextLoader: async (resource) => {
2004
+ const url = new URL(resource).href;
2005
+ if (url === remoteContextUrl) throw new RangeError(`Temporary remote context cache window exceeded: ${url}`);
2006
+ return await mockDocumentLoader(url);
2007
+ }
2008
+ });
2009
+ await assertRejects(() => handleInbox(rangeErrorHttpSignedRequest, {
2010
+ recipient: null,
2011
+ context: rangeErrorHttpSignedContext,
2012
+ inboxContextFactory(_activity) {
2013
+ return createInboxContext({
2014
+ ...rangeErrorHttpSignedContext,
2015
+ clone: void 0
2016
+ });
2017
+ },
2018
+ ...inboxOptions
2019
+ }), Error);
2020
+ const syntaxErrorHttpSignedRequest = await signRequest(new Request("https://example.com/", {
2021
+ method: "POST",
2022
+ body: JSON.stringify({
2023
+ "@context": [remoteContextUrl, "https://www.w3.org/ns/activitystreams"],
2024
+ id: "https://example.com/activities/http-signed-syntax-context",
2025
+ type: "Create",
2026
+ actor: "https://example.com/person2",
2027
+ ext: "preserve-me",
2028
+ object: {
2029
+ id: "https://example.com/notes/http-signed-syntax-context",
2030
+ type: "Note",
2031
+ attributedTo: "https://example.com/person2",
2032
+ content: "Hello, world!"
2033
+ }
2034
+ })
2035
+ }), rsaPrivateKey3, rsaPublicKey3.id);
2036
+ const syntaxErrorHttpSignedContext = createRequestContext({
2037
+ federation,
2038
+ request: syntaxErrorHttpSignedRequest,
2039
+ url: new URL(syntaxErrorHttpSignedRequest.url),
2040
+ data: void 0,
2041
+ documentLoader: mockDocumentLoader,
2042
+ contextLoader: async (resource) => {
2043
+ const url = new URL(resource).href;
2044
+ if (url === remoteContextUrl) {
2045
+ const error = /* @__PURE__ */ new Error(`Transient syntax failure: ${url}`);
2046
+ error.name = "jsonld.SyntaxError";
2047
+ error.details = { code: "loading remote context failed" };
2048
+ throw error;
2049
+ }
2050
+ return await mockDocumentLoader(url);
2051
+ }
2052
+ });
2053
+ await assertRejects(() => handleInbox(syntaxErrorHttpSignedRequest, {
2054
+ recipient: null,
2055
+ context: syntaxErrorHttpSignedContext,
2056
+ inboxContextFactory(_activity) {
2057
+ return createInboxContext({
2058
+ ...syntaxErrorHttpSignedContext,
2059
+ clone: void 0
2060
+ });
2061
+ },
2062
+ ...inboxOptions
2063
+ }), Error);
2064
+ response = await handleInbox(signedRequest, {
2065
+ recipient: "someone",
2066
+ context: signedContext,
2067
+ inboxContextFactory(_activity) {
2068
+ return createInboxContext({
2069
+ ...unsignedContext,
2070
+ clone: void 0,
2071
+ recipient: "someone"
2072
+ });
2073
+ },
2074
+ ...inboxOptions
2075
+ });
2076
+ assertEquals(onNotFoundCalled, null);
2077
+ assertEquals([response.status, await response.text()], [202, ""]);
2078
+ response = await handleInbox(unsignedRequest, {
2079
+ recipient: null,
2080
+ context: unsignedContext,
2081
+ inboxContextFactory(_activity) {
2082
+ return createInboxContext({
2083
+ ...unsignedContext,
2084
+ clone: void 0
2085
+ });
2086
+ },
2087
+ ...inboxOptions,
2088
+ skipSignatureVerification: true
2089
+ });
2090
+ assertEquals(onNotFoundCalled, null);
2091
+ assertEquals(response.status, 202);
2092
+ response = await handleInbox(unsignedRequest, {
2093
+ recipient: "someone",
2094
+ context: unsignedContext,
2095
+ inboxContextFactory(_activity) {
2096
+ return createInboxContext({
2097
+ ...unsignedContext,
2098
+ clone: void 0,
2099
+ recipient: "someone"
2100
+ });
2101
+ },
2102
+ ...inboxOptions,
2103
+ skipSignatureVerification: true
2104
+ });
2105
+ assertEquals(onNotFoundCalled, null);
2106
+ assertEquals(response.status, 202);
2107
+ const unsafeJson = {
2108
+ "@context": ["https://www.w3.org/ns/activitystreams", { rev: "@reverse" }],
2109
+ id: "https://example.com/activities/unsafe",
2110
+ type: "Announce",
2111
+ actor: "https://example.com/person2",
2112
+ object: "https://example.com/notes/1",
2113
+ rev: { object: {
2114
+ id: "https://example.com/activities/undo",
2115
+ type: "Undo",
2116
+ actor: "https://example.com/person2"
2117
+ } }
2118
+ };
2119
+ const unsafeRequest = await signRequest(new Request("https://example.com/", {
2120
+ method: "POST",
2121
+ body: JSON.stringify(unsafeJson)
2122
+ }), rsaPrivateKey3, rsaPublicKey3.id);
2123
+ const unsafeContext = createRequestContext({
2124
+ federation,
2125
+ request: unsafeRequest,
2126
+ url: new URL(unsafeRequest.url),
2127
+ data: void 0,
2128
+ documentLoader: mockDocumentLoader
2129
+ });
2130
+ response = await handleInbox(unsafeRequest, {
2131
+ recipient: null,
2132
+ context: unsafeContext,
2133
+ inboxContextFactory(_activity) {
2134
+ return createInboxContext({
2135
+ ...unsafeContext,
2136
+ clone: void 0
2137
+ });
2138
+ },
2139
+ ...inboxOptions
2140
+ });
2141
+ assertEquals(response.status, 202);
2142
+ const unsafeLdRequest = new Request("https://example.com/", {
2143
+ method: "POST",
2144
+ body: JSON.stringify(await signJsonLd(unsafeJson, rsaPrivateKey3, rsaPublicKey3.id, { contextLoader: mockDocumentLoader }))
2145
+ });
2146
+ const unsafeLdContext = createRequestContext({
2147
+ federation,
2148
+ request: unsafeLdRequest,
2149
+ url: new URL(unsafeLdRequest.url),
2150
+ data: void 0,
2151
+ documentLoader: mockDocumentLoader
2152
+ });
2153
+ response = await handleInbox(unsafeLdRequest, {
2154
+ recipient: null,
2155
+ context: unsafeLdContext,
2156
+ inboxContextFactory(_activity) {
2157
+ return createInboxContext({
2158
+ ...unsafeLdContext,
2159
+ clone: void 0
2160
+ });
2161
+ },
2162
+ ...inboxOptions
2163
+ });
2164
+ assertEquals(response.status, 400);
2165
+ const signedInvalidRequest = await signRequest(new Request("https://example.com/", {
2166
+ method: "POST",
2167
+ body: JSON.stringify({
2168
+ "@context": [
2169
+ "https://www.w3.org/ns/activitystreams",
2170
+ true,
2171
+ 23
2172
+ ],
2173
+ type: "Create",
2174
+ object: {
2175
+ type: "Note",
2176
+ content: "Hello, world!"
2177
+ },
2178
+ actor: "https://example.com/users/alice"
2179
+ })
2180
+ }), rsaPrivateKey3, rsaPublicKey3.id);
2181
+ const signedInvalidContext = createRequestContext({
2182
+ federation,
2183
+ request: signedInvalidRequest,
2184
+ url: new URL(signedInvalidRequest.url),
2185
+ data: void 0,
2186
+ documentLoader: mockDocumentLoader
2187
+ });
2188
+ response = await handleInbox(signedInvalidRequest, {
2189
+ recipient: null,
2190
+ context: signedContext,
2191
+ inboxContextFactory(_activity) {
2192
+ return createInboxContext({
2193
+ ...signedInvalidContext,
2194
+ clone: void 0
2195
+ });
2196
+ },
2197
+ ...inboxOptions
2198
+ });
2199
+ assertEquals(onNotFoundCalled, null);
2200
+ assertEquals(response.status, 400);
2201
+ });
2202
+ test("handleInbox() preserves the raw signed payload for inboxContextFactory", async () => {
2203
+ const federation = createFederation({ kv: new MemoryKvStore() });
2204
+ const remoteContextUrl = "https://remote.example/contexts/ext";
2205
+ const sourceContextLoader = async (resource) => {
2206
+ const url = new URL(resource).href;
2207
+ if (url === remoteContextUrl) return {
2208
+ contextUrl: null,
2209
+ documentUrl: url,
2210
+ document: { "@context": { ext: "https://example.com/ext" } }
2211
+ };
2212
+ return await mockDocumentLoader(url);
2213
+ };
2214
+ const signed = await signJsonLd({
2215
+ "@context": [remoteContextUrl, "https://www.w3.org/ns/activitystreams"],
2216
+ id: "https://example.com/activities/preserve-raw",
2217
+ type: "Create",
2218
+ actor: "https://example.com/person2",
2219
+ ext: "preserve-me",
2220
+ object: {
2221
+ id: "https://example.com/notes/preserve-raw",
2222
+ type: "Note",
2223
+ attributedTo: "https://example.com/person2",
2224
+ content: "Hello, world!"
2225
+ }
2226
+ }, rsaPrivateKey3, rsaPublicKey3.id, { contextLoader: sourceContextLoader });
2227
+ const request = new Request("https://example.com/", {
2228
+ method: "POST",
2229
+ body: JSON.stringify(signed)
2230
+ });
2231
+ const context = createRequestContext({
2232
+ federation,
2233
+ request,
2234
+ url: new URL(request.url),
2235
+ data: void 0,
2236
+ documentLoader: mockDocumentLoader,
2237
+ contextLoader: sourceContextLoader
2238
+ });
2239
+ let receivedRaw = null;
2240
+ let receivedTyped = null;
2241
+ const inboxListeners = new InboxListenerSet();
2242
+ inboxListeners.add(Create, (ctx, activity) => {
2243
+ receivedRaw = ctx.activity;
2244
+ receivedTyped = activity;
2245
+ });
2246
+ const response = await handleInbox(request, {
2247
+ recipient: "someone",
2248
+ context,
2249
+ inboxContextFactory(recipient, activity, activityId, activityType) {
2250
+ return {
2251
+ ...createInboxContext({
2252
+ ...context,
2253
+ clone: void 0,
2254
+ recipient
2255
+ }),
2256
+ activity,
2257
+ activityId,
2258
+ activityType
2259
+ };
2260
+ },
2261
+ kv: new MemoryKvStore(),
2262
+ kvPrefixes: {
2263
+ activityIdempotence: ["_fedify", "activityIdempotence"],
2264
+ publicKey: ["_fedify", "publicKey"]
2265
+ },
2266
+ actorDispatcher: (_ctx, identifier) => identifier === "someone" ? new Person({ name: "Someone" }) : null,
2267
+ inboxListeners,
2268
+ onNotFound: () => new Response("Not found", { status: 404 }),
2269
+ signatureTimeWindow: { minutes: 5 },
2270
+ skipSignatureVerification: false
2271
+ });
2272
+ assertEquals([response.status, await response.text()], [202, ""]);
2273
+ assertEquals(receivedRaw, signed);
2274
+ const delivered = receivedTyped;
2275
+ assert(delivered != null);
2276
+ assertEquals(delivered.id?.href, "https://example.com/activities/preserve-raw");
2277
+ });
2278
+ test("handleInbox() enqueues normalizedActivity for LD-signed inbox work", async () => {
2279
+ const remoteContextUrl = "https://remote.example/contexts/ext";
2280
+ const sourceContextLoader = async (resource) => {
2281
+ const url = new URL(resource).href;
2282
+ if (url === remoteContextUrl) return {
2283
+ contextUrl: null,
2284
+ documentUrl: url,
2285
+ document: { "@context": { ext: "https://example.com/ext" } }
2286
+ };
2287
+ return await mockDocumentLoader(url);
2288
+ };
2289
+ let queuedMessage = null;
2290
+ const queue = {
2291
+ enqueue(message) {
2292
+ queuedMessage = message;
2293
+ return Promise.resolve();
2294
+ },
2295
+ async listen() {}
2296
+ };
2297
+ const federation = createFederation({
2298
+ kv: new MemoryKvStore(),
2299
+ queue
2300
+ });
2301
+ const signed = await signJsonLd({
2302
+ "@context": [remoteContextUrl, "https://www.w3.org/ns/activitystreams"],
2303
+ id: "https://example.com/activities/enqueued-normalized",
2304
+ type: "Create",
2305
+ actor: "https://example.com/person2",
2306
+ ext: "preserve-me",
2307
+ object: {
2308
+ id: "https://example.com/notes/enqueued-normalized",
2309
+ type: "Note",
2310
+ attributedTo: "https://example.com/person2",
2311
+ content: "Hello, world!"
2312
+ }
2313
+ }, rsaPrivateKey3, rsaPublicKey3.id, { contextLoader: sourceContextLoader });
2314
+ const request = new Request("https://example.com/", {
2315
+ method: "POST",
2316
+ body: JSON.stringify(signed)
2317
+ });
2318
+ const context = createRequestContext({
2319
+ federation,
2320
+ request,
2321
+ url: new URL(request.url),
2322
+ data: void 0,
2323
+ documentLoader: mockDocumentLoader,
2324
+ contextLoader: sourceContextLoader
2325
+ });
2326
+ const response = await handleInbox(request, {
2327
+ recipient: "someone",
2328
+ context,
2329
+ inboxContextFactory(recipient, activity, activityId, activityType) {
2330
+ return {
2331
+ ...createInboxContext({
2332
+ ...context,
2333
+ clone: void 0,
2334
+ recipient
2335
+ }),
2336
+ activity,
2337
+ activityId,
2338
+ activityType
2339
+ };
2340
+ },
2341
+ kv: new MemoryKvStore(),
2342
+ kvPrefixes: {
2343
+ activityIdempotence: ["_fedify", "activityIdempotence"],
2344
+ publicKey: ["_fedify", "publicKey"]
2345
+ },
2346
+ queue,
2347
+ actorDispatcher: (_ctx, identifier) => identifier === "someone" ? new Person({ name: "Someone" }) : null,
2348
+ onNotFound: () => new Response("Not found", { status: 404 }),
2349
+ signatureTimeWindow: { minutes: 5 },
2350
+ skipSignatureVerification: false
2351
+ });
2352
+ assertEquals([response.status, await response.text()], [202, "Activity is enqueued."]);
2353
+ const enqueued = queuedMessage;
2354
+ assert(enqueued != null);
2355
+ const inboxMessage = enqueued;
2356
+ assertEquals(inboxMessage.activity, signed);
2357
+ assertEquals(inboxMessage.normalizedActivity, await compactJsonLd(signed, sourceContextLoader));
2358
+ assertEquals(inboxMessage.ldSignatureVerified, true);
2359
+ });
2360
+ test("handleInbox() caches normalizedActivity for queued signature-bearing fallback traffic", async () => {
2361
+ const remoteContextUrl = "https://remote.example/contexts/ext";
2362
+ let queuedMessage = null;
2363
+ const queue = {
2364
+ enqueue(message) {
2365
+ queuedMessage = message;
2366
+ return Promise.resolve();
2367
+ },
2368
+ async listen() {}
2369
+ };
2370
+ const federation = createFederation({
2371
+ kv: new MemoryKvStore(),
2372
+ queue
2373
+ });
2374
+ const sourceContextLoader = async (resource) => {
2375
+ const url = new URL(resource).href;
2376
+ if (url === remoteContextUrl) return {
2377
+ contextUrl: null,
2378
+ documentUrl: url,
2379
+ document: { "@context": { ext: "https://example.com/ext" } }
2380
+ };
2381
+ return await mockDocumentLoader(url);
2382
+ };
2383
+ const unsignedBody = {
2384
+ "@context": [remoteContextUrl, "https://www.w3.org/ns/activitystreams"],
2385
+ id: "https://example.com/activities/non-lds-queued-signature",
2386
+ type: "Create",
2387
+ actor: "https://example.com/person2",
2388
+ ext: "preserve-me",
2389
+ object: {
2390
+ id: "https://example.com/notes/non-lds-queued-signature",
2391
+ type: "Note",
2392
+ attributedTo: "https://example.com/person2",
2393
+ content: "Hello, world!"
2394
+ },
2395
+ signature: {
2396
+ type: "RsaSignature2017",
2397
+ creator: "not a url",
2398
+ created: "2024-09-12T16:50:46Z",
2399
+ signatureValue: "Zm9v"
2400
+ }
2401
+ };
2402
+ const request = await signRequest(new Request("https://example.com/", {
2403
+ method: "POST",
2404
+ body: JSON.stringify(unsignedBody)
2405
+ }), rsaPrivateKey3, rsaPublicKey3.id);
2406
+ const context = createRequestContext({
2407
+ federation,
2408
+ request,
2409
+ url: new URL(request.url),
2410
+ data: void 0,
2411
+ documentLoader: mockDocumentLoader,
2412
+ contextLoader: sourceContextLoader
2413
+ });
2414
+ const response = await handleInbox(request, {
2415
+ recipient: "someone",
2416
+ context,
2417
+ inboxContextFactory(recipient, activity, activityId, activityType) {
2418
+ return {
2419
+ ...createInboxContext({
2420
+ ...context,
2421
+ clone: void 0,
2422
+ recipient
2423
+ }),
2424
+ activity,
2425
+ activityId,
2426
+ activityType
2427
+ };
2428
+ },
2429
+ kv: new MemoryKvStore(),
2430
+ kvPrefixes: {
2431
+ activityIdempotence: ["_fedify", "activityIdempotence"],
2432
+ publicKey: ["_fedify", "publicKey"]
2433
+ },
2434
+ queue,
2435
+ actorDispatcher: (_ctx, identifier) => identifier === "someone" ? new Person({ name: "Someone" }) : null,
2436
+ onNotFound: () => new Response("Not found", { status: 404 }),
2437
+ signatureTimeWindow: { minutes: 5 },
2438
+ skipSignatureVerification: false
2439
+ });
2440
+ assertEquals([response.status, await response.text()], [202, "Activity is enqueued."]);
2441
+ if (queuedMessage == null) throw new Error("Inbox message not queued.");
2442
+ const inboxMessage = queuedMessage;
2443
+ assertEquals(inboxMessage, {
2444
+ type: "inbox",
2445
+ id: inboxMessage.id,
2446
+ baseUrl: "https://example.com",
2447
+ activity: unsignedBody,
2448
+ normalizedActivity: await compactJsonLd(unsignedBody, sourceContextLoader),
2449
+ ldSignatureVerified: false,
2450
+ started: inboxMessage.started,
2451
+ attempt: 0,
2452
+ identifier: "someone",
2453
+ traceContext: inboxMessage.traceContext
2454
+ });
1139
2455
  });
1140
2456
  test("respondWithObject()", async () => {
1141
2457
  const response = await respondWithObject(new Note({