mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-02-09 08:38:53 +01:00
Fix absolute paths for data root. Allow setting data root via console args.
This commit is contained in:
parent
3e1ff9bc25
commit
dcbeab0aef
@ -102,6 +102,10 @@ const cliArguments = yargs(hideBin(process.argv))
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
describe: 'Enables whitelist mode',
|
||||
}).option('dataRoot', {
|
||||
type: 'string',
|
||||
default: null,
|
||||
describe: 'Root directory for data storage',
|
||||
}).parseSync();
|
||||
|
||||
// change all relative paths
|
||||
@ -121,6 +125,7 @@ const autorun = (cliArguments.autorun ?? getConfigValue('autorun', DEFAULT_AUTOR
|
||||
const listen = cliArguments.listen ?? getConfigValue('listen', DEFAULT_LISTEN);
|
||||
const enableCorsProxy = cliArguments.corsProxy ?? getConfigValue('enableCorsProxy', DEFAULT_CORS_PROXY);
|
||||
const enableWhitelist = cliArguments.whitelist ?? getConfigValue('whitelistMode', DEFAULT_WHITELIST);
|
||||
const dataRoot = cliArguments.dataRoot ?? getConfigValue('dataRoot', './data');
|
||||
const basicAuthMode = getConfigValue('basicAuthMode', false);
|
||||
const enableAccounts = getConfigValue('enableUserAccounts', false);
|
||||
|
||||
@ -526,7 +531,7 @@ const setupTasks = async function () {
|
||||
|
||||
// TODO: do endpoint init functions depend on certain directories existing or not existing? They should be callable
|
||||
// in any order for encapsulation reasons, but right now it's unknown if that would break anything.
|
||||
await userModule.initUserStorage();
|
||||
await userModule.initUserStorage(dataRoot);
|
||||
await settingsEndpoint.init();
|
||||
const directories = await userModule.ensurePublicDirectoriesExist();
|
||||
await userModule.migrateUserData();
|
||||
|
@ -1,5 +1,6 @@
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const mime = require('mime-types');
|
||||
const express = require('express');
|
||||
const sanitize = require('sanitize-filename');
|
||||
const fetch = require('node-fetch').default;
|
||||
@ -216,9 +217,11 @@ router.post('/download', jsonParser, async (request, response) => {
|
||||
await finished(res.body.pipe(fileStream));
|
||||
|
||||
if (category === 'character') {
|
||||
response.sendFile(temp_path, { root: process.cwd() }, () => {
|
||||
fs.rmSync(temp_path);
|
||||
});
|
||||
const fileContent = fs.readFileSync(temp_path);
|
||||
const contentType = mime.lookup(temp_path) || 'application/octet-stream';
|
||||
response.setHeader('Content-Type', contentType);
|
||||
response.send(fileContent);
|
||||
fs.rmSync(temp_path);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,13 @@
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const fsPromises = require('fs').promises;
|
||||
const readline = require('readline');
|
||||
const express = require('express');
|
||||
const sanitize = require('sanitize-filename');
|
||||
const writeFileAtomicSync = require('write-file-atomic').sync;
|
||||
const yaml = require('yaml');
|
||||
const _ = require('lodash');
|
||||
const mime = require('mime-types');
|
||||
|
||||
const jimp = require('jimp');
|
||||
|
||||
@ -1078,33 +1080,43 @@ router.post('/duplicate', jsonParser, async function (request, response) {
|
||||
});
|
||||
|
||||
router.post('/export', jsonParser, async function (request, response) {
|
||||
if (!request.body.format || !request.body.avatar_url) {
|
||||
return response.sendStatus(400);
|
||||
}
|
||||
try {
|
||||
if (!request.body.format || !request.body.avatar_url) {
|
||||
return response.sendStatus(400);
|
||||
}
|
||||
|
||||
let filename = path.join(request.user.directories.characters, sanitize(request.body.avatar_url));
|
||||
let filename = path.join(request.user.directories.characters, sanitize(request.body.avatar_url));
|
||||
|
||||
if (!fs.existsSync(filename)) {
|
||||
return response.sendStatus(404);
|
||||
}
|
||||
if (!fs.existsSync(filename)) {
|
||||
return response.sendStatus(404);
|
||||
}
|
||||
|
||||
switch (request.body.format) {
|
||||
case 'png':
|
||||
return response.sendFile(filename, { root: process.cwd() });
|
||||
case 'json': {
|
||||
try {
|
||||
let json = await readCharacterData(filename);
|
||||
if (json === undefined) return response.sendStatus(400);
|
||||
let jsonObject = getCharaCardV2(JSON.parse(json), request.user.directories);
|
||||
return response.type('json').send(JSON.stringify(jsonObject, null, 4));
|
||||
switch (request.body.format) {
|
||||
case 'png': {
|
||||
const fileContent = await fsPromises.readFile(filename);
|
||||
const contentType = mime.lookup(filename) || 'image/png';
|
||||
response.setHeader('Content-Type', contentType);
|
||||
response.setHeader('Content-Disposition', `attachment; filename=${path.basename(filename)}`);
|
||||
return response.send(fileContent);
|
||||
}
|
||||
catch {
|
||||
return response.sendStatus(400);
|
||||
case 'json': {
|
||||
try {
|
||||
let json = await readCharacterData(filename);
|
||||
if (json === undefined) return response.sendStatus(400);
|
||||
let jsonObject = getCharaCardV2(JSON.parse(json), request.user.directories);
|
||||
return response.type('json').send(JSON.stringify(jsonObject, null, 4));
|
||||
}
|
||||
catch {
|
||||
return response.sendStatus(400);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return response.sendStatus(400);
|
||||
return response.sendStatus(400);
|
||||
} catch (err) {
|
||||
console.error('Character export failed', err);
|
||||
response.sendStatus(500);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = { router };
|
||||
|
@ -122,7 +122,7 @@ async function seedContentForUser(contentIndex, directories, forceCategories) {
|
||||
}
|
||||
|
||||
const basePath = path.parse(contentItem.filename).base;
|
||||
const targetPath = path.join(process.cwd(), contentTarget, basePath);
|
||||
const targetPath = path.join(contentTarget, basePath);
|
||||
|
||||
if (fs.existsSync(targetPath)) {
|
||||
console.log(`Content file ${contentItem.filename} already exists in ${contentTarget}`);
|
||||
|
@ -1,5 +1,7 @@
|
||||
const fs = require('fs');
|
||||
const fsPromises = require('fs').promises;
|
||||
const path = require('path');
|
||||
const mime = require('mime-types');
|
||||
const express = require('express');
|
||||
const sanitize = require('sanitize-filename');
|
||||
const jimp = require('jimp');
|
||||
@ -165,38 +167,63 @@ const router = express.Router();
|
||||
|
||||
// Important: This route must be mounted as '/thumbnail'. It is used in the client code and saved to chat files.
|
||||
router.get('/', jsonParser, async function (request, response) {
|
||||
if (typeof request.query.file !== 'string' || typeof request.query.type !== 'string') return response.sendStatus(400);
|
||||
try{
|
||||
if (typeof request.query.file !== 'string' || typeof request.query.type !== 'string') {
|
||||
return response.sendStatus(400);
|
||||
}
|
||||
|
||||
const type = request.query.type;
|
||||
const file = sanitize(request.query.file);
|
||||
const type = request.query.type;
|
||||
const file = sanitize(request.query.file);
|
||||
|
||||
if (!type || !file) {
|
||||
return response.sendStatus(400);
|
||||
if (!type || !file) {
|
||||
return response.sendStatus(400);
|
||||
}
|
||||
|
||||
if (!(type == 'bg' || type == 'avatar')) {
|
||||
return response.sendStatus(400);
|
||||
}
|
||||
|
||||
if (sanitize(file) !== file) {
|
||||
console.error('Malicious filename prevented');
|
||||
return response.sendStatus(403);
|
||||
}
|
||||
|
||||
const thumbnailsDisabled = getConfigValue('disableThumbnails', false);
|
||||
if (thumbnailsDisabled) {
|
||||
const folder = getOriginalFolder(request.user.directories, type);
|
||||
|
||||
if (folder === undefined) {
|
||||
return response.sendStatus(400);
|
||||
}
|
||||
|
||||
const pathToOriginalFile = path.join(folder, file);
|
||||
if (!fs.existsSync(pathToOriginalFile)) {
|
||||
return response.sendStatus(404);
|
||||
}
|
||||
const contentType = mime.lookup(pathToOriginalFile) || 'image/png';
|
||||
const originalFile = await fsPromises.readFile(pathToOriginalFile);
|
||||
response.setHeader('Content-Type', contentType);
|
||||
return response.send(originalFile);
|
||||
}
|
||||
|
||||
const pathToCachedFile = await generateThumbnail(request.user.directories, type, file);
|
||||
|
||||
if (!pathToCachedFile) {
|
||||
return response.sendStatus(404);
|
||||
}
|
||||
|
||||
if (!fs.existsSync(pathToCachedFile)) {
|
||||
return response.sendStatus(404);
|
||||
}
|
||||
|
||||
const contentType = mime.lookup(pathToCachedFile) || 'image/jpeg';
|
||||
const cachedFile = await fsPromises.readFile(pathToCachedFile);
|
||||
response.setHeader('Content-Type', contentType);
|
||||
return response.send(cachedFile);
|
||||
} catch (error) {
|
||||
console.error('Failed getting thumbnail', error);
|
||||
return response.sendStatus(500);
|
||||
}
|
||||
|
||||
if (!(type == 'bg' || type == 'avatar')) {
|
||||
return response.sendStatus(400);
|
||||
}
|
||||
|
||||
if (sanitize(file) !== file) {
|
||||
console.error('Malicious filename prevented');
|
||||
return response.sendStatus(403);
|
||||
}
|
||||
|
||||
if (getConfigValue('disableThumbnails', false) == true) {
|
||||
let folder = getOriginalFolder(request.user.directories, type);
|
||||
if (folder === undefined) return response.sendStatus(400);
|
||||
const pathToOriginalFile = path.join(folder, file);
|
||||
return response.sendFile(pathToOriginalFile, { root: process.cwd() });
|
||||
}
|
||||
|
||||
const pathToCachedFile = await generateThumbnail(request.user.directories, type, file);
|
||||
|
||||
if (!pathToCachedFile) {
|
||||
return response.sendStatus(404);
|
||||
}
|
||||
|
||||
return response.sendFile(pathToCachedFile, { root: process.cwd() });
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
|
13
src/users.js
13
src/users.js
@ -15,10 +15,15 @@ const { getConfigValue, color, delay, setConfigValue, generateTimestamp } = requ
|
||||
const { readSecret, writeSecret } = require('./endpoints/secrets');
|
||||
|
||||
const KEY_PREFIX = 'user:';
|
||||
const DATA_ROOT = getConfigValue('dataRoot', './data');
|
||||
const ENABLE_ACCOUNTS = getConfigValue('enableUserAccounts', false);
|
||||
const ANON_CSRF_SECRET = crypto.randomBytes(64).toString('base64');
|
||||
|
||||
/**
|
||||
* The root directory for user data.
|
||||
* @type {string}
|
||||
*/
|
||||
let DATA_ROOT = './data';
|
||||
|
||||
/**
|
||||
* Cache for user directories.
|
||||
* @type {Map<string, UserDirectoryList>}
|
||||
@ -312,9 +317,13 @@ function toKey(handle) {
|
||||
|
||||
/**
|
||||
* Initializes the user storage. Currently a no-op.
|
||||
* @param {string} dataRoot The root directory for user data
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function initUserStorage() {
|
||||
async function initUserStorage(dataRoot) {
|
||||
DATA_ROOT = dataRoot;
|
||||
console.log('Using data root:', color.green(DATA_ROOT));
|
||||
console.log();
|
||||
await storage.init({
|
||||
dir: path.join(DATA_ROOT, '_storage'),
|
||||
ttl: true,
|
||||
|
Loading…
x
Reference in New Issue
Block a user