a LOTTTA more migration hoopla shii
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "@pkg/redis",
|
||||
"name": "@pkg/keystore",
|
||||
"module": "index.ts",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
@@ -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,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
{
|
||||
"name": "@pkg/logic",
|
||||
"scripts": {
|
||||
"auth:schemagen": "bun x @better-auth/cli generate --config ./domains/auth/config.base.ts --output ../../packages/db/schema/better.auth.schema.ts"
|
||||
"auth:schemagen": "pnpm dlx @better-auth/cli generate --config ./domains/auth/config.base.ts --output ../../packages/db/schema/better.auth.schema.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@hono/standard-validator": "^0.2.1",
|
||||
"@otplib/plugin-base32-scure": "^13.3.0",
|
||||
"@otplib/plugin-crypto-noble": "^13.3.0",
|
||||
"@otplib/totp": "^13.3.0",
|
||||
"@pkg/db": "workspace:*",
|
||||
"@pkg/logger": "workspace:*",
|
||||
"@pkg/redis": "workspace:*",
|
||||
"@pkg/keystore": "workspace:*",
|
||||
"@pkg/result": "workspace:*",
|
||||
"@pkg/settings": "workspace:*",
|
||||
"@types/pdfkit": "^0.14.0",
|
||||
|
||||
@@ -22,6 +22,7 @@ export const settingsSchema = v.object({
|
||||
betterAuthUrl: v.string(),
|
||||
betterAuthSecret: v.string(),
|
||||
|
||||
twoFaSecret: v.string(),
|
||||
twofaSessionExpiryMinutes: v.optional(v.number()),
|
||||
twofaRequiredHours: v.optional(v.number()),
|
||||
|
||||
@@ -107,6 +108,7 @@ function loadSettings(): Settings {
|
||||
betterAuthUrl: getEnv("BETTER_AUTH_URL"),
|
||||
betterAuthSecret: getEnv("BETTER_AUTH_SECRET"),
|
||||
|
||||
twoFaSecret: getEnv("TWOFA_SECRET"),
|
||||
twofaSessionExpiryMinutes: getEnvNumber(
|
||||
"TWOFA_SESSION_EXPIRY_MINUTES",
|
||||
10,
|
||||
|
||||
Reference in New Issue
Block a user