mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
Allow user to configure an address to listen to
This commit is contained in:
@ -6,6 +6,8 @@ cardsCacheCapacity: 100
|
|||||||
# -- SERVER CONFIGURATION --
|
# -- SERVER CONFIGURATION --
|
||||||
# Listen for incoming connections
|
# Listen for incoming connections
|
||||||
listen: false
|
listen: false
|
||||||
|
# Listen on a specific address, supports IPv4 and IPv6
|
||||||
|
listenAddress: 127.0.0.1
|
||||||
# Enables IPv6 and/or IPv4 protocols. Need to have at least one enabled!
|
# Enables IPv6 and/or IPv4 protocols. Need to have at least one enabled!
|
||||||
# - Use option "auto" to automatically detect support
|
# - Use option "auto" to automatically detect support
|
||||||
# - Use true or false (no qoutes) to enable or disable each protocol
|
# - Use true or false (no qoutes) to enable or disable each protocol
|
||||||
|
38
server.js
38
server.js
@ -130,6 +130,7 @@ if (process.versions && process.versions.node && process.versions.node.match(/20
|
|||||||
const DEFAULT_PORT = 8000;
|
const DEFAULT_PORT = 8000;
|
||||||
const DEFAULT_AUTORUN = false;
|
const DEFAULT_AUTORUN = false;
|
||||||
const DEFAULT_LISTEN = false;
|
const DEFAULT_LISTEN = false;
|
||||||
|
const DEFAULT_LISTEN_ADDRESS = '';
|
||||||
const DEFAULT_CORS_PROXY = false;
|
const DEFAULT_CORS_PROXY = false;
|
||||||
const DEFAULT_WHITELIST = true;
|
const DEFAULT_WHITELIST = true;
|
||||||
const DEFAULT_ACCOUNTS = false;
|
const DEFAULT_ACCOUNTS = false;
|
||||||
@ -185,6 +186,10 @@ const cliArguments = yargs(hideBin(process.argv))
|
|||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
default: null,
|
default: null,
|
||||||
describe: `SillyTavern is listening on all network interfaces (Wi-Fi, LAN, localhost). If false, will limit it only to internal localhost (127.0.0.1).\nIf not provided falls back to yaml config 'listen'.\n[config default: ${DEFAULT_LISTEN}]`,
|
describe: `SillyTavern is listening on all network interfaces (Wi-Fi, LAN, localhost). If false, will limit it only to internal localhost (127.0.0.1).\nIf not provided falls back to yaml config 'listen'.\n[config default: ${DEFAULT_LISTEN}]`,
|
||||||
|
}).option('listenAddress', {
|
||||||
|
type: 'string',
|
||||||
|
default: null,
|
||||||
|
describe: 'Set SillyTavern to listen to a specific address. If not set, it will fallback to listen to all.\n[config default: empty ]',
|
||||||
}).option('corsProxy', {
|
}).option('corsProxy', {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
default: null,
|
default: null,
|
||||||
@ -254,6 +259,8 @@ const server_port = cliArguments.port ?? process.env.SILLY_TAVERN_PORT ?? getCon
|
|||||||
const autorun = (cliArguments.autorun ?? getConfigValue('autorun', DEFAULT_AUTORUN)) && !cliArguments.ssl;
|
const autorun = (cliArguments.autorun ?? getConfigValue('autorun', DEFAULT_AUTORUN)) && !cliArguments.ssl;
|
||||||
/** @type {boolean} */
|
/** @type {boolean} */
|
||||||
const listen = cliArguments.listen ?? getConfigValue('listen', DEFAULT_LISTEN);
|
const listen = cliArguments.listen ?? getConfigValue('listen', DEFAULT_LISTEN);
|
||||||
|
/** @type {string} */
|
||||||
|
const listenAddress = cliArguments.listenAddress ?? getConfigValue('listenAddress', DEFAULT_LISTEN_ADDRESS);
|
||||||
/** @type {boolean} */
|
/** @type {boolean} */
|
||||||
const enableCorsProxy = cliArguments.corsProxy ?? getConfigValue('enableCorsProxy', DEFAULT_CORS_PROXY);
|
const enableCorsProxy = cliArguments.corsProxy ?? getConfigValue('enableCorsProxy', DEFAULT_CORS_PROXY);
|
||||||
const enableWhitelist = cliArguments.whitelist ?? getConfigValue('whitelistMode', DEFAULT_WHITELIST);
|
const enableWhitelist = cliArguments.whitelist ?? getConfigValue('whitelistMode', DEFAULT_WHITELIST);
|
||||||
@ -706,15 +713,17 @@ app.use('/api/backends/scale-alt', scaleAltRouter);
|
|||||||
app.use('/api/speech', speechRouter);
|
app.use('/api/speech', speechRouter);
|
||||||
app.use('/api/azure', azureRouter);
|
app.use('/api/azure', azureRouter);
|
||||||
|
|
||||||
|
const ipv6_regex = /^(?:(?:[a-fA-F\d]{1,4}:){7}(?:[a-fA-F\d]{1,4}|:)|(?:[a-fA-F\d]{1,4}:){6}(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|:[a-fA-F\d]{1,4}|:)|(?:[a-fA-F\d]{1,4}:){5}(?::(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,2}|:)|(?:[a-fA-F\d]{1,4}:){4}(?:(?::[a-fA-F\d]{1,4}){0,1}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,3}|:)|(?:[a-fA-F\d]{1,4}:){3}(?:(?::[a-fA-F\d]{1,4}){0,2}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,4}|:)|(?:[a-fA-F\d]{1,4}:){2}(?:(?::[a-fA-F\d]{1,4}){0,3}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,5}|:)|(?:[a-fA-F\d]{1,4}:){1}(?:(?::[a-fA-F\d]{1,4}){0,4}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,6}|:)|(?::(?:(?::[a-fA-F\d]{1,4}){0,5}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,7}|:)))(?:%[0-9a-zA-Z]{1,})?$/m;
|
||||||
const tavernUrlV6 = new URL(
|
const tavernUrlV6 = new URL(
|
||||||
(cliArguments.ssl ? 'https://' : 'http://') +
|
(cliArguments.ssl ? 'https://' : 'http://') +
|
||||||
(listen ? '[::]' : '[::1]') +
|
(listen ? (ipv6_regex.test(listenAddress) ? listenAddress : '[::]') : '[::1]') +
|
||||||
(':' + server_port),
|
(':' + server_port),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const ipv4_regex = /^(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}$/m;
|
||||||
const tavernUrl = new URL(
|
const tavernUrl = new URL(
|
||||||
(cliArguments.ssl ? 'https://' : 'http://') +
|
(cliArguments.ssl ? 'https://' : 'http://') +
|
||||||
(listen ? '0.0.0.0' : '127.0.0.1') +
|
(listen ? (ipv4_regex.test(listenAddress) ? listenAddress : '0.0.0.0') : '127.0.0.1') +
|
||||||
(':' + server_port),
|
(':' + server_port),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -780,6 +789,10 @@ const preSetupTasks = async function () {
|
|||||||
*/
|
*/
|
||||||
async function getAutorunHostname(useIPv6, useIPv4) {
|
async function getAutorunHostname(useIPv6, useIPv4) {
|
||||||
if (autorunHostname === 'auto') {
|
if (autorunHostname === 'auto') {
|
||||||
|
if (listen && (ipv4_regex.test(listenAddress) || ipv6_regex.test(listenAddress))) {
|
||||||
|
return listenAddress;
|
||||||
|
}
|
||||||
|
|
||||||
let localhostResolve = await canResolve('localhost', useIPv6, useIPv4);
|
let localhostResolve = await canResolve('localhost', useIPv6, useIPv4);
|
||||||
|
|
||||||
if (useIPv6 && useIPv4) {
|
if (useIPv6 && useIPv4) {
|
||||||
@ -842,10 +855,16 @@ const postSetupTasks = async function (v6Failed, v4Failed, useIPv6, useIPv4) {
|
|||||||
console.log('\n' + getSeparator(plainGoToLog.length) + '\n');
|
console.log('\n' + getSeparator(plainGoToLog.length) + '\n');
|
||||||
|
|
||||||
if (listen) {
|
if (listen) {
|
||||||
|
if (ipv4_regex.test(listenAddress) || ipv6_regex.test(listenAddress)) {
|
||||||
|
console.log(
|
||||||
|
`SillyTavern is listening on the address ${listenAddress}. If you want to limit it only to internal localhost ([::1] or 127.0.0.1), change the setting in config.yaml to "listen: false". Check "access.log" file in the SillyTavern directory if you want to inspect incoming connections.\n`,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
console.log(
|
console.log(
|
||||||
'[::] or 0.0.0.0 means SillyTavern is listening on all network interfaces (Wi-Fi, LAN, localhost). If you want to limit it only to internal localhost ([::1] or 127.0.0.1), change the setting in config.yaml to "listen: false". Check "access.log" file in the SillyTavern directory if you want to inspect incoming connections.\n',
|
'[::] or 0.0.0.0 means SillyTavern is listening on all network interfaces (Wi-Fi, LAN, localhost). If you want to limit it only to internal localhost ([::1] or 127.0.0.1), change the setting in config.yaml to "listen: false". Check "access.log" file in the SillyTavern directory if you want to inspect incoming connections.\n',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (basicAuthMode) {
|
if (basicAuthMode) {
|
||||||
if (perUserBasicAuth && !enableAccounts) {
|
if (perUserBasicAuth && !enableAccounts) {
|
||||||
@ -908,6 +927,19 @@ function logSecurityAlert(message) {
|
|||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints a warning message
|
||||||
|
* @param {string} message The warning message to print
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
function logSecurityWarning(message) {
|
||||||
|
if (basicAuthMode || enableWhitelist) return; // safe!
|
||||||
|
console.error(color.yellow(message));
|
||||||
|
if (getConfigValue('securityOverride', false)) {
|
||||||
|
console.warn(color.red('Security has been overridden. If it\'s not a trusted network, change the settings.'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the case where the server failed to start on one or both protocols.
|
* Handles the case where the server failed to start on one or both protocols.
|
||||||
* @param {boolean} v6Failed If the server failed to start on IPv6
|
* @param {boolean} v6Failed If the server failed to start on IPv6
|
||||||
@ -1083,7 +1115,7 @@ async function verifySecuritySettings() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!enableAccounts) {
|
if (!enableAccounts) {
|
||||||
logSecurityAlert('Your SillyTavern is currently insecurely open to the public. Enable whitelisting, basic authentication or user accounts.');
|
logSecurityAlert('Your current SillyTavern configuration is insecure (listening to non-localhost). Enable whitelisting, basic authentication or user accounts.');
|
||||||
}
|
}
|
||||||
|
|
||||||
const users = await getAllEnabledUsers();
|
const users = await getAllEnabledUsers();
|
||||||
|
Reference in New Issue
Block a user