import { AuthContext, MiddlewareContext, MiddlewareOptions } from "better-auth"; import { AccountRepository } from "../user/account.repository"; import { FlowExecCtx } from "@/core/flow.execution.context"; import { ResultAsync } from "neverthrow"; import { authErrors } from "./errors"; import { logger } from "@pkg/logger"; import { nanoid } from "nanoid"; import { db } from "@pkg/db"; export class AuthController { constructor(private accountRepo: AccountRepository) {} swapAccountPasswordForTwoFactor( fctx: FlowExecCtx, ctx: MiddlewareContext< MiddlewareOptions, AuthContext & { returned?: unknown; responseHeaders?: Headers } >, ) { logger.info("Swapping account password for 2FA", { ...fctx, }); if (!ctx.path.includes("two-factor")) { return ResultAsync.fromSafePromise(Promise.resolve(ctx)); } if (!ctx.body.password || ctx.body.password.length === 0) { return ResultAsync.fromSafePromise(Promise.resolve(ctx)); } logger.info("Rotating password for 2FA setup for user", { ...fctx, userId: ctx.body.userId, }); return this.accountRepo .rotatePassword(fctx, ctx.body.userId, nanoid()) .mapErr((err) => { logger.error("Failed to rotate password for 2FA", { ...fctx, error: err, }); return authErrors.passwordRotationFailed(fctx, err.detail); }) .map((newPassword) => { logger.info("Password rotated successfully for 2FA setup", { ...fctx, }); return { ...ctx, body: { ...ctx.body, password: newPassword }, }; }); } } export function getAuthController(): AuthController { return new AuthController(new AccountRepository(db)); }