Files
website/layers/diary/server/utils/auth.ts
T
2026-09-30 19:15:57 +02:00

37 lines
1.2 KiB
TypeScript

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<DiarySession>(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<Uint8Array> {
return new Uint8Array(await crypto.subtle.digest('SHA-256', new TextEncoder().encode(text)))
}
export async function passwordMatches(event: H3Event, guess: string): Promise<boolean> {
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
}