n8n/packages/cli/src/controllers/mfa.controller.ts
कारतोफ्फेलस्क्रिप्ट™ f69ddcd796
refactor(core): Use Dependency Injection for all Controller classes (no-changelog) (#8146)
## Review / Merge checklist
- [x] PR title and summary are descriptive
2023-12-27 11:50:43 +01:00

98 lines
2.8 KiB
TypeScript

import { Authorized, Delete, Get, Post, RestController } from '@/decorators';
import { AuthenticatedRequest, MFA } from '@/requests';
import { MfaService } from '@/Mfa/mfa.service';
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
@Authorized()
@RestController('/mfa')
export class MFAController {
constructor(private mfaService: MfaService) {}
@Get('/qr')
async getQRCode(req: AuthenticatedRequest) {
const { email, id, mfaEnabled } = req.user;
if (mfaEnabled)
throw new BadRequestError(
'MFA already enabled. Disable it to generate new secret and recovery codes',
);
const { decryptedSecret: secret, decryptedRecoveryCodes: recoveryCodes } =
await this.mfaService.getSecretAndRecoveryCodes(id);
if (secret && recoveryCodes.length) {
const qrCode = this.mfaService.totp.generateTOTPUri({
secret,
label: email,
});
return {
secret,
recoveryCodes,
qrCode,
};
}
const newRecoveryCodes = this.mfaService.generateRecoveryCodes();
const newSecret = this.mfaService.totp.generateSecret();
const qrCode = this.mfaService.totp.generateTOTPUri({ secret: newSecret, label: email });
await this.mfaService.saveSecretAndRecoveryCodes(id, newSecret, newRecoveryCodes);
return {
secret: newSecret,
qrCode,
recoveryCodes: newRecoveryCodes,
};
}
@Post('/enable')
async activateMFA(req: MFA.Activate) {
const { token = null } = req.body;
const { id, mfaEnabled } = req.user;
const { decryptedSecret: secret, decryptedRecoveryCodes: recoveryCodes } =
await this.mfaService.getSecretAndRecoveryCodes(id);
if (!token) throw new BadRequestError('Token is required to enable MFA feature');
if (mfaEnabled) throw new BadRequestError('MFA already enabled');
if (!secret || !recoveryCodes.length) {
throw new BadRequestError('Cannot enable MFA without generating secret and recovery codes');
}
const verified = this.mfaService.totp.verifySecret({ secret, token, window: 10 });
if (!verified)
throw new BadRequestError('MFA token expired. Close the modal and enable MFA again', 997);
await this.mfaService.enableMfa(id);
}
@Delete('/disable')
async disableMFA(req: AuthenticatedRequest) {
const { id } = req.user;
await this.mfaService.disableMfa(id);
}
@Post('/verify')
async verifyMFA(req: MFA.Verify) {
const { id } = req.user;
const { token } = req.body;
const { decryptedSecret: secret } = await this.mfaService.getSecretAndRecoveryCodes(id);
if (!token) throw new BadRequestError('Token is required to enable MFA feature');
if (!secret) throw new BadRequestError('No MFA secret se for this user');
const verified = this.mfaService.totp.verifySecret({ secret, token });
if (!verified) throw new BadRequestError('MFA secret could not be verified');
}
}