2023-12-14 17:36:41 -05:00
const path = require ( 'path' ) ;
const fs = require ( 'fs' ) ;
const ipMatching = require ( 'ip-matching' ) ;
2024-04-09 21:58:16 +03:00
const { getIpFromRequest } = require ( '../express-common' ) ;
2023-12-14 17:36:41 -05:00
const { color , getConfigValue } = require ( '../util' ) ;
const whitelistPath = path . join ( process . cwd ( ) , './whitelist.txt' ) ;
2024-04-22 15:52:59 +03:00
const enableForwardedWhitelist = getConfigValue ( 'enableForwardedWhitelist' , false ) ;
2023-12-14 17:36:41 -05:00
let whitelist = getConfigValue ( 'whitelist' , [ ] ) ;
2023-12-15 18:43:00 +02:00
let knownIPs = new Set ( ) ;
2023-12-14 17:36:41 -05:00
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 ) {
2024-04-22 15:52:59 +03:00
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' ] ) {
2024-04-22 15:52:59 +03:00
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' ] ) {
2024-04-22 15:52:59 +03:00
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 ;
}
2024-03-30 22:42:51 +02:00
/ * *
* Returns a middleware function that checks if the client IP is in the whitelist .
2024-04-12 01:33:39 +03:00
* @ param { boolean } whitelistMode If whitelist mode is enabled via config or command line
2024-03-30 22:42:51 +02:00
* @ param { boolean } listen If listen mode is enabled via config or command line
* @ returns { import ( 'express' ) . RequestHandler } The middleware function
* /
2024-04-12 01:33:39 +03:00
function whitelistMiddleware ( whitelistMode , listen ) {
2024-03-30 22:42:51 +02:00
return function ( req , res , next ) {
const clientIp = getIpFromRequest ( req ) ;
2024-04-12 22:03:36 -07:00
const forwardedIp = getForwardedIp ( req ) ;
2023-12-14 17:36:41 -05:00
2024-03-30 22:42:51 +02:00
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.' ) ;
2024-03-30 22:42:51 +02:00
}
next ( ) ;
} ;
}
2023-12-14 17:36:41 -05:00
module . exports = whitelistMiddleware ;