From de136939fcacafa2ae4e3d8d0e3aca3fc49d002d Mon Sep 17 00:00:00 2001 From: Hunter Johnston Date: Sun, 5 Feb 2023 14:09:50 -0500 Subject: [PATCH] final-video --- package.json | 5 ++- pnpm-lock.yaml | 43 +++++++++++++++++++++++++- prisma/schema.prisma | 35 +++++++++++++++++++++ src/app.d.ts | 15 ++++++++- src/hooks.server.ts | 10 ++++++ src/lib/server/lucia.ts | 18 +++++++++++ src/routes/+layout.server.ts | 5 ++- src/routes/+layout.svelte | 16 ++++++++-- src/routes/+page.server.ts | 26 ++++++++++++++-- src/routes/+page.svelte | 32 ++++++++++--------- src/routes/[articleId]/+page.server.ts | 31 ++++++++++++++++--- src/routes/login/+page.server.ts | 28 +++++++++++++++++ src/routes/logout/+server.ts | 14 +++++++-- src/routes/register/+page.server.ts | 36 +++++++++++++++++++++ 14 files changed, 284 insertions(+), 30 deletions(-) create mode 100644 src/hooks.server.ts create mode 100644 src/lib/server/lucia.ts diff --git a/package.json b/package.json index f6290d7..aa63c02 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,10 @@ }, "type": "module", "dependencies": { + "@lucia-auth/adapter-prisma": "^0.4.0", + "@lucia-auth/sveltekit": "^0.6.2", "@picocss/pico": "^1.5.7", - "@prisma/client": "^4.9.0" + "@prisma/client": "^4.9.0", + "lucia-auth": "^0.6.0" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5fb03b0..aaf97af 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,6 +1,8 @@ lockfileVersion: 5.4 specifiers: + '@lucia-auth/adapter-prisma': ^0.4.0 + '@lucia-auth/sveltekit': ^0.6.2 '@picocss/pico': ^1.5.7 '@playwright/test': ^1.30.0 '@prisma/client': ^4.9.0 @@ -11,6 +13,7 @@ specifiers: eslint: ^8.33.0 eslint-config-prettier: ^8.6.0 eslint-plugin-svelte3: ^4.0.0 + lucia-auth: ^0.6.0 prettier: ^2.8.3 prettier-plugin-svelte: ^2.9.0 prisma: ^4.9.0 @@ -23,8 +26,11 @@ specifiers: vitest: ^0.25.8 dependencies: + '@lucia-auth/adapter-prisma': 0.4.0_lucia-auth@0.6.0 + '@lucia-auth/sveltekit': 0.6.2_iyasqsbplmktfcni36hpxhd3zi '@picocss/pico': 1.5.7 '@prisma/client': 4.9.0_prisma@4.9.0 + lucia-auth: 0.6.0 devDependencies: '@playwright/test': 1.30.0 @@ -299,6 +305,29 @@ packages: '@jridgewell/sourcemap-codec': 1.4.14 dev: true + /@lucia-auth/adapter-prisma/0.4.0_lucia-auth@0.6.0: + resolution: {integrity: sha512-HMaGbVfB5KTZBs6KPqI5z6RFKVl4AKfm9u2KrrQglthpd/rWJoJRDI2oYkdcEX4Xu1FNdNJJrEtKKBtVAXYqrw==} + peerDependencies: + lucia-auth: 0.6.x + dependencies: + lucia-auth: 0.6.0 + dev: false + + /@lucia-auth/sveltekit/0.6.2_iyasqsbplmktfcni36hpxhd3zi: + resolution: {integrity: sha512-+lOhgctcdVkPRYtJegTaEZYLFhPJOHFjdAm9cBFFjpkV6cNGuHSTxobfOn7yRy3pGVhzGFM91uOfYrJxmECOBA==} + peerDependencies: + lucia-auth: 0.5.x - 0.6.x + svelte: 3.x + dependencies: + '@noble/hashes': 1.2.0 + lucia-auth: 0.6.0 + svelte: 3.55.1 + dev: false + + /@noble/hashes/1.2.0: + resolution: {integrity: sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==} + dev: false + /@nodelib/fs.scandir/2.1.5: resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -1321,6 +1350,13 @@ packages: yallist: 4.0.0 dev: true + /lucia-auth/0.6.0: + resolution: {integrity: sha512-8j5nPl3RbbqGoZWULER4q+2PP7i8F3Eq3OeN7EnL+bxi4YAn5I+5FcNq/ikUCj8neOxGZyzJiRzFJq+t3r28+g==} + dependencies: + '@noble/hashes': 1.2.0 + nanoid: 4.0.1 + dev: false + /magic-string/0.27.0: resolution: {integrity: sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==} engines: {node: '>=12'} @@ -1389,6 +1425,12 @@ packages: hasBin: true dev: true + /nanoid/4.0.1: + resolution: {integrity: sha512-udKGtCCUafD3nQtJg9wBhRP3KMbPglUsgV5JVsXhvyBs/oefqb4sqMEhKBBgqZncYowu58p1prsZQBYvAj/Gww==} + engines: {node: ^14 || ^16 || >=18} + hasBin: true + dev: false + /natural-compare-lite/1.4.0: resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} dev: true @@ -1807,7 +1849,6 @@ packages: /svelte/3.55.1: resolution: {integrity: sha512-S+87/P0Ve67HxKkEV23iCdAh/SX1xiSfjF1HOglno/YTbSTW7RniICMCofWGdJJbdjw3S+0PfFb1JtGfTXE0oQ==} engines: {node: '>= 8'} - dev: true /text-table/0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 6d8beb7..4e2128a 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -14,4 +14,39 @@ model Article { id Int @id @default(autoincrement()) title String content String + User User @relation(fields: [userId], references: [id]) + userId String +} + +model User { + id String @id @unique + name String + username String @unique + articles Article[] + session Session[] + Key Key[] + + @@map("user") +} + +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) + + @@index([user_id]) + @@map("session") +} + +model Key { + id String @id @unique + hashed_password String? + user_id String + primary Boolean + user User @relation(references: [id], fields: [user_id], onDelete: Cascade) + + @@index([user_id]) + @@map("key") } diff --git a/src/app.d.ts b/src/app.d.ts index 19ea674..cc85c67 100644 --- a/src/app.d.ts +++ b/src/app.d.ts @@ -3,11 +3,24 @@ import type { PrismaClient } from "@prisma/client" declare global { namespace App { // interface Error {} - // interface Locals {} + interface Locals { + validate: import("@lucia-auth/sveltekit").Validate + validateUser: import("@lucia-auth/sveltekit").ValidateUser + setSession: import("@lucia-auth/sveltekit").SetSession + } // interface PageData {} // interface Platform {} } var __prisma: PrismaClient + + /// + declare namespace Lucia { + type Auth = import("$lib/server/lucia").Auth + type UserAttributes = { + username: string + name: string + } + } } export {} diff --git a/src/hooks.server.ts b/src/hooks.server.ts new file mode 100644 index 0000000..5727024 --- /dev/null +++ b/src/hooks.server.ts @@ -0,0 +1,10 @@ +import { handleHooks } from "@lucia-auth/sveltekit" +import { auth } from "$lib/server/lucia" +import type { Handle } from "@sveltejs/kit" +import { sequence } from "@sveltejs/kit/hooks" + +export const customHandle: Handle = async ({ resolve, event }) => { + return resolve(event) +} + +export const handle: Handle = sequence(handleHooks(auth), customHandle) diff --git a/src/lib/server/lucia.ts b/src/lib/server/lucia.ts new file mode 100644 index 0000000..3afd315 --- /dev/null +++ b/src/lib/server/lucia.ts @@ -0,0 +1,18 @@ +import lucia from "lucia-auth" +import prismaAdapter from "@lucia-auth/adapter-prisma" +import { dev } from "$app/environment" +import { prisma } from "$lib/server/prisma" + +export const auth = lucia({ + adapter: prismaAdapter(prisma), + env: dev ? "DEV" : "PROD", + transformUserData: (userData) => { + return { + userId: userData.id, + username: userData.username, + name: userData.name, + } + }, +}) + +export type Auth = typeof auth diff --git a/src/routes/+layout.server.ts b/src/routes/+layout.server.ts index b2103e1..fb5c940 100644 --- a/src/routes/+layout.server.ts +++ b/src/routes/+layout.server.ts @@ -1,3 +1,6 @@ import type { LayoutServerLoad } from "./$types" -export const load: LayoutServerLoad = async () => {} +export const load: LayoutServerLoad = async ({ locals }) => { + const { user, session } = await locals.validateUser() + return { user } +} diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index b82c45d..d8b5e68 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -1,5 +1,7 @@
@@ -12,9 +14,17 @@ diff --git a/src/routes/+page.server.ts b/src/routes/+page.server.ts index 6993761..29f3e88 100644 --- a/src/routes/+page.server.ts +++ b/src/routes/+page.server.ts @@ -1,6 +1,6 @@ import type { Actions, PageServerLoad } from "./$types" import { prisma } from "$lib/server/prisma" -import { fail } from "@sveltejs/kit" +import { error, fail, redirect } from "@sveltejs/kit" export const load: PageServerLoad = async () => { return { @@ -9,7 +9,12 @@ export const load: PageServerLoad = async () => { } export const actions: Actions = { - createArticle: async ({ request }) => { + createArticle: async ({ request, locals }) => { + const { user, session } = await locals.validateUser() + if (!(user && session)) { + throw redirect(302, "/") + } + const { title, content } = Object.fromEntries( await request.formData(), ) as Record @@ -19,6 +24,7 @@ export const actions: Actions = { data: { title, content, + userId: user.userId, }, }) } catch (err) { @@ -30,13 +36,27 @@ export const actions: Actions = { status: 201, } }, - deleteArticle: async ({ url }) => { + deleteArticle: async ({ url, locals }) => { + const { user, session } = await locals.validateUser() + if (!(user && session)) { + throw redirect(302, "/") + } const id = url.searchParams.get("id") if (!id) { return fail(400, { message: "Invalid request" }) } try { + const article = await prisma.article.findUniqueOrThrow({ + where: { + id: Number(id), + }, + }) + + if (article.userId !== user.userId) { + throw error(403, "Not authorized") + } + await prisma.article.delete({ where: { id: Number(id), diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index e6ec5b1..e465d23 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -15,21 +15,25 @@

{article.content}

-
- -
- Edit Article + {#if article.userId === data.user?.userId} +
+ +
+ Edit Article + {/if} {/each}
-
-

New Article

- - - -