@fedify/fedify 1.2.24 → 1.2.25

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,19 @@
3
3
  Fedify changelog
4
4
  ================
5
5
 
6
+ Version 1.2.25
7
+ --------------
8
+
9
+ Released on August 25, 2025.
10
+
11
+ - Fixed a bug where `verifyRequest()` function threw a `TypeError` when
12
+ verifying HTTP Signatures with `created` or `expires` fields in
13
+ the `Signature` header as defined in draft-cavage-http-signatures-12,
14
+ causing `500 Internal Server Error` responses in inbox handlers.
15
+ Now it correctly handles these fields as unquoted integers according
16
+ to the specification.
17
+
18
+
6
19
  Version 1.2.24
7
20
  --------------
8
21
 
@@ -427,6 +440,19 @@ Released on October 31, 2024.
427
440
  [#118]: https://github.com/dahlia/fedify/issues/118
428
441
 
429
442
 
443
+ Version 1.1.25
444
+ --------------
445
+
446
+ Released on August 25, 2025.
447
+
448
+ - Fixed a bug where `verifyRequest()` function threw a `TypeError` when
449
+ verifying HTTP Signatures with `created` or `expires` fields in
450
+ the `Signature` header as defined in draft-cavage-http-signatures-12,
451
+ causing `500 Internal Server Error` responses in inbox handlers.
452
+ Now it correctly handles these fields as unquoted integers according
453
+ to the specification.
454
+
455
+
430
456
  Version 1.1.24
431
457
  --------------
432
458
 
@@ -892,6 +918,19 @@ Released on October 20, 2024.
892
918
  [#150]: https://github.com/dahlia/fedify/issues/150
893
919
 
894
920
 
921
+ Version 1.0.28
922
+ --------------
923
+
924
+ Released on August 25, 2025.
925
+
926
+ - Fixed a bug where `verifyRequest()` function threw a `TypeError` when
927
+ verifying HTTP Signatures with `created` or `expires` fields in
928
+ the `Signature` header as defined in draft-cavage-http-signatures-12,
929
+ causing `500 Internal Server Error` responses in inbox handlers.
930
+ Now it correctly handles these fields as unquoted integers according
931
+ to the specification.
932
+
933
+
895
934
  Version 1.0.27
896
935
  --------------
897
936
 
package/esm/sig/http.js CHANGED
@@ -150,7 +150,7 @@ export async function verifyRequest(request, { documentLoader, contextLoader, ti
150
150
  return null;
151
151
  }
152
152
  }
153
- 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)));
153
+ 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]]));
154
154
  if (!("keyId" in sigValues)) {
155
155
  logger.debug("Failed to verify; no keyId field found in the Signature header.", { signature: sigHeader });
156
156
  return null;
@@ -163,6 +163,41 @@ export async function verifyRequest(request, { documentLoader, contextLoader, ti
163
163
  logger.debug("Failed to verify; no signature field found in the Signature header.", { signature: sigHeader });
164
164
  return null;
165
165
  }
166
+ if ("expires" in sigValues) {
167
+ const expiresSeconds = parseInt(sigValues.expires);
168
+ if (!Number.isInteger(expiresSeconds)) {
169
+ logger.debug("Failed to verify; invalid expires field in the Signature header: {expires}.", { expires: sigValues.expires, signature: sigHeader });
170
+ return null;
171
+ }
172
+ const expires = dntShim.Temporal.Instant.fromEpochMilliseconds(expiresSeconds * 1000);
173
+ if (dntShim.Temporal.Instant.compare(now, expires) > 0) {
174
+ logger.debug("Failed to verify; signature expired at {expires} (now: {now}).", {
175
+ expires: expires.toString(),
176
+ now: now.toString(),
177
+ signature: sigHeader,
178
+ });
179
+ return null;
180
+ }
181
+ }
182
+ if ("created" in sigValues) {
183
+ const createdSeconds = parseInt(sigValues.created);
184
+ if (!Number.isInteger(createdSeconds)) {
185
+ logger.debug("Failed to verify; invalid created field in the Signature header: {created}.", { created: sigValues.created, signature: sigHeader });
186
+ return null;
187
+ }
188
+ if (timeWindow !== false) {
189
+ const created = dntShim.Temporal.Instant.fromEpochMilliseconds(createdSeconds * 1000);
190
+ const tw = timeWindow ?? { minutes: 1 };
191
+ if (dntShim.Temporal.Instant.compare(created, now.add(tw)) > 0) {
192
+ logger.debug("Failed to verify; created is too far in the future.", { created: created.toString(), now: now.toString() });
193
+ return null;
194
+ }
195
+ else if (dntShim.Temporal.Instant.compare(created, now.subtract(tw)) < 0) {
196
+ logger.debug("Failed to verify; created is too far in the past.", { created: created.toString(), now: now.toString() });
197
+ return null;
198
+ }
199
+ }
200
+ }
166
201
  const { keyId, headers, signature } = sigValues;
167
202
  const keyResult = await fetchKey(new URL(keyId), CryptographicKey, {
168
203
  documentLoader,
@@ -184,11 +219,15 @@ export async function verifyRequest(request, { documentLoader, contextLoader, ti
184
219
  return null;
185
220
  }
186
221
  const message = headerNames.map((name) => `${name}: ` +
187
- (name == "(request-target)"
222
+ (name === "(request-target)"
188
223
  ? `${request.method.toLowerCase()} ${new URL(request.url).pathname}`
189
- : name == "host"
190
- ? request.headers.get("host") ?? new URL(request.url).host
191
- : request.headers.get(name))).join("\n");
224
+ : name === "(created)"
225
+ ? (sigValues.created ?? "")
226
+ : name === "(expires)"
227
+ ? (sigValues.expires ?? "")
228
+ : name === "host"
229
+ ? request.headers.get("host") ?? new URL(request.url).host
230
+ : request.headers.get(name))).join("\n");
192
231
  const sig = decodeBase64(signature);
193
232
  // TODO: support other than RSASSA-PKCS1-v1_5:
194
233
  const verified = await dntShim.crypto.subtle.verify("RSASSA-PKCS1-v1_5", key.publicKey, sig, new TextEncoder().encode(message));
@@ -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
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fedify/fedify",
3
- "version": "1.2.24",
3
+ "version": "1.2.25",
4
4
  "description": "An ActivityPub server framework",
5
5
  "keywords": [
6
6
  "ActivityPub",
@@ -1 +1 @@
1
- {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/sig/http.ts"],"names":[],"mappings":";;AAAA,OAAO,KAAK,OAAO,MAAM,kBAAkB,CAAC;AAI5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAY,KAAK,QAAQ,EAAqB,MAAM,UAAU,CAAC;AAEtE;;;;;;;;GAQG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,OAAO,CAAC,SAAS,EAC7B,KAAK,EAAE,GAAG,GACT,OAAO,CAAC,OAAO,CAAC,CA0ClB;AAQD;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;OAEG;IACH,cAAc,CAAC,EAAE,cAAc,CAAC;IAEhC;;OAEG;IACH,aAAa,CAAC,EAAE,cAAc,CAAC;IAE/B;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,YAAY,GAAG,KAAK,CAAC;IAE/E;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC;IAEvC;;;OAGG;IACH,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,OAAO,EAChB,EAAE,cAAc,EAAE,aAAa,EAAE,UAAU,EAAE,WAAW,EAAE,QAAQ,EAAE,GAClE,oBAAyB,GAC1B,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAkNlC"}
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/sig/http.ts"],"names":[],"mappings":";;AAAA,OAAO,KAAK,OAAO,MAAM,kBAAkB,CAAC;AAI5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAY,KAAK,QAAQ,EAAqB,MAAM,UAAU,CAAC;AAEtE;;;;;;;;GAQG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,OAAO,CAAC,SAAS,EAC7B,KAAK,EAAE,GAAG,GACT,OAAO,CAAC,OAAO,CAAC,CA0ClB;AAQD;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;OAEG;IACH,cAAc,CAAC,EAAE,cAAc,CAAC;IAEhC;;OAEG;IACH,aAAa,CAAC,EAAE,cAAc,CAAC;IAE/B;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,YAAY,GAAG,KAAK,CAAC;IAE/E;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC;IAEvC;;;OAGG;IACH,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,OAAO,EAChB,EAAE,cAAc,EAAE,aAAa,EAAE,UAAU,EAAE,WAAW,EAAE,QAAQ,EAAE,GAClE,oBAAyB,GAC1B,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CA6QlC"}