Unset chat field on import/export Closes #3781

76c59cbc52c2569e4c4bf3f090dc224fa213735e

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

2 files changed, +32 -9Ignore whitespace
src/endpoints/characters.js+15 -9
@@ -15,9 +15,9 @@ import storage from 'node-persist';
1515
16import { AVATAR_WIDTH, AVATAR_HEIGHT } from '../constants.js';16import { AVATAR_WIDTH, AVATAR_HEIGHT } from '../constants.js';
17import { default as validateAvatarUrlMiddleware, getFileNameValidationFunction } from '../middleware/validateFileName.js';17import { default as validateAvatarUrlMiddleware, getFileNameValidationFunction } from '../middleware/validateFileName.js';
18import { deepMerge, humanizedISO8601DateTime, tryParse, extractFileFromZipBuffer, MemoryLimitedMap, getConfigValue } from '../util.js';18import { deepMerge, humanizedISO8601DateTime, tryParse, extractFileFromZipBuffer, MemoryLimitedMap, getConfigValue, mutateJsonString } from '../util.js';
19import { TavernCardValidator } from '../validator/TavernCardValidator.js';19import { TavernCardValidator } from '../validator/TavernCardValidator.js';
20import { parse, write } from '../character-card-parser.js';20import { parse, read, write } from '../character-card-parser.js';
21import { readWorldInfoFile } from './worldinfo.js';21import { readWorldInfoFile } from './worldinfo.js';
22import { invalidateThumbnail } from './thumbnails.js';22import { invalidateThumbnail } from './thumbnails.js';
23import { importRisuSprites } from './sprites.js';23import { importRisuSprites } from './sprites.js';
@@ -490,10 +490,13 @@ function convertToV2(char, directories) {
490 return result;490 return result;
491}491}
492492
493493/**
494function unsetFavFlag(char) {494 * Removes fields that are not meant to be shared.
495 */
496function unsetPrivateFields(char) {
495 _.set(char, 'fav', false);497 _.set(char, 'fav', false);
496 _.set(char, 'data.extensions.fav', false);498 _.set(char, 'data.extensions.fav', false);
499 _.unset(char, 'chat');
497}500}
498501
499function readFromV2(char) {502function readFromV2(char) {
@@ -779,7 +782,7 @@ async function importFromCharX(uploadPath, { request }, preservedFileName) {
779 }782 }
780 }783 }
781784
782 unsetFavFlag(card);785 unsetPrivateFields(card);
783 card['create_date'] = humanizedISO8601DateTime();786 card['create_date'] = humanizedISO8601DateTime();
784 card.name = sanitize(card.name);787 card.name = sanitize(card.name);
785 const fileName = preservedFileName || getPngName(card.name, request.user.directories);788 const fileName = preservedFileName || getPngName(card.name, request.user.directories);
@@ -803,7 +806,7 @@ async function importFromJson(uploadPath, { request }, preservedFileName) {
803 if (jsonData.spec !== undefined) {806 if (jsonData.spec !== undefined) {
804 console.info(`Importing from ${jsonData.spec} json`);807 console.info(`Importing from ${jsonData.spec} json`);
805 importRisuSprites(request.user.directories, jsonData);808 importRisuSprites(request.user.directories, jsonData);
806 unsetFavFlag(jsonData);809 unsetPrivateFields(jsonData);
807 jsonData = readFromV2(jsonData);810 jsonData = readFromV2(jsonData);
808 jsonData['create_date'] = humanizedISO8601DateTime();811 jsonData['create_date'] = humanizedISO8601DateTime();
809 const pngName = preservedFileName || getPngName(jsonData.data?.name || jsonData.name, request.user.directories);812 const pngName = preservedFileName || getPngName(jsonData.data?.name || jsonData.name, request.user.directories);
@@ -886,7 +889,7 @@ async function importFromPng(uploadPath, { request }, preservedFileName) {
886 if (jsonData.spec !== undefined) {889 if (jsonData.spec !== undefined) {
887 console.info(`Found a ${jsonData.spec} character file.`);890 console.info(`Found a ${jsonData.spec} character file.`);
888 importRisuSprites(request.user.directories, jsonData);891 importRisuSprites(request.user.directories, jsonData);
889 unsetFavFlag(jsonData);892 unsetPrivateFields(jsonData);
890 jsonData = readFromV2(jsonData);893 jsonData = readFromV2(jsonData);
891 jsonData['create_date'] = humanizedISO8601DateTime();894 jsonData['create_date'] = humanizedISO8601DateTime();
892 const char = JSON.stringify(jsonData);895 const char = JSON.stringify(jsonData);
@@ -1423,11 +1426,14 @@ router.post('/export', validateAvatarUrlMiddleware, async function (request, res
14231426
1424 switch (request.body.format) {1427 switch (request.body.format) {
1425 case 'png': {1428 case 'png': {
1426 const fileContent = await fsPromises.readFile(filename);1429 const rawBuffer = await fsPromises.readFile(filename);
1430 const rawData = read(rawBuffer);
1431 const mutatedData = mutateJsonString(rawData, unsetPrivateFields);
1432 const mutatedBuffer = write(rawBuffer, mutatedData);
1427 const contentType = mime.lookup(filename) || 'image/png';1433 const contentType = mime.lookup(filename) || 'image/png';
1428 response.setHeader('Content-Type', contentType);1434 response.setHeader('Content-Type', contentType);
1429 response.setHeader('Content-Disposition', `attachment; filename="${encodeURI(path.basename(filename))}"`);1435 response.setHeader('Content-Disposition', `attachment; filename="${encodeURI(path.basename(filename))}"`);
1430 return response.send(fileContent);1436 return response.send(mutatedBuffer);
1431 }1437 }
1432 case 'json': {1438 case 'json': {
1433 try {1439 try {
src/util.js+17 -0
@@ -1054,3 +1054,20 @@ export function setWindowTitle(title) {
1054 process.stdout.write(`\x1b]2;${title}\x1b\x5c`);1054 process.stdout.write(`\x1b]2;${title}\x1b\x5c`);
1055 }1055 }
1056}1056}
1057
1058/**
1059 * Parses a JSON string and applies a mutation function to the parsed object.
1060 * @param {string} jsonString JSON string to parse
1061 * @param {function(any): void} mutation Mutation function to apply to the parsed JSON object
1062 * @returns {string} Mutated JSON string
1063 */
1064export function mutateJsonString(jsonString, mutation) {
1065 try {
1066 const json = JSON.parse(jsonString);
1067 mutation(json);
1068 return JSON.stringify(json);
1069 } catch (error) {
1070 console.error('Error parsing or mutating JSON:', error);
1071 return jsonString;
1072 }
1073}