Upgrade to v3 Lucia, change all auth layers, upgrade all dependencies, and update eslint.

This commit is contained in:
Bradley Shellnut 2023-12-14 17:53:15 -08:00
parent 2c6d8f2510
commit b290f3092f
19 changed files with 836 additions and 516 deletions

View file

@ -1,8 +1,19 @@
module.exports = {
root: true,
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:svelte/recommended',
'prettier'
],
parser: '@typescript-eslint/parser',
extends: ['plugin:svelte/recommended'],
plugins: ['@typescript-eslint'],
parserOptions: {
sourceType: 'module',
ecmaVersion: 2020,
project: './tsconfig.json',
extraFileExtensions: ['.svelte'] // This is a required setting in `@typescript-eslint/parser` v4.24.0.
},
ignorePatterns: ['*.cjs'],
overrides: [
{
@ -14,15 +25,6 @@ module.exports = {
}
}
],
settings: {
'svelte3/typescript': () => require('typescript')
},
parserOptions: {
sourceType: 'module',
ecmaVersion: 2020,
project: './tsconfig.json',
extraFileExtensions: ['.svelte'] // This is a required setting in `@typescript-eslint/parser` v4.24.0.
},
env: {
browser: true,
es2017: true,

View file

@ -27,15 +27,16 @@
},
"devDependencies": {
"@melt-ui/pp": "^0.1.4",
"@melt-ui/svelte": "^0.57.3",
"@playwright/test": "^1.40.1",
"@resvg/resvg-js": "^2.4.1",
"@sveltejs/adapter-auto": "^2.1.1",
"@sveltejs/adapter-vercel": "^3.1.0",
"@sveltejs/kit": "^1.27.6",
"@sveltejs/kit": "^1.30.3",
"@types/cookie": "^0.5.4",
"@types/node": "^18.19.2",
"@typescript-eslint/eslint-plugin": "^6.13.2",
"@typescript-eslint/parser": "^6.13.2",
"@types/node": "^18.19.3",
"@typescript-eslint/eslint-plugin": "^6.14.0",
"@typescript-eslint/parser": "^6.14.0",
"autoprefixer": "^10.4.15",
"eslint": "^8.55.0",
"eslint-config-prettier": "^9.1.0",
@ -46,23 +47,23 @@
"postcss-import": "^15.1.0",
"postcss-load-config": "^4.0.2",
"postcss-preset-env": "^9.3.0",
"prettier": "^3.1.0",
"prettier": "^3.1.1",
"prettier-plugin-svelte": "^3.1.2",
"prisma": "^5.6.0",
"prisma": "^5.7.0",
"sass": "^1.65.1",
"satori": "^0.10.11",
"satori-html": "^0.3.2",
"svelte": "^4.2.8",
"svelte-check": "^3.6.2",
"svelte-meta-tags": "^3.1.0",
"svelte-preprocess": "^5.1.1",
"svelte-preprocess": "^5.1.2",
"svelte-sequential-preprocessor": "^2.0.1",
"sveltekit-flash-message": "^2.2.2",
"sveltekit-superforms": "^1.11.0",
"sveltekit-superforms": "^1.12.0",
"tailwindcss": "^3.3.6",
"ts-node": "^10.9.1",
"ts-node": "^10.9.2",
"tslib": "^2.6.1",
"typescript": "^5.3.2",
"typescript": "^5.3.3",
"vite": "^4.5.1",
"vitest": "^0.34.6",
"zod": "^3.22.4"
@ -76,13 +77,11 @@
"@fontsource/fira-mono": "^4.5.10",
"@iconify-icons/line-md": "^1.2.26",
"@iconify-icons/mdi": "^1.2.47",
"@lucia-auth/adapter-mysql": "^2.1.0",
"@lucia-auth/adapter-prisma": "^3.0.2",
"@lucia-auth/adapter-prisma": "4.0.0-beta.7",
"@lukeed/uuid": "^2.0.1",
"@melt-ui/svelte": "^0.57.3",
"@paralleldrive/cuid2": "^2.2.2",
"@prisma/client": "^5.6.0",
"@sentry/sveltekit": "^7.85.0",
"@prisma/client": "^5.7.0",
"@sentry/sveltekit": "^7.88.0",
"@types/feather-icons": "^4.29.4",
"@vercel/og": "^0.5.13",
"bits-ui": "^0.0.27",
@ -96,15 +95,16 @@
"iconify-icon": "^1.0.8",
"just-kebab-case": "^4.2.0",
"loader": "^2.1.1",
"lucia": "^2.7.4",
"lucia": "3.0.0-beta.12",
"lucide-svelte": "^0.256.1",
"open-props": "^1.6.13",
"open-props": "^1.6.16",
"oslo": "^0.24.0",
"radix-svelte": "^0.9.0",
"svelte-french-toast": "^1.2.0",
"svelte-lazy-loader": "^1.0.0",
"tailwind-merge": "^1.14.0",
"tailwind-variants": "^0.1.18",
"tailwindcss-animate": "^1.0.6",
"zod-to-json-schema": "^3.22.1"
"zod-to-json-schema": "^3.22.3"
}
}

File diff suppressed because it is too large Load diff

View file

@ -36,52 +36,41 @@ model UserRole {
}
model User {
id String @id @default(cuid())
username String @unique
email String? @unique
firstName String?
lastName String?
roles UserRole[]
verified Boolean @default(false)
receiveEmail Boolean @default(false)
token String? @unique
collection Collection?
wishlist Wishlist?
list List[]
theme String @default("system")
created_at DateTime @default(now()) @db.Timestamp(6)
updated_at DateTime @updatedAt @db.Timestamp(6)
auth_session Session[]
auth_key Key[]
id String @id @default(cuid())
username String @unique
hashed_password String?
email String? @unique
firstName String?
lastName String?
roles UserRole[]
verified Boolean @default(false)
receiveEmail Boolean @default(false)
collection Collection?
wishlist Wishlist?
list List[]
theme String @default("system")
created_at DateTime @default(now()) @db.Timestamp(6)
updated_at DateTime @updatedAt @db.Timestamp(6)
sessions Session[]
@@map("users")
}
model Session {
id String @id @unique
user_id String
active_expires BigInt
idle_expires BigInt
user User @relation(references: [id], fields: [user_id], onDelete: Cascade)
id String @id @unique
userId String
country String
expiresAt DateTime
user User @relation(references: [id], fields: [userId], onDelete: Cascade)
@@index([user_id])
@@index([userId])
@@map("sessions")
}
model Key {
id String @id @unique
hashed_password String?
user_id String
user User @relation(references: [id], fields: [user_id], onDelete: Cascade)
@@index([user_id])
@@map("keys")
}
model Collection {
id String @id @default(cuid())
user_id String @unique
user User @relation(references: [id], fields: [user_id])
id String @id @default(cuid())
user_id String @unique
user User @relation(references: [id], fields: [user_id])
items CollectionItem[]
@@index([user_id])

18
src/app.d.ts vendored
View file

@ -14,7 +14,7 @@ declare global {
}
interface Locals {
auth: import('lucia').AuthRequest;
user: Lucia.UserAttributes;
user: import('lucia').User | null;
prisma: PrismaClient;
startTimer: number;
error: string;
@ -43,14 +43,14 @@ declare global {
// interface Error {}
// interface Platform {}
/// <reference types="lucia" />
declare global {
namespace Lucia {
type Auth = import('$lib/server/lucia').Auth;
type DatabaseUserAttributes = User;
type DatabaseSessionAttributes = {};
}
}
// /// <reference types="lucia" />
// declare global {
// namespace Lucia {
// type Auth = import('$lib/server/lucia').Auth;
// type DatabaseUserAttributes = User;
// type DatabaseSessionAttributes = {};
// }
// }
// THIS IS IMPORTANT!!!
export {};

View file

@ -2,7 +2,7 @@ import * as Sentry from '@sentry/sveltekit';
import { sequence } from '@sveltejs/kit/hooks';
import type { Handle } from '@sveltejs/kit';
import { dev } from '$app/environment';
import { auth } from '$lib/server/lucia';
import { lucia } from '$lib/server/auth';
Sentry.init({
dsn: 'https://742e43279df93a3c4a4a78c12eb1f879@o4506057768632320.ingest.sentry.io/4506057770401792',
@ -14,22 +14,31 @@ export const authentication: Handle = async function ({ event, resolve }) {
const startTimer = Date.now();
event.locals.startTimer = startTimer;
event.locals.auth = auth.handleRequest(event);
if (event?.locals?.auth) {
try {
const session = await event.locals.auth.validate();
event.locals.user = session?.user;
// if (event.route.id?.startsWith('/(protected)')) {
// if (!user) throw redirect(302, '/sign-in');
// if (!user.verified) throw redirect(302, '/verify/email');
// }
} catch (error) {
console.error('Error validating user', error);
}
} else {
console.log('auth empty');
const ip = event.request.headers.get('x-forwarded-for') as string || event.getClientAddress();
const country = event.request.headers.get('x-vercel-ip-country') as string || 'unknown';
event.locals.session = {
ip,
country
};
const sessionId = event.cookies.get(lucia.sessionCookieName);
if (!sessionId) {
event.locals.user = null;
return resolve(event);
}
return await resolve(event);
const { session, user } = await lucia.validateSession(sessionId);
if (session && session.fresh) {
const sessionCookie = lucia.createSessionCookie(session.id);
event.cookies.set(sessionCookie.name, sessionCookie.value, sessionCookie.attributes);
}
if (!session) {
const sessionCookie = lucia.createBlankSessionCookie();
event.cookies.set(sessionCookie.name, sessionCookie.value, sessionCookie.attributes);
}
event.locals.user = user;
return resolve(event);
};
export const handle: Handle = sequence(sequence(Sentry.sentryHandle(), authentication));

54
src/lib/server/auth.ts Normal file
View file

@ -0,0 +1,54 @@
// lib/server/lucia.ts
import { Lucia, TimeSpan } from 'lucia';
import { PrismaAdapter } from '@lucia-auth/adapter-prisma';
import { dev } from '$app/environment';
import prisma_client from '$lib/prisma';
import { webcrypto } from "node:crypto";
globalThis.crypto = webcrypto as Crypto;
const adapter = new PrismaAdapter(prisma_client.session, prisma_client.user);
export const lucia = new Lucia(adapter, {
getSessionAttributes: (attributes) => {
return {
country: attributes.country,
};
},
getUserAttributes: (attributes) => {
return {
username: attributes.username,
email: attributes.email,
firstName: attributes.firstName,
lastName: attributes.lastName,
theme: attributes.theme
};
},
sessionExpiresIn: new TimeSpan(30, "d"), // 30 days
sessionCookie: {
name: 'session',
expires: false, // session cookies have very long lifespan (2 years)
attributes: {
// set to `true` when using HTTPS
secure: !dev,
sameSite: 'strict',
domain: dev ? 'localhost' : 'boredgame.vercel.app',
}
},
});
declare module "lucia" {
interface Register {
Lucia: typeof lucia;
}
interface DatabaseSessionAttributes {
country: string;
}
interface DatabaseUserAttributes {
username: string;
email: string;
firstName: string;
lastName: string;
theme: string;
}
}

View file

@ -1,29 +0,0 @@
// lib/server/lucia.ts
import { lucia } from 'lucia';
import { sveltekit } from 'lucia/middleware';
import { prisma } from '@lucia-auth/adapter-prisma';
import { dev } from '$app/environment';
import prisma_client from '$lib/prisma';
export const auth = lucia({
env: dev ? 'DEV' : 'PROD',
middleware: sveltekit(),
adapter: prisma(prisma_client),
getUserAttributes: (databaseUser) => {
return {
username: databaseUser.username,
email: databaseUser.email,
firstName: databaseUser.firstName,
lastName: databaseUser.lastName,
verified: databaseUser.verified,
receiveEmail: databaseUser.receiveEmail,
token: databaseUser.token,
theme: databaseUser.theme
};
},
experimental: {
debugMode: false
}
});
export type Auth = typeof auth;

View file

@ -0,0 +1,3 @@
export function isValidEmail(email: string): boolean {
return /.+@.+/.test(email);
}

View file

@ -6,8 +6,8 @@ import { search_schema } from '$lib/zodValidation.js';
import type { PageServerLoad } from './$types';
export const load: PageServerLoad = async ({ fetch, url, locals }) => {
const session = await locals.auth.validate();
if (!session) {
const user = locals.user;
if (!user) {
throw redirect(302, '/login');
}
@ -30,7 +30,7 @@ export const load: PageServerLoad = async ({ fetch, url, locals }) => {
try {
let collection = await prisma.collection.findUnique({
where: {
user_id: session.user.userId
user_id: user.id
}
});
console.log('collection', collection);
@ -103,11 +103,11 @@ export const actions: Actions = {
const { params, locals, request } = event;
const form = await superValidate(event, modifyListGameSchema);
const session = await locals.auth.validate();
if (!session) {
throw redirect(302, '/login');
if (!event.locals.user) {
throw fail(401);
}
const user = event.locals.user;
let game = await prisma.game.findUnique({
where: {
id: form.data.id
@ -127,7 +127,7 @@ export const actions: Actions = {
try {
const collection = await prisma.collection.findUnique({
where: {
user_id: session.user.userId
user_id: user.id
}
});
@ -154,17 +154,15 @@ export const actions: Actions = {
},
// Create new wishlist
create: async ({ params, locals, request }) => {
const session = await locals.auth.validate();
if (!session) {
throw redirect(302, '/login');
if (!locals.user) {
throw fail(401);
}
return error(405, 'Method not allowed');
},
// Delete a wishlist
delete: async ({ params, locals, request }) => {
const session = await locals.auth.validate();
if (!session) {
throw redirect(302, '/login');
if (!locals.user) {
throw fail(401);
}
return error(405, 'Method not allowed');
},
@ -173,9 +171,8 @@ export const actions: Actions = {
const { params, locals, request } = event;
const form = await superValidate(event, modifyListGameSchema);
const session = await locals.auth.validate();
if (!session) {
throw redirect(302, '/login');
if (!locals.user) {
throw fail(401);
}
let game = await prisma.game.findUnique({
@ -192,7 +189,7 @@ export const actions: Actions = {
try {
const collection = await prisma.collection.findUnique({
where: {
user_id: session.user.userId
user_id: locals.user.id
}
});

View file

@ -1,10 +1,9 @@
import { redirect } from '@sveltejs/kit';
import { fail, redirect } from '@sveltejs/kit';
import prisma from '$lib/prisma';
export async function load({ locals }) {
const session = await locals.auth.validate();
if (!session) {
throw redirect(302, '/login');
if (!locals.user) {
throw fail(401);
}
try {

View file

@ -3,8 +3,8 @@ import { superValidate } from 'sveltekit-superforms/server';
import prisma from '$lib/prisma';
export async function load({ params, locals }) {
const session = await locals.auth.validate();
if (!session) {
const user = locals.user;
if (!user) {
throw redirect(302, '/login');
}
@ -13,7 +13,7 @@ export async function load({ params, locals }) {
where: {
id: params.id,
AND: {
user_id: session.userId
user_id: user.id
}
},
include: {
@ -46,11 +46,11 @@ export const actions: Actions = {
const { params, locals, request } = event;
const form = await superValidate(event, modifyListGameSchema);
const session = await locals.auth.validate();
if (!session) {
throw redirect(302, '/login');
if (!locals.user) {
throw fail(401);
}
let game = await prisma.game.findUnique({
where: {
id: form.id
@ -74,7 +74,7 @@ export const actions: Actions = {
}
});
if (wishlist?.user_id !== session.userId) {
if (wishlist?.user_id !== locals.user.id) {
return fail(401, {
message: 'Unauthorized'
});
@ -103,23 +103,20 @@ export const actions: Actions = {
},
// Create new wishlist
create: async ({ params, locals, request }) => {
const session = await locals.auth.validate();
if (!session) {
throw redirect(302, '/login');
if (!locals.user) {
throw fail(401);
}
},
// Delete a wishlist
delete: async ({ params, locals, request }) => {
const session = await locals.auth.validate();
if (!session) {
throw redirect(302, '/login');
if (!locals.user) {
throw fail(401);
}
},
// Remove game from a wishlist
remove: async ({ params, locals, request }) => {
const session = await locals.auth.validate();
if (!session) {
throw redirect(302, '/login');
if (!locals.user) {
throw fail(401);
}
}
};

View file

@ -1,9 +1,10 @@
import { fail, redirect, type Actions } from '@sveltejs/kit';
import { message, setError, superValidate } from 'sveltekit-superforms/server';
import { LuciaError } from 'lucia';
// import { LuciaError } from 'lucia';
import { userSchema } from '$lib/config/zod-schemas';
import { auth } from '$lib/server/lucia.js';
import { Lucia } from '$lib/server/auth.js';
import type { PageServerLoad } from './$types';
import prisma from '$lib/prisma';
const profileSchema = userSchema.pick({
firstName: true,
@ -14,13 +15,12 @@ const profileSchema = userSchema.pick({
export const load: PageServerLoad = async (event) => {
const form = await superValidate(event, profileSchema);
const session = await event.locals.auth.validate();
if (!session) {
if (!event.locals.user) {
throw redirect(302, '/login');
}
const { user } = session;
const { user } = event.locals;
form.data = {
firstName: user.firstName,
@ -42,25 +42,29 @@ export const actions: Actions = {
form
});
}
if (!event.locals.user) {
throw redirect(302, '/login');
}
try {
console.log('updating profile');
const session = await event.locals.auth.validate();
if (!session) {
throw redirect(302, '/login');
}
const user = event.locals.user;
const user = session.user;
auth.updateUserAttributes(user.userId, {
firstName: form.data.firstName,
lastName: form.data.lastName,
email: form.data.email,
username: form.data.username
await prisma.user.update({
where: {
id: user.id
},
data: {
firstName: form.data.firstName,
lastName: form.data.lastName,
email: form.data.email,
username: form.data.username
}
});
if (user.email !== form.data.email) {
// Send email to confirm new email?
// auth.update
// await locals.prisma.key.update({
// where: {
@ -75,7 +79,7 @@ export const actions: Actions = {
// });
}
} catch (e) {
if (e instanceof LuciaError && e.message === `AUTH_INVALID_USER_ID`) {
if (e.message === `AUTH_INVALID_USER_ID`) {
// invalid user id
console.error(e);
}

View file

@ -4,17 +4,16 @@ import prisma from '$lib/prisma';
import { modifyListGameSchema } from '$lib/config/zod-schemas.js';
export async function load({ params, locals }) {
const session = await locals.auth.validate();
if (!session) {
if (!locals.user) {
throw redirect(302, '/login');
}
console.log('Wishlist load User id', session.user);
console.log('Wishlist load User id', locals.user.id);
try {
let wishlist = await prisma.wishlist.findUnique({
const wishlist = await prisma.wishlist.findUnique({
where: {
user_id: session?.user?.userId
user_id: locals.user.id
},
include: {
items: {
@ -49,16 +48,15 @@ export async function load({ params, locals }) {
export const actions: Actions = {
// Add game to a wishlist
add: async (event) => {
const { params, locals, request } = event;
const { locals } = event;
const form = await superValidate(event, modifyListGameSchema);
try {
const session = await locals.auth.validate();
if (!session) {
if (!locals.user) {
throw redirect(302, '/login');
}
let game = await prisma.game.findUnique({
const game = await prisma.game.findUnique({
where: {
id: form.data.id
}
@ -77,7 +75,7 @@ export const actions: Actions = {
if (game) {
const wishlist = await prisma.wishlist.findUnique({
where: {
user_id: session.user.userId
user_id: locals.user.id
}
});
@ -103,33 +101,30 @@ export const actions: Actions = {
}
},
// Create new wishlist
create: async ({ params, locals, request }) => {
const session = await locals.auth.validate();
if (!session) {
create: async ({ locals }) => {
if (!locals.user) {
throw redirect(302, '/login');
}
return error(405, 'Method not allowed');
},
// Delete a wishlist
delete: async ({ params, locals, request }) => {
const session = await locals.auth.validate();
if (!session) {
delete: async ({ locals }) => {
if (!locals.user) {
throw redirect(302, '/login');
}
return error(405, 'Method not allowed');
},
// Remove game from a wishlist
remove: async (event) => {
const { params, locals, request } = event;
const { locals } = event;
const form = await superValidate(event, modifyListGameSchema);
try {
const session = await locals.auth.validate();
if (!session) {
if (!locals.user) {
throw redirect(302, '/login');
}
let game = await prisma.game.findUnique({
const game = await prisma.game.findUnique({
where: {
id: form.data.id
}
@ -148,7 +143,7 @@ export const actions: Actions = {
if (game) {
const wishlist = await prisma.wishlist.findUnique({
where: {
user_id: session.user.userId
user_id: locals.user.id
}
});

View file

@ -68,7 +68,7 @@ export const load: PageServerLoad = async ({ params, locals, fetch }) => {
if (user) {
wishlist = await prisma.wishlist.findUnique({
where: {
user_id: user.userId
user_id: user.id
},
include: {
items: {
@ -81,7 +81,7 @@ export const load: PageServerLoad = async ({ params, locals, fetch }) => {
collection = await prisma.collection.findUnique({
where: {
user_id: user.userId
user_id: user.id
},
include: {
items: {

View file

@ -2,7 +2,8 @@ import { fail, type Actions } from '@sveltejs/kit';
import { setError, superValidate } from 'sveltekit-superforms/server';
import { redirect } from 'sveltekit-flash-message/server';
import prisma from '$lib/prisma';
import { auth } from '$lib/server/lucia';
import { lucia } from '$lib/server/auth';
import { Argon2id } from 'oslo/password';
import { userSchema } from '$lib/config/zod-schemas';
import type { PageServerLoad } from './$types';
@ -15,11 +16,11 @@ export const load: PageServerLoad = async (event) => {
const form = await superValidate(event, signInSchema);
console.log('login load event', event);
const session = await event.locals.auth.validate();
if (session) {
if (event.locals.user) {
const message = { type: 'info', message: 'You are already signed in' } as const;
throw redirect('/', message, event);
}
return {
form
};
@ -27,6 +28,7 @@ export const load: PageServerLoad = async (event) => {
export const actions: Actions = {
default: async (event) => {
const { cookies, locals } = event;
const form = await superValidate(event, signInSchema);
if (!form.valid) {
@ -36,56 +38,63 @@ export const actions: Actions = {
});
}
let session;
let sessionCookie;
try {
const key = await auth.useKey('username', form.data.username, form.data.password);
const session = await auth.createSession({
userId: key.userId,
attributes: {}
});
event.locals.auth.setSession(session);
const password = form.data.password;
const user = await prisma.user.findUnique({
where: {
id: session.user.userId
},
include: {
roles: {
select: {
role: true
}
}
username: form.data.username
}
});
if (user) {
await prisma.collection.upsert({
where: {
user_id: user.id
},
create: {
user_id: user.id
},
update: {
user_id: user.id
}
});
await prisma.wishlist.upsert({
where: {
user_id: user.id
},
create: {
user_id: user.id
},
update: {
user_id: user.id
}
});
if (!user || !user.hashed_password) {
form.data.password = '';
return setError(form, '', 'Your username or password is incorrect.');
}
const validPassword = await new Argon2id().verify(user.hashed_password, password);
if (!validPassword) {
form.data.password = '';
return setError(form, '', 'Your username or password is incorrect.');
}
session = await lucia.createSession(user.id, {
country: locals.session.ip,
});
sessionCookie = lucia.createSessionCookie(session.id);
await prisma.collection.upsert({
where: {
user_id: user.id
},
create: {
user_id: user.id
},
update: {
user_id: user.id
}
});
await prisma.wishlist.upsert({
where: {
user_id: user.id
},
create: {
user_id: user.id
},
update: {
user_id: user.id
}
});
} catch (e) {
// TODO: need to return error message to the client
console.error(e);
form.data.password = '';
return setError(form, '', 'Your username or password is incorrect.');
}
event.cookies.set(sessionCookie.name, sessionCookie.value, sessionCookie.attributes);
form.data.username = '';
form.data.password = '';
const message = { type: 'success', message: 'Signed In!' };

View file

@ -1,15 +1,15 @@
import { redirect, type Actions } from '@sveltejs/kit';
import { auth } from '$lib/server/lucia';
import { lucia } from '$lib/server/auth';
export const actions: Actions = {
default: async ({ locals }) => {
default: async ({ locals, cookies }) => {
console.log('Signing out user');
const session = await locals.auth.validate();
if (!session) {
const sessionId = cookies.get(lucia.sessionCookieName);
if (!locals.user || !sessionId) {
throw redirect(302, '/login');
}
await auth.invalidateSession(session.sessionId); // invalidate session
locals.auth.setSession(null); // remove cookie
await lucia.invalidateSession(sessionId);
// locals.auth.setSession(null); // remove cookie
throw redirect(302, '/');
}
};

View file

@ -1,9 +1,9 @@
import {fail, error, type Actions, redirect} from '@sveltejs/kit';
import { superValidate } from 'sveltekit-superforms/server';
import { LuciaError } from 'lucia';
import type { PageServerLoad } from './$types';
import prisma from '$lib/prisma';
import { auth } from '$lib/server/lucia';
import { lucia } from '$lib/server/auth';
import { Argon2id } from 'oslo/password';
import { userSchema } from '$lib/config/zod-schemas';
import { add_user_to_role } from '$server/roles';
import type { Message } from '$lib/types.js';
@ -41,8 +41,8 @@ export const load: PageServerLoad = async (event) => {
export const actions: Actions = {
default: async (event) => {
const { cookies } = event;
const form = await superValidate<typeof signUpSchema, Message>(event, signUpSchema);
debugger;
if (!form.valid) {
form.data.password = '';
form.data.confirm_password = '';
@ -51,50 +51,47 @@ export const actions: Actions = {
});
}
let session;
let sessionCookie;
// Adding user to the db
try {
console.log('Creating user');
const token = crypto.randomUUID();
const user = await auth.createUser({
key: {
providerId: 'username',
providerUserId: form.data.username,
password: form.data.password
},
attributes: {
email: form.data.email || null,
const hashedPassword = await new Argon2id().hash(form.data.password);
const user = await prisma.user.create({
data: {
username: form.data.username,
hashed_password: hashedPassword,
email: form.data.email || '',
firstName: form.data.firstName || '',
lastName: form.data.lastName || '',
verified: false,
receiveEmail: false,
theme: 'system',
token
theme: 'system'
}
});
console.log('signup user', user);
add_user_to_role(user.userId, 'user');
add_user_to_role(user.id, 'user');
await prisma.collection.create({
data: {
user_id: user.userId
user_id: user.id
}
});
await prisma.wishlist.create({
data: {
user_id: user.userId
user_id: user.id
}
});
console.log('User', user);
const session = await auth.createSession({
userId: user.userId,
attributes: {}
session = await lucia.createSession(user.id, {
country: event.locals.session.country
});
event.locals.auth.setSession(session);
} catch (e) {
if (e instanceof LuciaError && e.message.toUpperCase() === `DUPLICATE_KEY_ID`) {
sessionCookie = lucia.createSessionCookie(session.id);
} catch (e: any) {
if (e.message.toUpperCase() === `DUPLICATE_KEY_ID`) {
// key already exists
console.error('Lucia Error: ', e);
}
@ -107,6 +104,8 @@ export const actions: Actions = {
form.data.confirm_password = '';
throw error(500, message);
}
event.cookies.set(sessionCookie.name, sessionCookie.value, sessionCookie.attributes);
throw redirect(302, '/');
// const message = { type: 'success', message: 'Signed Up!' } as const;
// throw flashRedirect(message, event);

View file

@ -110,7 +110,7 @@
</Portal>
{/if}
<Toaster />
<!-- <Toaster /> -->
<style lang="postcss">
.loading {