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 /packages | |
| 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 'packages')
| -rw-r--r-- | packages/shared/logger.ts | 19 | ||||
| -rw-r--r-- | packages/trpc/auth.ts | 11 | ||||
| -rw-r--r-- | packages/trpc/index.ts | 6 | ||||
| -rw-r--r-- | packages/trpc/routers/apiKeys.ts | 27 | ||||
| -rw-r--r-- | packages/trpc/testUtils.ts | 3 |
5 files changed, 59 insertions, 7 deletions
diff --git a/packages/shared/logger.ts b/packages/shared/logger.ts index f406b447..f3aa3cb9 100644 --- a/packages/shared/logger.ts +++ b/packages/shared/logger.ts @@ -15,3 +15,22 @@ const logger = winston.createLogger({ }); export default logger; + +export const authFailureLogger = winston.createLogger({ + level: "debug", + format: winston.format.combine( + winston.format.timestamp(), + winston.format.printf( + (info) => `${info.timestamp} ${info.level}: ${info.message}`, + ), + ), + transports: [ + new winston.transports.Console(), + new winston.transports.File({ + filename: "auth_failures.log", + dirname: serverConfig.dataDir, + maxFiles: 2, + maxsize: 1024 * 1024, + }), + ], +}); diff --git a/packages/trpc/auth.ts b/packages/trpc/auth.ts index 39aebd3b..1efbdde6 100644 --- a/packages/trpc/auth.ts +++ b/packages/trpc/auth.ts @@ -4,6 +4,7 @@ import * as bcrypt from "bcryptjs"; import { db } from "@hoarder/db"; import { apiKeys } from "@hoarder/db/schema"; import serverConfig from "@hoarder/shared/config"; +import { authFailureLogger } from "@hoarder/shared/logger"; // API Keys @@ -102,3 +103,13 @@ export async function validatePassword(email: string, password: string) { return user; } + +export function logAuthenticationError( + user: string, + message: string, + ip: string | null, +): void { + authFailureLogger.error( + `Authentication error. User: "${user}", Message: "${message}", IP-Address: "${ip}"`, + ); +} diff --git a/packages/trpc/index.ts b/packages/trpc/index.ts index 5f351a8e..26d8ea96 100644 --- a/packages/trpc/index.ts +++ b/packages/trpc/index.ts @@ -15,11 +15,17 @@ interface User { export interface Context { user: User | null; db: typeof db; + req: { + ip: string | null; + }; } export interface AuthedContext { user: User; db: typeof db; + req: { + ip: string | null; + }; } // Avoid exporting the entire t-object diff --git a/packages/trpc/routers/apiKeys.ts b/packages/trpc/routers/apiKeys.ts index b7468dd2..c55dc095 100644 --- a/packages/trpc/routers/apiKeys.ts +++ b/packages/trpc/routers/apiKeys.ts @@ -5,7 +5,12 @@ import { z } from "zod"; import { apiKeys } from "@hoarder/db/schema"; import serverConfig from "@hoarder/shared/config"; -import { authenticateApiKey, generateApiKey, validatePassword } from "../auth"; +import { + authenticateApiKey, + generateApiKey, + logAuthenticationError, + validatePassword, +} from "../auth"; import { authedProcedure, publicProcedure, router } from "../index"; const zApiKeySchema = z.object({ @@ -73,7 +78,7 @@ export const apiKeysAppRouter = router({ }), ) .output(zApiKeySchema) - .mutation(async ({ input }) => { + .mutation(async ({ input, ctx }) => { let user; // Special handling as otherwise the extension would show "username or password is wrong" if (serverConfig.auth.disablePasswordAuth) { @@ -85,6 +90,8 @@ export const apiKeysAppRouter = router({ try { user = await validatePassword(input.email, input.password); } catch (e) { + const error = e as Error; + logAuthenticationError(input.email, error.message, ctx.req.ip); throw new TRPCError({ code: "UNAUTHORIZED" }); } return await generateApiKey(input.keyName, user.id); @@ -92,10 +99,16 @@ export const apiKeysAppRouter = router({ validate: publicProcedure .input(z.object({ apiKey: z.string() })) .output(z.object({ success: z.boolean() })) - .mutation(async ({ input }) => { - await authenticateApiKey(input.apiKey); // Throws if the key is invalid - return { - success: true, - }; + .mutation(async ({ input, ctx }) => { + try { + await authenticateApiKey(input.apiKey); // Throws if the key is invalid + return { + success: true, + }; + } catch (e) { + const error = e as Error; + logAuthenticationError("<unknown>", error.message, ctx.req.ip); + throw e; + } }), }); diff --git a/packages/trpc/testUtils.ts b/packages/trpc/testUtils.ts index 04e6b0a3..23dcdb33 100644 --- a/packages/trpc/testUtils.ts +++ b/packages/trpc/testUtils.ts @@ -37,6 +37,9 @@ export function getApiCaller(db: TestDB, userId?: string, email?: string) { } : null, db, + req: { + ip: null, + }, }); } |
