Fixing infinite user get loop.

This commit is contained in:
Bradley Shellnut 2024-08-15 16:46:58 -07:00
parent 60d0706d58
commit abe8ca90ee
5 changed files with 67 additions and 59 deletions

View file

@ -3,8 +3,6 @@ import 'reflect-metadata'
import { hc } from 'hono/client'; import { hc } from 'hono/client';
import { sequence } from '@sveltejs/kit/hooks'; import { sequence } from '@sveltejs/kit/hooks';
import { redirect, type Handle } from '@sveltejs/kit'; import { redirect, type Handle } from '@sveltejs/kit';
import { dev } from '$app/environment';
// import { lucia } from '$lib/server/auth';
import type { ApiRoutes } from '$lib/server/api'; import type { ApiRoutes } from '$lib/server/api';
import { parseApiResponse } from '$lib/utils/api'; import { parseApiResponse } from '$lib/utils/api';
import { StatusCodes } from '$lib/constants/status-codes'; import { StatusCodes } from '$lib/constants/status-codes';
@ -50,45 +48,45 @@ const apiClient: Handle = async ({ event, resolve }) => {
return response; return response;
}; };
export const authentication: Handle = async function ({ event, resolve }) { // export const authentication: Handle = async function ({ event, resolve }) {
event.locals.startTimer = Date.now(); // event.locals.startTimer = Date.now();
//
const ip = event.request.headers.get('x-forwarded-for') as string; // const ip = event.request.headers.get('x-forwarded-for') as string;
const country = event.request.headers.get('x-vercel-ip-country') as string; // const country = event.request.headers.get('x-vercel-ip-country') as string;
event.locals.ip = dev ? '127.0.0.1' : ip; // || event.getClientAddress(); // event.locals.ip = dev ? '127.0.0.1' : ip; // || event.getClientAddress();
event.locals.country = dev ? 'us' : country; // event.locals.country = dev ? 'us' : country;
//
const sessionId = event.cookies.get(lucia.sessionCookieName); // const sessionId = event.cookies.get(lucia.sessionCookieName);
if (!sessionId) { // if (!sessionId) {
event.locals.user = null; // event.locals.user = null;
event.locals.session = null; // event.locals.session = null;
return resolve(event); // return resolve(event);
} // }
//
const { session, user } = await lucia.validateSession(sessionId); // const { session, user } = await lucia.validateSession(sessionId);
if (session && session.fresh) { // if (session && session.fresh) {
const sessionCookie = lucia.createSessionCookie(session.id); // const sessionCookie = lucia.createSessionCookie(session.id);
console.log('sessionCookie', JSON.stringify(sessionCookie, null, 2)); // console.log('sessionCookie', JSON.stringify(sessionCookie, null, 2));
// sveltekit types deviates from the de-facto standard, you can use 'as any' too // // sveltekit types deviates from the de-facto standard, you can use 'as any' too
event.cookies.set(sessionCookie.name, sessionCookie.value, { // event.cookies.set(sessionCookie.name, sessionCookie.value, {
path: '.', // path: '.',
...sessionCookie.attributes, // ...sessionCookie.attributes,
}); // });
} // }
console.log('session from hooks', JSON.stringify(session, null, 2)); // console.log('session from hooks', JSON.stringify(session, null, 2));
if (!session) { // if (!session) {
const sessionCookie = lucia.createBlankSessionCookie(); // const sessionCookie = lucia.createBlankSessionCookie();
console.log('blank sessionCookie', JSON.stringify(sessionCookie, null, 2)); // console.log('blank sessionCookie', JSON.stringify(sessionCookie, null, 2));
event.cookies.set(sessionCookie.name, sessionCookie.value, { // event.cookies.set(sessionCookie.name, sessionCookie.value, {
path: '.', // path: '.',
...sessionCookie.attributes, // ...sessionCookie.attributes,
}); // });
} // }
event.locals.user = user; // event.locals.user = user;
event.locals.session = session; // event.locals.session = session;
//
return resolve(event); // return resolve(event);
}; // };
export const handle: Handle = sequence( export const handle: Handle = sequence(
// Sentry.sentryHandle(), // Sentry.sentryHandle(),

View file

@ -1,14 +1,19 @@
import { Hono } from 'hono'; import { Hono } from 'hono';
import { injectable } from 'tsyringe'; import { inject, injectable } from 'tsyringe';
import { setCookie } from 'hono/cookie';
import type { HonoTypes } from '../types'; import type { HonoTypes } from '../types';
import { requireAuth } from "../middleware/auth.middleware"; import { requireAuth } from "../middleware/auth.middleware";
import type { Controller } from '../interfaces/controller.interface'; import type { Controller } from '../interfaces/controller.interface';
import {IamService} from "$lib/server/api/services/iam.service";
import {LuciaProvider} from "$lib/server/api/providers";
@injectable() @injectable()
export class IamController implements Controller { export class IamController implements Controller {
controller = new Hono<HonoTypes>(); controller = new Hono<HonoTypes>();
constructor( constructor(
@inject(IamService) private readonly iamService: IamService,
@inject(LuciaProvider) private lucia: LuciaProvider
) { } ) { }
routes() { routes() {
@ -16,6 +21,21 @@ export class IamController implements Controller {
.get('/me', requireAuth, async (c) => { .get('/me', requireAuth, async (c) => {
const user = c.var.user; const user = c.var.user;
return c.json({ user }); return c.json({ user });
})
.post('/logout', requireAuth, async (c) => {
const sessionId = c.var.session.id;
await this.iamService.logout(sessionId);
const sessionCookie = this.lucia.createBlankSessionCookie();
setCookie(c, sessionCookie.name, sessionCookie.value, {
path: sessionCookie.attributes.path,
maxAge: sessionCookie.attributes.maxAge,
domain: sessionCookie.attributes.domain,
sameSite: sessionCookie.attributes.sameSite as any,
secure: sessionCookie.attributes.secure,
httpOnly: sessionCookie.attributes.httpOnly,
expires: sessionCookie.attributes.expires
});
return c.json({ status: 'success' });
}); });
} }
} }

View file

@ -5,7 +5,7 @@ import type { LayoutServerLoad } from '../$types';
export const load: LayoutServerLoad = loadFlash(async (event) => { export const load: LayoutServerLoad = loadFlash(async (event) => {
const { url, locals, cookies } = event; const { url, locals, cookies } = event;
const authedUser = await locals.getAuthedUserOrThrow(); const authedUser = await locals.getAuthedUser();
// if (userNotFullyAuthenticated(user, session)) { // if (userNotFullyAuthenticated(user, session)) {
// await lucia.invalidateSession(locals.session!.id!); // await lucia.invalidateSession(locals.session!.id!);

View file

@ -42,7 +42,7 @@ export const load: PageServerLoad = async (event) => {
}, },
}); });
// if (userFullyAuthenticated(user, session)) { if (authedUser) {
const dbUser = await db.query.usersTable.findFirst({ const dbUser = await db.query.usersTable.findFirst({
where: eq(usersTable.id, authedUser!.id!), where: eq(usersTable.id, authedUser!.id!),
}); });
@ -75,7 +75,7 @@ export const load: PageServerLoad = async (event) => {
wishlists: userWishlists, wishlists: userWishlists,
collections: userCollection, collections: userCollection,
}; };
// } }
return { metaTagsChild: metaTags, user: null, wishlists: [], collections: [] }; return { metaTagsChild: metaTags, user: null, wishlists: [], collections: [] };
}; };

View file

@ -1,22 +1,12 @@
import { fail } from '@sveltejs/kit';
import { redirect } from 'sveltekit-flash-message/server'; import { redirect } from 'sveltekit-flash-message/server';
import { lucia } from '$lib/server/auth';
import { signedOutMessage } from '$lib/flashMessages';
import type { Actions } from "./$types"; import type { Actions } from "./$types";
import {StatusCodes} from "$lib/constants/status-codes";
export const actions: Actions = { export const actions: Actions = {
default: async (event) => { default: async (event) => {
const { locals, cookies } = event; const { locals } = event;
console.log('Signing out user'); console.log('Signing out user');
if (!locals.session) { await locals.api.me.logout.$post()
return fail(401); redirect(StatusCodes.SEE_OTHER, '/login')
}
await lucia.invalidateSession(locals.session.id);
const sessionCookie = lucia.createBlankSessionCookie();
cookies.set(sessionCookie.name, sessionCookie.value, {
path: '.',
...sessionCookie.attributes
});
return redirect(302, '/login', signedOutMessage, event);
} }
}; };