-
-
Notifications
You must be signed in to change notification settings - Fork 35
Expand file tree
/
Copy pathfetch-handler.ts
More file actions
61 lines (55 loc) · 2.24 KB
/
Copy pathfetch-handler.ts
File metadata and controls
61 lines (55 loc) · 2.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import { behindProxy } from 'x-forwarded-fetch';
import { isLocalEnvironment } from '@/helpers/environment';
type FetchHandler = (request: Request) => Response | Promise<Response>;
/**
* Decorate a `fetch()` function so that the request is always treated as
* having been made over https.
*
* Canonical URLs are always https (see `AccountEntity.draft` /
* `AccountService.createInternalAccount`), but Fedify derives generated URIs
* (e.g. the actor's `publicKey.id`) from the incoming request URL. A reverse
* proxy that omits the `X-Forwarded-Proto` header would leave the request URL
* as http, producing http URIs that contradict the stored https actor IDs and
* breaking HTTP signature verification on remote servers.
*
* Fedify's `origin` option on `createFederation` would be the first-class way
* to pin generated URIs, but it takes a single static origin — unusable here,
* where the host varies per tenant.
*
* This must wrap a `fetch()` function already decorated with `behindProxy`
* (i.e. run before it), as `behindProxy` is what applies the header to the
* request URL — `createFetchHandler` owns that composition.
*/
function forceHttps(fetch: FetchHandler): FetchHandler {
return (request: Request) => {
request.headers.set('x-forwarded-proto', 'https');
return fetch(request);
};
}
function forceAcceptHeader(fetch: FetchHandler): FetchHandler {
return (request: Request) => {
request.headers.set('accept', 'application/activity+json');
return fetch(request);
};
}
/**
* Build the `fetch()` function passed to `serve()`: applies `X-Forwarded-*`
* headers to the request URL and forces the accept header, and — outside
* local environments, which serve plain http — forces the https scheme so
* generated URIs match the stored https canonical URLs regardless of proxy
* configuration.
*
* @param environment `process.env.NODE_ENV`
* @param fetch The app's `fetch()` function
*/
export function createFetchHandler(
environment: string | undefined,
fetch: FetchHandler,
): FetchHandler {
const proxiedFetch = behindProxy(fetch);
return forceAcceptHeader(
isLocalEnvironment(environment)
? proxiedFetch
: forceHttps(proxiedFetch),
);
}