Skip to content

Commit 7d7d047

Browse files
committed
feat: implements auto cleanup fix #3
1 parent c62fb3a commit 7d7d047

File tree

7 files changed

+60
-13
lines changed

7 files changed

+60
-13
lines changed

README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,21 @@ You can use any storage you want, but you have to use **shield** as the name of
8282
}
8383
```
8484

85+
### 4. Add `shield:clean` to `nuxt.config.ts`
86+
87+
```json
88+
{
89+
"nitro": {
90+
"experimental": {
91+
"tasks": true
92+
},
93+
"scheduledTasks": {
94+
"*/15 * * * *": ["shield:clean"] // clean the shield storage every 15 minutes
95+
}
96+
}
97+
}
98+
```
99+
85100
## Development
86101

87102
```bash

playground/nuxt.config.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ export default defineNuxtConfig({
44
limit: {
55
max: 12,
66
duration: 10,
7-
ban: 3600,
7+
ban: 30,
88
},
99
},
1010
nitro: {
@@ -15,6 +15,12 @@ export default defineNuxtConfig({
1515
base: ".shield",
1616
},
1717
},
18+
experimental: {
19+
tasks: true,
20+
},
21+
scheduledTasks: {
22+
"* * * * *": ["shield:clean"],
23+
},
1824
},
1925
devtools: { enabled: true },
2026
});
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import isBanExpired from "../../../../src/runtime/server/utils/isBanExpired";
2+
3+
export default defineTask({
4+
meta: {
5+
description: "Clean expired bans",
6+
},
7+
async run() {
8+
const shieldStorage = useStorage("shield");
9+
10+
const keys = await shieldStorage.getKeys();
11+
keys.forEach(async (key) => {
12+
const rateLimit = await shieldStorage.getItem(key);
13+
if (isBanExpired(rateLimit)) {
14+
await shieldStorage.removeItem(key);
15+
}
16+
});
17+
return { result: keys };
18+
},
19+
});

src/runtime/server/middleware/shield.ts

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
1-
import { defineEventHandler, getRequestIP } from "h3";
2-
import { createError, useRuntimeConfig, useStorage } from "#imports";
3-
4-
interface RateLimit {
5-
count: number;
6-
time: number;
7-
}
1+
import { createError, defineEventHandler, getRequestIP } from "h3";
2+
import { useRuntimeConfig, useStorage } from "#imports";
3+
import type { RateLimit } from "../types/RateLimit";
4+
import isBanExpired from "../utils/isBanExpired";
85

96
export default defineEventHandler(async (event) => {
107
if (!event.node.req.url?.startsWith("/api/")) {
@@ -58,11 +55,6 @@ const isNotRateLimited = (req: RateLimit) => {
5855
);
5956
};
6057

61-
const isBanExpired = (req: RateLimit) => {
62-
const options = useRuntimeConfig().public.nuxtApiShield;
63-
return (Date.now() - req.time) / 1000 > options.limit.ban;
64-
};
65-
6658
const banDelay = async (req: RateLimit) => {
6759
const options = useRuntimeConfig().public.nuxtApiShield;
6860

src/runtime/server/tsconfig.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extends": "../.nuxt/tsconfig.server.json"
3+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export type RateLimit = {
2+
count: number;
3+
time: number;
4+
};
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import type { RateLimit } from "../types/RateLimit";
2+
3+
const isBanExpired = (req: RateLimit) => {
4+
const options = useRuntimeConfig().public.nuxtApiShield;
5+
return (Date.now() - req.time) / 1000 > options.limit.ban;
6+
};
7+
8+
export default isBanExpired;

0 commit comments

Comments
 (0)