@fedify/fedify 1.9.10 → 1.9.12-dev.2265

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