From 1083f8beb5df3e26bafc5eeb319af7347dc4b8e9 Mon Sep 17 00:00:00 2001 From: JackAttack-365 <142643773+jackattack-4@users.noreply.github.com> Date: Tue, 6 Jan 2026 19:31:41 -0800 Subject: [PATCH 1/2] should work need to adjust --- src/lib/middleware/requireAuth.ts | 43 +++++++++++++++++++++++-------- src/redisClient.ts | 3 ++- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/src/lib/middleware/requireAuth.ts b/src/lib/middleware/requireAuth.ts index 22a07730..a5c5bd81 100644 --- a/src/lib/middleware/requireAuth.ts +++ b/src/lib/middleware/requireAuth.ts @@ -4,6 +4,7 @@ import { User } from "@prisma/client"; import { Request as ExpressRequest, Response, NextFunction } from "express"; import * as jose from "jose"; import { createHash } from "crypto"; +import { kv } from "../../redisClient.js"; export interface AuthenticatedRequest extends ExpressRequest { user: User; @@ -127,6 +128,12 @@ export const requireAuth = async ( }, }); + kv.del(`auth:user:${user.id}`); + + kv.set(`auth:user:${user.id}`, JSON.stringify(user), { + ex: 60 * 15, // wait 15 minutes before expiry (we can change this later) + }); + // Add user to request req.user = user; req.tokenType = "jwt"; @@ -134,20 +141,34 @@ export const requireAuth = async ( next(); } catch (error) { console.log("Using existing"); - const user = await prisma.user.findUnique({ - where: { - id: userId, - }, - }); + console.error(error); + + if (kv.get(`auth:user:${userId}`) !== null) { + req.user = JSON.parse( + (await kv.get(`auth:user:${userId}`)) as string, + ) as User; + + next(); + } else { + const user = await prisma.user.findUnique({ + where: { + id: userId, + }, + }); - if (!user) { - res.status(500).send("Internal server error"); - return; - } + if (!user) { + res.status(401).send("User not found"); + return; + } - req.user = user; + kv.set(`auth:user:${user.id}`, JSON.stringify(user), { + ex: 60 * 15, + }); - next(); + req.user = user; + + next(); + } } } catch (error) { console.error(error); diff --git a/src/redisClient.ts b/src/redisClient.ts index 6220288f..53844f2a 100644 --- a/src/redisClient.ts +++ b/src/redisClient.ts @@ -7,8 +7,9 @@ const redis = createClient({ url: process.env.REDIS_URL }) const set = async ( key: string, data: string, + options?: Record, ): ReturnType["set"]> => { - return await (await redis).set(key, data); + return await (await redis).set(key, data, options ?? {}) ; }; const get = async (key: string): ReturnType["get"]> => { From f825472234f55364a0b4ab3a27b65e02519d5211 Mon Sep 17 00:00:00 2001 From: JackAttack-365 <142643773+jackattack-4@users.noreply.github.com> Date: Thu, 8 Jan 2026 17:42:33 -0800 Subject: [PATCH 2/2] update requireAuth --- src/lib/middleware/requireAuth.ts | 108 +++++++++++++++++------------- src/redisClient.ts | 22 +++--- 2 files changed, 69 insertions(+), 61 deletions(-) diff --git a/src/lib/middleware/requireAuth.ts b/src/lib/middleware/requireAuth.ts index a5c5bd81..bc82c760 100644 --- a/src/lib/middleware/requireAuth.ts +++ b/src/lib/middleware/requireAuth.ts @@ -35,18 +35,23 @@ export const requireAuth = async ( const keyHash = createHash("sha256").update(tokenString).digest("hex"); - const rateLimit = await prisma.apiKey.findUnique({ - where: { - keyHash: keyHash, - }, - }); + const keyRowValue = await kv.get(`auth:apikey:${keyHash}:lastused`); + + let rateLimit = + keyRowValue !== null + ? ( + await prisma.apiKey.findUnique({ where: { keyHash: keyHash } }) + ).lastUsed.getTime() + : parseInt(keyRowValue as string); - if (Date.now() - rateLimit.lastUsed.getTime() <= 3 * 1000) { + if (Date.now() - rateLimit <= 3 * 1000) { res.status(429).json({ message: "You have exceeded the rate limit for an API Key. Please wait before making more requests.", retryAfterSeconds: 3, }); + + return; } const apiKey = await prisma.apiKey.update({ @@ -69,6 +74,13 @@ export const requireAuth = async ( return; } + await kv.set( + `auth:apikey:${keyHash}:lastused`, + apiKey.lastUsed.getTime().toString(), { + expiration: {type: "EX", value: 60 * 15}, + } + ); + req.user = apiKey.user; req.tokenType = "apiKey"; @@ -97,56 +109,58 @@ export const requireAuth = async ( // Get user info from Auth0 try { - const authResponse = await axios.get( - `https://${process.env.AUTH0_DOMAIN}/userinfo`, - { - headers: { - Authorization: `Bearer ${tokenString}`, - "Content-Type": "application/json", + const userRow = await kv.get(`auth:user:${userId}`); + if (userRow !== null) { + req.user = JSON.parse((await userRow) as string) as User; + + next(); + } else { + const authResponse = await axios.get( + `https://${process.env.AUTH0_DOMAIN}/userinfo`, + { + headers: { + Authorization: `Bearer ${tokenString}`, + "Content-Type": "application/json", + }, }, - }, - ); + ); - console.log("Updating"); - // Get JSON - const authData = authResponse.data; + console.log("Updating"); + // Get JSON + const authData = authResponse.data; - // Update database - const user = await prisma.user.upsert({ - where: { - id: userId, - }, - update: { - email: authData.email, - emailVerified: authData.email_verified, - }, - create: { - id: userId, - email: authData.email, - emailVerified: authData.email_verified, - role: "ANALYST", - }, - }); - - kv.del(`auth:user:${user.id}`); + // Update database + const user = await prisma.user.upsert({ + where: { + id: userId, + }, + update: { + email: authData.email, + emailVerified: authData.email_verified, + }, + create: { + id: userId, + email: authData.email, + emailVerified: authData.email_verified, + role: "ANALYST", + } + }); - kv.set(`auth:user:${user.id}`, JSON.stringify(user), { - ex: 60 * 15, // wait 15 minutes before expiry (we can change this later) - }); + kv.set(`auth:user:${user.id}`, JSON.stringify(user), { + expiration: {type: "EX", value: 60 * 15}, + }); - // Add user to request - req.user = user; - req.tokenType = "jwt"; + req.user = user; - next(); + next(); + } } catch (error) { console.log("Using existing"); console.error(error); - if (kv.get(`auth:user:${userId}`) !== null) { - req.user = JSON.parse( - (await kv.get(`auth:user:${userId}`)) as string, - ) as User; + const userRow = await kv.get(`auth:user:${userId}`); + if (userRow !== null) { + req.user = JSON.parse((await userRow) as string) as User; next(); } else { @@ -162,7 +176,7 @@ export const requireAuth = async ( } kv.set(`auth:user:${user.id}`, JSON.stringify(user), { - ex: 60 * 15, + expiration: {type: "EX", value: 60 * 15}, }); req.user = user; diff --git a/src/redisClient.ts b/src/redisClient.ts index 53844f2a..9e2e6e40 100644 --- a/src/redisClient.ts +++ b/src/redisClient.ts @@ -4,26 +4,20 @@ const redis = createClient({ url: process.env.REDIS_URL }) .on("error", (err) => console.log("Redis Client Error", err)) .connect(); -const set = async ( - key: string, - data: string, - options?: Record, -): ReturnType["set"]> => { - return await (await redis).set(key, data, options ?? {}) ; +const set: Awaited["set"] = async (...args) => { + return await (await redis).set(...args) ; }; -const get = async (key: string): ReturnType["get"]> => { - return await (await redis).get(key); +const get: Awaited["get"] = async (...args) => { + return await (await redis).get(...args) ; }; -const del = async ( - key: string[] | string, -): ReturnType["del"]> => { - return await (await redis).del(key); +const del: Awaited["del"] = async (...args) => { + return await (await redis).del(...args) ; }; -const flush = async (): ReturnType["flushDb"]> => { - return await (await redis).flushDb(); +const flush: Awaited["flushDb"] = async (...args) => { + return await (await redis).flushDb(...args) ; }; export const kv = {