feat: standalone: improve ratelimit system
This commit is contained in:
@@ -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,
|
||||
}),
|
||||
|
||||
@@ -129,7 +129,7 @@ export const capServer = new Elysia({
|
||||
.use(
|
||||
rateLimit({
|
||||
scoping: "scoped",
|
||||
max: 45,
|
||||
max: 30,
|
||||
duration: 5_000,
|
||||
generator: ratelimitGenerator,
|
||||
}),
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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" };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user