ratelimiting via "withRateLimit"

This commit is contained in:
Oliver Bryan
2026-01-21 23:04:38 +00:00
parent be57b4d6df
commit f780725a23
3 changed files with 199 additions and 47 deletions

View File

@@ -1,4 +1,5 @@
import { withAuth, withCors, withCSRF } from "./auth/middleware";
import type { BunRequest } from "bun";
import { withAuth, withCors, withCSRF, withRateLimit } from "./auth/middleware";
import { testDB } from "./db/client";
import { cleanupExpiredSessions } from "./db/queries";
import { routes } from "./routes";
@@ -20,69 +21,73 @@ const startSessionCleanup = () => {
setInterval(cleanup, SESSION_CLEANUP_INTERVAL);
};
type RouteHandler<T extends BunRequest = BunRequest> = (req: T) => Response | Promise<Response>;
const withGlobal = <T extends BunRequest>(handler: RouteHandler<T>) => withCors(withRateLimit(handler));
const main = async () => {
const server = Bun.serve({
port: Number(PORT),
routes: {
"/": withCors(() => new Response(`title: tnirps\ndev-mode: ${DEV}\nport: ${PORT}`)),
"/health": withCors(() => new Response("OK")),
"/": withGlobal(() => new Response(`title: tnirps\ndev-mode: ${DEV}\nport: ${PORT}`)),
"/health": withGlobal(() => new Response("OK")),
// routes that modify state require withCSRF middleware
"/auth/register": withCors(routes.authRegister),
"/auth/login": withCors(routes.authLogin),
"/auth/logout": withCors(withAuth(withCSRF(routes.authLogout))),
"/auth/me": withCors(withAuth(routes.authMe)),
"/auth/register": withGlobal(routes.authRegister),
"/auth/login": withGlobal(routes.authLogin),
"/auth/logout": withGlobal(withAuth(withCSRF(routes.authLogout))),
"/auth/me": withGlobal(withAuth(routes.authMe)),
"/user/by-username": withCors(withAuth(routes.userByUsername)),
"/user/update": withCors(withAuth(withCSRF(routes.userUpdate))),
"/user/upload-avatar": withCors(withAuth(withCSRF(routes.userUploadAvatar))),
"/user/by-username": withGlobal(withAuth(routes.userByUsername)),
"/user/update": withGlobal(withAuth(withCSRF(routes.userUpdate))),
"/user/upload-avatar": withGlobal(withAuth(withCSRF(routes.userUploadAvatar))),
"/issue/create": withCors(withAuth(withCSRF(routes.issueCreate))),
"/issue/update": withCors(withAuth(withCSRF(routes.issueUpdate))),
"/issue/delete": withCors(withAuth(withCSRF(routes.issueDelete))),
"/issue-comment/create": withCors(withAuth(withCSRF(routes.issueCommentCreate))),
"/issue-comment/delete": withCors(withAuth(withCSRF(routes.issueCommentDelete))),
"/issue/create": withGlobal(withAuth(withCSRF(routes.issueCreate))),
"/issue/update": withGlobal(withAuth(withCSRF(routes.issueUpdate))),
"/issue/delete": withGlobal(withAuth(withCSRF(routes.issueDelete))),
"/issue-comment/create": withGlobal(withAuth(withCSRF(routes.issueCommentCreate))),
"/issue-comment/delete": withGlobal(withAuth(withCSRF(routes.issueCommentDelete))),
"/issues/by-project": withCors(withAuth(routes.issuesByProject)),
"/issues/replace-status": withCors(withAuth(withCSRF(routes.issuesReplaceStatus))),
"/issues/status-count": withCors(withAuth(routes.issuesStatusCount)),
"/issues/all": withCors(withAuth(routes.issues)),
"/issue-comments/by-issue": withCors(withAuth(routes.issueCommentsByIssue)),
"/issues/by-project": withGlobal(withAuth(routes.issuesByProject)),
"/issues/replace-status": withGlobal(withAuth(withCSRF(routes.issuesReplaceStatus))),
"/issues/status-count": withGlobal(withAuth(routes.issuesStatusCount)),
"/issues/all": withGlobal(withAuth(routes.issues)),
"/issue-comments/by-issue": withGlobal(withAuth(routes.issueCommentsByIssue)),
"/organisation/create": withCors(withAuth(withCSRF(routes.organisationCreate))),
"/organisation/by-id": withCors(withAuth(routes.organisationById)),
"/organisation/update": withCors(withAuth(withCSRF(routes.organisationUpdate))),
"/organisation/delete": withCors(withAuth(withCSRF(routes.organisationDelete))),
"/organisation/upload-icon": withCors(withAuth(withCSRF(routes.organisationUploadIcon))),
"/organisation/add-member": withCors(withAuth(withCSRF(routes.organisationAddMember))),
"/organisation/members": withCors(withAuth(routes.organisationMembers)),
"/organisation/remove-member": withCors(withAuth(withCSRF(routes.organisationRemoveMember))),
"/organisation/update-member-role": withCors(
"/organisation/create": withGlobal(withAuth(withCSRF(routes.organisationCreate))),
"/organisation/by-id": withGlobal(withAuth(routes.organisationById)),
"/organisation/update": withGlobal(withAuth(withCSRF(routes.organisationUpdate))),
"/organisation/delete": withGlobal(withAuth(withCSRF(routes.organisationDelete))),
"/organisation/upload-icon": withGlobal(withAuth(withCSRF(routes.organisationUploadIcon))),
"/organisation/add-member": withGlobal(withAuth(withCSRF(routes.organisationAddMember))),
"/organisation/members": withGlobal(withAuth(routes.organisationMembers)),
"/organisation/remove-member": withGlobal(withAuth(withCSRF(routes.organisationRemoveMember))),
"/organisation/update-member-role": withGlobal(
withAuth(withCSRF(routes.organisationUpdateMemberRole)),
),
"/organisations/by-user": withCors(withAuth(routes.organisationsByUser)),
"/organisations/by-user": withGlobal(withAuth(routes.organisationsByUser)),
"/project/create": withCors(withAuth(withCSRF(routes.projectCreate))),
"/project/update": withCors(withAuth(withCSRF(routes.projectUpdate))),
"/project/delete": withCors(withAuth(withCSRF(routes.projectDelete))),
"/project/with-creator": withCors(withAuth(routes.projectWithCreator)),
"/project/create": withGlobal(withAuth(withCSRF(routes.projectCreate))),
"/project/update": withGlobal(withAuth(withCSRF(routes.projectUpdate))),
"/project/delete": withGlobal(withAuth(withCSRF(routes.projectDelete))),
"/project/with-creator": withGlobal(withAuth(routes.projectWithCreator)),
"/projects/by-creator": withCors(withAuth(routes.projectsByCreator)),
"/projects/by-organisation": withCors(withAuth(routes.projectsByOrganisation)),
"/projects/all": withCors(withAuth(routes.projectsAll)),
"/projects/with-creators": withCors(withAuth(routes.projectsWithCreators)),
"/projects/by-creator": withGlobal(withAuth(routes.projectsByCreator)),
"/projects/by-organisation": withGlobal(withAuth(routes.projectsByOrganisation)),
"/projects/all": withGlobal(withAuth(routes.projectsAll)),
"/projects/with-creators": withGlobal(withAuth(routes.projectsWithCreators)),
"/sprint/create": withCors(withAuth(withCSRF(routes.sprintCreate))),
"/sprint/update": withCors(withAuth(withCSRF(routes.sprintUpdate))),
"/sprint/delete": withCors(withAuth(withCSRF(routes.sprintDelete))),
"/sprints/by-project": withCors(withAuth(routes.sprintsByProject)),
"/sprint/create": withGlobal(withAuth(withCSRF(routes.sprintCreate))),
"/sprint/update": withGlobal(withAuth(withCSRF(routes.sprintUpdate))),
"/sprint/delete": withGlobal(withAuth(withCSRF(routes.sprintDelete))),
"/sprints/by-project": withGlobal(withAuth(routes.sprintsByProject)),
"/timer/toggle": withCors(withAuth(withCSRF(routes.timerToggle))),
"/timer/end": withCors(withAuth(withCSRF(routes.timerEnd))),
"/timer/get": withCors(withAuth(withCSRF(routes.timerGet))),
"/timer/get-inactive": withCors(withAuth(withCSRF(routes.timerGetInactive))),
"/timers": withCors(withAuth(withCSRF(routes.timers))),
"/timer/toggle": withGlobal(withAuth(withCSRF(routes.timerToggle))),
"/timer/end": withGlobal(withAuth(withCSRF(routes.timerEnd))),
"/timer/get": withGlobal(withAuth(withCSRF(routes.timerGet))),
"/timer/get-inactive": withGlobal(withAuth(withCSRF(routes.timerGetInactive))),
"/timers": withGlobal(withAuth(withCSRF(routes.timers))),
},
});