@@ -17,6 +17,7 @@ import { logger } from "$lib/server/logger";
1717import { ObjectId } from "mongodb" ;
1818import type { Cookie } from "elysia" ;
1919import { adminTokenManager } from "./adminToken" ;
20+ import type { User } from "$lib/types/User" ;
2021
2122export interface OIDCSettings {
2223 redirectURI : string ;
@@ -72,14 +73,27 @@ export function refreshSessionCookie(cookies: Cookies, sessionId: string) {
7273 } ) ;
7374}
7475
75- export async function findUser ( sessionId : string ) {
76+ export async function findUser (
77+ sessionId : string ,
78+ coupledCookieHash ?: string
79+ ) : Promise < {
80+ user : User | null ;
81+ invalidateSession : boolean ;
82+ } > {
7683 const session = await collections . sessions . findOne ( { sessionId } ) ;
7784
7885 if ( ! session ) {
79- return null ;
86+ return { user : null , invalidateSession : false } ;
87+ }
88+
89+ if ( coupledCookieHash && session . coupledCookieHash !== coupledCookieHash ) {
90+ return { user : null , invalidateSession : true } ;
8091 }
8192
82- return await collections . users . findOne ( { _id : session . userId } ) ;
93+ return {
94+ user : await collections . users . findOne ( { _id : session . userId } ) ,
95+ invalidateSession : false ,
96+ } ;
8397}
8498export const authCondition = ( locals : App . Locals ) => {
8599 if ( ! locals . user && ! locals . sessionId ) {
@@ -191,6 +205,23 @@ type HeaderRecord =
191205 | { type : "elysia" ; value : Record < string , string | undefined > }
192206 | { type : "svelte" ; value : Headers } ;
193207
208+ export async function getCoupledCookieHash ( cookie : CookieRecord ) : Promise < string | undefined > {
209+ if ( ! config . COUPLE_SESSION_WITH_COOKIE_NAME ) {
210+ return undefined ;
211+ }
212+
213+ const cookieValue =
214+ cookie . type === "elysia"
215+ ? cookie . value [ config . COUPLE_SESSION_WITH_COOKIE_NAME ] ?. value
216+ : cookie . value . get ( config . COUPLE_SESSION_WITH_COOKIE_NAME ) ;
217+
218+ if ( ! cookieValue ) {
219+ return "no-cookie" ;
220+ }
221+
222+ return await sha256 ( cookieValue ) ;
223+ }
224+
194225export async function authenticateRequest (
195226 headers : HeaderRecord ,
196227 cookie : CookieRecord ,
@@ -238,12 +269,23 @@ export async function authenticateRequest(
238269 if ( token ) {
239270 secretSessionId = token ;
240271 sessionId = await sha256 ( token ) ;
241- const user = await findUser ( sessionId ) ;
272+
273+ const result = await findUser ( sessionId , await getCoupledCookieHash ( cookie ) ) ;
274+
275+ if ( result . invalidateSession ) {
276+ secretSessionId = crypto . randomUUID ( ) ;
277+ sessionId = await sha256 ( secretSessionId ) ;
278+
279+ if ( await collections . sessions . findOne ( { sessionId } ) ) {
280+ throw new Error ( "Session ID collision" ) ;
281+ }
282+ }
283+
242284 return {
243- user : user ?? undefined ,
285+ user : result . user ?? undefined ,
244286 sessionId,
245287 secretSessionId,
246- isAdmin : user ?. isAdmin || adminTokenManager . isAdmin ( sessionId ) ,
288+ isAdmin : result . user ?. isAdmin || adminTokenManager . isAdmin ( sessionId ) ,
247289 } ;
248290 }
249291
0 commit comments