@fedify/fedify 0.12.0-dev.268 → 0.12.0-dev.276
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 +72 -0
- package/FEDERATION.md +6 -0
- package/esm/runtime/docloader.js +3 -0
- package/esm/runtime/url.js +75 -0
- package/esm/vocab/move.yaml +13 -0
- package/esm/vocab/read.yaml +11 -0
- package/esm/vocab/tentativeaccept.yaml +12 -0
- package/esm/vocab/tentativereject.yaml +12 -0
- package/esm/vocab/travel.yaml +14 -0
- package/esm/vocab/view.yaml +11 -0
- package/esm/vocab/vocab.js +1033 -144
- package/package.json +1 -1
- package/types/runtime/docloader.d.ts.map +1 -1
- package/types/runtime/url.d.ts +11 -0
- package/types/runtime/url.d.ts.map +1 -0
- package/types/runtime/url.test.d.ts.map +1 -0
- package/types/vocab/vocab.d.ts +1095 -110
- package/types/vocab/vocab.d.ts.map +1 -1
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)
|
package/esm/runtime/docloader.js
CHANGED
@@ -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: []
|