From af5267d97a61dc3e24c4196a2bfe7720c8b75e01 Mon Sep 17 00:00:00 2001 From: Bart van der Braak Date: Tue, 6 Feb 2024 21:00:38 +0100 Subject: [PATCH] feat: auth fully implemented --- apps/web/src/hooks.server.ts | 45 ++------- apps/web/src/lib/components/ui/tabs/index.ts | 10 +- .../components/ui/tabs/tabs-content.svelte | 10 +- .../lib/components/ui/tabs/tabs-list.svelte | 8 +- .../components/ui/tabs/tabs-trigger.svelte | 10 +- .../src/routes/(auth)/auth/+page.server.ts | 74 +++++++++++++++ apps/web/src/routes/(auth)/auth/+page.svelte | 82 ++++++++++++++-- apps/web/src/routes/(auth)/logout/+server.ts | 2 +- .../routes/(auth)/register/+page.server.ts | 69 -------------- .../src/routes/(auth)/register/+page.svelte | 95 ------------------- .../src/routes/(dashboard)/+layout.server.ts | 2 +- 11 files changed, 177 insertions(+), 230 deletions(-) delete mode 100644 apps/web/src/routes/(auth)/register/+page.server.ts delete mode 100644 apps/web/src/routes/(auth)/register/+page.svelte diff --git a/apps/web/src/hooks.server.ts b/apps/web/src/hooks.server.ts index fd11208..6107f63 100644 --- a/apps/web/src/hooks.server.ts +++ b/apps/web/src/hooks.server.ts @@ -1,29 +1,6 @@ -// import { type Handle } from '@sveltejs/kit'; -// import PocketBase from 'pocketbase'; -// import { pb } from '$lib/pocketbase'; -// import { SERVER_PB } from '$env/static/private'; - -// /** @type {import('@sveltejs/kit').Handle} */ -// export const handle: Handle = async ({ event, resolve }) => { -// event.locals.pocketBase = new PocketBase(SERVER_PB); - -// pb.set(event.locals.pocketBase); - -// event.locals.pocketBase.authStore.loadFromCookie(event.request.headers.get('cookie') ?? ''); - -// const response = await resolve(event); - -// response.headers.set( -// 'set-cookie', -// event.locals.pocketBase.authStore.exportToCookie({ secure: false }) -// ); - -// return response; -// }; - -import { redirect, type Handle } from '@sveltejs/kit'; +import { type Handle } from '@sveltejs/kit'; import PocketBase from 'pocketbase'; -import { building } from '$app/environment'; +import { building, dev } from '$app/environment'; import { SERVER_PB } from '$env/static/private'; export const handle: Handle = async ({ event, resolve }) => { @@ -39,27 +16,21 @@ export const handle: Handle = async ({ event, resolve }) => { const pb_auth = event.request.headers.get('cookie') ?? ''; event.locals.pocketBase.authStore.loadFromCookie(pb_auth); - - if (!event.locals.pocketBase.authStore.isValid) { - console.log('Session expired'); - throw redirect(303, '/auth'); - } try { const auth = await event.locals.pocketBase .collection('users') .authRefresh<{ id: string; email: string }>(); event.locals.id = auth.record.id; event.locals.email = auth.record.email; - } catch (_) { - throw redirect(303, '/auth'); - } - - if (!event.locals.id) { - throw redirect(303, '/auth'); + } catch (err) { + console.log('Error: ', err); } const response = await resolve(event); - const cookie = event.locals.pocketBase.authStore.exportToCookie({ sameSite: 'lax' }); + const cookie = event.locals.pocketBase.authStore.exportToCookie({ + secure: !dev, + sameSite: 'lax' + }); response.headers.append('set-cookie', cookie); return response; }; diff --git a/apps/web/src/lib/components/ui/tabs/index.ts b/apps/web/src/lib/components/ui/tabs/index.ts index f1ab372..00ecd77 100644 --- a/apps/web/src/lib/components/ui/tabs/index.ts +++ b/apps/web/src/lib/components/ui/tabs/index.ts @@ -1,7 +1,7 @@ -import { Tabs as TabsPrimitive } from "bits-ui"; -import Content from "./tabs-content.svelte"; -import List from "./tabs-list.svelte"; -import Trigger from "./tabs-trigger.svelte"; +import { Tabs as TabsPrimitive } from 'bits-ui'; +import Content from './tabs-content.svelte'; +import List from './tabs-list.svelte'; +import Trigger from './tabs-trigger.svelte'; const Root = TabsPrimitive.Root; @@ -14,5 +14,5 @@ export { Root as Tabs, Content as TabsContent, List as TabsList, - Trigger as TabsTrigger, + Trigger as TabsTrigger }; diff --git a/apps/web/src/lib/components/ui/tabs/tabs-content.svelte b/apps/web/src/lib/components/ui/tabs/tabs-content.svelte index 3866292..ca6bbf9 100644 --- a/apps/web/src/lib/components/ui/tabs/tabs-content.svelte +++ b/apps/web/src/lib/components/ui/tabs/tabs-content.svelte @@ -1,17 +1,17 @@ - import { Tabs as TabsPrimitive } from "bits-ui"; - import { cn } from "$lib/utils"; + import { Tabs as TabsPrimitive } from 'bits-ui'; + import { cn } from '$lib/utils'; type $$Props = TabsPrimitive.ListProps; - let className: $$Props["class"] = undefined; + let className: $$Props['class'] = undefined; export { className as class }; - import { Tabs as TabsPrimitive } from "bits-ui"; - import { cn } from "$lib/utils"; + import { Tabs as TabsPrimitive } from 'bits-ui'; + import { cn } from '$lib/utils'; type $$Props = TabsPrimitive.TriggerProps; type $$Events = TabsPrimitive.TriggerEvents; - let className: $$Props["class"] = undefined; - export let value: $$Props["value"]; + let className: $$Props['class'] = undefined; + export let value: $$Props['value']; export { className as class }; { + if (locals.pocketBase.authStore.isValid) { + return; + } + + const formData = await request.formData(); + + const name = formData.get('name'); + const email = formData.get('email'); + const password = formData.get('password'); + const passwordConfirm = formData.get('passwordConfirm'); + + try { + if (typeof name !== 'string') { + throw new Error('Name must be a string'); + } + + if (name.length === 0) { + throw new Error('Please enter a valid name'); + } + + if (typeof email !== 'string') { + throw new Error('Email must be a string'); + } + + if (email.length < 5) { + throw new Error('Please enter a valid e-mail address'); + } + + if (typeof password !== 'string') { + throw new Error('Password must be a string'); + } + + if (password.length < 8) { + throw new Error('Password must be at least 8 characters in length'); + } + + if (password !== passwordConfirm) { + throw new Error('Passwords do not match'); + } + + await locals.pocketBase.collection('users').create({ + name, + email, + password, + passwordConfirm + }); + + await locals.pocketBase.collection('users').authWithPassword(email, password); + if (!locals.pocketBase?.authStore?.model?.verified) { + locals.pocketBase.authStore.clear(); + return { + showLogin: true, + isLoading: false, + notVerified: true + }; + } + } catch (error) { + console.error(error); + + if (!(error instanceof Error)) { + return { + name, + email, + password, + error: 'Unknown error occured when signing up user' + }; + } + + return { error: error.message, name, email, password }; + } + + throw redirect(303, '/'); + }, oauth2: async ({ request, cookies }) => { const form = await request.formData(); const token = form.get('token'); diff --git a/apps/web/src/routes/(auth)/auth/+page.svelte b/apps/web/src/routes/(auth)/auth/+page.svelte index 3c8c33a..5f9a89b 100644 --- a/apps/web/src/routes/(auth)/auth/+page.svelte +++ b/apps/web/src/routes/(auth)/auth/+page.svelte @@ -44,7 +44,7 @@
@@ -54,7 +54,7 @@

Log into your account

-

+

Enter your credentials below to log into your account

@@ -64,6 +64,10 @@ action="?/login" use:enhance={() => { isLoading = true; + return async ({ update }) => { + isLoading = false; + update(); + }; }} >
@@ -91,7 +95,7 @@
{#if form?.notVerified} - + You must verify your email before you can login. @@ -101,7 +105,65 @@
- +
+

Create your account

+

+ Enter your details below to create a new account +

+
+
+
{ + isLoading = true; + return async ({ update }) => { + isLoading = false; + update(); + }; + }} + > +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+ {#if form?.notVerified} + + + You must verify your email before you can login. + + {/if} +
+
{#if providers.length}
{ isLoading = true; + return async ({ update }) => { + isLoading = false; + update(); + }; }} >
@@ -117,11 +183,11 @@
- Or continue with + Or continue with
@@ -148,7 +214,7 @@
{#if providers.length > 1}
- +
@@ -187,7 +253,7 @@ {/if} -

+

Don't have an account? Sign up.
Forgot password? Reset password.

diff --git a/apps/web/src/routes/(auth)/logout/+server.ts b/apps/web/src/routes/(auth)/logout/+server.ts index 44953cc..509ddbc 100644 --- a/apps/web/src/routes/(auth)/logout/+server.ts +++ b/apps/web/src/routes/(auth)/logout/+server.ts @@ -2,5 +2,5 @@ import { redirect } from '@sveltejs/kit'; export const GET = ({ locals }: { locals: App.Locals }) => { locals.pocketBase.authStore.clear(); - throw redirect(303, '/login'); + throw redirect(303, '/auth'); }; diff --git a/apps/web/src/routes/(auth)/register/+page.server.ts b/apps/web/src/routes/(auth)/register/+page.server.ts deleted file mode 100644 index dc1dbdd..0000000 --- a/apps/web/src/routes/(auth)/register/+page.server.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { redirect } from '@sveltejs/kit'; - -export const actions = { - default: async ({ request, locals }: { request: Request; locals: App.Locals }) => { - if (locals.pocketBase.authStore.isValid) { - return; - } - - const formData = await request.formData(); - - const name = formData.get('name'); - const email = formData.get('email'); - const password = formData.get('password'); - - try { - if (typeof name !== 'string') { - throw new Error('Name must be a string'); - } - - if (name.length === 0) { - throw new Error('Please enter a valid name'); - } - - if (typeof email !== 'string') { - throw new Error('Email must be a string'); - } - - if (email.length < 5) { - throw new Error('Please enter a valid e-mail address'); - } - - if (typeof password !== 'string') { - throw new Error('Password must be a string'); - } - - if (password.length < 8) { - throw new Error('Password must be at least 8 characters in length'); - } - - if (password !== formData.get('passwordConfirm')) { - throw new Error('Passwords do not match'); - } - - await locals.pocketBase.collection('users').create({ - email, - password, - name, - passwordConfirm: password - }); - - await locals.pocketBase.collection('users').authWithPassword(email, password); - } catch (error) { - console.error(error); - - if (!(error instanceof Error)) { - return { - name, - email, - password, - error: 'Unknown error occured when signing up user' - }; - } - - return { error: error.message, name, email, password }; - } - - throw redirect(303, '/'); - } -}; diff --git a/apps/web/src/routes/(auth)/register/+page.svelte b/apps/web/src/routes/(auth)/register/+page.svelte deleted file mode 100644 index 98750f1..0000000 --- a/apps/web/src/routes/(auth)/register/+page.svelte +++ /dev/null @@ -1,95 +0,0 @@ - - -
-
-
-

Create your account

-

Enter your details below to create a new account

-
-
- { - isLoading = true; - }} - > -
-
- - -
-
- - -
-
- - -
-
- - -
- -
- -
-
- -
-
- Or continue with -
-
- -
-

- Or sign in if you already have an account.
- Forgot password? Reset password. -

-
-
diff --git a/apps/web/src/routes/(dashboard)/+layout.server.ts b/apps/web/src/routes/(dashboard)/+layout.server.ts index ec58979..a198743 100644 --- a/apps/web/src/routes/(dashboard)/+layout.server.ts +++ b/apps/web/src/routes/(dashboard)/+layout.server.ts @@ -2,7 +2,7 @@ import { redirect } from '@sveltejs/kit'; export const load = async ({ locals }: { locals: App.Locals }) => { if (!locals.pocketBase.authStore.isValid) { - throw redirect(303, '/register'); + throw redirect(303, '/auth'); } return {};