fix(auth): clean up MFA routes — remove redundant imports, use userRepo.update()
- Remove redundant dynamic import('node:crypto'), use top-level nodeCrypto
- Remove getCollection import, use userRepo.update() for mfaEnabled/mfaMethods
- Expand update() Pick type to include mfaEnabled, mfaMethods, emailVerified
- Remove unused _reply param from MFA policy PUT handler
This commit is contained in:
parent
362b915ea9
commit
bdb3e95e00
@ -16,7 +16,6 @@
|
|||||||
import type { FastifyInstance } from 'fastify';
|
import type { FastifyInstance } from 'fastify';
|
||||||
import { BadRequestError, UnauthorizedError, ForbiddenError } from '../../../lib/errors.js';
|
import { BadRequestError, UnauthorizedError, ForbiddenError } from '../../../lib/errors.js';
|
||||||
import * as nodeCrypto from 'node:crypto';
|
import * as nodeCrypto from 'node:crypto';
|
||||||
import { getCollection } from '../../../lib/datastore.js';
|
|
||||||
import * as userRepo from '../repository.js';
|
import * as userRepo from '../repository.js';
|
||||||
import * as mfaRepo from './repository.js';
|
import * as mfaRepo from './repository.js';
|
||||||
import * as jwt from '../jwt.js';
|
import * as jwt from '../jwt.js';
|
||||||
@ -27,7 +26,6 @@ import {
|
|||||||
MfaDisableSchema,
|
MfaDisableSchema,
|
||||||
MfaPolicySchema,
|
MfaPolicySchema,
|
||||||
} from './types.js';
|
} from './types.js';
|
||||||
import type { UserDoc } from '../types.js';
|
|
||||||
import type { MfaPolicyDoc } from './types.js';
|
import type { MfaPolicyDoc } from './types.js';
|
||||||
|
|
||||||
export async function mfaRoutes(app: FastifyInstance) {
|
export async function mfaRoutes(app: FastifyInstance) {
|
||||||
@ -44,8 +42,7 @@ export async function mfaRoutes(app: FastifyInstance) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Generate TOTP secret (base32)
|
// Generate TOTP secret (base32)
|
||||||
const { randomBytes } = await import('node:crypto');
|
const secretBuffer = nodeCrypto.randomBytes(20);
|
||||||
const secretBuffer = randomBytes(20);
|
|
||||||
const secret = base32Encode(secretBuffer);
|
const secret = base32Encode(secretBuffer);
|
||||||
|
|
||||||
// Encrypt the secret
|
// Encrypt the secret
|
||||||
@ -113,11 +110,7 @@ export async function mfaRoutes(app: FastifyInstance) {
|
|||||||
|
|
||||||
// Update user doc
|
// Update user doc
|
||||||
try {
|
try {
|
||||||
await getCollection<UserDoc>('users', '/id').update(payload.sub, payload.sub, {
|
await userRepo.update(payload.sub, { mfaEnabled: true, mfaMethods: ['totp'] });
|
||||||
mfaEnabled: true,
|
|
||||||
mfaMethods: ['totp'],
|
|
||||||
updatedAt: now,
|
|
||||||
} as Partial<UserDoc>);
|
|
||||||
} catch {
|
} catch {
|
||||||
// best-effort
|
// best-effort
|
||||||
}
|
}
|
||||||
@ -205,12 +198,7 @@ export async function mfaRoutes(app: FastifyInstance) {
|
|||||||
|
|
||||||
// Update user doc
|
// Update user doc
|
||||||
try {
|
try {
|
||||||
const now = new Date().toISOString();
|
await userRepo.update(payload.sub, { mfaEnabled: false, mfaMethods: [] });
|
||||||
await getCollection<UserDoc>('users', '/id').update(payload.sub, payload.sub, {
|
|
||||||
mfaEnabled: false,
|
|
||||||
mfaMethods: [],
|
|
||||||
updatedAt: now,
|
|
||||||
} as Partial<UserDoc>);
|
|
||||||
} catch {
|
} catch {
|
||||||
// best-effort
|
// best-effort
|
||||||
}
|
}
|
||||||
@ -265,7 +253,7 @@ export async function mfaRoutes(app: FastifyInstance) {
|
|||||||
return { policy: policy ?? null };
|
return { policy: policy ?? null };
|
||||||
});
|
});
|
||||||
|
|
||||||
app.put('/auth/mfa/policies/:productId', async (req, _reply) => {
|
app.put('/auth/mfa/policies/:productId', async req => {
|
||||||
const role = req.jwtPayload?.role;
|
const role = req.jwtPayload?.role;
|
||||||
if (!role || !['super_admin', 'admin'].includes(role)) {
|
if (!role || !['super_admin', 'admin'].includes(role)) {
|
||||||
throw new ForbiddenError('Admin access required');
|
throw new ForbiddenError('Admin access required');
|
||||||
|
|||||||
@ -88,7 +88,19 @@ export async function countByPlan(productId: string): Promise<Record<string, num
|
|||||||
export async function update(
|
export async function update(
|
||||||
id: string,
|
id: string,
|
||||||
updates: Partial<
|
updates: Partial<
|
||||||
Pick<UserDoc, 'displayName' | 'role' | 'plan' | 'status' | 'phone' | 'bio' | 'avatarUrl'>
|
Pick<
|
||||||
|
UserDoc,
|
||||||
|
| 'displayName'
|
||||||
|
| 'role'
|
||||||
|
| 'plan'
|
||||||
|
| 'status'
|
||||||
|
| 'phone'
|
||||||
|
| 'bio'
|
||||||
|
| 'avatarUrl'
|
||||||
|
| 'mfaEnabled'
|
||||||
|
| 'mfaMethods'
|
||||||
|
| 'emailVerified'
|
||||||
|
>
|
||||||
>
|
>
|
||||||
): Promise<UserDoc | null> {
|
): Promise<UserDoc | null> {
|
||||||
try {
|
try {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user