| 
							 | 
						import { Issuer, BaseClient, type UserinfoResponse, TokenSet } from "openid-client"; | 
					
					
						
						| 
							 | 
						import { addHours, addYears } from "date-fns"; | 
					
					
						
						| 
							 | 
						import { | 
					
					
						
						| 
							 | 
							COOKIE_NAME, | 
					
					
						
						| 
							 | 
							OPENID_CLIENT_ID, | 
					
					
						
						| 
							 | 
							OPENID_CLIENT_SECRET, | 
					
					
						
						| 
							 | 
							OPENID_PROVIDER_URL, | 
					
					
						
						| 
							 | 
							OPENID_SCOPES, | 
					
					
						
						| 
							 | 
						} from "$env/static/private"; | 
					
					
						
						| 
							 | 
						import { sha256 } from "$lib/utils/sha256"; | 
					
					
						
						| 
							 | 
						import { z } from "zod"; | 
					
					
						
						| 
							 | 
						import { dev } from "$app/environment"; | 
					
					
						
						| 
							 | 
						import type { Cookies } from "@sveltejs/kit"; | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						export interface OIDCSettings { | 
					
					
						
						| 
							 | 
							redirectURI: string; | 
					
					
						
						| 
							 | 
						} | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						export interface OIDCUserInfo { | 
					
					
						
						| 
							 | 
							token: TokenSet; | 
					
					
						
						| 
							 | 
							userData: UserinfoResponse; | 
					
					
						
						| 
							 | 
						} | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						export const requiresUser = !!OPENID_CLIENT_ID && !!OPENID_CLIENT_SECRET; | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						export function refreshSessionCookie(cookies: Cookies, sessionId: string) { | 
					
					
						
						| 
							 | 
							cookies.set(COOKIE_NAME, sessionId, { | 
					
					
						
						| 
							 | 
								path: "/", | 
					
					
						
						| 
							 | 
								 | 
					
					
						
						| 
							 | 
								sameSite: dev ? "lax" : "none", | 
					
					
						
						| 
							 | 
								secure: !dev, | 
					
					
						
						| 
							 | 
								httpOnly: true, | 
					
					
						
						| 
							 | 
								expires: addYears(new Date(), 1), | 
					
					
						
						| 
							 | 
							}); | 
					
					
						
						| 
							 | 
						} | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						export const authCondition = (locals: App.Locals) => { | 
					
					
						
						| 
							 | 
							return locals.user | 
					
					
						
						| 
							 | 
								? { userId: locals.user._id } | 
					
					
						
						| 
							 | 
								: { sessionId: locals.sessionId, userId: { $exists: false } }; | 
					
					
						
						| 
							 | 
						}; | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						 | 
					
					
						
						| 
							 | 
						 | 
					
					
						
						| 
							 | 
						 | 
					
					
						
						| 
							 | 
						export async function generateCsrfToken(sessionId: string, redirectUrl: string): Promise<string> { | 
					
					
						
						| 
							 | 
							const data = { | 
					
					
						
						| 
							 | 
								expiration: addHours(new Date(), 1).getTime(), | 
					
					
						
						| 
							 | 
								redirectUrl, | 
					
					
						
						| 
							 | 
							}; | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
							return Buffer.from( | 
					
					
						
						| 
							 | 
								JSON.stringify({ | 
					
					
						
						| 
							 | 
									data, | 
					
					
						
						| 
							 | 
									signature: await sha256(JSON.stringify(data) + "##" + sessionId), | 
					
					
						
						| 
							 | 
								}) | 
					
					
						
						| 
							 | 
							).toString("base64"); | 
					
					
						
						| 
							 | 
						} | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						async function getOIDCClient(settings: OIDCSettings): Promise<BaseClient> { | 
					
					
						
						| 
							 | 
							const issuer = await Issuer.discover(OPENID_PROVIDER_URL); | 
					
					
						
						| 
							 | 
							return new issuer.Client({ | 
					
					
						
						| 
							 | 
								client_id: OPENID_CLIENT_ID, | 
					
					
						
						| 
							 | 
								client_secret: OPENID_CLIENT_SECRET, | 
					
					
						
						| 
							 | 
								redirect_uris: [settings.redirectURI], | 
					
					
						
						| 
							 | 
								response_types: ["code"], | 
					
					
						
						| 
							 | 
							}); | 
					
					
						
						| 
							 | 
						} | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						export async function getOIDCAuthorizationUrl( | 
					
					
						
						| 
							 | 
							settings: OIDCSettings, | 
					
					
						
						| 
							 | 
							params: { sessionId: string } | 
					
					
						
						| 
							 | 
						): Promise<string> { | 
					
					
						
						| 
							 | 
							const client = await getOIDCClient(settings); | 
					
					
						
						| 
							 | 
							const csrfToken = await generateCsrfToken(params.sessionId, settings.redirectURI); | 
					
					
						
						| 
							 | 
							const url = client.authorizationUrl({ | 
					
					
						
						| 
							 | 
								scope: OPENID_SCOPES, | 
					
					
						
						| 
							 | 
								state: csrfToken, | 
					
					
						
						| 
							 | 
							}); | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
							return url; | 
					
					
						
						| 
							 | 
						} | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						export async function getOIDCUserData(settings: OIDCSettings, code: string): Promise<OIDCUserInfo> { | 
					
					
						
						| 
							 | 
							const client = await getOIDCClient(settings); | 
					
					
						
						| 
							 | 
							const token = await client.callback(settings.redirectURI, { code }); | 
					
					
						
						| 
							 | 
							const userData = await client.userinfo(token); | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
							return { token, userData }; | 
					
					
						
						| 
							 | 
						} | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						export async function validateAndParseCsrfToken( | 
					
					
						
						| 
							 | 
							token: string, | 
					
					
						
						| 
							 | 
							sessionId: string | 
					
					
						
						| 
							 | 
						): Promise<{ | 
					
					
						
						| 
							 | 
							 | 
					
					
						
						| 
							 | 
							redirectUrl: string; | 
					
					
						
						| 
							 | 
						} | null> { | 
					
					
						
						| 
							 | 
							try { | 
					
					
						
						| 
							 | 
								const { data, signature } = z | 
					
					
						
						| 
							 | 
									.object({ | 
					
					
						
						| 
							 | 
										data: z.object({ | 
					
					
						
						| 
							 | 
											expiration: z.number().int(), | 
					
					
						
						| 
							 | 
											redirectUrl: z.string().url(), | 
					
					
						
						| 
							 | 
										}), | 
					
					
						
						| 
							 | 
										signature: z.string().length(64), | 
					
					
						
						| 
							 | 
									}) | 
					
					
						
						| 
							 | 
									.parse(JSON.parse(token)); | 
					
					
						
						| 
							 | 
								const reconstructSign = await sha256(JSON.stringify(data) + "##" + sessionId); | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
								if (data.expiration > Date.now() && signature === reconstructSign) { | 
					
					
						
						| 
							 | 
									return { redirectUrl: data.redirectUrl }; | 
					
					
						
						| 
							 | 
								} | 
					
					
						
						| 
							 | 
							} catch (e) { | 
					
					
						
						| 
							 | 
								console.error(e); | 
					
					
						
						| 
							 | 
							} | 
					
					
						
						| 
							 | 
							return null; | 
					
					
						
						| 
							 | 
						} | 
					
					
						
						| 
							 | 
						
 |