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 */
import {
Model, Types,
Model, Op, Types,
} from '@latus/db';
export default (latus) => {
@ -18,51 +18,57 @@ export default (latus) => {
}
static async check(req) {
const entries = keys.map((key) => [key, req[key]]);
const promises = entries.map(([key, value]) => this.findOne({where: {[key]: value}}));
const bans = await Promise.all(promises);
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];
const ban = this.fromRequest(req, keys);
const candidates = Object.entries(ban)
.reduce((r, [key, value]) => [...r, {[key]: value}], []);
const where = {
where: {
[Op.or]: candidates,
},
};
const bans = await this.findAll(where);
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];
}, []);
const prunedEntries = pruned
.reduce((r, ban, i) => ([
...r,
...(
ban
? [[
entries[i][0],
[ban.ttl, entries[i][1]],
]]
: []),
]), []);
if (0 === prunedEntries.length) {
return [...r, ban];
}, [])
.filter((ban) => !!ban)
.map((ban) => ban.toJSON());
if (0 === pruned.length) {
return;
}
throw new Error(this.format(prunedEntries));
}
static async create(req, keys, ttl) {
return Promise.all(keys.map((key) => super.create({[key]: req[key], ttl})));
throw new Error(this.format(pruned));
}
static format(bans) {
return [
'ban = {',
bans.map(
([key, [ttl, value]]) => ` ${key}: ${value},${ttl ? ` // ttl: ${ttl}` : ''}`,
).join('\n'),
'};',
'bans = [',
bans.map((ban) => {
const entries = Object.entries(ban)
.filter(([key]) => -1 === ['id', 'createdAt', 'updatedAt'].indexOf(key));
return [
' {',
entries.map(([key, value]) => ` ${key}: ${value},`).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};
const {
NODE_ENV,
} = process.env;
export default {
hooks: {
'@latus/core/config': () => ({
@ -46,8 +42,9 @@ export default {
return;
}
req.ban = async (keys, ttl = 0) => {
await Ban.create(req, keys, ttl);
res.status(403).send(`<pre>${Ban.format(keys.map((key) => [key, [ttl, req[key]]]))}</pre>`);
const ban = Ban.fromRequest(req, keys, ttl);
await Ban.create({...ban});
res.status(403).send(`<pre>${Ban.format([ban])}</pre>`);
};
try {
await limiter.consume(req.ip);
@ -55,8 +52,9 @@ export default {
}
catch (error) {
const {ttl, keys} = http;
await Ban.create(req, keys, ttl);
res.status(429).send(`<pre>${Ban.format(keys.map((key) => [key, [ttl, req[key]]]))}</pre>`);
const ban = Ban.fromRequest(req, keys, ttl);
await Ban.create({...ban});
res.status(429).send(`<pre>${Ban.format([ban])}</pre>`);
}
};
},
@ -77,7 +75,7 @@ export default {
return;
}
req.ban = async (keys, ttl) => {
await Ban.create(req, keys, ttl);
await Ban.create(Ban.fromRequest(req, keys, ttl));
socket.disconnect();
};
try {
@ -86,7 +84,7 @@ export default {
}
catch (error) {
const {ttl, keys} = socket;
await Ban.create(req, keys, ttl);
await Ban.create(Ban.fromRequest(req, keys, ttl));
next(error);
}
};