diff --git a/functions/_middleware.ts b/functions/_middleware.ts index d0b88c1..9639826 100644 --- a/functions/_middleware.ts +++ b/functions/_middleware.ts @@ -1,3 +1,5 @@ +import { jsonError } from "./common.js"; + async function constructHTML(context: RequestContext) { const { pathname } = new URL(context.request.url); @@ -26,6 +28,56 @@ async function generateTokenHash(token: string) { async function setAuth(context: RequestContext) { const cookies = context.request.headers.get("cookie"); + const auth = context.request.headers.get("authorization"); + + if (auth) { + const jwtSegments = auth.replace("Bearer ", "").split("."); + + if (jwtSegments.length !== 3) return jsonError("Malformed token", 401); + + const { alg } = JSON.parse(atob(jwtSegments[0])); + + if (alg !== "HS256") return jsonError("Invalid token", 400); + + const key = await crypto.subtle.importKey( + "raw", + // @ts-expect-error + Uint8Array.from( + atob( + context.env.JWT_SIGNING_KEY.replaceAll("-", "+").replaceAll("_", "/"), + ), + (m) => m.codePointAt(0), + ), + { hash: "SHA-256", name: "HMAC" }, + false, + ["verify"], + ); + + if ( + !(await crypto.subtle.verify( + "HMAC", + key, + // @ts-expect-error + Uint8Array.from( + atob(jwtSegments[2].replaceAll("-", "+").replaceAll("_", "/")), + (m) => m.codePointAt(0), + ), + new TextEncoder().encode(`${jwtSegments[0]}.${jwtSegments[1]}`), + )) + ) + return jsonError("Token could not be verified", 401); + + const { jti: sessionToken }: { jti: string } = JSON.parse(jwtSegments[1]); + + const linkedSessionData = await context.env.DATA.get( + `auth_${await generateTokenHash(sessionToken)}`, + ); + + if (linkedSessionData) { + context.data.current_user = JSON.parse(linkedSessionData); + return await context.next(); + } else return jsonError("Session is invalid or expired", 401); + } if (!cookies) return await context.next(); @@ -138,5 +190,5 @@ export const onRequest = [ setTheme, constructHTML, setBody, - setHeaders, + setHeaders ];