change return of getfilterstrings to object and destructure

indiachan-spamvector
Thomas Lynch 2 years ago
parent 3993b66116
commit ec5eb65aa7
Signed by: fatchan
GPG Key ID: 112884AA57DF40B1
  1. 4
      lib/post/getfilterstrings.js
  2. 20
      models/forms/editpost.js
  3. 66
      models/forms/makepost.js

@ -20,7 +20,7 @@ module.exports = (req, res, strict=false) => {
strictCombinedString += combinedString.replace(/[^a-zA-Z0-9.-]+/gm, ''); strictCombinedString += combinedString.replace(/[^a-zA-Z0-9.-]+/gm, '');
//urlendoded characters in URLs replaced (todo: remove this if/when the url regex gets updated to no longer match these) //urlendoded characters in URLs replaced (todo: remove this if/when the url regex gets updated to no longer match these)
strictCombinedString += combinedString.split(/(\%[^\%]+)/).map(part => { strictCombinedString += combinedString.split(/(%[^%]+)/).map(part => {
try { try {
return decodeURIComponent(part); return decodeURIComponent(part);
} catch(e) { } catch(e) {
@ -30,6 +30,6 @@ module.exports = (req, res, strict=false) => {
} }
return [combinedString, strictCombinedString]; return { combinedString, strictCombinedString };
}; };

@ -1,6 +1,6 @@
'use strict'; 'use strict';
const { Posts, Bans, Modlogs } = require(__dirname+'/../../db/') const { Posts, Modlogs } = require(__dirname+'/../../db/')
, Permissions = require(__dirname+'/../../lib/permission/permissions.js') , Permissions = require(__dirname+'/../../lib/permission/permissions.js')
, { createHash } = require('crypto') , { createHash } = require('crypto')
, Mongo = require(__dirname+'/../../db/db.js') , Mongo = require(__dirname+'/../../db/db.js')
@ -12,10 +12,9 @@ const { Posts, Bans, Modlogs } = require(__dirname+'/../../db/')
, config = require(__dirname+'/../../lib/misc/config.js') , config = require(__dirname+'/../../lib/misc/config.js')
, buildQueue = require(__dirname+'/../../lib/build/queue.js') , buildQueue = require(__dirname+'/../../lib/build/queue.js')
, dynamicResponse = require(__dirname+'/../../lib/misc/dynamic.js') , dynamicResponse = require(__dirname+'/../../lib/misc/dynamic.js')
, { buildThread } = require(__dirname+'/../../lib/build/tasks.js') , { buildThread } = require(__dirname+'/../../lib/build/tasks.js');
, { remove } = require('fs-extra');
module.exports = async (req, res, next) => { module.exports = async (req, res) => {
/* /*
todo: handle some more situations todo: handle some more situations
@ -33,10 +32,9 @@ todo: handle some more situations
//only global filters are checked, because anybody who could edit bypasses board filters //only global filters are checked, because anybody who could edit bypasses board filters
const { filters, filterMode, filterBanDuration } = config.get; const { filters, filterMode, filterBanDuration } = config.get;
if (filters.length > 0 && filterMode > 0) { if (filters.length > 0 && filterMode > 0) {
let hitGlobalFilter = false let hitGlobalFilter = false;
, ban; const { strictCombinedString } = getFilterStrings(req, res, strictFiltering);
const [combinedString, strictCombinedString] = getFilterStrings(req, res, strictFiltering); hitGlobalFilter = filters.some(filter => { return strictCombinedString.includes(filter.toLowerCase()); });
hitGlobalFilter = filters.some(filter => { return strictCombinedString.includes(filter.toLowerCase()) });
//block/ban edit //block/ban edit
if (hitGlobalFilter) { if (hitGlobalFilter) {
return filterActions(req, res, hitGlobalFilter, 0, filterMode, return filterActions(req, res, hitGlobalFilter, 0, filterMode,
@ -97,7 +95,7 @@ todo: handle some more situations
} }
//update the post //update the post
const postId = await Posts.db.updateOne({ await Posts.db.updateOne({
board: req.body.board, board: req.body.board,
postId: post.postId postId: post.postId
}, { }, {
@ -180,7 +178,7 @@ todo: handle some more situations
}).sort({ }).sort({
'postId': -1 'postId': -1
}).limit(previewReplies).toArray(); }).limit(previewReplies).toArray();
postInPreviewPosts = threadPreviewPosts.some(p => p.postId <= post.postId) postInPreviewPosts = threadPreviewPosts.some(p => p.postId <= post.postId);
} }
if (post.thread === null || postInPreviewPosts) { if (post.thread === null || postInPreviewPosts) {
@ -205,4 +203,4 @@ todo: handle some more situations
}); });
} }
} };

@ -1,7 +1,6 @@
'use strict'; 'use strict';
const path = require('path') const { createHash, randomBytes } = require('crypto')
, { createHash, randomBytes } = require('crypto')
, randomBytesAsync = require('util').promisify(randomBytes) , randomBytesAsync = require('util').promisify(randomBytes)
, { remove, emptyDir, pathExists, stat: fsStat } = require('fs-extra') , { remove, emptyDir, pathExists, stat: fsStat } = require('fs-extra')
, uploadDirectory = require(__dirname+'/../../lib/file/uploaddirectory.js') , uploadDirectory = require(__dirname+'/../../lib/file/uploaddirectory.js')
@ -34,7 +33,7 @@ const path = require('path')
, dynamicResponse = require(__dirname+'/../../lib/misc/dynamic.js') , dynamicResponse = require(__dirname+'/../../lib/misc/dynamic.js')
, { buildThread } = require(__dirname+'/../../lib/build/tasks.js'); , { buildThread } = require(__dirname+'/../../lib/build/tasks.js');
module.exports = async (req, res, next) => { module.exports = async (req, res) => {
const { filterBanAppealable, checkRealMimeTypes, thumbSize, thumbExtension, videoThumbPercentage, const { filterBanAppealable, checkRealMimeTypes, thumbSize, thumbExtension, videoThumbPercentage,
strictFiltering, animatedGifThumbnails, audioThumbnails, dontStoreRawIps } = config.get; strictFiltering, animatedGifThumbnails, audioThumbnails, dontStoreRawIps } = config.get;
@ -42,7 +41,7 @@ module.exports = async (req, res, next) => {
//spam/flood check //spam/flood check
const flood = await spamCheck(req, res); const flood = await spamCheck(req, res);
if (flood) { if (flood) {
deleteTempFiles(req).catch(e => console.error); deleteTempFiles(req).catch(console.error);
return dynamicResponse(req, res, 429, 'message', { return dynamicResponse(req, res, 429, 'message', {
'title': 'Flood detected', 'title': 'Flood detected',
'message': 'Please wait before making another post, or a post similar to another user', 'message': 'Please wait before making another post, or a post similar to another user',
@ -51,18 +50,18 @@ module.exports = async (req, res, next) => {
} }
// check if this is responding to an existing thread // check if this is responding to an existing thread
let redirect = `/${req.params.board}/` let redirect = `/${req.params.board}/`;
let salt = null; let salt = null;
let thread = null; let thread = null;
const isStaffOrGlobal = res.locals.permissions.hasAny(Permissions.MANAGE_GLOBAL_GENERAL, Permissions.MANAGE_BOARD_GENERAL); const isStaffOrGlobal = res.locals.permissions.hasAny(Permissions.MANAGE_GLOBAL_GENERAL, Permissions.MANAGE_BOARD_GENERAL);
const { filterBanDuration, filterMode, filters, blockedCountries, threadLimit, ids, userPostSpoiler, const { filterBanDuration, filterMode, filters, blockedCountries, threadLimit, ids, userPostSpoiler,
lockReset, captchaReset, pphTrigger, tphTrigger, tphTriggerAction, pphTriggerAction, pphTrigger, tphTrigger, tphTriggerAction, pphTriggerAction,
sageOnlyEmail, forceAnon, replyLimit, disableReplySubject, sageOnlyEmail, forceAnon, replyLimit, disableReplySubject,
captchaMode, lockMode, allowedFileTypes, customFlags, geoFlags, fileR9KMode, messageR9KMode } = res.locals.board.settings; captchaMode, lockMode, allowedFileTypes, customFlags, geoFlags, fileR9KMode, messageR9KMode } = res.locals.board.settings;
if (!isStaffOrGlobal if (!isStaffOrGlobal
&& res.locals.country //permission for this or nah? && res.locals.country //permission for this or nah?
&& blockedCountries.includes(res.locals.country.code)) { && blockedCountries.includes(res.locals.country.code)) {
await deleteTempFiles(req).catch(e => console.error); await deleteTempFiles(req).catch(console.error);
return dynamicResponse(req, res, 403, 'message', { return dynamicResponse(req, res, 403, 'message', {
'title': 'Forbidden', 'title': 'Forbidden',
'message': `Your country "${res.locals.country.name}" is not allowed to post on this board`, 'message': `Your country "${res.locals.country.name}" is not allowed to post on this board`,
@ -71,7 +70,7 @@ module.exports = async (req, res, next) => {
} }
if ((lockMode === 2 || (lockMode === 1 && !req.body.thread)) //if board lock, or thread lock and its a new thread if ((lockMode === 2 || (lockMode === 1 && !req.body.thread)) //if board lock, or thread lock and its a new thread
&& !isStaffOrGlobal) { //and not staff && !isStaffOrGlobal) { //and not staff
await deleteTempFiles(req).catch(e => console.error); await deleteTempFiles(req).catch(console.error);
return dynamicResponse(req, res, 400, 'message', { return dynamicResponse(req, res, 400, 'message', {
'title': 'Bad request', 'title': 'Bad request',
'message': lockMode === 1 ? 'Thread creation locked' : 'Board locked', 'message': lockMode === 1 ? 'Thread creation locked' : 'Board locked',
@ -81,7 +80,7 @@ module.exports = async (req, res, next) => {
if (req.body.thread) { if (req.body.thread) {
thread = await Posts.getPost(req.params.board, req.body.thread, true); thread = await Posts.getPost(req.params.board, req.body.thread, true);
if (!thread || thread.thread != null) { if (!thread || thread.thread != null) {
await deleteTempFiles(req).catch(e => console.error); await deleteTempFiles(req).catch(console.error);
return dynamicResponse(req, res, 400, 'message', { return dynamicResponse(req, res, 400, 'message', {
'title': 'Bad request', 'title': 'Bad request',
'message': 'Thread does not exist', 'message': 'Thread does not exist',
@ -89,9 +88,9 @@ module.exports = async (req, res, next) => {
}); });
} }
salt = thread.salt; salt = thread.salt;
redirect += `thread/${req.body.thread}.html` redirect += `thread/${req.body.thread}.html`;
if (thread.locked && !isStaffOrGlobal) { if (thread.locked && !isStaffOrGlobal) {
await deleteTempFiles(req).catch(e => console.error); await deleteTempFiles(req).catch(console.error);
return dynamicResponse(req, res, 400, 'message', { return dynamicResponse(req, res, 400, 'message', {
'title': 'Bad request', 'title': 'Bad request',
'message': 'Thread Locked', 'message': 'Thread Locked',
@ -99,7 +98,7 @@ module.exports = async (req, res, next) => {
}); });
} }
if (thread.replyposts >= replyLimit && !thread.cyclic) { //reply limit if (thread.replyposts >= replyLimit && !thread.cyclic) { //reply limit
await deleteTempFiles(req).catch(e => console.error); await deleteTempFiles(req).catch(console.error);
return dynamicResponse(req, res, 400, 'message', { return dynamicResponse(req, res, 400, 'message', {
'title': 'Bad request', 'title': 'Bad request',
'message': 'Thread reached reply limit', 'message': 'Thread reached reply limit',
@ -116,25 +115,24 @@ module.exports = async (req, res, next) => {
filterBanDuration: globalFilterBanDuration } = config.get; filterBanDuration: globalFilterBanDuration } = config.get;
let hitGlobalFilter = false let hitGlobalFilter = false
, hitLocalFilter = false , hitLocalFilter = false;
, ban; let { combinedString, strictCombinedString } = getFilterStrings(req, res, strictFiltering || res.locals.board.settings.strictFiltering);
let [combinedString, strictCombinedString] = getFilterStrings(req, res, strictFiltering || res.locals.board.settings.strictFiltering);
//compare to global filters //compare to global filters
if (globalFilters && globalFilters.length > 0 && globalFilterMode > 0) { if (globalFilters && globalFilters.length > 0 && globalFilterMode > 0) {
hitGlobalFilter = globalFilters.some(filter => { return strictCombinedString.includes(filter.toLowerCase()) }); hitGlobalFilter = globalFilters.some(filter => { return strictCombinedString.includes(filter.toLowerCase()); });
} }
//compare to board filters //compare to board filters
if (!hitGlobalFilter && !res.locals.permissions.get(Permissions.MANAGE_BOARD_GENERAL) if (!hitGlobalFilter && !res.locals.permissions.get(Permissions.MANAGE_BOARD_GENERAL)
&& filterMode > 0 && filters && filters.length > 0) { && filterMode > 0 && filters && filters.length > 0) {
const localFilterContents = res.locals.board.settings.strictFiltering === true ? strictCombinedString : combinedString; const localFilterContents = res.locals.board.settings.strictFiltering === true ? strictCombinedString : combinedString;
hitLocalFilter = filters.some(filter => { return localFilterContents.includes(filter.toLowerCase()) }); hitLocalFilter = filters.some(filter => { return localFilterContents.includes(filter.toLowerCase()); });
} }
//block post/apply bans if an active filter matched //block post/apply bans if an active filter matched
if (hitGlobalFilter || hitLocalFilter) { if (hitGlobalFilter || hitLocalFilter) {
await deleteTempFiles(req).catch(e => console.error); await deleteTempFiles(req).catch(console.error);
return filterActions(req, res, hitGlobalFilter, filterMode, globalFilterMode, return filterActions(req, res, hitGlobalFilter, filterMode, globalFilterMode,
filterBanDuration, globalFilterBanDuration, globalFilterBanDuration, filterBanDuration, globalFilterBanDuration, globalFilterBanDuration,
filterBanAppealable, redirect); filterBanAppealable, redirect);
@ -150,7 +148,7 @@ module.exports = async (req, res, next) => {
if ((req.body.thread && messageR9KMode === 1) || messageR9KMode === 2) { if ((req.body.thread && messageR9KMode === 1) || messageR9KMode === 2) {
const postWithExistingMessage = await Posts.checkExistingMessage(res.locals.board._id, (messageR9KMode === 2 ? null : req.body.thread), messageHash); const postWithExistingMessage = await Posts.checkExistingMessage(res.locals.board._id, (messageR9KMode === 2 ? null : req.body.thread), messageHash);
if (postWithExistingMessage != null) { if (postWithExistingMessage != null) {
await deleteTempFiles(req).catch(e => console.error); await deleteTempFiles(req).catch(console.error);
return dynamicResponse(req, res, 409, 'message', { return dynamicResponse(req, res, 409, 'message', {
'title': 'Conflict', 'title': 'Conflict',
'message': `Messages must be unique ${messageR9KMode === 1 ? 'in this thread' : 'on this board'}. Your message is not unique.`, 'message': `Messages must be unique ${messageR9KMode === 1 ? 'in this thread' : 'on this board'}. Your message is not unique.`,
@ -169,7 +167,7 @@ module.exports = async (req, res, next) => {
const filesHashes = req.files.file.map(f => f.sha256); const filesHashes = req.files.file.map(f => f.sha256);
const postWithExistingFiles = await Posts.checkExistingFiles(res.locals.board._id, (fileR9KMode === 2 ? null : req.body.thread), filesHashes); const postWithExistingFiles = await Posts.checkExistingFiles(res.locals.board._id, (fileR9KMode === 2 ? null : req.body.thread), filesHashes);
if (postWithExistingFiles != null) { if (postWithExistingFiles != null) {
await deleteTempFiles(req).catch(e => console.error); await deleteTempFiles(req).catch(console.error);
const conflictingFiles = req.files.file const conflictingFiles = req.files.file
.filter(f => postWithExistingFiles.files.some(fx => fx.hash === f.sha256)) .filter(f => postWithExistingFiles.files.some(fx => fx.hash === f.sha256))
.map(f => f.name) .map(f => f.name)
@ -185,7 +183,7 @@ module.exports = async (req, res, next) => {
//basic mime type check //basic mime type check
for (let i = 0; i < res.locals.numFiles; i++) { for (let i = 0; i < res.locals.numFiles; i++) {
if (!mimeTypes.allowed(req.files.file[i].mimetype, allowedFileTypes)) { if (!mimeTypes.allowed(req.files.file[i].mimetype, allowedFileTypes)) {
await deleteTempFiles(req).catch(e => console.error); await deleteTempFiles(req).catch(console.error);
return dynamicResponse(req, res, 400, 'message', { return dynamicResponse(req, res, 400, 'message', {
'title': 'Bad request', 'title': 'Bad request',
'message': `Mime type "${req.files.file[i].mimetype}" for "${req.files.file[i].name}" not allowed`, 'message': `Mime type "${req.files.file[i].mimetype}" for "${req.files.file[i].name}" not allowed`,
@ -198,7 +196,7 @@ module.exports = async (req, res, next) => {
if (checkRealMimeTypes) { if (checkRealMimeTypes) {
for (let i = 0; i < res.locals.numFiles; i++) { for (let i = 0; i < res.locals.numFiles; i++) {
if (!(await mimeTypes.realMimeCheck(req.files.file[i]))) { if (!(await mimeTypes.realMimeCheck(req.files.file[i]))) {
deleteTempFiles(req).catch(e => console.error); deleteTempFiles(req).catch(console.error);
return dynamicResponse(req, res, 400, 'message', { return dynamicResponse(req, res, 400, 'message', {
'title': 'Bad request', 'title': 'Bad request',
'message': `Mime type mismatch for file "${req.files.file[i].name}"`, 'message': `Mime type mismatch for file "${req.files.file[i].name}"`,
@ -233,14 +231,14 @@ module.exports = async (req, res, next) => {
let [type, subtype] = processedFile.mimetype.split('/'); let [type, subtype] = processedFile.mimetype.split('/');
//check if already exists //check if already exists
const existsFull = await pathExists(`${uploadDirectory}/file/${processedFile.filename}`); const existsFull = await pathExists(`${uploadDirectory}/file/${processedFile.filename}`);
processedFile.sizeString = formatSize(processedFile.size) processedFile.sizeString = formatSize(processedFile.size);
const saveFull = async () => { const saveFull = async () => {
await Files.increment(processedFile); await Files.increment(processedFile);
req.files.file[i].inced = true; req.files.file[i].inced = true;
if (!existsFull) { if (!existsFull) {
await moveUpload(file, processedFile.filename, 'file'); await moveUpload(file, processedFile.filename, 'file');
} }
} };
if (mimeTypes.other.has(processedFile.mimetype)) { if (mimeTypes.other.has(processedFile.mimetype)) {
//"other" mimes from config, overrides main type to avoid codec issues in browser or ffmpeg for unsupported filetypes //"other" mimes from config, overrides main type to avoid codec issues in browser or ffmpeg for unsupported filetypes
processedFile.hasThumb = false; processedFile.hasThumb = false;
@ -256,7 +254,7 @@ module.exports = async (req, res, next) => {
try { try {
imageData = await imageIdentify(req.files.file[i].tempFilePath, null, true); imageData = await imageIdentify(req.files.file[i].tempFilePath, null, true);
} catch (e) { } catch (e) {
await deleteTempFiles(req).catch(e => console.error); await deleteTempFiles(req).catch(console.error);
return dynamicResponse(req, res, 400, 'message', { return dynamicResponse(req, res, 400, 'message', {
'title': 'Bad request', 'title': 'Bad request',
'message': `The server failed to process "${req.files.file[i].name}". Possible unsupported or corrupt file.`, 'message': `The server failed to process "${req.files.file[i].name}". Possible unsupported or corrupt file.`,
@ -294,7 +292,7 @@ module.exports = async (req, res, next) => {
break; break;
} }
case 'audio': case 'audio':
case 'video': case 'video': {
//video metadata //video metadata
const audioVideoData = await ffprobe(req.files.file[i].tempFilePath, null, true); const audioVideoData = await ffprobe(req.files.file[i].tempFilePath, null, true);
processedFile.duration = audioVideoData.format.duration; processedFile.duration = audioVideoData.format.duration;
@ -303,7 +301,7 @@ module.exports = async (req, res, next) => {
if (videoStreams.length > 0) { if (videoStreams.length > 0) {
processedFile.thumbextension = thumbExtension; processedFile.thumbextension = thumbExtension;
processedFile.geometry = {width: videoStreams[0].coded_width, height: videoStreams[0].coded_height}; processedFile.geometry = {width: videoStreams[0].coded_width, height: videoStreams[0].coded_height};
processedFile.geometryString = `${processedFile.geometry.width}x${processedFile.geometry.height}` processedFile.geometryString = `${processedFile.geometry.width}x${processedFile.geometry.height}`;
processedFile.hasThumb = true; processedFile.hasThumb = true;
await saveFull(); await saveFull();
if (!existsThumb) { if (!existsThumb) {
@ -336,6 +334,7 @@ module.exports = async (req, res, next) => {
} }
} }
break; break;
}
default: default:
throw new Error(`invalid file mime type: ${processedFile.mimetype}`); throw new Error(`invalid file mime type: ${processedFile.mimetype}`);
} }
@ -360,7 +359,7 @@ module.exports = async (req, res, next) => {
} }
} }
// because express middleware is autistic i need to do this // because express middleware is autistic i need to do this
deleteTempFiles(req).catch(e => console.error); deleteTempFiles(req).catch(console.error);
let userId = null; let userId = null;
if (!salt) { if (!salt) {
@ -407,7 +406,7 @@ module.exports = async (req, res, next) => {
const { message, quotes, crossquotes } = await messageHandler(nomarkup, req.params.board, req.body.thread, res.locals.permissions); const { message, quotes, crossquotes } = await messageHandler(nomarkup, req.params.board, req.body.thread, res.locals.permissions);
//build post data for db. for some reason all the property names are lower case :^) //build post data for db. for some reason all the property names are lower case :^)
const now = Date.now() const now = Date.now();
const data = { const data = {
'date': new Date(now), 'date': new Date(now),
'u': now, 'u': now,
@ -433,7 +432,7 @@ module.exports = async (req, res, next) => {
quotes, //posts this post replies to quotes, //posts this post replies to
crossquotes, //quotes to other threads in same board crossquotes, //quotes to other threads in same board
'backlinks': [], //posts replying to this post 'backlinks': [], //posts replying to this post
} };
if (!req.body.thread) { if (!req.body.thread) {
//if this is a thread, add thread specific properties //if this is a thread, add thread specific properties
@ -458,7 +457,6 @@ module.exports = async (req, res, next) => {
const { postId, postMongoId } = await Posts.insertOne(res.locals.board, data, thread, res.locals.anonymizer); const { postId, postMongoId } = await Posts.insertOne(res.locals.board, data, thread, res.locals.anonymizer);
let enableCaptcha = false; //make this returned from some function, refactor and move the next section to another file let enableCaptcha = false; //make this returned from some function, refactor and move the next section to another file
const pphTriggerActive = (pphTriggerAction > 0 && pphTrigger > 0);
const tphTriggerActive = (tphTriggerAction > 0 && tphTrigger > 0); const tphTriggerActive = (tphTriggerAction > 0 && tphTrigger > 0);
if (pphTriggerAction || tphTriggerActive) { //if a trigger is enabled if (pphTriggerAction || tphTriggerActive) { //if a trigger is enabled
const triggerUpdate = { const triggerUpdate = {
@ -487,7 +485,7 @@ module.exports = async (req, res, next) => {
return true; return true;
} }
return false; return false;
} };
const updatedPphTrigger = pphTriggerUpdate && calcTriggerMode(triggerUpdate, pphTrigger, pphTriggerAction, hourPosts.pph); const updatedPphTrigger = pphTriggerUpdate && calcTriggerMode(triggerUpdate, pphTrigger, pphTriggerAction, hourPosts.pph);
const updatedTphTrigger = tphTriggerUpdate && calcTriggerMode(triggerUpdate, tphTrigger, tphTriggerAction, hourPosts.tph); const updatedTphTrigger = tphTriggerUpdate && calcTriggerMode(triggerUpdate, tphTrigger, tphTriggerAction, hourPosts.tph);
if (updatedPphTrigger || updatedTphTrigger) { if (updatedPphTrigger || updatedTphTrigger) {
@ -586,7 +584,7 @@ module.exports = async (req, res, next) => {
'locked': data.locked, 'locked': data.locked,
'bumplocked': data.bumplocked, 'bumplocked': data.bumplocked,
'cyclic': data.cyclic, 'cyclic': data.cyclic,
} };
if (data.thread) { if (data.thread) {
//dont emit thread to this socket, because the room only exists when the thread is open //dont emit thread to this socket, because the room only exists when the thread is open
Socketio.emitRoom(`${res.locals.board._id}-${data.thread}`, 'newPost', projectedPost); Socketio.emitRoom(`${res.locals.board._id}-${data.thread}`, 'newPost', projectedPost);
@ -665,4 +663,4 @@ module.exports = async (req, res, next) => {
} }
}); });
} };

Loading…
Cancel
Save