Rewrite to only consider Docker

This commit is contained in:
Cohee
2025-03-01 20:22:33 +02:00
parent 8aa7ed8635
commit 1d995fb92d
2 changed files with 20 additions and 61 deletions

View File

@@ -42,7 +42,8 @@ enableForwardedWhitelist: true
whitelist: whitelist:
- ::1 - ::1
- 127.0.0.1 - 127.0.0.1
- gateway.docker.internal # Automatically whitelist Docker host and gateway IPs
whitelistDockerHosts: true
# Toggle basic authentication for endpoints # Toggle basic authentication for endpoints
basicAuthMode: false basicAuthMode: false
# Basic authentication credentials # Basic authentication credentials

View File

@@ -3,14 +3,15 @@ import fs from 'node:fs';
import process from 'node:process'; import process from 'node:process';
import dns from 'node:dns'; import dns from 'node:dns';
import Handlebars from 'handlebars'; import Handlebars from 'handlebars';
import ipRegex from 'ip-regex';
import ipMatching from 'ip-matching'; import ipMatching from 'ip-matching';
import isDocker from 'is-docker';
import { getIpFromRequest } from '../express-common.js'; import { getIpFromRequest } from '../express-common.js';
import { color, getConfigValue, safeReadFileSync } from '../util.js'; import { color, getConfigValue, safeReadFileSync } from '../util.js';
const whitelistPath = path.join(process.cwd(), './whitelist.txt'); const whitelistPath = path.join(process.cwd(), './whitelist.txt');
const enableForwardedWhitelist = getConfigValue('enableForwardedWhitelist', false, 'boolean'); const enableForwardedWhitelist = !!getConfigValue('enableForwardedWhitelist', false, 'boolean');
const whitelistDockerHosts = !!getConfigValue('whitelistDockerHosts', false, 'boolean');
/** @type {string[]} */ /** @type {string[]} */
let whitelist = getConfigValue('whitelist', []); let whitelist = getConfigValue('whitelist', []);
@@ -48,69 +49,26 @@ function getForwardedIp(req) {
return undefined; return undefined;
} }
/**
* Checks if a string is a valid hostname according to RFC 1123
* @param {string} hostname The string to test
* @returns {boolean} True if the string is a valid hostname
*/
function isValidHostname(hostname) {
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;
return hostnameRegex.test(hostname);
}
/**
* Checks if a string is an IP address, CIDR notation, or IP wildcard
* @param {string} entry The string to test
* @returns {boolean} True if the string matches any IP format
*/
function isIpFormat(entry) {
// Match CIDR notation (e.g. 192.168.0.0/24)
if (entry.includes('/')) {
return true;
}
// Match exact IP address
if (ipRegex({ exact: true }).test(entry)) {
return true;
}
// Match IPv4 with wildcards (e.g. 192.168.*.* or 192.168.0.*)
const ipWildcardRegex = /^(\d{1,3}|\*)\.(\d{1,3}|\*)\.(\d{1,3}|\*)\.(\d{1,3}|\*)$/;
return ipWildcardRegex.test(entry);
}
/** /**
* Resolves hostnames in the whitelist to IP addresses. * Resolves hostnames in the whitelist to IP addresses.
* This function will modify the whitelist array in place. * This function will modify the whitelist array in place.
*/ */
async function resolveHostnames() { async function addDockerHostsToWhitelist() {
const resolvedWhitelist = []; if (!whitelistDockerHosts || !isDocker()) {
return;
}
const promises = whitelist.map(async (entry) => { const whitelistHosts = ['host.docker.internal', 'gateway.docker.internal'];
if (!entry || typeof entry !== 'string') {
return; for (const entry of whitelistHosts) {
try {
const result = await dns.promises.lookup(entry);
console.info(`Resolved whitelist hostname ${color.green(entry)} to IPv${result.family} address ${color.green(result.address)}`);
whitelist.push(result.address);
} catch (e) {
console.warn(`Failed to resolve whitelist hostname ${color.red(entry)}: ${e.message}`);
} }
}
// Skip if entry appears to be an IP address, CIDR notation, or IP wildcard
if (isIpFormat(entry)) {
resolvedWhitelist.push(entry);
return;
}
if (isValidHostname(entry)) {
try {
const result = await dns.promises.lookup(entry);
console.info(`Resolved whitelist hostname ${color.green(entry)} to IPv${result.family} address ${color.green(result.address)}`);
resolvedWhitelist.push(result.address);
} catch (e) {
console.warn(`Failed to resolve whitelist hostname ${color.red(entry)}: ${e.message}`);
}
} else {
resolvedWhitelist.push(entry);
}
});
await Promise.allSettled(promises);
} }
/** /**
@@ -126,7 +84,7 @@ export default async function getWhitelistMiddleware() {
'/favicon.ico', '/favicon.ico',
]; ];
await resolveHostnames(); await addDockerHostsToWhitelist();
return function (req, res, next) { return function (req, res, next) {
const clientIp = getIpFromRequest(req); const clientIp = getIpFromRequest(req);