import type { H3Event } from 'h3' interface DiarySession { unlocked?: boolean } const SESSION_MAX_AGE_S = 60 * 60 * 24 * 30 export function diarySession(event: H3Event) { const { sessionSecret } = useRuntimeConfig(event) if (!sessionSecret || sessionSecret.length < 32) { throw createError({ statusCode: 500, statusMessage: 'NUXT_SESSION_SECRET must be set (at least 32 characters)' }) } return useSession(event, { name: 'diary', password: sessionSecret, maxAge: SESSION_MAX_AGE_S, cookie: { httpOnly: true, sameSite: 'lax', secure: !import.meta.dev } }) } async function sha256(text: string): Promise { return new Uint8Array(await crypto.subtle.digest('SHA-256', new TextEncoder().encode(text))) } export async function passwordMatches(event: H3Event, guess: string): Promise { const { diaryPassword } = useRuntimeConfig(event) if (!diaryPassword) { throw createError({ statusCode: 500, statusMessage: 'NUXT_DIARY_PASSWORD is not set' }) } const [a, b] = await Promise.all([sha256(guess), sha256(diaryPassword)]) let difference = 0 for (let i = 0; i < a.length; i++) difference |= a[i]! ^ b[i]! return difference === 0 }