diff --git a/server/package.json b/server/package.json index c1bbe36..1d11842 100644 --- a/server/package.json +++ b/server/package.json @@ -15,6 +15,7 @@ "@types/debug": "^4.1.7", "@types/email-validator": "^1.0.6", "@types/express": "^4.17.17", + "@types/express-rate-limit": "^6.0.0", "@types/express-session": "^1.17.6", "@types/node": "^18.14.4", "@types/passport": "^1.0.12", @@ -32,6 +33,7 @@ "expiry-set": "^1.0.0", "express": "^4.18.2", "express-openid-connect": "^2.12.1", + "express-rate-limit": "^6.7.0", "express-session": "^1.17.3", "idb-keyval": "^6.2.0", "jsonwebtoken": "^9.0.0", diff --git a/server/src/index.ts b/server/src/index.ts index b5ffb48..e6eee6e 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -46,7 +46,9 @@ export default class ChatServer { constructor() { this.app = express(); - + } + + async initialize() { this.app.use(express.urlencoded({ extended: false })); if (process.env.AUTH0_CLIENT_ID && process.env.AUTH0_ISSUER && process.env.PUBLIC_URL) { @@ -71,6 +73,14 @@ export default class ChatServer { next(); }); + const { default: rateLimit } = await import('express-rate-limit'); // esm + const limiter = rateLimit({ + windowMs: 15 * 60 * 1000, // 15 minutes + max: 100, // limit each IP to 100 requests per windowMs + }); + + this.app.use(limiter); + this.app.get('/chatapi/health', (req, res) => new HealthRequestHandler(this, req, res)); this.app.get('/chatapi/session', (req, res) => new SessionRequestHandler(this, req, res)); this.app.post('/chatapi/messages', (req, res) => new MessagesRequestHandler(this, req, res)); @@ -92,9 +102,7 @@ export default class ChatServer { res.sendFile('public/index.html', { root: path.resolve(__dirname, '..') }); }); } - } - async initialize() { await this.objectStore.initialize(); await this.database.initialize();