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

Commit

Permalink
♻️ Hash passwords, ensure uncompromised
Browse files Browse the repository at this point in the history
  • Loading branch information
AnandChowdhary committed Oct 24, 2020
1 parent 183b674 commit b7cf9f3
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 1 deletion.
1 change: 1 addition & 0 deletions src/config/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export default () => ({
saltRounds: process.env.SALT_ROUNDS ?? 10,
jwtSecret: process.env.JWT_SECRET ?? 'staart',
accessTokenExpiry: process.env.ACCESS_TOKEN_EXPIRY ?? '1h',
passwordPwnedCheck: !!process.env.PASSWORD_PWNED_CHECK,
},
email: {
name: process.env.EMAIL_NAME ?? 'Staart',
Expand Down
4 changes: 4 additions & 0 deletions src/modules/auth/auth.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ export class RegisterDto {
@IsObject()
@IsOptional()
attributes?: Record<string, any>;

@IsBoolean()
@IsOptional()
ignorePwnedPassword?: boolean;
}

export class ResendEmailVerificationDto {
Expand Down
24 changes: 23 additions & 1 deletion src/modules/auth/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ import { Expose } from '../prisma/prisma.interface';
import { PrismaService } from '../prisma/prisma.service';
import { UsersService } from '../user/user.service';
import { RegisterDto } from './auth.dto';
import { compare } from 'bcrypt';
import { compare, hash } from 'bcrypt';
import { JwtService } from '@nestjs/jwt';
import { randomStringGenerator } from '@nestjs/common/utils/random-string-generator.util';
import { AccessTokenClaims } from './auth.interface';
import { PwnedService } from '../pwned/pwned.service';

@Injectable()
export class AuthService {
Expand All @@ -25,6 +26,7 @@ export class AuthService {
private email: EmailService,
private configService: ConfigService,
private jwtService: JwtService,
private pwnedService: PwnedService,
) {}

async validateUser(email: string, password?: string): Promise<number> {
Expand Down Expand Up @@ -66,7 +68,17 @@ export class AuthService {
async register(data: RegisterDto): Promise<Expose<users>> {
const email = data.email;
const emailSafe = this.users.getSafeEmail(email);
const ignorePwnedPassword = !!data.ignorePwnedPassword;
delete data.email;
delete data.ignorePwnedPassword;

if (data.password) {
if (!ignorePwnedPassword) await this.ensureSafePassword(data.password);
data.password = await hash(
data.password,
this.configService.get<number>('security.saltRounds'),
);
}

const users = await this.users.users({
take: 1,
Expand Down Expand Up @@ -150,6 +162,16 @@ export class AuthService {
});
}

async ensureSafePassword(password: string): Promise<void> {
if (!this.configService.get<boolean>('security.passwordPwnedCheck')) return;
const isSafe = this.pwnedService.isPasswordSafe(password);
if (!isSafe)
throw new HttpException(
'This password has been compromised in a data breach.',
HttpStatus.BAD_REQUEST,
);
}

async getScopes(userId: number): Promise<string[]> {
const scopes: string[] = [`user-${userId}:*`];
const memberships = await this.prisma.memberships.findMany({
Expand Down

0 comments on commit b7cf9f3

Please sign in to comment.