From 19df67079a58e98ac6d8267778d1f1df0529b39c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jozef=20Steinh=C3=BCbl?= Date: Sat, 3 Aug 2024 20:23:12 +0200 Subject: [PATCH] refactor: switch to lucia --- apps/website/.example.dev.vars | 6 ++ apps/website/.gitignore | 3 + apps/website/astro.config.ts | 9 +- apps/website/bun.lockb | Bin 363327 -> 286113 bytes apps/website/migrations/0001_auth.sql | 18 ++++ apps/website/package.json | 6 +- .../src/components/dashboard/UserInfo.astro | 22 +--- apps/website/src/env.d.ts | 25 ++++- apps/website/src/lib/auth.ts | 54 ++++++++++ apps/website/src/lib/guilds.ts | 26 ++--- apps/website/src/lib/user.ts | 10 +- apps/website/src/middleware.ts | 40 +++++++ apps/website/src/pages/api/user/guilds.ts | 7 +- .../src/pages/auth/callback/discord.ts | 100 ++++++++++++++++++ apps/website/src/pages/auth/login.astro | 15 --- apps/website/src/pages/auth/login.ts | 20 ++++ apps/website/src/pages/auth/logout.astro | 16 --- apps/website/src/pages/auth/logout.ts | 20 ++++ .../src/pages/dashboard/guilds/[id].astro | 6 +- apps/website/src/pages/dashboard/index.astro | 4 + apps/website/tsconfig.json | 5 +- apps/website/worker-configuration.d.ts | 11 ++ apps/website/wrangler.toml | 6 ++ 23 files changed, 335 insertions(+), 94 deletions(-) create mode 100644 apps/website/.example.dev.vars create mode 100644 apps/website/migrations/0001_auth.sql create mode 100644 apps/website/src/lib/auth.ts create mode 100644 apps/website/src/middleware.ts create mode 100644 apps/website/src/pages/auth/callback/discord.ts delete mode 100644 apps/website/src/pages/auth/login.astro create mode 100644 apps/website/src/pages/auth/login.ts delete mode 100644 apps/website/src/pages/auth/logout.astro create mode 100644 apps/website/src/pages/auth/logout.ts create mode 100644 apps/website/worker-configuration.d.ts create mode 100644 apps/website/wrangler.toml diff --git a/apps/website/.example.dev.vars b/apps/website/.example.dev.vars new file mode 100644 index 0000000..754628a --- /dev/null +++ b/apps/website/.example.dev.vars @@ -0,0 +1,6 @@ +PRO= + +DISCORD_CLIENT_ID= +DISCORD_CLIENT_SECRET= +DISCORD_BOT_TOKEN= +DISCORD_REDIRECT_URI=/auth/callback/discord diff --git a/apps/website/.gitignore b/apps/website/.gitignore index 6d4c0aa..57729bd 100644 --- a/apps/website/.gitignore +++ b/apps/website/.gitignore @@ -19,3 +19,6 @@ pnpm-debug.log* # macOS-specific files .DS_Store + +.dev.vars +.wrangler/ diff --git a/apps/website/astro.config.ts b/apps/website/astro.config.ts index 94fb94e..2c9091c 100644 --- a/apps/website/astro.config.ts +++ b/apps/website/astro.config.ts @@ -5,7 +5,6 @@ import preact from "@astrojs/preact"; import sitemap from "@astrojs/sitemap"; import tailwind from "@astrojs/tailwind"; import cloudflare from "@astrojs/cloudflare"; -import auth from "auth-astro"; import { CONFIG } from "./src/config"; @@ -14,17 +13,17 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url)); // https://astro.build/config export default defineConfig({ site: CONFIG.origin, - integrations: [sitemap(), tailwind(), auth(), preact()], + integrations: [sitemap(), tailwind(), preact()], output: "server", adapter: cloudflare(), + security: { + checkOrigin: true, + }, vite: { resolve: { alias: { "~": path.resolve(__dirname, "./src"), }, }, - ssr: { - external: ["node:path", "path", "os", "crypto"], - }, }, }); diff --git a/apps/website/bun.lockb b/apps/website/bun.lockb index 04bf4048430d01c4bff0fcce9bca2dec6269501d..9cfc3b040c289cfb12ff4b9d4e2220c09c8701bd 100755 GIT binary patch delta 61815 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 diff --git a/apps/website/migrations/0001_auth.sql b/apps/website/migrations/0001_auth.sql new file mode 100644 index 0000000..799cb93 --- /dev/null +++ b/apps/website/migrations/0001_auth.sql @@ -0,0 +1,18 @@ +-- Migration number: 0001 2024-08-03T15:43:57.349Z + +CREATE TABLE IF NOT EXISTS user ( + id TEXT NOT NULL PRIMARY KEY, + discord_id TEXT NOT NULL UNIQUE, + username TEXT NOT NULL, + avatar TEXT NOT NULL, + access_token TEXT NOT NULL, + access_token_expiration NUMBER NOT NULL, + refresh_token TEXT NOT NULL +); + +CREATE TABLE IF NOT EXISTS session ( + id TEXT NOT NULL PRIMARY KEY, + expires_at INTEGER NOT NULL, + user_id TEXT NOT NULL, + FOREIGN KEY (user_id) REFERENCES user (id) +); diff --git a/apps/website/package.json b/apps/website/package.json index c6424d3..5de2235 100644 --- a/apps/website/package.json +++ b/apps/website/package.json @@ -14,13 +14,13 @@ "@astrojs/prefetch": "^0.2.1", "@astrojs/sitemap": "^3.1.6", "@astrojs/tailwind": "^5.1.0", - "@auth/core": "^0.32.0", + "@lucia-auth/adapter-sqlite": "^3.0.2", "@tailwindcss/typography": "^0.5.9", + "arctic": "^1.9.2", "astro": "^4.11.5", "astro-google-fonts-optimizer": "^0.2.2", "astro-icon": "^0.8.0", - "auth-astro": "^4.1.2", - "dotenv": "^16.4.5", + "lucia": "^3.2.0", "preact": "^10.23.1", "tailwindcss": "^3.3.1" }, diff --git a/apps/website/src/components/dashboard/UserInfo.astro b/apps/website/src/components/dashboard/UserInfo.astro index 7261fc1..88cf86b 100644 --- a/apps/website/src/components/dashboard/UserInfo.astro +++ b/apps/website/src/components/dashboard/UserInfo.astro @@ -1,28 +1,12 @@ --- import { Image } from "astro:assets"; -import type { User } from "~/env"; -import { getUser } from "~/lib/user"; -interface Props { - user?: User; -} - -let user: User; -if (!Astro.props.user) { - const u = await getUser(Astro.request); - if (!u) { - return Astro.redirect("/auth/login"); - } - - user = u; -} else { - user = Astro.props.user; -} +const user = Astro.locals.user; ---

icon

- @{user.name} + @{user.username}

diff --git a/apps/website/src/env.d.ts b/apps/website/src/env.d.ts index 1bcd6b7..6577947 100644 --- a/apps/website/src/env.d.ts +++ b/apps/website/src/env.d.ts @@ -1,10 +1,13 @@ /// -import type { User as AuthCoreUser } from "@auth/core/types"; - -export type User = AuthCoreUser & { - global_name: string; - discordAccessToken: string; +type D1Database = import("@cloudflare/workers-types").D1Database; +type ENV = { + GITHUB_APP_NAME: string; + DISCORD_CLIENT_ID: string; + DISCORD_CLIENT_SECRET: string; + DISCORD_BOT_TOKEN: string; + DISCORD_REDIRECT_URI: string; + DB: D1Database; }; export interface Guild { @@ -19,3 +22,15 @@ export interface MutualeGuild { mutual: boolean; guild: Guild; } + +type Runtime = import("@astrojs/cloudflare").Runtime; + +// https://github.com/withastro/astro/issues/7394#issuecomment-1975657601 +declare namespace App { + interface Locals extends Runtime { + discord: import("arctic").Discord; + lucia: import("lucia").Lucia; + session: import("lucia").Session | null; + user: import("lucia").User | null; + } +} diff --git a/apps/website/src/lib/auth.ts b/apps/website/src/lib/auth.ts new file mode 100644 index 0000000..c7fa454 --- /dev/null +++ b/apps/website/src/lib/auth.ts @@ -0,0 +1,54 @@ +import { Lucia } from "lucia"; +import { D1Adapter } from "@lucia-auth/adapter-sqlite"; +import { Discord } from "arctic"; + +export function initializeLucia(D1: D1Database) { + const adapter = new D1Adapter(D1, { + user: "user", + session: "session", + }); + return new Lucia(adapter, { + sessionCookie: { + attributes: { + // set to `true` when using HTTPS + secure: import.meta.env.PROD, + }, + }, + getUserAttributes: (attributes) => { + return { + discordId: attributes.discord_id, + username: attributes.username, + avatar: attributes.avatar, + sensitive: { + accessToken: attributes.access_token, + refreshToken: attributes.refresh_token, + accessTokenExpiresAt: attributes.access_token_expiration, + }, + }; + }, + }); +} + +export function initializeDiscord( + discordClientId: string, + discordClientSecret: string, + redirectUri: string +) { + return new Discord(discordClientId, discordClientSecret, redirectUri); +} + +declare module "lucia" { + interface Register { + Lucia: ReturnType; + DatabaseUserAttributes: DatabaseUserAttributes; + } +} + +interface DatabaseUserAttributes { + discord_id: number; + username: string; + avatar: string; + access_token: string; + refresh_token: string; + access_token_expiration: number; +} diff --git a/apps/website/src/lib/guilds.ts b/apps/website/src/lib/guilds.ts index b7996f9..502c7da 100644 --- a/apps/website/src/lib/guilds.ts +++ b/apps/website/src/lib/guilds.ts @@ -1,24 +1,25 @@ -import type { Guild, MutualeGuild, User } from "~/env"; +import type { Guild, MutualeGuild } from "~/env"; import { isUserEligible } from "./user"; export async function getGuild( - user: User, - guildId: string + user, + guildId: string, + env ): Promise { const guilds = await getUserGuilds(user); const guild = guilds.find((g) => g.id === guildId); - if (!guild || !(await isMutualGuild(guild))) return undefined; + if (!guild || !(await isMutualGuild(guild, env))) return undefined; return guild; } -export async function getUserGuilds(user: User): Promise { +export async function getUserGuilds(user): Promise { const discordApiGuildsResponse = await fetch( "https://discord.com/api/v10/users/@me/guilds", { headers: { - Authorization: `Bearer ${user.discordAccessToken as string}`, + Authorization: `Bearer ${user.sensitive.accessToken as string}`, "Cache-Control": "max-age=300", }, } @@ -28,7 +29,8 @@ export async function getUserGuilds(user: User): Promise { } export async function filterUserGuilds( - guilds: Guild[] + guilds: Guild[], + env ): Promise { const filtered = guilds .filter(isUserEligible) @@ -37,7 +39,7 @@ export async function filterUserGuilds( const result: MutualeGuild[] = []; for (const guild of filtered) { - const mutual = await isMutualGuild(guild); + const mutual = await isMutualGuild(guild, env); result.push({ mutual, guild }); } @@ -47,14 +49,12 @@ export async function filterUserGuilds( return result; } -export async function isMutualGuild(guild: Guild): Promise { +export async function isMutualGuild(guild: Guild, env): Promise { const res = await fetch( - `https://discord.com/api/v10/guilds/${guild.id}/members/${ - import.meta.env.DISCORD_CLIENT_ID - }`, + `https://discord.com/api/v10/guilds/${guild.id}/members/${env.DISCORD_CLIENT_ID}`, { headers: { - Authorization: `Bot ${import.meta.env.DISCORD_BOT_TOKEN}`, + Authorization: `Bot ${env.DISCORD_BOT_TOKEN}`, }, } ); diff --git a/apps/website/src/lib/user.ts b/apps/website/src/lib/user.ts index de9ea56..a98dab3 100644 --- a/apps/website/src/lib/user.ts +++ b/apps/website/src/lib/user.ts @@ -1,12 +1,4 @@ -import { getSession } from "auth-astro/server"; -import type { Guild, User } from "~/env"; - -export async function getUser(req: Request): Promise { - const session = await getSession(req); - if (!session || !session.user) return null; - - return session.user as User; -} +import type { Guild } from "~/env"; // Checks if user has AMDINISTRATOR permissions in the guild export function isUserEligible(guild: Guild): boolean { diff --git a/apps/website/src/middleware.ts b/apps/website/src/middleware.ts new file mode 100644 index 0000000..7c50700 --- /dev/null +++ b/apps/website/src/middleware.ts @@ -0,0 +1,40 @@ +import { initializeLucia, initializeDiscord } from "./lib/auth"; +import { defineMiddleware } from "astro:middleware"; + +export const onRequest = defineMiddleware(async (context, next) => { + const lucia = initializeLucia(context.locals.runtime.env.DB); + context.locals.lucia = lucia; + const discord = initializeDiscord( + context.locals.runtime.env.DISCORD_CLIENT_ID, + context.locals.runtime.env.DISCORD_CLIENT_SECRET, + context.locals.runtime.env.DISCORD_REDIRECT_URI + ); + context.locals.discord = discord; + const sessionId = context.cookies.get(lucia.sessionCookieName)?.value ?? null; + if (!sessionId) { + context.locals.user = null; + context.locals.session = null; + return next(); + } + + const { session, user } = await lucia.validateSession(sessionId); + if (session && session.fresh) { + const sessionCookie = lucia.createSessionCookie(session.id); + context.cookies.set( + sessionCookie.name, + sessionCookie.value, + sessionCookie.attributes + ); + } + if (!session) { + const sessionCookie = lucia.createBlankSessionCookie(); + context.cookies.set( + sessionCookie.name, + sessionCookie.value, + sessionCookie.attributes + ); + } + context.locals.session = session; + context.locals.user = user; + return next(); +}); diff --git a/apps/website/src/pages/api/user/guilds.ts b/apps/website/src/pages/api/user/guilds.ts index 13a3a47..8328a71 100644 --- a/apps/website/src/pages/api/user/guilds.ts +++ b/apps/website/src/pages/api/user/guilds.ts @@ -1,9 +1,8 @@ import type { APIRoute } from "astro"; import { filterUserGuilds, getUserGuilds } from "~/lib/guilds"; -import { getUser } from "~/lib/user"; -export const GET: APIRoute = async ({ request }) => { - const user = await getUser(request); +export const GET: APIRoute = async ({ locals }) => { + const user = locals.user; if (!user) { return new Response(null, { status: 401, @@ -11,7 +10,7 @@ export const GET: APIRoute = async ({ request }) => { } const guilds = await getUserGuilds(user); - const res = await filterUserGuilds(guilds); + const res = await filterUserGuilds(guilds, locals.runtime.env); return Response.json(res); }; diff --git a/apps/website/src/pages/auth/callback/discord.ts b/apps/website/src/pages/auth/callback/discord.ts new file mode 100644 index 0000000..e180945 --- /dev/null +++ b/apps/website/src/pages/auth/callback/discord.ts @@ -0,0 +1,100 @@ +import { OAuth2RequestError } from "arctic"; +import type { APIContext } from "astro"; +import { generateIdFromEntropySize } from "lucia"; + +type UserRow = { + id: string; +}; + +export async function GET(context: APIContext): Promise { + const code = context.url.searchParams.get("code"); + const state = context.url.searchParams.get("state"); + const storedState = context.cookies.get("discord_oauth_state")?.value ?? null; + if (!code || !state || !storedState || state !== storedState) { + return new Response(null, { + status: 400, + }); + } + + try { + const tokens = await context.locals.discord.validateAuthorizationCode(code); + const disocrdUserResponse = await fetch( + "https://discord.com/api/users/@me", + { + headers: { + Authorization: `Bearer ${tokens.accessToken}`, + }, + } + ); + + const discordUser: DiscordUser = await disocrdUserResponse.json(); + + const existingUser = await context.locals.runtime.env.DB.prepare( + "SELECT * FROM user WHERE discord_id = ?1" + ) + .bind(discordUser.id) + .first(); + + if (existingUser) { + const session = await context.locals.lucia.createSession( + existingUser.id, + {} + ); + + const sessionCookie = context.locals.lucia.createSessionCookie( + session.id + ); + + context.cookies.set( + sessionCookie.name, + sessionCookie.value, + sessionCookie.attributes + ); + return context.redirect("/dashboard"); + } + + const userId = generateIdFromEntropySize(10); // 16 characters long + + await context.locals.runtime.env.DB.prepare( + "INSERT INTO user (id, discord_id, username, avatar, access_token, access_token_expiration, refresh_token) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)" + ) + .bind( + userId, + discordUser.id, + discordUser.username, + discordUser.avatar, + tokens.accessToken, + tokens.accessTokenExpiresAt.getTime(), + tokens.refreshToken + ) + .run(); + + const session = await context.locals.lucia.createSession(userId, {}); + const sessionCookie = context.locals.lucia.createSessionCookie(session.id); + context.cookies.set( + sessionCookie.name, + sessionCookie.value, + sessionCookie.attributes + ); + return context.redirect("/dashboard"); + } catch (e) { + console.error(e.message); + + // the specific error message depends on the provider + if (e instanceof OAuth2RequestError) { + // invalid code + return new Response(null, { + status: 400, + }); + } + return new Response(null, { + status: 500, + }); + } +} + +interface DiscordUser { + id: string; + username: string; + avatar: string; +} diff --git a/apps/website/src/pages/auth/login.astro b/apps/website/src/pages/auth/login.astro deleted file mode 100644 index 9598ec1..0000000 --- a/apps/website/src/pages/auth/login.astro +++ /dev/null @@ -1,15 +0,0 @@ ---- -import Layout from "~/layouts/Layout.astro"; - -export const prerender = true; ---- - - - - diff --git a/apps/website/src/pages/auth/login.ts b/apps/website/src/pages/auth/login.ts new file mode 100644 index 0000000..1e63010 --- /dev/null +++ b/apps/website/src/pages/auth/login.ts @@ -0,0 +1,20 @@ +import { generateState } from "arctic"; + +import type { APIContext } from "astro"; + +export async function GET(context: APIContext): Promise { + const state = generateState(); + const url = await context.locals.discord.createAuthorizationURL(state, { + scopes: ["identify", "guilds"], + }); + + context.cookies.set("discord_oauth_state", state, { + path: "/", + secure: import.meta.env.PROD, + httpOnly: true, + maxAge: 60 * 10, + sameSite: "lax", + }); + + return context.redirect(url.toString()); +} diff --git a/apps/website/src/pages/auth/logout.astro b/apps/website/src/pages/auth/logout.astro deleted file mode 100644 index eb95095..0000000 --- a/apps/website/src/pages/auth/logout.astro +++ /dev/null @@ -1,16 +0,0 @@ ---- -import Layout from "~/layouts/Layout.astro"; - -export const prerender = true; ---- - - - - diff --git a/apps/website/src/pages/auth/logout.ts b/apps/website/src/pages/auth/logout.ts new file mode 100644 index 0000000..4cbaaa7 --- /dev/null +++ b/apps/website/src/pages/auth/logout.ts @@ -0,0 +1,20 @@ +import type { APIContext } from "astro"; + +export async function GET(context: APIContext): Promise { + if (!context.locals.session) { + return new Response(null, { + status: 401, + }); + } + + await context.locals.lucia.invalidateSession(context.locals.session.id); + + const sessionCookie = context.locals.lucia.createBlankSessionCookie(); + context.cookies.set( + sessionCookie.name, + sessionCookie.value, + sessionCookie.attributes + ); + + return context.redirect("/"); +} diff --git a/apps/website/src/pages/dashboard/guilds/[id].astro b/apps/website/src/pages/dashboard/guilds/[id].astro index 088bf70..cfadc13 100644 --- a/apps/website/src/pages/dashboard/guilds/[id].astro +++ b/apps/website/src/pages/dashboard/guilds/[id].astro @@ -1,15 +1,15 @@ --- import { getGuild } from "~/lib/guilds"; -import { getUser, isUserEligible } from "~/lib/user"; +import { isUserEligible } from "~/lib/user"; const { id } = Astro.params; -const user = await getUser(Astro.request); +const user = Astro.locals.user; if (!user || !id) { return Astro.redirect("/auth/login"); } -const guild = await getGuild(user, id); +const guild = await getGuild(user, id, Astro.locals.runtime.env); if (!guild) { return Astro.redirect("/dashboard"); } diff --git a/apps/website/src/pages/dashboard/index.astro b/apps/website/src/pages/dashboard/index.astro index 3165a2f..5533745 100644 --- a/apps/website/src/pages/dashboard/index.astro +++ b/apps/website/src/pages/dashboard/index.astro @@ -3,6 +3,10 @@ import Layout from "~/layouts/Layout.astro"; import Container from "~/components/Container.astro"; import GuildSelector from "~/components/preact/GuildSelector"; import UserInfo from "~/components/dashboard/UserInfo.astro"; + +if (!Astro.locals.user) { + return Astro.redirect("/auth/login"); +} --- diff --git a/apps/website/tsconfig.json b/apps/website/tsconfig.json index 8543cd5..f35cf4f 100644 --- a/apps/website/tsconfig.json +++ b/apps/website/tsconfig.json @@ -1,11 +1,12 @@ { - "extends": "astro/tsconfigs/base", + "extends": "astro/tsconfigs/strictest", "compilerOptions": { "strictNullChecks": true, "allowJs": true, "baseUrl": ".", "paths": { "~/*": ["src/*"] - } + }, + "types": ["./src/env.d.ts"] } } diff --git a/apps/website/worker-configuration.d.ts b/apps/website/worker-configuration.d.ts new file mode 100644 index 0000000..94aec6d --- /dev/null +++ b/apps/website/worker-configuration.d.ts @@ -0,0 +1,11 @@ +// Generated by Wrangler on Sat Aug 03 2024 17:34:42 GMT+0200 (Central European Summer Time) +// by running `wrangler types` + +interface Env { + PRO: string; + DISCORD_CLIENT_ID: string; + DISCORD_CLIENT_SECRET: string; + DISCORD_BOT_TOKEN: string; + DISCORD_REDIRECT_URI: string; + DB: D1Database; +} diff --git a/apps/website/wrangler.toml b/apps/website/wrangler.toml new file mode 100644 index 0000000..644039c --- /dev/null +++ b/apps/website/wrangler.toml @@ -0,0 +1,6 @@ +name = "roles-bot" + +[[d1_databases]] +binding = "DB" # i.e. available in your Worker on env.DB +database_name = "roles-bot-dashboard" +database_id = "fdc6f902-9142-44bf-9be9-b38d351ffd27"