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

Commit 0cbe65c

Browse files
♻️ Update MFA module with returns
1 parent fd347ee commit 0cbe65c

2 files changed

Lines changed: 32 additions & 27 deletions

File tree

src/modules/multi-factor-authentication/multi-factor-authentication.controller.ts

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,7 @@ export class MultiFactorAuthenticationController {
2323
private multiFactorAuthenticationService: MultiFactorAuthenticationService,
2424
) {}
2525

26-
@Post('regenerate')
27-
@Scopes('user-{userId}:write-mfa-regenerate')
28-
async regenerateBackupCodes(
29-
@Param('userId', ParseIntPipe) userId: number,
30-
): Promise<string[]> {
31-
return this.multiFactorAuthenticationService.regenerateBackupCodes(userId);
32-
}
33-
26+
/** Disable MFA for a user */
3427
@Delete()
3528
@Scopes('user-{userId}:delete-mfa-*')
3629
async disable2FA(
@@ -39,53 +32,70 @@ export class MultiFactorAuthenticationController {
3932
return this.multiFactorAuthenticationService.disableMfa(userId);
4033
}
4134

35+
/** Regenerate backup codes for a user */
36+
@Post('regenerate')
37+
@Scopes('user-{userId}:write-mfa-regenerate')
38+
async regenerateBackupCodes(
39+
@Param('userId', ParseIntPipe) userId: number,
40+
): Promise<string[]> {
41+
return this.multiFactorAuthenticationService.regenerateBackupCodes(userId);
42+
}
43+
44+
/** Enable TOTP-based MFA for a user */
4245
@Post('totp')
4346
@Scopes('user-{userId}:write-mfa-totp')
4447
async enableTotp(
4548
@Param('userId', ParseIntPipe) userId: number,
4649
@Body() body: EnableTotpMfaDto,
47-
): Promise<string[] | string> {
50+
): Promise<string[] | { img: string }> {
4851
if (body.token)
4952
return this.multiFactorAuthenticationService.enableMfa(
5053
'TOTP',
5154
userId,
5255
body.token,
5356
);
54-
return this.multiFactorAuthenticationService.requestTotpMfa(userId);
57+
return {
58+
img: await this.multiFactorAuthenticationService.requestTotpMfa(userId),
59+
};
5560
}
5661

62+
/** Enable SMS-based MFA for a user */
5763
@Post('sms')
5864
@Scopes('user-{userId}:write-mfa-sms')
5965
async enableSms(
6066
@Param('userId', ParseIntPipe) userId: number,
6167
@Body() body: EnableSmsMfaDto,
62-
): Promise<string[] | void> {
68+
): Promise<string[] | { success: true }> {
6369
if (body.token)
6470
return this.multiFactorAuthenticationService.enableMfa(
6571
'SMS',
6672
userId,
6773
body.token,
6874
);
69-
if (body.phone)
70-
return this.multiFactorAuthenticationService.requestSmsMfa(
75+
if (body.phone) {
76+
await this.multiFactorAuthenticationService.requestSmsMfa(
7177
userId,
7278
body.phone,
7379
);
80+
return { success: true };
81+
}
7482
throw new BadRequestException(MFA_PHONE_OR_TOKEN_REQUIRED);
7583
}
7684

85+
/** Enable email-based MFA for a user */
7786
@Post('email')
7887
@Scopes('user-{userId}:write-mfa-email')
7988
async enableEmail(
8089
@Param('userId', ParseIntPipe) userId: number,
8190
@Body() body: EnableTotpMfaDto,
82-
): Promise<string[] | void> {
91+
): Promise<string[] | { success: true }> {
8392
if (body.token)
8493
return this.multiFactorAuthenticationService.enableMfa(
8594
'EMAIL',
8695
userId,
8796
body.token,
8897
);
89-
return this.multiFactorAuthenticationService.requestEmailMfa(userId);
98+
await this.multiFactorAuthenticationService.requestEmailMfa(userId);
99+
return { success: true };
90100
}
91101
}

src/modules/multi-factor-authentication/multi-factor-authentication.service.ts

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import { ConfigService } from '@nestjs/config';
88
import type { MfaMethod } from '@prisma/client';
99
import { User } from '@prisma/client';
1010
import { hash } from 'bcrypt';
11-
import { Configuration } from '../../config/configuration.interface';
1211
import {
1312
MFA_ENABLED_CONFLICT,
1413
MFA_NOT_ENABLED,
@@ -52,18 +51,16 @@ export class MultiFactorAuthenticationService {
5251
if (!enabled) throw new NotFoundException(USER_NOT_FOUND);
5352
if (enabled.twoFactorMethod !== 'NONE')
5453
throw new ConflictException(MFA_ENABLED_CONFLICT);
55-
const secret = this.tokensService.generateUuid();
54+
const secret = this.auth.authenticator.generateSecret();
5655
await this.prisma.user.update({
5756
where: { id: userId },
5857
data: { twoFactorSecret: secret, twoFactorPhone: phone },
5958
});
6059
return this.twilioService.send({
6160
to: phone,
62-
body: `${this.auth.getOneTimePassword(
63-
secret,
64-
)} is your ${this.configService.get<Configuration['meta']['appName']>(
65-
'meta.appName',
66-
)} verification code.`,
61+
body: `${this.auth.getOneTimePassword(secret)} is your ${
62+
this.configService.get<string>('meta.appName') ?? ''
63+
} verification code.`,
6764
});
6865
}
6966

@@ -80,7 +77,7 @@ export class MultiFactorAuthenticationService {
8077
if (!user) throw new NotFoundException(USER_NOT_FOUND);
8178
if (user.twoFactorMethod !== 'NONE')
8279
throw new ConflictException(MFA_ENABLED_CONFLICT);
83-
const secret = this.tokensService.generateUuid();
80+
const secret = this.auth.authenticator.generateSecret();
8481
await this.prisma.user.update({
8582
where: { id: userId },
8683
data: { twoFactorSecret: secret },
@@ -124,13 +121,11 @@ export class MultiFactorAuthenticationService {
124121
await this.prisma.backupCode.deleteMany({ where: { user: { id } } });
125122
const codes: string[] = [];
126123
for await (const _ of [...Array(10)]) {
127-
const unsafeCode = this.tokensService.generateUuid();
124+
const unsafeCode = await this.tokensService.generateRandomString(10);
128125
codes.push(unsafeCode);
129126
const code = await hash(
130127
unsafeCode,
131-
this.configService.get<Configuration['security']['saltRounds']>(
132-
'security.saltRounds',
133-
) ?? 10,
128+
this.configService.get<number>('security.saltRounds') ?? 10,
134129
);
135130
await this.prisma.backupCode.create({
136131
data: { user: { connect: { id } }, code },

0 commit comments

Comments
 (0)