1- import { BadRequestException , forwardRef , HttpException , Inject , Injectable } from '@nestjs/common' ;
2- import { InjectModel } from '@nestjs/mongoose' ;
3- import { Document , Model , ModifyResult , Query , Types } from 'mongoose' ;
4- import { AbstractServiceSchema } from '~/_common/abstracts/abstract.service.schema' ;
5- import { AbstractSchema } from '~/_common/abstracts/schemas/abstract.schema' ;
6- import { ValidationConfigException , ValidationSchemaException } from '~/_common/errors/ValidationException' ;
7- import { IdentitiesUpsertDto } from './_dto/identities.dto' ;
8- import { IdentityState } from './_enums/states.enum' ;
9- import { Identities } from './_schemas/identities.schema' ;
10- import { IdentitiesValidationService } from './validations/identities.validation.service' ;
11- import { FactorydriveService } from '@the-software-compagny/nestjs_module_factorydrive' ;
12- import { BackendsService } from '~/core/backends/backends.service' ;
13- import { construct , omit } from 'radash' ;
14- import { toPlainAndCrush } from '~/_common/functions/to-plain-and-crush' ;
15- import { createHash } from 'node:crypto' ;
16- import { PasswdadmService } from "~/settings/passwdadm.service" ;
17- import { DataStatusEnum } from "~/management/identities/_enums/data-status" ;
18- import { JobState } from "~/core/jobs/_enums/state.enum" ;
1+ import { BadRequestException , forwardRef , HttpException , Inject , Injectable } from '@nestjs/common' ;
2+ import { InjectModel } from '@nestjs/mongoose' ;
3+ import { Document , Model , ModifyResult , Query , Types } from 'mongoose' ;
4+ import { AbstractServiceSchema } from '~/_common/abstracts/abstract.service.schema' ;
5+ import { AbstractSchema } from '~/_common/abstracts/schemas/abstract.schema' ;
6+ import { ValidationConfigException , ValidationSchemaException } from '~/_common/errors/ValidationException' ;
7+ import { IdentitiesUpsertDto } from './_dto/identities.dto' ;
8+ import { IdentityState } from './_enums/states.enum' ;
9+ import { Identities } from './_schemas/identities.schema' ;
10+ import { IdentitiesValidationService } from './validations/identities.validation.service' ;
11+ import { FactorydriveService } from '@the-software-compagny/nestjs_module_factorydrive' ;
12+ import { BackendsService } from '~/core/backends/backends.service' ;
13+ import { construct , omit } from 'radash' ;
14+ import { toPlainAndCrush } from '~/_common/functions/to-plain-and-crush' ;
15+ import { createHash } from 'node:crypto' ;
16+ import { PasswdadmService } from "~/settings/passwdadm.service" ;
17+ import { DataStatusEnum } from "~/management/identities/_enums/data-status" ;
18+ import { JobState } from "~/core/jobs/_enums/state.enum" ;
1919
2020@Injectable ( )
2121export abstract class AbstractIdentitiesService extends AbstractServiceSchema {
@@ -121,27 +121,40 @@ export abstract class AbstractIdentitiesService extends AbstractServiceSchema {
121121 return updated as unknown as ModifyResult < Query < T , T , any , T > > ;
122122 }
123123
124+ private stableStringify ( obj ) {
125+ if ( typeof obj !== "object" || obj === null ) {
126+ return JSON . stringify ( obj ) ;
127+ }
128+
129+ if ( Array . isArray ( obj ) ) {
130+ return `[${ obj . map ( this . stableStringify ) . join ( ',' ) } ]` ;
131+ }
132+
133+ return `{${ Object . keys ( obj ) . sort ( ) . map ( key =>
134+ JSON . stringify ( key ) + ':' + this . stableStringify ( obj [ key ] )
135+ ) . join ( ',' ) } }`;
136+ }
137+
124138 protected async previewFingerprint ( identity : any ) : Promise < string > {
125139 const additionalFields = omit ( identity . additionalFields , [ 'validations' ] ) ;
126- const data = JSON . stringify (
127- construct (
128- omit (
129- toPlainAndCrush ( {
130- inetOrgPerson : identity . inetOrgPerson ,
131- additionalFields,
132- } ) as any ,
133- [
134- //TODO: add configurable fields to exclude
135- /* 'additionalFields.attributes.supannPerson.supannOIDCGenre' */
136- ] ,
137- ) ,
140+ const data = construct (
141+ omit (
142+ toPlainAndCrush ( {
143+ inetOrgPerson : identity . inetOrgPerson ,
144+ additionalFields,
145+ } ) as any ,
146+ [
147+ //TODO: add configurable fields to exclude
148+ /* 'additionalFields.attributes.supannPerson.supannOIDCGenre' */
149+ ] ,
138150 ) ,
139151 ) ;
140152
141153 const hash = createHash ( 'sha256' ) ;
142- hash . update ( data ) ;
154+ hash . update ( this . stableStringify ( data ) ) ;
143155 return hash . digest ( 'hex' ) . toString ( ) ;
144156 }
157+
145158 public async activation ( id : string , status : DataStatusEnum ) {
146159 //recherche de l'identité
147160 let identity : Identities = null ;
@@ -164,19 +177,20 @@ export abstract class AbstractIdentitiesService extends AbstractServiceSchema {
164177 if ( statusChanged ) {
165178 // le dataStaus à changé on envoye l info aux backend et on enregistre l identité
166179 // Envoi du status au backend
167- let statusBackend = true
168- if ( status == DataStatusEnum . INACTIVE || status == DataStatusEnum . PASSWORDNEEDTOBECHANGED ) {
169- statusBackend = false
180+ let statusBackend = true
181+ if ( status == DataStatusEnum . INACTIVE || status == DataStatusEnum . PASSWORDNEEDTOBECHANGED ) {
182+ statusBackend = false
170183 }
171- const result = await this . backends . activationIdentity ( identity . _id . toString ( ) , statusBackend ) ;
184+ const result = await this . backends . activationIdentity ( identity . _id . toString ( ) , statusBackend ) ;
172185 if ( result . state === JobState . COMPLETED ) {
173186 await super . update ( identity . _id , identity ) ;
174187 } else {
175188 throw new HttpException ( 'Backend failed' , 400 ) ;
176189 }
177190 }
178191 }
179- public async askToChangePassword ( id : string ) {
192+
193+ public async askToChangePassword ( id : string ) {
180194 try {
181195 const identity = await this . findById < Identities > ( id ) ;
182196 if ( identity . dataStatus === DataStatusEnum . ACTIVE ) {
@@ -189,49 +203,52 @@ export abstract class AbstractIdentitiesService extends AbstractServiceSchema {
189203 throw new HttpException ( 'Id not found' , 400 ) ;
190204 }
191205 }
206+
192207 /**
193208 * Check if mail and uid are unique. If mail is empty it is not checked
194209 * @param data
195210 * @private
196211 */
197- protected async checkMailAndUid ( data ) : Promise < boolean > {
198- let dataDup = [ ] ;
199- if ( data . inetOrgPerson . hasOwnProperty ( 'mail' ) && data . inetOrgPerson . mail !== '' ) {
200- const id = new Types . ObjectId ( data [ '_id' ] ) ;
201- const f : any = { '_id' : { $ne : id } , $or : [ { 'inetOrgPerson.uid' : data . inetOrgPerson . uid } , { 'inetOrgPerson.mail' : data . inetOrgPerson . mail } ] } ;
212+ protected async checkMailAndUid ( data ) : Promise < boolean > {
213+ let dataDup = [ ] ;
214+ if ( data . inetOrgPerson . hasOwnProperty ( 'mail' ) && data . inetOrgPerson . mail !== '' ) {
215+ const id = new Types . ObjectId ( data [ '_id' ] ) ;
216+ const f : any = { '_id' : { $ne : id } , $or : [ { 'inetOrgPerson.uid' : data . inetOrgPerson . uid } , { 'inetOrgPerson.mail' : data . inetOrgPerson . mail } ] } ;
202217 dataDup = await this . _model . find ( f ) . exec ( )
203- } else {
204- const id = new Types . ObjectId ( data [ '_id' ] ) ;
205- const f : any = { '_id' : { $ne : id } , 'inetOrgPerson.uid' : data . inetOrgPerson . uid } ;
218+ } else {
219+ const id = new Types . ObjectId ( data [ '_id' ] ) ;
220+ const f : any = { '_id' : { $ne : id } , 'inetOrgPerson.uid' : data . inetOrgPerson . uid } ;
206221 dataDup = await this . _model . find ( f ) . exec ( )
207222 }
208223 if ( dataDup . length > 0 ) {
209224 return false
210- } else {
225+ } else {
211226 return true
212227 }
213228 }
214- protected async checkMail ( data ) : Promise < boolean > {
215- let dataDup = 0 ;
216- if ( data . inetOrgPerson . hasOwnProperty ( 'mail' ) && data . inetOrgPerson . mail !== '' ) {
217- const id = new Types . ObjectId ( data [ '_id' ] ) ;
218- const f : any = { '_id' : { $ne : id } , 'inetOrgPerson.mail' : data . inetOrgPerson . mail } ;
229+
230+ protected async checkMail ( data ) : Promise < boolean > {
231+ let dataDup = 0 ;
232+ if ( data . inetOrgPerson . hasOwnProperty ( 'mail' ) && data . inetOrgPerson . mail !== '' ) {
233+ const id = new Types . ObjectId ( data [ '_id' ] ) ;
234+ const f : any = { '_id' : { $ne : id } , 'inetOrgPerson.mail' : data . inetOrgPerson . mail } ;
219235 dataDup = await this . _model . countDocuments ( f ) . exec ( )
220236 }
221- if ( dataDup > 0 ) {
237+ if ( dataDup > 0 ) {
222238 return false
223- } else {
239+ } else {
224240 return true
225241 }
226242 }
227- protected async checkUid ( data ) : Promise < boolean > {
228- let dataDup = 0 ;
229- const id = new Types . ObjectId ( data [ '_id' ] ) ;
230- const f : any = { '_id' : { $ne : id } , 'inetOrgPerson.uid' : data . inetOrgPerson . uid } ;
243+
244+ protected async checkUid ( data ) : Promise < boolean > {
245+ let dataDup = 0 ;
246+ const id = new Types . ObjectId ( data [ '_id' ] ) ;
247+ const f : any = { '_id' : { $ne : id } , 'inetOrgPerson.uid' : data . inetOrgPerson . uid } ;
231248 dataDup = await this . _model . countDocuments ( f ) . exec ( )
232249 if ( dataDup > 0 ) {
233250 return false
234- } else {
251+ } else {
235252 return true
236253 }
237254 }
0 commit comments