import assert from "node:assert/strict"; import test from "node:test"; import type { Pool } from "pg"; import { buildAuthOptions, createEmailOtpOptions } from "../src/modules/identity/auth-factory.ts"; import { createDatabaseAdminAuthorizer, createIdentityPool } from "../src/modules/identity/auth.ts"; import { FakeEmailOtpSender } from "../src/modules/identity/email/fake-email-otp-sender.ts"; import type { SelfHostedIdentityConfig } from "../src/modules/identity/config.ts"; const config: SelfHostedIdentityConfig = { provider: "self-hosted", databaseUrl: "postgresql://identity_runtime:test-password@postgres:5432/jyotisha", userOrigin: "https://staging.jyotisha.chat", adminOrigin: "https://admin.staging.jyotisha.chat", userSecret: "user-secret-that-is-at-least-32-bytes-long", resendApiKey: "re_test", resendFrom: "Jyotisha ", testOtp: null }; const database = { kind: "pool" } as unknown as Pool; test("Better Auth trusts only the two exact origins and keeps host-only cookies", () => { const options = buildAuthOptions({ config, database, emailSender: new FakeEmailOtpSender() }); assert.equal(options.baseURL, config.userOrigin); assert.equal(options.secret, config.userSecret); assert.equal(options.advanced?.cookiePrefix, "jyotisha-user"); assert.deepEqual(options.trustedOrigins, [config.userOrigin, config.adminOrigin]); assert.equal(options.advanced?.defaultCookieAttributes?.domain, undefined); assert.ok(options.plugins?.some((plugin) => plugin.id === "email-otp")); assert.ok(options.plugins?.some((plugin) => plugin.id === "two-factor")); assert.ok(options.plugins?.some((plugin) => plugin.id === "admin")); assert.equal(options.databaseHooks, undefined); }); test("Better Auth two-factor plugin uses the identity schema without bypassing enrollment verification", () => { const options = buildAuthOptions({ config, database, emailSender: new FakeEmailOtpSender() }); const plugin = options.plugins?.find((candidate) => candidate.id === "two-factor"); assert.ok(plugin); assert.equal(plugin.schema?.twoFactor?.modelName, "two_factors"); assert.equal(plugin.schema?.user?.fields?.twoFactorEnabled?.defaultValue, false); assert.equal(plugin.schema?.twoFactor?.fields?.backupCodes?.returned, false); assert.equal(plugin.schema?.twoFactor?.fields?.secret?.returned, false); }); test("OTP policy remains hashed and bounded", async () => { const sender = new FakeEmailOtpSender(); const options = createEmailOtpOptions(sender, config.userSecret, false); assert.equal(options.storeOTP, "hashed"); assert.equal(options.allowedAttempts, 3); await options.sendVerificationOTP({ email: "person@example.com", otp: "123456", type: "sign-in" }); assert.match(sender.messages[0].idempotencyKey, /^otp-[0-9a-f]{64}$/); }); test("test OTP channel pins a fixed code and never sends a real email", async () => { const sender = new FakeEmailOtpSender(); const options = createEmailOtpOptions(sender, config.userSecret, false, "123456"); assert.equal(options.generateOTP?.({ email: "tester@example.com", type: "sign-in" }), "123456"); const message = sender.messages[0]; await options.sendVerificationOTP({ email: "tester@example.com", otp: "123456", type: "sign-in" }); assert.equal(sender.messages.length, 1); assert.equal(sender.messages[0].otp, "123456"); assert.match(sender.messages[0].idempotencyKey, /^otp-[0-9a-f]{64}$/); }); test("identity pool forces the identity search path", async () => { const pool = createIdentityPool(config.databaseUrl); try { assert.equal(pool.options.options, "-c search_path=identity,pg_catalog"); } finally { await pool.end(); } }); test("database admin authorizer accepts only persisted admin", async () => { const rows = new Map>([ ["admin", { role: "user,admin", banned: false, ban_expires: null }], ["viewer", { role: "viewer", banned: false, ban_expires: null }], ]); const pool = { async query(_sql: string, values: unknown[]) { const row = rows.get(String(values[0])); return { rows: row ? [row] : [] }; } } as unknown as Pool; const authorize = createDatabaseAdminAuthorizer(pool); assert.equal(await authorize("admin"), true); assert.equal(await authorize("viewer"), false); });