Skip to content

Commit 59b7ad5

Browse files
committed
chore: Update ExecuteJobOptions interface to include updateStatus field
1 parent c409ee3 commit 59b7ad5

File tree

7 files changed

+103
-53
lines changed

7 files changed

+103
-53
lines changed

src/core/auth/_strategies/jwt.strategy.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') {
2727
payload: JwtPayload & { identity: AgentType },
2828
done: VerifiedCallback,
2929
): Promise<void> {
30-
Logger.debug(`Atempt to authenticate with JTI: <${payload.jti}>`, 'JwtStrategy');
30+
Logger.verbose(`Atempt to authenticate with JTI: <${payload.jti}>`, JwtStrategy.name);
3131
if (!payload?.identity) return done(new UnauthorizedException(), false);
3232
const user = await this.auth.verifyIdentity(payload);
3333

src/core/auth/_strategies/local.strategy.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export class LocalStrategy extends PassportStrategy(Strategy) {
2222
// eslint-disable-next-line
2323
done: (error: any, user?: Express.User | false, options?: IVerifyOptions) => void,
2424
): Promise<void> {
25-
Logger.debug(`Try to authenticate user : ${username}`, 'LocalStrategy');
25+
Logger.verbose(`Try to authenticate user : ${username}`, LocalStrategy.name);
2626
const user = await this.auth.authenticateWithLocal(username, password);
2727
// console.log(user);
2828
if (!user) done(new UnauthorizedException(), false);

src/core/auth/auth.service.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,6 @@ export class AuthService extends AbstractService implements OnModuleInit {
7070
public async authenticateWithLocal(username: string, password: string): Promise<Agents | null> {
7171
try {
7272
const user = await this.agentsService.findOne<Agents>({ username });
73-
// console.log(user);
7473
if (user && (await argon2Verify(user.password, password))) {
7574
return user;
7675
}
@@ -82,7 +81,6 @@ export class AuthService extends AbstractService implements OnModuleInit {
8281

8382
// eslint-disable-next-line
8483
public async verifyIdentity(payload: any & { identity: AgentType & { token: string } }): Promise<any> {
85-
this.logger.debug(`Atempt to authenticate with JTI: <${payload.jti}>`);
8684
if (payload.scopes.includes('offline')) {
8785
return payload.identity;
8886
}

src/core/backends/_interfaces/execute-job-options.interface.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export interface ExecuteJobOptions {
77
disableLogs?: boolean;
88
syncTimeout?: number;
99
timeoutDiscard?: boolean;
10+
updateStatus?: boolean;
1011
comment?: string;
1112
task?: Types.ObjectId;
1213
}

src/core/backends/backends.service.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import {
33
HttpException,
44
HttpStatus,
55
Injectable,
6-
NotFoundException,
76
UnprocessableEntityException,
87
} from '@nestjs/common';
98
import { ModuleRef } from '@nestjs/core';
@@ -244,7 +243,7 @@ export class BackendsService extends AbstractQueueProcessor {
244243
});
245244
}
246245

247-
if (concernedTo) {
246+
if (concernedTo && !!options?.updateStatus) {
248247
await this.identitiesService.model.findByIdAndUpdate(concernedTo, {
249248
$set: {
250249
state: IdentityState.PROCESSING,
@@ -257,6 +256,7 @@ export class BackendsService extends AbstractQueueProcessor {
257256
try {
258257
const response = await job.waitUntilFinished(this.queueEvents, options.syncTimeout || DEFAULT_SYNC_TIMEOUT);
259258
let jobStoreUpdated: ModifyResult<Query<Jobs, Jobs>> = null;
259+
260260
if (!options?.disableLogs) {
261261
jobStoreUpdated = await this.jobsService.update<Jobs>(jobStore._id, {
262262
$set: {
@@ -267,13 +267,15 @@ export class BackendsService extends AbstractQueueProcessor {
267267
},
268268
});
269269
}
270-
if (concernedTo) {
270+
271+
if (concernedTo && !!options?.updateStatus) {
271272
await this.identitiesService.model.findByIdAndUpdate(concernedTo, {
272273
$set: {
273274
state: IdentityState.SYNCED,
274275
},
275276
});
276277
}
278+
277279
return [jobStoreUpdated as unknown as Jobs, response];
278280
} catch (err) {
279281
error = err;
@@ -293,7 +295,7 @@ export class BackendsService extends AbstractQueueProcessor {
293295
},
294296
});
295297
}
296-
if (concernedTo) {
298+
if (concernedTo && !!options?.updateStatus) {
297299
await this.identitiesService.model.findByIdAndUpdate(concernedTo, {
298300
$set: {
299301
state: IdentityState.ON_ERROR,

src/management/passwd/passwd.controller.ts

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,18 @@ export class PasswdController {
1818
@ApiOperation({ summary: 'Execute un job de changement de mot de passe sur le/les backends' })
1919
@ApiResponse({ status: HttpStatus.OK, description: 'Mot de passe synchronisé sur le/les backends' })
2020
public async change(@Body() body: ChangePasswordDto, @Res() res: Response): Promise<Response> {
21+
const debug = {}
2122
const [_, data] = await this.passwdService.change(body);
2223
this.logger.log(`Call passwd change for : ${body.uid}`);
2324

24-
return res.status(HttpStatus.OK).json(data);
25+
if (process.env.NODE_ENV === 'development') {
26+
debug['_debug'] = data;
27+
}
28+
29+
return res.status(HttpStatus.OK).json({
30+
message: 'Password changed',
31+
...debug,
32+
});
2533
}
2634

2735
@Post('gettoken')
@@ -31,7 +39,7 @@ export class PasswdController {
3139
this.logger.log('GetToken for : ' + asktoken.uid);
3240
const token = await this.passwdService.askToken(asktoken);
3341

34-
return res.status(HttpStatus.OK).json({ token });
42+
return res.status(HttpStatus.OK).json({ data: { token } });
3543
}
3644

3745
@Post('verifytoken')
@@ -41,15 +49,23 @@ export class PasswdController {
4149
this.logger.log('Verify token : ' + body.token);
4250
const data = await this.passwdService.decryptToken(body.token);
4351

44-
return res.status(HttpStatus.OK).json(data);
52+
return res.status(HttpStatus.OK).json({ data });
4553
}
4654

4755
@Post('reset')
4856
@ApiOperation({ summary: 'Execute un job de réinitialisation de mot de passe sur le/les backends' })
4957
@ApiResponse({ status: HttpStatus.OK })
5058
public async reset(@Body() body: ResetPasswordDto, @Res() res: Response): Promise<Response> {
51-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
59+
const debug = {}
5260
const [_, data] = await this.passwdService.reset(body);
53-
return res.status(HttpStatus.OK).json(data);
61+
62+
if (process.env.NODE_ENV === 'development') {
63+
debug['_debug'] = data;
64+
}
65+
66+
return res.status(HttpStatus.OK).json({
67+
message: 'Password changed',
68+
...debug,
69+
});
5470
}
5571
}

src/management/passwd/passwd.service.ts

Lines changed: 73 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -42,68 +42,101 @@ export class PasswdService extends AbstractService {
4242
}
4343

4444
public async change(passwdDto: ChangePasswordDto): Promise<[Jobs, any]> {
45-
const identity = await this.identities.findOne({ 'inetOrgPerson.uid': passwdDto.uid }) as Identities;
46-
47-
return await this.backends.executeJob(ActionType.IDENTITY_PASSWORD_CHANGE, identity._id, {
48-
...passwdDto,
49-
...pick(identity.toJSON(), ['inetOrgPerson']),
50-
}, {
51-
async: false,
52-
});
45+
try {
46+
const identity = await this.identities.findOne({ 'inetOrgPerson.uid': passwdDto.uid }) as Identities;
47+
48+
return await this.backends.executeJob(ActionType.IDENTITY_PASSWORD_CHANGE, identity._id, {
49+
...passwdDto,
50+
...pick(identity.toJSON(), ['inetOrgPerson']),
51+
}, {
52+
async: false,
53+
timeoutDiscard: true,
54+
disableLogs: true,
55+
});
56+
} catch (e) {
57+
this.logger.error("Error while changing password. " + e + ` (uid=${passwdDto?.uid})`);
58+
throw new BadRequestException('Une erreur est survenue : Mot de passe incorrect ou utilisateur inconnu');
59+
}
5360
}
5461

5562
public async askToken(askToken: AskTokenDto): Promise<string> {
56-
await this.identities.findOne({ 'inetOrgPerson.uid': askToken.uid });
57-
58-
const k = crypto.randomBytes(PasswdService.RANDOM_BYTES_K).toString('hex');
59-
const iv = crypto.randomBytes(PasswdService.RANDOM_BYTES_IV).toString('base64');
60-
const cipher = crypto.createCipheriv(PasswdService.TOKEN_ALGORITHM, k, iv);
61-
62-
let ciphertext = cipher.update(
63-
JSON.stringify(<CipherData>{ uid: askToken.uid, mail: askToken.mail }),
64-
'utf8',
65-
'base64',
66-
);
67-
ciphertext += cipher.final('base64');
68-
69-
await this.redis.set(
70-
ciphertext,
71-
JSON.stringify(<TokenData>{
72-
k,
73-
iv,
74-
tag: cipher.getAuthTag().toString('base64'),
75-
}),
76-
);
77-
await this.redis.expire(ciphertext, PasswdService.TOKEN_EXPIRATION);
78-
return ciphertext;
63+
try {
64+
await this.identities.findOne({ 'inetOrgPerson.uid': askToken.uid });
65+
66+
const k = crypto.randomBytes(PasswdService.RANDOM_BYTES_K).toString('hex');
67+
const iv = crypto.randomBytes(PasswdService.RANDOM_BYTES_IV).toString('base64');
68+
const cipher = crypto.createCipheriv(PasswdService.TOKEN_ALGORITHM, k, iv);
69+
70+
let ciphertext = cipher.update(
71+
JSON.stringify(<CipherData>{ uid: askToken.uid, mail: askToken.mail }),
72+
'utf8',
73+
'base64',
74+
);
75+
ciphertext += cipher.final('base64');
76+
77+
await this.redis.set(
78+
ciphertext,
79+
JSON.stringify(<TokenData>{
80+
k,
81+
iv,
82+
tag: cipher.getAuthTag().toString('base64'),
83+
}),
84+
);
85+
await this.redis.expire(ciphertext, PasswdService.TOKEN_EXPIRATION);
86+
return ciphertext;
87+
} catch (e) {
88+
this.logger.error("Error while ask token. " + e + ` (uid=${askToken?.uid})`);
89+
throw new BadRequestException('Impossible de générer un token, une erreur est survenue');
90+
}
7991
}
8092

8193
public async decryptToken(token: string): Promise<CipherData> {
8294
try {
8395
const result = await this.redis.get(token);
8496
const cypherData: TokenData = JSON.parse(result);
8597

98+
if (cypherData?.iv === undefined || cypherData?.k === undefined || cypherData?.tag === undefined) {
99+
throw new NotFoundException('Invalid token');
100+
}
101+
86102
const decipher = crypto.createDecipheriv(PasswdService.TOKEN_ALGORITHM, cypherData.k, cypherData.iv);
87103
decipher.setAuthTag(Buffer.from(cypherData.tag, 'base64'));
88104
const plaintext = decipher.update(token, 'base64', 'ascii');
89105

90106
return JSON.parse(plaintext);
91107
} catch (error) {
108+
this.logger.verbose("Error while decrypting token. " + error + ` (token=${token})`);
92109
throw new BadRequestException('Invalid token');
93110
}
94111
}
95112

96113
public async reset(data: ResetPasswordDto): Promise<[Jobs, any]> {
97114
const tokenData = await this.decryptToken(data.token);
98-
const identity = await this.identities.findOne({ 'inetOrgPerson.uid': tokenData.uid }) as Identities;
99115

100-
return await this.backends.executeJob(
101-
ActionType.IDENTITY_PASSWORD_RESET,
102-
identity._id,
103-
{ uid: tokenData.uid, newPassword: data.newPassword, ...pick(identity, ['inetOrgPerson']) },
104-
{
105-
async: false,
106-
},
107-
);
116+
try {
117+
const identity = await this.identities.findOne({ 'inetOrgPerson.uid': tokenData.uid }) as Identities;
118+
119+
const [_, response] = await this.backends.executeJob(
120+
ActionType.IDENTITY_PASSWORD_RESET,
121+
identity._id,
122+
{ uid: tokenData.uid, newPassword: data.newPassword, ...pick(identity, ['inetOrgPerson']) },
123+
{
124+
async: false,
125+
timeoutDiscard: true,
126+
disableLogs: true,
127+
},
128+
);
129+
130+
if (response?.status === 0) {
131+
await this.redis.del(data.token);
132+
return [_, response];
133+
}
134+
135+
throw new InternalServerErrorException('Une erreur est survenue : Impossible de réinitialiser le mot de passe');
136+
137+
} catch (e) {
138+
this.logger.error("Error while reseting password. " + e + ` (token=${data?.token})`);
139+
throw new BadRequestException('Une erreur est survenue : Tentative de réinitialisation de mot de passe impossible');
140+
}
108141
}
109142
}

0 commit comments

Comments
 (0)