Merge branch 'new-dev' of ssh.gitgud.io:fatchan/jschan into new-dev

merge-requests/208/head
Thomas Lynch 4 years ago
commit 7bf4f1fdee
  1. 8
      configs/main.js.example
  2. 8
      controllers/forms/makepost.js
  3. 4
      db/posts.js
  4. 4
      helpers/captcha/verify.js
  5. 6
      helpers/checks/blockbypass.js
  6. 2
      helpers/checks/dnsbl.js
  7. 8
      helpers/checks/torprebypass.js
  8. 10
      helpers/countries.js
  9. 4
      helpers/filemiddlewares.js
  10. 4
      helpers/geoip.js
  11. 2
      helpers/processip.js
  12. 1
      migrations/index.js
  13. 12
      migrations/migration-0.0.18.js
  14. 2
      models/forms/changeboardsettings.js
  15. 2
      models/forms/makepost.js
  16. 2
      models/pages/captcha.js
  17. 2
      package.json
  18. 4
      views/pages/managesettings.pug

@ -72,10 +72,10 @@ module.exports = {
},
//disable file posting over .onion globally, overrides any board setting.
disableOnionFilePosting: false,
disableAnonymizerFilePosting: false,
//count .onion posters as "users" in stats. if set to false, all .onion is counted as a single user. doesnt affect pph stat.
statsCountOnionUsers: true,
statsCountAnonymizers: true,
floodTimers: { //basic delays to stop flooding, in ms. 0 to disable
sameContentSameIp: 120000, //same message or any file from same ip
@ -86,7 +86,7 @@ module.exports = {
//block bypasses
blockBypass: {
enabled: false,
forceOnion: true, //option to override blockbypass setting for .onion users
forceAnonymizers: true, //option to override blockbypass setting for .onion users
expireAfterUses: 40, //however many (attempted) posts per block bypass captcha
expireAfterTime: 86400000, //expiry in ms regardless if the limit was reached, default 1 day
bypassDnsbl: false,
@ -374,7 +374,7 @@ module.exports = {
defaultName: 'Anon',
customCSS: null,
blockedCountries: [], //2 char ISO country codes to block
disableOnionFilePosting: false,
disableAnonymizerFilePosting: false,
filters: [], //words/phrases to block
filterMode: 0, //0=nothing, 1=prevent post, 2=auto ban
filterBanDuration: 0, //duration (in ms) to ban if filter mode=2

@ -4,7 +4,7 @@ const makePost = require(__dirname+'/../../models/forms/makepost.js')
, deleteTempFiles = require(__dirname+'/../../helpers/files/deletetempfiles.js')
, dynamicResponse = require(__dirname+'/../../helpers/dynamic.js')
, pruneFiles = require(__dirname+'/../../schedules/prune.js')
, { pruneImmediately, globalLimits, disableOnionFilePosting } = require(__dirname+'/../../configs/main.js')
, { pruneImmediately, globalLimits, disableAnonymizerFilePosting } = require(__dirname+'/../../configs/main.js')
, { Files } = require(__dirname+'/../../db/');
module.exports = async (req, res, next) => {
@ -15,10 +15,10 @@ module.exports = async (req, res, next) => {
if ((!req.body.message || res.locals.messageLength === 0) && res.locals.numFiles === 0) {
errors.push('Posts must include a message or file');
}
if (res.locals.tor
&& (disableOnionFilePosting || res.locals.board.settings.disableOnionFilePosting)
if (res.locals.anonymizer
&& (disableAnonymizerFilePosting || res.locals.board.settings.disableAnonymizerFilePosting)
&& res.locals.numFiles > 0) {
errors.push(`Posting files through the .onion address has been disabled ${disableOnionFilePosting ? 'globally' : 'on this board'}`);
errors.push(`Posting files through the .onion address has been disabled ${disableAnonymizerFilePosting ? 'globally' : 'on this board'}`);
}
if (res.locals.numFiles > res.locals.board.settings.maxFiles) {
errors.push(`Too many files. Max files per post ${res.locals.board.settings.maxFiles < globalLimits.postFiles.max ? 'on this board ' : ''}is ${res.locals.board.settings.maxFiles}`);

@ -4,7 +4,7 @@ const Mongo = require(__dirname+'/db.js')
, Boards = require(__dirname+'/boards.js')
, Stats = require(__dirname+'/stats.js')
, db = Mongo.db.collection('posts')
, { quoteLimit, previewReplies, stickyPreviewReplies, statsCountOnionUsers,
, { quoteLimit, previewReplies, stickyPreviewReplies, statsCountAnonymizers,
ipHashPermLevel, early404Replies, early404Fraction } = require(__dirname+'/../configs/main.js');
module.exports = {
@ -474,7 +474,7 @@ module.exports = {
//insert the post itself
const postMongoId = await db.insertOne(data).then(result => result.insertedId); //_id of post
const statsIp = (statsCountOnionUsers === false && res.locals.tor === true) ? null : data.ip.single;
const statsIp = (statsCountAnonymizers === false && res.locals.anonymizer === true) ? null : data.ip.single;
await Stats.updateOne(board._id, statsIp, data.thread == null);
//add backlinks to the posts this post quotes

@ -12,7 +12,7 @@ const { Ratelimits } = require(__dirname+'/../../db/')
module.exports = async (req, res, next) => {
//already solved in pre stage for getting bypassID for "ip"
if (res.locals.tor && res.locals.solvedCaptcha) {
if (res.locals.anonymizer && res.locals.solvedCaptcha) {
return next();
}
@ -49,7 +49,7 @@ module.exports = async (req, res, next) => {
//for builtin captchas, clear captchaid cookie, delete file and reset quota
res.clearCookie('captchaid');
await Promise.all([
!res.locals.tor && Ratelimits.resetQuota(res.locals.ip.single, 'captcha'),
!res.locals.anonymizer && Ratelimits.resetQuota(res.locals.ip.single, 'captcha'),
remove(`${uploadDirectory}/captcha/${captchaId}.jpg`)
]);
}

@ -11,8 +11,8 @@ module.exports = async (req, res, next) => {
if (res.locals.preFetchedBypassId //if they already have a bypass
|| (!blockBypass.enabled //or if block bypass isnt enabled
&& (!blockBypass.forceOnion //and we dont force it for .onion
|| !res.locals.tor))) { //or they arent a .onion
&& (!blockBypass.forceAnonymizers //and we dont force it for anonymizer
|| !res.locals.anonymizer))) { //or they arent a .onion
return next();
}
@ -45,7 +45,7 @@ module.exports = async (req, res, next) => {
if (bypass //if they have a valid bypass
&& (bypass.uses < blockBypass.expireAfterUses //and its not overused
|| (res.locals.tor && !blockBypass.forceOnion))) { //OR its disabled for .onion, which ignores usage check
|| (res.locals.anonymizer && !blockBypass.forceOnion))) { //OR its disabled for .onion, which ignores usage check
return next();
}

@ -9,7 +9,7 @@ const cache = require(__dirname+'/../../redis.js')
module.exports = async (req, res, next) => {
if (dnsbl.enabled && dnsbl.blacklists.length > 0 //if dnsbl enabled and has more than 0 blacklists
&& !res.locals.tor //tor cant be dnsbl'd
&& !res.locals.anonymizer //anonymizers cant be dnsbl'd
&& (!res.locals.blockBypass || !blockBypass.bypassDnsbl)) { //and there is no valid block bypass, or they do not bypass dnsbl
const ip = req.headers[ipHeader] || req.connection.remoteAddress;
let isBlacklisted = await cache.get(`blacklisted:${ip}`);

@ -12,14 +12,14 @@ const { Bypass } = require(__dirname+'/../../db/')
module.exports = async (req, res, next) => {
//early bypass is only needed for tor users
if (!res.locals.tor) {
//early bypass is only needed for anonymizer users
if (!res.locals.anonymizer) {
return next();
}
let bypassId = req.signedCookies.bypassid;
if (blockBypass.enabled || blockBypass.forceOnion) {
if (blockBypass.enabled || blockBypass.forceAnonymizers) {
const input = req.body.captcha;
const captchaId = req.cookies.captchaid;
if (input && !bypassId) {
@ -46,7 +46,7 @@ module.exports = async (req, res, next) => {
if (res.locals.solvedCaptcha //if they just solved a captcha
|| (!blockBypass.enabled //OR blockbypass isnt enabled
&& !blockBypass.forceOnion //AND its not forced for .onion
&& !blockBypass.forceAnonymizers //AND its not forced for anonymizers
&& !bypassId)) { //AND they dont already have one,
//then give the user a bypass id
const newBypass = await Bypass.getBypass();

@ -2,8 +2,11 @@
const countries = require('i18n-iso-countries')
, countryNamesMap = countries.getNames('en')
, countryCodes = ['EU', 'XX', 'T1', 'TOR', 'LOKI']
.concat(Object.keys(countryNamesMap));
, extraCountryCodes = ['EU', 'XX', 'T1']
, anonymizerCountryCodes = ['TOR', 'LOKI']
, anonymizerCountryCodesSet = new Set(anonymizerCountryCodes)
, countryCodes = Object.keys(countryNamesMap)
.concat(extraCountryCodes, anonymizerCountryCodes);
//this dumb library conveniently includes 2 names for some countries...
Object.entries(countryNamesMap)
@ -19,4 +22,7 @@ countryNamesMap['LOKI'] = 'Lokinet SNApp';
module.exports = {
countryNamesMap,
countryCodes,
isAnonymizer: (code) => {
return anonymizerCountryCodesSet.has(code);
},
}

@ -63,14 +63,14 @@ module.exports = {
}),
handlePostFilesEarlyTor: (req, res, next) => {
if (res.locals.tor) {
if (res.locals.anonymizer) {
return postFiles(req, res, next);
}
return next();
},
handlePostFiles: (req, res, next) => {
if (res.locals.tor) {
if (res.locals.anonymizer) {
return next();
}
return postFiles(req, res, next);

@ -1,11 +1,11 @@
'use strict'
const { countryNamesMap } = require(__dirname+'/countries.js')
, { countryCodeHeader } = require(__dirname+'/../configs/main.js');
, { countryCodeHeader, isAnonymizer } = require(__dirname+'/../configs/main.js')
module.exports = (req, res, next) => {
const code = req.headers[countryCodeHeader] || 'XX';
res.locals.tor = code === 'TOR' || code === 'LOKI'; //NOTE: for ticket #312 change this to use a single x-anonymizer header
res.locals.anonymizer = isAnonymizer(code);
res.locals.country = {
code,
name: countryNamesMap[code],

@ -9,7 +9,7 @@ const { ipHeader, ipHashPermLevel } = require(__dirname+'/../configs/main.js')
module.exports = (req, res, next) => {
//tor user ip uses bypass id, if they dont have one send to blockbypass
if (res.locals.tor) {
if (res.locals.anonymizer) {
const pseudoIp = res.locals.preFetchedBypassId || req.signedCookies.bypassid;
res.locals.ip = {
raw: pseudoIp,

@ -18,4 +18,5 @@ module.exports = {
'0.0.15': require(__dirname+'/migration-0.0.15.js'), //messages r9k option
'0.0.16': require(__dirname+'/migration-0.0.16.js'), //separate tph/pph triggers
'0.0.17': require(__dirname+'/migration-0.0.17.js'), //add custompages collection
'0.0.18': require(__dirname+'/migration-0.0.18.js'), //disable onion file posting to disable anonymizer file posting
}

@ -0,0 +1,12 @@
'use strict';
module.exports = async(db, redis) => {
console.log('Renaming disable onion file posting to disable anonymizer file posting');
await db.collection('boards').updateMany({}, {
'$rename': {
'settings.disableOnionFilePosting' : 'settings.disableAnonymizerFilePosting',
}
});
console.log('Cleared boards cache');
await redis.deletePattern('board:*');
};

@ -116,7 +116,7 @@ module.exports = async (req, res, next) => {
'tags': arraySetting(req.body.tags, oldSettings.tags, 10),
'filters': arraySetting(req.body.filters, oldSettings.filters, 50),
'blockedCountries': req.body.countries || [],
'disableOnionFilePosting': booleanSetting(req.body.disable_onion_file_posting),
'disableAnonymizerFilePosting': booleanSetting(req.body.disable_anonymizer_file_posting),
'strictFiltering': booleanSetting(req.body.strict_filtering),
'customCss': globalLimits.customCss.enabled ? (req.body.custom_css !== null ? req.body.custom_css : oldSettings.customCss) : null,
'announcement': {

@ -455,7 +455,7 @@ ${res.locals.numFiles > 0 ? req.files.file.map(f => f.name+'|'+(f.phash || '')).
});
}
const postId = await Posts.insertOne(res.locals.board, data, thread, res.locals.tor);
const postId = 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
const pphTriggerActive = (pphTriggerAction > 0 && pphTrigger > 0);

@ -16,7 +16,7 @@ module.exports = async (req, res, next) => {
let captchaId;
let maxAge = 5*60*1000;
try {
if (!res.locals.tor) {
if (!res.locals.anonymizer) {
const ratelimit = await Ratelimits.incrmentQuota(res.locals.ip.single, 'captcha', rateLimitCost.captcha);
if (ratelimit > 100) {
return res.status(429).redirect('/file/ratelimit.png');

@ -1,7 +1,7 @@
{
"name": "jschan",
"version": "0.0.1",
"migrateVersion": "0.0.17",
"migrateVersion": "0.0.18",
"description": "",
"main": "server.js",
"dependencies": {

@ -257,9 +257,9 @@ block content
label.postform-style.ph-5
input(type='checkbox', name='early404', value='true' checked=board.settings.early404)
.row
.label Disable .onion file posting
.label Disable anonymizer file posting
label.postform-style.ph-5
input(type='checkbox', name='disable_onion_file_posting', value='true' checked=board.settings.disableOnionFilePosting)
input(type='checkbox', name='disable_onion_file_posting', value='true' checked=board.settings.disableAnonymizerFilePosting)
.row
.label Blocked Countries
include ../includes/2charisocountries.pug

Loading…
Cancel
Save