Use default middleware for parsing request body

67d013e40a404ba350e7cf8626f1dd709ab2e57d

Cohee <18619528+Cohee1207@users.noreply.github.com>

44 files changed, +253 -298Showing whitespace changes
server.js+3 -3
@@ -113,6 +113,9 @@ app.use(helmet({
113app.use(compression());113app.use(compression());
114app.use(responseTime());114app.use(responseTime());
115115
116app.use(bodyParser.json({ limit: '200mb' }));
117app.use(bodyParser.urlencoded({ extended: true, limit: '200mb' }));
118
116// CORS Settings //119// CORS Settings //
117const CORS = cors({120const CORS = cors({
118 origin: 'null',121 origin: 'null',
@@ -135,9 +138,6 @@ if (cliArgs.listen) {
135}138}
136139
137if (cliArgs.enableCorsProxy) {140if (cliArgs.enableCorsProxy) {
138 app.use(bodyParser.json({
139 limit: '200mb',
140 }));
141 app.use('/proxy/:url(*)', corsProxyMiddleware);141 app.use('/proxy/:url(*)', corsProxyMiddleware);
142} else {142} else {
143 app.use('/proxy/:url(*)', async (_, res) => {143 app.use('/proxy/:url(*)', async (_, res) => {
src/endpoints/anthropic.js+1 -2
@@ -2,11 +2,10 @@ import fetch from 'node-fetch';
2import express from 'express';2import express from 'express';
33
4import { readSecret, SECRET_KEYS } from './secrets.js';4import { readSecret, SECRET_KEYS } from './secrets.js';
5import { jsonParser } from '../express-common.js';
65
7export const router = express.Router();6export const router = express.Router();
87
9router.post('/caption-image', jsonParser, async (request, response) => {8router.post('/caption-image', async (request, response) => {
10 try {9 try {
11 const mimeType = request.body.image.split(';')[0].split(':')[1];10 const mimeType = request.body.image.split(';')[0].split(':')[1];
12 const base64Data = request.body.image.split(',')[1];11 const base64Data = request.body.image.split(',')[1];
src/endpoints/assets.js+4 -5
@@ -8,7 +8,6 @@ import sanitize from 'sanitize-filename';
8import fetch from 'node-fetch';8import fetch from 'node-fetch';
99
10import { UNSAFE_EXTENSIONS } from '../constants.js';10import { UNSAFE_EXTENSIONS } from '../constants.js';
11import { jsonParser } from '../express-common.js';
12import { clientRelativePath } from '../util.js';11import { clientRelativePath } from '../util.js';
1312
14const VALID_CATEGORIES = ['bgm', 'ambient', 'blip', 'live2d', 'vrm', 'character', 'temp'];13const VALID_CATEGORIES = ['bgm', 'ambient', 'blip', 'live2d', 'vrm', 'character', 'temp'];
@@ -105,7 +104,7 @@ export const router = express.Router();
105 *104 *
106 * @returns {void}105 * @returns {void}
107 */106 */
108router.post('/get', jsonParser, async (request, response) => {107router.post('/get', async (request, response) => {
109 const folderPath = path.join(request.user.directories.assets);108 const folderPath = path.join(request.user.directories.assets);
110 let output = {};109 let output = {};
111110
@@ -189,7 +188,7 @@ router.post('/get', jsonParser, async (request, response) => {
189 *188 *
190 * @returns {void}189 * @returns {void}
191 */190 */
192router.post('/download', jsonParser, async (request, response) => {191router.post('/download', async (request, response) => {
193 const url = request.body.url;192 const url = request.body.url;
194 const inputCategory = request.body.category;193 const inputCategory = request.body.category;
195194
@@ -260,7 +259,7 @@ router.post('/download', jsonParser, async (request, response) => {
260 *259 *
261 * @returns {void}260 * @returns {void}
262 */261 */
263router.post('/delete', jsonParser, async (request, response) => {262router.post('/delete', async (request, response) => {
264 const inputCategory = request.body.category;263 const inputCategory = request.body.category;
265264
266 // Check category265 // Check category
@@ -312,7 +311,7 @@ router.post('/delete', jsonParser, async (request, response) => {
312 *311 *
313 * @returns {void}312 * @returns {void}
314 */313 */
315router.post('/character', jsonParser, async (request, response) => {314router.post('/character', async (request, response) => {
316 if (request.query.name === undefined) return response.sendStatus(400);315 if (request.query.name === undefined) return response.sendStatus(400);
317316
318 // For backwards compatibility, don't reject invalid character names, just sanitize them317 // For backwards compatibility, don't reject invalid character names, just sanitize them
src/endpoints/avatars.js+3 -4
@@ -6,19 +6,18 @@ import sanitize from 'sanitize-filename';
6import jimp from 'jimp';6import jimp from 'jimp';
7import { sync as writeFileAtomicSync } from 'write-file-atomic';7import { sync as writeFileAtomicSync } from 'write-file-atomic';
88
9import { jsonParser, urlencodedParser } from '../express-common.js';
10import { AVATAR_WIDTH, AVATAR_HEIGHT } from '../constants.js';9import { AVATAR_WIDTH, AVATAR_HEIGHT } from '../constants.js';
11import { getImages, tryParse } from '../util.js';10import { getImages, tryParse } from '../util.js';
12import { getFileNameValidationFunction } from '../middleware/validateFileName.js';11import { getFileNameValidationFunction } from '../middleware/validateFileName.js';
1312
14export const router = express.Router();13export const router = express.Router();
1514
16router.post('/get', jsonParser, function (request, response) {15router.post('/get', function (request, response) {
17 var images = getImages(request.user.directories.avatars);16 var images = getImages(request.user.directories.avatars);
18 response.send(JSON.stringify(images));17 response.send(JSON.stringify(images));
19});18});
2019
21router.post('/delete', jsonParser, getFileNameValidationFunction('avatar'), function (request, response) {20router.post('/delete', getFileNameValidationFunction('avatar'), function (request, response) {
22 if (!request.body) return response.sendStatus(400);21 if (!request.body) return response.sendStatus(400);
2322
24 if (request.body.avatar !== sanitize(request.body.avatar)) {23 if (request.body.avatar !== sanitize(request.body.avatar)) {
@@ -36,7 +35,7 @@ router.post('/delete', jsonParser, getFileNameValidationFunction('avatar'), func
36 return response.sendStatus(404);35 return response.sendStatus(404);
37});36});
3837
39router.post('/upload', urlencodedParser, async (request, response) => {38router.post('/upload', async (request, response) => {
40 if (!request.file) return response.sendStatus(400);39 if (!request.file) return response.sendStatus(400);
4140
42 try {41 try {
src/endpoints/azure.js+2 -3
@@ -2,11 +2,10 @@ import fetch from 'node-fetch';
2import { Router } from 'express';2import { Router } from 'express';
33
4import { readSecret, SECRET_KEYS } from './secrets.js';4import { readSecret, SECRET_KEYS } from './secrets.js';
5import { jsonParser } from '../express-common.js';
65
7export const router = Router();6export const router = Router();
87
9router.post('/list', jsonParser, async (req, res) => {8router.post('/list', async (req, res) => {
10 try {9 try {
11 const key = readSecret(req.user.directories, SECRET_KEYS.AZURE_TTS);10 const key = readSecret(req.user.directories, SECRET_KEYS.AZURE_TTS);
1211
@@ -44,7 +43,7 @@ router.post('/list', jsonParser, async (req, res) => {
44 }43 }
45});44});
4645
47router.post('/generate', jsonParser, async (req, res) => {46router.post('/generate', async (req, res) => {
48 try {47 try {
49 const key = readSecret(req.user.directories, SECRET_KEYS.AZURE_TTS);48 const key = readSecret(req.user.directories, SECRET_KEYS.AZURE_TTS);
5049
src/endpoints/backends/chat-completions.js+3 -4
@@ -2,7 +2,6 @@ import process from 'node:process';
2import express from 'express';2import express from 'express';
3import fetch from 'node-fetch';3import fetch from 'node-fetch';
44
5import { jsonParser } from '../../express-common.js';
6import {5import {
7 CHAT_COMPLETION_SOURCES,6 CHAT_COMPLETION_SOURCES,
8 GEMINI_SAFETY,7 GEMINI_SAFETY,
@@ -821,7 +820,7 @@ async function sendDeepSeekRequest(request, response) {
821820
822export const router = express.Router();821export const router = express.Router();
823822
824router.post('/status', jsonParser, async function (request, response_getstatus_openai) {823router.post('/status', async function (request, response_getstatus_openai) {
825 if (!request.body) return response_getstatus_openai.sendStatus(400);824 if (!request.body) return response_getstatus_openai.sendStatus(400);
826825
827 let api_url;826 let api_url;
@@ -937,7 +936,7 @@ router.post('/status', jsonParser, async function (request, response_getstatus_o
937 }936 }
938});937});
939938
940router.post('/bias', jsonParser, async function (request, response) {939router.post('/bias', async function (request, response) {
941 if (!request.body || !Array.isArray(request.body))940 if (!request.body || !Array.isArray(request.body))
942 return response.sendStatus(400);941 return response.sendStatus(400);
943942
@@ -1022,7 +1021,7 @@ router.post('/bias', jsonParser, async function (request, response) {
1022});1021});
10231022
10241023
1025router.post('/generate', jsonParser, function (request, response) {1024router.post('/generate', function (request, response) {
1026 if (!request.body) return response.status(400).send({ error: true });1025 if (!request.body) return response.status(400).send({ error: true });
10271026
1028 switch (request.body.chat_completion_source) {1027 switch (request.body.chat_completion_source) {
src/endpoints/backends/kobold.js+3 -4
@@ -2,14 +2,13 @@ import fs from 'node:fs';
2import express from 'express';2import express from 'express';
3import fetch from 'node-fetch';3import fetch from 'node-fetch';
44
5import { jsonParser, urlencodedParser } from '../../express-common.js';
6import { forwardFetchResponse, delay } from '../../util.js';5import { forwardFetchResponse, delay } from '../../util.js';
7import { getOverrideHeaders, setAdditionalHeaders, setAdditionalHeadersByType } from '../../additional-headers.js';6import { getOverrideHeaders, setAdditionalHeaders, setAdditionalHeadersByType } from '../../additional-headers.js';
8import { TEXTGEN_TYPES } from '../../constants.js';7import { TEXTGEN_TYPES } from '../../constants.js';
98
10export const router = express.Router();9export const router = express.Router();
1110
12router.post('/generate', jsonParser, async function (request, response_generate) {11router.post('/generate', async function (request, response_generate) {
13 if (!request.body) return response_generate.sendStatus(400);12 if (!request.body) return response_generate.sendStatus(400);
1413
15 if (request.body.api_server.indexOf('localhost') != -1) {14 if (request.body.api_server.indexOf('localhost') != -1) {
@@ -141,7 +140,7 @@ router.post('/generate', jsonParser, async function (request, response_generate)
141 return response_generate.send({ error: true });140 return response_generate.send({ error: true });
142});141});
143142
144router.post('/status', jsonParser, async function (request, response) {143router.post('/status', async function (request, response) {
145 if (!request.body) return response.sendStatus(400);144 if (!request.body) return response.sendStatus(400);
146 let api_server = request.body.api_server;145 let api_server = request.body.api_server;
147 if (api_server.indexOf('localhost') != -1) {146 if (api_server.indexOf('localhost') != -1) {
@@ -188,7 +187,7 @@ router.post('/status', jsonParser, async function (request, response) {
188 response.send(result);187 response.send(result);
189});188});
190189
191router.post('/transcribe-audio', urlencodedParser, async function (request, response) {190router.post('/transcribe-audio', async function (request, response) {
192 try {191 try {
193 const server = request.body.server;192 const server = request.body.server;
194193
src/endpoints/backends/scale-alt.js+1 -2
@@ -1,12 +1,11 @@
1import express from 'express';1import express from 'express';
2import fetch from 'node-fetch';2import fetch from 'node-fetch';
33
4import { jsonParser } from '../../express-common.js';
5import { readSecret, SECRET_KEYS } from '../secrets.js';4import { readSecret, SECRET_KEYS } from '../secrets.js';
65
7export const router = express.Router();6export const router = express.Router();
87
9router.post('/generate', jsonParser, async function (request, response) {8router.post('/generate', async function (request, response) {
10 if (!request.body) return response.sendStatus(400);9 if (!request.body) return response.sendStatus(400);
1110
12 try {11 try {
src/endpoints/backends/text-completions.js+9 -10
@@ -3,7 +3,6 @@ import fetch from 'node-fetch';
3import express from 'express';3import express from 'express';
4import _ from 'lodash';4import _ from 'lodash';
55
6import { jsonParser } from '../../express-common.js';
7import {6import {
8 TEXTGEN_TYPES,7 TEXTGEN_TYPES,
9 TOGETHERAI_KEYS,8 TOGETHERAI_KEYS,
@@ -93,7 +92,7 @@ async function abortKoboldCppRequest(url) {
93}92}
9493
95//************** Ooba/OpenAI text completions API94//************** Ooba/OpenAI text completions API
96router.post('/status', jsonParser, async function (request, response) {95router.post('/status', async function (request, response) {
97 if (!request.body) return response.sendStatus(400);96 if (!request.body) return response.sendStatus(400);
9897
99 try {98 try {
@@ -227,7 +226,7 @@ router.post('/status', jsonParser, async function (request, response) {
227 }226 }
228});227});
229228
230router.post('/props', jsonParser, async function (request, response) {229router.post('/props', async function (request, response) {
231 if (!request.body.api_server) return response.sendStatus(400);230 if (!request.body.api_server) return response.sendStatus(400);
232231
233 try {232 try {
@@ -261,7 +260,7 @@ router.post('/props', jsonParser, async function (request, response) {
261 }260 }
262});261});
263262
264router.post('/generate', jsonParser, async function (request, response) {263router.post('/generate', async function (request, response) {
265 if (!request.body) return response.sendStatus(400);264 if (!request.body) return response.sendStatus(400);
266265
267 try {266 try {
@@ -432,7 +431,7 @@ router.post('/generate', jsonParser, async function (request, response) {
432431
433const ollama = express.Router();432const ollama = express.Router();
434433
435ollama.post('/download', jsonParser, async function (request, response) {434ollama.post('/download', async function (request, response) {
436 try {435 try {
437 if (!request.body.name || !request.body.api_server) return response.sendStatus(400);436 if (!request.body.name || !request.body.api_server) return response.sendStatus(400);
438437
@@ -462,7 +461,7 @@ ollama.post('/download', jsonParser, async function (request, response) {
462 }461 }
463});462});
464463
465ollama.post('/caption-image', jsonParser, async function (request, response) {464ollama.post('/caption-image', async function (request, response) {
466 try {465 try {
467 if (!request.body.server_url || !request.body.model) {466 if (!request.body.server_url || !request.body.model) {
468 return response.sendStatus(400);467 return response.sendStatus(400);
@@ -507,7 +506,7 @@ ollama.post('/caption-image', jsonParser, async function (request, response) {
507506
508const llamacpp = express.Router();507const llamacpp = express.Router();
509508
510llamacpp.post('/caption-image', jsonParser, async function (request, response) {509llamacpp.post('/caption-image', async function (request, response) {
511 try {510 try {
512 if (!request.body.server_url) {511 if (!request.body.server_url) {
513 return response.sendStatus(400);512 return response.sendStatus(400);
@@ -552,7 +551,7 @@ llamacpp.post('/caption-image', jsonParser, async function (request, response) {
552 }551 }
553});552});
554553
555llamacpp.post('/props', jsonParser, async function (request, response) {554llamacpp.post('/props', async function (request, response) {
556 try {555 try {
557 if (!request.body.server_url) {556 if (!request.body.server_url) {
558 return response.sendStatus(400);557 return response.sendStatus(400);
@@ -581,7 +580,7 @@ llamacpp.post('/props', jsonParser, async function (request, response) {
581 }580 }
582});581});
583582
584llamacpp.post('/slots', jsonParser, async function (request, response) {583llamacpp.post('/slots', async function (request, response) {
585 try {584 try {
586 if (!request.body.server_url) {585 if (!request.body.server_url) {
587 return response.sendStatus(400);586 return response.sendStatus(400);
@@ -633,7 +632,7 @@ llamacpp.post('/slots', jsonParser, async function (request, response) {
633632
634const tabby = express.Router();633const tabby = express.Router();
635634
636tabby.post('/download', jsonParser, async function (request, response) {635tabby.post('/download', async function (request, response) {
637 try {636 try {
638 const baseUrl = String(request.body.api_server).replace(/\/$/, '');637 const baseUrl = String(request.body.api_server).replace(/\/$/, '');
639638
src/endpoints/backgrounds.js+4 -5
@@ -4,19 +4,18 @@ import path from 'node:path';
4import express from 'express';4import express from 'express';
5import sanitize from 'sanitize-filename';5import sanitize from 'sanitize-filename';
66
7import { jsonParser, urlencodedParser } from '../express-common.js';
8import { invalidateThumbnail } from './thumbnails.js';7import { invalidateThumbnail } from './thumbnails.js';
9import { getImages } from '../util.js';8import { getImages } from '../util.js';
10import { getFileNameValidationFunction } from '../middleware/validateFileName.js';9import { getFileNameValidationFunction } from '../middleware/validateFileName.js';
1110
12export const router = express.Router();11export const router = express.Router();
1312
14router.post('/all', jsonParser, function (request, response) {13router.post('/all', function (request, response) {
15 var images = getImages(request.user.directories.backgrounds);14 var images = getImages(request.user.directories.backgrounds);
16 response.send(JSON.stringify(images));15 response.send(JSON.stringify(images));
17});16});
1817
19router.post('/delete', jsonParser, getFileNameValidationFunction('bg'), function (request, response) {18router.post('/delete', getFileNameValidationFunction('bg'), function (request, response) {
20 if (!request.body) return response.sendStatus(400);19 if (!request.body) return response.sendStatus(400);
2120
22 if (request.body.bg !== sanitize(request.body.bg)) {21 if (request.body.bg !== sanitize(request.body.bg)) {
@@ -36,7 +35,7 @@ router.post('/delete', jsonParser, getFileNameValidationFunction('bg'), function
36 return response.send('ok');35 return response.send('ok');
37});36});
3837
39router.post('/rename', jsonParser, function (request, response) {38router.post('/rename', function (request, response) {
40 if (!request.body) return response.sendStatus(400);39 if (!request.body) return response.sendStatus(400);
4140
42 const oldFileName = path.join(request.user.directories.backgrounds, sanitize(request.body.old_bg));41 const oldFileName = path.join(request.user.directories.backgrounds, sanitize(request.body.old_bg));
@@ -58,7 +57,7 @@ router.post('/rename', jsonParser, function (request, response) {
58 return response.send('ok');57 return response.send('ok');
59});58});
6059
61router.post('/upload', urlencodedParser, function (request, response) {60router.post('/upload', function (request, response) {
62 if (!request.body || !request.file) return response.sendStatus(400);61 if (!request.body || !request.file) return response.sendStatus(400);
6362
64 const img_path = path.join(request.file.destination, request.file.filename);63 const img_path = path.join(request.file.destination, request.file.filename);
src/endpoints/caption.js+1 -2
@@ -1,12 +1,11 @@
1import express from 'express';1import express from 'express';
2import { jsonParser } from '../express-common.js';
3import { getPipeline, getRawImage } from '../transformers.js';2import { getPipeline, getRawImage } from '../transformers.js';
43
5export const router = express.Router();4export const router = express.Router();
65
7const TASK = 'image-to-text';6const TASK = 'image-to-text';
87
9router.post('/', jsonParser, async (req, res) => {8router.post('/', async (req, res) => {
10 try {9 try {
11 const { image } = req.body;10 const { image } = req.body;
1211
src/endpoints/characters.js+12 -13
@@ -13,7 +13,6 @@ import mime from 'mime-types';
13import jimp from 'jimp';13import jimp from 'jimp';
1414
15import { AVATAR_WIDTH, AVATAR_HEIGHT } from '../constants.js';15import { AVATAR_WIDTH, AVATAR_HEIGHT } from '../constants.js';
16import { jsonParser, urlencodedParser } from '../express-common.js';
17import { default as validateAvatarUrlMiddleware, getFileNameValidationFunction } from '../middleware/validateFileName.js';16import { default as validateAvatarUrlMiddleware, getFileNameValidationFunction } from '../middleware/validateFileName.js';
18import { deepMerge, humanizedISO8601DateTime, tryParse, extractFileFromZipBuffer, MemoryLimitedMap, getConfigValue } from '../util.js';17import { deepMerge, humanizedISO8601DateTime, tryParse, extractFileFromZipBuffer, MemoryLimitedMap, getConfigValue } from '../util.js';
19import { TavernCardValidator } from '../validator/TavernCardValidator.js';18import { TavernCardValidator } from '../validator/TavernCardValidator.js';
@@ -768,7 +767,7 @@ async function importFromPng(uploadPath, { request }, preservedFileName) {
768767
769export const router = express.Router();768export const router = express.Router();
770769
771router.post('/create', urlencodedParser, async function (request, response) {770router.post('/create', async function (request, response) {
772 try {771 try {
773 if (!request.body) return response.sendStatus(400);772 if (!request.body) return response.sendStatus(400);
774773
@@ -797,7 +796,7 @@ router.post('/create', urlencodedParser, async function (request, response) {
797 }796 }
798});797});
799798
800router.post('/rename', jsonParser, validateAvatarUrlMiddleware, async function (request, response) {799router.post('/rename', validateAvatarUrlMiddleware, async function (request, response) {
801 if (!request.body.avatar_url || !request.body.new_name) {800 if (!request.body.avatar_url || !request.body.new_name) {
802 return response.sendStatus(400);801 return response.sendStatus(400);
803 }802 }
@@ -844,7 +843,7 @@ router.post('/rename', jsonParser, validateAvatarUrlMiddleware, async function (
844 }843 }
845});844});
846845
847router.post('/edit', urlencodedParser, validateAvatarUrlMiddleware, async function (request, response) {846router.post('/edit', validateAvatarUrlMiddleware, async function (request, response) {
848 if (!request.body) {847 if (!request.body) {
849 console.warn('Error: no response body detected');848 console.warn('Error: no response body detected');
850 response.status(400).send('Error: no response body detected');849 response.status(400).send('Error: no response body detected');
@@ -896,7 +895,7 @@ router.post('/edit', urlencodedParser, validateAvatarUrlMiddleware, async functi
896 * @param {Object} response - The HTTP response object.895 * @param {Object} response - The HTTP response object.
897 * @returns {void}896 * @returns {void}
898 */897 */
899router.post('/edit-attribute', jsonParser, validateAvatarUrlMiddleware, async function (request, response) {898router.post('/edit-attribute', validateAvatarUrlMiddleware, async function (request, response) {
900 console.debug(request.body);899 console.debug(request.body);
901 if (!request.body) {900 if (!request.body) {
902 console.warn('Error: no response body detected');901 console.warn('Error: no response body detected');
@@ -942,7 +941,7 @@ router.post('/edit-attribute', jsonParser, validateAvatarUrlMiddleware, async fu
942 *941 *
943 * @returns {void}942 * @returns {void}
944 * */943 * */
945router.post('/merge-attributes', jsonParser, getFileNameValidationFunction('avatar'), async function (request, response) {944router.post('/merge-attributes', getFileNameValidationFunction('avatar'), async function (request, response) {
946 try {945 try {
947 const update = request.body;946 const update = request.body;
948 const avatarPath = path.join(request.user.directories.characters, update.avatar);947 const avatarPath = path.join(request.user.directories.characters, update.avatar);
@@ -973,7 +972,7 @@ router.post('/merge-attributes', jsonParser, getFileNameValidationFunction('avat
973 }972 }
974});973});
975974
976router.post('/delete', jsonParser, validateAvatarUrlMiddleware, async function (request, response) {975router.post('/delete', validateAvatarUrlMiddleware, async function (request, response) {
977 if (!request.body || !request.body.avatar_url) {976 if (!request.body || !request.body.avatar_url) {
978 return response.sendStatus(400);977 return response.sendStatus(400);
979 }978 }
@@ -1023,7 +1022,7 @@ router.post('/delete', jsonParser, validateAvatarUrlMiddleware, async function (
1023 * @param {import("express").Response} response The HTTP response object.1022 * @param {import("express").Response} response The HTTP response object.
1024 * @return {void}1023 * @return {void}
1025 */1024 */
1026router.post('/all', jsonParser, async function (request, response) {1025router.post('/all', async function (request, response) {
1027 try {1026 try {
1028 const files = fs.readdirSync(request.user.directories.characters);1027 const files = fs.readdirSync(request.user.directories.characters);
1029 const pngFiles = files.filter(file => file.endsWith('.png'));1028 const pngFiles = files.filter(file => file.endsWith('.png'));
@@ -1036,7 +1035,7 @@ router.post('/all', jsonParser, async function (request, response) {
1036 }1035 }
1037});1036});
10381037
1039router.post('/get', jsonParser, validateAvatarUrlMiddleware, async function (request, response) {1038router.post('/get', validateAvatarUrlMiddleware, async function (request, response) {
1040 try {1039 try {
1041 if (!request.body) return response.sendStatus(400);1040 if (!request.body) return response.sendStatus(400);
1042 const item = request.body.avatar_url;1041 const item = request.body.avatar_url;
@@ -1055,7 +1054,7 @@ router.post('/get', jsonParser, validateAvatarUrlMiddleware, async function (req
1055 }1054 }
1056});1055});
10571056
1058router.post('/chats', jsonParser, validateAvatarUrlMiddleware, async function (request, response) {1057router.post('/chats', validateAvatarUrlMiddleware, async function (request, response) {
1059 try {1058 try {
1060 if (!request.body) return response.sendStatus(400);1059 if (!request.body) return response.sendStatus(400);
10611060
@@ -1164,7 +1163,7 @@ function getPreservedName(request) {
1164 : undefined;1163 : undefined;
1165}1164}
11661165
1167router.post('/import', urlencodedParser, async function (request, response) {1166router.post('/import', async function (request, response) {
1168 if (!request.body || !request.file) return response.sendStatus(400);1167 if (!request.body || !request.file) return response.sendStatus(400);
11691168
1170 const uploadPath = path.join(request.file.destination, request.file.filename);1169 const uploadPath = path.join(request.file.destination, request.file.filename);
@@ -1204,7 +1203,7 @@ router.post('/import', urlencodedParser, async function (request, response) {
1204 }1203 }
1205});1204});
12061205
1207router.post('/duplicate', jsonParser, validateAvatarUrlMiddleware, async function (request, response) {1206router.post('/duplicate', validateAvatarUrlMiddleware, async function (request, response) {
1208 try {1207 try {
1209 if (!request.body.avatar_url) {1208 if (!request.body.avatar_url) {
1210 console.warn('avatar URL not found in request body');1209 console.warn('avatar URL not found in request body');
@@ -1250,7 +1249,7 @@ router.post('/duplicate', jsonParser, validateAvatarUrlMiddleware, async functio
1250 }1249 }
1251});1250});
12521251
1253router.post('/export', jsonParser, validateAvatarUrlMiddleware, async function (request, response) {1252router.post('/export', validateAvatarUrlMiddleware, async function (request, response) {
1254 try {1253 try {
1255 if (!request.body.format || !request.body.avatar_url) {1254 if (!request.body.format || !request.body.avatar_url) {
1256 return response.sendStatus(400);1255 return response.sendStatus(400);
src/endpoints/chats.js+11 -13
@@ -8,7 +8,6 @@ import sanitize from 'sanitize-filename';
8import { sync as writeFileAtomicSync } from 'write-file-atomic';8import { sync as writeFileAtomicSync } from 'write-file-atomic';
9import _ from 'lodash';9import _ from 'lodash';
1010
11import { jsonParser, urlencodedParser } from '../express-common.js';
12import validateAvatarUrlMiddleware from '../middleware/validateFileName.js';11import validateAvatarUrlMiddleware from '../middleware/validateFileName.js';
13import {12import {
14 getConfigValue,13 getConfigValue,
@@ -295,7 +294,7 @@ function importRisuChat(userName, characterName, jsonData) {
295294
296export const router = express.Router();295export const router = express.Router();
297296
298router.post('/save', jsonParser, validateAvatarUrlMiddleware, function (request, response) {297router.post('/save', validateAvatarUrlMiddleware, function (request, response) {
299 try {298 try {
300 const directoryName = String(request.body.avatar_url).replace('.png', '');299 const directoryName = String(request.body.avatar_url).replace('.png', '');
301 const chatData = request.body.chat;300 const chatData = request.body.chat;
@@ -311,7 +310,7 @@ router.post('/save', jsonParser, validateAvatarUrlMiddleware, function (request,
311 }310 }
312});311});
313312
314router.post('/get', jsonParser, validateAvatarUrlMiddleware, function (request, response) {313router.post('/get', validateAvatarUrlMiddleware, function (request, response) {
315 try {314 try {
316 const dirName = String(request.body.avatar_url).replace('.png', '');315 const dirName = String(request.body.avatar_url).replace('.png', '');
317 const directoryPath = path.join(request.user.directories.chats, dirName);316 const directoryPath = path.join(request.user.directories.chats, dirName);
@@ -347,8 +346,7 @@ router.post('/get', jsonParser, validateAvatarUrlMiddleware, function (request,
347 }346 }
348});347});
349348
350349router.post('/rename', validateAvatarUrlMiddleware, async function (request, response) {
351router.post('/rename', jsonParser, validateAvatarUrlMiddleware, async function (request, response) {
352 if (!request.body || !request.body.original_file || !request.body.renamed_file) {350 if (!request.body || !request.body.original_file || !request.body.renamed_file) {
353 return response.sendStatus(400);351 return response.sendStatus(400);
354 }352 }
@@ -373,7 +371,7 @@ router.post('/rename', jsonParser, validateAvatarUrlMiddleware, async function (
373 return response.send({ ok: true, sanitizedFileName });371 return response.send({ ok: true, sanitizedFileName });
374});372});
375373
376router.post('/delete', jsonParser, validateAvatarUrlMiddleware, function (request, response) {374router.post('/delete', validateAvatarUrlMiddleware, function (request, response) {
377 const dirName = String(request.body.avatar_url).replace('.png', '');375 const dirName = String(request.body.avatar_url).replace('.png', '');
378 const fileName = String(request.body.chatfile);376 const fileName = String(request.body.chatfile);
379 const filePath = path.join(request.user.directories.chats, dirName, sanitize(fileName));377 const filePath = path.join(request.user.directories.chats, dirName, sanitize(fileName));
@@ -389,7 +387,7 @@ router.post('/delete', jsonParser, validateAvatarUrlMiddleware, function (reques
389 return response.send('ok');387 return response.send('ok');
390});388});
391389
392router.post('/export', jsonParser, validateAvatarUrlMiddleware, async function (request, response) {390router.post('/export', validateAvatarUrlMiddleware, async function (request, response) {
393 if (!request.body.file || (!request.body.avatar_url && request.body.is_group === false)) {391 if (!request.body.file || (!request.body.avatar_url && request.body.is_group === false)) {
394 return response.sendStatus(400);392 return response.sendStatus(400);
395 }393 }
@@ -458,7 +456,7 @@ router.post('/export', jsonParser, validateAvatarUrlMiddleware, async function (
458 }456 }
459});457});
460458
461router.post('/group/import', urlencodedParser, function (request, response) {459router.post('/group/import', function (request, response) {
462 try {460 try {
463 const filedata = request.file;461 const filedata = request.file;
464462
@@ -478,7 +476,7 @@ router.post('/group/import', urlencodedParser, function (request, response) {
478 }476 }
479});477});
480478
481router.post('/import', urlencodedParser, validateAvatarUrlMiddleware, function (request, response) {479router.post('/import', validateAvatarUrlMiddleware, function (request, response) {
482 if (!request.body) return response.sendStatus(400);480 if (!request.body) return response.sendStatus(400);
483481
484 const format = request.body.file_type;482 const format = request.body.file_type;
@@ -571,7 +569,7 @@ router.post('/import', urlencodedParser, validateAvatarUrlMiddleware, function (
571 }569 }
572});570});
573571
574router.post('/group/get', jsonParser, (request, response) => {572router.post('/group/get', (request, response) => {
575 if (!request.body || !request.body.id) {573 if (!request.body || !request.body.id) {
576 return response.sendStatus(400);574 return response.sendStatus(400);
577 }575 }
@@ -591,7 +589,7 @@ router.post('/group/get', jsonParser, (request, response) => {
591 }589 }
592});590});
593591
594router.post('/group/delete', jsonParser, (request, response) => {592router.post('/group/delete', (request, response) => {
595 if (!request.body || !request.body.id) {593 if (!request.body || !request.body.id) {
596 return response.sendStatus(400);594 return response.sendStatus(400);
597 }595 }
@@ -607,7 +605,7 @@ router.post('/group/delete', jsonParser, (request, response) => {
607 return response.send({ error: true });605 return response.send({ error: true });
608});606});
609607
610router.post('/group/save', jsonParser, (request, response) => {608router.post('/group/save', (request, response) => {
611 if (!request.body || !request.body.id) {609 if (!request.body || !request.body.id) {
612 return response.sendStatus(400);610 return response.sendStatus(400);
613 }611 }
@@ -626,7 +624,7 @@ router.post('/group/save', jsonParser, (request, response) => {
626 return response.send({ ok: true });624 return response.send({ ok: true });
627});625});
628626
629router.post('/search', jsonParser, validateAvatarUrlMiddleware, function (request, response) {627router.post('/search', validateAvatarUrlMiddleware, function (request, response) {
630 try {628 try {
631 const { query, avatar_url, group_id } = request.body;629 const { query, avatar_url, group_id } = request.body;
632 let chatFiles = [];630 let chatFiles = [];
src/endpoints/classify.js+2 -3
@@ -1,7 +1,6 @@
1import express from 'express';1import express from 'express';
22
3import { getPipeline } from '../transformers.js';3import { getPipeline } from '../transformers.js';
4import { jsonParser } from '../express-common.js';
54
6const TASK = 'text-classification';5const TASK = 'text-classification';
76
@@ -12,7 +11,7 @@ export const router = express.Router();
12 */11 */
13const cacheObject = new Map();12const cacheObject = new Map();
1413
15router.post('/labels', jsonParser, async (req, res) => {14router.post('/labels', async (req, res) => {
16 try {15 try {
17 const pipe = await getPipeline(TASK);16 const pipe = await getPipeline(TASK);
18 const result = Object.keys(pipe.model.config.label2id);17 const result = Object.keys(pipe.model.config.label2id);
@@ -23,7 +22,7 @@ router.post('/labels', jsonParser, async (req, res) => {
23 }22 }
24});23});
2524
26router.post('/', jsonParser, async (req, res) => {25router.post('/', async (req, res) => {
27 try {26 try {
28 const { text } = req.body;27 const { text } = req.body;
2928
src/endpoints/content-manager.js+2 -3
@@ -9,7 +9,6 @@ import sanitize from 'sanitize-filename';
9import { sync as writeFileAtomicSync } from 'write-file-atomic';9import { sync as writeFileAtomicSync } from 'write-file-atomic';
1010
11import { getConfigValue, color } from '../util.js';11import { getConfigValue, color } from '../util.js';
12import { jsonParser } from '../express-common.js';
13import { write } from '../character-card-parser.js';12import { write } from '../character-card-parser.js';
1413
15const contentDirectory = path.join(process.cwd(), 'default/content');14const contentDirectory = path.join(process.cwd(), 'default/content');
@@ -627,7 +626,7 @@ function isHostWhitelisted(host) {
627626
628export const router = express.Router();627export const router = express.Router();
629628
630router.post('/importURL', jsonParser, async (request, response) => {629router.post('/importURL', async (request, response) => {
631 if (!request.body.url) {630 if (!request.body.url) {
632 return response.sendStatus(400);631 return response.sendStatus(400);
633 }632 }
@@ -713,7 +712,7 @@ router.post('/importURL', jsonParser, async (request, response) => {
713 }712 }
714});713});
715714
716router.post('/importUUID', jsonParser, async (request, response) => {715router.post('/importUUID', async (request, response) => {
717 if (!request.body.url) {716 if (!request.body.url) {
718 return response.sendStatus(400);717 return response.sendStatus(400);
719 }718 }
src/endpoints/extensions.js+6 -7
@@ -6,7 +6,6 @@ import sanitize from 'sanitize-filename';
6import { default as simpleGit } from 'simple-git';6import { default as simpleGit } from 'simple-git';
77
8import { PUBLIC_DIRECTORIES } from '../constants.js';8import { PUBLIC_DIRECTORIES } from '../constants.js';
9import { jsonParser } from '../express-common.js';
109
11/**10/**
12 * This function extracts the extension information from the manifest file.11 * This function extracts the extension information from the manifest file.
@@ -60,7 +59,7 @@ export const router = express.Router();
60 *59 *
61 * @returns {void}60 * @returns {void}
62 */61 */
63router.post('/install', jsonParser, async (request, response) => {62router.post('/install', async (request, response) => {
64 if (!request.body.url) {63 if (!request.body.url) {
65 return response.status(400).send('Bad Request: URL is required in the request body.');64 return response.status(400).send('Bad Request: URL is required in the request body.');
66 }65 }
@@ -114,7 +113,7 @@ router.post('/install', jsonParser, async (request, response) => {
114 *113 *
115 * @returns {void}114 * @returns {void}
116 */115 */
117router.post('/update', jsonParser, async (request, response) => {116router.post('/update', async (request, response) => {
118 const git = simpleGit();117 const git = simpleGit();
119 if (!request.body.extensionName) {118 if (!request.body.extensionName) {
120 return response.status(400).send('Bad Request: extensionName is required in the request body.');119 return response.status(400).send('Bad Request: extensionName is required in the request body.');
@@ -155,7 +154,7 @@ router.post('/update', jsonParser, async (request, response) => {
155 }154 }
156});155});
157156
158router.post('/move', jsonParser, async (request, response) => {157router.post('/move', async (request, response) => {
159 try {158 try {
160 const { extensionName, source, destination } = request.body;159 const { extensionName, source, destination } = request.body;
161160
@@ -209,7 +208,7 @@ router.post('/move', jsonParser, async (request, response) => {
209 *208 *
210 * @returns {void}209 * @returns {void}
211 */210 */
212router.post('/version', jsonParser, async (request, response) => {211router.post('/version', async (request, response) => {
213 const git = simpleGit();212 const git = simpleGit();
214 if (!request.body.extensionName) {213 if (!request.body.extensionName) {
215 return response.status(400).send('Bad Request: extensionName is required in the request body.');214 return response.status(400).send('Bad Request: extensionName is required in the request body.');
@@ -256,7 +255,7 @@ router.post('/version', jsonParser, async (request, response) => {
256 *255 *
257 * @returns {void}256 * @returns {void}
258 */257 */
259router.post('/delete', jsonParser, async (request, response) => {258router.post('/delete', async (request, response) => {
260 if (!request.body.extensionName) {259 if (!request.body.extensionName) {
261 return response.status(400).send('Bad Request: extensionName is required in the request body.');260 return response.status(400).send('Bad Request: extensionName is required in the request body.');
262 }261 }
@@ -291,7 +290,7 @@ router.post('/delete', jsonParser, async (request, response) => {
291 * Discover the extension folders290 * Discover the extension folders
292 * If the folder is called third-party, search for subfolders instead291 * If the folder is called third-party, search for subfolders instead
293 */292 */
294router.get('/discover', jsonParser, function (request, response) {293router.get('/discover', function (request, response) {
295 if (!fs.existsSync(path.join(request.user.directories.extensions))) {294 if (!fs.existsSync(path.join(request.user.directories.extensions))) {
296 fs.mkdirSync(path.join(request.user.directories.extensions));295 fs.mkdirSync(path.join(request.user.directories.extensions));
297 }296 }
src/endpoints/files.js+4 -5
@@ -6,12 +6,11 @@ import sanitize from 'sanitize-filename';
6import { sync as writeFileSyncAtomic } from 'write-file-atomic';6import { sync as writeFileSyncAtomic } from 'write-file-atomic';
77
8import { validateAssetFileName } from './assets.js';8import { validateAssetFileName } from './assets.js';
9import { jsonParser } from '../express-common.js';
10import { clientRelativePath } from '../util.js';9import { clientRelativePath } from '../util.js';
1110
12export const router = express.Router();11export const router = express.Router();
1312
14router.post('/sanitize-filename', jsonParser, async (request, response) => {13router.post('/sanitize-filename', async (request, response) => {
15 try {14 try {
16 const fileName = String(request.body.fileName);15 const fileName = String(request.body.fileName);
17 if (!fileName) {16 if (!fileName) {
@@ -26,7 +25,7 @@ router.post('/sanitize-filename', jsonParser, async (request, response) => {
26 }25 }
27});26});
2827
29router.post('/upload', jsonParser, async (request, response) => {28router.post('/upload', async (request, response) => {
30 try {29 try {
31 if (!request.body.name) {30 if (!request.body.name) {
32 return response.status(400).send('No upload name specified');31 return response.status(400).send('No upload name specified');
@@ -52,7 +51,7 @@ router.post('/upload', jsonParser, async (request, response) => {
52 }51 }
53});52});
5453
55router.post('/delete', jsonParser, async (request, response) => {54router.post('/delete', async (request, response) => {
56 try {55 try {
57 if (!request.body.path) {56 if (!request.body.path) {
58 return response.status(400).send('No path specified');57 return response.status(400).send('No path specified');
@@ -76,7 +75,7 @@ router.post('/delete', jsonParser, async (request, response) => {
76 }75 }
77});76});
7877
79router.post('/verify', jsonParser, async (request, response) => {78router.post('/verify', async (request, response) => {
80 try {79 try {
81 if (!Array.isArray(request.body.urls)) {80 if (!Array.isArray(request.body.urls)) {
82 return response.status(400).send('No URLs specified');81 return response.status(400).send('No URLs specified');
src/endpoints/google.js+2 -3
@@ -4,14 +4,13 @@ import express from 'express';
4import { speak, languages } from 'google-translate-api-x';4import { speak, languages } from 'google-translate-api-x';
55
6import { readSecret, SECRET_KEYS } from './secrets.js';6import { readSecret, SECRET_KEYS } from './secrets.js';
7import { jsonParser } from '../express-common.js';
8import { GEMINI_SAFETY } from '../constants.js';7import { GEMINI_SAFETY } from '../constants.js';
98
10const API_MAKERSUITE = 'https://generativelanguage.googleapis.com';9const API_MAKERSUITE = 'https://generativelanguage.googleapis.com';
1110
12export const router = express.Router();11export const router = express.Router();
1312
14router.post('/caption-image', jsonParser, async (request, response) => {13router.post('/caption-image', async (request, response) => {
15 try {14 try {
16 const mimeType = request.body.image.split(';')[0].split(':')[1];15 const mimeType = request.body.image.split(';')[0].split(':')[1];
17 const base64Data = request.body.image.split(',')[1];16 const base64Data = request.body.image.split(',')[1];
@@ -75,7 +74,7 @@ router.post('/list-voices', (_, response) => {
75 return response.json(languages);74 return response.json(languages);
76});75});
7776
78router.post('/generate-voice', jsonParser, async (request, response) => {77router.post('/generate-voice', async (request, response) => {
79 try {78 try {
80 const text = request.body.text;79 const text = request.body.text;
81 const voice = request.body.voice ?? 'en';80 const voice = request.body.voice ?? 'en';
src/endpoints/groups.js+4 -5
@@ -5,12 +5,11 @@ import express from 'express';
5import sanitize from 'sanitize-filename';5import sanitize from 'sanitize-filename';
6import { sync as writeFileAtomicSync } from 'write-file-atomic';6import { sync as writeFileAtomicSync } from 'write-file-atomic';
77
8import { jsonParser } from '../express-common.js';
9import { humanizedISO8601DateTime } from '../util.js';8import { humanizedISO8601DateTime } from '../util.js';
109
11export const router = express.Router();10export const router = express.Router();
1211
13router.post('/all', jsonParser, (request, response) => {12router.post('/all', (request, response) => {
14 const groups = [];13 const groups = [];
1514
16 if (!fs.existsSync(request.user.directories.groups)) {15 if (!fs.existsSync(request.user.directories.groups)) {
@@ -54,7 +53,7 @@ router.post('/all', jsonParser, (request, response) => {
54 return response.send(groups);53 return response.send(groups);
55});54});
5655
57router.post('/create', jsonParser, (request, response) => {56router.post('/create', (request, response) => {
58 if (!request.body) {57 if (!request.body) {
59 return response.sendStatus(400);58 return response.sendStatus(400);
60 }59 }
@@ -88,7 +87,7 @@ router.post('/create', jsonParser, (request, response) => {
88 return response.send(groupMetadata);87 return response.send(groupMetadata);
89});88});
9089
91router.post('/edit', jsonParser, (request, response) => {90router.post('/edit', (request, response) => {
92 if (!request.body || !request.body.id) {91 if (!request.body || !request.body.id) {
93 return response.sendStatus(400);92 return response.sendStatus(400);
94 }93 }
@@ -100,7 +99,7 @@ router.post('/edit', jsonParser, (request, response) => {
100 return response.send({ ok: true });99 return response.send({ ok: true });
101});100});
102101
103router.post('/delete', jsonParser, async (request, response) => {102router.post('/delete', async (request, response) => {
104 if (!request.body || !request.body.id) {103 if (!request.body || !request.body.id) {
105 return response.sendStatus(400);104 return response.sendStatus(400);
106 }105 }
src/endpoints/horde.js+11 -12
@@ -3,7 +3,6 @@ import express from 'express';
3import { AIHorde, ModelGenerationInputStableSamplers, ModelInterrogationFormTypes, HordeAsyncRequestStates } from '@zeldafan0225/ai_horde';3import { AIHorde, ModelGenerationInputStableSamplers, ModelInterrogationFormTypes, HordeAsyncRequestStates } from '@zeldafan0225/ai_horde';
4import { getVersion, delay, Cache } from '../util.js';4import { getVersion, delay, Cache } from '../util.js';
5import { readSecret, SECRET_KEYS } from './secrets.js';5import { readSecret, SECRET_KEYS } from './secrets.js';
6import { jsonParser } from '../express-common.js';
76
8const ANONYMOUS_KEY = '0000000000';7const ANONYMOUS_KEY = '0000000000';
9const HORDE_TEXT_MODEL_METADATA_URL = 'https://raw.githubusercontent.com/db0/AI-Horde-text-model-reference/main/db.json';8const HORDE_TEXT_MODEL_METADATA_URL = 'https://raw.githubusercontent.com/db0/AI-Horde-text-model-reference/main/db.json';
@@ -56,7 +55,7 @@ function sanitizeHordeImagePrompt(prompt) {
56 return prompt;55 return prompt;
57}56}
5857
59router.post('/text-workers', jsonParser, async (request, response) => {58router.post('/text-workers', async (request, response) => {
60 try {59 try {
61 const cachedWorkers = cache.get('workers');60 const cachedWorkers = cache.get('workers');
6261
@@ -94,7 +93,7 @@ async function mergeModelsAndMetadata(models, metadata) {
94 });93 });
95}94}
9695
97router.post('/text-models', jsonParser, async (request, response) => {96router.post('/text-models', async (request, response) => {
98 try {97 try {
99 const cachedModels = cache.get('models');98 const cachedModels = cache.get('models');
100 if (cachedModels && !request.body.force) {99 if (cachedModels && !request.body.force) {
@@ -127,7 +126,7 @@ router.post('/text-models', jsonParser, async (request, response) => {
127 }126 }
128});127});
129128
130router.post('/status', jsonParser, async (_, response) => {129router.post('/status', async (_, response) => {
131 try {130 try {
132 const agent = await getClientAgent();131 const agent = await getClientAgent();
133 const fetchResult = await fetch('https://aihorde.net/api/v2/status/heartbeat', {132 const fetchResult = await fetch('https://aihorde.net/api/v2/status/heartbeat', {
@@ -143,7 +142,7 @@ router.post('/status', jsonParser, async (_, response) => {
143 }142 }
144});143});
145144
146router.post('/cancel-task', jsonParser, async (request, response) => {145router.post('/cancel-task', async (request, response) => {
147 try {146 try {
148 const taskId = request.body.taskId;147 const taskId = request.body.taskId;
149 const agent = await getClientAgent();148 const agent = await getClientAgent();
@@ -163,7 +162,7 @@ router.post('/cancel-task', jsonParser, async (request, response) => {
163 }162 }
164});163});
165164
166router.post('/task-status', jsonParser, async (request, response) => {165router.post('/task-status', async (request, response) => {
167 try {166 try {
168 const taskId = request.body.taskId;167 const taskId = request.body.taskId;
169 const agent = await getClientAgent();168 const agent = await getClientAgent();
@@ -182,7 +181,7 @@ router.post('/task-status', jsonParser, async (request, response) => {
182 }181 }
183});182});
184183
185router.post('/generate-text', jsonParser, async (request, response) => {184router.post('/generate-text', async (request, response) => {
186 const apiKey = readSecret(request.user.directories, SECRET_KEYS.HORDE) || ANONYMOUS_KEY;185 const apiKey = readSecret(request.user.directories, SECRET_KEYS.HORDE) || ANONYMOUS_KEY;
187 const url = 'https://aihorde.net/api/v2/generate/text/async';186 const url = 'https://aihorde.net/api/v2/generate/text/async';
188 const agent = await getClientAgent();187 const agent = await getClientAgent();
@@ -213,7 +212,7 @@ router.post('/generate-text', jsonParser, async (request, response) => {
213 }212 }
214});213});
215214
216router.post('/sd-samplers', jsonParser, async (_, response) => {215router.post('/sd-samplers', async (_, response) => {
217 try {216 try {
218 const samplers = Object.values(ModelGenerationInputStableSamplers);217 const samplers = Object.values(ModelGenerationInputStableSamplers);
219 response.send(samplers);218 response.send(samplers);
@@ -223,7 +222,7 @@ router.post('/sd-samplers', jsonParser, async (_, response) => {
223 }222 }
224});223});
225224
226router.post('/sd-models', jsonParser, async (_, response) => {225router.post('/sd-models', async (_, response) => {
227 try {226 try {
228 const ai_horde = await getHordeClient();227 const ai_horde = await getHordeClient();
229 const models = await ai_horde.getModels();228 const models = await ai_horde.getModels();
@@ -234,7 +233,7 @@ router.post('/sd-models', jsonParser, async (_, response) => {
234 }233 }
235});234});
236235
237router.post('/caption-image', jsonParser, async (request, response) => {236router.post('/caption-image', async (request, response) => {
238 try {237 try {
239 const api_key_horde = readSecret(request.user.directories, SECRET_KEYS.HORDE) || ANONYMOUS_KEY;238 const api_key_horde = readSecret(request.user.directories, SECRET_KEYS.HORDE) || ANONYMOUS_KEY;
240 const ai_horde = await getHordeClient();239 const ai_horde = await getHordeClient();
@@ -286,7 +285,7 @@ router.post('/caption-image', jsonParser, async (request, response) => {
286 }285 }
287});286});
288287
289router.post('/user-info', jsonParser, async (request, response) => {288router.post('/user-info', async (request, response) => {
290 const api_key_horde = readSecret(request.user.directories, SECRET_KEYS.HORDE);289 const api_key_horde = readSecret(request.user.directories, SECRET_KEYS.HORDE);
291290
292 if (!api_key_horde) {291 if (!api_key_horde) {
@@ -303,7 +302,7 @@ router.post('/user-info', jsonParser, async (request, response) => {
303 }302 }
304});303});
305304
306router.post('/generate-image', jsonParser, async (request, response) => {305router.post('/generate-image', async (request, response) => {
307 if (!request.body.prompt) {306 if (!request.body.prompt) {
308 return response.sendStatus(400);307 return response.sendStatus(400);
309 }308 }
src/endpoints/images.js+2 -3
@@ -5,7 +5,6 @@ import { Buffer } from 'node:buffer';
5import express from 'express';5import express from 'express';
6import sanitize from 'sanitize-filename';6import sanitize from 'sanitize-filename';
77
8import { jsonParser } from '../express-common.js';
9import { clientRelativePath, removeFileExtension, getImages } from '../util.js';8import { clientRelativePath, removeFileExtension, getImages } from '../util.js';
109
11/**10/**
@@ -36,7 +35,7 @@ export const router = express.Router();
36 * @param {string} [request.body.ch_name] - Optional character name to determine the sub-directory.35 * @param {string} [request.body.ch_name] - Optional character name to determine the sub-directory.
37 * @returns {Object} response - The response object containing the path where the image was saved.36 * @returns {Object} response - The response object containing the path where the image was saved.
38 */37 */
39router.post('/upload', jsonParser, async (request, response) => {38router.post('/upload', async (request, response) => {
40 // Check for image data39 // Check for image data
41 if (!request.body || !request.body.image) {40 if (!request.body || !request.body.image) {
42 return response.status(400).send({ error: 'No image data provided' });41 return response.status(400).send({ error: 'No image data provided' });
@@ -76,7 +75,7 @@ router.post('/upload', jsonParser, async (request, response) => {
76 }75 }
77});76});
7877
79router.post('/list/:folder?', jsonParser, (request, response) => {78router.post('/list/:folder?', (request, response) => {
80 try {79 try {
81 if (request.params.folder) {80 if (request.params.folder) {
82 if (request.body.folder) {81 if (request.body.folder) {
src/endpoints/moving-ui.js+1 -3
@@ -3,11 +3,9 @@ import express from 'express';
3import sanitize from 'sanitize-filename';3import sanitize from 'sanitize-filename';
4import { sync as writeFileAtomicSync } from 'write-file-atomic';4import { sync as writeFileAtomicSync } from 'write-file-atomic';
55
6import { jsonParser } from '../express-common.js';
7
8export const router = express.Router();6export const router = express.Router();
97
10router.post('/save', jsonParser, (request, response) => {8router.post('/save', (request, response) => {
11 if (!request.body || !request.body.name) {9 if (!request.body || !request.body.name) {
12 return response.sendStatus(400);10 return response.sendStatus(400);
13 }11 }
src/endpoints/novelai.js+4 -5
@@ -6,7 +6,6 @@ import express from 'express';
66
7import { readSecret, SECRET_KEYS } from './secrets.js';7import { readSecret, SECRET_KEYS } from './secrets.js';
8import { readAllChunks, extractFileFromZipBuffer, forwardFetchResponse } from '../util.js';8import { readAllChunks, extractFileFromZipBuffer, forwardFetchResponse } from '../util.js';
9import { jsonParser } from '../express-common.js';
109
11const API_NOVELAI = 'https://api.novelai.net';10const API_NOVELAI = 'https://api.novelai.net';
12const TEXT_NOVELAI = 'https://text.novelai.net';11const TEXT_NOVELAI = 'https://text.novelai.net';
@@ -115,7 +114,7 @@ function getRepPenaltyWhitelist(model) {
115114
116export const router = express.Router();115export const router = express.Router();
117116
118router.post('/status', jsonParser, async function (req, res) {117router.post('/status', async function (req, res) {
119 if (!req.body) return res.sendStatus(400);118 if (!req.body) return res.sendStatus(400);
120 const api_key_novel = readSecret(req.user.directories, SECRET_KEYS.NOVEL);119 const api_key_novel = readSecret(req.user.directories, SECRET_KEYS.NOVEL);
121120
@@ -150,7 +149,7 @@ router.post('/status', jsonParser, async function (req, res) {
150 }149 }
151});150});
152151
153router.post('/generate', jsonParser, async function (req, res) {152router.post('/generate', async function (req, res) {
154 if (!req.body) return res.sendStatus(400);153 if (!req.body) return res.sendStatus(400);
155154
156 const api_key_novel = readSecret(req.user.directories, SECRET_KEYS.NOVEL);155 const api_key_novel = readSecret(req.user.directories, SECRET_KEYS.NOVEL);
@@ -284,7 +283,7 @@ router.post('/generate', jsonParser, async function (req, res) {
284 }283 }
285});284});
286285
287router.post('/generate-image', jsonParser, async (request, response) => {286router.post('/generate-image', async (request, response) => {
288 if (!request.body) {287 if (!request.body) {
289 return response.sendStatus(400);288 return response.sendStatus(400);
290 }289 }
@@ -418,7 +417,7 @@ router.post('/generate-image', jsonParser, async (request, response) => {
418 }417 }
419});418});
420419
421router.post('/generate-voice', jsonParser, async (request, response) => {420router.post('/generate-voice', async (request, response) => {
422 const token = readSecret(request.user.directories, SECRET_KEYS.NOVEL);421 const token = readSecret(request.user.directories, SECRET_KEYS.NOVEL);
423422
424 if (!token) {423 if (!token) {
src/endpoints/openai.js+5 -6
@@ -5,7 +5,6 @@ import fetch from 'node-fetch';
5import FormData from 'form-data';5import FormData from 'form-data';
6import express from 'express';6import express from 'express';
77
8import { jsonParser, urlencodedParser } from '../express-common.js';
9import { getConfigValue, mergeObjectWithYaml, excludeKeysByYaml, trimV1 } from '../util.js';8import { getConfigValue, mergeObjectWithYaml, excludeKeysByYaml, trimV1 } from '../util.js';
10import { setAdditionalHeaders } from '../additional-headers.js';9import { setAdditionalHeaders } from '../additional-headers.js';
11import { readSecret, SECRET_KEYS } from './secrets.js';10import { readSecret, SECRET_KEYS } from './secrets.js';
@@ -13,7 +12,7 @@ import { OPENROUTER_HEADERS } from '../constants.js';
1312
14export const router = express.Router();13export const router = express.Router();
1514
16router.post('/caption-image', jsonParser, async (request, response) => {15router.post('/caption-image', async (request, response) => {
17 try {16 try {
18 let key = '';17 let key = '';
19 let headers = {};18 let headers = {};
@@ -189,7 +188,7 @@ router.post('/caption-image', jsonParser, async (request, response) => {
189 }188 }
190});189});
191190
192router.post('/transcribe-audio', urlencodedParser, async (request, response) => {191router.post('/transcribe-audio', async (request, response) => {
193 try {192 try {
194 const key = readSecret(request.user.directories, SECRET_KEYS.OPENAI);193 const key = readSecret(request.user.directories, SECRET_KEYS.OPENAI);
195194
@@ -237,7 +236,7 @@ router.post('/transcribe-audio', urlencodedParser, async (request, response) =>
237 }236 }
238});237});
239238
240router.post('/generate-voice', jsonParser, async (request, response) => {239router.post('/generate-voice', async (request, response) => {
241 try {240 try {
242 const key = readSecret(request.user.directories, SECRET_KEYS.OPENAI);241 const key = readSecret(request.user.directories, SECRET_KEYS.OPENAI);
243242
@@ -276,7 +275,7 @@ router.post('/generate-voice', jsonParser, async (request, response) => {
276 }275 }
277});276});
278277
279router.post('/generate-image', jsonParser, async (request, response) => {278router.post('/generate-image', async (request, response) => {
280 try {279 try {
281 const key = readSecret(request.user.directories, SECRET_KEYS.OPENAI);280 const key = readSecret(request.user.directories, SECRET_KEYS.OPENAI);
282281
@@ -312,7 +311,7 @@ router.post('/generate-image', jsonParser, async (request, response) => {
312311
313const custom = express.Router();312const custom = express.Router();
314313
315custom.post('/generate-voice', jsonParser, async (request, response) => {314custom.post('/generate-voice', async (request, response) => {
316 try {315 try {
317 const key = readSecret(request.user.directories, SECRET_KEYS.CUSTOM_OPENAI_TTS);316 const key = readSecret(request.user.directories, SECRET_KEYS.CUSTOM_OPENAI_TTS);
318 const { input, provider_endpoint, response_format, voice, speed, model } = request.body;317 const { input, provider_endpoint, response_format, voice, speed, model } = request.body;
src/endpoints/openrouter.js+2 -3
@@ -1,10 +1,9 @@
1import express from 'express';1import express from 'express';
2import { jsonParser } from '../express-common.js';
32
4export const router = express.Router();3export const router = express.Router();
5const API_OPENROUTER = 'https://openrouter.ai/api/v1';4const API_OPENROUTER = 'https://openrouter.ai/api/v1';
65
7router.post('/models/providers', jsonParser, async (req, res) => {6router.post('/models/providers', async (req, res) => {
8 try {7 try {
9 const { model } = req.body;8 const { model } = req.body;
10 const response = await fetch(`${API_OPENROUTER}/models/${model}/endpoints`, {9 const response = await fetch(`${API_OPENROUTER}/models/${model}/endpoints`, {
@@ -29,7 +28,7 @@ router.post('/models/providers', jsonParser, async (req, res) => {
29 }28 }
30});29});
3130
32router.post('/models/multimodal', jsonParser, async (_req, res) => {31router.post('/models/multimodal', async (_req, res) => {
33 try {32 try {
34 // The endpoint is available without authentication33 // The endpoint is available without authentication
35 const response = await fetch(`${API_OPENROUTER}/models`, {34 const response = await fetch(`${API_OPENROUTER}/models`, {
src/endpoints/presets.js+5 -6
@@ -6,7 +6,6 @@ import sanitize from 'sanitize-filename';
6import { sync as writeFileAtomicSync } from 'write-file-atomic';6import { sync as writeFileAtomicSync } from 'write-file-atomic';
77
8import { getDefaultPresetFile, getDefaultPresets } from './content-manager.js';8import { getDefaultPresetFile, getDefaultPresets } from './content-manager.js';
9import { jsonParser } from '../express-common.js';
109
11/**10/**
12 * Gets the folder and extension for the preset settings based on the API source ID.11 * Gets the folder and extension for the preset settings based on the API source ID.
@@ -38,7 +37,7 @@ function getPresetSettingsByAPI(apiId, directories) {
3837
39export const router = express.Router();38export const router = express.Router();
4039
41router.post('/save', jsonParser, function (request, response) {40router.post('/save', function (request, response) {
42 const name = sanitize(request.body.name);41 const name = sanitize(request.body.name);
43 if (!request.body.preset || !name) {42 if (!request.body.preset || !name) {
44 return response.sendStatus(400);43 return response.sendStatus(400);
@@ -56,7 +55,7 @@ router.post('/save', jsonParser, function (request, response) {
56 return response.send({ name });55 return response.send({ name });
57});56});
5857
59router.post('/delete', jsonParser, function (request, response) {58router.post('/delete', function (request, response) {
60 const name = sanitize(request.body.name);59 const name = sanitize(request.body.name);
61 if (!name) {60 if (!name) {
62 return response.sendStatus(400);61 return response.sendStatus(400);
@@ -79,7 +78,7 @@ router.post('/delete', jsonParser, function (request, response) {
79 }78 }
80});79});
8180
82router.post('/restore', jsonParser, function (request, response) {81router.post('/restore', function (request, response) {
83 try {82 try {
84 const settings = getPresetSettingsByAPI(request.body.apiId, request.user.directories);83 const settings = getPresetSettingsByAPI(request.body.apiId, request.user.directories);
85 const name = sanitize(request.body.name);84 const name = sanitize(request.body.name);
@@ -102,7 +101,7 @@ router.post('/restore', jsonParser, function (request, response) {
102});101});
103102
104// TODO: Merge with /api/presets/save103// TODO: Merge with /api/presets/save
105router.post('/save-openai', jsonParser, function (request, response) {104router.post('/save-openai', function (request, response) {
106 if (!request.body || typeof request.query.name !== 'string') return response.sendStatus(400);105 if (!request.body || typeof request.query.name !== 'string') return response.sendStatus(400);
107 const name = sanitize(request.query.name);106 const name = sanitize(request.query.name);
108 if (!name) return response.sendStatus(400);107 if (!name) return response.sendStatus(400);
@@ -114,7 +113,7 @@ router.post('/save-openai', jsonParser, function (request, response) {
114});113});
115114
116// TODO: Merge with /api/presets/delete115// TODO: Merge with /api/presets/delete
117router.post('/delete-openai', jsonParser, function (request, response) {116router.post('/delete-openai', function (request, response) {
118 if (!request.body || !request.body.name) {117 if (!request.body || !request.body.name) {
119 return response.sendStatus(400);118 return response.sendStatus(400);
120 }119 }
src/endpoints/quick-replies.js+2 -4
@@ -5,11 +5,9 @@ import express from 'express';
5import sanitize from 'sanitize-filename';5import sanitize from 'sanitize-filename';
6import { sync as writeFileAtomicSync } from 'write-file-atomic';6import { sync as writeFileAtomicSync } from 'write-file-atomic';
77
8import { jsonParser } from '../express-common.js';
9
10export const router = express.Router();8export const router = express.Router();
119
12router.post('/save', jsonParser, (request, response) => {10router.post('/save', (request, response) => {
13 if (!request.body || !request.body.name) {11 if (!request.body || !request.body.name) {
14 return response.sendStatus(400);12 return response.sendStatus(400);
15 }13 }
@@ -20,7 +18,7 @@ router.post('/save', jsonParser, (request, response) => {
20 return response.sendStatus(200);18 return response.sendStatus(200);
21});19});
2220
23router.post('/delete', jsonParser, (request, response) => {21router.post('/delete', (request, response) => {
24 if (!request.body || !request.body.name) {22 if (!request.body || !request.body.name) {
25 return response.sendStatus(400);23 return response.sendStatus(400);
26 }24 }
src/endpoints/search.js+7 -8
@@ -3,7 +3,6 @@ import express from 'express';
33
4import { decode } from 'html-entities';4import { decode } from 'html-entities';
5import { readSecret, SECRET_KEYS } from './secrets.js';5import { readSecret, SECRET_KEYS } from './secrets.js';
6import { jsonParser } from '../express-common.js';
7import { trimV1 } from '../util.js';6import { trimV1 } from '../util.js';
8import { setAdditionalHeaders } from '../additional-headers.js';7import { setAdditionalHeaders } from '../additional-headers.js';
98
@@ -91,7 +90,7 @@ async function extractTranscript(videoPageBody, lang) {
91 return transcriptText;90 return transcriptText;
92}91}
9392
94router.post('/serpapi', jsonParser, async (request, response) => {93router.post('/serpapi', async (request, response) => {
95 try {94 try {
96 const key = readSecret(request.user.directories, SECRET_KEYS.SERPAPI);95 const key = readSecret(request.user.directories, SECRET_KEYS.SERPAPI);
9796
@@ -124,7 +123,7 @@ router.post('/serpapi', jsonParser, async (request, response) => {
124 * Get the transcript of a YouTube video123 * Get the transcript of a YouTube video
125 * @copyright https://github.com/Kakulukian/youtube-transcript (MIT License)124 * @copyright https://github.com/Kakulukian/youtube-transcript (MIT License)
126 */125 */
127router.post('/transcript', jsonParser, async (request, response) => {126router.post('/transcript', async (request, response) => {
128 try {127 try {
129 const id = request.body.id;128 const id = request.body.id;
130 const lang = request.body.lang;129 const lang = request.body.lang;
@@ -161,7 +160,7 @@ router.post('/transcript', jsonParser, async (request, response) => {
161 }160 }
162});161});
163162
164router.post('/searxng', jsonParser, async (request, response) => {163router.post('/searxng', async (request, response) => {
165 try {164 try {
166 const { baseUrl, query, preferences, categories } = request.body;165 const { baseUrl, query, preferences, categories } = request.body;
167166
@@ -215,7 +214,7 @@ router.post('/searxng', jsonParser, async (request, response) => {
215 }214 }
216});215});
217216
218router.post('/tavily', jsonParser, async (request, response) => {217router.post('/tavily', async (request, response) => {
219 try {218 try {
220 const apiKey = readSecret(request.user.directories, SECRET_KEYS.TAVILY);219 const apiKey = readSecret(request.user.directories, SECRET_KEYS.TAVILY);
221220
@@ -264,7 +263,7 @@ router.post('/tavily', jsonParser, async (request, response) => {
264 }263 }
265});264});
266265
267router.post('/koboldcpp', jsonParser, async (request, response) => {266router.post('/koboldcpp', async (request, response) => {
268 try {267 try {
269 const { query, url } = request.body;268 const { query, url } = request.body;
270269
@@ -300,7 +299,7 @@ router.post('/koboldcpp', jsonParser, async (request, response) => {
300 }299 }
301});300});
302301
303router.post('/serper', jsonParser, async (request, response) => {302router.post('/serper', async (request, response) => {
304 try {303 try {
305 const key = readSecret(request.user.directories, SECRET_KEYS.SERPER);304 const key = readSecret(request.user.directories, SECRET_KEYS.SERPER);
306305
@@ -342,7 +341,7 @@ router.post('/serper', jsonParser, async (request, response) => {
342 }341 }
343});342});
344343
345router.post('/visit', jsonParser, async (request, response) => {344router.post('/visit', async (request, response) => {
346 try {345 try {
347 const url = request.body.url;346 const url = request.body.url;
348 const html = Boolean(request.body.html ?? true);347 const html = Boolean(request.body.html ?? true);
src/endpoints/secrets.js+4 -5
@@ -4,7 +4,6 @@ import path from 'node:path';
4import express from 'express';4import express from 'express';
5import { sync as writeFileAtomicSync } from 'write-file-atomic';5import { sync as writeFileAtomicSync } from 'write-file-atomic';
6import { getConfigValue } from '../util.js';6import { getConfigValue } from '../util.js';
7import { jsonParser } from '../express-common.js';
87
9export const SECRETS_FILE = 'secrets.json';8export const SECRETS_FILE = 'secrets.json';
10export const SECRET_KEYS = {9export const SECRET_KEYS = {
@@ -164,7 +163,7 @@ export function getAllSecrets(directories) {
164163
165export const router = express.Router();164export const router = express.Router();
166165
167router.post('/write', jsonParser, (request, response) => {166router.post('/write', (request, response) => {
168 const key = request.body.key;167 const key = request.body.key;
169 const value = request.body.value;168 const value = request.body.value;
170169
@@ -172,7 +171,7 @@ router.post('/write', jsonParser, (request, response) => {
172 return response.send('ok');171 return response.send('ok');
173});172});
174173
175router.post('/read', jsonParser, (request, response) => {174router.post('/read', (request, response) => {
176 try {175 try {
177 const state = readSecretState(request.user.directories);176 const state = readSecretState(request.user.directories);
178 return response.send(state);177 return response.send(state);
@@ -182,7 +181,7 @@ router.post('/read', jsonParser, (request, response) => {
182 }181 }
183});182});
184183
185router.post('/view', jsonParser, async (request, response) => {184router.post('/view', async (request, response) => {
186 const allowKeysExposure = getConfigValue('allowKeysExposure', false, 'boolean');185 const allowKeysExposure = getConfigValue('allowKeysExposure', false, 'boolean');
187186
188 if (!allowKeysExposure) {187 if (!allowKeysExposure) {
@@ -204,7 +203,7 @@ router.post('/view', jsonParser, async (request, response) => {
204 }203 }
205});204});
206205
207router.post('/find', jsonParser, (request, response) => {206router.post('/find', (request, response) => {
208 const allowKeysExposure = getConfigValue('allowKeysExposure', false, 'boolean');207 const allowKeysExposure = getConfigValue('allowKeysExposure', false, 'boolean');
209 const key = request.body.key;208 const key = request.body.key;
210209
src/endpoints/settings.js+6 -7
@@ -7,7 +7,6 @@ import { sync as writeFileAtomicSync } from 'write-file-atomic';
77
8import { SETTINGS_FILE } from '../constants.js';8import { SETTINGS_FILE } from '../constants.js';
9import { getConfigValue, generateTimestamp, removeOldBackups } from '../util.js';9import { getConfigValue, generateTimestamp, removeOldBackups } from '../util.js';
10import { jsonParser } from '../express-common.js';
11import { getAllUserHandles, getUserDirectories } from '../users.js';10import { getAllUserHandles, getUserDirectories } from '../users.js';
12import { getFileNameValidationFunction } from '../middleware/validateFileName.js';11import { getFileNameValidationFunction } from '../middleware/validateFileName.js';
1312
@@ -195,7 +194,7 @@ function getLatestBackup(handle) {
195194
196export const router = express.Router();195export const router = express.Router();
197196
198router.post('/save', jsonParser, function (request, response) {197router.post('/save', function (request, response) {
199 try {198 try {
200 const pathToSettings = path.join(request.user.directories.root, SETTINGS_FILE);199 const pathToSettings = path.join(request.user.directories.root, SETTINGS_FILE);
201 writeFileAtomicSync(pathToSettings, JSON.stringify(request.body, null, 4), 'utf8');200 writeFileAtomicSync(pathToSettings, JSON.stringify(request.body, null, 4), 'utf8');
@@ -208,7 +207,7 @@ router.post('/save', jsonParser, function (request, response) {
208});207});
209208
210// Wintermute's code209// Wintermute's code
211router.post('/get', jsonParser, (request, response) => {210router.post('/get', (request, response) => {
212 let settings;211 let settings;
213 try {212 try {
214 const pathToSettings = path.join(request.user.directories.root, SETTINGS_FILE);213 const pathToSettings = path.join(request.user.directories.root, SETTINGS_FILE);
@@ -279,7 +278,7 @@ router.post('/get', jsonParser, (request, response) => {
279 });278 });
280});279});
281280
282router.post('/get-snapshots', jsonParser, async (request, response) => {281router.post('/get-snapshots', async (request, response) => {
283 try {282 try {
284 const snapshots = fs.readdirSync(request.user.directories.backups);283 const snapshots = fs.readdirSync(request.user.directories.backups);
285 const userFilesPattern = getFilePrefix(request.user.profile.handle);284 const userFilesPattern = getFilePrefix(request.user.profile.handle);
@@ -297,7 +296,7 @@ router.post('/get-snapshots', jsonParser, async (request, response) => {
297 }296 }
298});297});
299298
300router.post('/load-snapshot', jsonParser, getFileNameValidationFunction('name'), async (request, response) => {299router.post('/load-snapshot', getFileNameValidationFunction('name'), async (request, response) => {
301 try {300 try {
302 const userFilesPattern = getFilePrefix(request.user.profile.handle);301 const userFilesPattern = getFilePrefix(request.user.profile.handle);
303302
@@ -321,7 +320,7 @@ router.post('/load-snapshot', jsonParser, getFileNameValidationFunction('name'),
321 }320 }
322});321});
323322
324router.post('/make-snapshot', jsonParser, async (request, response) => {323router.post('/make-snapshot', async (request, response) => {
325 try {324 try {
326 backupUserSettings(request.user.profile.handle, false);325 backupUserSettings(request.user.profile.handle, false);
327 response.sendStatus(204);326 response.sendStatus(204);
@@ -331,7 +330,7 @@ router.post('/make-snapshot', jsonParser, async (request, response) => {
331 }330 }
332});331});
333332
334router.post('/restore-snapshot', jsonParser, getFileNameValidationFunction('name'), async (request, response) => {333router.post('/restore-snapshot', getFileNameValidationFunction('name'), async (request, response) => {
335 try {334 try {
336 const userFilesPattern = getFilePrefix(request.user.profile.handle);335 const userFilesPattern = getFilePrefix(request.user.profile.handle);
337336
src/endpoints/speech.js+2 -3
@@ -1,7 +1,6 @@
1import { Buffer } from 'node:buffer';1import { Buffer } from 'node:buffer';
2import express from 'express';2import express from 'express';
3import wavefile from 'wavefile';3import wavefile from 'wavefile';
4import { jsonParser } from '../express-common.js';
5import { getPipeline } from '../transformers.js';4import { getPipeline } from '../transformers.js';
65
7export const router = express.Router();6export const router = express.Router();
@@ -34,7 +33,7 @@ function getWaveFile(audio) {
34 return audioData;33 return audioData;
35}34}
3635
37router.post('/recognize', jsonParser, async (req, res) => {36router.post('/recognize', async (req, res) => {
38 try {37 try {
39 const TASK = 'automatic-speech-recognition';38 const TASK = 'automatic-speech-recognition';
40 const { model, audio, lang } = req.body;39 const { model, audio, lang } = req.body;
@@ -53,7 +52,7 @@ router.post('/recognize', jsonParser, async (req, res) => {
53 }52 }
54});53});
5554
56router.post('/synthesize', jsonParser, async (req, res) => {55router.post('/synthesize', async (req, res) => {
57 try {56 try {
58 const TASK = 'text-to-speech';57 const TASK = 'text-to-speech';
59 const { text, model, speaker } = req.body;58 const { text, model, speaker } = req.body;
src/endpoints/sprites.js+4 -5
@@ -7,7 +7,6 @@ import sanitize from 'sanitize-filename';
7import { sync as writeFileAtomicSync } from 'write-file-atomic';7import { sync as writeFileAtomicSync } from 'write-file-atomic';
88
9import { getImageBuffers } from '../util.js';9import { getImageBuffers } from '../util.js';
10import { jsonParser, urlencodedParser } from '../express-common.js';
1110
12/**11/**
13 * Gets the path to the sprites folder for the provided character name12 * Gets the path to the sprites folder for the provided character name
@@ -109,7 +108,7 @@ export function importRisuSprites(directories, data) {
109108
110export const router = express.Router();109export const router = express.Router();
111110
112router.get('/get', jsonParser, function (request, response) {111router.get('/get', function (request, response) {
113 const name = String(request.query.name);112 const name = String(request.query.name);
114 const isSubfolder = name.includes('/');113 const isSubfolder = name.includes('/');
115 const spritesPath = getSpritesPath(request.user.directories, name, isSubfolder);114 const spritesPath = getSpritesPath(request.user.directories, name, isSubfolder);
@@ -144,7 +143,7 @@ router.get('/get', jsonParser, function (request, response) {
144 return response.send(sprites);143 return response.send(sprites);
145});144});
146145
147router.post('/delete', jsonParser, async (request, response) => {146router.post('/delete', async (request, response) => {
148 const label = request.body.label;147 const label = request.body.label;
149 const name = request.body.name;148 const name = request.body.name;
150 const spriteName = request.body.spriteName || label;149 const spriteName = request.body.spriteName || label;
@@ -177,7 +176,7 @@ router.post('/delete', jsonParser, async (request, response) => {
177 }176 }
178});177});
179178
180router.post('/upload-zip', urlencodedParser, async (request, response) => {179router.post('/upload-zip', async (request, response) => {
181 const file = request.file;180 const file = request.file;
182 const name = request.body.name;181 const name = request.body.name;
183182
@@ -224,7 +223,7 @@ router.post('/upload-zip', urlencodedParser, async (request, response) => {
224 }223 }
225});224});
226225
227router.post('/upload', urlencodedParser, async (request, response) => {226router.post('/upload', async (request, response) => {
228 const file = request.file;227 const file = request.file;
229 const label = request.body.label;228 const label = request.body.label;
230 const name = request.body.name;229 const name = request.body.name;
src/endpoints/stable-diffusion.js+38 -39
@@ -10,7 +10,6 @@ import urlJoin from 'url-join';
10import _ from 'lodash';10import _ from 'lodash';
1111
12import { delay, getBasicAuthHeader, tryParse } from '../util.js';12import { delay, getBasicAuthHeader, tryParse } from '../util.js';
13import { jsonParser } from '../express-common.js';
14import { readSecret, SECRET_KEYS } from './secrets.js';13import { readSecret, SECRET_KEYS } from './secrets.js';
1514
16/**15/**
@@ -27,7 +26,7 @@ function getComfyWorkflows(directories) {
2726
28export const router = express.Router();27export const router = express.Router();
2928
30router.post('/ping', jsonParser, async (request, response) => {29router.post('/ping', async (request, response) => {
31 try {30 try {
32 const url = new URL(request.body.url);31 const url = new URL(request.body.url);
33 url.pathname = '/sdapi/v1/options';32 url.pathname = '/sdapi/v1/options';
@@ -50,7 +49,7 @@ router.post('/ping', jsonParser, async (request, response) => {
50 }49 }
51});50});
5251
53router.post('/upscalers', jsonParser, async (request, response) => {52router.post('/upscalers', async (request, response) => {
54 try {53 try {
55 async function getUpscalerModels() {54 async function getUpscalerModels() {
56 const url = new URL(request.body.url);55 const url = new URL(request.body.url);
@@ -104,7 +103,7 @@ router.post('/upscalers', jsonParser, async (request, response) => {
104 }103 }
105});104});
106105
107router.post('/vaes', jsonParser, async (request, response) => {106router.post('/vaes', async (request, response) => {
108 try {107 try {
109 const autoUrl = new URL(request.body.url);108 const autoUrl = new URL(request.body.url);
110 autoUrl.pathname = '/sdapi/v1/sd-vae';109 autoUrl.pathname = '/sdapi/v1/sd-vae';
@@ -136,7 +135,7 @@ router.post('/vaes', jsonParser, async (request, response) => {
136 }135 }
137});136});
138137
139router.post('/samplers', jsonParser, async (request, response) => {138router.post('/samplers', async (request, response) => {
140 try {139 try {
141 const url = new URL(request.body.url);140 const url = new URL(request.body.url);
142 url.pathname = '/sdapi/v1/samplers';141 url.pathname = '/sdapi/v1/samplers';
@@ -163,7 +162,7 @@ router.post('/samplers', jsonParser, async (request, response) => {
163 }162 }
164});163});
165164
166router.post('/schedulers', jsonParser, async (request, response) => {165router.post('/schedulers', async (request, response) => {
167 try {166 try {
168 const url = new URL(request.body.url);167 const url = new URL(request.body.url);
169 url.pathname = '/sdapi/v1/schedulers';168 url.pathname = '/sdapi/v1/schedulers';
@@ -189,7 +188,7 @@ router.post('/schedulers', jsonParser, async (request, response) => {
189 }188 }
190});189});
191190
192router.post('/models', jsonParser, async (request, response) => {191router.post('/models', async (request, response) => {
193 try {192 try {
194 const url = new URL(request.body.url);193 const url = new URL(request.body.url);
195 url.pathname = '/sdapi/v1/sd-models';194 url.pathname = '/sdapi/v1/sd-models';
@@ -215,7 +214,7 @@ router.post('/models', jsonParser, async (request, response) => {
215 }214 }
216});215});
217216
218router.post('/get-model', jsonParser, async (request, response) => {217router.post('/get-model', async (request, response) => {
219 try {218 try {
220 const url = new URL(request.body.url);219 const url = new URL(request.body.url);
221 url.pathname = '/sdapi/v1/options';220 url.pathname = '/sdapi/v1/options';
@@ -235,7 +234,7 @@ router.post('/get-model', jsonParser, async (request, response) => {
235 }234 }
236});235});
237236
238router.post('/set-model', jsonParser, async (request, response) => {237router.post('/set-model', async (request, response) => {
239 try {238 try {
240 async function getProgress() {239 async function getProgress() {
241 const url = new URL(request.body.url);240 const url = new URL(request.body.url);
@@ -294,7 +293,7 @@ router.post('/set-model', jsonParser, async (request, response) => {
294 }293 }
295});294});
296295
297router.post('/generate', jsonParser, async (request, response) => {296router.post('/generate', async (request, response) => {
298 try {297 try {
299 try {298 try {
300 const optionsUrl = new URL(request.body.url);299 const optionsUrl = new URL(request.body.url);
@@ -349,7 +348,7 @@ router.post('/generate', jsonParser, async (request, response) => {
349 }348 }
350});349});
351350
352router.post('/sd-next/upscalers', jsonParser, async (request, response) => {351router.post('/sd-next/upscalers', async (request, response) => {
353 try {352 try {
354 const url = new URL(request.body.url);353 const url = new URL(request.body.url);
355 url.pathname = '/sdapi/v1/upscalers';354 url.pathname = '/sdapi/v1/upscalers';
@@ -384,7 +383,7 @@ router.post('/sd-next/upscalers', jsonParser, async (request, response) => {
384383
385const comfy = express.Router();384const comfy = express.Router();
386385
387comfy.post('/ping', jsonParser, async (request, response) => {386comfy.post('/ping', async (request, response) => {
388 try {387 try {
389 const url = new URL(urlJoin(request.body.url, '/system_stats'));388 const url = new URL(urlJoin(request.body.url, '/system_stats'));
390389
@@ -400,7 +399,7 @@ comfy.post('/ping', jsonParser, async (request, response) => {
400 }399 }
401});400});
402401
403comfy.post('/samplers', jsonParser, async (request, response) => {402comfy.post('/samplers', async (request, response) => {
404 try {403 try {
405 const url = new URL(urlJoin(request.body.url, '/object_info'));404 const url = new URL(urlJoin(request.body.url, '/object_info'));
406405
@@ -418,7 +417,7 @@ comfy.post('/samplers', jsonParser, async (request, response) => {
418 }417 }
419});418});
420419
421comfy.post('/models', jsonParser, async (request, response) => {420comfy.post('/models', async (request, response) => {
422 try {421 try {
423 const url = new URL(urlJoin(request.body.url, '/object_info'));422 const url = new URL(urlJoin(request.body.url, '/object_info'));
424423
@@ -446,7 +445,7 @@ comfy.post('/models', jsonParser, async (request, response) => {
446 }445 }
447});446});
448447
449comfy.post('/schedulers', jsonParser, async (request, response) => {448comfy.post('/schedulers', async (request, response) => {
450 try {449 try {
451 const url = new URL(urlJoin(request.body.url, '/object_info'));450 const url = new URL(urlJoin(request.body.url, '/object_info'));
452451
@@ -464,7 +463,7 @@ comfy.post('/schedulers', jsonParser, async (request, response) => {
464 }463 }
465});464});
466465
467comfy.post('/vaes', jsonParser, async (request, response) => {466comfy.post('/vaes', async (request, response) => {
468 try {467 try {
469 const url = new URL(urlJoin(request.body.url, '/object_info'));468 const url = new URL(urlJoin(request.body.url, '/object_info'));
470469
@@ -482,7 +481,7 @@ comfy.post('/vaes', jsonParser, async (request, response) => {
482 }481 }
483});482});
484483
485comfy.post('/workflows', jsonParser, async (request, response) => {484comfy.post('/workflows', async (request, response) => {
486 try {485 try {
487 const data = getComfyWorkflows(request.user.directories);486 const data = getComfyWorkflows(request.user.directories);
488 return response.send(data);487 return response.send(data);
@@ -492,7 +491,7 @@ comfy.post('/workflows', jsonParser, async (request, response) => {
492 }491 }
493});492});
494493
495comfy.post('/workflow', jsonParser, async (request, response) => {494comfy.post('/workflow', async (request, response) => {
496 try {495 try {
497 let filePath = path.join(request.user.directories.comfyWorkflows, sanitize(String(request.body.file_name)));496 let filePath = path.join(request.user.directories.comfyWorkflows, sanitize(String(request.body.file_name)));
498 if (!fs.existsSync(filePath)) {497 if (!fs.existsSync(filePath)) {
@@ -506,7 +505,7 @@ comfy.post('/workflow', jsonParser, async (request, response) => {
506 }505 }
507});506});
508507
509comfy.post('/save-workflow', jsonParser, async (request, response) => {508comfy.post('/save-workflow', async (request, response) => {
510 try {509 try {
511 const filePath = path.join(request.user.directories.comfyWorkflows, sanitize(String(request.body.file_name)));510 const filePath = path.join(request.user.directories.comfyWorkflows, sanitize(String(request.body.file_name)));
512 writeFileAtomicSync(filePath, request.body.workflow, 'utf8');511 writeFileAtomicSync(filePath, request.body.workflow, 'utf8');
@@ -518,7 +517,7 @@ comfy.post('/save-workflow', jsonParser, async (request, response) => {
518 }517 }
519});518});
520519
521comfy.post('/delete-workflow', jsonParser, async (request, response) => {520comfy.post('/delete-workflow', async (request, response) => {
522 try {521 try {
523 const filePath = path.join(request.user.directories.comfyWorkflows, sanitize(String(request.body.file_name)));522 const filePath = path.join(request.user.directories.comfyWorkflows, sanitize(String(request.body.file_name)));
524 if (fs.existsSync(filePath)) {523 if (fs.existsSync(filePath)) {
@@ -531,7 +530,7 @@ comfy.post('/delete-workflow', jsonParser, async (request, response) => {
531 }530 }
532});531});
533532
534comfy.post('/generate', jsonParser, async (request, response) => {533comfy.post('/generate', async (request, response) => {
535 try {534 try {
536 let item;535 let item;
537 const url = new URL(urlJoin(request.body.url, '/prompt'));536 const url = new URL(urlJoin(request.body.url, '/prompt'));
@@ -599,7 +598,7 @@ comfy.post('/generate', jsonParser, async (request, response) => {
599598
600const together = express.Router();599const together = express.Router();
601600
602together.post('/models', jsonParser, async (request, response) => {601together.post('/models', async (request, response) => {
603 try {602 try {
604 const key = readSecret(request.user.directories, SECRET_KEYS.TOGETHERAI);603 const key = readSecret(request.user.directories, SECRET_KEYS.TOGETHERAI);
605604
@@ -638,7 +637,7 @@ together.post('/models', jsonParser, async (request, response) => {
638 }637 }
639});638});
640639
641together.post('/generate', jsonParser, async (request, response) => {640together.post('/generate', async (request, response) => {
642 try {641 try {
643 const key = readSecret(request.user.directories, SECRET_KEYS.TOGETHERAI);642 const key = readSecret(request.user.directories, SECRET_KEYS.TOGETHERAI);
644643
@@ -694,7 +693,7 @@ together.post('/generate', jsonParser, async (request, response) => {
694693
695const drawthings = express.Router();694const drawthings = express.Router();
696695
697drawthings.post('/ping', jsonParser, async (request, response) => {696drawthings.post('/ping', async (request, response) => {
698 try {697 try {
699 const url = new URL(request.body.url);698 const url = new URL(request.body.url);
700 url.pathname = '/';699 url.pathname = '/';
@@ -714,7 +713,7 @@ drawthings.post('/ping', jsonParser, async (request, response) => {
714 }713 }
715});714});
716715
717drawthings.post('/get-model', jsonParser, async (request, response) => {716drawthings.post('/get-model', async (request, response) => {
718 try {717 try {
719 const url = new URL(request.body.url);718 const url = new URL(request.body.url);
720 url.pathname = '/';719 url.pathname = '/';
@@ -733,7 +732,7 @@ drawthings.post('/get-model', jsonParser, async (request, response) => {
733 }732 }
734});733});
735734
736drawthings.post('/get-upscaler', jsonParser, async (request, response) => {735drawthings.post('/get-upscaler', async (request, response) => {
737 try {736 try {
738 const url = new URL(request.body.url);737 const url = new URL(request.body.url);
739 url.pathname = '/';738 url.pathname = '/';
@@ -752,7 +751,7 @@ drawthings.post('/get-upscaler', jsonParser, async (request, response) => {
752 }751 }
753});752});
754753
755drawthings.post('/generate', jsonParser, async (request, response) => {754drawthings.post('/generate', async (request, response) => {
756 try {755 try {
757 console.debug('SD DrawThings API request:', request.body);756 console.debug('SD DrawThings API request:', request.body);
758757
@@ -788,7 +787,7 @@ drawthings.post('/generate', jsonParser, async (request, response) => {
788787
789const pollinations = express.Router();788const pollinations = express.Router();
790789
791pollinations.post('/models', jsonParser, async (_request, response) => {790pollinations.post('/models', async (_request, response) => {
792 try {791 try {
793 const modelsUrl = new URL('https://image.pollinations.ai/models');792 const modelsUrl = new URL('https://image.pollinations.ai/models');
794 const result = await fetch(modelsUrl);793 const result = await fetch(modelsUrl);
@@ -813,7 +812,7 @@ pollinations.post('/models', jsonParser, async (_request, response) => {
813 }812 }
814});813});
815814
816pollinations.post('/generate', jsonParser, async (request, response) => {815pollinations.post('/generate', async (request, response) => {
817 try {816 try {
818 const promptUrl = new URL(`https://image.pollinations.ai/prompt/${encodeURIComponent(request.body.prompt)}`);817 const promptUrl = new URL(`https://image.pollinations.ai/prompt/${encodeURIComponent(request.body.prompt)}`);
819 const params = new URLSearchParams({818 const params = new URLSearchParams({
@@ -850,7 +849,7 @@ pollinations.post('/generate', jsonParser, async (request, response) => {
850849
851const stability = express.Router();850const stability = express.Router();
852851
853stability.post('/generate', jsonParser, async (request, response) => {852stability.post('/generate', async (request, response) => {
854 try {853 try {
855 const key = readSecret(request.user.directories, SECRET_KEYS.STABILITY);854 const key = readSecret(request.user.directories, SECRET_KEYS.STABILITY);
856855
@@ -910,7 +909,7 @@ stability.post('/generate', jsonParser, async (request, response) => {
910909
911const blockentropy = express.Router();910const blockentropy = express.Router();
912911
913blockentropy.post('/models', jsonParser, async (request, response) => {912blockentropy.post('/models', async (request, response) => {
914 try {913 try {
915 const key = readSecret(request.user.directories, SECRET_KEYS.BLOCKENTROPY);914 const key = readSecret(request.user.directories, SECRET_KEYS.BLOCKENTROPY);
916915
@@ -946,7 +945,7 @@ blockentropy.post('/models', jsonParser, async (request, response) => {
946 }945 }
947});946});
948947
949blockentropy.post('/generate', jsonParser, async (request, response) => {948blockentropy.post('/generate', async (request, response) => {
950 try {949 try {
951 const key = readSecret(request.user.directories, SECRET_KEYS.BLOCKENTROPY);950 const key = readSecret(request.user.directories, SECRET_KEYS.BLOCKENTROPY);
952951
@@ -993,7 +992,7 @@ blockentropy.post('/generate', jsonParser, async (request, response) => {
993992
994const huggingface = express.Router();993const huggingface = express.Router();
995994
996huggingface.post('/generate', jsonParser, async (request, response) => {995huggingface.post('/generate', async (request, response) => {
997 try {996 try {
998 const key = readSecret(request.user.directories, SECRET_KEYS.HUGGINGFACE);997 const key = readSecret(request.user.directories, SECRET_KEYS.HUGGINGFACE);
999998
@@ -1032,7 +1031,7 @@ huggingface.post('/generate', jsonParser, async (request, response) => {
10321031
1033const nanogpt = express.Router();1032const nanogpt = express.Router();
10341033
1035nanogpt.post('/models', jsonParser, async (request, response) => {1034nanogpt.post('/models', async (request, response) => {
1036 try {1035 try {
1037 const key = readSecret(request.user.directories, SECRET_KEYS.NANOGPT);1036 const key = readSecret(request.user.directories, SECRET_KEYS.NANOGPT);
10381037
@@ -1072,7 +1071,7 @@ nanogpt.post('/models', jsonParser, async (request, response) => {
1072 }1071 }
1073});1072});
10741073
1075nanogpt.post('/generate', jsonParser, async (request, response) => {1074nanogpt.post('/generate', async (request, response) => {
1076 try {1075 try {
1077 const key = readSecret(request.user.directories, SECRET_KEYS.NANOGPT);1076 const key = readSecret(request.user.directories, SECRET_KEYS.NANOGPT);
10781077
@@ -1116,7 +1115,7 @@ nanogpt.post('/generate', jsonParser, async (request, response) => {
11161115
1117const bfl = express.Router();1116const bfl = express.Router();
11181117
1119bfl.post('/generate', jsonParser, async (request, response) => {1118bfl.post('/generate', async (request, response) => {
1120 try {1119 try {
1121 const key = readSecret(request.user.directories, SECRET_KEYS.BFL);1120 const key = readSecret(request.user.directories, SECRET_KEYS.BFL);
11221121
@@ -1230,7 +1229,7 @@ bfl.post('/generate', jsonParser, async (request, response) => {
12301229
1231const falai = express.Router();1230const falai = express.Router();
12321231
1233falai.post('/models', jsonParser, async (_request, response) => {1232falai.post('/models', async (_request, response) => {
1234 try {1233 try {
1235 const modelsUrl = new URL('https://fal.ai/api/models?categories=text-to-image');1234 const modelsUrl = new URL('https://fal.ai/api/models?categories=text-to-image');
1236 const result = await fetch(modelsUrl);1235 const result = await fetch(modelsUrl);
@@ -1260,7 +1259,7 @@ falai.post('/models', jsonParser, async (_request, response) => {
1260 }1259 }
1261});1260});
12621261
1263falai.post('/generate', jsonParser, async (request, response) => {1262falai.post('/generate', async (request, response) => {
1264 try {1263 try {
1265 const key = readSecret(request.user.directories, SECRET_KEYS.FALAI);1264 const key = readSecret(request.user.directories, SECRET_KEYS.FALAI);
12661265
@@ -1276,7 +1275,7 @@ falai.post('/generate', jsonParser, async (request, response) => {
1276 seed: request.body.seed ?? null,1275 seed: request.body.seed ?? null,
1277 guidance_scale: request.body.guidance,1276 guidance_scale: request.body.guidance,
1278 enable_safety_checker: false, // Disable general safety checks1277 enable_safety_checker: false, // Disable general safety checks
1279 safety_tolerance: 6 // Make Flux the least strict1278 safety_tolerance: 6, // Make Flux the least strict
1280 };1279 };
12811280
1282 console.debug('FAL.AI request:', requestBody);1281 console.debug('FAL.AI request:', requestBody);
src/endpoints/stats.js+3 -4
@@ -8,7 +8,6 @@ import writeFileAtomic from 'write-file-atomic';
8const readFile = fs.promises.readFile;8const readFile = fs.promises.readFile;
9const readdir = fs.promises.readdir;9const readdir = fs.promises.readdir;
1010
11import { jsonParser } from '../express-common.js';
12import { getAllUserHandles, getUserDirectories } from '../users.js';11import { getAllUserHandles, getUserDirectories } from '../users.js';
1312
14const STATS_FILE = 'stats.json';13const STATS_FILE = 'stats.json';
@@ -440,7 +439,7 @@ export const router = express.Router();
440/**439/**
441 * Handle a POST request to get the stats object440 * Handle a POST request to get the stats object
442 */441 */
443router.post('/get', jsonParser, function (request, response) {442router.post('/get', function (request, response) {
444 const stats = STATS.get(request.user.profile.handle) || {};443 const stats = STATS.get(request.user.profile.handle) || {};
445 response.send(stats);444 response.send(stats);
446});445});
@@ -448,7 +447,7 @@ router.post('/get', jsonParser, function (request, response) {
448/**447/**
449 * Triggers the recreation of statistics from chat files.448 * Triggers the recreation of statistics from chat files.
450 */449 */
451router.post('/recreate', jsonParser, async function (request, response) {450router.post('/recreate', async function (request, response) {
452 try {451 try {
453 await recreateStats(request.user.profile.handle, request.user.directories.chats, request.user.directories.characters);452 await recreateStats(request.user.profile.handle, request.user.directories.chats, request.user.directories.characters);
454 return response.sendStatus(200);453 return response.sendStatus(200);
@@ -461,7 +460,7 @@ router.post('/recreate', jsonParser, async function (request, response) {
461/**460/**
462 * Handle a POST request to update the stats object461 * Handle a POST request to update the stats object
463*/462*/
464router.post('/update', jsonParser, function (request, response) {463router.post('/update', function (request, response) {
465 if (!request.body) return response.sendStatus(400);464 if (!request.body) return response.sendStatus(400);
466 setCharStats(request.user.profile.handle, request.body);465 setCharStats(request.user.profile.handle, request.body);
467 return response.sendStatus(200);466 return response.sendStatus(200);
src/endpoints/themes.js+2 -4
@@ -5,11 +5,9 @@ import express from 'express';
5import sanitize from 'sanitize-filename';5import sanitize from 'sanitize-filename';
6import { sync as writeFileAtomicSync } from 'write-file-atomic';6import { sync as writeFileAtomicSync } from 'write-file-atomic';
77
8import { jsonParser } from '../express-common.js';
9
10export const router = express.Router();8export const router = express.Router();
119
12router.post('/save', jsonParser, (request, response) => {10router.post('/save', (request, response) => {
13 if (!request.body || !request.body.name) {11 if (!request.body || !request.body.name) {
14 return response.sendStatus(400);12 return response.sendStatus(400);
15 }13 }
@@ -20,7 +18,7 @@ router.post('/save', jsonParser, (request, response) => {
20 return response.sendStatus(200);18 return response.sendStatus(200);
21});19});
2220
23router.post('/delete', jsonParser, function (request, response) {21router.post('/delete', function (request, response) {
24 if (!request.body || !request.body.name) {22 if (!request.body || !request.body.name) {
25 return response.sendStatus(400);23 return response.sendStatus(400);
26 }24 }
src/endpoints/thumbnails.js+1 -2
@@ -10,7 +10,6 @@ import { sync as writeFileAtomicSync } from 'write-file-atomic';
1010
11import { getAllUserHandles, getUserDirectories } from '../users.js';11import { getAllUserHandles, getUserDirectories } from '../users.js';
12import { getConfigValue } from '../util.js';12import { getConfigValue } from '../util.js';
13import { jsonParser } from '../express-common.js';
1413
15const thumbnailsEnabled = !!getConfigValue('thumbnails.enabled', true, 'boolean');14const thumbnailsEnabled = !!getConfigValue('thumbnails.enabled', true, 'boolean');
16const quality = Math.min(100, Math.max(1, parseInt(getConfigValue('thumbnails.quality', 95, 'number'))));15const quality = Math.min(100, Math.max(1, parseInt(getConfigValue('thumbnails.quality', 95, 'number'))));
@@ -176,7 +175,7 @@ export async function ensureThumbnailCache() {
176export const router = express.Router();175export const router = express.Router();
177176
178// Important: This route must be mounted as '/thumbnail'. It is used in the client code and saved to chat files.177// Important: This route must be mounted as '/thumbnail'. It is used in the client code and saved to chat files.
179router.get('/', jsonParser, async function (request, response) {178router.get('/', async function (request, response) {
180 try{179 try{
181 if (typeof request.query.file !== 'string' || typeof request.query.type !== 'string') {180 if (typeof request.query.file !== 'string' || typeof request.query.type !== 'string') {
182 return response.sendStatus(400);181 return response.sendStatus(400);
src/endpoints/tokenizers.js+34 -35
@@ -11,7 +11,6 @@ import tiktoken from 'tiktoken';
1111
12import { convertClaudePrompt } from '../prompt-converters.js';12import { convertClaudePrompt } from '../prompt-converters.js';
13import { TEXTGEN_TYPES } from '../constants.js';13import { TEXTGEN_TYPES } from '../constants.js';
14import { jsonParser } from '../express-common.js';
15import { setAdditionalHeaders } from '../additional-headers.js';14import { setAdditionalHeaders } from '../additional-headers.js';
16import { getConfigValue, isValidUrl } from '../util.js';15import { getConfigValue, isValidUrl } from '../util.js';
1716
@@ -689,36 +688,36 @@ function createWebTokenizerDecodingHandler(tokenizer) {
689688
690export const router = express.Router();689export const router = express.Router();
691690
692router.post('/llama/encode', jsonParser, createSentencepieceEncodingHandler(spp_llama));691router.post('/llama/encode', createSentencepieceEncodingHandler(spp_llama));
693router.post('/nerdstash/encode', jsonParser, createSentencepieceEncodingHandler(spp_nerd));692router.post('/nerdstash/encode', createSentencepieceEncodingHandler(spp_nerd));
694router.post('/nerdstash_v2/encode', jsonParser, createSentencepieceEncodingHandler(spp_nerd_v2));693router.post('/nerdstash_v2/encode', createSentencepieceEncodingHandler(spp_nerd_v2));
695router.post('/mistral/encode', jsonParser, createSentencepieceEncodingHandler(spp_mistral));694router.post('/mistral/encode', createSentencepieceEncodingHandler(spp_mistral));
696router.post('/yi/encode', jsonParser, createSentencepieceEncodingHandler(spp_yi));695router.post('/yi/encode', createSentencepieceEncodingHandler(spp_yi));
697router.post('/gemma/encode', jsonParser, createSentencepieceEncodingHandler(spp_gemma));696router.post('/gemma/encode', createSentencepieceEncodingHandler(spp_gemma));
698router.post('/jamba/encode', jsonParser, createSentencepieceEncodingHandler(spp_jamba));697router.post('/jamba/encode', createSentencepieceEncodingHandler(spp_jamba));
699router.post('/gpt2/encode', jsonParser, createTiktokenEncodingHandler('gpt2'));698router.post('/gpt2/encode', createTiktokenEncodingHandler('gpt2'));
700router.post('/claude/encode', jsonParser, createWebTokenizerEncodingHandler(claude_tokenizer));699router.post('/claude/encode', createWebTokenizerEncodingHandler(claude_tokenizer));
701router.post('/llama3/encode', jsonParser, createWebTokenizerEncodingHandler(llama3_tokenizer));700router.post('/llama3/encode', createWebTokenizerEncodingHandler(llama3_tokenizer));
702router.post('/qwen2/encode', jsonParser, createWebTokenizerEncodingHandler(qwen2Tokenizer));701router.post('/qwen2/encode', createWebTokenizerEncodingHandler(qwen2Tokenizer));
703router.post('/command-r/encode', jsonParser, createWebTokenizerEncodingHandler(commandTokenizer));702router.post('/command-r/encode', createWebTokenizerEncodingHandler(commandTokenizer));
704router.post('/nemo/encode', jsonParser, createWebTokenizerEncodingHandler(nemoTokenizer));703router.post('/nemo/encode', createWebTokenizerEncodingHandler(nemoTokenizer));
705router.post('/deepseek/encode', jsonParser, createWebTokenizerEncodingHandler(deepseekTokenizer));704router.post('/deepseek/encode', createWebTokenizerEncodingHandler(deepseekTokenizer));
706router.post('/llama/decode', jsonParser, createSentencepieceDecodingHandler(spp_llama));705router.post('/llama/decode', createSentencepieceDecodingHandler(spp_llama));
707router.post('/nerdstash/decode', jsonParser, createSentencepieceDecodingHandler(spp_nerd));706router.post('/nerdstash/decode', createSentencepieceDecodingHandler(spp_nerd));
708router.post('/nerdstash_v2/decode', jsonParser, createSentencepieceDecodingHandler(spp_nerd_v2));707router.post('/nerdstash_v2/decode', createSentencepieceDecodingHandler(spp_nerd_v2));
709router.post('/mistral/decode', jsonParser, createSentencepieceDecodingHandler(spp_mistral));708router.post('/mistral/decode', createSentencepieceDecodingHandler(spp_mistral));
710router.post('/yi/decode', jsonParser, createSentencepieceDecodingHandler(spp_yi));709router.post('/yi/decode', createSentencepieceDecodingHandler(spp_yi));
711router.post('/gemma/decode', jsonParser, createSentencepieceDecodingHandler(spp_gemma));710router.post('/gemma/decode', createSentencepieceDecodingHandler(spp_gemma));
712router.post('/jamba/decode', jsonParser, createSentencepieceDecodingHandler(spp_jamba));711router.post('/jamba/decode', createSentencepieceDecodingHandler(spp_jamba));
713router.post('/gpt2/decode', jsonParser, createTiktokenDecodingHandler('gpt2'));712router.post('/gpt2/decode', createTiktokenDecodingHandler('gpt2'));
714router.post('/claude/decode', jsonParser, createWebTokenizerDecodingHandler(claude_tokenizer));713router.post('/claude/decode', createWebTokenizerDecodingHandler(claude_tokenizer));
715router.post('/llama3/decode', jsonParser, createWebTokenizerDecodingHandler(llama3_tokenizer));714router.post('/llama3/decode', createWebTokenizerDecodingHandler(llama3_tokenizer));
716router.post('/qwen2/decode', jsonParser, createWebTokenizerDecodingHandler(qwen2Tokenizer));715router.post('/qwen2/decode', createWebTokenizerDecodingHandler(qwen2Tokenizer));
717router.post('/command-r/decode', jsonParser, createWebTokenizerDecodingHandler(commandTokenizer));716router.post('/command-r/decode', createWebTokenizerDecodingHandler(commandTokenizer));
718router.post('/nemo/decode', jsonParser, createWebTokenizerDecodingHandler(nemoTokenizer));717router.post('/nemo/decode', createWebTokenizerDecodingHandler(nemoTokenizer));
719router.post('/deepseek/decode', jsonParser, createWebTokenizerDecodingHandler(deepseekTokenizer));718router.post('/deepseek/decode', createWebTokenizerDecodingHandler(deepseekTokenizer));
720719
721router.post('/openai/encode', jsonParser, async function (req, res) {720router.post('/openai/encode', async function (req, res) {
722 try {721 try {
723 const queryModel = String(req.query.model || '');722 const queryModel = String(req.query.model || '');
724723
@@ -786,7 +785,7 @@ router.post('/openai/encode', jsonParser, async function (req, res) {
786 }785 }
787});786});
788787
789router.post('/openai/decode', jsonParser, async function (req, res) {788router.post('/openai/decode', async function (req, res) {
790 try {789 try {
791 const queryModel = String(req.query.model || '');790 const queryModel = String(req.query.model || '');
792791
@@ -854,7 +853,7 @@ router.post('/openai/decode', jsonParser, async function (req, res) {
854 }853 }
855});854});
856855
857router.post('/openai/count', jsonParser, async function (req, res) {856router.post('/openai/count', async function (req, res) {
858 try {857 try {
859 if (!req.body) return res.sendStatus(400);858 if (!req.body) return res.sendStatus(400);
860859
@@ -968,7 +967,7 @@ router.post('/openai/count', jsonParser, async function (req, res) {
968 }967 }
969});968});
970969
971router.post('/remote/kobold/count', jsonParser, async function (request, response) {970router.post('/remote/kobold/count', async function (request, response) {
972 if (!request.body) {971 if (!request.body) {
973 return response.sendStatus(400);972 return response.sendStatus(400);
974 }973 }
@@ -1002,7 +1001,7 @@ router.post('/remote/kobold/count', jsonParser, async function (request, respons
1002 }1001 }
1003});1002});
10041003
1005router.post('/remote/textgenerationwebui/encode', jsonParser, async function (request, response) {1004router.post('/remote/textgenerationwebui/encode', async function (request, response) {
1006 if (!request.body) {1005 if (!request.body) {
1007 return response.sendStatus(400);1006 return response.sendStatus(400);
1008 }1007 }
src/endpoints/translate.js+8 -9
@@ -8,7 +8,6 @@ import urlJoin from 'url-join';
88
9import { readSecret, SECRET_KEYS } from './secrets.js';9import { readSecret, SECRET_KEYS } from './secrets.js';
10import { getConfigValue, uuidv4 } from '../util.js';10import { getConfigValue, uuidv4 } from '../util.js';
11import { jsonParser } from '../express-common.js';
1211
13const DEEPLX_URL_DEFAULT = 'http://127.0.0.1:1188/translate';12const DEEPLX_URL_DEFAULT = 'http://127.0.0.1:1188/translate';
14const ONERING_URL_DEFAULT = 'http://127.0.0.1:4990/translate';13const ONERING_URL_DEFAULT = 'http://127.0.0.1:4990/translate';
@@ -40,7 +39,7 @@ function decodeBuffer(buffer) {
40 }39 }
41}40}
4241
43router.post('/libre', jsonParser, async (request, response) => {42router.post('/libre', async (request, response) => {
44 try {43 try {
45 const key = readSecret(request.user.directories, SECRET_KEYS.LIBRE);44 const key = readSecret(request.user.directories, SECRET_KEYS.LIBRE);
46 const url = readSecret(request.user.directories, SECRET_KEYS.LIBRE_URL);45 const url = readSecret(request.user.directories, SECRET_KEYS.LIBRE_URL);
@@ -100,7 +99,7 @@ router.post('/libre', jsonParser, async (request, response) => {
100 }99 }
101});100});
102101
103router.post('/google', jsonParser, async (request, response) => {102router.post('/google', async (request, response) => {
104 try {103 try {
105 const text = request.body.text;104 const text = request.body.text;
106 const lang = request.body.lang;105 const lang = request.body.lang;
@@ -133,7 +132,7 @@ router.post('/google', jsonParser, async (request, response) => {
133 }132 }
134});133});
135134
136router.post('/yandex', jsonParser, async (request, response) => {135router.post('/yandex', async (request, response) => {
137 try {136 try {
138 if (request.body.lang === 'pt-PT') {137 if (request.body.lang === 'pt-PT') {
139 request.body.lang = 'pt';138 request.body.lang = 'pt';
@@ -189,7 +188,7 @@ router.post('/yandex', jsonParser, async (request, response) => {
189 }188 }
190});189});
191190
192router.post('/lingva', jsonParser, async (request, response) => {191router.post('/lingva', async (request, response) => {
193 try {192 try {
194 const secretUrl = readSecret(request.user.directories, SECRET_KEYS.LINGVA_URL);193 const secretUrl = readSecret(request.user.directories, SECRET_KEYS.LINGVA_URL);
195 const baseUrl = secretUrl || LINGVA_DEFAULT;194 const baseUrl = secretUrl || LINGVA_DEFAULT;
@@ -233,7 +232,7 @@ router.post('/lingva', jsonParser, async (request, response) => {
233 }232 }
234});233});
235234
236router.post('/deepl', jsonParser, async (request, response) => {235router.post('/deepl', async (request, response) => {
237 try {236 try {
238 const key = readSecret(request.user.directories, SECRET_KEYS.DEEPL);237 const key = readSecret(request.user.directories, SECRET_KEYS.DEEPL);
239238
@@ -295,7 +294,7 @@ router.post('/deepl', jsonParser, async (request, response) => {
295 }294 }
296});295});
297296
298router.post('/onering', jsonParser, async (request, response) => {297router.post('/onering', async (request, response) => {
299 try {298 try {
300 const secretUrl = readSecret(request.user.directories, SECRET_KEYS.ONERING_URL);299 const secretUrl = readSecret(request.user.directories, SECRET_KEYS.ONERING_URL);
301 const url = secretUrl || ONERING_URL_DEFAULT;300 const url = secretUrl || ONERING_URL_DEFAULT;
@@ -352,7 +351,7 @@ router.post('/onering', jsonParser, async (request, response) => {
352 }351 }
353});352});
354353
355router.post('/deeplx', jsonParser, async (request, response) => {354router.post('/deeplx', async (request, response) => {
356 try {355 try {
357 const secretUrl = readSecret(request.user.directories, SECRET_KEYS.DEEPLX_URL);356 const secretUrl = readSecret(request.user.directories, SECRET_KEYS.DEEPLX_URL);
358 const url = secretUrl || DEEPLX_URL_DEFAULT;357 const url = secretUrl || DEEPLX_URL_DEFAULT;
@@ -408,7 +407,7 @@ router.post('/deeplx', jsonParser, async (request, response) => {
408 }407 }
409});408});
410409
411router.post('/bing', jsonParser, async (request, response) => {410router.post('/bing', async (request, response) => {
412 try {411 try {
413 const text = request.body.text;412 const text = request.body.text;
414 let lang = request.body.lang;413 let lang = request.body.lang;
src/endpoints/users-admin.js+8 -9
@@ -3,7 +3,6 @@ import { promises as fsPromises } from 'node:fs';
3import storage from 'node-persist';3import storage from 'node-persist';
4import express from 'express';4import express from 'express';
5import lodash from 'lodash';5import lodash from 'lodash';
6import { jsonParser } from '../express-common.js';
7import { checkForNewContent, CONTENT_TYPES } from './content-manager.js';6import { checkForNewContent, CONTENT_TYPES } from './content-manager.js';
8import {7import {
9 KEY_PREFIX,8 KEY_PREFIX,
@@ -20,7 +19,7 @@ import { DEFAULT_USER } from '../constants.js';
2019
21export const router = express.Router();20export const router = express.Router();
2221
23router.post('/get', requireAdminMiddleware, jsonParser, async (_request, response) => {22router.post('/get', requireAdminMiddleware, async (_request, response) => {
24 try {23 try {
25 /** @type {import('../users.js').User[]} */24 /** @type {import('../users.js').User[]} */
26 const users = await storage.values(x => x.key.startsWith(KEY_PREFIX));25 const users = await storage.values(x => x.key.startsWith(KEY_PREFIX));
@@ -50,7 +49,7 @@ router.post('/get', requireAdminMiddleware, jsonParser, async (_request, respons
50 }49 }
51});50});
5251
53router.post('/disable', requireAdminMiddleware, jsonParser, async (request, response) => {52router.post('/disable', requireAdminMiddleware, async (request, response) => {
54 try {53 try {
55 if (!request.body.handle) {54 if (!request.body.handle) {
56 console.warn('Disable user failed: Missing required fields');55 console.warn('Disable user failed: Missing required fields');
@@ -79,7 +78,7 @@ router.post('/disable', requireAdminMiddleware, jsonParser, async (request, resp
79 }78 }
80});79});
8180
82router.post('/enable', requireAdminMiddleware, jsonParser, async (request, response) => {81router.post('/enable', requireAdminMiddleware, async (request, response) => {
83 try {82 try {
84 if (!request.body.handle) {83 if (!request.body.handle) {
85 console.warn('Enable user failed: Missing required fields');84 console.warn('Enable user failed: Missing required fields');
@@ -103,7 +102,7 @@ router.post('/enable', requireAdminMiddleware, jsonParser, async (request, respo
103 }102 }
104});103});
105104
106router.post('/promote', requireAdminMiddleware, jsonParser, async (request, response) => {105router.post('/promote', requireAdminMiddleware, async (request, response) => {
107 try {106 try {
108 if (!request.body.handle) {107 if (!request.body.handle) {
109 console.warn('Promote user failed: Missing required fields');108 console.warn('Promote user failed: Missing required fields');
@@ -127,7 +126,7 @@ router.post('/promote', requireAdminMiddleware, jsonParser, async (request, resp
127 }126 }
128});127});
129128
130router.post('/demote', requireAdminMiddleware, jsonParser, async (request, response) => {129router.post('/demote', requireAdminMiddleware, async (request, response) => {
131 try {130 try {
132 if (!request.body.handle) {131 if (!request.body.handle) {
133 console.warn('Demote user failed: Missing required fields');132 console.warn('Demote user failed: Missing required fields');
@@ -156,7 +155,7 @@ router.post('/demote', requireAdminMiddleware, jsonParser, async (request, respo
156 }155 }
157});156});
158157
159router.post('/create', requireAdminMiddleware, jsonParser, async (request, response) => {158router.post('/create', requireAdminMiddleware, async (request, response) => {
160 try {159 try {
161 if (!request.body.handle || !request.body.name) {160 if (!request.body.handle || !request.body.name) {
162 console.warn('Create user failed: Missing required fields');161 console.warn('Create user failed: Missing required fields');
@@ -203,7 +202,7 @@ router.post('/create', requireAdminMiddleware, jsonParser, async (request, respo
203 }202 }
204});203});
205204
206router.post('/delete', requireAdminMiddleware, jsonParser, async (request, response) => {205router.post('/delete', requireAdminMiddleware, async (request, response) => {
207 try {206 try {
208 if (!request.body.handle) {207 if (!request.body.handle) {
209 console.warn('Delete user failed: Missing required fields');208 console.warn('Delete user failed: Missing required fields');
@@ -235,7 +234,7 @@ router.post('/delete', requireAdminMiddleware, jsonParser, async (request, respo
235 }234 }
236});235});
237236
238router.post('/slugify', requireAdminMiddleware, jsonParser, async (request, response) => {237router.post('/slugify', requireAdminMiddleware, async (request, response) => {
239 try {238 try {
240 if (!request.body.text) {239 if (!request.body.text) {
241 console.warn('Slugify failed: Missing required fields');240 console.warn('Slugify failed: Missing required fields');
src/endpoints/users-private.js+7 -8
@@ -5,7 +5,6 @@ import crypto from 'node:crypto';
5import storage from 'node-persist';5import storage from 'node-persist';
6import express from 'express';6import express from 'express';
77
8import { jsonParser } from '../express-common.js';
9import { getUserAvatar, toKey, getPasswordHash, getPasswordSalt, createBackupArchive, ensurePublicDirectoriesExist, toAvatarKey } from '../users.js';8import { getUserAvatar, toKey, getPasswordHash, getPasswordSalt, createBackupArchive, ensurePublicDirectoriesExist, toAvatarKey } from '../users.js';
10import { SETTINGS_FILE } from '../constants.js';9import { SETTINGS_FILE } from '../constants.js';
11import { checkForNewContent, CONTENT_TYPES } from './content-manager.js';10import { checkForNewContent, CONTENT_TYPES } from './content-manager.js';
@@ -55,7 +54,7 @@ router.get('/me', async (request, response) => {
55 }54 }
56});55});
5756
58router.post('/change-avatar', jsonParser, async (request, response) => {57router.post('/change-avatar', async (request, response) => {
59 try {58 try {
60 if (!request.body.handle) {59 if (!request.body.handle) {
61 console.warn('Change avatar failed: Missing required fields');60 console.warn('Change avatar failed: Missing required fields');
@@ -90,7 +89,7 @@ router.post('/change-avatar', jsonParser, async (request, response) => {
90 }89 }
91});90});
9291
93router.post('/change-password', jsonParser, async (request, response) => {92router.post('/change-password', async (request, response) => {
94 try {93 try {
95 if (!request.body.handle) {94 if (!request.body.handle) {
96 console.warn('Change password failed: Missing required fields');95 console.warn('Change password failed: Missing required fields');
@@ -137,7 +136,7 @@ router.post('/change-password', jsonParser, async (request, response) => {
137 }136 }
138});137});
139138
140router.post('/backup', jsonParser, async (request, response) => {139router.post('/backup', async (request, response) => {
141 try {140 try {
142 const handle = request.body.handle;141 const handle = request.body.handle;
143142
@@ -158,7 +157,7 @@ router.post('/backup', jsonParser, async (request, response) => {
158 }157 }
159});158});
160159
161router.post('/reset-settings', jsonParser, async (request, response) => {160router.post('/reset-settings', async (request, response) => {
162 try {161 try {
163 const password = request.body.password;162 const password = request.body.password;
164163
@@ -178,7 +177,7 @@ router.post('/reset-settings', jsonParser, async (request, response) => {
178 }177 }
179});178});
180179
181router.post('/change-name', jsonParser, async (request, response) => {180router.post('/change-name', async (request, response) => {
182 try {181 try {
183 if (!request.body.name || !request.body.handle) {182 if (!request.body.name || !request.body.handle) {
184 console.warn('Change name failed: Missing required fields');183 console.warn('Change name failed: Missing required fields');
@@ -208,7 +207,7 @@ router.post('/change-name', jsonParser, async (request, response) => {
208 }207 }
209});208});
210209
211router.post('/reset-step1', jsonParser, async (request, response) => {210router.post('/reset-step1', async (request, response) => {
212 try {211 try {
213 const resetCode = String(crypto.randomInt(1000, 9999));212 const resetCode = String(crypto.randomInt(1000, 9999));
214 console.log();213 console.log();
@@ -222,7 +221,7 @@ router.post('/reset-step1', jsonParser, async (request, response) => {
222 }221 }
223});222});
224223
225router.post('/reset-step2', jsonParser, async (request, response) => {224router.post('/reset-step2', async (request, response) => {
226 try {225 try {
227 if (!request.body.code) {226 if (!request.body.code) {
228 console.warn('Recover step 2 failed: Missing required fields');227 console.warn('Recover step 2 failed: Missing required fields');
src/endpoints/users-public.js+4 -4
@@ -3,7 +3,7 @@ import crypto from 'node:crypto';
3import storage from 'node-persist';3import storage from 'node-persist';
4import express from 'express';4import express from 'express';
5import { RateLimiterMemory, RateLimiterRes } from 'rate-limiter-flexible';5import { RateLimiterMemory, RateLimiterRes } from 'rate-limiter-flexible';
6import { jsonParser, getIpFromRequest, getRealIpFromHeader } from '../express-common.js';6import { getIpFromRequest, getRealIpFromHeader } from '../express-common.js';
7import { color, Cache, getConfigValue } from '../util.js';7import { color, Cache, getConfigValue } from '../util.js';
8import { KEY_PREFIX, getUserAvatar, toKey, getPasswordHash, getPasswordSalt } from '../users.js';8import { KEY_PREFIX, getUserAvatar, toKey, getPasswordHash, getPasswordSalt } from '../users.js';
99
@@ -56,7 +56,7 @@ router.post('/list', async (_request, response) => {
56 }56 }
57});57});
5858
59router.post('/login', jsonParser, async (request, response) => {59router.post('/login', async (request, response) => {
60 try {60 try {
61 if (!request.body.handle) {61 if (!request.body.handle) {
62 console.warn('Login failed: Missing required fields');62 console.warn('Login failed: Missing required fields');
@@ -104,7 +104,7 @@ router.post('/login', jsonParser, async (request, response) => {
104 }104 }
105});105});
106106
107router.post('/recover-step1', jsonParser, async (request, response) => {107router.post('/recover-step1', async (request, response) => {
108 try {108 try {
109 if (!request.body.handle) {109 if (!request.body.handle) {
110 console.warn('Recover step 1 failed: Missing required fields');110 console.warn('Recover step 1 failed: Missing required fields');
@@ -144,7 +144,7 @@ router.post('/recover-step1', jsonParser, async (request, response) => {
144 }144 }
145});145});
146146
147router.post('/recover-step2', jsonParser, async (request, response) => {147router.post('/recover-step2', async (request, response) => {
148 try {148 try {
149 if (!request.body.handle || !request.body.code) {149 if (!request.body.handle || !request.body.code) {
150 console.warn('Recover step 2 failed: Missing required fields');150 console.warn('Recover step 2 failed: Missing required fields');
src/endpoints/vectors.js+7 -8
@@ -5,7 +5,6 @@ import vectra from 'vectra';
5import express from 'express';5import express from 'express';
6import sanitize from 'sanitize-filename';6import sanitize from 'sanitize-filename';
77
8import { jsonParser } from '../express-common.js';
9import { getConfigValue } from '../util.js';8import { getConfigValue } from '../util.js';
109
11import { getNomicAIBatchVector, getNomicAIVector } from '../vectors/nomicai-vectors.js';10import { getNomicAIBatchVector, getNomicAIVector } from '../vectors/nomicai-vectors.js';
@@ -384,7 +383,7 @@ async function regenerateCorruptedIndexErrorHandler(req, res, error) {
384383
385export const router = express.Router();384export const router = express.Router();
386385
387router.post('/query', jsonParser, async (req, res) => {386router.post('/query', async (req, res) => {
388 try {387 try {
389 if (!req.body.collectionId || !req.body.searchText) {388 if (!req.body.collectionId || !req.body.searchText) {
390 return res.sendStatus(400);389 return res.sendStatus(400);
@@ -404,7 +403,7 @@ router.post('/query', jsonParser, async (req, res) => {
404 }403 }
405});404});
406405
407router.post('/query-multi', jsonParser, async (req, res) => {406router.post('/query-multi', async (req, res) => {
408 try {407 try {
409 if (!Array.isArray(req.body.collectionIds) || !req.body.searchText) {408 if (!Array.isArray(req.body.collectionIds) || !req.body.searchText) {
410 return res.sendStatus(400);409 return res.sendStatus(400);
@@ -424,7 +423,7 @@ router.post('/query-multi', jsonParser, async (req, res) => {
424 }423 }
425});424});
426425
427router.post('/insert', jsonParser, async (req, res) => {426router.post('/insert', async (req, res) => {
428 try {427 try {
429 if (!Array.isArray(req.body.items) || !req.body.collectionId) {428 if (!Array.isArray(req.body.items) || !req.body.collectionId) {
430 return res.sendStatus(400);429 return res.sendStatus(400);
@@ -442,7 +441,7 @@ router.post('/insert', jsonParser, async (req, res) => {
442 }441 }
443});442});
444443
445router.post('/list', jsonParser, async (req, res) => {444router.post('/list', async (req, res) => {
446 try {445 try {
447 if (!req.body.collectionId) {446 if (!req.body.collectionId) {
448 return res.sendStatus(400);447 return res.sendStatus(400);
@@ -459,7 +458,7 @@ router.post('/list', jsonParser, async (req, res) => {
459 }458 }
460});459});
461460
462router.post('/delete', jsonParser, async (req, res) => {461router.post('/delete', async (req, res) => {
463 try {462 try {
464 if (!Array.isArray(req.body.hashes) || !req.body.collectionId) {463 if (!Array.isArray(req.body.hashes) || !req.body.collectionId) {
465 return res.sendStatus(400);464 return res.sendStatus(400);
@@ -477,7 +476,7 @@ router.post('/delete', jsonParser, async (req, res) => {
477 }476 }
478});477});
479478
480router.post('/purge-all', jsonParser, async (req, res) => {479router.post('/purge-all', async (req, res) => {
481 try {480 try {
482 for (const source of SOURCES) {481 for (const source of SOURCES) {
483 const sourcePath = path.join(req.user.directories.vectors, sanitize(source));482 const sourcePath = path.join(req.user.directories.vectors, sanitize(source));
@@ -495,7 +494,7 @@ router.post('/purge-all', jsonParser, async (req, res) => {
495 }494 }
496});495});
497496
498router.post('/purge', jsonParser, async (req, res) => {497router.post('/purge', async (req, res) => {
499 try {498 try {
500 if (!req.body.collectionId) {499 if (!req.body.collectionId) {
501 return res.sendStatus(400);500 return res.sendStatus(400);
src/endpoints/worldinfo.js+4 -6
@@ -5,8 +5,6 @@ import express from 'express';
5import sanitize from 'sanitize-filename';5import sanitize from 'sanitize-filename';
6import { sync as writeFileAtomicSync } from 'write-file-atomic';6import { sync as writeFileAtomicSync } from 'write-file-atomic';
77
8import { jsonParser, urlencodedParser } from '../express-common.js';
9
10/**8/**
11 * Reads a World Info file and returns its contents9 * Reads a World Info file and returns its contents
12 * @param {import('../users.js').UserDirectoryList} directories User directories10 * @param {import('../users.js').UserDirectoryList} directories User directories
@@ -36,7 +34,7 @@ export function readWorldInfoFile(directories, worldInfoName, allowDummy) {
3634
37export const router = express.Router();35export const router = express.Router();
3836
39router.post('/get', jsonParser, (request, response) => {37router.post('/get', (request, response) => {
40 if (!request.body?.name) {38 if (!request.body?.name) {
41 return response.sendStatus(400);39 return response.sendStatus(400);
42 }40 }
@@ -46,7 +44,7 @@ router.post('/get', jsonParser, (request, response) => {
46 return response.send(file);44 return response.send(file);
47});45});
4846
49router.post('/delete', jsonParser, (request, response) => {47router.post('/delete', (request, response) => {
50 if (!request.body?.name) {48 if (!request.body?.name) {
51 return response.sendStatus(400);49 return response.sendStatus(400);
52 }50 }
@@ -64,7 +62,7 @@ router.post('/delete', jsonParser, (request, response) => {
64 return response.sendStatus(200);62 return response.sendStatus(200);
65});63});
6664
67router.post('/import', urlencodedParser, (request, response) => {65router.post('/import', (request, response) => {
68 if (!request.file) return response.sendStatus(400);66 if (!request.file) return response.sendStatus(400);
6967
70 const filename = `${path.parse(sanitize(request.file.originalname)).name}.json`;68 const filename = `${path.parse(sanitize(request.file.originalname)).name}.json`;
@@ -99,7 +97,7 @@ router.post('/import', urlencodedParser, (request, response) => {
99 return response.send({ name: worldName });97 return response.send({ name: worldName });
100});98});
10199
102router.post('/edit', jsonParser, (request, response) => {100router.post('/edit', (request, response) => {
103 if (!request.body) {101 if (!request.body) {
104 return response.sendStatus(400);102 return response.sendStatus(400);
105 }103 }
src/express-common.js+5 -4
@@ -1,9 +1,10 @@
1import express from 'express';
2import ipaddr from 'ipaddr.js';1import ipaddr from 'ipaddr.js';
32
4// Instantiate parser middleware here with application-level size limits3const noopMiddleware = (_req, _res, next) => next();
5export const jsonParser = express.json({ limit: '200mb' });4/** @deprecated Do not use. A global middleware is provided at the application level. */
6export const urlencodedParser = express.urlencoded({ extended: true, limit: '200mb' });5export const jsonParser = noopMiddleware;
6/** @deprecated Do not use. A global middleware is provided at the application level. */
7export const urlencodedParser = noopMiddleware;
78
8/**9/**
9 * Gets the IP address of the client from the request object.10 * Gets the IP address of the client from the request object.