mirror of
https://github.com/directus/directus.git
synced 2026-04-25 03:00:53 -04:00
Global rate limiter (#17296)
Co-authored-by: Azri Kahar <42867097+azrikahar@users.noreply.github.com>
This commit is contained in:
@@ -22,7 +22,7 @@ import { ActivityService } from './activity';
|
||||
import { SettingsService } from './settings';
|
||||
import { TFAService } from './tfa';
|
||||
|
||||
const loginAttemptsLimiter = createRateLimiter({ duration: 0 });
|
||||
const loginAttemptsLimiter = createRateLimiter('RATE_LIMITER', { duration: 0 });
|
||||
|
||||
export class AuthenticationService {
|
||||
knex: Knex;
|
||||
|
||||
@@ -8,7 +8,7 @@ import { getCache } from '../cache';
|
||||
import getDatabase, { hasDatabaseConnection } from '../database';
|
||||
import env from '../env';
|
||||
import logger from '../logger';
|
||||
import { rateLimiter } from '../middleware/rate-limiter';
|
||||
import { rateLimiter } from '../middleware/rate-limiter-ip';
|
||||
import { getStorage } from '../storage';
|
||||
import { AbstractServiceOptions } from '../types';
|
||||
import { Accountability, SchemaOverview } from '@directus/shared/types';
|
||||
@@ -17,6 +17,7 @@ import getMailer from '../mailer';
|
||||
import { SettingsService } from './settings';
|
||||
import { getOSInfo } from '../utils/get-os-info';
|
||||
import { Readable } from 'node:stream';
|
||||
import { rateLimiterGlobal } from '../middleware/rate-limiter-global';
|
||||
|
||||
export class ServerService {
|
||||
knex: Knex;
|
||||
@@ -59,6 +60,14 @@ export class ServerService {
|
||||
} else {
|
||||
info.rateLimit = false;
|
||||
}
|
||||
if (env.RATE_LIMITER_GLOBAL_ENABLED) {
|
||||
info.rateLimitGlobal = {
|
||||
points: env.RATE_LIMITER_GLOBAL_POINTS,
|
||||
duration: env.RATE_LIMITER_GLOBAL_DURATION,
|
||||
};
|
||||
} else {
|
||||
info.rateLimitGlobal = false;
|
||||
}
|
||||
|
||||
info.flows = {
|
||||
execAllowedModules: env.FLOWS_EXEC_ALLOWED_MODULES ? toArray(env.FLOWS_EXEC_ALLOWED_MODULES) : [],
|
||||
@@ -117,7 +126,14 @@ export class ServerService {
|
||||
releaseId: version,
|
||||
serviceId: env.KEY,
|
||||
checks: merge(
|
||||
...(await Promise.all([testDatabase(), testCache(), testRateLimiter(), testStorage(), testEmail()]))
|
||||
...(await Promise.all([
|
||||
testDatabase(),
|
||||
testCache(),
|
||||
testRateLimiter(),
|
||||
testRateLimiterGlobal(),
|
||||
testStorage(),
|
||||
testEmail(),
|
||||
]))
|
||||
),
|
||||
};
|
||||
|
||||
@@ -286,6 +302,49 @@ export class ServerService {
|
||||
return checks;
|
||||
}
|
||||
|
||||
async function testRateLimiterGlobal(): Promise<Record<string, HealthCheck[]>> {
|
||||
if (env.RATE_LIMITER_GLOBAL_ENABLED !== true) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const checks: Record<string, HealthCheck[]> = {
|
||||
'rateLimiterGlobal:responseTime': [
|
||||
{
|
||||
status: 'ok',
|
||||
componentType: 'ratelimiter',
|
||||
observedValue: 0,
|
||||
observedUnit: 'ms',
|
||||
threshold: env.RATE_LIMITER_GLOBAL_HEALTHCHECK_THRESHOLD
|
||||
? +env.RATE_LIMITER_GLOBAL_HEALTHCHECK_THRESHOLD
|
||||
: 150,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const startTime = performance.now();
|
||||
|
||||
try {
|
||||
await rateLimiterGlobal.consume(`health-${checkID}`, 1);
|
||||
await rateLimiterGlobal.delete(`health-${checkID}`);
|
||||
} catch (err: any) {
|
||||
checks['rateLimiterGlobal:responseTime'][0].status = 'error';
|
||||
checks['rateLimiterGlobal:responseTime'][0].output = err;
|
||||
} finally {
|
||||
const endTime = performance.now();
|
||||
checks['rateLimiterGlobal:responseTime'][0].observedValue = +(endTime - startTime).toFixed(3);
|
||||
|
||||
if (
|
||||
checks['rateLimiterGlobal:responseTime'][0].observedValue >
|
||||
checks['rateLimiterGlobal:responseTime'][0].threshold! &&
|
||||
checks['rateLimiterGlobal:responseTime'][0].status !== 'error'
|
||||
) {
|
||||
checks['rateLimiterGlobal:responseTime'][0].status = 'warn';
|
||||
}
|
||||
}
|
||||
|
||||
return checks;
|
||||
}
|
||||
|
||||
async function testStorage(): Promise<Record<string, HealthCheck[]>> {
|
||||
const storage = await getStorage();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user