feat!: reset password with email

This commit is contained in:
Elias Schneider
2023-02-09 18:17:53 +01:00
parent 8ab359b71d
commit 5d1a7f0310
20 changed files with 459 additions and 156 deletions

View File

@@ -6,10 +6,8 @@ import {
} from "@nestjs/common";
import { User } from "@prisma/client";
import * as argon from "argon2";
import * as crypto from "crypto";
import { authenticator, totp } from "otplib";
import * as qrcode from "qrcode-svg";
import { ConfigService } from "src/config/config.service";
import { PrismaService } from "src/prisma/prisma.service";
import { AuthService } from "./auth.service";
import { AuthSignInTotpDTO } from "./dto/authSignInTotp.dto";
@@ -17,7 +15,6 @@ import { AuthSignInTotpDTO } from "./dto/authSignInTotp.dto";
@Injectable()
export class AuthTotpService {
constructor(
private config: ConfigService,
private prisma: PrismaService,
private authService: AuthService
) {}
@@ -57,9 +54,7 @@ export class AuthTotpService {
throw new BadRequestException("TOTP is not enabled");
}
const decryptedSecret = this.decryptTotpSecret(totpSecret, dto.password);
const expected = authenticator.generate(decryptedSecret);
const expected = authenticator.generate(totpSecret);
if (dto.totp !== expected) {
throw new BadRequestException("Invalid code");
@@ -81,41 +76,6 @@ export class AuthTotpService {
return { accessToken, refreshToken };
}
encryptTotpSecret(totpSecret: string, password: string) {
let iv = this.config.get("TOTP_SECRET");
iv = Buffer.from(iv, "base64");
const key = crypto
.createHash("sha256")
.update(String(password))
.digest("base64")
.substr(0, 32);
const cipher = crypto.createCipheriv("aes-256-cbc", key, iv);
let encrypted = cipher.update(totpSecret);
encrypted = Buffer.concat([encrypted, cipher.final()]);
return encrypted.toString("base64");
}
decryptTotpSecret(encryptedTotpSecret: string, password: string) {
let iv = this.config.get("TOTP_SECRET");
iv = Buffer.from(iv, "base64");
const key = crypto
.createHash("sha256")
.update(String(password))
.digest("base64")
.substr(0, 32);
const encryptedText = Buffer.from(encryptedTotpSecret, "base64");
const decipher = crypto.createDecipheriv("aes-256-cbc", key, iv);
let decrypted = decipher.update(encryptedText);
decrypted = Buffer.concat([decrypted, decipher.final()]);
return decrypted.toString();
}
async enableTotp(user: User, password: string) {
if (!(await argon.verify(user.password, password)))
throw new ForbiddenException("Invalid password");
@@ -132,7 +92,6 @@ export class AuthTotpService {
// TODO: Maybe make the issuer configurable with env vars?
const secret = authenticator.generateSecret();
const encryptedSecret = this.encryptTotpSecret(secret, password);
const otpURL = totp.keyuri(
user.username || user.email,
@@ -144,7 +103,7 @@ export class AuthTotpService {
where: { id: user.id },
data: {
totpEnabled: true,
totpSecret: encryptedSecret,
totpSecret: secret,
},
});
@@ -177,9 +136,7 @@ export class AuthTotpService {
throw new BadRequestException("TOTP is not in progress");
}
const decryptedSecret = this.decryptTotpSecret(totpSecret, password);
const expected = authenticator.generate(decryptedSecret);
const expected = authenticator.generate(totpSecret);
if (code !== expected) {
throw new BadRequestException("Invalid code");
@@ -208,9 +165,7 @@ export class AuthTotpService {
throw new BadRequestException("TOTP is not enabled");
}
const decryptedSecret = this.decryptTotpSecret(totpSecret, password);
const expected = authenticator.generate(decryptedSecret);
const expected = authenticator.generate(totpSecret);
if (code !== expected) {
throw new BadRequestException("Invalid code");