Rewrite to only consider Docker

1d995fb92d20a9ae5362e8eabf8c838cc01ddd00

Cohee <18619528+Cohee1207@users.noreply.github.com>

2 files changed, +11 -52Showing whitespace changes
default/config.yaml+2 -1
@@ -42,7 +42,8 @@ enableForwardedWhitelist: true
4242whitelist:
4343 - ::1
4444 - 127.0.0.1
45- - gateway.docker.internal
45+# Automatically whitelist Docker host and gateway IPs
46+whitelistDockerHosts: true
4647# Toggle basic authentication for endpoints
4748basicAuthMode: false
4849# Basic authentication credentials
src/middleware/whitelist.js+9 -51
@@ -3,14 +3,15 @@ import fs from 'node:fs';
33import process from 'node:process';
44import dns from 'node:dns';
55import Handlebars from 'handlebars';
6-import ipRegex from 'ip-regex';
76import ipMatching from 'ip-matching';
7+import isDocker from 'is-docker';
88
99import { getIpFromRequest } from '../express-common.js';
1010import { color, getConfigValue, safeReadFileSync } from '../util.js';
1111
1212const whitelistPath = path.join(process.cwd(), './whitelist.txt');
1313const enableForwardedWhitelist = !!getConfigValue('enableForwardedWhitelist', false, 'boolean');
14+const whitelistDockerHosts = !!getConfigValue('whitelistDockerHosts', false, 'boolean');
1415/** @type {string[]} */
1516let whitelist = getConfigValue('whitelist', []);
1617
@@ -49,68 +50,25 @@ function getForwardedIp(req) {
4950}
5051
5152/**
52- * Checks if a string is a valid hostname according to RFC 1123
53- * @param {string} hostname The string to test
54- * @returns {boolean} True if the string is a valid hostname
55- */
56-function isValidHostname(hostname) {
57- const hostnameRegex = /^(([a-z0-9]|[a-z0-9][a-z0-9-]*[a-z0-9])\.)*([a-z0-9]|[a-z0-9][a-z0-9-]*[a-z0-9])$/i;
58- return hostnameRegex.test(hostname);
59-}
60-
61-/**
62- * Checks if a string is an IP address, CIDR notation, or IP wildcard
63- * @param {string} entry The string to test
64- * @returns {boolean} True if the string matches any IP format
65- */
66-function isIpFormat(entry) {
67- // Match CIDR notation (e.g. 192.168.0.0/24)
68- if (entry.includes('/')) {
69- return true;
70- }
71-
72- // Match exact IP address
73- if (ipRegex({ exact: true }).test(entry)) {
74- return true;
75- }
76-
77- // Match IPv4 with wildcards (e.g. 192.168.*.* or 192.168.0.*)
78- const ipWildcardRegex = /^(\d{1,3}|\*)\.(\d{1,3}|\*)\.(\d{1,3}|\*)\.(\d{1,3}|\*)$/;
79- return ipWildcardRegex.test(entry);
80-}
81-
82-/**
8353 * Resolves hostnames in the whitelist to IP addresses.
8454 * This function will modify the whitelist array in place.
8555 */
8656async function resolveHostnamesaddDockerHostsToWhitelist() {
87- const resolvedWhitelist = [];
57+ if (!whitelistDockerHosts || !isDocker()) {
88-
89- const promises = whitelist.map(async (entry) => {
90- if (!entry || typeof entry !== 'string') {
9158 return;
9259 }
9360
94- // Skip if entry appears to be an IP address, CIDR notation, or IP wildcard
61+ const whitelistHosts = ['host.docker.internal', 'gateway.docker.internal'];
95- if (isIpFormat(entry)) {
96- resolvedWhitelist.push(entry);
97- return;
98- }
9962
100- if (isValidHostname(entry)) {
63+ for (const entry of whitelistHosts) {
10164 try {
10265 const result = await dns.promises.lookup(entry);
10366 console.info(`Resolved whitelist hostname ${color.green(entry)} to IPv${result.family} address ${color.green(result.address)}`);
10467 resolvedWhitelist whitelist.push(result.address);
10568 } catch (e) {
10669 console.warn(`Failed to resolve whitelist hostname ${color.red(entry)}: ${e.message}`);
10770 }
108- } else {
109- resolvedWhitelist.push(entry);
11071 }
111- });
112-
113- await Promise.allSettled(promises);
11472}
11573
11674/**
@@ -126,7 +84,7 @@ export default async function getWhitelistMiddleware() {
12684 '/favicon.ico',
12785 ];
12886
12987 await resolveHostnamesaddDockerHostsToWhitelist();
13088
13189 return function (req, res, next) {
13290 const clientIp = getIpFromRequest(req);