From 396acf3bbbe00a192cb0ea0a9ccf91b1d8d2850b Mon Sep 17 00:00:00 2001 From: Fuwn <50817549+Fuwn@users.noreply.github.com> Date: Sat, 24 Jan 2026 13:09:50 +0000 Subject: Initial commit Created from https://vercel.com/new --- src/lib/auth.ts | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 src/lib/auth.ts (limited to 'src/lib/auth.ts') diff --git a/src/lib/auth.ts b/src/lib/auth.ts new file mode 100644 index 0000000..ba6d8b0 --- /dev/null +++ b/src/lib/auth.ts @@ -0,0 +1,80 @@ +import debug from 'debug'; +import { ROLE_PERMISSIONS, ROLES, SHARE_TOKEN_HEADER } from '@/lib/constants'; +import { secret } from '@/lib/crypto'; +import { getRandomChars } from '@/lib/generate'; +import { createSecureToken, parseSecureToken, parseToken } from '@/lib/jwt'; +import redis from '@/lib/redis'; +import { ensureArray } from '@/lib/utils'; +import { getUser } from '@/queries/prisma/user'; + +const log = debug('umami:auth'); + +export function getBearerToken(request: Request) { + const auth = request.headers.get('authorization'); + + return auth?.split(' ')[1]; +} + +export async function checkAuth(request: Request) { + const token = getBearerToken(request); + const payload = parseSecureToken(token, secret()); + const shareToken = await parseShareToken(request); + + let user = null; + const { userId, authKey } = payload || {}; + + if (userId) { + user = await getUser(userId); + } else if (redis.enabled && authKey) { + const key = await redis.client.get(authKey); + + if (key?.userId) { + user = await getUser(key.userId); + } + } + + log({ token, payload, authKey, shareToken, user }); + + if (!user?.id && !shareToken) { + log('User not authorized'); + return null; + } + + if (user) { + user.isAdmin = user.role === ROLES.admin; + } + + return { + token, + authKey, + shareToken, + user, + }; +} + +export async function saveAuth(data: any, expire = 0) { + const authKey = `auth:${getRandomChars(32)}`; + + if (redis.enabled) { + await redis.client.set(authKey, data); + + if (expire) { + await redis.client.expire(authKey, expire); + } + } + + return createSecureToken({ authKey }, secret()); +} + +export async function hasPermission(role: string, permission: string | string[]) { + return ensureArray(permission).some(e => ROLE_PERMISSIONS[role]?.includes(e)); +} + +export function parseShareToken(request: Request) { + try { + return parseToken(request.headers.get(SHARE_TOKEN_HEADER), secret()); + } catch (e) { + log(e); + return null; + } +} -- cgit v1.2.3