diff --git a/server/internal/session/index.ts b/server/internal/session/index.ts index 713727b..f3b2f33 100644 --- a/server/internal/session/index.ts +++ b/server/internal/session/index.ts @@ -2,15 +2,20 @@ import { H3Event, Session } from "h3"; import createMemorySessionProvider from "./memory"; import { SessionProvider } from "./types"; import prisma from "../db/database"; +import { v4 as uuidv4 } from "uuid"; +import moment from "moment"; /* -This is a poorly organised implemention. +This implementation may need work. It exposes an API that should stay static, but there are plenty of opportunities for optimisation/organisation under the hood */ const userSessionKey = "_userSession"; const userIdKey = "_userId"; +const dropTokenCookie = "drop-token"; +const normalSessionLength = [31, "days"]; +const extendedSessionLength = [1, "year"]; export class SessionHandler { private sessionProvider: SessionProvider; @@ -20,33 +25,63 @@ export class SessionHandler { this.sessionProvider = createMemorySessionProvider(); } + private getSessionToken(h3: H3Event) { + const cookie = getCookie(h3, dropTokenCookie); + return cookie; + } + + private async createSession(h3: H3Event, extend = false) { + const token = uuidv4(); + const expiry = moment().add( + ...(extend ? extendedSessionLength : normalSessionLength) + ); + + setCookie(h3, dropTokenCookie, token, { expires: expiry.toDate() }); + + this.sessionProvider.setSession(dropTokenCookie, {}); + + return token; + } + async getSession(h3: H3Event) { + const token = this.getSessionToken(h3); + if (!token) return undefined; const data = await this.sessionProvider.getSession<{ [userSessionKey]: T }>( - h3 + token ); if (!data) return undefined; return data[userSessionKey]; } - async setSession(h3: H3Event, data: any, expend = false) { + async setSession(h3: H3Event, data: any, extend = false) { + const token = + this.getSessionToken(h3) ?? (await this.createSession(h3, extend)); const result = await this.sessionProvider.updateSession( - h3, + token, userSessionKey, data ); - if (!result) { - const toCreate = { [userSessionKey]: data }; - await this.sessionProvider.setSession(h3, toCreate, expend); - } + + return result; } async clearSession(h3: H3Event) { - await this.sessionProvider.clearSession(h3); + const token = this.getSessionToken(h3); + if (!token) return false; + await this.sessionProvider.clearSession(token); + return true; } - async getUserId(h3: H3Event) { + async getUserId(h3: H3Event, tag: string | boolean = false) { + const token = this.getSessionToken(h3); + if (!token) return undefined; + const session = await this.sessionProvider.getSession<{ [userIdKey]: string | undefined; - }>(h3); + }>(token); + + if (tag) + console.log(`${tag} ${JSON.stringify(h3)} ${JSON.stringify(session)}`); + if (!session) return undefined; return session[userIdKey]; @@ -61,15 +96,14 @@ export class SessionHandler { } async setUserId(h3: H3Event, userId: string, extend = false) { + const token = + this.getSessionToken(h3) ?? (await this.createSession(h3, extend)); + const result = await this.sessionProvider.updateSession( - h3, + token, userIdKey, userId ); - if (!result) { - const toCreate = { [userIdKey]: userId }; - await this.sessionProvider.setSession(h3, toCreate, extend); - } } async getAdminUser(h3: H3Event) { diff --git a/server/internal/session/memory.ts b/server/internal/session/memory.ts index 0ca3a50..f4ad75e 100644 --- a/server/internal/session/memory.ts +++ b/server/internal/session/memory.ts @@ -1,43 +1,22 @@ -import moment from "moment"; import { Session, SessionProvider } from "./types"; -import { v4 as uuidv4 } from "uuid"; export default function createMemorySessionHandler() { const sessions: { [key: string]: Session } = {}; - const sessionCookieName = "drop-session"; - const memoryProvider: SessionProvider = { - async setSession(h3, data, extend = false) { - const existingCookie = getCookie(h3, sessionCookieName); - if (existingCookie) delete sessions[existingCookie]; // Clear any previous session - - const cookie = uuidv4(); - const expiry = moment().add(31, extend ? "month" : "day"); - setCookie(h3, sessionCookieName, cookie, { expires: expiry.toDate() }); - - sessions[cookie] = data; + async setSession(token, data) { + sessions[token] = data; return true; }, - async updateSession(h3, key, data) { - const cookie = getCookie(h3, sessionCookieName); - if (!cookie) return false; - - sessions[cookie] = Object.assign({}, sessions[cookie], { [key]: data }); + async updateSession(token, key, data) { + sessions[token] = Object.assign({}, sessions[token], { [key]: data }); return true; }, - async getSession(h3) { - const cookie = getCookie(h3, sessionCookieName); - if (!cookie) return undefined; - - return sessions[cookie] as any; // Wild type cast because we let the user specify types if they want + async getSession(token) { + return sessions[token] as any; // Wild type cast because we let the user specify types if they want }, - async clearSession(h3) { - const cookie = getCookie(h3, sessionCookieName); - if (!cookie) return; - - delete sessions[cookie]; - deleteCookie(h3, sessionCookieName); + async clearSession(token) { + delete sessions[token]; }, }; diff --git a/server/internal/session/types.d.ts b/server/internal/session/types.d.ts index 7a6a602..5977e7c 100644 --- a/server/internal/session/types.d.ts +++ b/server/internal/session/types.d.ts @@ -3,12 +3,8 @@ import { H3Event } from "h3"; export type Session = { [key: string]: any }; export interface SessionProvider { - setSession: ( - h3: H3Event, - data: Session, - extend?: boolean - ) => Promise; - updateSession: (h3: H3Event, key: string, data: any) => Promise; - getSession: (h3: H3Event) => Promise; - clearSession: (h3: H3Event) => Promise; + setSession: (token: string, data: Session) => Promise; + updateSession: (token: string, key: string, data: any) => Promise; + getSession: (token: string) => Promise; + clearSession: (token: string) => Promise; }