a LOTTTA more migration hoopla shii

This commit is contained in:
user
2026-02-28 16:20:47 +02:00
parent 4d107c8cab
commit 2c8cd1fd15
18 changed files with 208 additions and 81 deletions

View File

@@ -1,7 +1,7 @@
import { errAsync, okAsync, ResultAsync } from "neverthrow";
import { FlowExecCtx } from "@core/flow.execution.context";
import { UserRepository } from "@domains/user/repository";
import { getRedisInstance, Redis } from "@pkg/redis";
import { getRedisInstance, Redis } from "@pkg/keystore";
import { TwofaRepository } from "./repository";
import { auth } from "../auth/config.base";
import type { TwoFaSession } from "./data";
@@ -17,6 +17,7 @@ export class TwofaController {
private twofaRepo: TwofaRepository,
private userRepo: UserRepository,
private store: Redis,
private secret: string,
) {}
checkTotp(secret: string, code: string) {
@@ -42,7 +43,7 @@ export class TwofaController {
.andThen((enabled) =>
enabled
? errAsync(twofaErrors.alreadyEnabled(fctx))
: this.twofaRepo.setup(fctx, user.id),
: this.twofaRepo.setup(fctx, user.id, this.secret),
)
.map((secret) => {
const appName = settings.appName;
@@ -345,5 +346,6 @@ export function getTwofaController() {
new TwofaRepository(db, _redis),
new UserRepository(db),
_redis,
settings.twoFaSecret,
);
}

View File

@@ -3,13 +3,15 @@ import { FlowExecCtx } from "@core/flow.execution.context";
import { hashString, verifyHash } from "@/core/hash.utils";
import { twoFactor, twofaSessions } from "@pkg/db/schema";
import { TwoFactor, type TwoFaSession } from "./data";
import { crypto } from "@otplib/plugin-crypto-noble";
import { base32 } from "@otplib/plugin-base32-scure";
import { and, Database, eq, gt, lt } from "@pkg/db";
import { generateSecret, verify } from "otplib";
import { generate, verify } from "@otplib/totp";
import { settings } from "@core/settings";
import type { Err } from "@pkg/result";
import { twofaErrors } from "./errors";
import { Redis } from "@pkg/keystore";
import { logger } from "@pkg/logger";
import { Redis } from "@pkg/redis";
import { nanoid } from "nanoid";
type TwoFaSetup = {
@@ -30,7 +32,7 @@ export class TwofaRepository {
) {}
checkTotp(secret: string, code: string) {
const checked = verify({ secret, token: code });
const checked = verify({ secret, token: code, crypto, base32 });
logger.debug("TOTP check result", { checked });
return checked;
}
@@ -98,14 +100,22 @@ export class TwofaRepository {
});
}
setup(fctx: FlowExecCtx, userId: string): ResultAsync<string, Err> {
setup(
fctx: FlowExecCtx,
userId: string,
secret: string,
): ResultAsync<string, Err> {
logger.info("Starting 2FA setup", { ...fctx, userId });
return ResultAsync.fromSafePromise(
(async () => {
const secret = generateSecret();
const payload = {
const token = await generate({
secret,
crypto,
base32,
});
const payload = {
secret: token,
lastUsedCode: "",
tries: 0,
} as TwoFaSetup;

View File

@@ -10,7 +10,7 @@ import { AuthController, getAuthController } from "./controller";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { FlowExecCtx } from "@/core/flow.execution.context";
import { UserRoleMap } from "@domains/user/data";
import { getRedisInstance } from "@pkg/redis";
import { getRedisInstance } from "@pkg/keystore";
import { APIError } from "better-auth/api";
import { settings } from "@core/settings";
import { betterAuth } from "better-auth";