import { randomBytes, scryptSync } from "node:crypto"; import { db } from "@kk/db"; import * as schema from "@kk/db/schema/auth"; import { env } from "@kk/env/server"; import { betterAuth } from "better-auth"; import { drizzleAdapter } from "better-auth/adapters/drizzle"; import { tanstackStartCookies } from "better-auth/tanstack-start"; import nodemailer from "nodemailer"; const _smtpFrom = env.SMTP_FROM ?? "Kunstenkamp "; let _transport: nodemailer.Transporter | null | undefined; function getTransport(): nodemailer.Transporter | null { if (_transport !== undefined) return _transport; if (!env.SMTP_HOST || !env.SMTP_USER || !env.SMTP_PASS) { _transport = null; return null; } _transport = nodemailer.createTransport({ host: env.SMTP_HOST, port: env.SMTP_PORT, secure: env.SMTP_PORT === 465, auth: { user: env.SMTP_USER, pass: env.SMTP_PASS }, }); return _transport; } async function sendPasswordResetEmail(to: string, resetUrl: string) { const transport = getTransport(); if (!transport) { console.warn("SMTP not configured — skipping password reset email"); return; } const html = ` Wachtwoord opnieuw instellen

Kunstenkamp

Wachtwoord opnieuw instellen

We hebben een aanvraag ontvangen om het wachtwoord van je Kunstenkamp-account opnieuw in te stellen.

Klik op de knop hieronder om een nieuw wachtwoord in te stellen. Deze link is 1 uur geldig.

Stel wachtwoord in

Of kopieer deze link: ${resetUrl}

Heb je dit niet aangevraagd? Dan hoef je niets te doen — je wachtwoord blijft ongewijzigd.

Vragen? Mail ons op info@kunstenkamp.be
Kunstenkamp vzw — Een initiatief voor en door kunstenaars.

`; await transport.sendMail({ from: _smtpFrom, to, subject: "Wachtwoord opnieuw instellen — Kunstenkamp", html, }); } export const auth = betterAuth({ database: drizzleAdapter(db, { provider: "sqlite", schema: schema, }), trustedOrigins: [ env.CORS_ORIGIN, "http://localhost:3000", "http://localhost:3001", ], emailAndPassword: { enabled: true, // Use Cloudflare's native scrypt via node:crypto for better performance // This avoids CPU time limit errors on Cloudflare Workers password: { hash: async (password) => { const salt = randomBytes(16).toString("hex"); const hash = scryptSync(password, salt, 64).toString("hex"); return `${salt}:${hash}`; }, verify: async ({ hash, password }) => { const [salt, key] = hash.split(":"); if (!salt || !key) return false; const keyBuffer = Buffer.from(key, "hex"); const hashBuffer = scryptSync(password, salt, 64); return keyBuffer.equals(hashBuffer); }, }, sendResetPassword: async ({ user, url }) => { await sendPasswordResetEmail(user.email, url); }, }, user: { additionalFields: { role: { type: "string", input: false, }, }, }, plugins: [tanstackStartCookies()], });