Loading CHANGES.md +1 −0 Original line number Diff line number Diff line Loading @@ -11,6 +11,7 @@ To be released. - Removed `expand` option of `Object.toJsonLd()` method, which was deprecated in version 0.14.0. Use `format: "expand"` option instead. - Added `Context.lookupObject()` method. - Added `allowPrivateAddress` option to `CreateFederationOptions` interface. - Renamed the short option `-c` for `--compact` of `fedify lookup` command to `-C` to avoid conflict with the short option `-c` for `--cache-dir`. - Added `-r`/`--raw` option to `fedify lookup` command to output the raw JSON Loading docs/manual/federation.md +21 −0 Original line number Diff line number Diff line Loading @@ -181,6 +181,27 @@ load remote JSON-LD contexts. The type of the function is the same as the [*Document loader vs. context loader* section](./context.md#document-loader-vs-context-loader)). ### `allowPrivateAddress` *This API is available since Fedify 0.15.0.* > [!WARNING] > Do not turn on this option in production environments. Disallowing fetching > private network addresses is a security feature to prevent [SSRF] attacks. Whether to allow fetching private network addresses in the document loader. If turned on, [`documentLoader`](#documentloader), [`contextLoader`](#contextloader), and [`authenticatedDocumentLoaderFactory`](#authenticateddocumentloaderfactory) cannot be configured. Mostly useful for testing purposes. Turned off by default. [SSRF]: https://owasp.org/www-community/attacks/Server_Side_Request_Forgery ### `outboxRetryPolicy` *This API is available since Fedify 0.12.0.* Loading docs/manual/test.md +35 −0 Original line number Diff line number Diff line Loading @@ -111,3 +111,38 @@ Fedify provides a [CLI toolchain](../cli.md) for testing and debugging. The [`fedify inbox` command](../cli.md#fedify-inbox-ephemeral-inbox-server) is a simple tool for spinning up an ephemeral inbox server that receives and displays incoming ActivityPub messages. Allowing fetching private network addresses ------------------------------------------- *This API is available since Fedify 0.15.0.* By default, Fedify disallows fetching private network addresses (e.g., localhost) in order to prevent [SSRF] attacks. However, in some cases, you may want to allow fetching private network addresses for testing purposes (e.g., end-to-end testing). In this case, you can set the [`allowPrivateAddress`](./federation.md#allowprivateaddress) option to `true` in the `createFederation()` function: ~~~~ typescript const federation = createFederation({ // ... other options allowPrivateAddress: true, }); ~~~~ > [!NOTE] > By turning on the `allowPrivateAddress` option, you cannot configure other > options related to document loaders including > [`documentLoader`](./federation.md#documentloader), > [`contextLoader`](./federation.md#contextloader), and > [`authenticatedDocumentLoaderFactory`](./federation.md#authenticateddocumentloaderfactory) > [!WARNING] > Be careful when you allow fetching private network addresses. It may cause > security vulnerabilities such as [SSRF]. Make sure to turn off the option > when you finish testing, or conditionally turn it on only in the testing > environment. [SSRF]: https://owasp.org/www-community/attacks/Server_Side_Request_Forgery src/federation/middleware.test.ts +22 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,28 @@ import { MemoryKvStore } from "./kv.ts"; import { createFederation } from "./middleware.ts"; import { RouterError } from "./router.ts"; test("createFederation()", () => { const kv = new MemoryKvStore(); assertThrows(() => createFederation<number>({ kv, documentLoader: mockDocumentLoader, allowPrivateAddress: true, }), TypeError); assertThrows(() => createFederation<number>({ kv, contextLoader: mockDocumentLoader, allowPrivateAddress: true, }), TypeError); assertThrows(() => createFederation<number>({ kv, authenticatedDocumentLoaderFactory: () => mockDocumentLoader, allowPrivateAddress: true, }), TypeError); }); test("Federation.createContext()", async (t) => { const kv = new MemoryKvStore(); const documentLoader = (url: string) => { Loading src/federation/middleware.ts +36 −2 Original line number Diff line number Diff line Loading @@ -121,6 +121,20 @@ export interface CreateFederationOptions { */ authenticatedDocumentLoaderFactory?: AuthenticatedDocumentLoaderFactory; /** * Whether to allow fetching private network addresses in the document loader. * * If turned on, {@link CreateFederationOptions.documentLoader}, * {@link CreateFederationOptions.contextLoader}, and * {@link CreateFederationOptions.authenticatedDocumentLoaderFactory} * cannot be configured. * * Mostly useful for testing purposes. *Do not use in production.* * * Turned off by default. */ allowPrivateAddress?: boolean; /** * A callback that handles errors during outbox processing. Note that this * callback can be called multiple times for the same activity, because Loading Loading @@ -742,15 +756,35 @@ class FederationImpl<TContextData> implements Federation<TContextData> { this.router.add("/.well-known/nodeinfo", "nodeInfoJrd"); this.objectCallbacks = {}; this.objectTypeIds = {}; if (options.allowPrivateAddress) { if (options.documentLoader != null) { throw new TypeError( "Cannot set documentLoader with allowPrivateAddress turned on.", ); } else if (options.contextLoader != null) { throw new TypeError( "Cannot set contextLoader with allowPrivateAddress turned on.", ); } else if (options.authenticatedDocumentLoaderFactory != null) { throw new TypeError( "Cannot set authenticatedDocumentLoaderFactory with " + "allowPrivateAddress turned on.", ); } } this.documentLoader = options.documentLoader ?? kvCache({ loader: fetchDocumentLoader, loader: options.allowPrivateAddress ? (url) => fetchDocumentLoader(url, true) : fetchDocumentLoader, kv: options.kv, prefix: this.kvPrefixes.remoteDocument, }); this.contextLoader = options.contextLoader ?? this.documentLoader; this.authenticatedDocumentLoaderFactory = options.authenticatedDocumentLoaderFactory ?? getAuthenticatedDocumentLoader; (options.allowPrivateAddress ? (identity) => getAuthenticatedDocumentLoader(identity, true) : getAuthenticatedDocumentLoader); this.onOutboxError = options.onOutboxError; this.signatureTimeWindow = options.signatureTimeWindow ?? { minutes: 1 }; this.skipSignatureVerification = options.skipSignatureVerification ?? false; Loading Loading
CHANGES.md +1 −0 Original line number Diff line number Diff line Loading @@ -11,6 +11,7 @@ To be released. - Removed `expand` option of `Object.toJsonLd()` method, which was deprecated in version 0.14.0. Use `format: "expand"` option instead. - Added `Context.lookupObject()` method. - Added `allowPrivateAddress` option to `CreateFederationOptions` interface. - Renamed the short option `-c` for `--compact` of `fedify lookup` command to `-C` to avoid conflict with the short option `-c` for `--cache-dir`. - Added `-r`/`--raw` option to `fedify lookup` command to output the raw JSON Loading
docs/manual/federation.md +21 −0 Original line number Diff line number Diff line Loading @@ -181,6 +181,27 @@ load remote JSON-LD contexts. The type of the function is the same as the [*Document loader vs. context loader* section](./context.md#document-loader-vs-context-loader)). ### `allowPrivateAddress` *This API is available since Fedify 0.15.0.* > [!WARNING] > Do not turn on this option in production environments. Disallowing fetching > private network addresses is a security feature to prevent [SSRF] attacks. Whether to allow fetching private network addresses in the document loader. If turned on, [`documentLoader`](#documentloader), [`contextLoader`](#contextloader), and [`authenticatedDocumentLoaderFactory`](#authenticateddocumentloaderfactory) cannot be configured. Mostly useful for testing purposes. Turned off by default. [SSRF]: https://owasp.org/www-community/attacks/Server_Side_Request_Forgery ### `outboxRetryPolicy` *This API is available since Fedify 0.12.0.* Loading
docs/manual/test.md +35 −0 Original line number Diff line number Diff line Loading @@ -111,3 +111,38 @@ Fedify provides a [CLI toolchain](../cli.md) for testing and debugging. The [`fedify inbox` command](../cli.md#fedify-inbox-ephemeral-inbox-server) is a simple tool for spinning up an ephemeral inbox server that receives and displays incoming ActivityPub messages. Allowing fetching private network addresses ------------------------------------------- *This API is available since Fedify 0.15.0.* By default, Fedify disallows fetching private network addresses (e.g., localhost) in order to prevent [SSRF] attacks. However, in some cases, you may want to allow fetching private network addresses for testing purposes (e.g., end-to-end testing). In this case, you can set the [`allowPrivateAddress`](./federation.md#allowprivateaddress) option to `true` in the `createFederation()` function: ~~~~ typescript const federation = createFederation({ // ... other options allowPrivateAddress: true, }); ~~~~ > [!NOTE] > By turning on the `allowPrivateAddress` option, you cannot configure other > options related to document loaders including > [`documentLoader`](./federation.md#documentloader), > [`contextLoader`](./federation.md#contextloader), and > [`authenticatedDocumentLoaderFactory`](./federation.md#authenticateddocumentloaderfactory) > [!WARNING] > Be careful when you allow fetching private network addresses. It may cause > security vulnerabilities such as [SSRF]. Make sure to turn off the option > when you finish testing, or conditionally turn it on only in the testing > environment. [SSRF]: https://owasp.org/www-community/attacks/Server_Side_Request_Forgery
src/federation/middleware.test.ts +22 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,28 @@ import { MemoryKvStore } from "./kv.ts"; import { createFederation } from "./middleware.ts"; import { RouterError } from "./router.ts"; test("createFederation()", () => { const kv = new MemoryKvStore(); assertThrows(() => createFederation<number>({ kv, documentLoader: mockDocumentLoader, allowPrivateAddress: true, }), TypeError); assertThrows(() => createFederation<number>({ kv, contextLoader: mockDocumentLoader, allowPrivateAddress: true, }), TypeError); assertThrows(() => createFederation<number>({ kv, authenticatedDocumentLoaderFactory: () => mockDocumentLoader, allowPrivateAddress: true, }), TypeError); }); test("Federation.createContext()", async (t) => { const kv = new MemoryKvStore(); const documentLoader = (url: string) => { Loading
src/federation/middleware.ts +36 −2 Original line number Diff line number Diff line Loading @@ -121,6 +121,20 @@ export interface CreateFederationOptions { */ authenticatedDocumentLoaderFactory?: AuthenticatedDocumentLoaderFactory; /** * Whether to allow fetching private network addresses in the document loader. * * If turned on, {@link CreateFederationOptions.documentLoader}, * {@link CreateFederationOptions.contextLoader}, and * {@link CreateFederationOptions.authenticatedDocumentLoaderFactory} * cannot be configured. * * Mostly useful for testing purposes. *Do not use in production.* * * Turned off by default. */ allowPrivateAddress?: boolean; /** * A callback that handles errors during outbox processing. Note that this * callback can be called multiple times for the same activity, because Loading Loading @@ -742,15 +756,35 @@ class FederationImpl<TContextData> implements Federation<TContextData> { this.router.add("/.well-known/nodeinfo", "nodeInfoJrd"); this.objectCallbacks = {}; this.objectTypeIds = {}; if (options.allowPrivateAddress) { if (options.documentLoader != null) { throw new TypeError( "Cannot set documentLoader with allowPrivateAddress turned on.", ); } else if (options.contextLoader != null) { throw new TypeError( "Cannot set contextLoader with allowPrivateAddress turned on.", ); } else if (options.authenticatedDocumentLoaderFactory != null) { throw new TypeError( "Cannot set authenticatedDocumentLoaderFactory with " + "allowPrivateAddress turned on.", ); } } this.documentLoader = options.documentLoader ?? kvCache({ loader: fetchDocumentLoader, loader: options.allowPrivateAddress ? (url) => fetchDocumentLoader(url, true) : fetchDocumentLoader, kv: options.kv, prefix: this.kvPrefixes.remoteDocument, }); this.contextLoader = options.contextLoader ?? this.documentLoader; this.authenticatedDocumentLoaderFactory = options.authenticatedDocumentLoaderFactory ?? getAuthenticatedDocumentLoader; (options.allowPrivateAddress ? (identity) => getAuthenticatedDocumentLoader(identity, true) : getAuthenticatedDocumentLoader); this.onOutboxError = options.onOutboxError; this.signatureTimeWindow = options.signatureTimeWindow ?? { minutes: 1 }; this.skipSignatureVerification = options.skipSignatureVerification ?? false; Loading