fix(mfa): generate SVG QR code

Replace the rasterized 180px PNG QR code with a crisp 250px SVG
This commit is contained in:
jubnl
2026-04-05 17:14:36 +02:00
parent 9ee5d21c3a
commit c6148ba4f2
4 changed files with 7 additions and 7 deletions

View File

@@ -260,8 +260,8 @@ router.post('/mfa/setup', authenticate, (req: Request, res: Response) => {
const result = setupMfa(authReq.user.id, authReq.user.email);
if (result.error) return res.status(result.status!).json({ error: result.error });
result.qrPromise!
.then((qr_data_url: string) => {
res.json({ secret: result.secret, otpauth_url: result.otpauth_url, qr_data_url });
.then((qr_svg: string) => {
res.json({ secret: result.secret, otpauth_url: result.otpauth_url, qr_svg });
})
.catch((err: unknown) => {
console.error('[MFA] QR code generation error:', err);

View File

@@ -816,7 +816,7 @@ export function setupMfa(userId: number, userEmail: string): { error?: string; s
console.error('[MFA] Setup error:', err);
return { error: 'MFA setup failed', status: 500 };
}
return { secret, otpauth_url, qrPromise: QRCode.toDataURL(otpauth_url) };
return { secret, otpauth_url, qrPromise: QRCode.toString(otpauth_url, { type: 'svg', width: 250 }) };
}
export function enableMfa(userId: number, code?: string): { error?: string; status?: number; success?: boolean; mfa_enabled?: boolean; backup_codes?: string[] } {

View File

@@ -312,7 +312,7 @@ describe('MFA', () => {
expect(res.status).toBe(200);
expect(res.body.secret).toBeDefined();
expect(res.body.otpauth_url).toContain('otpauth://');
expect(res.body.qr_data_url).toMatch(/^data:image/);
expect(res.body.qr_svg).toMatch(/^<svg/);
});
it('AUTH-015 — POST /api/auth/mfa/enable with valid TOTP code enables MFA', async () => {