refactor: bans

This commit is contained in:
cha0s 2020-12-13 04:17:03 -06:00
parent 3d7db1a001
commit 7f66434cda
2 changed files with 50 additions and 46 deletions

View File

@ -1,6 +1,6 @@
/* eslint-disable import/no-extraneous-dependencies */ /* eslint-disable import/no-extraneous-dependencies */
import { import {
Model, Types, Model, Op, Types,
} from '@latus/db'; } from '@latus/db';
export default (latus) => { export default (latus) => {
@ -18,51 +18,57 @@ export default (latus) => {
} }
static async check(req) { static async check(req) {
const entries = keys.map((key) => [key, req[key]]); const ban = this.fromRequest(req, keys);
const promises = entries.map(([key, value]) => this.findOne({where: {[key]: value}})); const candidates = Object.entries(ban)
const bans = await Promise.all(promises); .reduce((r, [key, value]) => [...r, {[key]: value}], []);
const pruned = bans.reduce((r, ban) => { const where = {
if (ban && ban.ttl > 0) { where: {
const expiresAt = new Date(ban.createdAt); [Op.or]: candidates,
expiresAt.setSeconds(expiresAt.getSeconds() + ban.ttl); },
if (Date.now() >= expiresAt.getTime()) { };
this.destroy({where: {id: ban.id}}); const bans = await this.findAll(where);
return [...r, null]; const pruned = bans
.reduce((r, ban) => {
if (ban && ban.ttl > 0) {
const expiresAt = new Date(ban.createdAt);
expiresAt.setSeconds(expiresAt.getSeconds() + ban.ttl);
if (Date.now() >= expiresAt.getTime()) {
this.destroy({where: {id: ban.id}});
return [...r, null];
}
// eslint-disable-next-line no-param-reassign
ban.ttl = Math.ceil((expiresAt.getTime() - Date.now()) / 1000);
} }
} return [...r, ban];
return [...r, ban]; }, [])
}, []); .filter((ban) => !!ban)
const prunedEntries = pruned .map((ban) => ban.toJSON());
.reduce((r, ban, i) => ([ if (0 === pruned.length) {
...r,
...(
ban
? [[
entries[i][0],
[ban.ttl, entries[i][1]],
]]
: []),
]), []);
if (0 === prunedEntries.length) {
return; return;
} }
throw new Error(this.format(prunedEntries)); throw new Error(this.format(pruned));
}
static async create(req, keys, ttl) {
return Promise.all(keys.map((key) => super.create({[key]: req[key], ttl})));
} }
static format(bans) { static format(bans) {
return [ return [
'ban = {', 'bans = [',
bans.map( bans.map((ban) => {
([key, [ttl, value]]) => ` ${key}: ${value},${ttl ? ` // ttl: ${ttl}` : ''}`, const entries = Object.entries(ban)
).join('\n'), .filter(([key]) => -1 === ['id', 'createdAt', 'updatedAt'].indexOf(key));
'};', return [
' {',
entries.map(([key, value]) => ` ${key}: ${value},`).join('\n'),
' },',
].join('\n');
}).join('\n'),
'];',
].join('\n'); ].join('\n');
} }
static fromRequest(req, keys, ttl = 0) {
return keys.reduce((r, key) => ({...r, [key]: req[key]}), ttl ? {ttl} : {});
}
}; };
}; };

View File

@ -6,10 +6,6 @@ import createLimiter from './limiter';
export {createLimiter}; export {createLimiter};
const {
NODE_ENV,
} = process.env;
export default { export default {
hooks: { hooks: {
'@latus/core/config': () => ({ '@latus/core/config': () => ({
@ -46,8 +42,9 @@ export default {
return; return;
} }
req.ban = async (keys, ttl = 0) => { req.ban = async (keys, ttl = 0) => {
await Ban.create(req, keys, ttl); const ban = Ban.fromRequest(req, keys, ttl);
res.status(403).send(`<pre>${Ban.format(keys.map((key) => [key, [ttl, req[key]]]))}</pre>`); await Ban.create({...ban});
res.status(403).send(`<pre>${Ban.format([ban])}</pre>`);
}; };
try { try {
await limiter.consume(req.ip); await limiter.consume(req.ip);
@ -55,8 +52,9 @@ export default {
} }
catch (error) { catch (error) {
const {ttl, keys} = http; const {ttl, keys} = http;
await Ban.create(req, keys, ttl); const ban = Ban.fromRequest(req, keys, ttl);
res.status(429).send(`<pre>${Ban.format(keys.map((key) => [key, [ttl, req[key]]]))}</pre>`); await Ban.create({...ban});
res.status(429).send(`<pre>${Ban.format([ban])}</pre>`);
} }
}; };
}, },
@ -77,7 +75,7 @@ export default {
return; return;
} }
req.ban = async (keys, ttl) => { req.ban = async (keys, ttl) => {
await Ban.create(req, keys, ttl); await Ban.create(Ban.fromRequest(req, keys, ttl));
socket.disconnect(); socket.disconnect();
}; };
try { try {
@ -86,7 +84,7 @@ export default {
} }
catch (error) { catch (error) {
const {ttl, keys} = socket; const {ttl, keys} = socket;
await Ban.create(req, keys, ttl); await Ban.create(Ban.fromRequest(req, keys, ttl));
next(error); next(error);
} }
}; };