From b6c051f3cbed3585a7f82cf214de05e2f0652e7b Mon Sep 17 00:00:00 2001 From: regalijan Date: Thu, 19 Oct 2023 16:51:16 -0400 Subject: [PATCH] Let's hope i didn't break anything --- functions/_middleware.ts | 94 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 90 insertions(+), 4 deletions(-) diff --git a/functions/_middleware.ts b/functions/_middleware.ts index 9639826..1cd5b26 100644 --- a/functions/_middleware.ts +++ b/functions/_middleware.ts @@ -1,3 +1,4 @@ +import getPermissions from "./permissions.js"; import { jsonError } from "./common.js"; async function constructHTML(context: RequestContext) { @@ -26,6 +27,80 @@ async function generateTokenHash(token: string) { .replace(/=/g, ""); } +async function refreshAuth(context: RequestContext) { + const { current_user: currentUser } = context.data; + + if (!currentUser || currentUser.refresh_at > Date.now()) + return await context.next(); + + const refreshedTokenResponse = await fetch( + "https://discord.com/api/v10/oauth2/token", + { + body: `grant_type=refresh_token&refresh_token=${currentUser.refresh_token}`, + headers: { + authorization: `Basic ${btoa( + context.env.DISCORD_ID + ":" + context.env.DISCORD_SECRET, + )}`, + "content-type": "application/x-www-form-urlencoded", + }, + method: "POST", + }, + ); + + if (!refreshedTokenResponse.ok) return await context.next(); + + const accessData: { [k: string]: any } = await refreshedTokenResponse.json(); + + let userData: { [k: string]: any } = { + ...accessData, + refresh_at: Date.now() + 3600000, + }; + + const newDiscordData = await fetch("https://discord.com/api/v10/users/@me", { + headers: { + authorization: `Bearer ${accessData.access_token}`, + }, + }); + + if (!newDiscordData.ok) return await context.next(); + + userData = { + ...userData, + ...(await newDiscordData.json()), + }; + + const updatedServerMemberReq = await fetch( + "https://discord.com/api/v10/users/@me/guilds/242263977986359297/member", + { + headers: { + authorization: `Bearer ${accessData.access_token}`, + }, + }, + ); + + userData.permissions = await getPermissions( + userData.id, + context, + updatedServerMemberReq.ok + ? ( + (await updatedServerMemberReq.json()) as { + [k: string]: any; + } + ).roles + : undefined, + ); + + const tokenHash = await generateTokenHash(context.data.sid); + + await context.env.DATA.put(`auth_${tokenHash}`, JSON.stringify(userData), { + expirationTtl: accessData.expires_in, + }); + + delete context.data.sid; + + return await context.next(); +} + async function setAuth(context: RequestContext) { const cookies = context.request.headers.get("cookie"); const auth = context.request.headers.get("authorization"); @@ -67,7 +142,13 @@ async function setAuth(context: RequestContext) { ) return jsonError("Token could not be verified", 401); - const { jti: sessionToken }: { jti: string } = JSON.parse(jwtSegments[1]); + const { + jti: sessionToken, + }: { + jti: string; + } = JSON.parse( + atob(jwtSegments[1].replaceAll("-", "+").replaceAll("_", "/")), + ); const linkedSessionData = await context.env.DATA.get( `auth_${await generateTokenHash(sessionToken)}`, @@ -75,6 +156,8 @@ async function setAuth(context: RequestContext) { if (linkedSessionData) { context.data.current_user = JSON.parse(linkedSessionData); + context.data.sid = sessionToken; + return await context.next(); } else return jsonError("Session is invalid or expired", 401); } @@ -92,8 +175,10 @@ async function setAuth(context: RequestContext) { `auth_${await generateTokenHash(value)}`, ); - if (userData) context.data.current_user = JSON.parse(userData); - else + if (userData) { + context.data.current_user = JSON.parse(userData); + context.data.sid = value; + } else context.request.headers.append( "set-cookie", "_s=; HttpOnly; Max-Age=0; Path=/; Secure;", @@ -187,8 +272,9 @@ async function setTheme(context: RequestContext) { export const onRequest = [ setAuth, + refreshAuth, setTheme, constructHTML, setBody, - setHeaders + setHeaders, ];