diff --git a/package.json b/package.json index c0ff76f..847b2c2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "adventurelog", - "version": "0.1.0", + "version": "0.1.6", "description": "Embark, Explore, Remember. 🌍", "private": true, "scripts": { diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 67b0334..904454a 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -19,7 +19,6 @@ let isServerSetup = data.isServerSetup; onMount(() => { - console.log("isServerSetup", isServerSetup); if (!isServerSetup && $page.url.pathname !== "/setup") { goto("/setup"); } diff --git a/src/routes/settings/admin/+page.server.ts b/src/routes/settings/admin/+page.server.ts new file mode 100644 index 0000000..888ea6e --- /dev/null +++ b/src/routes/settings/admin/+page.server.ts @@ -0,0 +1,36 @@ +import { error, redirect, type Actions, type Handle } from "@sveltejs/kit"; +import type { PageServerLoad } from "./$types"; +import { db } from "$lib/db/db.server"; +import { sessionTable } from "$lib/db/schema"; + +export const load: PageServerLoad = async (event) => { + if (!event.locals.user) { + return redirect(302, "/login"); + } else { + if (event.locals.user.role !== "admin") { + return redirect(302, "/settings"); + } + } +}; + +export const actions: Actions = { + clearAllSessions: async (event) => { + if (event.locals.user && event.locals.user.role !== "admin") { + return error(403, { + message: "You are not authorized to perform this action", + }); + } else { + console.log("ALL SESSIONS CLEARED"); + await db.delete(sessionTable).execute(); + return { + status: 200, + headers: { + "content-type": "application/json", + }, + body: JSON.stringify({ + message: "Cleared all sessions", + }), + }; + } + }, +}; diff --git a/src/routes/settings/admin/+page.svelte b/src/routes/settings/admin/+page.svelte new file mode 100644 index 0000000..d79147d --- /dev/null +++ b/src/routes/settings/admin/+page.svelte @@ -0,0 +1,102 @@ + + +

Admin Settings

+ +

Add User

+
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+ +{#if errors.message} +
+ {errors.message} +
+{/if} + +

Session Managment

+
+
+ +
+
diff --git a/src/routes/signup/+page.server.ts b/src/routes/signup/+page.server.ts index 691db63..e287775 100644 --- a/src/routes/signup/+page.server.ts +++ b/src/routes/signup/+page.server.ts @@ -1,6 +1,6 @@ // routes/signup/+page.server.ts import { lucia } from "$lib/server/auth"; -import { fail, redirect } from "@sveltejs/kit"; +import { error, fail, redirect } from "@sveltejs/kit"; import { generateId } from "lucia"; import { Argon2id } from "oslo/password"; import { db } from "$lib/db/db.server"; @@ -17,23 +17,33 @@ export const actions: Actions = { const password = formData.get("password"); const firstName = formData.get("first_name"); const lastName = formData.get("last_name"); + let role: string = ""; // username must be between 4 ~ 31 characters, and only consists of lowercase letters, 0-9, -, and _ // keep in mind some database (e.g. mysql) are case insensitive // check all to make sure all fields are provided if (!username || !password || !firstName || !lastName) { - return fail(400, { + return error(400, { message: "All fields are required", }); } + if (!event.locals.user) { + role = "user"; + } + + if (event.locals.user && event.locals.user.role === "admin") { + const isAdmin = formData.get("role") === "on"; + role = isAdmin ? "admin" : "user"; + } + if ( typeof username !== "string" || username.length < 3 || username.length > 31 || !/^[a-z0-9_-]+$/.test(username) ) { - return fail(400, { + return error(400, { message: "Invalid username", }); } @@ -42,7 +52,7 @@ export const actions: Actions = { password.length < 6 || password.length > 255 ) { - return fail(400, { + return error(400, { message: "Invalid password", }); } @@ -52,7 +62,7 @@ export const actions: Actions = { firstName.length < 1 || firstName.length > 255 ) { - return fail(400, { + return error(400, { message: "Invalid first name", }); } @@ -62,14 +72,11 @@ export const actions: Actions = { lastName.length < 1 || lastName.length > 255 ) { - return fail(400, { + return error(400, { message: "Invalid last name", }); } - const userId = generateId(15); - const hashedPassword = await new Argon2id().hash(password); - const usernameTaken = await db .select() .from(userTable) @@ -78,10 +85,14 @@ export const actions: Actions = { .then((results) => results[0] as unknown as DatabaseUser | undefined); if (usernameTaken) { - return fail(400, { + return error(400, { message: "Username already taken", }); } + + const userId = generateId(15); + const hashedPassword = await new Argon2id().hash(password); + await db .insert(userTable) .values({ @@ -91,18 +102,36 @@ export const actions: Actions = { last_name: lastName, hashed_password: hashedPassword, signup_date: new Date(), - role: "user", + role: role, last_login: new Date(), } as DatabaseUser) .execute(); - const session = await lucia.createSession(userId, {}); - const sessionCookie = lucia.createSessionCookie(session.id); - event.cookies.set(sessionCookie.name, sessionCookie.value, { - path: ".", - ...sessionCookie.attributes, - }); + if (!event.locals.user) { + const session = await lucia.createSession(userId, {}); + const sessionCookie = lucia.createSessionCookie(session.id); + event.cookies.set(sessionCookie.name, sessionCookie.value, { + path: ".", + ...sessionCookie.attributes, + }); - redirect(302, "/"); + redirect(302, "/"); + } else { + if (event.locals.user && event.locals.user.role !== "admin") { + return error(403, { + message: "You are not authorized to add users", + }); + } + + return { + status: 200, + headers: { + "content-type": "application/json", + }, + body: JSON.stringify({ + message: "User created", + }), + }; + } }, };