diff --git a/src/app.d.ts b/src/app.d.ts index 5b99784..19204d5 100644 --- a/src/app.d.ts +++ b/src/app.d.ts @@ -3,11 +3,19 @@ declare global { namespace App { // interface Error {} - // interface Locals {} + interface Locals { + user: User + } // interface PageData {} // interface PageState {} // interface Platform {} } + + interface User { + id: string + username: string + password?: string + } } export {} diff --git a/src/hooks.server.ts b/src/hooks.server.ts new file mode 100644 index 0000000..8ab2ee0 --- /dev/null +++ b/src/hooks.server.ts @@ -0,0 +1,27 @@ +import { redirect, type Handle } from '@sveltejs/kit' +import { SECRET_JWT_KEY, SECRET_INTERNAL_API_KEY } from '$env/static/private' +import jwt from 'jsonwebtoken' + +export const handle: Handle = async ({ event, resolve }) => { + const nonJwtProtectedRoutes = ['/login', '/api'] + const urlpath = event.url.pathname + + if (urlpath.startsWith('/api') && event.request.headers.get('apikey') !== SECRET_INTERNAL_API_KEY && event.url.searchParams.get('apikey') !== SECRET_INTERNAL_API_KEY) { + return new Response('Unauthorized', { status: 400 }) + } + + if (!nonJwtProtectedRoutes.some((route) => urlpath.startsWith(route))) { + const authToken = event.cookies.get('lazuli-auth') + if (!authToken) throw redirect(303, `/login?redirect=${urlpath}`) + + try { + const tokenData = jwt.verify(authToken, SECRET_JWT_KEY) as User + event.locals.user = tokenData + } catch { + throw redirect(303, `/login?redirect=${urlpath}`) + } + } + + const response = await resolve(event) + return response +} diff --git a/src/lib/server/users.db b/src/lib/server/users.db index e69de29..4716b4e 100644 Binary files a/src/lib/server/users.db and b/src/lib/server/users.db differ diff --git a/src/lib/server/users.ts b/src/lib/server/users.ts index de8d8be..f1e523f 100644 --- a/src/lib/server/users.ts +++ b/src/lib/server/users.ts @@ -11,12 +11,6 @@ db.exec(initUsersTable) db.exec(initServicesTable) db.exec(initConnectionsTable) -interface User { - id: string - username: string - password?: string -} - type UserQueryParams = { includePassword?: boolean } diff --git a/src/routes/(app)/+layout.svelte b/src/routes/(app)/+layout.svelte new file mode 100644 index 0000000..4fb6c98 --- /dev/null +++ b/src/routes/(app)/+layout.svelte @@ -0,0 +1,38 @@ + \ No newline at end of file diff --git a/src/routes/+layout.server.ts b/src/routes/+layout.server.ts new file mode 100644 index 0000000..12a06fd --- /dev/null +++ b/src/routes/+layout.server.ts @@ -0,0 +1,5 @@ +import type { LayoutServerLoad } from './$types' + +export const load: LayoutServerLoad = ({ url, locals }) => { + return { urlPathname: url.pathname, user: locals.user } +} diff --git a/src/routes/login/+page.server.ts b/src/routes/login/+page.server.ts index d22093f..27a56f4 100644 --- a/src/routes/login/+page.server.ts +++ b/src/routes/login/+page.server.ts @@ -3,7 +3,7 @@ import { fail, redirect } from '@sveltejs/kit' import { compare, hash } from 'bcrypt-ts' import type { PageServerLoad, Actions } from './$types' import { Users } from '$lib/server/users' -import { sign } from 'jsonwebtoken' +import jwt from 'jsonwebtoken' export const load: PageServerLoad = async ({ url }) => { const redirectLocation = url.searchParams.get('redirect') @@ -21,7 +21,7 @@ export const actions: Actions = { const passwordValid = await compare(password.toString(), user.password!) if (!passwordValid) return fail(400, { message: 'Invalid Password' }) - const authToken = sign({ id: user.id, username: user.username }, SECRET_JWT_KEY, { expiresIn: '100d' }) + const authToken = jwt.sign({ id: user.id, username: user.username }, SECRET_JWT_KEY, { expiresIn: '100d' }) cookies.set('lazuli-auth', authToken, { path: '/', httpOnly: true, sameSite: 'strict', secure: false, maxAge: 60 * 60 * 24 * 100 }) @@ -40,7 +40,7 @@ export const actions: Actions = { const passwordHash = await hash(password.toString(), 10) const newUser = Users.addUser(username.toString(), passwordHash) - const authToken = sign({ id: newUser.id, username: newUser.username }, SECRET_JWT_KEY, { expiresIn: '100d' }) + const authToken = jwt.sign(newUser, SECRET_JWT_KEY, { expiresIn: '100d' }) cookies.set('lazuli-auth', authToken, { path: '/', httpOnly: true, sameSite: 'strict', secure: false, maxAge: 60 * 60 * 24 * 100 })