diff options
| author | kamtschatka <simon.schatka@gmx.at> | 2024-10-19 22:24:26 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-10-19 21:24:26 +0100 |
| commit | 0debc6b415baa466245901fb52c009d09ef3ba15 (patch) | |
| tree | 8590ad3849dd2652dd567308f9cc9ace125c691d /apps | |
| parent | e55362ec57f2a20ed096f971e769269b6f8211c8 (diff) | |
| download | karakeep-0debc6b415baa466245901fb52c009d09ef3ba15.tar.zst | |
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 <you@example.com>
Diffstat (limited to 'apps')
| -rw-r--r-- | apps/web/package.json | 2 | ||||
| -rw-r--r-- | apps/web/server/api/client.ts | 29 | ||||
| -rw-r--r-- | apps/web/server/auth.ts | 11 |
3 files changed, 37 insertions, 5 deletions
diff --git a/apps/web/package.json b/apps/web/package.json index e6691563..cbc01a50 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -68,6 +68,7 @@ "react-syntax-highlighter": "^15.5.0", "remark-breaks": "^4.0.0", "remark-gfm": "^4.0.0", + "request-ip": "^3.3.0", "sharp": "^0.33.3", "superjson": "^2.2.1", "tailwind-merge": "^2.2.1", @@ -83,6 +84,7 @@ "@types/react": "^18.2.55", "@types/react-dom": "^18.2.19", "@types/react-syntax-highlighter": "^15.5.13", + "@types/request-ip": "^0.0.41", "autoprefixer": "^10.4.17", "postcss": "^8.4.35", "tailwindcss": "^3.4.1", 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<Context> => { +export const createContext = async ( + database?: typeof db, + ip?: string | null, +): Promise<Context> => { 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, + }, }; }; diff --git a/apps/web/server/auth.ts b/apps/web/server/auth.ts index 042be1ae..ee226743 100644 --- a/apps/web/server/auth.ts +++ b/apps/web/server/auth.ts @@ -8,6 +8,7 @@ import NextAuth, { } from "next-auth"; import CredentialsProvider from "next-auth/providers/credentials"; import { Provider } from "next-auth/providers/index"; +import requestIp from "request-ip"; import { db } from "@hoarder/db"; import { @@ -17,7 +18,7 @@ import { verificationTokens, } from "@hoarder/db/schema"; import serverConfig from "@hoarder/shared/config"; -import { validatePassword } from "@hoarder/trpc/auth"; +import { logAuthenticationError, validatePassword } from "@hoarder/trpc/auth"; type UserRole = "admin" | "user"; @@ -77,7 +78,7 @@ const providers: Provider[] = [ email: { label: "Email", type: "email", placeholder: "Email" }, password: { label: "Password", type: "password" }, }, - async authorize(credentials) { + async authorize(credentials, req) { if (!credentials) { return null; } @@ -88,6 +89,12 @@ const providers: Provider[] = [ credentials?.password, ); } catch (e) { + const error = e as Error; + logAuthenticationError( + credentials?.email, + error.message, + requestIp.getClientIp({ headers: req.headers }), + ); return null; } }, |
