diff --git a/src/endpoints/characters.js b/src/endpoints/characters.js index 2f71021ad..e7f1a266e 100644 --- a/src/endpoints/characters.js +++ b/src/endpoints/characters.js @@ -15,9 +15,9 @@ import storage from 'node-persist'; import { AVATAR_WIDTH, AVATAR_HEIGHT } from '../constants.js'; import { default as validateAvatarUrlMiddleware, getFileNameValidationFunction } from '../middleware/validateFileName.js'; -import { deepMerge, humanizedISO8601DateTime, tryParse, extractFileFromZipBuffer, MemoryLimitedMap, getConfigValue } from '../util.js'; +import { deepMerge, humanizedISO8601DateTime, tryParse, extractFileFromZipBuffer, MemoryLimitedMap, getConfigValue, mutateJsonString } from '../util.js'; import { TavernCardValidator } from '../validator/TavernCardValidator.js'; -import { parse, write } from '../character-card-parser.js'; +import { parse, read, write } from '../character-card-parser.js'; import { readWorldInfoFile } from './worldinfo.js'; import { invalidateThumbnail } from './thumbnails.js'; import { importRisuSprites } from './sprites.js'; @@ -490,10 +490,13 @@ function convertToV2(char, directories) { return result; } - -function unsetFavFlag(char) { +/** + * Removes fields that are not meant to be shared. + */ +function unsetPrivateFields(char) { _.set(char, 'fav', false); _.set(char, 'data.extensions.fav', false); + _.unset(char, 'chat'); } function readFromV2(char) { @@ -779,7 +782,7 @@ async function importFromCharX(uploadPath, { request }, preservedFileName) { } } - unsetFavFlag(card); + unsetPrivateFields(card); card['create_date'] = humanizedISO8601DateTime(); card.name = sanitize(card.name); const fileName = preservedFileName || getPngName(card.name, request.user.directories); @@ -803,7 +806,7 @@ async function importFromJson(uploadPath, { request }, preservedFileName) { if (jsonData.spec !== undefined) { console.info(`Importing from ${jsonData.spec} json`); importRisuSprites(request.user.directories, jsonData); - unsetFavFlag(jsonData); + unsetPrivateFields(jsonData); jsonData = readFromV2(jsonData); jsonData['create_date'] = humanizedISO8601DateTime(); const pngName = preservedFileName || getPngName(jsonData.data?.name || jsonData.name, request.user.directories); @@ -886,7 +889,7 @@ async function importFromPng(uploadPath, { request }, preservedFileName) { if (jsonData.spec !== undefined) { console.info(`Found a ${jsonData.spec} character file.`); importRisuSprites(request.user.directories, jsonData); - unsetFavFlag(jsonData); + unsetPrivateFields(jsonData); jsonData = readFromV2(jsonData); jsonData['create_date'] = humanizedISO8601DateTime(); const char = JSON.stringify(jsonData); @@ -1423,11 +1426,14 @@ router.post('/export', validateAvatarUrlMiddleware, async function (request, res switch (request.body.format) { case 'png': { - const fileContent = await fsPromises.readFile(filename); + const rawBuffer = await fsPromises.readFile(filename); + const rawData = read(rawBuffer); + const mutatedData = mutateJsonString(rawData, unsetPrivateFields); + const mutatedBuffer = write(rawBuffer, mutatedData); const contentType = mime.lookup(filename) || 'image/png'; response.setHeader('Content-Type', contentType); response.setHeader('Content-Disposition', `attachment; filename="${encodeURI(path.basename(filename))}"`); - return response.send(fileContent); + return response.send(mutatedBuffer); } case 'json': { try { diff --git a/src/util.js b/src/util.js index 1dec2b466..ec94ceb1a 100644 --- a/src/util.js +++ b/src/util.js @@ -1054,3 +1054,20 @@ export function setWindowTitle(title) { process.stdout.write(`\x1b]2;${title}\x1b\x5c`); } } + +/** + * Parses a JSON string and applies a mutation function to the parsed object. + * @param {string} jsonString JSON string to parse + * @param {function(any): void} mutation Mutation function to apply to the parsed JSON object + * @returns {string} Mutated JSON string + */ +export function mutateJsonString(jsonString, mutation) { + try { + const json = JSON.parse(jsonString); + mutation(json); + return JSON.stringify(json); + } catch (error) { + console.error('Error parsing or mutating JSON:', error); + return jsonString; + } +}