aboutsummaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
authorkamtschatka <simon.schatka@gmx.at>2024-10-19 22:24:26 +0200
committerGitHub <noreply@github.com>2024-10-19 21:24:26 +0100
commit0debc6b415baa466245901fb52c009d09ef3ba15 (patch)
tree8590ad3849dd2652dd567308f9cc9ace125c691d /apps
parente55362ec57f2a20ed096f971e769269b6f8211c8 (diff)
downloadkarakeep-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.json2
-rw-r--r--apps/web/server/api/client.ts29
-rw-r--r--apps/web/server/auth.ts11
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;
}
},