jschan - Anonymous imageboard software. Classic look, modern features and feel. Works without JavaScript and supports Tor, I2P, Lokinet, etc.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

343 lines
7.7 KiB

'use strict';
const { Boards, Posts, Accounts } = require(__dirname+'/../../db/')
, dynamicResponse = require(__dirname+'/../../helpers/dynamic.js')
, uploadDirectory = require(__dirname+'/../../helpers/files/uploadDirectory.js')
, buildQueue = require(__dirname+'/../../queue.js')
, cache = require(__dirname+'/../../redis.js')
, { remove } = require('fs-extra');
module.exports = async (req, res, next) => {
const promises = [];
const oldSettings = await cache.get('globalsettings');
const newSettings = {
//todo: holy fuck this is gonna be too much boilerplate, not like per-board settings wasnt too much already (^:
//todo: make massive fucking template update for expanded global settings page
//idea: for permissions level and stuff, we can show the name as "Admin" and send the value as perm level number
secureCookies: true,
refererCheck: true,
allowedHosts: [],
countryCodeHeader: 'x-country-code',
ipHeader: 'x-real-ip',
meta: {
siteName: 'fatchan',
url: 'https://fatchan.org'
},
captchaOptions: {
type: 'grid',
generateLimit: 250,
google: {
siteKey: 'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz',
secretKey: 'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz'
},
hcaptcha: {
siteKey: 'zzzz',
secretKey: 'xxxxxxxxxxxxxxxx'
},
grid: {
size: 4,
imageSize: 120,
iconYOffset: 15,
},
numDistorts: {
min: 2,
max: 3
},
distortion: 7,
},
dnsbl: {
enabled: false,
blacklists: ['tor.dan.me.uk', 'zen.spamhaus.org'],
cacheTime: 3600
},
disableAnonymizerFilePosting: false,
statsCountAnonymizers: true,
floodTimers: {
sameContentSameIp: 120000,
sameContentAnyIp: 30000,
anyContentSameIp: 5000,
},
blockBypass: {
enabled: true,
forceAnonymizers: true,
expireAfterUses: 50,
expireAfterTime: 86400000,
bypassDnsbl: false,
},
ipHashPermLevel: 0,
deleteBoardPermLevel: 2,
pruneImmediately: true,
hashImages: false,
rateLimitCost: {
captcha: 11,
boardSettings: 30,
editPost: 30,
},
overboardLimit: 20,
overboardCatalogLimit: 50,
cacheTemplates: true,
debugLogs: true,
lockWait: 3000,
pruneModlogs: 30,
pruneIps: false,
enableWebring: true,
enableUserBoardCreation: false,
enableUserAccountCreation: true,
thumbExtension: '.jpg',
animatedGifThumbnails: false,
audioThumbnails: true,
ffmpegGifThumbnails: true,
thumbSize: 250,
videoThumbPercentage: 5,
otherMimeTypes: [
'text/plain',
'application/pdf',
'application/x-sid',
],
checkRealMimeTypes: false,
allowMimeNoMatch: false,
defaultBanDuration: 31536000000,
quoteLimit: 25,
strictFiltering: true,
previewReplies: 5,
stickyPreviewReplies: 5,
early404Fraction: 3,
early404Replies: 5,
maxRecentNews: 5,
filterFileNames: false,
spaceFileNameReplacement: '_',
highlightOptions: {
languageSubset: [
'javascript',
'typescript',
'perl',
'js',
'c++',
'c',
'java',
'kotlin',
'php',
'h',
'csharp',
'bash',
'sh',
'zsh',
'python',
'ruby',
'css',
'html',
'json',
'golang',
'rust'
],
threshold: 5
},
themes: [],
codeThemes: [],
globalLimits: {
threadLimit: {
min: 10,
max: 200
},
replyLimit: {
min: 10,
max: 1000
},
bumpLimit: {
min: 10,
max: 1000
},
postFiles: {
max: 5
},
postFilesSize: {
max: 21023948
},
bannerFiles: {
width: 600,
height: 600,
forceAspectRatio: false,
max: 10,
total: 100,
},
bannerFilesSize: {
max: 10485760
},
fieldLength: {
name: 100,
email: 100,
subject: 100,
postpassword: 100,
message: 20000,
report_reason: 100,
ban_reason: 100,
log_message: 100,
uri: 50,
boardname: 50,
description: 100,
},
multiInputs: {
posts: {
anon: 20,
staff: 100,
},
},
customCss: {
enabled: true,
max: 10000,
strict: true,
filters: [
'@',
'url(',
]
},
customPages: {
max: 5,
maxLength: 10000,
}
},
frontendScriptDefault: {
embedsEnabled: true,
heightUnlimit: false,
hideRecursive: true,
crispImages: false,
hideThumbnails: false,
nonColorIds: false,
alwaysShowSpoilers: false,
hidePostStubs: false,
smoothScrolling: true,
defaultVolume: 100,
loop: true,
imageLoadingBars: true,
live: true,
scrollToPosts: false,
localTime: true,
hour24Time: false,
relativeTime: true,
notificationsEnabled: false,
notificationsYousOnly: true,
showYous: true,
},
boardDefaults: {
theme: 'clear',
codeTheme: 'ir-black',
sfw: false,
lockMode: 0,
fileR9KMode: 0,
messageR9KMode: 0,
unlistedLocal: false,
unlistedWebring: false,
captchaMode: 0,
tphTrigger: 10,
pphTrigger: 50,
tphTriggerAction: 1,
pphTriggerAction: 2,
captchaReset: 0,
lockReset: 0,
forceAnon: false,
sageOnlyEmail: false,
early404: true,
ids: false,
flags: false,
userPostDelete: true,
userPostSpoiler: true,
userPostUnlink: true,
threadLimit: 200,
replyLimit: 700,
bumpLimit: 500,
maxFiles: 5,
forceReplyMessage: false,
forceReplyFile: false,
forceThreadMessage: false,
forceThreadFile: false,
forceThreadSubject: false,
disableReplySubject: false,
minThreadMessageLength: 0,
minReplyMessageLength: 0,
maxThreadMessageLength: 20000,
maxReplyMessageLength: 20000,
defaultName: 'Anon',
customCSS: null,
blockedCountries: [],
disableAnonymizerFilePosting: false,
filters: [],
filterMode: 0,
filterBanDuration: 0,
strictFiltering: false,
announcement: {
raw: null,
markdown: null
},
allowedFileTypes: {
animatedImage: true,
image: true,
video: true,
audio: true,
other: false
}
},
'filters': req.body.filters !== null ? req.body.filters.split(/\r?\n/).filter(n => n) : oldSettings.filters,
'filterMode': typeof req.body.filter_mode === 'number' && req.body.filter_mode !== oldSettings.filterMode ? req.body.filter_mode : oldSettings.filterMode,
'filterBanDuration': typeof req.body.ban_duration === 'number' && req.body.ban_duration !== oldSettings.filterBanDuration ? req.body.ban_duration : oldSettings.filterBanDuration,
};
cache.set('globalsettings', newSettings);
let rebuildThreads = false
, rebuildBoard = false
, rebuildCatalog = false;
/*
//todo: implement removing pages/rebuilding for all affected boards i.e. query for ones with settings.catchaMode < newSettings.captchaMode
if (newSettings.captchaMode > oldSettings.captchaMode) {
rebuildBoard = true;
rebuildCatalog = true;
if (newSettings.captchaMode == 2) {
rebuildThreads = true; //thread captcha enabled, removes threads
}
const affectedBoards = //query here
for (let i = 0; i < affectedBoards.length; i++) {
const board = affectedBoards[i];
if (rebuildThreads) {
promises.push(remove(`${uploadDirectory}/html/${board._id}/thread/`));
}
if (rebuildBoard) {
buildQueue.push({
'task': 'buildBoardMultiple',
'options': {
board,
'startpage': 1,
'endpage': null //no endpage will use whatver maxpage of board is
}
});
}
if (rebuildCatalog) {
buildQueue.push({
'task': 'buildCatalog',
'options': {
board,
}
});
}
}
}
*/
//finish the promises in parallel e.g. removing files
if (promises.length > 0) {
await Promise.all(promises);
}
//publish to redis so running processes get updated config
cache.redisPublisher.publish('config', 'TODO: put the full config object here, so no need to query db on all instances');
return dynamicResponse(req, res, 200, 'message', {
'title': 'Success',
'message': 'Updated settings.',
'redirect': '/globalmanage/settings.html'
});
}