@fedify/fedify 1.3.21 → 1.3.23

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.
package/CHANGES.md CHANGED
@@ -3,6 +3,30 @@
3
3
  Fedify changelog
4
4
  ================
5
5
 
6
+ Version 1.3.23
7
+ --------------
8
+
9
+ Released on September 17, 2025.
10
+
11
+ - Added a temporary workaround for invalid AT Protocol URIs from BridgyFed.
12
+ URIs like `at://did:plc:...` that violate RFC 3986 URI syntax are now
13
+ automatically URL-encoded to `at://did%3Aplc%3A...` to prevent parsing
14
+ failures when processing bridged Bluesky content. [[#436]]
15
+
16
+
17
+ Version 1.3.22
18
+ --------------
19
+
20
+ Released on August 25, 2025.
21
+
22
+ - Fixed a bug where `verifyRequest()` function threw a `TypeError` when
23
+ verifying HTTP Signatures with `created` or `expires` fields in
24
+ the `Signature` header as defined in draft-cavage-http-signatures-12,
25
+ causing `500 Internal Server Error` responses in inbox handlers.
26
+ Now it correctly handles these fields as unquoted integers according
27
+ to the specification.
28
+
29
+
6
30
  Version 1.3.21
7
31
  --------------
8
32
 
@@ -394,6 +418,30 @@ Released on November 30, 2024.
394
418
  [#193]: https://github.com/fedify-dev/fedify/issues/193
395
419
 
396
420
 
421
+ Version 1.2.26
422
+ --------------
423
+
424
+ Released on September 17, 2025.
425
+
426
+ - Added a temporary workaround for invalid AT Protocol URIs from BridgyFed.
427
+ URIs like `at://did:plc:...` that violate RFC 3986 URI syntax are now
428
+ automatically URL-encoded to `at://did%3Aplc%3A...` to prevent parsing
429
+ failures when processing bridged Bluesky content. [[#436]]
430
+
431
+
432
+ Version 1.2.25
433
+ --------------
434
+
435
+ Released on August 25, 2025.
436
+
437
+ - Fixed a bug where `verifyRequest()` function threw a `TypeError` when
438
+ verifying HTTP Signatures with `created` or `expires` fields in
439
+ the `Signature` header as defined in draft-cavage-http-signatures-12,
440
+ causing `500 Internal Server Error` responses in inbox handlers.
441
+ Now it correctly handles these fields as unquoted integers according
442
+ to the specification.
443
+
444
+
397
445
  Version 1.2.24
398
446
  --------------
399
447
 
@@ -818,6 +866,30 @@ Released on October 31, 2024.
818
866
  [#118]: https://github.com/fedify-dev/fedify/issues/118
819
867
 
820
868
 
869
+ Version 1.1.26
870
+ --------------
871
+
872
+ Released on September 17, 2025.
873
+
874
+ - Added a temporary workaround for invalid AT Protocol URIs from BridgyFed.
875
+ URIs like `at://did:plc:...` that violate RFC 3986 URI syntax are now
876
+ automatically URL-encoded to `at://did%3Aplc%3A...` to prevent parsing
877
+ failures when processing bridged Bluesky content. [[#436]]
878
+
879
+
880
+ Version 1.1.25
881
+ --------------
882
+
883
+ Released on August 25, 2025.
884
+
885
+ - Fixed a bug where `verifyRequest()` function threw a `TypeError` when
886
+ verifying HTTP Signatures with `created` or `expires` fields in
887
+ the `Signature` header as defined in draft-cavage-http-signatures-12,
888
+ causing `500 Internal Server Error` responses in inbox handlers.
889
+ Now it correctly handles these fields as unquoted integers according
890
+ to the specification.
891
+
892
+
821
893
  Version 1.1.24
822
894
  --------------
823
895
 
@@ -1283,6 +1355,32 @@ Released on October 20, 2024.
1283
1355
  [#150]: https://github.com/fedify-dev/fedify/issues/150
1284
1356
 
1285
1357
 
1358
+ Version 1.0.29
1359
+ --------------
1360
+
1361
+ Released on September 17, 2025.
1362
+
1363
+ - Added a temporary workaround for invalid AT Protocol URIs from BridgyFed.
1364
+ URIs like `at://did:plc:...` that violate RFC 3986 URI syntax are now
1365
+ automatically URL-encoded to `at://did%3Aplc%3A...` to prevent parsing
1366
+ failures when processing bridged Bluesky content. [[#436]]
1367
+
1368
+ [#436]: https://github.com/fedify-dev/fedify/issues/436
1369
+
1370
+
1371
+ Version 1.0.28
1372
+ --------------
1373
+
1374
+ Released on August 25, 2025.
1375
+
1376
+ - Fixed a bug where `verifyRequest()` function threw a `TypeError` when
1377
+ verifying HTTP Signatures with `created` or `expires` fields in
1378
+ the `Signature` header as defined in draft-cavage-http-signatures-12,
1379
+ causing `500 Internal Server Error` responses in inbox handlers.
1380
+ Now it correctly handles these fields as unquoted integers according
1381
+ to the specification.
1382
+
1383
+
1286
1384
  Version 1.0.27
1287
1385
  --------------
1288
1386
 
package/esm/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "@fedify/fedify",
3
- "version": "1.3.21",
3
+ "version": "1.3.23",
4
4
  "license": "MIT",
5
5
  "exports": {
6
6
  ".": "./mod.ts",
package/esm/sig/http.js CHANGED
@@ -221,7 +221,7 @@ async function verifyRequestInternal(request, span, { documentLoader, contextLoa
221
221
  return null;
222
222
  }
223
223
  }
224
- const sigValues = Object.fromEntries(sigHeader.split(",").map((pair) => pair.match(/^\s*([A-Za-z]+)="([^"]*)"\s*$/)).filter((m) => m != null).map((m) => m.slice(1, 3)));
224
+ const sigValues = Object.fromEntries(sigHeader.split(",").map((pair) => pair.match(/^\s*([A-Za-z]+)=(?:"([^"]*)"|(\d+))\s*$/)).filter((m) => m != null).map((m) => [m[1], m[2] ?? m[3]]));
225
225
  if (!("keyId" in sigValues)) {
226
226
  logger.debug("Failed to verify; no keyId field found in the Signature header.", { signature: sigHeader });
227
227
  return null;
@@ -234,6 +234,41 @@ async function verifyRequestInternal(request, span, { documentLoader, contextLoa
234
234
  logger.debug("Failed to verify; no signature field found in the Signature header.", { signature: sigHeader });
235
235
  return null;
236
236
  }
237
+ if ("expires" in sigValues) {
238
+ const expiresSeconds = parseInt(sigValues.expires);
239
+ if (!Number.isInteger(expiresSeconds)) {
240
+ logger.debug("Failed to verify; invalid expires field in the Signature header: {expires}.", { expires: sigValues.expires, signature: sigHeader });
241
+ return null;
242
+ }
243
+ const expires = dntShim.Temporal.Instant.fromEpochMilliseconds(expiresSeconds * 1000);
244
+ if (dntShim.Temporal.Instant.compare(now, expires) > 0) {
245
+ logger.debug("Failed to verify; signature expired at {expires} (now: {now}).", {
246
+ expires: expires.toString(),
247
+ now: now.toString(),
248
+ signature: sigHeader,
249
+ });
250
+ return null;
251
+ }
252
+ }
253
+ if ("created" in sigValues) {
254
+ const createdSeconds = parseInt(sigValues.created);
255
+ if (!Number.isInteger(createdSeconds)) {
256
+ logger.debug("Failed to verify; invalid created field in the Signature header: {created}.", { created: sigValues.created, signature: sigHeader });
257
+ return null;
258
+ }
259
+ if (timeWindow !== false) {
260
+ const created = dntShim.Temporal.Instant.fromEpochMilliseconds(createdSeconds * 1000);
261
+ const tw = timeWindow ?? { minutes: 1 };
262
+ if (dntShim.Temporal.Instant.compare(created, now.add(tw)) > 0) {
263
+ logger.debug("Failed to verify; created is too far in the future.", { created: created.toString(), now: now.toString() });
264
+ return null;
265
+ }
266
+ else if (dntShim.Temporal.Instant.compare(created, now.subtract(tw)) < 0) {
267
+ logger.debug("Failed to verify; created is too far in the past.", { created: created.toString(), now: now.toString() });
268
+ return null;
269
+ }
270
+ }
271
+ }
237
272
  const { keyId, headers, signature } = sigValues;
238
273
  span?.setAttribute("http_signatures.key_id", keyId);
239
274
  if ("algorithm" in sigValues) {
@@ -259,11 +294,15 @@ async function verifyRequestInternal(request, span, { documentLoader, contextLoa
259
294
  return null;
260
295
  }
261
296
  const message = headerNames.map((name) => `${name}: ` +
262
- (name == "(request-target)"
297
+ (name === "(request-target)"
263
298
  ? `${request.method.toLowerCase()} ${new URL(request.url).pathname}`
264
- : name == "host"
265
- ? request.headers.get("host") ?? new URL(request.url).host
266
- : request.headers.get(name))).join("\n");
299
+ : name === "(created)"
300
+ ? (sigValues.created ?? "")
301
+ : name === "(expires)"
302
+ ? (sigValues.expires ?? "")
303
+ : name === "host"
304
+ ? request.headers.get("host") ?? new URL(request.url).host
305
+ : request.headers.get(name))).join("\n");
267
306
  const sig = decodeBase64(signature);
268
307
  span?.setAttribute("http_signatures.signature", encodeHex(sig));
269
308
  // TODO: support other than RSASSA-PKCS1-v1_5:
@@ -0,0 +1,24 @@
1
+ {
2
+ "@context": [
3
+ "https://www.w3.org/ns/activitystreams",
4
+ "https://w3id.org/security/v1"
5
+ ],
6
+ "id": "https://oeee.cafe/ap/users/3609fd4e-d51d-4db8-9f04-4189815864dd",
7
+ "type": "Person",
8
+ "preferredUsername": "hongminhee",
9
+ "name": "洪兔",
10
+ "inbox": "https://oeee.cafe/ap/users/3609fd4e-d51d-4db8-9f04-4189815864dd/inbox",
11
+ "outbox": "https://oeee.cafe/ap/users/3609fd4e-d51d-4db8-9f04-4189815864dd/outbox",
12
+ "publicKey": {
13
+ "id": "https://oeee.cafe/ap/users/3609fd4e-d51d-4db8-9f04-4189815864dd#main-key",
14
+ "owner": "https://oeee.cafe/ap/users/3609fd4e-d51d-4db8-9f04-4189815864dd",
15
+ "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAowJfOzpA/nAYyL0bVDTm\niCAOlhFCIBnqwk1jvGrbkDhMzxlsgyoDqUSlmcJdKaPwu24YdFajDtJIgto27Ju7\nIC3hB7OFchnZ4JZrdYFo7CJABOzK58o12sdmmkCdY5hXWf1604E+mzyIdBAJ1FFJ\nL8vP07VEUsZ7yo9x0iVNg7HpCOK+y6BqI2GHS2dq9qkqQEIhC2TKHXn/RQVXwYB6\nG+YQmVUtcsbCVKdcWyTKhItLRGnepu3BqBSbieLxV27B1O9NFSoPu8xiBUnYwMoe\nsUQCE5tGcqxc75HzcVCbq7PqVqHZ1NW9RYssaSUqi4FYcjXxQrR08DrAl8rR4eXT\n4QIDAQAB\n-----END PUBLIC KEY-----\n"
16
+ },
17
+ "endpoints": {
18
+ "type": "as:Endpoints",
19
+ "sharedInbox": "https://oeee.cafe/inbox"
20
+ },
21
+ "followers": "https://oeee.cafe/ap/users/3609fd4e-d51d-4db8-9f04-4189815864dd/followers",
22
+ "manuallyApprovesFollowers": false,
23
+ "url": "https://oeee.cafe/@hongminhee"
24
+ }