Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env.docker
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ APP_URL=http://localhost:3000
COOKIE_DOMAIN=localhost
COOKIE_SECRET=super-secret-here
JWT_SECRET=super-secret-here
HASH_PEPPER=super-pepper-here

# E-mails
EMAIL_PROVIDER=none
Expand Down
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ APP_URL="http://localhost:3000"
COOKIE_DOMAIN="localhost"
COOKIE_SECRET="super-secret-here"
JWT_SECRET="super-secret-here"
HASH_PEPPER="super-pepper-here"

# E-mails
EMAIL_PROVIDER="none"
Expand Down
1 change: 1 addition & 0 deletions .env.test
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ APP_URL="http://localhost:3000"
COOKIE_DOMAIN="localhost"
COOKIE_SECRET="test-cookie-secret-key-for-testing-only"
JWT_SECRET="test-jwt-secret-key-for-testing-only"
HASH_PEPPER="super-pepper-here"

# E-mails
EMAIL_PROVIDER="none"
Expand Down
21 changes: 15 additions & 6 deletions src/app/cryptography/crypography.service.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { createHmac } from 'node:crypto';

import { Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { compare, hash } from 'bcryptjs';
Expand All @@ -12,19 +14,26 @@ type SetCookieOptions = CookieOptions & {

@Injectable()
export class CryptographyService {
private readonly HASH_SALT_LENGTH = 10;

constructor(
private readonly jwtService: JwtService,
private readonly envService: EnvService,
) {}

createHash(plain: string): Promise<string> {
return hash(plain, this.HASH_SALT_LENGTH);
async createHash(plain: string): Promise<string> {
const rounds = this.envService.get('NODE_ENV') === 'test' ? 1 : 14;
const plainWithPepper = this.applyPepper(plain);
return await hash(plainWithPepper, rounds);
}

async compareHash(plain: string, hash: string): Promise<boolean> {
const plainWithPepper = this.applyPepper(plain);
return await compare(plainWithPepper, hash);
}

compareHash(plain: string, hash: string): Promise<boolean> {
return compare(plain, hash);
private applyPepper(value: string) {
const pepper = this.envService.get('HASH_PEPPER');
if (!pepper) return value;
return createHmac('sha256', pepper).update(value).digest('base64');
}

async verifyToken<Payload extends object>(token: string): Promise<Payload> {
Expand Down
3 changes: 2 additions & 1 deletion src/env/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ export const envSchema = z.object({
// Environment
NODE_ENV: z.enum(['production', 'development', 'homolog', 'test']),
APP_ENVIRONMENT: z.enum(['lambda', 'docker', 'local']),
MAINTENANCE: z.enum(['true', 'false']).transform((val) => val === 'true'),
ENABLE_NEST_LOGS: z
.enum(['true', 'false'])
.transform((val) => val === 'true'),
MAINTENANCE: z.enum(['true', 'false']).transform((val) => val === 'true'),

// API
API_BASE_URL: z.string().url().optional(),
Expand All @@ -20,6 +20,7 @@ export const envSchema = z.object({
COOKIE_DOMAIN: z.string().min(1),
COOKIE_SECRET: z.string().min(1),
JWT_SECRET: z.string().min(1),
HASH_PEPPER: z.string().min(1),

// Database
DB_HOST: z.string().min(1),
Expand Down
Loading