From 82687eb4ede0e88c6d848dfa5fdc1231e927b742 Mon Sep 17 00:00:00 2001 From: bricked Date: Wed, 9 Oct 2024 21:03:10 +0200 Subject: [PATCH] feat: move account pages from club page --- src/actions/index.ts | 11 ++++++++ src/actions/login.ts | 36 +++++++++++++++++++++++++ src/actions/logout.ts | 15 +++++++++++ src/actions/settings.ts | 36 +++++++++++++++++++++++++ src/actions/signup.ts | 34 +++++++++++++++++++++++ src/assets/icon.png | Bin 0 -> 58751 bytes src/env.d.ts | 6 +++++ src/layouts/Layout.astro | 57 +++++++++++++++++++++++++++++++++++++++ src/lib/auth/index.ts | 34 +++++++++++++++++++++++ src/lib/db/index.ts | 2 ++ src/lib/db/init.ts | 7 +++++ src/lib/db/schema.ts | 19 +++++++++++++ src/lib/schema/index.ts | 13 +++++++++ src/middleware.ts | 32 ++++++++++++++++++++++ src/pages/404.astro | 10 +++++++ src/pages/500.astro | 11 ++++++++ src/pages/index.astro | 5 ++++ src/pages/login.astro | 18 +++++++++++++ src/pages/settings.astro | 40 +++++++++++++++++++++++++++ src/pages/signup.astro | 34 +++++++++++++++++++++++ 20 files changed, 420 insertions(+) create mode 100644 src/actions/index.ts create mode 100644 src/actions/login.ts create mode 100644 src/actions/logout.ts create mode 100644 src/actions/settings.ts create mode 100644 src/actions/signup.ts create mode 100644 src/assets/icon.png create mode 100644 src/env.d.ts create mode 100644 src/layouts/Layout.astro create mode 100644 src/lib/auth/index.ts create mode 100644 src/lib/db/index.ts create mode 100644 src/lib/db/init.ts create mode 100644 src/lib/db/schema.ts create mode 100644 src/lib/schema/index.ts create mode 100644 src/middleware.ts create mode 100644 src/pages/404.astro create mode 100644 src/pages/500.astro create mode 100644 src/pages/index.astro create mode 100644 src/pages/login.astro create mode 100644 src/pages/settings.astro create mode 100644 src/pages/signup.astro diff --git a/src/actions/index.ts b/src/actions/index.ts new file mode 100644 index 0000000..602f7fd --- /dev/null +++ b/src/actions/index.ts @@ -0,0 +1,11 @@ +import { login } from "./login"; +import { signup } from "./signup"; +import { settings } from "./settings"; +import { logout } from "./logout"; + +export const server = { + login, + signup, + settings, + logout, +}; diff --git a/src/actions/login.ts b/src/actions/login.ts new file mode 100644 index 0000000..89b151f --- /dev/null +++ b/src/actions/login.ts @@ -0,0 +1,36 @@ +import { ActionError, defineAction } from "astro:actions"; +import { z } from "astro:schema"; +import { slug } from "@lib/schema"; +import { db, users } from "@lib/db"; +import { lucia, hashOptions } from "@lib/auth/index"; +import { verify } from "@node-rs/argon2"; +import { eq } from "drizzle-orm"; + +export const login = defineAction({ + accept: "form", + input: z.object({ + slug: slug(), + password: z.string(), + }), + handler: async ({ slug, password }, { cookies }) => { + const authError = new ActionError({ + code: "BAD_REQUEST", + message: "The entered slug or password is incorrect.", + }); + + const [user] = await db.select().from(users).where(eq(users.slug, slug)); + if (!user) throw authError; + + const passwordValid = await verify(user.password, password, hashOptions); + if (!passwordValid) throw authError; + + const session = await lucia.createSession(user.id, {}); + const sessionCookie = lucia.createSessionCookie(session.id); + + cookies.set( + sessionCookie.name, + sessionCookie.value, + sessionCookie.attributes, + ); + }, +}); diff --git a/src/actions/logout.ts b/src/actions/logout.ts new file mode 100644 index 0000000..99546aa --- /dev/null +++ b/src/actions/logout.ts @@ -0,0 +1,15 @@ +import { ActionError, defineAction } from "astro:actions"; +import { lucia } from "@lib/auth/index"; + +export const logout = defineAction({ + accept: "form", + handler: async (_, { locals: { user, session } }) => { + if (!user || !session) + throw new ActionError({ + code: "UNAUTHORIZED", + message: "You must be logged in to log out.", + }); + + await lucia.invalidateSession(session.id); + }, +}); diff --git a/src/actions/settings.ts b/src/actions/settings.ts new file mode 100644 index 0000000..6097b24 --- /dev/null +++ b/src/actions/settings.ts @@ -0,0 +1,36 @@ +import { ActionError, defineAction } from "astro:actions"; +import { z } from "astro:schema"; +import { emptyString, slug } from "@lib/schema"; +import { db, users } from "@lib/db"; +import { hashOptions } from "@lib/auth/index"; +import { hash } from "@node-rs/argon2"; +import { eq } from "drizzle-orm"; + +export const settings = defineAction({ + accept: "form", + input: z.object({ + name: emptyString().nullable().or(z.string()), + slug: emptyString().nullable().or(slug()), + password: emptyString().nullable().or(z.string()), + }), + handler: async ({ name, slug, password }, { locals: { user } }) => { + if (!user) + throw new ActionError({ + code: "UNAUTHORIZED", + message: "You need to be logged in to edit your preferences.", + }); + + if (name == user.name) name = null; + if (slug == user.slug) slug = null; + if (!(name || slug || password)) return; + + await db + .update(users) + .set({ + name: name ?? undefined, + slug: slug ?? undefined, + password: password ? await hash(password, hashOptions) : undefined, + }) + .where(eq(users.id, user.id)); + }, +}); diff --git a/src/actions/signup.ts b/src/actions/signup.ts new file mode 100644 index 0000000..cb33a7f --- /dev/null +++ b/src/actions/signup.ts @@ -0,0 +1,34 @@ +import { defineAction } from "astro:actions"; +import { z } from "astro:schema"; +import { slug } from "@lib/schema"; +import { db, users } from "@lib/db"; +import { lucia, hashOptions } from "@lib/auth/index"; +import { hash } from "@node-rs/argon2"; +import { generateIdFromEntropySize } from "lucia"; + +export const signup = defineAction({ + accept: "form", + input: z.object({ + name: z.string(), + slug: slug(), + password: z.string(), + }), + handler: async ({ name, slug, password }, { cookies }) => { + const id = generateIdFromEntropySize(10); + await db.insert(users).values({ + id, + name, + slug, + password: await hash(password, hashOptions), + }); + + const session = await lucia.createSession(id, {}); + const sessionCookie = lucia.createSessionCookie(session.id); + + cookies.set( + sessionCookie.name, + sessionCookie.value, + sessionCookie.attributes, + ); + }, +}); diff --git a/src/assets/icon.png b/src/assets/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..1e8957bbf176e9b524eb660f4ed9447711723d73 GIT binary patch literal 58751 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
  • VLF?DDw6WLM_ z;uKl*t3r2T=+-6pln_F32Eld9YmG@ID3@aF>`1rDDsx3AwpXZ}m!K}E4lMt5cJS6G z$%qpE*JpAL`{)WJa%06M`zD0%0D8WUJhy?+>DYIY%cmrBj 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 literal 0 HcmV?d00001 diff --git a/src/env.d.ts b/src/env.d.ts new file mode 100644 index 0000000..4fa3ab7 --- /dev/null +++ b/src/env.d.ts @@ -0,0 +1,6 @@ +declare namespace App { + interface Locals { + session: import("lucia").Session | null; + user: import("lucia").User | null; + } +} diff --git a/src/layouts/Layout.astro b/src/layouts/Layout.astro new file mode 100644 index 0000000..fe80f59 --- /dev/null +++ b/src/layouts/Layout.astro @@ -0,0 +1,57 @@ +--- +import Icon from "@assets/icon.png"; +import "@fontsource-variable/baloo-2"; +import Header from "@fancade-club/comps/layouts/Header.astro"; +import Footer from "@fancade-club/comps/layouts/Footer.astro"; +import Disclaimer from "@fancade-club/comps/layouts/Disclaimer.astro"; +import NavLink from "@fancade-club/comps/layouts/NavLink.astro" + +interface Props { + title?: string; + description?: string; +} + +const { title = "", description = "" } = Astro.props; + +const metaDescription = + description || + "The Fancade Club is a worldwide community of Fancade enthusiasts. Join and become a member today!"; + +const metaTitle = (title && title + " - ") + "Fancade Club Account"; +--- + + + + + + + + + + {metaTitle} + + +
    Club
    +
    + {title &&

    {title}

    } + +
    +
    + + + + diff --git a/src/lib/auth/index.ts b/src/lib/auth/index.ts new file mode 100644 index 0000000..febea58 --- /dev/null +++ b/src/lib/auth/index.ts @@ -0,0 +1,34 @@ +import { Lucia } from "lucia"; +import { DrizzlePostgreSQLAdapter } from "@lucia-auth/adapter-drizzle"; +import { db, sessions, users } from "@lib/db"; + +export const adapter = new DrizzlePostgreSQLAdapter(db, sessions, users); + +export const lucia = new Lucia(adapter, { + sessionCookie: { + attributes: { + secure: import.meta.env.PROD, + }, + }, + getUserAttributes: ({ name, slug }) => ({ + name, + slug, + }), +}); + +export const hashOptions = { + memoryCost: 19456, + timeCost: 2, + hashLength: 32, + parallelism: 1, +}; + +declare module "lucia" { + interface Register { + Lucia: typeof lucia; + DatabaseUserAttributes: { + name: string; + slug: string; + }; + } +} diff --git a/src/lib/db/index.ts b/src/lib/db/index.ts new file mode 100644 index 0000000..c85094f --- /dev/null +++ b/src/lib/db/index.ts @@ -0,0 +1,2 @@ +export * from "./schema"; +export * from "./init"; diff --git a/src/lib/db/init.ts b/src/lib/db/init.ts new file mode 100644 index 0000000..520ce89 --- /dev/null +++ b/src/lib/db/init.ts @@ -0,0 +1,7 @@ +import { neon } from "@neondatabase/serverless"; +import { drizzle } from "drizzle-orm/neon-http"; +import { DATABASE_URL } from "astro:env/server"; + +export const sql = neon(DATABASE_URL); +export const db = drizzle(sql); +export type DB = typeof db; diff --git a/src/lib/db/schema.ts b/src/lib/db/schema.ts new file mode 100644 index 0000000..72ee7bc --- /dev/null +++ b/src/lib/db/schema.ts @@ -0,0 +1,19 @@ +import { pgTable, text, timestamp } from "drizzle-orm/pg-core"; + +export const users = pgTable("users", { + id: text("id").primaryKey(), + slug: text("slug").unique().notNull(), + password: text("password").notNull(), + name: text("name").notNull(), +}); + +export const sessions = pgTable("sessions", { + id: text("id").primaryKey(), + userId: text("user_id") + .notNull() + .references(() => users.id), + expiresAt: timestamp("expires_at", { + withTimezone: true, + mode: "date", + }).notNull(), +}); diff --git a/src/lib/schema/index.ts b/src/lib/schema/index.ts new file mode 100644 index 0000000..f3147b6 --- /dev/null +++ b/src/lib/schema/index.ts @@ -0,0 +1,13 @@ +import { z } from "astro:schema"; +import slugify from "@sindresorhus/slugify"; +import zxcvbn from "zxcvbn"; + +export const emptyString = () => z.literal("").transform(() => null); + +export const slug = () => + z.preprocess( + (val) => slugify(z.string().parse(val)), + z.string().min(3).max(16), + ); + +export const password = () => z.string().refine((val) => zxcvbn(val).score > 4); diff --git a/src/middleware.ts b/src/middleware.ts new file mode 100644 index 0000000..c23f8af --- /dev/null +++ b/src/middleware.ts @@ -0,0 +1,32 @@ +import { lucia } from "@lib/auth"; +import { defineMiddleware } from "astro:middleware"; + +export const onRequest = defineMiddleware(async (context, next) => { + 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/src/pages/404.astro b/src/pages/404.astro new file mode 100644 index 0000000..191cc01 --- /dev/null +++ b/src/pages/404.astro @@ -0,0 +1,10 @@ +--- +import Layout from "@layouts/Layout.astro"; +--- + + +

    + The page you tried to access doesn't exist. In case you tried to access a + distinct service, it's likely it doesn't exist yet, or hasn't been approved. +

    +
    diff --git a/src/pages/500.astro b/src/pages/500.astro new file mode 100644 index 0000000..cde2a6c --- /dev/null +++ b/src/pages/500.astro @@ -0,0 +1,11 @@ +--- +import Layout from "@layouts/Layout.astro"; +--- + + +

    + An internal server error occured while rendering this page. Please contribute by reporting this bug and describe the sequence of actions that lead you here. +

    +
    diff --git a/src/pages/index.astro b/src/pages/index.astro new file mode 100644 index 0000000..264e557 --- /dev/null +++ b/src/pages/index.astro @@ -0,0 +1,5 @@ +--- +const { user } = Astro.locals; +if (user) return Astro.redirect("/settings"); +else return Astro.redirect("/signup"); +--- diff --git a/src/pages/login.astro b/src/pages/login.astro new file mode 100644 index 0000000..73a7fa8 --- /dev/null +++ b/src/pages/login.astro @@ -0,0 +1,18 @@ +--- +import { actions } from "astro:actions"; +import Layout from "@layouts/Layout.astro"; +import Form from "@fancade-club/comps/forms/Form.astro"; +import Input from "@fancade-club/comps/forms/Input.astro"; +import Button from "@fancade-club/comps/forms/Button.astro"; + +if (Astro.locals.user) return Astro.redirect("/account"); +--- + + +
    + + + +
    +

    Not a member yet? Sign up!

    +
    diff --git a/src/pages/settings.astro b/src/pages/settings.astro new file mode 100644 index 0000000..ab872e5 --- /dev/null +++ b/src/pages/settings.astro @@ -0,0 +1,40 @@ +--- +import Layout from "@layouts/Layout.astro"; +import Form from "@fancade-club/comps/forms/Form.astro"; +import Input from "@fancade-club/comps/forms/Input.astro"; +import Button from "@fancade-club/comps/forms/Button.astro"; +import { actions } from "astro:actions"; + +const { user } = Astro.locals; +if (!user) return Astro.redirect("/signup"); +--- + + +
    + + + + +
    +

    Account Management

    +
    + +
    +
    + + diff --git a/src/pages/signup.astro b/src/pages/signup.astro new file mode 100644 index 0000000..c285641 --- /dev/null +++ b/src/pages/signup.astro @@ -0,0 +1,34 @@ +--- +import { actions } from "astro:actions"; +import Layout from "@layouts/Layout.astro"; +import Form from "@fancade-club/comps/forms/Form.astro"; +import Input from "@fancade-club/comps/forms/Input.astro"; +import Button from "@fancade-club/comps/forms/Button.astro"; + +if (Astro.locals.user) return Astro.redirect("/account"); +--- + + +
    + + + + +
    +

    Already a member? Log in!

    +
    + +