Skip to content

Commit

Permalink
Route protection
Browse files Browse the repository at this point in the history
  • Loading branch information
hopperelec committed Dec 4, 2023
1 parent 90e0b1b commit f0b73a6
Show file tree
Hide file tree
Showing 9 changed files with 99 additions and 35 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE `User` ADD COLUMN `allowed` BOOLEAN NOT NULL DEFAULT false;
1 change: 1 addition & 0 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ model User {
school_id Int @db.UnsignedInt
google_sub String @db.VarChar(255)
is_teacher Boolean @default(false)
allowed Boolean @default(false)
sessions Session[]
}

Expand Down
13 changes: 13 additions & 0 deletions src/app.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type { User } from "@prisma/client";

declare global {
declare namespace App {
// interface Error {}
interface Locals {
user: User;
}

// interface PageData {}
// interface Platform {}
}
}
60 changes: 51 additions & 9 deletions src/hooks.server.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import type { Handle } from "@sveltejs/kit";
import { minify } from "html-minifier-terser";
import type { Handle, RequestEvent } from "@sveltejs/kit";
import { error } from "@sveltejs/kit";
import type { Options } from "html-minifier-terser";
import { minify } from "html-minifier-terser";
import prisma from "$lib/prisma";
import { toBuffer } from "uuid-buffer";

const minification_options: Options = {
collapseInlineTagWhitespace: true,
Expand All @@ -11,15 +14,54 @@ const minification_options: Options = {
removeRedundantAttributes: true,
};

async function isAuthorized(event: RequestEvent): Promise<boolean> {
if (event.url.pathname.startsWith("/login")) {
return true;
}
const sessionUUID = event.cookies.get("session");
if (!sessionUUID) {
return false;
}
const session = await prisma.session.findUnique({
where: {
uuid_bin: toBuffer(sessionUUID),
},
include: {
user: true,
},
});
if (!session) {
throw error(400, "Invalid session UUID");
}
if (new Date() > session.expires) {
return false;
}
if (session.user.allowed) {
event.locals.user = session.user;
return true;
}

throw error(
403,
"Currently, only accounts registered with my school are allowed to access Definition Dash",
);
}

export const handle: Handle = async ({ event, resolve }) => {
let page = "";

return resolve(event, {
transformPageChunk: ({ html, done }) => {
page += html;
if (done) {
return minify(page, minification_options);
}
},
if (await isAuthorized(event)) {
return resolve(event, {
transformPageChunk: ({ html, done }) => {
page += html;
if (done) {
return minify(page, minification_options);
}
},
});
}
return new Response("Redirect", {
status: 303,
headers: { Location: "/login" },
});
};
7 changes: 7 additions & 0 deletions src/routes/(app)/+layout.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { LayoutServerLoad } from "./$types";

export const load: LayoutServerLoad = async ({ locals }) => {
return {
user: locals.user,
};
};
7 changes: 7 additions & 0 deletions src/routes/(app)/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<script lang="ts">
import type { LayoutData } from "./$types";
export let data: LayoutData;
</script>

You are currently logged in as {data.user.name}
5 changes: 0 additions & 5 deletions src/routes/+page.svelte

This file was deleted.

18 changes: 9 additions & 9 deletions src/lib/LoginPage.svelte → src/routes/login/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
<script>
import { PUBLIC_GOOGLE_CLIENT_ID, PUBLIC_BASE_URL } from "$env/static/public";
import { PUBLIC_BASE_URL, PUBLIC_GOOGLE_CLIENT_ID } from "$env/static/public";
</script>

<svelte:head>
<script src="https://accounts.google.com/gsi/client" async></script>
<script async src="https://accounts.google.com/gsi/client"></script>
</svelte:head>

<div
id="g_id_onload"
data-auto_prompt="false"
data-client_id={PUBLIC_GOOGLE_CLIENT_ID}
data-context="signin"
data-login_uri="{PUBLIC_BASE_URL}/login/callback"
data-ux_mode="redirect"
data-login_uri="{PUBLIC_BASE_URL}/callback"
data-auto_prompt="false"
id="g_id_onload"
></div>

<main>
<header>Definition Dash</header>
<div
class="g_id_signin"
data-type="standard"
data-logo_alignment="left"
data-shape="rectangular"
data-theme="outline"
data-text="continue_with"
data-size="large"
data-logo_alignment="left"
data-text="continue_with"
data-theme="outline"
data-type="standard"
>
<!-- prettier-ignore -->
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,26 +35,20 @@ export const POST: RequestHandler = async ({ request, cookies }) => {
where: { google_sub: payload.sub },
});
if (!user) {
if (payload.hd != ALLOWED_DOMAIN) {
throw error(
403,
"Currently, only accounts registered with my school are allowed to access Definition Dash",
);
}
const domain = payload.hd || ALLOWED_DOMAIN;
let school: School | null = await prisma.school.findUnique({
where: { domain: payload.hd },
where: { domain },
});
if (!school) {
school = await prisma.school.create({
data: {
domain: payload.hd,
},
data: { domain },
});
}
user = await prisma.user.create({
data: {
school_id: school.id,
google_sub: payload.sub,
allowed: payload.hd === ALLOWED_DOMAIN,
},
});
}
Expand Down Expand Up @@ -82,10 +76,13 @@ export const POST: RequestHandler = async ({ request, cookies }) => {
cookies.set("session", session_uuid, {
path: "/",
httpOnly: true,
sameSite: true,
sameSite: !dev,
secure: !dev,
maxAge: 60 * 60 * 24 * SESSION_DURATION_DAYS,
});

return new Response("Authenticated!");
return new Response("Redirect", {
status: 303,
headers: { Location: "/" },
});
};

0 comments on commit f0b73a6

Please sign in to comment.