feat: standalone: improve ratelimit system

This commit is contained in:
tiago
2026-03-01 16:09:32 +00:00
parent 338a01b40d
commit 6b8a816f15
5 changed files with 3 additions and 51 deletions
+1 -1
View File
@@ -16,7 +16,7 @@ export const auth = new Elysia({
.use(
rateLimit({
duration: 30_000,
max: 20_000,
max: 200, // this is intentionally permissive
scoping: "scoped",
generator: ratelimitGenerator,
}),
+1 -1
View File
@@ -129,7 +129,7 @@ export const capServer = new Elysia({
.use(
rateLimit({
scoping: "scoped",
max: 45,
max: 30,
duration: 5_000,
generator: ratelimitGenerator,
}),
-8
View File
@@ -63,12 +63,6 @@ async function initDb() {
primary key (siteKey, token)
)`.simple();
await db`create table if not exists ip_bans (
ip text primary key not null,
reason text not null,
expires integer not null
)`.simple();
await db`create table if not exists api_keys (
id text not null,
name text not null,
@@ -84,7 +78,6 @@ async function initDb() {
await db`delete from sessions where expires < ${now}`;
await db`delete from tokens where expires < ${now}`;
await db`delete from challenge_blocklist where expires < ${now}`;
await db`delete from ip_bans where expires < ${now}`;
} catch (e) {
console.error("failed to cleanup:", e);
}
@@ -95,7 +88,6 @@ async function initDb() {
await db`delete from sessions where expires < ${now}`;
await db`delete from tokens where expires < ${now}`;
await db`delete from challenge_blocklist where expires < ${now}`;
await db`delete from ip_bans where expires < ${now}`;
return db;
}
-10
View File
@@ -1,9 +1,7 @@
import { randomBytes } from "node:crypto";
import { Elysia, t } from "elysia";
import { rateLimit } from "elysia-rate-limit";
import { authBeforeHandle } from "./auth.js";
import { db } from "./db.js";
import { ratelimitGenerator } from "./ratelimit.js";
const keyDefaults = {
difficulty: 4,
@@ -23,14 +21,6 @@ export const server = new Elysia({
],
},
})
.use(
rateLimit({
scoping: "scoped",
max: 150,
duration: 10_000,
generator: ratelimitGenerator,
}),
)
.onBeforeHandle(authBeforeHandle)
.get(
"/keys",
+1 -31
View File
@@ -2,7 +2,6 @@ import { cors } from "@elysiajs/cors";
import { Elysia } from "elysia";
import { db } from "./db.js";
import { ratelimitGenerator } from "./ratelimit.js";
export const siteverifyServer = new Elysia({
detail: {
@@ -15,27 +14,7 @@ export const siteverifyServer = new Elysia({
methods: ["POST"],
}),
)
.post("/:siteKey/siteverify", async ({ body, set, params, request, server }) => {
const ip = ratelimitGenerator(request, server);
const now = Date.now();
if (ip) {
const [ban] = await db`SELECT * FROM ip_bans WHERE ip = ${ip} AND expires > ${now}`;
if (ban) {
const retryAfter = Math.ceil((ban.expires - now) / 1000);
set.status = 429;
set.headers["Retry-After"] = retryAfter.toString();
set.headers["X-RateLimit-Limit"] = "1";
set.headers["X-RateLimit-Remaining"] = "0";
set.headers["X-RateLimit-Reset"] = Math.ceil(ban.expires / 1000).toString();
return {
success: false,
error:
"You were temporarily blocked for using an invalid secret key. Please try again later.",
};
}
}
.post("/:siteKey/siteverify", async ({ body, set, params }) => {
const sitekey = params.siteKey;
const { secret, response } = body;
@@ -54,15 +33,6 @@ export const siteverifyServer = new Elysia({
const isValidSecret = await Bun.password.verify(secret, keyHash);
if (!isValidSecret) {
if (ip) {
const banExpires = now + 1_000;
await db`
INSERT INTO ip_bans (ip, reason, expires)
VALUES (${ip}, ${"invalid_secret"}, ${banExpires})
ON CONFLICT (ip)
DO UPDATE SET reason = ${"invalid_secret"}, expires = ${banExpires}
`;
}
set.status = 403;
return { success: false, error: "Invalid site key or secret" };
}