ban tor in guestbook

This commit is contained in:
b1ek 2023-04-20 16:40:47 +10:00
parent 0c3ed4152e
commit 00703e39d1
Signed by: blek
GPG Key ID: 14546221E3595D0C
6 changed files with 71 additions and 3 deletions

View File

@ -11,4 +11,8 @@ DB_USERNAME=homepage
DB_DATABASE=homepage DB_DATABASE=homepage
REDIS_HOST=redis REDIS_HOST=redis
REDIS_PORT=6379 REDIS_PORT=6379
# list services that are not tor-allowed
# separated by comma (,)
DISALLOW_TOR=guestbook

View File

@ -3,5 +3,6 @@ module.exports = {
TimeSince: require('./timesince'), TimeSince: require('./timesince'),
HtmlString: require('./htmlstring'), HtmlString: require('./htmlstring'),
GPG: require('./gpg'), GPG: require('./gpg'),
Minify: require('./minify') Minify: require('./minify'),
TorChecker: require('./tor_check')
} }

52
helpers/tor_check.js Normal file
View File

@ -0,0 +1,52 @@
const fs = require('fs');
// fucking es6
const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
let exits_list;
let is_job_running;
if (exits_list == undefined) {
if (!fs.existsSync('store/torexits.json')) {
refreshList();
} else {
exits_list = JSON.parse(fs.readFileSync('store/torexits.json', {encoding: 'utf-8'}));
}
}
function isOutdated() {
// list expires in 4 hours
return Date.now() - exits_list.last_update > 1000 * 60 * 60 * 4;
}
async function check(ip) {
if (!exits_list) {
await refreshList();
}
return exits_list.ips.indexOf(ip) !== -1;
}
async function refreshList() {
let data = {
last_update: Date.now(),
ips: undefined
};
let raw_list = await (await fetch('https://check.torproject.org/torbulkexitlist')).text();
let ips = raw_list.replace('\r', '').split('\n');
exits_list = {
last_update: Date.now(),
ips
};
fs.writeFileSync('store/torexits.json', JSON.stringify(exits_list, undefined, process.env.APP_DEBUG ? ' ' : undefined));
}
async function run_refresh_job() {
if (isOutdated()) {
refreshList();
}
setTimeout(run_refresh_job, 1000 * 60 * 30);
}
module.exports = { check, isOutdated };

View File

@ -32,6 +32,7 @@
"ioredis": "^5.3.1", "ioredis": "^5.3.1",
"js-base64": "^3.7.5", "js-base64": "^3.7.5",
"mocha": "^10.2.0", "mocha": "^10.2.0",
"node-fetch": "^3.3.1",
"node-gpg": "^0.2.0", "node-gpg": "^0.2.0",
"otplib": "^12.0.1", "otplib": "^12.0.1",
"pg": "^8.9.0", "pg": "^8.9.0",

View File

@ -1,6 +1,7 @@
const Sequelize = require('../models'); const Sequelize = require('../models');
const xml = require('xml'); const xml = require('xml');
const handler = require('express-async-handler'); const handler = require('express-async-handler');
const Helpers = require('../helpers');
const send_error = async (res, error) => { const send_error = async (res, error) => {
return res.redirect('/guestbook?error=' + encodeURIComponent(error)); return res.redirect('/guestbook?error=' + encodeURIComponent(error));
@ -21,7 +22,6 @@ async function guestbook(req, res, next) {
}); });
if (!data) throw new Error('Failed to get guestbook entries'); if (!data) throw new Error('Failed to get guestbook entries');
res.template('guestbook.pug', { res.template('guestbook.pug', {
current_route: req.originalUrl, current_route: req.originalUrl,
ip: req.ip, ip: req.ip,
@ -61,6 +61,14 @@ async function submit(req, res, next) {
if (message == '') { if (message == '') {
errors.push('Message should not be empty!'); errors.push('Message should not be empty!');
} }
if (process.env.DISALLOW_TOR.split(',').indexOf('guestbook') !== -1) {
let ip4 = req.ip.startsWith('::ffff:') ? req.ip.replace(/^::ffff:/, '') : req.ip;
if (await Helpers.TorChecker.check(ip4)) {
errors.push('Using tor is not allowed: IP ' + ip4 + ' is listed as a tor exit');
}
}
if (errors.length !== 0) { if (errors.length !== 0) {
send_error(res, "<p>" + errors.join('<br/>') + "</p>"); send_error(res, "<p>" + errors.join('<br/>') + "</p>");
return; return;

2
store/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*
!.gitignore