Testing anonymous sessions and cleaning out when logging in.

This commit is contained in:
Bradley Shellnut 2024-11-10 11:52:48 -08:00
parent c9b6269ce9
commit a3558f590f
4 changed files with 56 additions and 37 deletions

View file

@ -1,20 +1,20 @@
import 'reflect-metadata'; import 'reflect-metadata';
import {Controller} from '$lib/server/api/common/types/controller'; import { Controller } from '$lib/server/api/common/types/controller';
import {cookieExpiresAt, createSessionTokenCookie, setSessionCookie} from '$lib/server/api/common/utils/cookies'; import { cookieExpiresAt, createSessionTokenCookie, setSessionCookie } from '$lib/server/api/common/utils/cookies';
import {signinUsernameDto} from '$lib/server/api/dtos/signin-username.dto'; import { signinUsernameDto } from '$lib/server/api/dtos/signin-username.dto';
import {SessionsService} from '$lib/server/api/services/sessions.service'; import { SessionsService } from '$lib/server/api/services/sessions.service';
import {zValidator} from '@hono/zod-validator'; import { zValidator } from '@hono/zod-validator';
import {openApi} from 'hono-zod-openapi'; import { openApi } from 'hono-zod-openapi';
import {inject, injectable} from 'tsyringe'; import { inject, injectable } from 'tsyringe';
import {limiter} from '../middleware/rate-limiter.middleware'; import { limiter } from '../middleware/rate-limiter.middleware';
import {LoginRequestsService} from '../services/loginrequest.service'; import { LoginRequestsService } from '../services/loginrequest.service';
import {signinUsername} from './login.routes'; import { signinUsername } from './login.routes';
@injectable() @injectable()
export class LoginController extends Controller { export class LoginController extends Controller {
constructor( constructor(
@inject(LoginRequestsService) private readonly loginRequestsService: LoginRequestsService, @inject(LoginRequestsService) private readonly loginRequestsService: LoginRequestsService,
@inject(SessionsService) private luciaService: SessionsService, @inject(SessionsService) private sessionsService: SessionsService,
) { ) {
super(); super();
} }
@ -29,6 +29,13 @@ export class LoginController extends Controller {
const { username, password } = c.req.valid('json'); const { username, password } = c.req.valid('json');
const session = await this.loginRequestsService.verify({ username, password }, c.req); const session = await this.loginRequestsService.verify({ username, password }, c.req);
const sessionCookie = createSessionTokenCookie(session.id, cookieExpiresAt); const sessionCookie = createSessionTokenCookie(session.id, cookieExpiresAt);
// Cleanup old session
const currentSession = c.var.session;
if (currentSession) {
await this.sessionsService.invalidateSession(currentSession.id);
}
console.log('set cookie', sessionCookie); console.log('set cookie', sessionCookie);
setSessionCookie(c, sessionCookie); setSessionCookie(c, sessionCookie);
return c.json({ message: 'ok' }); return c.json({ message: 'ok' });

View file

@ -1,19 +1,19 @@
import createApp from '$lib/server/api/common/create-app'; import createApp from '$lib/server/api/common/create-app';
import configureOpenAPI from '$lib/server/api/configure-open-api'; import configureOpenAPI from '$lib/server/api/configure-open-api';
import {CollectionController} from '$lib/server/api/controllers/collection.controller'; import { CollectionController } from '$lib/server/api/controllers/collection.controller';
import {MfaController} from '$lib/server/api/controllers/mfa.controller'; import { MfaController } from '$lib/server/api/controllers/mfa.controller';
import {OAuthController} from '$lib/server/api/controllers/oauth.controller'; import { OAuthController } from '$lib/server/api/controllers/oauth.controller';
import {SignupController} from '$lib/server/api/controllers/signup.controller'; import { SignupController } from '$lib/server/api/controllers/signup.controller';
import {UserController} from '$lib/server/api/controllers/user.controller'; import { UserController } from '$lib/server/api/controllers/user.controller';
import {WishlistController} from '$lib/server/api/controllers/wishlist.controller'; import { WishlistController } from '$lib/server/api/controllers/wishlist.controller';
import {AuthCleanupJobs} from '$lib/server/api/jobs/auth-cleanup.job'; import { AuthCleanupJobs } from '$lib/server/api/jobs/auth-cleanup.job';
import {extendZodWithOpenApi} from 'hono-zod-openapi'; import { extendZodWithOpenApi } from 'hono-zod-openapi';
import {hc} from 'hono/client'; import { hc } from 'hono/client';
import {container} from 'tsyringe'; import { container } from 'tsyringe';
import {z} from 'zod'; import { z } from 'zod';
import {config} from './common/config'; import { config } from './common/config';
import {IamController} from './controllers/iam.controller'; import { IamController } from './controllers/iam.controller';
import {LoginController} from './controllers/login.controller'; import { LoginController } from './controllers/login.controller';
extendZodWithOpenApi(z); extendZodWithOpenApi(z);

View file

@ -1,19 +1,19 @@
import 'reflect-metadata'; import 'reflect-metadata';
import { import {
type SessionCookie,
cookieExpiresAt, cookieExpiresAt,
cookieName, cookieName,
createBlankSessionTokenCookie, createBlankSessionTokenCookie,
createSessionTokenCookie, createSessionTokenCookie,
type SessionCookie,
setSessionCookie, setSessionCookie,
} from '$lib/server/api/common/utils/cookies'; } from '$lib/server/api/common/utils/cookies';
import {SessionsService} from '$lib/server/api/services/sessions.service'; import { SessionsService } from '$lib/server/api/services/sessions.service';
import type {MiddlewareHandler} from 'hono'; import type { MiddlewareHandler } from 'hono';
import {getCookie} from 'hono/cookie'; import { getCookie } from 'hono/cookie';
import {createMiddleware} from 'hono/factory'; import { createMiddleware } from 'hono/factory';
import {verifyRequestOrigin} from 'oslo/request'; import { verifyRequestOrigin } from 'oslo/request';
import {container} from 'tsyringe'; import { container } from 'tsyringe';
import type {AppBindings} from '../common/types/hono'; import type { AppBindings } from '../common/types/hono';
// resolve dependencies from the container // resolve dependencies from the container
const sessionService = container.resolve(SessionsService); const sessionService = container.resolve(SessionsService);
@ -34,8 +34,20 @@ export const verifyOrigin: MiddlewareHandler<AppBindings> = createMiddleware(asy
export const validateAuthSession: MiddlewareHandler<AppBindings> = createMiddleware(async (c, next) => { export const validateAuthSession: MiddlewareHandler<AppBindings> = createMiddleware(async (c, next) => {
const sessionId = getCookie(c, cookieName) ?? null; const sessionId = getCookie(c, cookieName) ?? null;
if (!sessionId) { if (!sessionId) {
const requestIpAddress = c.req.header('x-real-ip');
const requestIpCountry = c.req.header('x-vercel-ip-country');
const session = await sessionService.createSession(
sessionService.generateSessionToken(),
'anonymous',
requestIpCountry || 'unknown',
requestIpAddress || 'unknown',
false,
false,
);
const sessionCookie = createSessionTokenCookie(session.id, cookieExpiresAt);
setSessionCookie(c, sessionCookie);
c.set('session', session);
c.set('user', null); c.set('user', null);
c.set('session', null);
return next(); return next();
} }

View file

@ -26,7 +26,7 @@ export type Session = {
isTwoFactorAuthenticated: boolean; isTwoFactorAuthenticated: boolean;
}; };
export type SessionValidationResult = { session: Session; user: Users } | { session: null; user: null } | { session: Session; user: undefined }; export type SessionValidationResult = { session: Session; user: Users } | { session: null; user: null } | { session: Session; user: null };
@injectable() @injectable()
export class SessionsService { export class SessionsService {
@ -97,7 +97,7 @@ export class SessionsService {
isTwoFactorAuthenticated: result.is_two_factor_authenticated, isTwoFactorAuthenticated: result.is_two_factor_authenticated,
}; };
let user: Users | undefined = undefined; let user: Users | undefined = undefined;
if (session.userId) { if (session.userId && session.userId !== 'anonymous') {
user = await this.usersRepository.findOneById(session.userId); user = await this.usersRepository.findOneById(session.userId);
} }
if (Date.now() >= session.expiresAt.getTime()) { if (Date.now() >= session.expiresAt.getTime()) {
@ -126,7 +126,7 @@ export class SessionsService {
); );
} }
return { session, user }; return { session, user: user ?? null };
} }
async invalidateSession(sessionId: string) { async invalidateSession(sessionId: string) {