From 290ab487a176cf0f59f21e1e6a1492239fec3be9 Mon Sep 17 00:00:00 2001 From: orosmatthew Date: Fri, 28 Apr 2023 13:42:16 -0400 Subject: [PATCH] Implement login --- web/package-lock.json | 16 +++++++ web/package.json | 2 + web/prisma/schema.prisma | 12 ++++- web/src/hooks.server.ts | 57 +++++++++++++++++++++++ web/src/routes/admin/reviews/+page.svelte | 2 + web/src/routes/login/+page.server.ts | 4 ++ web/src/routes/logout/+page.server.ts | 16 +++++++ web/src/routes/logout/+page.svelte | 1 + 8 files changed, 108 insertions(+), 2 deletions(-) create mode 100644 web/src/hooks.server.ts create mode 100644 web/src/routes/logout/+page.server.ts create mode 100644 web/src/routes/logout/+page.svelte diff --git a/web/package-lock.json b/web/package-lock.json index 693a980..9d4aed6 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -15,6 +15,7 @@ "diff2html": "^3.4.35", "highlight.js": "^11.7.0", "prisma": "^4.13.0", + "uuid": "^9.0.0", "zod": "^3.21.4" }, "devDependencies": { @@ -22,6 +23,7 @@ "@sveltejs/kit": "^1.15.9", "@types/bootstrap": "^5.2.6", "@types/diff": "^5.0.3", + "@types/uuid": "^9.0.1", "@typescript-eslint/eslint-plugin": "^5.59.1", "@typescript-eslint/parser": "^5.59.1", "eslint": "^8.39.0", @@ -826,6 +828,12 @@ "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", "dev": true }, + "node_modules/@types/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-rFT3ak0/2trgvp4yYZo5iKFEPsET7vKydKF+VRCxlQ9bpheehyAJH89dAkaLEq/j/RZXJIqcgsmPJKUP1Z28HA==", + "dev": true + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "5.59.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.1.tgz", @@ -3105,6 +3113,14 @@ "punycode": "^2.1.0" } }, + "node_modules/uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/vite": { "version": "4.3.3", "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.3.tgz", diff --git a/web/package.json b/web/package.json index f888e97..c24f1d7 100644 --- a/web/package.json +++ b/web/package.json @@ -16,6 +16,7 @@ "@sveltejs/kit": "^1.15.9", "@types/bootstrap": "^5.2.6", "@types/diff": "^5.0.3", + "@types/uuid": "^9.0.1", "@typescript-eslint/eslint-plugin": "^5.59.1", "@typescript-eslint/parser": "^5.59.1", "eslint": "^8.39.0", @@ -38,6 +39,7 @@ "diff2html": "^3.4.35", "highlight.js": "^11.7.0", "prisma": "^4.13.0", + "uuid": "^9.0.0", "zod": "^3.21.4" } } diff --git a/web/prisma/schema.prisma b/web/prisma/schema.prisma index 8e1a76a..eae9959 100644 --- a/web/prisma/schema.prisma +++ b/web/prisma/schema.prisma @@ -8,9 +8,17 @@ datasource db { } model User { - id Int @id @default(autoincrement()) - username String @unique + id Int @id @default(autoincrement()) + username String @unique password String + sessions Session[] +} + +model Session { + token String @id + createdAt DateTime @default(now()) + user User @relation(fields: [userId], references: [id]) + userId Int } enum SubmissionState { diff --git a/web/src/hooks.server.ts b/web/src/hooks.server.ts new file mode 100644 index 0000000..21f4985 --- /dev/null +++ b/web/src/hooks.server.ts @@ -0,0 +1,57 @@ +import { redirect, type Handle } from '@sveltejs/kit'; +import { db } from '$lib/server/prisma'; +import type { Session } from '@prisma/client'; + +const sessionExpireMilliseconds = 1000 * 60 * 60 * 24; // 24 hours + +function isSessionExpired(session: Session): boolean { + return session.createdAt.valueOf() + sessionExpireMilliseconds < new Date().valueOf(); +} + +async function removeExpiredSessions(userId: number) { + const sessions: Session[] = await db.session.findMany({ where: { userId: userId } }); + sessions.forEach(async (session) => { + if (isSessionExpired(session)) { + await db.session.delete({ where: { token: session.token } }); + } + }); +} + +export const handle = (async ({ event, resolve }) => { + if (event.url.pathname.startsWith('/login')) { + if (event.cookies.get('token')) { + const session = await db.session.findUnique({ where: { token: event.cookies.get('token') } }); + if (session) { + removeExpiredSessions(session.userId); + if (!isSessionExpired(session)) { + throw redirect(302, '/admin/reviews'); + } else { + event.cookies.delete('token'); + } + } else { + const res = resolve(event); + return res; + } + } + } + if (event.url.pathname.startsWith('/admin')) { + if (event.cookies.get('token')) { + const session = await db.session.findUnique({ where: { token: event.cookies.get('token') } }); + if (session) { + removeExpiredSessions(session.userId); + if (!isSessionExpired(session)) { + const res = await resolve(event); + return res; + } else { + event.cookies.delete('token'); + } + } else { + throw redirect(302, '/login'); + } + } else { + throw redirect(302, '/login'); + } + } + const res = await resolve(event); + return res; +}) satisfies Handle; diff --git a/web/src/routes/admin/reviews/+page.svelte b/web/src/routes/admin/reviews/+page.svelte index 6999d39..90c2c9d 100644 --- a/web/src/routes/admin/reviews/+page.svelte +++ b/web/src/routes/admin/reviews/+page.svelte @@ -6,6 +6,8 @@

Reviews

+Logout +