Skip to content

Commit bcd5c8d

Browse files
Merge pull request #28 from MaddyGuthridge/maddy-cloudflare-requests
Add support for CF-Incoming-IP header
2 parents 29ba8ef + 90650cf commit bcd5c8d

File tree

7 files changed

+51
-4
lines changed

7 files changed

+51
-4
lines changed

src/lib/server/auth/setup.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ export async function authSetup(
5454
loginBannedIps: {},
5555
bannedIps: [],
5656
bannedUserAgents: [],
57+
allowCloudflareIp: false,
5758
keyPath: null,
5859
version,
5960
};

src/lib/server/data/localConfig.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,12 @@ export const ConfigLocalJsonStruct = object({
6767
* be blocked.
6868
*/
6969
bannedIps: array(string()),
70+
/**
71+
* Whether to allow determining incoming IP addresses using Cloudflare's
72+
* `CF-Connecting-IP` header. Only enable if running behind a Cloudflare
73+
* tunnel, otherwise the client's IP address can be faked.
74+
*/
75+
allowCloudflareIp: boolean(),
7076
/**
7177
* Array of regular expressions matching user-agent strings which should be
7278
* blocked.

src/lib/server/data/migrations/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import migrateToV020 from './v0.2.0';
55
import migrateToV030 from './v0.3.0';
66
import migrateToV040 from './v0.4.0';
77
import migrateToV060 from './v0.6.0';
8+
import migrateToV061 from './v0.6.1';
89
import semver from 'semver';
910

1011

@@ -22,8 +23,9 @@ const migrations: Record<string, MigrationFunction> = {
2223
// function
2324
'~0.4.0': migrateToV060,
2425
'~0.5.0': migrateToV060,
26+
'0.6.0': migrateToV061,
2527
// Pre-empt future releases
26-
'~0.6.0': updateConfigVersions,
28+
'~0.6.1': updateConfigVersions,
2729
};
2830

2931
/** Perform a migration from the given version */
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**
2+
* Migration to v0.6.1
3+
*/
4+
5+
import { setLocalConfig } from '../localConfig';
6+
import { unsafeLoadLocalConfig } from './unsafeLoad';
7+
8+
9+
export default async function migrate(dataDir: string, privateDataDir: string) {
10+
const config = await unsafeLoadLocalConfig(privateDataDir) as any;
11+
config.allowCloudflareIp = false;
12+
await setLocalConfig(config);
13+
}

src/lib/server/request.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/**
2+
* Code for managing more complex aspects of requests.
3+
*/
4+
5+
import type { RequestEvent } from '@sveltejs/kit';
6+
import { authIsSetUp } from './data/dataDir';
7+
import { getLocalConfig } from './data/localConfig';
8+
9+
/** Returns the IP address of the client that sent the request */
10+
export async function getIpFromRequest(event: RequestEvent): Promise<string> {
11+
if (!await authIsSetUp()) {
12+
return event.getClientAddress();
13+
}
14+
const config = await getLocalConfig();
15+
const realIp = event.getClientAddress();
16+
if (config.allowCloudflareIp) {
17+
return event.request.headers.get('CF-Connecting-IP') ?? realIp;
18+
} else {
19+
return realIp;
20+
}
21+
}

src/middleware/bans.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { authIsSetUp } from '$lib/server/data/dataDir';
22
import { getLocalConfig } from '$lib/server/data/localConfig';
3+
import { getIpFromRequest } from '$lib/server/request';
34
import { error, type Handle } from '@sveltejs/kit';
45

56
const banMiddleware: Handle = async (req) => {
@@ -12,7 +13,7 @@ const banMiddleware: Handle = async (req) => {
1213
return req.resolve(req.event);
1314
}
1415
const config = await getLocalConfig();
15-
const ip = req.event.getClientAddress();
16+
const ip = await getIpFromRequest(req.event);
1617
if (config.bannedIps.includes(ip)) {
1718
error(403, 'This IP address is banned');
1819
}

src/routes/api/admin/auth/login/+server.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@ import { isIpBanned, notifyFailedLogin } from '$lib/server/auth/fail2ban.js';
22
import { validateCredentials } from '$lib/server/auth/passwords';
33
import { generateToken } from '$lib/server/auth/tokens';
44
import { authIsSetUp } from '$lib/server/data/dataDir.js';
5+
import { getIpFromRequest } from '$lib/server/request.js';
56
import { error, json } from '@sveltejs/kit';
67

78

89
export async function POST(req: import('./$types.js').RequestEvent) {
910
if (!await authIsSetUp()) error(400, 'Auth is not set up yet');
1011

11-
if (await isIpBanned(req.getClientAddress())) {
12+
const ip = await getIpFromRequest(req);
13+
14+
if (await isIpBanned(ip)) {
1215
error(403, 'IP address is banned');
1316
}
1417

@@ -18,7 +21,7 @@ export async function POST(req: import('./$types.js').RequestEvent) {
1821
try {
1922
uid = await validateCredentials(username, password);
2023
} catch (e) {
21-
await notifyFailedLogin(req.getClientAddress());
24+
await notifyFailedLogin(ip);
2225
throw e;
2326
}
2427

0 commit comments

Comments
 (0)