import { jsonError } from "../../../common.js"; import tokenPrefixes from "../../../../data/token_prefixes.json"; export async function onRequestDelete(context: RequestContext) { const authHeader = context.request.headers.get("authorization"); if (!authHeader) return jsonError("No token provided", 401); const payload = JSON.parse( atob(authHeader.split(".")[1]).replaceAll("-", "+").replaceAll("_", "/"), ); const tokenHash = await crypto.subtle.digest( "SHA-512", new TextEncoder().encode(payload.jti), ); await context.env.DATA.delete( `auth_${btoa(String.fromCharCode(...new Uint8Array(tokenHash))) .replaceAll("+", "-") .replaceAll("/", "_") .replaceAll("=", "")}`, ); return new Response(null, { status: 204, }); } export async function onRequestGet(context: RequestContext) { const { current_user: currentUser } = context.data; if (!currentUser) return jsonError("Unauthorized", 401); const header = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"; const tokenStart = tokenPrefixes[Math.round(Math.random() * (tokenPrefixes.length - 1))] + "_"; const tokenId = tokenStart + `${crypto.randomUUID()}${crypto.randomUUID()}${crypto.randomUUID()}${crypto.randomUUID()}`.replaceAll( "-", "", ); await context.env.DATA.put( `auth_${btoa( String.fromCharCode( ...new Uint8Array( await crypto.subtle.digest( "SHA-512", new TextEncoder().encode(tokenId), ), ), ), ) .replaceAll("+", "-") .replaceAll("/", "_") .replaceAll("=", "")}`, JSON.stringify(currentUser), { expirationTtl: currentUser.expires_in + 1209600, }, ); const claimSet = btoa( JSON.stringify({ email: currentUser.email, email_verified: true, exp: Math.floor(Date.now() / 1000) + currentUser.expires_in, iat: Math.floor(Date.now() / 1000), iss: "https://carcrushers.cc/auth/mobile/token", jti: tokenId, name: currentUser.username, permissions: currentUser.permissions, picture: currentUser.avatar ?? "https://carcrushers.cc/files/logo192.png", sub: currentUser.id, }), ) .replaceAll("+", "-") .replaceAll("/", "_") .replaceAll("=", ""); const key = await crypto.subtle.importKey( "raw", // @ts-ignore Uint8Array.from( atob( context.env.JWT_SIGNING_KEY.replaceAll("-", "+").replaceAll("_", "/"), ), (m) => m.codePointAt(0), ), { hash: "SHA-256", name: "HMAC" }, false, ["sign"], ); const signature = await crypto.subtle.sign( "HMAC", key, new TextEncoder().encode(`${header}.${claimSet}`), ); const encodedSignature = btoa( String.fromCodePoint(...new Uint8Array(signature)), ) .replaceAll("+", "-") .replaceAll("/", "_") .replaceAll("=", ""); return Response.redirect( `com.carcrushers.app://login-callback?token=${header}.${claimSet}.${encodedSignature}`, ); }