37 lines
1.2 KiB
TypeScript
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
|
|
}
|