mirror of
https://github.com/Drop-OSS/drop.git
synced 2025-11-13 16:22:39 +10:00
feat(session): under the hood organisation and consolidation
This commit is contained in:
@ -2,15 +2,20 @@ import { H3Event, Session } from "h3";
|
|||||||
import createMemorySessionProvider from "./memory";
|
import createMemorySessionProvider from "./memory";
|
||||||
import { SessionProvider } from "./types";
|
import { SessionProvider } from "./types";
|
||||||
import prisma from "../db/database";
|
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
|
It exposes an API that should stay static, but there are plenty of opportunities for optimisation/organisation under the hood
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const userSessionKey = "_userSession";
|
const userSessionKey = "_userSession";
|
||||||
const userIdKey = "_userId";
|
const userIdKey = "_userId";
|
||||||
|
const dropTokenCookie = "drop-token";
|
||||||
|
const normalSessionLength = [31, "days"];
|
||||||
|
const extendedSessionLength = [1, "year"];
|
||||||
|
|
||||||
export class SessionHandler {
|
export class SessionHandler {
|
||||||
private sessionProvider: SessionProvider;
|
private sessionProvider: SessionProvider;
|
||||||
@ -20,33 +25,63 @@ export class SessionHandler {
|
|||||||
this.sessionProvider = createMemorySessionProvider();
|
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<T extends Session>(h3: H3Event) {
|
async getSession<T extends Session>(h3: H3Event) {
|
||||||
|
const token = this.getSessionToken(h3);
|
||||||
|
if (!token) return undefined;
|
||||||
const data = await this.sessionProvider.getSession<{ [userSessionKey]: T }>(
|
const data = await this.sessionProvider.getSession<{ [userSessionKey]: T }>(
|
||||||
h3
|
token
|
||||||
);
|
);
|
||||||
if (!data) return undefined;
|
if (!data) return undefined;
|
||||||
|
|
||||||
return data[userSessionKey];
|
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(
|
const result = await this.sessionProvider.updateSession(
|
||||||
h3,
|
token,
|
||||||
userSessionKey,
|
userSessionKey,
|
||||||
data
|
data
|
||||||
);
|
);
|
||||||
if (!result) {
|
|
||||||
const toCreate = { [userSessionKey]: data };
|
return result;
|
||||||
await this.sessionProvider.setSession(h3, toCreate, expend);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
async clearSession(h3: H3Event) {
|
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<{
|
const session = await this.sessionProvider.getSession<{
|
||||||
[userIdKey]: string | undefined;
|
[userIdKey]: string | undefined;
|
||||||
}>(h3);
|
}>(token);
|
||||||
|
|
||||||
|
if (tag)
|
||||||
|
console.log(`${tag} ${JSON.stringify(h3)} ${JSON.stringify(session)}`);
|
||||||
|
|
||||||
if (!session) return undefined;
|
if (!session) return undefined;
|
||||||
|
|
||||||
return session[userIdKey];
|
return session[userIdKey];
|
||||||
@ -61,15 +96,14 @@ export class SessionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async setUserId(h3: H3Event, userId: string, extend = false) {
|
async setUserId(h3: H3Event, userId: string, extend = false) {
|
||||||
|
const token =
|
||||||
|
this.getSessionToken(h3) ?? (await this.createSession(h3, extend));
|
||||||
|
|
||||||
const result = await this.sessionProvider.updateSession(
|
const result = await this.sessionProvider.updateSession(
|
||||||
h3,
|
token,
|
||||||
userIdKey,
|
userIdKey,
|
||||||
userId
|
userId
|
||||||
);
|
);
|
||||||
if (!result) {
|
|
||||||
const toCreate = { [userIdKey]: userId };
|
|
||||||
await this.sessionProvider.setSession(h3, toCreate, extend);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getAdminUser(h3: H3Event) {
|
async getAdminUser(h3: H3Event) {
|
||||||
|
|||||||
@ -1,43 +1,22 @@
|
|||||||
import moment from "moment";
|
|
||||||
import { Session, SessionProvider } from "./types";
|
import { Session, SessionProvider } from "./types";
|
||||||
import { v4 as uuidv4 } from "uuid";
|
|
||||||
|
|
||||||
export default function createMemorySessionHandler() {
|
export default function createMemorySessionHandler() {
|
||||||
const sessions: { [key: string]: Session } = {};
|
const sessions: { [key: string]: Session } = {};
|
||||||
|
|
||||||
const sessionCookieName = "drop-session";
|
|
||||||
|
|
||||||
const memoryProvider: SessionProvider = {
|
const memoryProvider: SessionProvider = {
|
||||||
async setSession(h3, data, extend = false) {
|
async setSession(token, data) {
|
||||||
const existingCookie = getCookie(h3, sessionCookieName);
|
sessions[token] = data;
|
||||||
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;
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
async updateSession(h3, key, data) {
|
async updateSession(token, key, data) {
|
||||||
const cookie = getCookie(h3, sessionCookieName);
|
sessions[token] = Object.assign({}, sessions[token], { [key]: data });
|
||||||
if (!cookie) return false;
|
|
||||||
|
|
||||||
sessions[cookie] = Object.assign({}, sessions[cookie], { [key]: data });
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
async getSession(h3) {
|
async getSession(token) {
|
||||||
const cookie = getCookie(h3, sessionCookieName);
|
return sessions[token] as any; // Wild type cast because we let the user specify types if they want
|
||||||
if (!cookie) return undefined;
|
|
||||||
|
|
||||||
return sessions[cookie] as any; // Wild type cast because we let the user specify types if they want
|
|
||||||
},
|
},
|
||||||
async clearSession(h3) {
|
async clearSession(token) {
|
||||||
const cookie = getCookie(h3, sessionCookieName);
|
delete sessions[token];
|
||||||
if (!cookie) return;
|
|
||||||
|
|
||||||
delete sessions[cookie];
|
|
||||||
deleteCookie(h3, sessionCookieName);
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
12
server/internal/session/types.d.ts
vendored
12
server/internal/session/types.d.ts
vendored
@ -3,12 +3,8 @@ import { H3Event } from "h3";
|
|||||||
export type Session = { [key: string]: any };
|
export type Session = { [key: string]: any };
|
||||||
|
|
||||||
export interface SessionProvider {
|
export interface SessionProvider {
|
||||||
setSession: (
|
setSession: (token: string, data: Session) => Promise<boolean>;
|
||||||
h3: H3Event,
|
updateSession: (token: string, key: string, data: any) => Promise<boolean>;
|
||||||
data: Session,
|
getSession: <T extends Session>(token: string) => Promise<T | undefined>;
|
||||||
extend?: boolean
|
clearSession: (token: string) => Promise<void>;
|
||||||
) => Promise<boolean>;
|
|
||||||
updateSession: (h3: H3Event, key: string, data: any) => Promise<boolean>;
|
|
||||||
getSession: <T extends Session>(h3: H3Event) => Promise<T | undefined>;
|
|
||||||
clearSession: (h3: H3Event) => Promise<void>;
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user