oro-sdk 3.13.0 → 3.16.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,21 +1,12 @@
1
- import { Grant, VaultIndex } from 'oro-sdk-apis';
1
+ import { Grant } from 'oro-sdk-apis';
2
2
  import { OroClient, Uuid } from '..';
3
3
  /**
4
4
  * @name filterGrantsWithLockboxMetadata
5
- * @description searches for the applied filters in the vault index
5
+ * @description searches for the existance of a consult uuid in each granted lockbox
6
6
  * @param oroClient
7
- * @param filter: the metadata filter applied to each the lockboxes
8
- * @param vaultIndex: the index to which the filter will be applied
9
- * @param forceRefresh
10
- * @returns the filtered grants
7
+ * @param filter: the consult uuid
8
+ * @returns the grants containing the consult uuid
11
9
  */
12
- export declare function filterGrantsWithLockboxMetadata(oroClient: OroClient, filter?: {
10
+ export declare function filterGrantsWithLockboxMetadata(oroClient: OroClient, filter: {
13
11
  consultationId: Uuid;
14
- }, vaultIndex?: VaultIndex, forceRefresh?: boolean): Promise<Grant[]>;
15
- /** Finds all grants for the logged user
16
- * requests a list of unique consultation ids for each lockbox the user has access to
17
- * builds and sets the index of consultations
18
- * @param oroClient
19
- * @returns the constructed vaultIndex
20
- */
21
- export declare function buildLegacyVaultIndex(oroClient: OroClient): Promise<VaultIndex>;
12
+ }): Promise<Grant[]>;
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "3.13.0",
2
+ "version": "3.16.0",
3
3
  "main": "dist/index.js",
4
4
  "typings": "dist/index.d.ts",
5
5
  "files": [
@@ -54,7 +54,7 @@
54
54
  "form-data": "^4.0.0",
55
55
  "formdata-node": "^4.3.1",
56
56
  "idb-keyval": "^5.0.6",
57
- "oro-sdk-apis": "1.48.0",
57
+ "oro-sdk-apis": "1.50.0",
58
58
  "oro-toolbox": "0.0.6",
59
59
  "uuid": "^8.3.2"
60
60
  }
package/src/client.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import {
2
+ AllRoleType,
2
3
  AuthTokenRequest,
3
4
  Consult,
4
5
  ConsultRequest,
@@ -23,12 +24,15 @@ import {
23
24
  Meta,
24
25
  Metadata,
25
26
  MetadataCategory,
27
+ OtherRoleType,
26
28
  PersonalMeta,
27
29
  PopulatedWorkflowData,
28
30
  Practice,
29
31
  PracticeService,
32
+ PractitionnerRoleType,
30
33
  PreferenceMeta,
31
34
  RecoveryMeta,
35
+ RoleBasedScopes,
32
36
  SearchService,
33
37
  SecretShard,
34
38
  TellerService,
@@ -48,13 +52,14 @@ import {
48
52
  IncompleteAuthentication,
49
53
  LocalEncryptedData,
50
54
  MissingGrant,
55
+ MissingGrantFilter,
51
56
  MissingLockbox,
52
57
  MissingLockboxOwner,
53
58
  RecoveryData,
54
59
  RegisterPatientOutput,
55
60
  UserPreference,
56
61
  } from './models'
57
- import { buildLegacyVaultIndex, filterGrantsWithLockboxMetadata } from './sdk-revision'
62
+ import { filterGrantsWithLockboxMetadata } from './sdk-revision'
58
63
 
59
64
  export class OroClient {
60
65
  private rsa?: CryptoRSA
@@ -83,13 +88,12 @@ export class OroClient {
83
88
  public workflowClient: WorkflowService,
84
89
  public diagnosisClient: DiagnosisService,
85
90
  private authenticationCallback?: (err: Error) => void
86
- ) {}
91
+ ) { }
87
92
 
88
93
  /**
89
94
  * clears the vaultIndex and cached metadata grants
90
95
  */
91
96
  public async cleanIndex() {
92
- this.vaultIndex = undefined
93
97
  this.cachedMetadataGrants = {}
94
98
  this.cachedManifest = {}
95
99
  }
@@ -297,28 +301,6 @@ export class OroClient {
297
301
  return registerPatient(patientUuid, consult, workflow, this, this.toolbox.uuid(), recoveryQA, indexSearch)
298
302
  }
299
303
 
300
- /**
301
- * Builds the vault index for the logged user
302
- *
303
- * Steps:
304
- * 1. Retrieves, decrypts and sets the lockbox IndexSnapshot
305
- * 2. Retrieves, decrypts and adds all other index entries starting at the snapshot timestamp
306
- * 3. Updates the IndexSnapshot if changed
307
- * @deprecated
308
- * @returns the latest vault index
309
- */
310
- public async buildVaultIndex(forceRefresh: boolean = false) {
311
- if (!this.vaultIndex || forceRefresh) await buildLegacyVaultIndex(this)
312
- }
313
-
314
- /**
315
- * Setter for the vault index
316
- * @param index
317
- */
318
- public setVaultIndex(index: VaultIndex) {
319
- this.vaultIndex = index
320
- }
321
-
322
304
  /**
323
305
  * Fetches all grants, and consultations that exist in each lockbox
324
306
  * Then updates the index for the current user with the lockbox consult relationship
@@ -393,91 +375,25 @@ export class OroClient {
393
375
  }))
394
376
  .map(
395
377
  (e: IndexConsultLockbox) =>
396
- ({
397
- uuid: e.uuid,
398
- timestamp: e.timestamp,
399
- uniqueHash: e.uniqueHash,
400
- encryptedIndexEntry: CryptoRSA.jsonWithPubEncryptToBase64(
401
- {
402
- consultationId: e.consultationId,
403
- grant: e.grant,
404
- },
405
- rsaPub
406
- ),
407
- } as EncryptedIndexEntry)
378
+ ({
379
+ uuid: e.uuid,
380
+ timestamp: e.timestamp,
381
+ uniqueHash: e.uniqueHash,
382
+ encryptedIndexEntry: CryptoRSA.jsonWithPubEncryptToBase64(
383
+ {
384
+ consultationId: e.consultationId,
385
+ grant: e.grant,
386
+ },
387
+ rsaPub
388
+ ),
389
+ } as EncryptedIndexEntry)
408
390
  )
409
391
  break
410
- //// DEPRECATED : REMOVE ME : BEGIN ///////////////////////////////////////////
411
- case IndexKey.Consultation:
412
- encryptedIndex[key] = (entries[key] as IndexConsultLockbox[])
413
- .map((e) => ({
414
- ...e,
415
- uniqueHash: this.toolbox.hashStringToBase64(
416
- JSON.stringify({
417
- consultationId: e.consultationId,
418
- grant: e.grant,
419
- })
420
- ),
421
- }))
422
- .filter(
423
- (e) =>
424
- !this.vaultIndex ||
425
- !this.vaultIndex[IndexKey.Consultation]?.find((v) => v.uniqueHash === e.uniqueHash)
426
- )
427
- .map(
428
- (e: IndexConsultLockbox) =>
429
- ({
430
- uuid: e.uuid,
431
- timestamp: e.timestamp,
432
- uniqueHash: e.uniqueHash,
433
- encryptedIndexEntry: CryptoRSA.jsonWithPubEncryptToBase64(
434
- {
435
- consultationId: e.consultationId,
436
- grant: e.grant,
437
- },
438
- rsaPub
439
- ),
440
- } as EncryptedIndexEntry)
441
- )
442
- break
443
- //// DEPRECATED : REMOVE ME : END ///////////////////////////////////////////
444
392
  }
445
393
  }
446
394
  await this.vaultClient.vaultIndexPut(encryptedIndex, indexOwnerUuid)
447
395
  }
448
396
 
449
- /**
450
- * adds or updates the index snapshot for the logged user
451
- * @param index
452
- */
453
- public async indexSnapshotAdd(index: VaultIndex) {
454
- if (!this.rsa) throw IncompleteAuthentication
455
- let rsaPub: Uint8Array = this.rsa.public()
456
-
457
- let cleanedIndex: VaultIndex = {
458
- [IndexKey.Consultation]: index[IndexKey.Consultation]
459
- ?.filter((c) => c)
460
- .map((c) => {
461
- return {
462
- grant: c.grant,
463
- consultationId: c.consultationId,
464
- }
465
- }),
466
- }
467
-
468
- // the data of the snapshot should not contain the `IndexEntry` data
469
- // (will create conflicts while updating)
470
- let encryptedIndexEntry = CryptoRSA.jsonWithPubEncryptToBase64(cleanedIndex, rsaPub)
471
-
472
- // The encryptedIndexEntry can have the uuid and timstamp (for updating)
473
- let encryptedIndex: EncryptedIndexEntry = {
474
- uuid: index.uuid,
475
- timestamp: index.timestamp,
476
- encryptedIndexEntry,
477
- }
478
- this.vaultClient.vaultIndexSnapshotPut(encryptedIndex)
479
- }
480
-
481
397
  /**
482
398
  * @name grantLockbox
483
399
  * @description Grants a lockbox by retrieving the shared secret of the lockbox and encrypting it with the grantees public key
@@ -777,44 +693,60 @@ export class OroClient {
777
693
  * @param filter: the consultationId in which the grant exists
778
694
  * @returns decrypted lockboxes granted to user
779
695
  */
780
- public async getGrants(filter?: { consultationId: Uuid }, forceRefresh: boolean = false): Promise<Grant[]> {
696
+ public async getGrants(filter?: { consultationId: Uuid }): Promise<Grant[]> {
781
697
  if (!this.rsa) throw IncompleteAuthentication
782
698
 
783
699
  let filterString = JSON.stringify(filter)
784
700
  // retrieves cached grants
785
- // Note: if filters is set to empty, it will be stored in the `undefined` key
786
- if (!forceRefresh && this.cachedMetadataGrants[filterString]) return this.cachedMetadataGrants[filterString]
787
-
788
- // if there is a filter to apply, then the grant can be retrieved from the vault index, otherwise, all grants are fetched
701
+ if (this.cachedMetadataGrants[filterString]) return this.cachedMetadataGrants[filterString]
702
+
703
+ // We're using the account role to determine the way a grant is accessed
704
+ let currentAccountRole = await this.getAccountRole()
705
+
706
+ if ([OtherRoleType.Patient, OtherRoleType.User].every(requiredRole => currentAccountRole.includes(requiredRole))) {
707
+ let encryptedGrants
708
+ // if there are no grants with the applied filter from index, attempt for naive filter with backwards compatibility
709
+ if (filter) {
710
+ encryptedGrants = await filterGrantsWithLockboxMetadata(this, filter)
711
+ } else {
712
+ encryptedGrants = (await this.vaultClient.grantsGet()).grants
713
+ }
714
+ const decryptedGrants = await decryptGrants(encryptedGrants, this.rsa)
715
+ // sets the cached grant
716
+ this.cachedMetadataGrants[filterString] = decryptedGrants
717
+ console.info('[sdk:grant] Found grant for patient')
718
+ return decryptedGrants
719
+ }
720
+ // if not a patient, then a practitioner is trying to retrieve a grant, it **Must** contain a filter, otherwise too many grants are possible
721
+ if (!filter)
722
+ throw MissingGrantFilter
789
723
  // Note: will work only if the filter being applied is exclusively a consult id
790
- const grantsByConsultLockbox = filter
791
- ? await this.vaultClient
792
- .vaultIndexGet([IndexKey.ConsultationLockbox], [filter.consultationId])
793
- .then((res) => res[IndexKey.ConsultationLockbox])
794
- .catch((e) => {
795
- console.error(e)
796
- return []
797
- })
798
- : undefined
724
+ const grantsByConsultLockbox = await this.vaultClient
725
+ .vaultIndexGet([IndexKey.ConsultationLockbox], [filter.consultationId])
726
+ .then((res) => res[IndexKey.ConsultationLockbox])
727
+ .catch((e) => {
728
+ console.error(e)
729
+ return []
730
+ })
731
+
799
732
  const decryptedConsults = decryptConsultLockboxGrants(grantsByConsultLockbox ?? [], this.rsa)
800
733
  if (decryptedConsults.length > 0) {
801
734
  console.info('[sdk:index] Grants found in user`s constant time secure index')
802
- this.cachedMetadataGrants[JSON.stringify(filter)] = decryptedConsults
735
+ this.cachedMetadataGrants[filterString] = decryptedConsults
803
736
  return this.cachedMetadataGrants[filterString]
804
737
  }
805
738
 
806
- let encryptedGrants
807
- // if there are no grants with the applied filter from index, attempt for naive filter with backwards compatibility
808
- if (filter) {
809
- encryptedGrants = await filterGrantsWithLockboxMetadata(this, filter, this.vaultIndex, forceRefresh)
810
- } else {
811
- encryptedGrants = (await this.vaultClient.grantsGet()).grants
812
- }
739
+ // if we have no valid grants, then return nothing
740
+ return []
741
+ }
813
742
 
814
- const decryptedGrants = await decryptGrants(encryptedGrants, this.rsa)
815
- // sets the cached grant
816
- this.cachedMetadataGrants[filterString] = decryptedGrants
817
- return decryptedGrants
743
+ /**
744
+ * Fetches the role of the account that is logged in
745
+ *
746
+ * @returns the role based scopes defined by the whoami
747
+ */
748
+ async getAccountRole(): Promise<RoleBasedScopes[]> {
749
+ return (await this.guardClient.whoAmI()).scope.split(' ') as RoleBasedScopes[]
818
750
  }
819
751
 
820
752
  /**
@@ -1206,9 +1138,9 @@ export class OroClient {
1206
1138
  * @param practiceUuid the uuid of the practice to look consult into
1207
1139
  * @returns the list of consults
1208
1140
  */
1209
- public async getAssignedConsultations(practiceUuid: Uuid, forceRefresh: boolean = false): Promise<Consult[]> {
1141
+ public async getAssignedConsultations(practiceUuid: Uuid): Promise<Consult[]> {
1210
1142
  return Promise.all(
1211
- (await this.getGrants(undefined, forceRefresh)).map((grant) =>
1143
+ (await this.getGrants()).map((grant) =>
1212
1144
  this.getLockboxManifest(
1213
1145
  grant.lockboxUuid!,
1214
1146
  {
@@ -1216,8 +1148,7 @@ export class OroClient {
1216
1148
  documentType: DocumentType.PopulatedWorkflowData,
1217
1149
  },
1218
1150
  true,
1219
- undefined,
1220
- forceRefresh
1151
+ undefined
1221
1152
  ).then((manifest) =>
1222
1153
  Promise.all(
1223
1154
  manifest.map(
@@ -1278,7 +1209,7 @@ export class OroClient {
1278
1209
  ): Promise<PopulatedWorkflowData[]> {
1279
1210
  //TODO: make use of getPatientDocumentsList instead of doing it manually here
1280
1211
  return Promise.all(
1281
- (await this.getGrants({ consultationId }, forceRefresh))
1212
+ (await this.getGrants({ consultationId }))
1282
1213
  .map((grant) =>
1283
1214
  this.getLockboxManifest(
1284
1215
  grant.lockboxUuid!,
@@ -194,7 +194,7 @@ export async function registerPatient(
194
194
  await Promise.all([...grantPromises, ...consultIndexPromises])
195
195
 
196
196
 
197
- if(indexSearch) {
197
+ if (indexSearch) {
198
198
  await buildConsultSearchIndex(consult, workflow, oroClient).catch((err) => {
199
199
  console.error(
200
200
  '[SDK: registration] personal information not found or another error occured during search indexing',
@@ -265,7 +265,7 @@ async function getOrCreatePatientConsultationUuid(consult: ConsultRequest, oroCl
265
265
  * @returns the lockbox Uuid
266
266
  */
267
267
  async function getOrCreatePatientLockbox(oroClient: OroClient): Promise<Uuid> {
268
- let grants = await oroClient.getGrants(undefined, true)
268
+ let grants = await oroClient.getGrants()
269
269
  if (grants.length > 0) {
270
270
  console.log('The grant has already been created, skipping lockbox create step')
271
271
  return grants[0].lockboxUuid!
@@ -1,6 +1,7 @@
1
- export class IncompleteAuthentication extends Error {}
2
- export class MissingGrant extends Error {}
3
- export class MissingLockbox extends Error {}
4
- export class MissingLockboxOwner extends Error {}
5
- export class AssociatedLockboxNotFound extends Error {}
6
- export class WorkflowAnswersMissingError extends Error {}
1
+ export class IncompleteAuthentication extends Error { }
2
+ export class MissingGrant extends Error { }
3
+ export class MissingGrantFilter extends Error { }
4
+ export class MissingLockbox extends Error { }
5
+ export class MissingLockboxOwner extends Error { }
6
+ export class AssociatedLockboxNotFound extends Error { }
7
+ export class WorkflowAnswersMissingError extends Error { }
@@ -3,65 +3,27 @@ import { OroClient, Uuid } from '..'
3
3
 
4
4
  /**
5
5
  * @name filterGrantsWithLockboxMetadata
6
- * @description searches for the applied filters in the vault index
6
+ * @description searches for the existance of a consult uuid in each granted lockbox
7
7
  * @param oroClient
8
- * @param filter: the metadata filter applied to each the lockboxes
9
- * @param vaultIndex: the index to which the filter will be applied
10
- * @param forceRefresh
11
- * @returns the filtered grants
8
+ * @param filter: the consult uuid
9
+ * @returns the grants containing the consult uuid
12
10
  */
13
11
  export async function filterGrantsWithLockboxMetadata(
14
12
  oroClient: OroClient,
15
- filter?: { consultationId: Uuid },
16
- vaultIndex?: VaultIndex,
17
- forceRefresh = false
13
+ filter: { consultationId: Uuid },
18
14
  ): Promise<Grant[]> {
19
- if (!vaultIndex || forceRefresh) {
20
- vaultIndex = await buildLegacyVaultIndex(oroClient)
21
- }
22
- if (vaultIndex[IndexKey.Consultation] && filter) {
23
- let indexConsults = (vaultIndex[IndexKey.Consultation] ?? [])
24
- .filter((consultGrant: { consultationId: Uuid }) => consultGrant.consultationId === filter.consultationId)
25
- .map((consultGrant: { consultationId: Uuid; grant: Grant }) => consultGrant.grant as Grant)
26
- return indexConsults as Grant[]
27
- } else {
28
- // No grants exist and the index has already been built
29
- return []
30
- }
31
- }
32
-
33
- /** Finds all grants for the logged user
34
- * requests a list of unique consultation ids for each lockbox the user has access to
35
- * builds and sets the index of consultations
36
- * @param oroClient
37
- * @returns the constructed vaultIndex
38
- */
39
- export async function buildLegacyVaultIndex(oroClient: OroClient): Promise<VaultIndex> {
40
15
  let grants = await oroClient.getGrants()
41
- let consultGrants: IndexConsultLockbox[] = []
16
+ let filteredGrants = []
42
17
  for (let grant of grants) {
43
- let consults = (
44
- await oroClient.vaultClient.lockboxMetadataGet(grant.lockboxUuid!, ['consultationId'], [], {
45
- category: MetadataCategory.Consultation,
46
- })
47
- )[0] as Uuid[]
48
-
49
- consultGrants = [
50
- ...consultGrants,
51
- ...consults.map((consult: any) => ({
52
- ...consult,
53
- grant: {
54
- lockboxOwnerUuid: grant.lockboxOwnerUuid,
55
- lockboxUuid: grant.lockboxUuid,
56
- },
57
- })),
58
- ]
18
+ // Fetches in each lockbox the existance of a given consult id
19
+ let consultationIdExistsInMetadata = await oroClient.vaultClient.lockboxMetadataGet(grant.lockboxUuid!, ['consultationId'], [], {
20
+ category: MetadataCategory.Consultation,
21
+ consultationId: filter.consultationId
22
+ })
23
+ // If there are entries in the metadata, it means that the consult exists in the lockbox
24
+ if (consultationIdExistsInMetadata[0].length >= 0)
25
+ filteredGrants.push(grant)
59
26
  }
60
27
 
61
- let vaultIndex = {
62
- [IndexKey.Consultation]: consultGrants,
63
- }
64
- oroClient.setVaultIndex(vaultIndex)
65
- console.info('[sdk:index] Successfully Built Vault Index')
66
- return vaultIndex
28
+ return filteredGrants
67
29
  }