Skip to content
This repository has been archived by the owner on Apr 19, 2023. It is now read-only.

Commit

Permalink
♻️ Update MFA module with returns
Browse files Browse the repository at this point in the history
  • Loading branch information
AnandChowdhary committed Jan 9, 2021
1 parent fd347ee commit 0cbe65c
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,7 @@ export class MultiFactorAuthenticationController {
private multiFactorAuthenticationService: MultiFactorAuthenticationService,
) {}

@Post('regenerate')
@Scopes('user-{userId}:write-mfa-regenerate')
async regenerateBackupCodes(
@Param('userId', ParseIntPipe) userId: number,
): Promise<string[]> {
return this.multiFactorAuthenticationService.regenerateBackupCodes(userId);
}

/** Disable MFA for a user */
@Delete()
@Scopes('user-{userId}:delete-mfa-*')
async disable2FA(
Expand All @@ -39,53 +32,70 @@ export class MultiFactorAuthenticationController {
return this.multiFactorAuthenticationService.disableMfa(userId);
}

/** Regenerate backup codes for a user */
@Post('regenerate')
@Scopes('user-{userId}:write-mfa-regenerate')
async regenerateBackupCodes(
@Param('userId', ParseIntPipe) userId: number,
): Promise<string[]> {
return this.multiFactorAuthenticationService.regenerateBackupCodes(userId);
}

/** Enable TOTP-based MFA for a user */
@Post('totp')
@Scopes('user-{userId}:write-mfa-totp')
async enableTotp(
@Param('userId', ParseIntPipe) userId: number,
@Body() body: EnableTotpMfaDto,
): Promise<string[] | string> {
): Promise<string[] | { img: string }> {
if (body.token)
return this.multiFactorAuthenticationService.enableMfa(
'TOTP',
userId,
body.token,
);
return this.multiFactorAuthenticationService.requestTotpMfa(userId);
return {
img: await this.multiFactorAuthenticationService.requestTotpMfa(userId),
};
}

/** Enable SMS-based MFA for a user */
@Post('sms')
@Scopes('user-{userId}:write-mfa-sms')
async enableSms(
@Param('userId', ParseIntPipe) userId: number,
@Body() body: EnableSmsMfaDto,
): Promise<string[] | void> {
): Promise<string[] | { success: true }> {
if (body.token)
return this.multiFactorAuthenticationService.enableMfa(
'SMS',
userId,
body.token,
);
if (body.phone)
return this.multiFactorAuthenticationService.requestSmsMfa(
if (body.phone) {
await this.multiFactorAuthenticationService.requestSmsMfa(
userId,
body.phone,
);
return { success: true };
}
throw new BadRequestException(MFA_PHONE_OR_TOKEN_REQUIRED);
}

/** Enable email-based MFA for a user */
@Post('email')
@Scopes('user-{userId}:write-mfa-email')
async enableEmail(
@Param('userId', ParseIntPipe) userId: number,
@Body() body: EnableTotpMfaDto,
): Promise<string[] | void> {
): Promise<string[] | { success: true }> {
if (body.token)
return this.multiFactorAuthenticationService.enableMfa(
'EMAIL',
userId,
body.token,
);
return this.multiFactorAuthenticationService.requestEmailMfa(userId);
await this.multiFactorAuthenticationService.requestEmailMfa(userId);
return { success: true };
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { ConfigService } from '@nestjs/config';
import type { MfaMethod } from '@prisma/client';
import { User } from '@prisma/client';
import { hash } from 'bcrypt';
import { Configuration } from '../../config/configuration.interface';
import {
MFA_ENABLED_CONFLICT,
MFA_NOT_ENABLED,
Expand Down Expand Up @@ -52,18 +51,16 @@ export class MultiFactorAuthenticationService {
if (!enabled) throw new NotFoundException(USER_NOT_FOUND);
if (enabled.twoFactorMethod !== 'NONE')
throw new ConflictException(MFA_ENABLED_CONFLICT);
const secret = this.tokensService.generateUuid();
const secret = this.auth.authenticator.generateSecret();
await this.prisma.user.update({
where: { id: userId },
data: { twoFactorSecret: secret, twoFactorPhone: phone },
});
return this.twilioService.send({
to: phone,
body: `${this.auth.getOneTimePassword(
secret,
)} is your ${this.configService.get<Configuration['meta']['appName']>(
'meta.appName',
)} verification code.`,
body: `${this.auth.getOneTimePassword(secret)} is your ${
this.configService.get<string>('meta.appName') ?? ''
} verification code.`,
});
}

Expand All @@ -80,7 +77,7 @@ export class MultiFactorAuthenticationService {
if (!user) throw new NotFoundException(USER_NOT_FOUND);
if (user.twoFactorMethod !== 'NONE')
throw new ConflictException(MFA_ENABLED_CONFLICT);
const secret = this.tokensService.generateUuid();
const secret = this.auth.authenticator.generateSecret();
await this.prisma.user.update({
where: { id: userId },
data: { twoFactorSecret: secret },
Expand Down Expand Up @@ -124,13 +121,11 @@ export class MultiFactorAuthenticationService {
await this.prisma.backupCode.deleteMany({ where: { user: { id } } });
const codes: string[] = [];
for await (const _ of [...Array(10)]) {
const unsafeCode = this.tokensService.generateUuid();
const unsafeCode = await this.tokensService.generateRandomString(10);
codes.push(unsafeCode);
const code = await hash(
unsafeCode,
this.configService.get<Configuration['security']['saltRounds']>(
'security.saltRounds',
) ?? 10,
this.configService.get<number>('security.saltRounds') ?? 10,
);
await this.prisma.backupCode.create({
data: { user: { connect: { id } }, code },
Expand Down

0 comments on commit 0cbe65c

Please sign in to comment.