@fedify/fedify 0.12.0-dev.268 → 0.12.0-dev.276

Sign up to get free protection for your applications and to get access to all the features.
package/CHANGES.md CHANGED
@@ -40,6 +40,21 @@ To be released.
40
40
 
41
41
  - Added `ChatMessage` class to Activity Vocabulary API. [[#85]]
42
42
 
43
+ - Added `Move` class to Activity Vocabulary API. [[#65], [#92] by Lee Dogeon]
44
+
45
+ - Added `Read` class to Activity Vocabulary API. [[#65], [#92] by Lee Dogeon]
46
+
47
+ - Added `Travel` class to Activity Vocabulary API.
48
+ [[#65], [#92] by Lee Dogeon]
49
+
50
+ - Added `View` class to Activity Vocabulary API. [[#65], [#92] by Lee Dogeon]
51
+
52
+ - Added `TentativeAccept` class to Activity Vocabulary API.
53
+ [[#65], [#92] by Lee Dogeon]
54
+
55
+ - Added `TentativeReject` class to Activity Vocabulary API.
56
+ [[#65], [#92] by Lee Dogeon]
57
+
43
58
  - Improved multitenancy (virtual hosting) support. [[#66]]
44
59
 
45
60
  - Added `Context.hostname` property.
@@ -54,6 +69,15 @@ To be released.
54
69
  - The last parameter of `Federation.sendActivity()` method is no longer
55
70
  optional. Also, it now takes the required `contextData` option.
56
71
 
72
+ - Fixed a SSRF vulnerability in the built-in document loader.
73
+ [[CVE-2024-39687]]
74
+
75
+ - The `fetchDocumentLoader()` function now throws an error when the given
76
+ URL is not an HTTP or HTTPS URL or refers to a private network address.
77
+ - The `getAuthenticatedDocumentLoader()` function now returns a document
78
+ loader that throws an error when the given URL is not an HTTP or HTTPS
79
+ URL or refers to a private network address.
80
+
57
81
  - Added more log messages using the [LogTape] library. Currently the below
58
82
  logger categories are used:
59
83
 
@@ -63,6 +87,22 @@ To be released.
63
87
  [#66]: https://github.com/dahlia/fedify/issues/66
64
88
  [#70]: https://github.com/dahlia/fedify/issues/70
65
89
  [#85]: https://github.com/dahlia/fedify/issues/85
90
+ [#92]: https://github.com/dahlia/fedify/pull/92
91
+
92
+
93
+ Version 0.11.1
94
+ --------------
95
+
96
+ Released on July 5, 2024.
97
+
98
+ - Fixed a SSRF vulnerability in the built-in document loader.
99
+ [[CVE-2024-39687]]
100
+
101
+ - The `fetchDocumentLoader()` function now throws an error when the given
102
+ URL is not an HTTP or HTTPS URL or refers to a private network address.
103
+ - The `getAuthenticatedDocumentLoader()` function now returns a document
104
+ loader that throws an error when the given URL is not an HTTP or HTTPS
105
+ URL or refers to a private network address.
66
106
 
67
107
 
68
108
  Version 0.11.0
@@ -248,6 +288,21 @@ Released on June 29, 2024.
248
288
  [#80]: https://github.com/dahlia/fedify/pull/80
249
289
 
250
290
 
291
+ Version 0.10.1
292
+ --------------
293
+
294
+ Released on July 5, 2024.
295
+
296
+ - Fixed a SSRF vulnerability in the built-in document loader.
297
+ [[CVE-2024-39687]]
298
+
299
+ - The `fetchDocumentLoader()` function now throws an error when the given
300
+ URL is not an HTTP or HTTPS URL or refers to a private network address.
301
+ - The `getAuthenticatedDocumentLoader()` function now returns a document
302
+ loader that throws an error when the given URL is not an HTTP or HTTPS
303
+ URL or refers to a private network address.
304
+
305
+
251
306
  Version 0.10.0
252
307
  --------------
253
308
 
@@ -409,6 +464,23 @@ is now distributed under the [MIT License] to encourage wider adoption.
409
464
  [x-forwarded-fetch]: https://github.com/dahlia/x-forwarded-fetch
410
465
 
411
466
 
467
+ Version 0.9.2
468
+ -------------
469
+
470
+ Released on July 5, 2024.
471
+
472
+ - Fixed a SSRF vulnerability in the built-in document loader.
473
+ [[CVE-2024-39687]]
474
+
475
+ - The `fetchDocumentLoader()` function now throws an error when the given
476
+ URL is not an HTTP or HTTPS URL or refers to a private network address.
477
+ - The `getAuthenticatedDocumentLoader()` function now returns a document
478
+ loader that throws an error when the given URL is not an HTTP or HTTPS
479
+ URL or refers to a private network address.
480
+
481
+ [CVE-2024-39687]: https://github.com/dahlia/fedify/security/advisories/GHSA-p9cg-vqcc-grcx
482
+
483
+
412
484
  Version 0.9.1
413
485
  -------------
414
486
 
package/FEDERATION.md CHANGED
@@ -61,9 +61,15 @@ lists the activity types that Fedify provides:
61
61
  - [`Leave`](https://jsr.io/@fedify/fedify/doc/vocab/~/Leave)
62
62
  - [`Like`](https://jsr.io/@fedify/fedify/doc/vocab/~/Like)
63
63
  - [`Listen`](https://jsr.io/@fedify/fedify/doc/vocab/~/Listen)
64
+ - [`Move`](https://jsr.io/@fedify/fedify/doc/vocab/~/Move)
64
65
  - [`Offer`](https://jsr.io/@fedify/fedify/doc/vocab/~/Offer)
65
66
  - [`Question`](https://jsr.io/@fedify/fedify/doc/vocab/~/Question)
67
+ - [`Read`](https://jsr.io/@fedify/fedify/doc/vocab/~/Read)
66
68
  - [`Reject`](https://jsr.io/@fedify/fedify/doc/vocab/~/Reject)
67
69
  - [`Remove`](https://jsr.io/@fedify/fedify/doc/vocab/~/Remove)
70
+ - [`TentativeAccept`](https://jsr.io/@fedify/fedify/doc/vocab/~/TentativeAccept)
71
+ - [`TentativeReject`](https://jsr.io/@fedify/fedify/doc/vocab/~/TentativeReject)
72
+ - [`Travel`](https://jsr.io/@fedify/fedify/doc/vocab/~/Travel)
68
73
  - [`Undo`](https://jsr.io/@fedify/fedify/doc/vocab/~/Undo)
69
74
  - [`Update`](https://jsr.io/@fedify/fedify/doc/vocab/~/Update)
75
+ - [`View`](https://jsr.io/@fedify/fedify/doc/vocab/~/View)
@@ -3,6 +3,7 @@ import { getLogger } from "@logtape/logtape";
3
3
  import { signRequest } from "../sig/http.js";
4
4
  import { validateCryptoKey } from "../sig/key.js";
5
5
  import preloadedContexts from "./contexts.js";
6
+ import { validatePublicUrl } from "./url.js";
6
7
  const logger = getLogger(["fedify", "runtime", "docloader"]);
7
8
  /**
8
9
  * Error thrown when fetching a JSON-LD document failed.
@@ -82,6 +83,7 @@ export async function fetchDocumentLoader(url) {
82
83
  documentUrl: url,
83
84
  };
84
85
  }
86
+ await validatePublicUrl(url);
85
87
  const request = createRequest(url);
86
88
  logRequest(request);
87
89
  const response = await fetch(request, {
@@ -110,6 +112,7 @@ export async function fetchDocumentLoader(url) {
110
112
  export function getAuthenticatedDocumentLoader(identity) {
111
113
  validateCryptoKey(identity.privateKey);
112
114
  async function load(url) {
115
+ await validatePublicUrl(url);
113
116
  let request = createRequest(url);
114
117
  request = await signRequest(request, identity.privateKey, identity.keyId);
115
118
  logRequest(request);
@@ -0,0 +1,75 @@
1
+ import * as dntShim from "../_dnt.shims.js";
2
+ import { lookup } from "node:dns/promises";
3
+ import { isIP } from "node:net";
4
+ export class UrlError extends Error {
5
+ constructor(message) {
6
+ super(message);
7
+ this.name = "UrlError";
8
+ }
9
+ }
10
+ /**
11
+ * Validates a URL to prevent SSRF attacks.
12
+ */
13
+ export async function validatePublicUrl(url) {
14
+ const parsed = new URL(url);
15
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
16
+ throw new UrlError(`Unsupported protocol: ${parsed.protocol}`);
17
+ }
18
+ let hostname = parsed.hostname;
19
+ if (hostname.startsWith("[") && hostname.endsWith("]")) {
20
+ hostname = hostname.substring(1, hostname.length - 2);
21
+ }
22
+ if (hostname === "localhost") {
23
+ throw new UrlError("Localhost is not allowed");
24
+ }
25
+ if ("Deno" in dntShim.dntGlobalThis && !isIP(hostname)) {
26
+ // If the `net` permission is not granted, we can't resolve the hostname.
27
+ // However, we can safely assume that it cannot gain access to private
28
+ // resources.
29
+ const netPermission = await dntShim.Deno.permissions.query({ name: "net" });
30
+ if (netPermission.state !== "granted")
31
+ return;
32
+ }
33
+ const { address, family } = await lookup(hostname);
34
+ if (family === 4 && !isValidPublicIPv4Address(address) ||
35
+ family === 6 && !isValidPublicIPv6Address(address) ||
36
+ family < 4 || family === 5 || family > 6) {
37
+ throw new UrlError(`Invalid or private address: ${address}`);
38
+ }
39
+ }
40
+ export function isValidPublicIPv4Address(address) {
41
+ const parts = address.split(".");
42
+ const first = parseInt(parts[0]);
43
+ if (first === 0 || first === 10 || first === 127)
44
+ return false;
45
+ const second = parseInt(parts[1]);
46
+ if (first === 169 && second === 254)
47
+ return false;
48
+ if (first === 172 && second >= 16 && second <= 31)
49
+ return false;
50
+ if (first === 192 && second === 168)
51
+ return false;
52
+ return true;
53
+ }
54
+ export function isValidPublicIPv6Address(address) {
55
+ address = expandIPv6Address(address);
56
+ if (address.at(4) !== ":")
57
+ return false;
58
+ const firstWord = parseInt(address.substring(0, 4), 16);
59
+ return !((firstWord >= 0xfc00 && firstWord <= 0xfdff) || // ULA
60
+ (firstWord >= 0xfe80 && firstWord <= 0xfebf) || // Link-local
61
+ firstWord === 0 || firstWord >= 0xff00 // Multicast
62
+ );
63
+ }
64
+ export function expandIPv6Address(address) {
65
+ address = address.toLowerCase();
66
+ if (address === "::")
67
+ return "0000:0000:0000:0000:0000:0000:0000:0000";
68
+ if (address.startsWith("::"))
69
+ address = "0000" + address;
70
+ if (address.endsWith("::"))
71
+ address = address + "0000";
72
+ address = address.replace("::", ":0000".repeat(8 - (address.match(/:/g) || []).length) + ":");
73
+ const parts = address.split(":");
74
+ return parts.map((part) => part.padStart(4, "0")).join(":");
75
+ }
@@ -0,0 +1,13 @@
1
+ $schema: ../codegen/schema.yaml
2
+ name: Move
3
+ uri: "https://www.w3.org/ns/activitystreams#Move"
4
+ extends: "https://www.w3.org/ns/activitystreams#Activity"
5
+ entity: true
6
+ description: |
7
+ Indicates that the `actor` has moved `object` from `origin` to `target`.
8
+ If the `origin` or `target` are not specified,
9
+ either can be determined by context.
10
+ defaultContext:
11
+ - "https://www.w3.org/ns/activitystreams"
12
+ - "https://w3id.org/security/data-integrity/v1"
13
+ properties: []
@@ -0,0 +1,11 @@
1
+ $schema: ../codegen/schema.yaml
2
+ name: Read
3
+ uri: "https://www.w3.org/ns/activitystreams#Read"
4
+ extends: "https://www.w3.org/ns/activitystreams#Activity"
5
+ entity: true
6
+ description: |
7
+ Indicates that the `actor` has read the `object`.
8
+ defaultContext:
9
+ - "https://www.w3.org/ns/activitystreams"
10
+ - "https://w3id.org/security/data-integrity/v1"
11
+ properties: []
@@ -0,0 +1,12 @@
1
+ $schema: ../codegen/schema.yaml
2
+ name: TentativeAccept
3
+ uri: "https://www.w3.org/ns/activitystreams#TentativeAccept"
4
+ extends: "https://www.w3.org/ns/activitystreams#Accept"
5
+ entity: true
6
+ description: |
7
+ A specialization of {@link Accept} indicating that
8
+ the acceptance is tentative.
9
+ defaultContext:
10
+ - "https://www.w3.org/ns/activitystreams"
11
+ - "https://w3id.org/security/data-integrity/v1"
12
+ properties: []
@@ -0,0 +1,12 @@
1
+ $schema: ../codegen/schema.yaml
2
+ name: TentativeReject
3
+ uri: "https://www.w3.org/ns/activitystreams#TentativeReject"
4
+ extends: "https://www.w3.org/ns/activitystreams#Reject"
5
+ entity: true
6
+ description: |
7
+ A specialization of {@link Reject} in which
8
+ the rejection is considered tentative.
9
+ defaultContext:
10
+ - "https://www.w3.org/ns/activitystreams"
11
+ - "https://w3id.org/security/data-integrity/v1"
12
+ properties: []
@@ -0,0 +1,14 @@
1
+ $schema: ../codegen/schema.yaml
2
+ name: Travel
3
+ uri: "https://www.w3.org/ns/activitystreams#Travel"
4
+ extends: "https://www.w3.org/ns/activitystreams#IntransitiveActivity"
5
+ entity: true
6
+ description: |
7
+ Indicates that the `actor` is traveling to `target` from `origin`.
8
+ `Travel` is an `IntransitiveObject` whose `actor` specifies the direct object.
9
+ If the `target` or `origin` are not specified,
10
+ either can be determined by context.
11
+ defaultContext:
12
+ - "https://www.w3.org/ns/activitystreams"
13
+ - "https://w3id.org/security/data-integrity/v1"
14
+ properties: []
@@ -0,0 +1,11 @@
1
+ $schema: ../codegen/schema.yaml
2
+ name: View
3
+ uri: "https://www.w3.org/ns/activitystreams#View"
4
+ extends: "https://www.w3.org/ns/activitystreams#Activity"
5
+ entity: true
6
+ description: |
7
+ Indicates that the `actor` has viewed the object.
8
+ defaultContext:
9
+ - "https://www.w3.org/ns/activitystreams"
10
+ - "https://w3id.org/security/data-integrity/v1"
11
+ properties: []