feat: rate-limit for excessive groups

This commit is contained in:
KernelDeimos 2024-07-04 19:00:21 -04:00 committed by Eric Dubé
parent 0855f2b36e
commit 4af279a72f
3 changed files with 63 additions and 1 deletions

View File

@ -295,6 +295,9 @@ const install = async ({ services, app, useapi }) => {
const { MountpointService } = require('./services/MountpointService');
services.registerService('mountpoint', MountpointService);
const { AnomalyService } = require('./services/AnomalyService');
services.registerService('anomaly', AnomalyService);
}
const install_legacy = async ({ services }) => {

View File

@ -0,0 +1,35 @@
const BaseService = require("./BaseService");
const DENY_SERVICE_INSTRUCTION = Symbol('DENY_SERVICE_INSTRUCTION');
class AnomalyService extends BaseService {
_construct () {
this.types = {};
}
register (type, config) {
const type_instance = {
config,
}
if ( config.handler ) {
type_instance.handler = config.handler;
} else if ( config.high ) {
type_instance.handler = data => {
if ( data.value > config.high ) {
return new Set([DENY_SERVICE_INSTRUCTION]);
}
}
}
this.types[type] = type_instance;
}
async note (id, data) {
const type = this.types[id];
if ( ! type ) return;
return type.handler(data);
}
}
module.exports = {
AnomalyService,
DENY_SERVICE_INSTRUCTION,
};

View File

@ -1,4 +1,6 @@
const APIError = require("../../api/APIError");
const Group = require("../../entities/Group");
const { DENY_SERVICE_INSTRUCTION } = require("../AnomalyService");
const BaseService = require("../BaseService");
const { DB_WRITE } = require("../database/consts");
@ -9,6 +11,11 @@ class GroupService extends BaseService {
_init () {
this.db = this.services.get('database').get(DB_WRITE, 'permissions');
const svc_anomaly = this.services.get('anomaly');
svc_anomaly.register('groups-user-hour', {
high: 20,
});
}
async get({ uid }) {
@ -31,7 +38,24 @@ class GroupService extends BaseService {
metadata = metadata ?? {};
const uid = this.modules.uuidv4();
const [{ n_groups }] = await this.db.read(
"SELECT COUNT(*) AS n_groups FROM `group` WHERE " +
"owner_user_id=? AND " +
"created_at >= datetime('now', '-1 hour')",
[owner_user_id]
);
const svc_anomaly = this.services.get('anomaly');
const anomaly = await svc_anomaly.note('groups-user-hour', {
value: n_groups,
user_id: owner_user_id,
});
if ( anomaly && anomaly.has(DENY_SERVICE_INSTRUCTION) ) {
throw APIError.create('too_many_requests');
}
await this.db.write(
'INSERT INTO `group` ' +
'(`uid`, `owner_user_id`, `extra`, `metadata`) ' +