From 0debc6b415baa466245901fb52c009d09ef3ba15 Mon Sep 17 00:00:00 2001 From: kamtschatka Date: Sat, 19 Oct 2024 22:24:26 +0200 Subject: feature: Log authentication failures to support fail2ban. Fixes #477 (#569) * How do I set the variable "user" or "system" for AI inference #262 changed from system to user * [Feature Request] Log failed login attempts for fail2ban implementation #477 added logging of failed logins * [Feature Request] Log failed login attempts for fail2ban implementation #477 added more logging for extension related logins * Propagte IP to trpc --------- Co-authored-by: Your Name --- apps/web/server/api/client.ts | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) (limited to 'apps/web/server/api') diff --git a/apps/web/server/api/client.ts b/apps/web/server/api/client.ts index 6a0a8909..fb2d84bc 100644 --- a/apps/web/server/api/client.ts +++ b/apps/web/server/api/client.ts @@ -1,4 +1,6 @@ +import { headers } from "next/headers"; import { getServerAuthSession } from "@/server/auth"; +import requestIp from "request-ip"; import { db } from "@hoarder/db"; import { Context, createCallerFactory } from "@hoarder/trpc"; @@ -8,25 +10,46 @@ import { appRouter } from "@hoarder/trpc/routers/_app"; export async function createContextFromRequest(req: Request) { // TODO: This is a hack until we offer a proper REST API instead of the trpc based one. // Check if the request has an Authorization token, if it does, assume that API key authentication is requested. + const ip = requestIp.getClientIp({ + headers: Object.fromEntries(req.headers.entries()), + }); const authorizationHeader = req.headers.get("Authorization"); if (authorizationHeader && authorizationHeader.startsWith("Bearer ")) { const token = authorizationHeader.split(" ")[1]; try { const user = await authenticateApiKey(token); - return { user, db }; + return { + user, + db, + req: { + ip, + }, + }; } catch (e) { // Fallthrough to cookie-based auth } } - return createContext(); + return createContext(db, ip); } -export const createContext = async (database?: typeof db): Promise => { +export const createContext = async ( + database?: typeof db, + ip?: string | null, +): Promise => { const session = await getServerAuthSession(); + if (ip === undefined) { + const hdrs = headers(); + ip = requestIp.getClientIp({ + headers: Object.fromEntries(hdrs.entries()), + }); + } return { user: session?.user ?? null, db: database ?? db, + req: { + ip, + }, }; }; -- cgit v1.2.3-70-g09d2