docs: add spam protection implementation plan
This commit is contained in:
parent
2e19540db4
commit
b98ef0b714
1 changed files with 174 additions and 0 deletions
174
docs/superpowers/plans/2026-05-11-spam-protection.md
Normal file
174
docs/superpowers/plans/2026-05-11-spam-protection.md
Normal file
|
|
@ -0,0 +1,174 @@
|
||||||
|
# Spam Protection Implementation Plan
|
||||||
|
|
||||||
|
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||||
|
|
||||||
|
**Goal:** Limit each user to max 5 dienst requests per day, with automatic daily reset.
|
||||||
|
|
||||||
|
**Architecture:** In-memory rate limiter module that tracks request counts per user per day. Integrated into the message handler pipeline before dienst lookup. Sends a friendly warning when limit is exceeded.
|
||||||
|
|
||||||
|
**Tech Stack:** Node.js, no new dependencies needed
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 1: Create rate limiter module
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Create: `src/rateLimiter.js`
|
||||||
|
|
||||||
|
- [ ] **Step 1: Create `src/rateLimiter.js`**
|
||||||
|
|
||||||
|
```js
|
||||||
|
const MAX_REQUESTS_PER_DAY = parseInt(process.env.MAX_REQUESTS_PER_DAY, 10) || 5
|
||||||
|
|
||||||
|
const userCounts = new Map()
|
||||||
|
let currentDate = new Date().toDateString()
|
||||||
|
|
||||||
|
function resetIfNeeded() {
|
||||||
|
const today = new Date().toDateString()
|
||||||
|
if (today !== currentDate) {
|
||||||
|
userCounts.clear()
|
||||||
|
currentDate = today
|
||||||
|
console.log('Rate limiter: daily counters reset')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkLimit(userId) {
|
||||||
|
resetIfNeeded()
|
||||||
|
const count = userCounts.get(userId) || 0
|
||||||
|
return {
|
||||||
|
allowed: count < MAX_REQUESTS_PER_DAY,
|
||||||
|
count,
|
||||||
|
max: MAX_REQUESTS_PER_DAY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function increment(userId) {
|
||||||
|
resetIfNeeded()
|
||||||
|
const count = (userCounts.get(userId) || 0) + 1
|
||||||
|
userCounts.set(userId, count)
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { checkLimit, increment, MAX_REQUESTS_PER_DAY }
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add src/rateLimiter.js
|
||||||
|
git commit -m "feat: add rate limiter module"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 2: Integrate rate limiter into message handler
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `src/messageHandler.js:1,25-36`
|
||||||
|
|
||||||
|
- [ ] **Step 1: Add rate limiter import at top of `src/messageHandler.js`**
|
||||||
|
|
||||||
|
Add after line 2:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const { checkLimit, increment, MAX_REQUESTS_PER_DAY } = require('./rateLimiter')
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Add rate limit check in `handleWebhook` after dienstnummer extraction**
|
||||||
|
|
||||||
|
Insert between the `dienstnummer` null check (line 36) and the `console.log` (line 38), replacing lines 38-40 with:
|
||||||
|
|
||||||
|
```js
|
||||||
|
console.log(`Processing dienst ${dienstnummer} for ${message.author}`)
|
||||||
|
|
||||||
|
const author = message.author
|
||||||
|
if (!author) return
|
||||||
|
|
||||||
|
const limit = checkLimit(author)
|
||||||
|
if (!limit.allowed) {
|
||||||
|
await sendTextMessage(author, `Je hebt vandaag het maximum van ${limit.max} diensten bereikt. Probeer het morgen opnieuw.`)
|
||||||
|
console.log(`Rate limit reached for ${author} (${limit.count}/${limit.max})`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
increment(author)
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 3: Verify the file looks correct**
|
||||||
|
|
||||||
|
Run: `node -e "require('./src/messageHandler')"` (should not throw)
|
||||||
|
|
||||||
|
- [ ] **Step 4: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add src/messageHandler.js
|
||||||
|
git commit -m "feat: integrate rate limiter into message handler"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 3: Add config to .env and restart
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `.env`
|
||||||
|
- Modify: `.env.example`
|
||||||
|
|
||||||
|
- [ ] **Step 1: Add `MAX_REQUESTS_PER_DAY` to `.env`**
|
||||||
|
|
||||||
|
Append to `.env`:
|
||||||
|
|
||||||
|
```
|
||||||
|
# Rate limiting
|
||||||
|
MAX_REQUESTS_PER_DAY=5
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Add `MAX_REQUESTS_PER_DAY` to `.env.example`**
|
||||||
|
|
||||||
|
Append to `.env.example`:
|
||||||
|
|
||||||
|
```
|
||||||
|
# Rate limiting
|
||||||
|
MAX_REQUESTS_PER_DAY=5
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 3: Restart bot and verify**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx pm2 restart dienst-bot && npx pm2 save
|
||||||
|
npx pm2 logs dienst-bot --lines 5 --nostream
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: bot starts without errors, logs show listening on port 3002.
|
||||||
|
|
||||||
|
- [ ] **Step 4: Commit and push**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add .env.example
|
||||||
|
git commit -m "feat: add rate limiting config option"
|
||||||
|
git push
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 4: Update README
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `README.md`
|
||||||
|
|
||||||
|
- [ ] **Step 1: Add rate limiting section to README.md**
|
||||||
|
|
||||||
|
Add after the "Foutafhandeling" section:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## Spam protectie
|
||||||
|
|
||||||
|
Elke gebruiker kan maximaal `MAX_REQUESTS_PER_DAY` (standaard 5) diensten per dag opvragen. Bij overschrijding krijgt de gebruiker een melding. De teller wordt dagelijks automatisch gereset (bij de eerste request na middernacht).
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Commit and push**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add README.md
|
||||||
|
git commit -m "docs: add spam protection section to README"
|
||||||
|
git push
|
||||||
|
```
|
||||||
Loading…
Reference in a new issue