From aeba55b315d71d8879de83abd23885ccb88b365d Mon Sep 17 00:00:00 2001 From: Chad Freeman Date: Sat, 17 Aug 2024 14:07:09 -0400 Subject: [PATCH] Fully set up username/password auth --- .prettierrc | 1 + bun.lockb | Bin 126796 -> 127212 bytes package.json | 1 + src/app.d.ts | 10 +++- src/hooks.server.ts | 33 +++++++++++++ src/lib/auth.ts | 74 +++++++++++++++++++++--------- src/routes/+page.svelte | 1 - src/routes/+page.ts | 5 ++ src/routes/app/+page.server.ts | 7 +++ src/routes/app/+page.svelte | 3 ++ src/routes/auth/+page.server.ts | 54 ++++++++++++++++------ src/routes/auth/+page.svelte | 49 +++++++++++--------- src/routes/auth/logout/+server.ts | 15 ++++++ 13 files changed, 194 insertions(+), 59 deletions(-) create mode 100644 src/hooks.server.ts delete mode 100644 src/routes/+page.svelte create mode 100644 src/routes/+page.ts create mode 100644 src/routes/app/+page.server.ts create mode 100644 src/routes/app/+page.svelte create mode 100644 src/routes/auth/logout/+server.ts diff --git a/.prettierrc b/.prettierrc index 89e142b..10e6cad 100644 --- a/.prettierrc +++ b/.prettierrc @@ -2,6 +2,7 @@ "useTabs": true, "singleQuote": true, "trailingComma": "none", + "semi": false, "printWidth": 100, "plugins": ["prettier-plugin-svelte"], "overrides": [ diff --git a/bun.lockb b/bun.lockb index 30652b63b899d8a811eebd5872faa55388b86ccd..5789f389dcc13f0132db51e70c27e18f60258d69 100755 GIT binary patch delta 17851 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 Cb3o|; delta 17689 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, string> | null; + session: FlatDocumentData, string> | null; + } } } -export {}; +export { }; diff --git a/src/hooks.server.ts b/src/hooks.server.ts new file mode 100644 index 0000000..fd4e407 --- /dev/null +++ b/src/hooks.server.ts @@ -0,0 +1,33 @@ +import { cookieController, cookieExpiration, getUserAndSession } from "$lib/auth"; +import type { Handle } from "@sveltejs/kit"; +import { createDate } from "oslo"; + +export const handle: Handle = async ({ event, resolve }) => { + const sessionId = event.cookies.get("auth_session"); + if (!sessionId) { + event.locals.user = null; + event.locals.session = null; + return resolve(event); + } + + const res = await getUserAndSession(sessionId); + if(res.isNone()) { + const sessionCookie = cookieController.createBlankCookie(); + event.cookies.set(sessionCookie.name, sessionCookie.value, { + path: ".", + ...sessionCookie.attributes + }); + event.locals.user = null; + event.locals.session = null; + return resolve(event); + } + const { session, user } = res.unwrap() + const sessionCookie = cookieController.createCookie(session.id) + event.cookies.set(sessionCookie.name, sessionCookie.value, { + path: ".", + ...sessionCookie.attributes + }) + event.locals.user = user; + event.locals.session = session; + return resolve(event); +}; \ No newline at end of file diff --git a/src/lib/auth.ts b/src/lib/auth.ts index b2bd9dd..1321f6f 100644 --- a/src/lib/auth.ts +++ b/src/lib/auth.ts @@ -1,30 +1,60 @@ -import type { z } from "zod" -import { db, session } from "./db" -import { Err, Ok, Result } from "@oxi/result" -import type { FlatDocumentData } from "@olli/kvdex" -import { nanoid } from "nanoid" -import { TimeSpan, createDate } from "oslo" -import { alphabet, generateRandomString } from "oslo/crypto" +import type { z } from 'zod' +import { db, session } from './db' +import { Err, Ok, Result } from '@oxi/result' +import { Option, None, Some } from '@oxi/option' +import type { FlatDocumentData } from '@olli/kvdex' +import { nanoid } from 'nanoid' +import { TimeSpan, createDate } from 'oslo' +import { alphabet, generateRandomString } from 'oslo/crypto' +import { CookieController } from "oslo/cookie" const sessionTimeSpan = new TimeSpan(1, 'w') -async function createSessionForUser(userId: string): Promise, string>, null>> { - const user = (await db.user.find(userId))?.flat() - if(!user) return Err(null) - const sessionId = generateRandomString(10, alphabet("0-9", "a-z")) - const createdSession = (await db.session.set(sessionId, { - expiresAt: createDate(sessionTimeSpan), - userId - }, { expireIn: sessionTimeSpan.milliseconds() })) - if(!createdSession.ok) return Err(null) - return Ok((await db.session.find(sessionId))?.flat()!) +async function createSessionForUser( + userId: string +): Promise, string>>> { + const user = (await db.user.find(userId))?.flat() + if (!user) return None + const sessionId = generateRandomString(21, alphabet('0-9', 'a-z')) + const createdSession = await db.session.set( + sessionId, + { + expiresAt: createDate(sessionTimeSpan), + userId + }, + { expireIn: sessionTimeSpan.milliseconds() } + ) + if (!createdSession.ok) return None + return Some((await db.session.find(sessionId))?.flat()!) } async function deleteSession(sessionId: string): Promise { - await db.session.delete(sessionId) + await db.session.delete(sessionId) } -export { - createSessionForUser, - deleteSession -} \ No newline at end of file +async function getUserAndSession( + sessionId: string +): Promise< + Option<{ + user: FlatDocumentData, string> + session: FlatDocumentData, string> + }> +> { + const session = (await db.session.find(sessionId))?.flat() + if (!session) return None + const user = (await db.user.find(session.userId))?.flat() + if (!user) return None + await db.session.update(sessionId, { + expiresAt: createDate(sessionTimeSpan) + }, { expireIn: sessionTimeSpan.milliseconds() }) + return Some({ user, session }) +} + +export const cookieExpiration = new TimeSpan(365 * 2, 'd') +export const cookieController = new CookieController('auth_session', { + httpOnly: true, + secure: true, + sameSite: "lax", + path: ".", +}, { expiresIn: cookieExpiration }) +export { createSessionForUser, deleteSession, getUserAndSession } diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte deleted file mode 100644 index f0b453d..0000000 --- a/src/routes/+page.svelte +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/routes/+page.ts b/src/routes/+page.ts new file mode 100644 index 0000000..f7d2f63 --- /dev/null +++ b/src/routes/+page.ts @@ -0,0 +1,5 @@ +import { redirect } from "@sveltejs/kit"; + +export async function load() { + return redirect(302, '/app') +} \ No newline at end of file diff --git a/src/routes/app/+page.server.ts b/src/routes/app/+page.server.ts new file mode 100644 index 0000000..ac9b605 --- /dev/null +++ b/src/routes/app/+page.server.ts @@ -0,0 +1,7 @@ +import { redirect } from '@sveltejs/kit'; + +export async function load({ locals }) { + if(!locals.session) { + return redirect(302, "/auth") + } +} \ No newline at end of file diff --git a/src/routes/app/+page.svelte b/src/routes/app/+page.svelte new file mode 100644 index 0000000..bd92406 --- /dev/null +++ b/src/routes/app/+page.svelte @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/src/routes/auth/+page.server.ts b/src/routes/auth/+page.server.ts index 56bdadc..7a941a5 100644 --- a/src/routes/auth/+page.server.ts +++ b/src/routes/auth/+page.server.ts @@ -2,32 +2,50 @@ import { alphabet, generateRandomString } from 'oslo/crypto'; import { fail, message, setError, superValidate } from 'sveltekit-superforms'; import { zod } from 'sveltekit-superforms/adapters'; import { z } from 'zod'; -import { hash } from "@ts-rex/argon2" +import { hash, verify } from "@ts-rex/argon2" import { db } from '$lib/db.js'; +import { cookieController, cookieExpiration, createSessionForUser } from '$lib/auth.js'; +import { createDate } from 'oslo'; +import { redirect } from '@sveltejs/kit'; const schema = z.object({ username: z.string().min(4, "must be atleast 4 characters").max(32, "must be less than 32 characters").regex(/^[a-z0-9_\-]+$/i, `must be alphanumeric, with the exception of "_" and "-"`), password: z.string().min(8, "must be atleast 8 characters").max(255) }); -export async function load() { +export async function load({ locals }) { + if(locals.session) { + return redirect(302, '/app') + } const form = await superValidate(zod(schema)); return { form }; }; export const actions = { - login: async ({ request }) => { + login: async ({ request, cookies }) => { const form = await superValidate(request, zod(schema)); if (!form.valid) return fail(400, { form }); const { username, password } = form.data - - // TODO: Login user - return message(form, 'Login form submitted'); + const user = (await db.user.findByPrimaryIndex('username', username))?.flat(); + if (!user) return setError(form, "user does not exist") + if (!user.password) return setError(form, "this account does not have a password, maybe try a different method?") + const isvalid = verify(password, user.password); + if (!isvalid) return setError(form, "incorrect password") + const session = (await createSessionForUser(user.id)) + if (session.isSome()) { + const sessionCookie = cookieController.createCookie(session.unwrap().id) + cookies.set(sessionCookie.name, sessionCookie.value, { + path: ".", + ...sessionCookie.attributes + }) + return redirect(302, '/app') + } else { + return fail(500, { form }) + } }, - signup: async ({ request }) => { + signup: async ({ request, cookies }) => { const form = await superValidate(request, zod(schema)); - console.log(form) if (!form.valid) return fail(400, { form }); const { username, password } = form.data @@ -35,15 +53,23 @@ export const actions = { const passwordHash = hash(password) const user = (await db.user.findByPrimaryIndex('username', username))?.flat() - if(user) return setError(form, 'Username already exists') - console.log(userId, password, passwordHash); - console.log(await db.user.set(userId, { + if (user) return setError(form, "username", 'username already exists') + await db.user.set(userId, { displayName: username, username, id: userId, password: passwordHash - })) - - return message(form, 'Signup form submitted'); + }) + const session = (await createSessionForUser(userId)) + if (session.isSome()) { + const sessionCookie = cookieController.createCookie(session.unwrap().id) + cookies.set(sessionCookie.name, sessionCookie.value, { + path: ".", + ...sessionCookie.attributes + }) + return redirect(302, '/app') + } else { + return fail(500, { form }) + } } } \ No newline at end of file diff --git a/src/routes/auth/+page.svelte b/src/routes/auth/+page.svelte index b553b4f..248507e 100644 --- a/src/routes/auth/+page.svelte +++ b/src/routes/auth/+page.svelte @@ -1,18 +1,18 @@ or
-