mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-03-13 18:40:11 +01:00
Move cookie secret to data root. Make config.yaml immutable
This commit is contained in:
parent
3bb8b887e1
commit
7ea2c5f8cf
@ -79,8 +79,6 @@ minLogLevel: 0
|
||||
## Set to 0 to expire session when the browser is closed
|
||||
## Set to a negative number to disable session expiration
|
||||
sessionTimeout: -1
|
||||
# Used to sign session cookies. Will be auto-generated if not set
|
||||
cookieSecret: ''
|
||||
# Disable CSRF protection - NOT RECOMMENDED
|
||||
disableCsrfProtection: false
|
||||
# Disable startup security checks - NOT RECOMMENDED
|
||||
|
@ -104,6 +104,15 @@ const keyMigrationMap = [
|
||||
newKey: 'extensions.models.textToSpeech',
|
||||
migrate: (value) => value,
|
||||
},
|
||||
// uncommend one release after 1.12.13
|
||||
/*
|
||||
{
|
||||
oldKey: 'cookieSecret',
|
||||
newKey: 'cookieSecret',
|
||||
migrate: () => void 0,
|
||||
remove: true,
|
||||
},
|
||||
*/
|
||||
];
|
||||
|
||||
/**
|
||||
@ -163,8 +172,17 @@ function addMissingConfigValues() {
|
||||
|
||||
// Migrate old keys to new keys
|
||||
const migratedKeys = [];
|
||||
for (const { oldKey, newKey, migrate } of keyMigrationMap) {
|
||||
for (const { oldKey, newKey, migrate, remove } of keyMigrationMap) {
|
||||
if (_.has(config, oldKey)) {
|
||||
if (remove) {
|
||||
_.unset(config, oldKey);
|
||||
migratedKeys.push({
|
||||
oldKey,
|
||||
newValue: void 0,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
const oldValue = _.get(config, oldKey);
|
||||
const newValue = migrate(oldValue);
|
||||
_.set(config, newKey, newValue);
|
||||
|
@ -274,7 +274,7 @@ const listenAddressIPv4 = cliArguments.listenAddressIPv4 ?? getConfigValue('list
|
||||
const enableCorsProxy = cliArguments.corsProxy ?? getConfigValue('enableCorsProxy', DEFAULT_CORS_PROXY);
|
||||
const enableWhitelist = cliArguments.whitelist ?? getConfigValue('whitelistMode', DEFAULT_WHITELIST);
|
||||
/** @type {string} */
|
||||
const dataRoot = cliArguments.dataRoot ?? getConfigValue('dataRoot', './data');
|
||||
globalThis.DATA_ROOT = cliArguments.dataRoot ?? getConfigValue('dataRoot', './data');
|
||||
/** @type {boolean} */
|
||||
const disableCsrf = cliArguments.disableCsrf ?? getConfigValue('disableCsrfProtection', DEFAULT_CSRF_DISABLED);
|
||||
const basicAuthMode = cliArguments.basicAuthMode ?? getConfigValue('basicAuthMode', DEFAULT_BASIC_AUTH);
|
||||
@ -282,7 +282,7 @@ const perUserBasicAuth = getConfigValue('perUserBasicAuth', DEFAULT_PER_USER_BAS
|
||||
/** @type {boolean} */
|
||||
const enableAccounts = getConfigValue('enableUserAccounts', DEFAULT_ACCOUNTS);
|
||||
|
||||
const uploadsPath = path.join(dataRoot, UPLOADS_DIRECTORY);
|
||||
const uploadsPath = path.join(globalThis.DATA_ROOT, UPLOADS_DIRECTORY);
|
||||
|
||||
|
||||
/** @type {boolean | "auto"} */
|
||||
@ -466,7 +466,7 @@ app.use(cookieSession({
|
||||
sameSite: 'strict',
|
||||
httpOnly: true,
|
||||
maxAge: getSessionCookieAge(),
|
||||
secret: getCookieSecret(),
|
||||
secret: getCookieSecret(globalThis.DATA_ROOT),
|
||||
}));
|
||||
|
||||
app.use(setUserDataMiddleware);
|
||||
@ -1137,7 +1137,7 @@ function apply404Middleware() {
|
||||
}
|
||||
|
||||
// User storage module needs to be initialized before starting the server
|
||||
initUserStorage(dataRoot)
|
||||
initUserStorage(globalThis.DATA_ROOT)
|
||||
.then(ensurePublicDirectoriesExist)
|
||||
.then(migrateUserData)
|
||||
.then(migrateSystemPrompts)
|
||||
|
32
src/users.js
32
src/users.js
@ -15,7 +15,7 @@ import _ from 'lodash';
|
||||
import { sync as writeFileAtomicSync } from 'write-file-atomic';
|
||||
|
||||
import { USER_DIRECTORY_TEMPLATE, DEFAULT_USER, PUBLIC_DIRECTORIES, SETTINGS_FILE } from './constants.js';
|
||||
import { getConfigValue, color, delay, setConfigValue, generateTimestamp } from './util.js';
|
||||
import { getConfigValue, color, delay, generateTimestamp } from './util.js';
|
||||
import { readSecret, writeSecret } from './endpoints/secrets.js';
|
||||
import { getContentOfType } from './endpoints/content-manager.js';
|
||||
|
||||
@ -32,6 +32,7 @@ const ANON_CSRF_SECRET = crypto.randomBytes(64).toString('base64');
|
||||
*/
|
||||
const DIRECTORIES_CACHE = new Map();
|
||||
const PUBLIC_USER_AVATAR = '/img/default-user.png';
|
||||
const COOKIE_SECRET_PATH = 'cookie-secret.txt';
|
||||
|
||||
const STORAGE_KEYS = {
|
||||
csrfSecret: 'csrfSecret',
|
||||
@ -412,11 +413,10 @@ export function toAvatarKey(handle) {
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export async function initUserStorage(dataRoot) {
|
||||
globalThis.DATA_ROOT = dataRoot;
|
||||
console.log('Using data root:', color.green(globalThis.DATA_ROOT));
|
||||
console.log('Using data root:', color.green(dataRoot));
|
||||
console.log();
|
||||
await storage.init({
|
||||
dir: path.join(globalThis.DATA_ROOT, '_storage'),
|
||||
dir: path.join(dataRoot, '_storage'),
|
||||
ttl: false, // Never expire
|
||||
});
|
||||
|
||||
@ -430,17 +430,29 @@ export async function initUserStorage(dataRoot) {
|
||||
|
||||
/**
|
||||
* Get the cookie secret from the config. If it doesn't exist, generate a new one.
|
||||
* @param {string} dataRoot The root directory for user data
|
||||
* @returns {string} The cookie secret
|
||||
*/
|
||||
export function getCookieSecret() {
|
||||
let secret = getConfigValue(STORAGE_KEYS.cookieSecret);
|
||||
export function getCookieSecret(dataRoot) {
|
||||
const cookieSecretPath = path.join(dataRoot, COOKIE_SECRET_PATH);
|
||||
|
||||
if (!secret) {
|
||||
console.warn(color.yellow('Cookie secret is missing from config.yaml. Generating a new one...'));
|
||||
secret = crypto.randomBytes(64).toString('base64');
|
||||
setConfigValue(STORAGE_KEYS.cookieSecret, secret);
|
||||
if (fs.existsSync(cookieSecretPath)) {
|
||||
const stat = fs.statSync(cookieSecretPath);
|
||||
if (stat.size > 0) {
|
||||
return fs.readFileSync(cookieSecretPath, 'utf8');
|
||||
}
|
||||
}
|
||||
|
||||
const oldSecret = getConfigValue(STORAGE_KEYS.cookieSecret);
|
||||
if (oldSecret) {
|
||||
console.log('Migrating cookie secret from config.yaml...');
|
||||
writeFileAtomicSync(cookieSecretPath, oldSecret, { encoding: 'utf8' });
|
||||
return oldSecret;
|
||||
}
|
||||
|
||||
console.warn(color.yellow('Cookie secret is missing from data root. Generating a new one...'));
|
||||
const secret = crypto.randomBytes(64).toString('base64');
|
||||
writeFileAtomicSync(cookieSecretPath, secret, { encoding: 'utf8' });
|
||||
return secret;
|
||||
}
|
||||
|
||||
|
14
src/util.js
14
src/util.js
@ -9,7 +9,6 @@ import { promises as dnsPromise } from 'node:dns';
|
||||
|
||||
import yaml from 'yaml';
|
||||
import { sync as commandExistsSync } from 'command-exists';
|
||||
import { sync as writeFileAtomicSync } from 'write-file-atomic';
|
||||
import _ from 'lodash';
|
||||
import yauzl from 'yauzl';
|
||||
import mime from 'mime-types';
|
||||
@ -58,19 +57,6 @@ export function getConfigValue(key, defaultValue = null) {
|
||||
return _.get(config, key, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a value for the given key in the config object and writes it to the config.yaml file.
|
||||
* @param {string} key Key to set
|
||||
* @param {any} value Value to set
|
||||
*/
|
||||
export function setConfigValue(key, value) {
|
||||
// Reset cache so that the next getConfig call will read the updated config file
|
||||
CACHED_CONFIG = null;
|
||||
const config = getConfig();
|
||||
_.set(config, key, value);
|
||||
writeFileAtomicSync('./config.yaml', yaml.stringify(config));
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the Basic Auth header value for the given user and password.
|
||||
* @param {string} auth username:password
|
||||
|
Loading…
x
Reference in New Issue
Block a user