Merge pull request #3478 from Dakraid/feature/set-listen-ip Feature: Allow user to configure an address to listen to
Signed| @@ -6,6 +6,10 @@ cardsCacheCapacity: 100 | ||
| 6 | 6 | # -- SERVER CONFIGURATION -- |
| 7 | 7 | # Listen for incoming connections |
| 8 | 8 | listen: false |
| 9 | +# Listen on a specific address, supports IPv4 and IPv6 | |
| 10 | +listenAddress: | |
| 11 | + ipv4: 0.0.0.0 | |
| 12 | + ipv6: '[::]' | |
| 9 | 13 | # Enables IPv6 and/or IPv4 protocols. Need to have at least one enabled! |
| 10 | 14 | # - Use option "auto" to automatically detect support |
| 11 | 15 | # - Use true or false (no qoutes) to enable or disable each protocol |
| @@ -41,6 +41,7 @@ | ||
| 41 | 41 | "html-entities": "^2.5.2", |
| 42 | 42 | "iconv-lite": "^0.6.3", |
| 43 | 43 | "ip-matching": "^2.1.2", |
| 44 | + "ip-regex": "^5.0.0", | |
| 44 | 45 | "ipaddr.js": "^2.0.1", |
| 45 | 46 | "jimp": "^0.22.10", |
| 46 | 47 | "localforage": "^1.10.0", |
| @@ -4628,6 +4629,18 @@ | ||
| 4628 | 4629 | "integrity": "sha512-/ok+VhKMasgR5gvTRViwRFQfc0qYt9Vdowg6TO4/pFlDCob5ZjGPkwuOoQVCd5OrMm20zqh+1vA8KLJZTeWudg==", |
| 4629 | 4630 | "license": "LGPL-3.0-only" |
| 4630 | 4631 | }, |
| 4632 | + "node_modules/ip-regex": { | |
| 4633 | + "version": "5.0.0", | |
| 4634 | + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-5.0.0.tgz", | |
| 4635 | + "integrity": "sha512-fOCG6lhoKKakwv+C6KdsOnGvgXnmgfmp0myi3bcNwj3qfwPAxRKWEuFhvEFF7ceYIz6+1jRZ+yguLFAmUNPEfw==", | |
| 4636 | + "license": "MIT", | |
| 4637 | + "engines": { | |
| 4638 | + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" | |
| 4639 | + }, | |
| 4640 | + "funding": { | |
| 4641 | + "url": "https://github.com/sponsors/sindresorhus" | |
| 4642 | + } | |
| 4643 | + }, | |
| 4631 | 4644 | "node_modules/ipaddr.js": { |
| 4632 | 4645 | "version": "2.1.0", |
| 4633 | 4646 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", |
| @@ -31,6 +31,7 @@ | ||
| 31 | 31 | "html-entities": "^2.5.2", |
| 32 | 32 | "iconv-lite": "^0.6.3", |
| 33 | 33 | "ip-matching": "^2.1.2", |
| 34 | + "ip-regex": "^5.0.0", | |
| 34 | 35 | "ipaddr.js": "^2.0.1", |
| 35 | 36 | "jimp": "^0.22.10", |
| 36 | 37 | "localforage": "^1.10.0", |
| @@ -89,6 +90,7 @@ | ||
| 89 | 90 | "version": "1.12.11", |
| 90 | 91 | "scripts": { |
| 91 | 92 | "start": "node server.js", |
| 93 | + "debug": "node server.js --inspect", | |
| 92 | 94 | "start:deno": "deno run --allow-run --allow-net --allow-read --allow-write --allow-sys --allow-env server.js", |
| 93 | 95 | "start:bun": "bun server.js", |
| 94 | 96 | "start:no-csrf": "node server.js --disableCsrf", |
| @@ -30,6 +30,7 @@ import bodyParser from 'body-parser'; | ||
| 30 | 30 | |
| 31 | 31 | // net related library imports |
| 32 | 32 | import fetch from 'node-fetch'; |
| 33 | +import ipRegex from 'ip-regex'; | |
| 33 | 34 | |
| 34 | 35 | // Unrestrict console logs display limit |
| 35 | 36 | util.inspect.defaultOptions.maxArrayLength = null; |
| @@ -130,6 +131,8 @@ if (process.versions && process.versions.node && process.versions.node.match(/20 | ||
| 130 | 131 | const DEFAULT_PORT = 8000; |
| 131 | 132 | const DEFAULT_AUTORUN = false; |
| 132 | 133 | const DEFAULT_LISTEN = false; |
| 134 | +const DEFAULT_LISTEN_ADDRESS_IPV6 = '[::]'; | |
| 135 | +const DEFAULT_LISTEN_ADDRESS_IPV4 = '0.0.0.0'; | |
| 133 | 136 | const DEFAULT_CORS_PROXY = false; |
| 134 | 137 | const DEFAULT_WHITELIST = true; |
| 135 | 138 | const DEFAULT_ACCOUNTS = false; |
| @@ -185,6 +188,14 @@ const cliArguments = yargs(hideBin(process.argv)) | ||
| 185 | 188 | type: 'boolean', |
| 186 | 189 | default: null, |
| 187 | 190 | 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}]`, |
| 191 | + }).option('listenAddressIPv6', { | |
| 192 | + type: 'string', | |
| 193 | + default: null, | |
| 194 | + describe: 'Set SillyTavern to listen to a specific IPv6 address. If not set, it will fallback to listen to all.\n[config default: [::] ]', | |
| 195 | + }).option('listenAddressIPv4', { | |
| 196 | + type: 'string', | |
| 197 | + default: null, | |
| 198 | + describe: 'Set SillyTavern to listen to a specific IPv4 address. If not set, it will fallback to listen to all.\n[config default: 0.0.0.0 ]', | |
| 188 | 199 | }).option('corsProxy', { |
| 189 | 200 | type: 'boolean', |
| 190 | 201 | default: null, |
| @@ -254,6 +265,10 @@ const server_port = cliArguments.port ?? process.env.SILLY_TAVERN_PORT ?? getCon | ||
| 254 | 265 | const autorun = (cliArguments.autorun ?? getConfigValue('autorun', DEFAULT_AUTORUN)) && !cliArguments.ssl; |
| 255 | 266 | /** @type {boolean} */ |
| 256 | 267 | const listen = cliArguments.listen ?? getConfigValue('listen', DEFAULT_LISTEN); |
| 268 | +/** @type {string} */ | |
| 269 | +const listenAddressIPv6 = cliArguments.listenAddressIPv6 ?? getConfigValue('listenAddress.ipv6', DEFAULT_LISTEN_ADDRESS_IPV6); | |
| 270 | +/** @type {string} */ | |
| 271 | +const listenAddressIPv4 = cliArguments.listenAddressIPv4 ?? getConfigValue('listenAddress.ipv4', DEFAULT_LISTEN_ADDRESS_IPV4); | |
| 257 | 272 | /** @type {boolean} */ |
| 258 | 273 | const enableCorsProxy = cliArguments.corsProxy ?? getConfigValue('enableCorsProxy', DEFAULT_CORS_PROXY); |
| 259 | 274 | const enableWhitelist = cliArguments.whitelist ?? getConfigValue('whitelistMode', DEFAULT_WHITELIST); |
| @@ -708,13 +723,13 @@ app.use('/api/azure', azureRouter); | ||
| 708 | 723 | |
| 709 | 724 | const tavernUrlV6 = new URL( |
| 710 | 725 | (cliArguments.ssl ? 'https://' : 'http://') + |
| 711 | 726 | (listen ? (ipRegex.v6({ exact: true }).test(listenAddressIPv6) ? listenAddressIPv6 : '[::]') : '[::1]') + |
| 712 | 727 | (':' + server_port), |
| 713 | 728 | ); |
| 714 | 729 | |
| 715 | 730 | const tavernUrl = new URL( |
| 716 | 731 | (cliArguments.ssl ? 'https://' : 'http://') + |
| 717 | 732 | (listen ? (ipRegex.v4({ exact: true }).test(listenAddressIPv4) ? listenAddressIPv4 : '0.0.0.0') : '127.0.0.1') + |
| 718 | 733 | (':' + server_port), |
| 719 | 734 | ); |
| 720 | 735 | |
| @@ -837,15 +852,15 @@ const postSetupTasks = async function (v6Failed, v4Failed, useIPv6, useIPv4) { | ||
| 837 | 852 | const plainGoToLog = removeColorFormatting(goToLog); |
| 838 | 853 | |
| 839 | 854 | console.log(logListen); |
| 855 | + if (listen) { | |
| 856 | + console.log(); | |
| 857 | + console.log('To limit connections to internal localhost only ([::1] or 127.0.0.1), change the setting in config.yaml to "listen: false".'); | |
| 858 | + console.log('Check the "access.log" file in the SillyTavern directory to inspect incoming connections.'); | |
| 859 | + } | |
| 840 | 860 | console.log('\n' + getSeparator(plainGoToLog.length) + '\n'); |
| 841 | 861 | console.log(goToLog); |
| 842 | 862 | console.log('\n' + getSeparator(plainGoToLog.length) + '\n'); |
| 843 | 863 | |
| 844 | - if (listen) { | |
| 845 | - console.log( | |
| 846 | - '[::] 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', | |
| 847 | - ); | |
| 848 | - } | |
| 849 | 864 | |
| 850 | 865 | if (basicAuthMode) { |
| 851 | 866 | if (perUserBasicAuth && !enableAccounts) { |
| @@ -1083,7 +1098,7 @@ async function verifySecuritySettings() { | ||
| 1083 | 1098 | } |
| 1084 | 1099 | |
| 1085 | 1100 | if (!enableAccounts) { |
| 1086 | 1101 | logSecurityAlert('Your current SillyTavern isconfiguration currentlyis insecurelyinsecure open(listening to the publicnon-localhost). Enable whitelisting, basic authentication or user accounts.'); |
| 1087 | 1102 | } |
| 1088 | 1103 | |
| 1089 | 1104 | const users = await getAllEnabledUsers(); |