feat: slow down request after 50 requests

This commit is contained in:
tdurieux
2022-10-19 11:04:52 +02:00
parent 8508a01c28
commit 04b85599a6
3 changed files with 94 additions and 13 deletions

68
package-lock.json generated
View File

@@ -22,6 +22,7 @@
"express": "^4.18.1",
"express-rate-limit": "^6.6.0",
"express-session": "^1.17.3",
"express-slow-down": "^1.5.0",
"got": "^11.8.5",
"istextorbinary": "^6.0.0",
"mime-types": "^2.1.35",
@@ -44,6 +45,7 @@
"@types/express": "^4.17.13",
"@types/express-rate-limit": "^6.0.0",
"@types/express-session": "^1.17.5",
"@types/express-slow-down": "^1.3.2",
"@types/got": "^9.6.12",
"@types/mime-types": "^2.1.0",
"@types/parse-github-url": "^1.0.0",
@@ -875,6 +877,15 @@
"@types/express": "*"
}
},
"node_modules/@types/express-slow-down": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/@types/express-slow-down/-/express-slow-down-1.3.2.tgz",
"integrity": "sha512-Jw/orNMX+htFMYMugjhLotS5eRkdId4V5/89vqNXoUfxaHBU8VVIshItDh5YuWeyGeKuPli2fh94ORjYz/dkxA==",
"dev": true,
"dependencies": {
"@types/express": "*"
}
},
"node_modules/@types/glob": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz",
@@ -1845,6 +1856,14 @@
"wrap-ansi": "^7.0.0"
}
},
"node_modules/clone": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
"integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==",
"engines": {
"node": ">=0.8"
}
},
"node_modules/clone-response": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz",
@@ -2160,6 +2179,17 @@
"node": ">=0.12"
}
},
"node_modules/defaults": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz",
"integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==",
"dependencies": {
"clone": "^1.0.2"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/defer-to-connect": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz",
@@ -2516,6 +2546,14 @@
}
]
},
"node_modules/express-slow-down": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/express-slow-down/-/express-slow-down-1.5.0.tgz",
"integrity": "sha512-GCoa2a+mf7CE7C00TIoPMbcgQSXxEVolSAbP97uHyzVy87ssp0/IDtJ/GBxjv+gnfM2R1l2QcEfYixFJK75n7w==",
"dependencies": {
"defaults": "^1.0.3"
}
},
"node_modules/express/node_modules/debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
@@ -6048,6 +6086,15 @@
"@types/express": "*"
}
},
"@types/express-slow-down": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/@types/express-slow-down/-/express-slow-down-1.3.2.tgz",
"integrity": "sha512-Jw/orNMX+htFMYMugjhLotS5eRkdId4V5/89vqNXoUfxaHBU8VVIshItDh5YuWeyGeKuPli2fh94ORjYz/dkxA==",
"dev": true,
"requires": {
"@types/express": "*"
}
},
"@types/glob": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz",
@@ -6843,6 +6890,11 @@
"wrap-ansi": "^7.0.0"
}
},
"clone": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
"integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg=="
},
"clone-response": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz",
@@ -7070,6 +7122,14 @@
"type-detect": "^4.0.0"
}
},
"defaults": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz",
"integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==",
"requires": {
"clone": "^1.0.2"
}
},
"defer-to-connect": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz",
@@ -7364,6 +7424,14 @@
}
}
},
"express-slow-down": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/express-slow-down/-/express-slow-down-1.5.0.tgz",
"integrity": "sha512-GCoa2a+mf7CE7C00TIoPMbcgQSXxEVolSAbP97uHyzVy87ssp0/IDtJ/GBxjv+gnfM2R1l2QcEfYixFJK75n7w==",
"requires": {
"defaults": "^1.0.3"
}
},
"fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",

View File

@@ -37,6 +37,7 @@
"express": "^4.18.1",
"express-rate-limit": "^6.6.0",
"express-session": "^1.17.3",
"express-slow-down": "^1.5.0",
"got": "^11.8.5",
"istextorbinary": "^6.0.0",
"mime-types": "^2.1.35",
@@ -59,6 +60,7 @@
"@types/express": "^4.17.13",
"@types/express-rate-limit": "^6.0.0",
"@types/express-session": "^1.17.5",
"@types/express-slow-down": "^1.3.2",
"@types/got": "^9.6.12",
"@types/mime-types": "^2.1.0",
"@types/parse-github-url": "^1.0.0",

View File

@@ -2,6 +2,7 @@ import * as path from "path";
import * as ofs from "fs";
import { createClient } from "redis";
import rateLimit from "express-rate-limit";
import * as slowDown from "express-slow-down";
import RedisStore from "rate-limit-redis";
import * as express from "express";
import * as compression from "compression";
@@ -37,7 +38,7 @@ export default async function start() {
app.use(express.json());
app.use(compression());
app.set("trust proxy", config.TRUST_PROXY);
app.set("trust proxy", true);
app.set("etag", "strong");
app.get('/ip', (request, response) => response.send(request.ip))
@@ -67,29 +68,36 @@ export default async function start() {
max: config.RATE_LIMIT, // limit each IP
standardHeaders: true,
legacyHeaders: false,
// delayMs: 0, // disable delaying - full speed until the max limit is reached
});
const speedLimiter = slowDown({
windowMs: 15 * 60 * 1000, // 15 minutes
delayAfter: 50,
delayMs: 5000,
headers: true,
});
app.use("/github", rate, connection.router);
app.use("/github", rate, speedLimiter, connection.router);
// api routes
app.use("/api/admin", rate, router.admin);
app.use("/api/options", rate, router.option);
app.use("/api/conferences", rate, router.conference);
app.use("/api/user", rate, router.user);
app.use("/api/repo", rate, router.repositoryPublic);
app.use("/api/repo", rate, router.file);
app.use("/api/repo", rate, router.repositoryPrivate);
app.use("/w/", rate, router.webview);
const apiRouter = express.Router()
app.use("/api", rate, speedLimiter, apiRouter);
app.get("/api/message", async (_, res) => {
apiRouter.use("/admin", router.admin);
apiRouter.use("/options", router.option);
apiRouter.use("/conferences", router.conference);
apiRouter.use("/user", router.user);
apiRouter.use("/repo", router.repositoryPublic);
apiRouter.use("/repo", router.file);
apiRouter.use("/repo", router.repositoryPrivate);
apiRouter.get("/message", async (_, res) => {
if (ofs.existsSync("./message.txt")) {
return res.sendFile(path.resolve(__dirname, "..", "message.txt"));
}
res.sendStatus(404);
});
app.get("/api/stat", async (_, res) => {
apiRouter.get("/stat", async (_, res) => {
const nbRepositories =
await AnonymizedRepositoryModel.estimatedDocumentCount();
@@ -97,6 +105,9 @@ export default async function start() {
res.json({ nbRepositories, nbUsers });
});
// web view
app.use("/w/", rate, speedLimiter, router.webview);
app
.get("/", indexResponse)
.get("/404", indexResponse)