feat(backend-app-api): start implementing in memory rate limit
Signed-off-by: Camila Belo <camilaibs@gmail.com>
This commit is contained in:
Vendored
+12
@@ -14,6 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { HumanDuration } from '@backstage/types';
|
||||
|
||||
export interface Config {
|
||||
backend?: {
|
||||
auth?: {
|
||||
@@ -32,6 +34,16 @@ export interface Config {
|
||||
* unless you configure credentials for service calls.
|
||||
*/
|
||||
dangerouslyDisableDefaultAuthPolicy?: boolean;
|
||||
rateLimit?: {
|
||||
/**
|
||||
* Limit each IP to max requests per window
|
||||
*/
|
||||
max?: number;
|
||||
/**
|
||||
* The duration for which the rate limit is enforced
|
||||
*/
|
||||
window?: HumanDuration;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -64,6 +64,7 @@
|
||||
"cors": "^2.8.5",
|
||||
"express": "^4.17.1",
|
||||
"express-promise-router": "^4.1.0",
|
||||
"express-rate-limit": "^7.2.0",
|
||||
"fs-extra": "^11.2.0",
|
||||
"helmet": "^6.0.0",
|
||||
"jose": "^5.0.0",
|
||||
|
||||
+24
-2
@@ -19,8 +19,11 @@ import {
|
||||
HttpRouterServiceAuthPolicy,
|
||||
RootConfigService,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import { durationToMilliseconds } from '@backstage/types';
|
||||
import { RequestHandler } from 'express';
|
||||
import { pathToRegexp } from 'path-to-regexp';
|
||||
import { rateLimit } from 'express-rate-limit';
|
||||
import { readDurationFromConfig } from '@backstage/config';
|
||||
|
||||
export function createPathPolicyPredicate(policyPath: string) {
|
||||
if (policyPath === '/' || policyPath === '*') {
|
||||
@@ -59,13 +62,32 @@ export function createCredentialsBarrier(options: {
|
||||
const unauthenticatedPredicates = new Array<(path: string) => boolean>();
|
||||
const cookiePredicates = new Array<(path: string) => boolean>();
|
||||
|
||||
const middleware: RequestHandler = (req, _, next) => {
|
||||
// Default rate limit is 100 requests per 15 minutes
|
||||
const max = config?.has('backend.auth.rateLimit.max')
|
||||
? config.getNumber('backend.auth.rateLimit.max')
|
||||
: 100;
|
||||
|
||||
const duration = config?.has('backend.auth.rateLimit.window')
|
||||
? readDurationFromConfig(config.getConfig('backend.auth.rateLimit.window'))
|
||||
: undefined;
|
||||
|
||||
// Default rate limit window is 15 minutes
|
||||
const windowMs = duration ? durationToMilliseconds(duration) : 15 * 60 * 1000;
|
||||
|
||||
const limiter = rateLimit({
|
||||
windowMs,
|
||||
max,
|
||||
standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
|
||||
legacyHeaders: false, // Disable the `X-RateLimit-*` headers
|
||||
});
|
||||
|
||||
const middleware: RequestHandler = (req, res, next) => {
|
||||
const allowsUnauthenticated = unauthenticatedPredicates.some(predicate =>
|
||||
predicate(req.path),
|
||||
);
|
||||
|
||||
if (allowsUnauthenticated) {
|
||||
next();
|
||||
limiter(req, res, next);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -3248,6 +3248,7 @@ __metadata:
|
||||
cors: ^2.8.5
|
||||
express: ^4.17.1
|
||||
express-promise-router: ^4.1.0
|
||||
express-rate-limit: ^7.2.0
|
||||
fs-extra: ^11.2.0
|
||||
helmet: ^6.0.0
|
||||
http-errors: ^2.0.0
|
||||
@@ -28044,6 +28045,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"express-rate-limit@npm:^7.2.0":
|
||||
version: 7.2.0
|
||||
resolution: "express-rate-limit@npm:7.2.0"
|
||||
peerDependencies:
|
||||
express: 4 || 5 || ^5.0.0-beta.1
|
||||
checksum: 6adc3e06d430e91cf8ef8da23107466ffd9193b5680b03bc12702894cab0adcbb980634602b839b3a1444620f2379707098af3a4dcc38c909e89214abaf6c1bf
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"express-session@npm:^1.17.1, express-session@npm:^1.17.3":
|
||||
version: 1.18.0
|
||||
resolution: "express-session@npm:1.18.0"
|
||||
|
||||
Reference in New Issue
Block a user