SillyTavern/src/middleware/whitelist.js

86 lines
3.6 KiB
JavaScript
Raw Normal View History

2024-10-11 00:28:17 +03:00
import path from 'node:path';
import fs from 'node:fs';
2024-10-11 10:43:29 +03:00
import process from 'node:process';
2024-10-10 22:37:22 +03:00
import ipMatching from 'ip-matching';
2024-10-10 22:37:22 +03:00
import { getIpFromRequest } from '../express-common.js';
import { color, getConfigValue } from '../util.js';
const whitelistPath = path.join(process.cwd(), './whitelist.txt');
const enableForwardedWhitelist = getConfigValue('enableForwardedWhitelist', false);
let whitelist = getConfigValue('whitelist', []);
2023-12-15 18:43:00 +02:00
let knownIPs = new Set();
if (fs.existsSync(whitelistPath)) {
try {
let whitelistTxt = fs.readFileSync(whitelistPath, 'utf-8');
whitelist = whitelistTxt.split('\n').filter(ip => ip).map(ip => ip.trim());
} catch (e) {
// Ignore errors that may occur when reading the whitelist (e.g. permissions)
}
}
2024-04-13 15:26:48 +03:00
/**
* Get the client IP address from the request headers.
* @param {import('express').Request} req Express request object
* @returns {string|undefined} The client IP address
*/
2024-04-12 22:03:36 -07:00
function getForwardedIp(req) {
if (!enableForwardedWhitelist) {
return undefined;
}
2024-04-12 22:03:36 -07:00
// Check if X-Real-IP is available
if (req.headers['x-real-ip']) {
return req.headers['x-real-ip'].toString();
2024-04-12 22:03:36 -07:00
}
// Check for X-Forwarded-For and parse if available
if (req.headers['x-forwarded-for']) {
const ipList = req.headers['x-forwarded-for'].toString().split(',').map(ip => ip.trim());
2024-04-12 22:03:36 -07:00
return ipList[0];
}
// If none of the headers are available, return undefined
return undefined;
}
/**
* Returns a middleware function that checks if the client IP is in the whitelist.
* @param {boolean} whitelistMode If whitelist mode is enabled via config or command line
* @param {boolean} listen If listen mode is enabled via config or command line
* @returns {import('express').RequestHandler} The middleware function
*/
2024-10-10 22:37:22 +03:00
export default function whitelistMiddleware(whitelistMode, listen) {
return function (req, res, next) {
const clientIp = getIpFromRequest(req);
2024-04-12 22:03:36 -07:00
const forwardedIp = getForwardedIp(req);
if (listen && !knownIPs.has(clientIp)) {
const userAgent = req.headers['user-agent'];
console.log(color.yellow(`New connection from ${clientIp}; User Agent: ${userAgent}\n`));
knownIPs.add(clientIp);
// Write access log
const timestamp = new Date().toISOString();
const log = `${timestamp} ${clientIp} ${userAgent}\n`;
fs.appendFile('access.log', log, (err) => {
if (err) {
console.error('Failed to write access log:', err);
}
});
}
//clientIp = req.connection.remoteAddress.split(':').pop();
2024-04-12 22:03:36 -07:00
if (whitelistMode === true && !whitelist.some(x => ipMatching.matches(clientIp, ipMatching.getMatch(x)))
|| forwardedIp && whitelistMode === true && !whitelist.some(x => ipMatching.matches(forwardedIp, ipMatching.getMatch(x)))
) {
// Log the connection attempt with real IP address
const ipDetails = forwardedIp ? `${clientIp} (forwarded from ${forwardedIp})` : clientIp;
console.log(color.red('Forbidden: Connection attempt from ' + ipDetails + '. If you are attempting to connect, please add your IP address in whitelist or disable whitelist mode in config.yaml in root of SillyTavern folder.\n'));
return res.status(403).send('<b>Forbidden</b>: Connection attempt from <b>' + ipDetails + '</b>. If you are attempting to connect, please add your IP address in whitelist or disable whitelist mode in config.yaml in root of SillyTavern folder.');
}
next();
};
}