Skip to content

Commit 7b6e29d

Browse files
committed
feat: implement password change dialog and validation in agent settings
#157
1 parent c501347 commit 7b6e29d

6 files changed

Lines changed: 339 additions & 143 deletions

File tree

apps/api/src/core/agents/agents.controller.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -405,9 +405,10 @@ export class AgentsController extends AbstractController {
405405
}
406406

407407
const newPassword = `${payload.password}`.trim();
408-
if ((await this.passwdadmService.checkPolicies(newPassword)) === false) {
408+
const policyViolation = await this.passwdadmService.getPolicyViolation(newPassword);
409+
if (policyViolation) {
409410
throw new BadRequestException({
410-
message: 'Une erreur est survenue : Le mot de passe ne respecte pas la politique des mots de passe',
411+
message: policyViolation,
411412
error: 'Bad Request',
412413
statusCode: 400,
413414
});
@@ -778,9 +779,10 @@ export class AgentsController extends AbstractController {
778779
const payload: Record<string, any> = { ...(body as Record<string, any>) };
779780
if (typeof payload.password === 'string' && payload.password.trim().length > 0) {
780781
const newPassword = `${payload.password}`.trim();
781-
if ((await this.passwdadmService.checkPolicies(newPassword)) === false) {
782+
const policyViolation = await this.passwdadmService.getPolicyViolation(newPassword);
783+
if (policyViolation) {
782784
throw new BadRequestException({
783-
message: 'Une erreur est survenue : Le mot de passe ne respecte pas la politique des mots de passe',
785+
message: policyViolation,
784786
error: 'Bad Request',
785787
statusCode: 400,
786788
});

apps/api/src/settings/passwdadm.service.ts

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,54 +15,55 @@ export class PasswdadmService extends AbstractSettingsService {
1515
return this.setParameter('passwordpolicies', policies);
1616
}
1717

18-
public async checkPolicies(password: string): Promise<boolean> {
18+
public async getPolicyViolation(password: string): Promise<string | null> {
1919
const policies = await this.getPolicies();
2020
if (password.length < policies.len) {
2121
this.logger.error('Password too short');
22-
return false;
22+
return `Le mot de passe est trop court (minimum ${policies.len} caractères)`;
2323
}
24-
//tes caracteres speciaux
2524
if (policies.hasSpecialChars > 0) {
2625
if (/[!@#\$%\^\&*\)\(+=._-]/.test(password) === false) {
2726
this.logger.error('must have special characters');
28-
return false;
27+
return 'Le mot de passe doit contenir au moins un caractère spécial';
2928
}
3029
}
3130
if (policies.hasLowerCase > 0) {
3231
if (/[a-z]/.test(password) === false) {
3332
this.logger.error('must have lower case characters');
34-
return false;
33+
return 'Le mot de passe doit contenir au moins une minuscule';
3534
}
3635
}
3736
if (policies.hasUpperCase > 0) {
3837
if (/[A-Z]/.test(password) === false) {
3938
this.logger.error('must have upper case characters');
40-
return false;
39+
return 'Le mot de passe doit contenir au moins une majuscule';
4140
}
4241
}
4342
if (policies.hasNumbers > 0) {
4443
if (/[0-9]/.test(password) === false) {
4544
this.logger.error('must have number');
46-
return false;
45+
return 'Le mot de passe doit contenir au moins un chiffre';
4746
}
4847
}
49-
//calcul de l'entropie
5048
if (policies.minComplexity > 0) {
5149
const c = stringEntropy(password);
5250
if (c < policies.minComplexity) {
5351
this.logger.error('entropie trop faible');
54-
return false;
52+
return 'La complexité du mot de passe est insuffisante';
5553
}
5654
}
5755

58-
// check si le mdp est pwned
5956
if (policies.checkPwned === true) {
6057
const numPwns = await pwnedPassword(password);
6158
if (numPwns > 0) {
62-
return false;
59+
return "Ce mot de passe est déjà apparu lors d'une violation de données";
6360
}
6461
}
65-
return true;
62+
return null;
63+
}
64+
65+
public async checkPolicies(password: string): Promise<boolean> {
66+
return (await this.getPolicyViolation(password)) === null;
6667
}
6768

6869
protected async defaultValues<T = PasswordPoliciesDto>(): Promise<T> {

apps/api/tests/unit/settings/passwdadm.service.spec.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { PasswdadmService } from '~/settings/passwdadm.service';
22

3-
describe('PasswdadmService.checkPolicies', () => {
3+
describe('PasswdadmService.getPolicyViolation', () => {
44
it('should reject when hasNumbers enabled and password has no digits', async () => {
55
const ctx = {
66
getPolicies: async () => ({
@@ -15,8 +15,8 @@ describe('PasswdadmService.checkPolicies', () => {
1515
logger: { error: jest.fn() },
1616
} as any;
1717

18-
const ok = await PasswdadmService.prototype.checkPolicies.call(ctx, 'NoDigitsHere!');
19-
expect(ok).toBe(false);
18+
const violation = await PasswdadmService.prototype.getPolicyViolation.call(ctx, 'NoDigitsHere!');
19+
expect(violation).toBe('Le mot de passe doit contenir au moins un chiffre');
2020
});
2121

2222
it('should accept when hasNumbers enabled and password has digits', async () => {
@@ -33,7 +33,7 @@ describe('PasswdadmService.checkPolicies', () => {
3333
logger: { error: jest.fn() },
3434
} as any;
3535

36-
const ok = await PasswdadmService.prototype.checkPolicies.call(ctx, 'Has1Digit');
37-
expect(ok).toBe(true);
36+
const violation = await PasswdadmService.prototype.getPolicyViolation.call(ctx, 'Has1Digit');
37+
expect(violation).toBeNull();
3838
});
3939
});

0 commit comments

Comments
 (0)