@icure/api 7.1.34 → 7.1.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. package/icc-api/api/IccAuthApi.d.ts +1 -0
  2. package/icc-api/api/IccAuthApi.js +1 -0
  3. package/icc-api/api/IccAuthApi.js.map +1 -1
  4. package/icc-x-api/index.d.ts +22 -29
  5. package/icc-x-api/index.js +60 -38
  6. package/icc-x-api/index.js.map +1 -1
  7. package/package.json +1 -1
  8. package/test/icc-api/api/IccDocumentApi.d.ts +1 -0
  9. package/test/icc-api/api/IccDocumentApi.js +200 -0
  10. package/test/icc-api/api/IccDocumentApi.js.map +1 -0
  11. package/test/icc-api/api/IccGroupApi.d.ts +1 -0
  12. package/test/icc-api/api/IccGroupApi.js +50 -0
  13. package/test/icc-api/api/IccGroupApi.js.map +1 -0
  14. package/test/icc-api/api/IccRoleApi.d.ts +1 -0
  15. package/test/icc-api/api/IccRoleApi.js +34 -0
  16. package/test/icc-api/api/IccRoleApi.js.map +1 -0
  17. package/test/icc-api/api/IccUserApi.d.ts +1 -0
  18. package/test/icc-api/api/IccUserApi.js +80 -0
  19. package/test/icc-api/api/IccUserApi.js.map +1 -0
  20. package/test/icc-api/e2e/IccCalendarItemApi.d.ts +1 -0
  21. package/test/icc-api/e2e/IccCalendarItemApi.js +45 -0
  22. package/test/icc-api/e2e/IccCalendarItemApi.js.map +1 -0
  23. package/test/icc-api/model/modelHelpersTest.d.ts +1 -0
  24. package/test/icc-api/model/modelHelpersTest.js +45 -0
  25. package/test/icc-api/model/modelHelpersTest.js.map +1 -0
  26. package/test/icc-x-api/auth/group-switch-test.d.ts +1 -0
  27. package/test/icc-x-api/auth/group-switch-test.js +81 -0
  28. package/test/icc-x-api/auth/group-switch-test.js.map +1 -0
  29. package/test/icc-x-api/auth/jwt-concurrency-test.d.ts +2 -0
  30. package/test/icc-x-api/auth/jwt-concurrency-test.js +113 -0
  31. package/test/icc-x-api/auth/jwt-concurrency-test.js.map +1 -0
  32. package/test/icc-x-api/auth/smart-auth-provider-test.d.ts +1 -0
  33. package/test/icc-x-api/auth/smart-auth-provider-test.js +222 -0
  34. package/test/icc-x-api/auth/smart-auth-provider-test.js.map +1 -0
  35. package/test/icc-x-api/crypto/KeyManager-test.d.ts +1 -0
  36. package/test/icc-x-api/crypto/KeyManager-test.js +225 -0
  37. package/test/icc-x-api/crypto/KeyManager-test.js.map +1 -0
  38. package/test/icc-x-api/crypto/concurrency.d.ts +1 -0
  39. package/test/icc-x-api/crypto/concurrency.js +35 -0
  40. package/test/icc-x-api/crypto/concurrency.js.map +1 -0
  41. package/test/icc-x-api/crypto/crypto-utils.d.ts +1 -0
  42. package/test/icc-x-api/crypto/crypto-utils.js +80 -0
  43. package/test/icc-x-api/crypto/crypto-utils.js.map +1 -0
  44. package/test/icc-x-api/crypto/cryptoTest.d.ts +2 -0
  45. package/test/icc-x-api/crypto/cryptoTest.js +275 -0
  46. package/test/icc-x-api/crypto/cryptoTest.js.map +1 -0
  47. package/test/icc-x-api/crypto/delegate-ci-to-patient-with-missing-keys-test.d.ts +1 -0
  48. package/test/icc-x-api/crypto/delegate-ci-to-patient-with-missing-keys-test.js +132 -0
  49. package/test/icc-x-api/crypto/delegate-ci-to-patient-with-missing-keys-test.js.map +1 -0
  50. package/test/icc-x-api/crypto/full-crypto-test.d.ts +1 -0
  51. package/test/icc-x-api/crypto/full-crypto-test.js +458 -0
  52. package/test/icc-x-api/crypto/full-crypto-test.js.map +1 -0
  53. package/test/icc-x-api/crypto/shamir.d.ts +2 -0
  54. package/test/icc-x-api/crypto/shamir.js +156 -0
  55. package/test/icc-x-api/crypto/shamir.js.map +1 -0
  56. package/test/icc-x-api/crypto/share-to-newly-created-patient-from-hcp.d.ts +1 -0
  57. package/test/icc-x-api/crypto/share-to-newly-created-patient-from-hcp.js +75 -0
  58. package/test/icc-x-api/crypto/share-to-newly-created-patient-from-hcp.js.map +1 -0
  59. package/test/icc-x-api/data-compatibility-test-7to6.d.ts +1 -0
  60. package/test/icc-x-api/data-compatibility-test-7to6.js +343 -0
  61. package/test/icc-x-api/data-compatibility-test-7to6.js.map +1 -0
  62. package/test/icc-x-api/entity-with-attachments-api-test.d.ts +1 -0
  63. package/test/icc-x-api/entity-with-attachments-api-test.js +142 -0
  64. package/test/icc-x-api/entity-with-attachments-api-test.js.map +1 -0
  65. package/test/icc-x-api/filters/filters.d.ts +1 -0
  66. package/test/icc-x-api/filters/filters.js +49 -0
  67. package/test/icc-x-api/filters/filters.js.map +1 -0
  68. package/test/icc-x-api/icc-accesslog-x-api.d.ts +1 -0
  69. package/test/icc-x-api/icc-accesslog-x-api.js +121 -0
  70. package/test/icc-x-api/icc-accesslog-x-api.js.map +1 -0
  71. package/test/icc-x-api/icc-auth-api.d.ts +1 -0
  72. package/test/icc-x-api/icc-auth-api.js +46 -0
  73. package/test/icc-x-api/icc-auth-api.js.map +1 -0
  74. package/test/icc-x-api/icc-calendar-item-x-api.d.ts +1 -0
  75. package/test/icc-x-api/icc-calendar-item-x-api.js +146 -0
  76. package/test/icc-x-api/icc-calendar-item-x-api.js.map +1 -0
  77. package/test/icc-x-api/icc-contact-x-api.d.ts +1 -0
  78. package/test/icc-x-api/icc-contact-x-api.js +311 -0
  79. package/test/icc-x-api/icc-contact-x-api.js.map +1 -0
  80. package/test/icc-x-api/icc-form-x-api.d.ts +1 -0
  81. package/test/icc-x-api/icc-form-x-api.js +331 -0
  82. package/test/icc-x-api/icc-form-x-api.js.map +1 -0
  83. package/test/icc-x-api/icc-helement-x-api-test.d.ts +1 -0
  84. package/test/icc-x-api/icc-helement-x-api-test.js +158 -0
  85. package/test/icc-x-api/icc-helement-x-api-test.js.map +1 -0
  86. package/test/icc-x-api/icc-invoice-x-api.d.ts +1 -0
  87. package/test/icc-x-api/icc-invoice-x-api.js +115 -0
  88. package/test/icc-x-api/icc-invoice-x-api.js.map +1 -0
  89. package/test/icc-x-api/icc-maintenance-task-x-api-test.d.ts +1 -0
  90. package/test/icc-x-api/icc-maintenance-task-x-api-test.js +230 -0
  91. package/test/icc-x-api/icc-maintenance-task-x-api-test.js.map +1 -0
  92. package/test/icc-x-api/icc-patient-x-api-test.d.ts +1 -0
  93. package/test/icc-x-api/icc-patient-x-api-test.js +169 -0
  94. package/test/icc-x-api/icc-patient-x-api-test.js.map +1 -0
  95. package/test/icc-x-api/icc-time-table-x-api.d.ts +1 -0
  96. package/test/icc-x-api/icc-time-table-x-api.js +110 -0
  97. package/test/icc-x-api/icc-time-table-x-api.js.map +1 -0
  98. package/test/icc-x-api/icc-user-x-api-test.d.ts +1 -0
  99. package/test/icc-x-api/icc-user-x-api-test.js +108 -0
  100. package/test/icc-x-api/icc-user-x-api-test.js.map +1 -0
  101. package/test/icc-x-api/icureapi-group-test.d.ts +1 -0
  102. package/test/icc-x-api/icureapi-group-test.js +130 -0
  103. package/test/icc-x-api/icureapi-group-test.js.map +1 -0
  104. package/test/icc-x-api/patient-user.d.ts +2 -0
  105. package/test/icc-x-api/patient-user.js +117 -0
  106. package/test/icc-x-api/patient-user.js.map +1 -0
  107. package/test/icc-x-api/storage/storage.d.ts +1 -0
  108. package/test/icc-x-api/storage/storage.js +50 -0
  109. package/test/icc-x-api/storage/storage.js.map +1 -0
  110. package/test/icc-x-api/subscription-apis.d.ts +2 -0
  111. package/test/icc-x-api/subscription-apis.js +498 -0
  112. package/test/icc-x-api/subscription-apis.js.map +1 -0
  113. package/test/icc-x-api/test-api-no-parent.d.ts +1 -0
  114. package/test/icc-x-api/test-api-no-parent.js +79 -0
  115. package/test/icc-x-api/test-api-no-parent.js.map +1 -0
  116. package/test/icc-x-api/test-legacy-data-support.d.ts +1 -0
  117. package/test/icc-x-api/test-legacy-data-support.js +231 -0
  118. package/test/icc-x-api/test-legacy-data-support.js.map +1 -0
  119. package/test/icc-x-api/utils/crypto-utils-test.d.ts +1 -0
  120. package/test/icc-x-api/utils/crypto-utils-test.js +586 -0
  121. package/test/icc-x-api/utils/crypto-utils-test.js.map +1 -0
  122. package/test/icc-x-api/utils/graph-test.d.ts +1 -0
  123. package/test/icc-x-api/utils/graph-test.js +54 -0
  124. package/test/icc-x-api/utils/graph-test.js.map +1 -0
  125. package/test/support/CSM-185.d.ts +1 -0
  126. package/test/support/CSM-185.js +120 -0
  127. package/test/support/CSM-185.js.map +1 -0
  128. package/test/support/CSM-87.d.ts +0 -0
  129. package/test/support/CSM-87.js +21 -0
  130. package/test/support/CSM-87.js.map +1 -0
  131. package/test/support/CSM-93.d.ts +1 -0
  132. package/test/support/CSM-93.js +111 -0
  133. package/test/support/CSM-93.js.map +1 -0
  134. package/test/utils/TestApi.d.ts +3 -0
  135. package/test/utils/TestApi.js +27 -0
  136. package/test/utils/TestApi.js.map +1 -0
  137. package/test/utils/TestCollectionUtils.d.ts +1 -0
  138. package/test/utils/TestCollectionUtils.js +109 -0
  139. package/test/utils/TestCollectionUtils.js.map +1 -0
  140. package/test/utils/TestCryptoStrategies.d.ts +37 -0
  141. package/test/utils/TestCryptoStrategies.js +72 -0
  142. package/test/utils/TestCryptoStrategies.js.map +1 -0
  143. package/test/utils/TestStorage.d.ts +31 -0
  144. package/test/utils/TestStorage.js +88 -0
  145. package/test/utils/TestStorage.js.map +1 -0
  146. package/test/utils/test_utils.d.ts +60 -0
  147. package/test/utils/test_utils.js +313 -0
  148. package/test/utils/test_utils.js.map +1 -0
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const test_utils_1 = require("../../utils/test_utils");
13
+ const types_1 = require("@icure/test-setup/types");
14
+ require("isomorphic-fetch");
15
+ const icc_api_1 = require("../../../icc-api");
16
+ const AuthenticationProvider_1 = require("../../../icc-x-api/auth/AuthenticationProvider");
17
+ const chai_1 = require("chai");
18
+ const chaiAsPromised = require("chai-as-promised");
19
+ const SmartAuthProvider_1 = require("../../../icc-x-api/auth/SmartAuthProvider");
20
+ (0, chai_1.use)(chaiAsPromised);
21
+ (0, test_utils_1.setLocalStorage)(fetch);
22
+ let host;
23
+ let userDetails;
24
+ describe('Authentication providers should be able to switch group', function () {
25
+ before(function () {
26
+ return __awaiter(this, void 0, void 0, function* () {
27
+ this.timeout(600000);
28
+ const initializer = yield (0, test_utils_1.getEnvironmentInitializer)();
29
+ const env = yield initializer.execute((0, types_1.getEnvVariables)());
30
+ host = env.iCureUrl;
31
+ userDetails = yield (0, test_utils_1.createUserInMultipleGroups)(env);
32
+ console.log('Users created');
33
+ });
34
+ });
35
+ const authenticationProviders = [
36
+ ['Basic', () => new AuthenticationProvider_1.BasicAuthenticationProvider(userDetails.userLogin, userDetails.userPw12)],
37
+ [
38
+ 'Jwt',
39
+ () => new AuthenticationProvider_1.JwtAuthenticationProvider(new icc_api_1.IccAuthApi(host, {}, new AuthenticationProvider_1.NoAuthenticationProvider(), fetch), userDetails.userLogin, userDetails.userPw12),
40
+ ],
41
+ [
42
+ 'Ensemble',
43
+ () => new AuthenticationProvider_1.EnsembleAuthenticationProvider(new icc_api_1.IccAuthApi(host, {}, new AuthenticationProvider_1.NoAuthenticationProvider(), fetch), userDetails.userLogin, userDetails.userPw12),
44
+ ],
45
+ [
46
+ 'Smart',
47
+ () => SmartAuthProvider_1.SmartAuthProvider.initialise(new icc_api_1.IccAuthApi(host, {}, new AuthenticationProvider_1.NoAuthenticationProvider(), fetch), userDetails.userLogin, {
48
+ getSecret(acceptedSecrets, previousAttempts) {
49
+ (0, chai_1.expect)(acceptedSecrets).to.include(SmartAuthProvider_1.AuthSecretType.PASSWORD);
50
+ return Promise.resolve({ value: userDetails.userPw12, secretType: SmartAuthProvider_1.AuthSecretType.PASSWORD });
51
+ },
52
+ }),
53
+ ],
54
+ ];
55
+ for (const [providerType, providerFactory] of authenticationProviders) {
56
+ it(`should be able to switch to another group if the username-password is the same in the new group (${providerType})`, () => __awaiter(this, void 0, void 0, function* () {
57
+ const provider = providerFactory();
58
+ const initialUserApi = new icc_api_1.IccUserApi(host, {}, provider, fetch);
59
+ const initialUser = yield initialUserApi.getCurrentUser();
60
+ (0, chai_1.expect)(initialUser.id).to.be.oneOf([userDetails.user1.id, userDetails.user2.id]);
61
+ const matches = yield initialUserApi.getMatchingUsers();
62
+ (0, chai_1.expect)(matches.map((x) => x.userId)).to.have.members([userDetails.user1.id, userDetails.user2.id]);
63
+ const switchedToGroup2Provider = yield provider.switchGroup(userDetails.group2.id, matches);
64
+ const userApiGroup2 = new icc_api_1.IccUserApi(host, {}, switchedToGroup2Provider.switchedProvider, fetch);
65
+ const userGroup2 = yield userApiGroup2.getCurrentUser();
66
+ (0, chai_1.expect)(userGroup2.id).to.equal(userDetails.user2.id);
67
+ const switchedToGroup1Provider = yield switchedToGroup2Provider.switchedProvider.switchGroup(userDetails.group1.id, matches);
68
+ const userApiGroup1 = new icc_api_1.IccUserApi(host, {}, switchedToGroup1Provider.switchedProvider, fetch);
69
+ const userGroup1 = yield userApiGroup1.getCurrentUser();
70
+ (0, chai_1.expect)(userGroup1.id).to.equal(userDetails.user1.id);
71
+ }));
72
+ it(`should not be able to switch to another group if the username-password is different in the new group (${providerType})`, () => __awaiter(this, void 0, void 0, function* () {
73
+ const provider = providerFactory();
74
+ const initialUserApi = new icc_api_1.IccUserApi(host, {}, provider, fetch);
75
+ const matches = yield initialUserApi.getMatchingUsers();
76
+ (0, chai_1.expect)(matches.map((x) => x.userId)).to.not.contain(userDetails.user3.id);
77
+ yield (0, chai_1.expect)(provider.switchGroup(userDetails.group3.id, matches)).to.be.rejected;
78
+ }));
79
+ }
80
+ });
81
+ //# sourceMappingURL=group-switch-test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"group-switch-test.js","sourceRoot":"","sources":["../../../../test/icc-x-api/auth/group-switch-test.ts"],"names":[],"mappings":"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","sourcesContent":["import { createUserInMultipleGroups, getEnvironmentInitializer, setLocalStorage, UserInManyGroupsDetails } from '../../utils/test_utils'\nimport { getEnvVariables } from '@icure/test-setup/types'\nimport 'isomorphic-fetch'\nimport { IccAuthApi, IccUserApi } from '../../../icc-api'\nimport {\n AuthenticationProvider,\n BasicAuthenticationProvider,\n EnsembleAuthenticationProvider,\n JwtAuthenticationProvider,\n NoAuthenticationProvider,\n} from '../../../icc-x-api/auth/AuthenticationProvider'\nimport { expect, use as chaiUse } from 'chai'\nimport * as chaiAsPromised from 'chai-as-promised'\nimport { AuthSecretType, AuthSecretDetails, SmartAuthProvider } from '../../../icc-x-api/auth/SmartAuthProvider'\n\nchaiUse(chaiAsPromised)\n\nsetLocalStorage(fetch)\n\nlet host: string\nlet userDetails: UserInManyGroupsDetails\n\ndescribe('Authentication providers should be able to switch group', function () {\n before(async function () {\n this.timeout(600000)\n const initializer = await getEnvironmentInitializer()\n const env = await initializer.execute(getEnvVariables())\n host = env.iCureUrl\n userDetails = await createUserInMultipleGroups(env)\n console.log('Users created')\n })\n\n const authenticationProviders: [string, () => AuthenticationProvider][] = [\n ['Basic', () => new BasicAuthenticationProvider(userDetails.userLogin, userDetails.userPw12)],\n [\n 'Jwt',\n () =>\n new JwtAuthenticationProvider(new IccAuthApi(host, {}, new NoAuthenticationProvider(), fetch), userDetails.userLogin, userDetails.userPw12),\n ],\n [\n 'Ensemble',\n () =>\n new EnsembleAuthenticationProvider(\n new IccAuthApi(host, {}, new NoAuthenticationProvider(), fetch),\n userDetails.userLogin,\n userDetails.userPw12\n ),\n ],\n [\n 'Smart',\n () =>\n SmartAuthProvider.initialise(new IccAuthApi(host, {}, new NoAuthenticationProvider(), fetch), userDetails.userLogin, {\n getSecret(acceptedSecrets: AuthSecretType[], previousAttempts: AuthSecretDetails[]): Promise<AuthSecretDetails> {\n expect(acceptedSecrets).to.include(AuthSecretType.PASSWORD)\n return Promise.resolve({ value: userDetails.userPw12, secretType: AuthSecretType.PASSWORD })\n },\n }),\n ],\n ]\n\n for (const [providerType, providerFactory] of authenticationProviders) {\n it(`should be able to switch to another group if the username-password is the same in the new group (${providerType})`, async () => {\n const provider = providerFactory()\n const initialUserApi = new IccUserApi(host, {}, provider, fetch)\n const initialUser = await initialUserApi.getCurrentUser()\n expect(initialUser.id).to.be.oneOf([userDetails.user1.id, userDetails.user2.id])\n const matches = await initialUserApi.getMatchingUsers()\n expect(matches.map((x) => x.userId)).to.have.members([userDetails.user1.id, userDetails.user2.id])\n const switchedToGroup2Provider = await provider.switchGroup(userDetails.group2.id!, matches)\n const userApiGroup2 = new IccUserApi(host, {}, switchedToGroup2Provider.switchedProvider, fetch)\n const userGroup2 = await userApiGroup2.getCurrentUser()\n expect(userGroup2.id).to.equal(userDetails.user2.id)\n const switchedToGroup1Provider = await switchedToGroup2Provider.switchedProvider.switchGroup(userDetails.group1.id!, matches)\n const userApiGroup1 = new IccUserApi(host, {}, switchedToGroup1Provider.switchedProvider, fetch)\n const userGroup1 = await userApiGroup1.getCurrentUser()\n expect(userGroup1.id).to.equal(userDetails.user1.id)\n })\n\n it(`should not be able to switch to another group if the username-password is different in the new group (${providerType})`, async () => {\n const provider = providerFactory()\n const initialUserApi = new IccUserApi(host, {}, provider, fetch)\n const matches = await initialUserApi.getMatchingUsers()\n expect(matches.map((x) => x.userId)).to.not.contain(userDetails.user3.id)\n await expect(provider.switchGroup(userDetails.group3.id!, matches)).to.be.rejected\n })\n }\n})\n"]}
@@ -0,0 +1,2 @@
1
+ import 'isomorphic-fetch';
2
+ export declare function sleep(ms: number): Promise<any>;
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.sleep = void 0;
13
+ require("isomorphic-fetch");
14
+ const mocha_1 = require("mocha");
15
+ const test_utils_1 = require("../../utils/test_utils");
16
+ const TestApi_1 = require("../../utils/TestApi");
17
+ const icc_x_api_1 = require("../../../icc-x-api");
18
+ const crypto_1 = require("crypto");
19
+ const chai_1 = require("chai");
20
+ const icc_api_1 = require("../../../icc-api");
21
+ const AuthenticationProvider_1 = require("../../../icc-x-api/auth/AuthenticationProvider");
22
+ const types_1 = require("@icure/test-setup/types");
23
+ (0, test_utils_1.setLocalStorage)(fetch);
24
+ let env;
25
+ function sleep(ms) {
26
+ return new Promise((resolve) => setTimeout(resolve, ms));
27
+ }
28
+ exports.sleep = sleep;
29
+ describe('Jwt authentication concurrency test', () => {
30
+ (0, mocha_1.before)(function () {
31
+ return __awaiter(this, void 0, void 0, function* () {
32
+ this.timeout(600000);
33
+ const initializer = yield (0, test_utils_1.getEnvironmentInitializer)();
34
+ env = yield initializer.execute((0, types_1.getEnvVariables)());
35
+ });
36
+ });
37
+ it('Can login simultaneously with the same user', () => __awaiter(void 0, void 0, void 0, function* () {
38
+ const api = yield (0, TestApi_1.TestApi)(env.iCureUrl, env.dataOwnerDetails[test_utils_1.hcp1Username].user, env.dataOwnerDetails[test_utils_1.hcp1Username].password, crypto_1.webcrypto);
39
+ const users = yield Promise.all([...Array(5)].map(() => __awaiter(void 0, void 0, void 0, function* () {
40
+ return yield api.userApi.getCurrentUser();
41
+ })));
42
+ users.forEach((u) => {
43
+ (0, chai_1.expect)(u.login).to.be.equal(env.dataOwnerDetails[test_utils_1.hcp1Username].user);
44
+ });
45
+ }));
46
+ it('After logging in, can make requests asynchronously', () => __awaiter(void 0, void 0, void 0, function* () {
47
+ const api = yield (0, TestApi_1.TestApi)(env.iCureUrl, env.dataOwnerDetails[test_utils_1.hcp1Username].user, env.dataOwnerDetails[test_utils_1.hcp1Username].password, crypto_1.webcrypto);
48
+ yield api.userApi.getCurrentUser();
49
+ const users = yield Promise.all([...Array(5)].map(() => __awaiter(void 0, void 0, void 0, function* () {
50
+ return yield api.userApi.getCurrentUser();
51
+ })));
52
+ users.forEach((u) => {
53
+ (0, chai_1.expect)(u.login).to.be.equal(env.dataOwnerDetails[test_utils_1.hcp1Username].user);
54
+ });
55
+ }));
56
+ it('It can refresh the token asynchronously', function () {
57
+ return __awaiter(this, void 0, void 0, function* () {
58
+ if (!process.env.TEST_ENVIRONMENT || process.env.TEST_ENVIRONMENT === 'acceptance') {
59
+ this.skip();
60
+ }
61
+ const api = yield (0, TestApi_1.TestApi)(env.iCureUrl, env.dataOwnerDetails[test_utils_1.hcp1Username].user, env.dataOwnerDetails[test_utils_1.hcp1Username].password, crypto_1.webcrypto);
62
+ yield api.userApi.getCurrentUser();
63
+ yield sleep(20000);
64
+ const users = yield Promise.all([...Array(5)].map(() => __awaiter(this, void 0, void 0, function* () {
65
+ return yield api.userApi.getCurrentUser();
66
+ })));
67
+ users.forEach((u) => {
68
+ (0, chai_1.expect)(u.login).to.be.equal(env.dataOwnerDetails[test_utils_1.hcp1Username].user);
69
+ });
70
+ });
71
+ });
72
+ it('Can instantiate a x-api without provider and get a 401', () => __awaiter(void 0, void 0, void 0, function* () {
73
+ const xUserApi = new icc_x_api_1.IccUserXApi(env.iCureUrl, {}, new AuthenticationProvider_1.NoAuthenticationProvider(), null);
74
+ xUserApi
75
+ .getCurrentUser()
76
+ .then(() => {
77
+ (0, chai_1.expect)(false).to.be.eq(true, 'I should not get here');
78
+ })
79
+ .catch((e) => {
80
+ (0, chai_1.expect)(e.statusCode).to.be.eq(401);
81
+ });
82
+ }));
83
+ it('Can instantiate a user-x-api with JWT provider and make requests', () => __awaiter(void 0, void 0, void 0, function* () {
84
+ const authApi = new icc_api_1.IccAuthApi(env.iCureUrl, {});
85
+ const provider = new AuthenticationProvider_1.JwtAuthenticationProvider(authApi, env.dataOwnerDetails[test_utils_1.hcp1Username].user, env.dataOwnerDetails[test_utils_1.hcp1Username].password);
86
+ const xUserApi = new icc_x_api_1.IccUserXApi(env.iCureUrl, {}, provider, null);
87
+ const users = yield Promise.all([...Array(5)].map(() => __awaiter(void 0, void 0, void 0, function* () {
88
+ return yield xUserApi.getCurrentUser();
89
+ })));
90
+ users.forEach((u) => {
91
+ (0, chai_1.expect)(u.login).to.be.equal(env.dataOwnerDetails[test_utils_1.hcp1Username].user);
92
+ });
93
+ const tokens = yield provider.getIcureTokens();
94
+ (0, chai_1.expect)(tokens).to.not.be.undefined;
95
+ const tokenOnlyProvider = new AuthenticationProvider_1.JwtAuthenticationProvider(authApi, undefined, undefined, undefined, tokens);
96
+ const xUserApiTokenOnly = new icc_x_api_1.IccUserXApi(env.iCureUrl, {}, tokenOnlyProvider, null);
97
+ const usersTokenOnly = yield Promise.all([...Array(5)].map(() => __awaiter(void 0, void 0, void 0, function* () {
98
+ return yield xUserApiTokenOnly.getCurrentUser();
99
+ })));
100
+ usersTokenOnly.forEach((u) => {
101
+ (0, chai_1.expect)(u.login).to.be.equal(env.dataOwnerDetails[test_utils_1.hcp1Username].user);
102
+ });
103
+ }));
104
+ it('Can instantiate a user-x-api with Basic provider and make requests', () => __awaiter(void 0, void 0, void 0, function* () {
105
+ const a = new AuthenticationProvider_1.BasicAuthenticationProvider(env.dataOwnerDetails[test_utils_1.hcp1Username].user, env.dataOwnerDetails[test_utils_1.hcp1Username].password);
106
+ const xUserApi = new icc_x_api_1.IccUserXApi(env.iCureUrl, {}, a, null);
107
+ const currentUser = yield xUserApi.getCurrentUser();
108
+ (0, chai_1.expect)(currentUser.login).to.be.equal(env.dataOwnerDetails[test_utils_1.hcp1Username].user);
109
+ const fetchedUser = yield xUserApi.getUser(currentUser.id);
110
+ (0, chai_1.expect)(fetchedUser.id).to.be.equal(currentUser.id);
111
+ }));
112
+ });
113
+ //# sourceMappingURL=jwt-concurrency-test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwt-concurrency-test.js","sourceRoot":"","sources":["../../../../test/icc-x-api/auth/jwt-concurrency-test.ts"],"names":[],"mappings":"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","sourcesContent":["import 'isomorphic-fetch'\nimport { before } from 'mocha'\nimport { getEnvironmentInitializer, hcp1Username, setLocalStorage } from '../../utils/test_utils'\nimport { TestApi } from '../../utils/TestApi'\nimport { IccUserXApi } from '../../../icc-x-api'\nimport { webcrypto } from 'crypto'\nimport { expect } from 'chai'\nimport { XHR } from '../../../icc-api/api/XHR'\nimport XHRError = XHR.XHRError\nimport { IccAuthApi } from '../../../icc-api'\nimport { BasicAuthenticationProvider, JwtAuthenticationProvider, NoAuthenticationProvider } from '../../../icc-x-api/auth/AuthenticationProvider'\nimport { getEnvVariables, TestVars } from '@icure/test-setup/types'\n\nsetLocalStorage(fetch)\nlet env: TestVars\n\nexport function sleep(ms: number): Promise<any> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\ndescribe('Jwt authentication concurrency test', () => {\n before(async function () {\n this.timeout(600000)\n const initializer = await getEnvironmentInitializer()\n env = await initializer.execute(getEnvVariables())\n })\n\n it('Can login simultaneously with the same user', async () => {\n const api = await TestApi(\n env.iCureUrl,\n env.dataOwnerDetails[hcp1Username].user,\n env.dataOwnerDetails[hcp1Username].password,\n webcrypto as unknown as Crypto\n )\n const users = await Promise.all(\n [...Array<number>(5)].map(async () => {\n return await api.userApi.getCurrentUser()\n })\n )\n users.forEach((u) => {\n expect(u.login).to.be.equal(env.dataOwnerDetails[hcp1Username].user)\n })\n })\n\n it('After logging in, can make requests asynchronously', async () => {\n const api = await TestApi(\n env.iCureUrl,\n env.dataOwnerDetails[hcp1Username].user,\n env.dataOwnerDetails[hcp1Username].password,\n webcrypto as unknown as Crypto\n )\n\n await api.userApi.getCurrentUser()\n\n const users = await Promise.all(\n [...Array<number>(5)].map(async () => {\n return await api.userApi.getCurrentUser()\n })\n )\n users.forEach((u) => {\n expect(u.login).to.be.equal(env.dataOwnerDetails[hcp1Username].user)\n })\n })\n\n it('It can refresh the token asynchronously', async function () {\n if (!process.env.TEST_ENVIRONMENT || process.env.TEST_ENVIRONMENT === 'acceptance') {\n this.skip()\n }\n const api = await TestApi(\n env.iCureUrl,\n env.dataOwnerDetails[hcp1Username].user,\n env.dataOwnerDetails[hcp1Username].password,\n webcrypto as unknown as Crypto\n )\n await api.userApi.getCurrentUser()\n\n await sleep(20000)\n\n const users = await Promise.all(\n [...Array<number>(5)].map(async () => {\n return await api.userApi.getCurrentUser()\n })\n )\n users.forEach((u) => {\n expect(u.login).to.be.equal(env.dataOwnerDetails[hcp1Username].user)\n })\n })\n\n it('Can instantiate a x-api without provider and get a 401', async () => {\n const xUserApi = new IccUserXApi(env.iCureUrl, {}, new NoAuthenticationProvider(), null as any)\n xUserApi\n .getCurrentUser()\n .then(() => {\n expect(false).to.be.eq(true, 'I should not get here')\n })\n .catch((e: XHRError) => {\n expect(e.statusCode).to.be.eq(401)\n })\n })\n\n it('Can instantiate a user-x-api with JWT provider and make requests', async () => {\n const authApi = new IccAuthApi(env.iCureUrl, {})\n const provider = new JwtAuthenticationProvider(authApi, env.dataOwnerDetails[hcp1Username].user, env.dataOwnerDetails[hcp1Username].password)\n const xUserApi = new IccUserXApi(env.iCureUrl, {}, provider, null as any)\n\n const users = await Promise.all(\n [...Array<number>(5)].map(async () => {\n return await xUserApi.getCurrentUser()\n })\n )\n users.forEach((u) => {\n expect(u.login).to.be.equal(env.dataOwnerDetails[hcp1Username].user)\n })\n\n const tokens = await provider.getIcureTokens()\n expect(tokens).to.not.be.undefined\n const tokenOnlyProvider = new JwtAuthenticationProvider(authApi, undefined, undefined, undefined, tokens)\n const xUserApiTokenOnly = new IccUserXApi(env.iCureUrl, {}, tokenOnlyProvider, null as any)\n\n const usersTokenOnly = await Promise.all(\n [...Array<number>(5)].map(async () => {\n return await xUserApiTokenOnly.getCurrentUser()\n })\n )\n usersTokenOnly.forEach((u) => {\n expect(u.login).to.be.equal(env.dataOwnerDetails[hcp1Username].user)\n })\n })\n\n it('Can instantiate a user-x-api with Basic provider and make requests', async () => {\n const a = new BasicAuthenticationProvider(env.dataOwnerDetails[hcp1Username].user, env.dataOwnerDetails[hcp1Username].password)\n const xUserApi = new IccUserXApi(env.iCureUrl, {}, a, null as any)\n\n const currentUser = await xUserApi.getCurrentUser()\n expect(currentUser.login).to.be.equal(env.dataOwnerDetails[hcp1Username].user)\n\n const fetchedUser = await xUserApi.getUser(currentUser.id!)\n expect(fetchedUser.id).to.be.equal(currentUser.id)\n })\n})\n"]}
@@ -0,0 +1 @@
1
+ import 'isomorphic-fetch';
@@ -0,0 +1,222 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const types_1 = require("@icure/test-setup/types");
13
+ const mocha_1 = require("mocha");
14
+ const test_utils_1 = require("../../utils/test_utils");
15
+ const icc_x_api_1 = require("../../../icc-x-api");
16
+ const icc_api_1 = require("../../../icc-api");
17
+ require("isomorphic-fetch");
18
+ const SmartAuthProvider_1 = require("../../../icc-x-api/auth/SmartAuthProvider");
19
+ const chai_1 = require("chai");
20
+ const crypto_1 = require("crypto");
21
+ var initMasterApi = test_utils_1.TestUtils.initMasterApi;
22
+ const assert_1 = require("assert");
23
+ const otpauth_1 = require("otpauth");
24
+ (0, test_utils_1.setLocalStorage)(fetch);
25
+ let env;
26
+ let authApi;
27
+ describe('Smart authentication provider', () => {
28
+ (0, mocha_1.before)(function () {
29
+ return __awaiter(this, void 0, void 0, function* () {
30
+ this.timeout(600000);
31
+ const initializer = yield (0, test_utils_1.getEnvironmentInitializer)();
32
+ env = yield initializer.execute((0, types_1.getEnvVariables)());
33
+ authApi = new icc_api_1.IccAuthApi(env.iCureUrl, {}, new icc_x_api_1.NoAuthenticationProvider(), fetch);
34
+ });
35
+ });
36
+ function userApiWithProvider(authProvider) {
37
+ return new icc_api_1.IccUserApi(env.iCureUrl, {}, authProvider, fetch);
38
+ }
39
+ it('Should automatically ask for secret to get a new token, and reasks the secret if it is not valid', () => __awaiter(void 0, void 0, void 0, function* () {
40
+ const { credentials } = yield (0, test_utils_1.createNewHcpApi)(env);
41
+ let calls = 0;
42
+ const authProvider = SmartAuthProvider_1.SmartAuthProvider.initialise(authApi, credentials.user, {
43
+ getSecret: (acceptedSecrets, previousAttempts) => __awaiter(void 0, void 0, void 0, function* () {
44
+ (0, chai_1.expect)(acceptedSecrets).to.include(SmartAuthProvider_1.AuthSecretType.PASSWORD);
45
+ (0, chai_1.expect)(acceptedSecrets).to.include(SmartAuthProvider_1.AuthSecretType.LONG_LIVED_TOKEN);
46
+ (0, chai_1.expect)(acceptedSecrets).to.include(SmartAuthProvider_1.AuthSecretType.SHORT_LIVED_TOKEN);
47
+ (0, chai_1.expect)(acceptedSecrets).to.not.include(SmartAuthProvider_1.AuthSecretType.TWO_FACTOR_AUTHENTICATION_TOKEN);
48
+ if (calls == 0) {
49
+ (0, chai_1.expect)(previousAttempts).to.be.empty;
50
+ }
51
+ else if (calls == 1) {
52
+ (0, chai_1.expect)(previousAttempts).to.have.length(1);
53
+ (0, chai_1.expect)(previousAttempts[0].value).to.equal('wrong');
54
+ (0, chai_1.expect)(previousAttempts[0].secretType).to.equal(SmartAuthProvider_1.AuthSecretType.LONG_LIVED_TOKEN);
55
+ }
56
+ else
57
+ (0, assert_1.fail)(`Unexpected number of calls: ${calls}`);
58
+ return calls++ == 0
59
+ ? { value: 'wrong', secretType: SmartAuthProvider_1.AuthSecretType.LONG_LIVED_TOKEN } // pragma: allowlist secret
60
+ : { value: credentials.password, secretType: SmartAuthProvider_1.AuthSecretType.LONG_LIVED_TOKEN };
61
+ }),
62
+ });
63
+ const userApi = userApiWithProvider(authProvider);
64
+ const user = yield userApi.getCurrentUser();
65
+ (0, chai_1.expect)(user.healthcarePartyId).to.equal(credentials.dataOwnerId);
66
+ (0, chai_1.expect)(calls).to.equal(2);
67
+ }));
68
+ it('Should automatically ask for a more powerful secret to perform elevated-security operations if the available secret/token is not good enough', () => __awaiter(void 0, void 0, void 0, function* () {
69
+ const { credentials, api } = yield (0, test_utils_1.createNewHcpApi)(env);
70
+ const initialUser = yield api.userApi.getCurrentUser();
71
+ const masterApi = yield initMasterApi(env);
72
+ const userToken = (0, crypto_1.randomUUID)();
73
+ const userPw = (0, crypto_1.randomUUID)();
74
+ const userWithLongTokenAndPw = yield masterApi.userApi.modifyUser(Object.assign(Object.assign({}, initialUser), { passwordHash: userPw, authenticationTokens: {
75
+ 'test-long-lived-token': {
76
+ token: userToken,
77
+ creationTime: Date.now(),
78
+ validity: 60 * 60 * 24 * 7,
79
+ },
80
+ } }));
81
+ let calls = 0;
82
+ const authProvider = SmartAuthProvider_1.SmartAuthProvider.initialise(authApi, credentials.user, {
83
+ getSecret: (acceptedSecrets, previousAttempts) => __awaiter(void 0, void 0, void 0, function* () {
84
+ if (calls == 0) {
85
+ (0, chai_1.expect)(acceptedSecrets).to.include(SmartAuthProvider_1.AuthSecretType.PASSWORD);
86
+ (0, chai_1.expect)(acceptedSecrets).to.include(SmartAuthProvider_1.AuthSecretType.LONG_LIVED_TOKEN);
87
+ (0, chai_1.expect)(acceptedSecrets).to.include(SmartAuthProvider_1.AuthSecretType.SHORT_LIVED_TOKEN);
88
+ (0, chai_1.expect)(acceptedSecrets).to.not.include(SmartAuthProvider_1.AuthSecretType.TWO_FACTOR_AUTHENTICATION_TOKEN);
89
+ (0, chai_1.expect)(previousAttempts).to.be.empty;
90
+ calls++;
91
+ return { value: userToken, secretType: SmartAuthProvider_1.AuthSecretType.LONG_LIVED_TOKEN };
92
+ }
93
+ else if (calls == 1) {
94
+ (0, chai_1.expect)(acceptedSecrets).to.include(SmartAuthProvider_1.AuthSecretType.PASSWORD);
95
+ (0, chai_1.expect)(acceptedSecrets).to.not.include(SmartAuthProvider_1.AuthSecretType.LONG_LIVED_TOKEN);
96
+ (0, chai_1.expect)(acceptedSecrets).to.include(SmartAuthProvider_1.AuthSecretType.SHORT_LIVED_TOKEN);
97
+ (0, chai_1.expect)(acceptedSecrets).to.not.include(SmartAuthProvider_1.AuthSecretType.TWO_FACTOR_AUTHENTICATION_TOKEN);
98
+ (0, chai_1.expect)(previousAttempts).to.be.empty;
99
+ calls++;
100
+ return { value: userPw, secretType: SmartAuthProvider_1.AuthSecretType.PASSWORD };
101
+ }
102
+ else
103
+ throw new Error(`Unexpected number of calls: ${calls}`);
104
+ }),
105
+ });
106
+ const userApi = userApiWithProvider(authProvider);
107
+ (0, chai_1.expect)((yield userApi.getCurrentUser()).rev).to.equal(userWithLongTokenAndPw.rev);
108
+ (0, chai_1.expect)(calls).to.equal(1);
109
+ const newPw = (0, crypto_1.randomUUID)();
110
+ const userWithNewPw = yield userApi.modifyUser(Object.assign(Object.assign({}, userWithLongTokenAndPw), { passwordHash: newPw }));
111
+ (0, chai_1.expect)(userWithNewPw.rev).to.not.equal(userWithLongTokenAndPw.rev);
112
+ (0, chai_1.expect)(calls).to.equal(2);
113
+ const retrievedWithNewPw = yield userApiWithProvider(new icc_x_api_1.BasicAuthenticationProvider(credentials.user, newPw)).getCurrentUser();
114
+ (0, chai_1.expect)(retrievedWithNewPw.rev).to.equal(userWithNewPw.rev);
115
+ const couldRetrieveWithOldPw = yield userApiWithProvider(new icc_x_api_1.BasicAuthenticationProvider(credentials.user, userPw))
116
+ .getCurrentUser()
117
+ .then(() => true, () => false);
118
+ (0, chai_1.expect)(couldRetrieveWithOldPw).to.be.false;
119
+ }));
120
+ it('Should automatically ask for TOTP after password if user has 2fa enabled', () => __awaiter(void 0, void 0, void 0, function* () {
121
+ const { credentials, api } = yield (0, test_utils_1.createNewHcpApi)(env);
122
+ const initialUser = yield api.userApi.getCurrentUser();
123
+ const masterApi = yield initMasterApi(env);
124
+ const totpSecret = 'AAPX7PW2RJIGZ3D4'; // pragma: allowlist secret (fake secret generated only for test)
125
+ const totp = new otpauth_1.TOTP({
126
+ algorithm: 'SHA1',
127
+ digits: 6,
128
+ period: 30,
129
+ secret: totpSecret,
130
+ });
131
+ const userPw = (0, crypto_1.randomUUID)();
132
+ const userWithPwAnd2fa = yield masterApi.userApi.modifyUser(Object.assign(Object.assign({}, initialUser), { passwordHash: userPw, use2fa: true, secret: totpSecret }));
133
+ let calls = 0;
134
+ const authProvider = SmartAuthProvider_1.SmartAuthProvider.initialise(authApi, credentials.user, {
135
+ getSecret: (acceptedSecrets, previousAttempts) => __awaiter(void 0, void 0, void 0, function* () {
136
+ if (calls == 0) {
137
+ (0, chai_1.expect)(acceptedSecrets).to.include(SmartAuthProvider_1.AuthSecretType.PASSWORD);
138
+ (0, chai_1.expect)(acceptedSecrets).to.include(SmartAuthProvider_1.AuthSecretType.LONG_LIVED_TOKEN);
139
+ (0, chai_1.expect)(acceptedSecrets).to.include(SmartAuthProvider_1.AuthSecretType.SHORT_LIVED_TOKEN);
140
+ (0, chai_1.expect)(acceptedSecrets).to.not.include(SmartAuthProvider_1.AuthSecretType.TWO_FACTOR_AUTHENTICATION_TOKEN);
141
+ (0, chai_1.expect)(previousAttempts).to.be.empty;
142
+ calls++;
143
+ return { value: userPw, secretType: SmartAuthProvider_1.AuthSecretType.PASSWORD };
144
+ }
145
+ else if (calls == 1 || calls == 2) {
146
+ (0, chai_1.expect)(acceptedSecrets).to.have.members([SmartAuthProvider_1.AuthSecretType.TWO_FACTOR_AUTHENTICATION_TOKEN]);
147
+ if (calls == 1)
148
+ (0, chai_1.expect)(previousAttempts).to.be.empty;
149
+ if (calls == 2)
150
+ (0, chai_1.expect)(previousAttempts).to.have.length(1);
151
+ return calls++ == 1
152
+ ? { value: totp.generate() + '13', secretType: SmartAuthProvider_1.AuthSecretType.TWO_FACTOR_AUTHENTICATION_TOKEN }
153
+ : { value: totp.generate(), secretType: SmartAuthProvider_1.AuthSecretType.TWO_FACTOR_AUTHENTICATION_TOKEN };
154
+ }
155
+ else
156
+ throw new Error(`Unexpected number of calls: ${calls}`);
157
+ }),
158
+ });
159
+ const userApi = userApiWithProvider(authProvider);
160
+ (0, chai_1.expect)((yield userApi.getCurrentUser()).rev).to.equal(userWithPwAnd2fa.rev);
161
+ (0, chai_1.expect)(calls).to.equal(3);
162
+ }));
163
+ it('Should ask for TOTP directly if password is cached', () => __awaiter(void 0, void 0, void 0, function* () {
164
+ const { credentials, api } = yield (0, test_utils_1.createNewHcpApi)(env);
165
+ const initialUser = yield api.userApi.getCurrentUser();
166
+ const masterApi = yield initMasterApi(env);
167
+ const totpSecret = 'AAPX7PW2RJIGZ3D4'; // pragma: allowlist secret (fake secret generated only for test)
168
+ const totp = new otpauth_1.TOTP({
169
+ algorithm: 'SHA1',
170
+ digits: 6,
171
+ period: 30,
172
+ secret: totpSecret,
173
+ });
174
+ const userPw = (0, crypto_1.randomUUID)();
175
+ const userWithPwAnd2fa = yield masterApi.userApi.modifyUser(Object.assign(Object.assign({}, initialUser), { passwordHash: userPw, use2fa: true, secret: totpSecret }));
176
+ let calls = 0;
177
+ const authProvider = SmartAuthProvider_1.SmartAuthProvider.initialise(authApi, credentials.user, {
178
+ getSecret: (acceptedSecrets, previousAttempts) => __awaiter(void 0, void 0, void 0, function* () {
179
+ (0, chai_1.expect)(acceptedSecrets).to.have.members([SmartAuthProvider_1.AuthSecretType.TWO_FACTOR_AUTHENTICATION_TOKEN]);
180
+ (0, chai_1.expect)(previousAttempts).to.be.empty;
181
+ (0, chai_1.expect)(calls++).to.equal(0);
182
+ return { value: totp.generate(), secretType: SmartAuthProvider_1.AuthSecretType.TWO_FACTOR_AUTHENTICATION_TOKEN };
183
+ }),
184
+ }, {
185
+ initialSecret: { plainSecret: userPw },
186
+ });
187
+ const userApi = userApiWithProvider(authProvider);
188
+ (0, chai_1.expect)((yield userApi.getCurrentUser()).rev).to.equal(userWithPwAnd2fa.rev);
189
+ (0, chai_1.expect)(calls).to.equal(1);
190
+ }));
191
+ it('Switched provider should keep cached secrets and should be able to have elevated security context', () => __awaiter(void 0, void 0, void 0, function* () {
192
+ var _a;
193
+ const details = yield (0, test_utils_1.createUserInMultipleGroups)(env);
194
+ let calls = 0;
195
+ const authProvider = SmartAuthProvider_1.SmartAuthProvider.initialise(authApi, details.userLogin, {
196
+ getSecret: (acceptedSecrets, previousAttempts) => __awaiter(void 0, void 0, void 0, function* () {
197
+ (0, chai_1.expect)(acceptedSecrets).to.have.include(SmartAuthProvider_1.AuthSecretType.PASSWORD);
198
+ (0, chai_1.expect)(previousAttempts).to.be.empty;
199
+ (0, chai_1.expect)(calls++).to.equal(0);
200
+ return { value: details.userPw12, secretType: SmartAuthProvider_1.AuthSecretType.PASSWORD };
201
+ }),
202
+ });
203
+ const defaultGroupUserApi = userApiWithProvider(authProvider);
204
+ const defaultGroupUser = yield defaultGroupUserApi.getCurrentUser();
205
+ const otherGroupId = details.group1.id == defaultGroupUser.groupId ? details.group2.id : details.group1.id;
206
+ const matches = yield defaultGroupUserApi.getMatchingUsers();
207
+ const switchedUserApi = userApiWithProvider((yield authProvider.switchGroup(otherGroupId, matches)).switchedProvider);
208
+ const switchedUser = yield switchedUserApi.getCurrentUser();
209
+ (0, chai_1.expect)(switchedUser.id).to.not.equal(defaultGroupUser.id);
210
+ (0, chai_1.expect)(switchedUser.groupId).to.equal(otherGroupId);
211
+ const updatedDefault = yield switchedUserApi.modifyUser(Object.assign(Object.assign({}, switchedUser), { authenticationTokens: {
212
+ 'new-token': {
213
+ token: (0, crypto_1.randomUUID)(),
214
+ creationTime: Date.now(),
215
+ validity: 60 * 60 * 24 * 7,
216
+ },
217
+ } }));
218
+ (0, chai_1.expect)(updatedDefault.rev).to.not.equal(switchedUser.rev);
219
+ (0, chai_1.expect)(Object.keys((_a = updatedDefault.authenticationTokens) !== null && _a !== void 0 ? _a : {})).to.not.be.empty;
220
+ }));
221
+ });
222
+ //# sourceMappingURL=smart-auth-provider-test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smart-auth-provider-test.js","sourceRoot":"","sources":["../../../../test/icc-x-api/auth/smart-auth-provider-test.ts"],"names":[],"mappings":";;;;;;;;;;;AAAA,mDAAmE;AACnE,iCAA8B;AAC9B,uDAA2I;AAC3I,kDAAkH;AAClH,8CAAyD;AACzD,4BAAyB;AACzB,iFAAgH;AAChH,+BAA6B;AAC7B,mCAAmC;AACnC,IAAO,aAAa,GAAG,sBAAS,CAAC,aAAa,CAAA;AAC9C,mCAA6B;AAC7B,qCAA8B;AAC9B,IAAA,4BAAe,EAAC,KAAK,CAAC,CAAA;AAEtB,IAAI,GAAa,CAAA;AACjB,IAAI,OAAmB,CAAA;AAEvB,QAAQ,CAAC,+BAA+B,EAAE,GAAG,EAAE;IAC7C,IAAA,cAAM,EAAC;;YACL,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;YACpB,MAAM,WAAW,GAAG,MAAM,IAAA,sCAAyB,GAAE,CAAA;YACrD,GAAG,GAAG,MAAM,WAAW,CAAC,OAAO,CAAC,IAAA,uBAAe,GAAE,CAAC,CAAA;YAClD,OAAO,GAAG,IAAI,oBAAU,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,EAAE,IAAI,oCAAwB,EAAE,EAAE,KAAK,CAAC,CAAA;QACnF,CAAC;KAAA,CAAC,CAAA;IAEF,SAAS,mBAAmB,CAAC,YAAoC;QAC/D,OAAO,IAAI,oBAAU,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,EAAE,YAAY,EAAE,KAAK,CAAC,CAAA;IAC9D,CAAC;IAED,EAAE,CAAC,kGAAkG,EAAE,GAAS,EAAE;QAChH,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,IAAA,4BAAe,EAAC,GAAG,CAAC,CAAA;QAClD,IAAI,KAAK,GAAG,CAAC,CAAA;QACb,MAAM,YAAY,GAAG,qCAAiB,CAAC,UAAU,CAAC,OAAO,EAAE,WAAW,CAAC,IAAI,EAAE;YAC3E,SAAS,EAAE,CAAO,eAAiC,EAAE,gBAAqC,EAAE,EAAE;gBAC5F,IAAA,aAAM,EAAC,eAAe,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,kCAAc,CAAC,QAAQ,CAAC,CAAA;gBAC3D,IAAA,aAAM,EAAC,eAAe,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,kCAAc,CAAC,gBAAgB,CAAC,CAAA;gBACnE,IAAA,aAAM,EAAC,eAAe,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,kCAAc,CAAC,iBAAiB,CAAC,CAAA;gBACpE,IAAA,aAAM,EAAC,eAAe,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,kCAAc,CAAC,+BAA+B,CAAC,CAAA;gBACtF,IAAI,KAAK,IAAI,CAAC,EAAE;oBACd,IAAA,aAAM,EAAC,gBAAgB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAA;iBACrC;qBAAM,IAAI,KAAK,IAAI,CAAC,EAAE;oBACrB,IAAA,aAAM,EAAC,gBAAgB,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;oBAC1C,IAAA,aAAM,EAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;oBACnD,IAAA,aAAM,EAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,kCAAc,CAAC,gBAAgB,CAAC,CAAA;iBACjF;;oBAAM,IAAA,aAAI,EAAC,+BAA+B,KAAK,EAAE,CAAC,CAAA;gBACnD,OAAO,KAAK,EAAE,IAAI,CAAC;oBACjB,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,kCAAc,CAAC,gBAAgB,EAAE,CAAC,2BAA2B;oBAC7F,CAAC,CAAC,EAAE,KAAK,EAAE,WAAW,CAAC,QAAQ,EAAE,UAAU,EAAE,kCAAc,CAAC,gBAAgB,EAAE,CAAA;YAClF,CAAC,CAAA;SACF,CAAC,CAAA;QACF,MAAM,OAAO,GAAG,mBAAmB,CAAC,YAAY,CAAC,CAAA;QACjD,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,cAAc,EAAE,CAAA;QAC3C,IAAA,aAAM,EAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,WAAW,CAAC,CAAA;QAChE,IAAA,aAAM,EAAC,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IAC3B,CAAC,CAAA,CAAC,CAAA;IAEF,EAAE,CAAC,8IAA8I,EAAE,GAAS,EAAE;QAC5J,MAAM,EAAE,WAAW,EAAE,GAAG,EAAE,GAAG,MAAM,IAAA,4BAAe,EAAC,GAAG,CAAC,CAAA;QACvD,MAAM,WAAW,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,cAAc,EAAE,CAAA;QACtD,MAAM,SAAS,GAAG,MAAM,aAAa,CAAC,GAAG,CAAC,CAAA;QAC1C,MAAM,SAAS,GAAG,IAAA,mBAAU,GAAE,CAAA;QAC9B,MAAM,MAAM,GAAG,IAAA,mBAAU,GAAE,CAAA;QAC3B,MAAM,sBAAsB,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,UAAU,iCAC5D,WAAW,KACd,YAAY,EAAE,MAAM,EACpB,oBAAoB,EAAE;gBACpB,uBAAuB,EAAE;oBACvB,KAAK,EAAE,SAAS;oBAChB,YAAY,EAAE,IAAI,CAAC,GAAG,EAAE;oBACxB,QAAQ,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;iBAC3B;aACF,IACD,CAAA;QACF,IAAI,KAAK,GAAG,CAAC,CAAA;QACb,MAAM,YAAY,GAAG,qCAAiB,CAAC,UAAU,CAAC,OAAO,EAAE,WAAW,CAAC,IAAI,EAAE;YAC3E,SAAS,EAAE,CAAO,eAAiC,EAAE,gBAAqC,EAAE,EAAE;gBAC5F,IAAI,KAAK,IAAI,CAAC,EAAE;oBACd,IAAA,aAAM,EAAC,eAAe,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,kCAAc,CAAC,QAAQ,CAAC,CAAA;oBAC3D,IAAA,aAAM,EAAC,eAAe,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,kCAAc,CAAC,gBAAgB,CAAC,CAAA;oBACnE,IAAA,aAAM,EAAC,eAAe,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,kCAAc,CAAC,iBAAiB,CAAC,CAAA;oBACpE,IAAA,aAAM,EAAC,eAAe,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,kCAAc,CAAC,+BAA+B,CAAC,CAAA;oBACtF,IAAA,aAAM,EAAC,gBAAgB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAA;oBACpC,KAAK,EAAE,CAAA;oBACP,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,kCAAc,CAAC,gBAAgB,EAAE,CAAA;iBACzE;qBAAM,IAAI,KAAK,IAAI,CAAC,EAAE;oBACrB,IAAA,aAAM,EAAC,eAAe,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,kCAAc,CAAC,QAAQ,CAAC,CAAA;oBAC3D,IAAA,aAAM,EAAC,eAAe,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,kCAAc,CAAC,gBAAgB,CAAC,CAAA;oBACvE,IAAA,aAAM,EAAC,eAAe,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,kCAAc,CAAC,iBAAiB,CAAC,CAAA;oBACpE,IAAA,aAAM,EAAC,eAAe,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,kCAAc,CAAC,+BAA+B,CAAC,CAAA;oBACtF,IAAA,aAAM,EAAC,gBAAgB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAA;oBACpC,KAAK,EAAE,CAAA;oBACP,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,kCAAc,CAAC,QAAQ,EAAE,CAAA;iBAC9D;;oBAAM,MAAM,IAAI,KAAK,CAAC,+BAA+B,KAAK,EAAE,CAAC,CAAA;YAChE,CAAC,CAAA;SACF,CAAC,CAAA;QACF,MAAM,OAAO,GAAG,mBAAmB,CAAC,YAAY,CAAC,CAAA;QACjD,IAAA,aAAM,EAAC,CAAC,MAAM,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,sBAAsB,CAAC,GAAG,CAAC,CAAA;QACjF,IAAA,aAAM,EAAC,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;QACzB,MAAM,KAAK,GAAG,IAAA,mBAAU,GAAE,CAAA;QAC1B,MAAM,aAAa,GAAG,MAAM,OAAO,CAAC,UAAU,iCAAM,sBAAsB,KAAE,YAAY,EAAE,KAAK,IAAG,CAAA;QAClG,IAAA,aAAM,EAAC,aAAa,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,sBAAsB,CAAC,GAAG,CAAC,CAAA;QAClE,IAAA,aAAM,EAAC,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;QACzB,MAAM,kBAAkB,GAAG,MAAM,mBAAmB,CAAC,IAAI,uCAA2B,CAAC,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,cAAc,EAAE,CAAA;QAC/H,IAAA,aAAM,EAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,CAAA;QAC1D,MAAM,sBAAsB,GAAG,MAAM,mBAAmB,CAAC,IAAI,uCAA2B,CAAC,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;aAChH,cAAc,EAAE;aAChB,IAAI,CACH,GAAG,EAAE,CAAC,IAAI,EACV,GAAG,EAAE,CAAC,KAAK,CACZ,CAAA;QACH,IAAA,aAAM,EAAC,sBAAsB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAA;IAC5C,CAAC,CAAA,CAAC,CAAA;IAEF,EAAE,CAAC,0EAA0E,EAAE,GAAS,EAAE;QACxF,MAAM,EAAE,WAAW,EAAE,GAAG,EAAE,GAAG,MAAM,IAAA,4BAAe,EAAC,GAAG,CAAC,CAAA;QACvD,MAAM,WAAW,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,cAAc,EAAE,CAAA;QACtD,MAAM,SAAS,GAAG,MAAM,aAAa,CAAC,GAAG,CAAC,CAAA;QAC1C,MAAM,UAAU,GAAG,kBAAkB,CAAA,CAAC,iEAAiE;QACvG,MAAM,IAAI,GAAG,IAAI,cAAI,CAAC;YACpB,SAAS,EAAE,MAAM;YACjB,MAAM,EAAE,CAAC;YACT,MAAM,EAAE,EAAE;YACV,MAAM,EAAE,UAAU;SACnB,CAAC,CAAA;QACF,MAAM,MAAM,GAAG,IAAA,mBAAU,GAAE,CAAA;QAC3B,MAAM,gBAAgB,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,UAAU,iCACtD,WAAW,KACd,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,IAAI,EACZ,MAAM,EAAE,UAAU,IAClB,CAAA;QACF,IAAI,KAAK,GAAG,CAAC,CAAA;QACb,MAAM,YAAY,GAAG,qCAAiB,CAAC,UAAU,CAAC,OAAO,EAAE,WAAW,CAAC,IAAI,EAAE;YAC3E,SAAS,EAAE,CAAO,eAAiC,EAAE,gBAAqC,EAAE,EAAE;gBAC5F,IAAI,KAAK,IAAI,CAAC,EAAE;oBACd,IAAA,aAAM,EAAC,eAAe,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,kCAAc,CAAC,QAAQ,CAAC,CAAA;oBAC3D,IAAA,aAAM,EAAC,eAAe,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,kCAAc,CAAC,gBAAgB,CAAC,CAAA;oBACnE,IAAA,aAAM,EAAC,eAAe,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,kCAAc,CAAC,iBAAiB,CAAC,CAAA;oBACpE,IAAA,aAAM,EAAC,eAAe,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,kCAAc,CAAC,+BAA+B,CAAC,CAAA;oBACtF,IAAA,aAAM,EAAC,gBAAgB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAA;oBACpC,KAAK,EAAE,CAAA;oBACP,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,kCAAc,CAAC,QAAQ,EAAE,CAAA;iBAC9D;qBAAM,IAAI,KAAK,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE;oBACnC,IAAA,aAAM,EAAC,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,kCAAc,CAAC,+BAA+B,CAAC,CAAC,CAAA;oBACzF,IAAI,KAAK,IAAI,CAAC;wBAAE,IAAA,aAAM,EAAC,gBAAgB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAA;oBACpD,IAAI,KAAK,IAAI,CAAC;wBAAE,IAAA,aAAM,EAAC,gBAAgB,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;oBAC1D,OAAO,KAAK,EAAE,IAAI,CAAC;wBACjB,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,QAAQ,EAAE,GAAG,IAAI,EAAE,UAAU,EAAE,kCAAc,CAAC,+BAA+B,EAAE;wBAC/F,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,QAAQ,EAAE,EAAE,UAAU,EAAE,kCAAc,CAAC,+BAA+B,EAAE,CAAA;iBAC3F;;oBAAM,MAAM,IAAI,KAAK,CAAC,+BAA+B,KAAK,EAAE,CAAC,CAAA;YAChE,CAAC,CAAA;SACF,CAAC,CAAA;QACF,MAAM,OAAO,GAAG,mBAAmB,CAAC,YAAY,CAAC,CAAA;QACjD,IAAA,aAAM,EAAC,CAAC,MAAM,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAA;QAC3E,IAAA,aAAM,EAAC,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IAC3B,CAAC,CAAA,CAAC,CAAA;IAEF,EAAE,CAAC,oDAAoD,EAAE,GAAS,EAAE;QAClE,MAAM,EAAE,WAAW,EAAE,GAAG,EAAE,GAAG,MAAM,IAAA,4BAAe,EAAC,GAAG,CAAC,CAAA;QACvD,MAAM,WAAW,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,cAAc,EAAE,CAAA;QACtD,MAAM,SAAS,GAAG,MAAM,aAAa,CAAC,GAAG,CAAC,CAAA;QAC1C,MAAM,UAAU,GAAG,kBAAkB,CAAA,CAAC,iEAAiE;QACvG,MAAM,IAAI,GAAG,IAAI,cAAI,CAAC;YACpB,SAAS,EAAE,MAAM;YACjB,MAAM,EAAE,CAAC;YACT,MAAM,EAAE,EAAE;YACV,MAAM,EAAE,UAAU;SACnB,CAAC,CAAA;QACF,MAAM,MAAM,GAAG,IAAA,mBAAU,GAAE,CAAA;QAC3B,MAAM,gBAAgB,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,UAAU,iCACtD,WAAW,KACd,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,IAAI,EACZ,MAAM,EAAE,UAAU,IAClB,CAAA;QACF,IAAI,KAAK,GAAG,CAAC,CAAA;QACb,MAAM,YAAY,GAAG,qCAAiB,CAAC,UAAU,CAC/C,OAAO,EACP,WAAW,CAAC,IAAI,EAChB;YACE,SAAS,EAAE,CAAO,eAAiC,EAAE,gBAAqC,EAAE,EAAE;gBAC5F,IAAA,aAAM,EAAC,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,kCAAc,CAAC,+BAA+B,CAAC,CAAC,CAAA;gBACzF,IAAA,aAAM,EAAC,gBAAgB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAA;gBACpC,IAAA,aAAM,EAAC,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;gBAC3B,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,QAAQ,EAAE,EAAE,UAAU,EAAE,kCAAc,CAAC,+BAA+B,EAAE,CAAA;YAC/F,CAAC,CAAA;SACF,EACD;YACE,aAAa,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE;SACvC,CACF,CAAA;QACD,MAAM,OAAO,GAAG,mBAAmB,CAAC,YAAY,CAAC,CAAA;QACjD,IAAA,aAAM,EAAC,CAAC,MAAM,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAA;QAC3E,IAAA,aAAM,EAAC,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IAC3B,CAAC,CAAA,CAAC,CAAA;IAEF,EAAE,CAAC,mGAAmG,EAAE,GAAS,EAAE;;QACjH,MAAM,OAAO,GAAG,MAAM,IAAA,uCAA0B,EAAC,GAAG,CAAC,CAAA;QACrD,IAAI,KAAK,GAAG,CAAC,CAAA;QACb,MAAM,YAAY,GAAG,qCAAiB,CAAC,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,SAAS,EAAE;YAC5E,SAAS,EAAE,CAAO,eAAiC,EAAE,gBAAqC,EAAE,EAAE;gBAC5F,IAAA,aAAM,EAAC,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,kCAAc,CAAC,QAAQ,CAAC,CAAA;gBAChE,IAAA,aAAM,EAAC,gBAAgB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAA;gBACpC,IAAA,aAAM,EAAC,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;gBAC3B,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,QAAQ,EAAE,UAAU,EAAE,kCAAc,CAAC,QAAQ,EAAE,CAAA;YACzE,CAAC,CAAA;SACF,CAAC,CAAA;QACF,MAAM,mBAAmB,GAAG,mBAAmB,CAAC,YAAY,CAAC,CAAA;QAC7D,MAAM,gBAAgB,GAAG,MAAM,mBAAmB,CAAC,cAAc,EAAE,CAAA;QACnE,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAA;QAC1G,MAAM,OAAO,GAAG,MAAM,mBAAmB,CAAC,gBAAgB,EAAE,CAAA;QAC5D,MAAM,eAAe,GAAG,mBAAmB,CAAC,CAAC,MAAM,YAAY,CAAC,WAAW,CAAC,YAAa,EAAE,OAAO,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAA;QACtH,MAAM,YAAY,GAAG,MAAM,eAAe,CAAC,cAAc,EAAE,CAAA;QAC3D,IAAA,aAAM,EAAC,YAAY,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAA;QACzD,IAAA,aAAM,EAAC,YAAY,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,CAAA;QACnD,MAAM,cAAc,GAAG,MAAM,eAAe,CAAC,UAAU,iCAClD,YAAY,KACf,oBAAoB,EAAE;gBACpB,WAAW,EAAE;oBACX,KAAK,EAAE,IAAA,mBAAU,GAAE;oBACnB,YAAY,EAAE,IAAI,CAAC,GAAG,EAAE;oBACxB,QAAQ,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;iBAC3B;aACF,IACD,CAAA;QACF,IAAA,aAAM,EAAC,cAAc,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,CAAA;QACzD,IAAA,aAAM,EAAC,MAAM,CAAC,IAAI,CAAC,MAAA,cAAc,CAAC,oBAAoB,mCAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAA;IAChF,CAAC,CAAA,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["import { getEnvVariables, TestVars } from '@icure/test-setup/types'\nimport { before } from 'mocha'\nimport { createNewHcpApi, createUserInMultipleGroups, getEnvironmentInitializer, setLocalStorage, TestUtils } from '../../utils/test_utils'\nimport { AuthenticationProvider, BasicAuthenticationProvider, NoAuthenticationProvider } from '../../../icc-x-api'\nimport { IccAuthApi, IccUserApi } from '../../../icc-api'\nimport 'isomorphic-fetch'\nimport { AuthSecretDetails, AuthSecretType, SmartAuthProvider } from '../../../icc-x-api/auth/SmartAuthProvider'\nimport { expect } from 'chai'\nimport { randomUUID } from 'crypto'\nimport initMasterApi = TestUtils.initMasterApi\nimport { fail } from 'assert'\nimport { TOTP } from 'otpauth'\nsetLocalStorage(fetch)\n\nlet env: TestVars\nlet authApi: IccAuthApi\n\ndescribe('Smart authentication provider', () => {\n before(async function () {\n this.timeout(600000)\n const initializer = await getEnvironmentInitializer()\n env = await initializer.execute(getEnvVariables())\n authApi = new IccAuthApi(env.iCureUrl, {}, new NoAuthenticationProvider(), fetch)\n })\n\n function userApiWithProvider(authProvider: AuthenticationProvider): IccUserApi {\n return new IccUserApi(env.iCureUrl, {}, authProvider, fetch)\n }\n\n it('Should automatically ask for secret to get a new token, and reasks the secret if it is not valid', async () => {\n const { credentials } = await createNewHcpApi(env)\n let calls = 0\n const authProvider = SmartAuthProvider.initialise(authApi, credentials.user, {\n getSecret: async (acceptedSecrets: AuthSecretType[], previousAttempts: AuthSecretDetails[]) => {\n expect(acceptedSecrets).to.include(AuthSecretType.PASSWORD)\n expect(acceptedSecrets).to.include(AuthSecretType.LONG_LIVED_TOKEN)\n expect(acceptedSecrets).to.include(AuthSecretType.SHORT_LIVED_TOKEN)\n expect(acceptedSecrets).to.not.include(AuthSecretType.TWO_FACTOR_AUTHENTICATION_TOKEN)\n if (calls == 0) {\n expect(previousAttempts).to.be.empty\n } else if (calls == 1) {\n expect(previousAttempts).to.have.length(1)\n expect(previousAttempts[0].value).to.equal('wrong')\n expect(previousAttempts[0].secretType).to.equal(AuthSecretType.LONG_LIVED_TOKEN)\n } else fail(`Unexpected number of calls: ${calls}`)\n return calls++ == 0\n ? { value: 'wrong', secretType: AuthSecretType.LONG_LIVED_TOKEN } // pragma: allowlist secret\n : { value: credentials.password, secretType: AuthSecretType.LONG_LIVED_TOKEN }\n },\n })\n const userApi = userApiWithProvider(authProvider)\n const user = await userApi.getCurrentUser()\n expect(user.healthcarePartyId).to.equal(credentials.dataOwnerId)\n expect(calls).to.equal(2)\n })\n\n it('Should automatically ask for a more powerful secret to perform elevated-security operations if the available secret/token is not good enough', async () => {\n const { credentials, api } = await createNewHcpApi(env)\n const initialUser = await api.userApi.getCurrentUser()\n const masterApi = await initMasterApi(env)\n const userToken = randomUUID()\n const userPw = randomUUID()\n const userWithLongTokenAndPw = await masterApi.userApi.modifyUser({\n ...initialUser,\n passwordHash: userPw,\n authenticationTokens: {\n 'test-long-lived-token': {\n token: userToken,\n creationTime: Date.now(),\n validity: 60 * 60 * 24 * 7,\n },\n },\n })\n let calls = 0\n const authProvider = SmartAuthProvider.initialise(authApi, credentials.user, {\n getSecret: async (acceptedSecrets: AuthSecretType[], previousAttempts: AuthSecretDetails[]) => {\n if (calls == 0) {\n expect(acceptedSecrets).to.include(AuthSecretType.PASSWORD)\n expect(acceptedSecrets).to.include(AuthSecretType.LONG_LIVED_TOKEN)\n expect(acceptedSecrets).to.include(AuthSecretType.SHORT_LIVED_TOKEN)\n expect(acceptedSecrets).to.not.include(AuthSecretType.TWO_FACTOR_AUTHENTICATION_TOKEN)\n expect(previousAttempts).to.be.empty\n calls++\n return { value: userToken, secretType: AuthSecretType.LONG_LIVED_TOKEN }\n } else if (calls == 1) {\n expect(acceptedSecrets).to.include(AuthSecretType.PASSWORD)\n expect(acceptedSecrets).to.not.include(AuthSecretType.LONG_LIVED_TOKEN)\n expect(acceptedSecrets).to.include(AuthSecretType.SHORT_LIVED_TOKEN)\n expect(acceptedSecrets).to.not.include(AuthSecretType.TWO_FACTOR_AUTHENTICATION_TOKEN)\n expect(previousAttempts).to.be.empty\n calls++\n return { value: userPw, secretType: AuthSecretType.PASSWORD }\n } else throw new Error(`Unexpected number of calls: ${calls}`)\n },\n })\n const userApi = userApiWithProvider(authProvider)\n expect((await userApi.getCurrentUser()).rev).to.equal(userWithLongTokenAndPw.rev)\n expect(calls).to.equal(1)\n const newPw = randomUUID()\n const userWithNewPw = await userApi.modifyUser({ ...userWithLongTokenAndPw, passwordHash: newPw })\n expect(userWithNewPw.rev).to.not.equal(userWithLongTokenAndPw.rev)\n expect(calls).to.equal(2)\n const retrievedWithNewPw = await userApiWithProvider(new BasicAuthenticationProvider(credentials.user, newPw)).getCurrentUser()\n expect(retrievedWithNewPw.rev).to.equal(userWithNewPw.rev)\n const couldRetrieveWithOldPw = await userApiWithProvider(new BasicAuthenticationProvider(credentials.user, userPw))\n .getCurrentUser()\n .then(\n () => true,\n () => false\n )\n expect(couldRetrieveWithOldPw).to.be.false\n })\n\n it('Should automatically ask for TOTP after password if user has 2fa enabled', async () => {\n const { credentials, api } = await createNewHcpApi(env)\n const initialUser = await api.userApi.getCurrentUser()\n const masterApi = await initMasterApi(env)\n const totpSecret = 'AAPX7PW2RJIGZ3D4' // pragma: allowlist secret (fake secret generated only for test)\n const totp = new TOTP({\n algorithm: 'SHA1',\n digits: 6,\n period: 30,\n secret: totpSecret,\n })\n const userPw = randomUUID()\n const userWithPwAnd2fa = await masterApi.userApi.modifyUser({\n ...initialUser,\n passwordHash: userPw,\n use2fa: true,\n secret: totpSecret,\n })\n let calls = 0\n const authProvider = SmartAuthProvider.initialise(authApi, credentials.user, {\n getSecret: async (acceptedSecrets: AuthSecretType[], previousAttempts: AuthSecretDetails[]) => {\n if (calls == 0) {\n expect(acceptedSecrets).to.include(AuthSecretType.PASSWORD)\n expect(acceptedSecrets).to.include(AuthSecretType.LONG_LIVED_TOKEN)\n expect(acceptedSecrets).to.include(AuthSecretType.SHORT_LIVED_TOKEN)\n expect(acceptedSecrets).to.not.include(AuthSecretType.TWO_FACTOR_AUTHENTICATION_TOKEN)\n expect(previousAttempts).to.be.empty\n calls++\n return { value: userPw, secretType: AuthSecretType.PASSWORD }\n } else if (calls == 1 || calls == 2) {\n expect(acceptedSecrets).to.have.members([AuthSecretType.TWO_FACTOR_AUTHENTICATION_TOKEN])\n if (calls == 1) expect(previousAttempts).to.be.empty\n if (calls == 2) expect(previousAttempts).to.have.length(1)\n return calls++ == 1\n ? { value: totp.generate() + '13', secretType: AuthSecretType.TWO_FACTOR_AUTHENTICATION_TOKEN }\n : { value: totp.generate(), secretType: AuthSecretType.TWO_FACTOR_AUTHENTICATION_TOKEN }\n } else throw new Error(`Unexpected number of calls: ${calls}`)\n },\n })\n const userApi = userApiWithProvider(authProvider)\n expect((await userApi.getCurrentUser()).rev).to.equal(userWithPwAnd2fa.rev)\n expect(calls).to.equal(3)\n })\n\n it('Should ask for TOTP directly if password is cached', async () => {\n const { credentials, api } = await createNewHcpApi(env)\n const initialUser = await api.userApi.getCurrentUser()\n const masterApi = await initMasterApi(env)\n const totpSecret = 'AAPX7PW2RJIGZ3D4' // pragma: allowlist secret (fake secret generated only for test)\n const totp = new TOTP({\n algorithm: 'SHA1',\n digits: 6,\n period: 30,\n secret: totpSecret,\n })\n const userPw = randomUUID()\n const userWithPwAnd2fa = await masterApi.userApi.modifyUser({\n ...initialUser,\n passwordHash: userPw,\n use2fa: true,\n secret: totpSecret,\n })\n let calls = 0\n const authProvider = SmartAuthProvider.initialise(\n authApi,\n credentials.user,\n {\n getSecret: async (acceptedSecrets: AuthSecretType[], previousAttempts: AuthSecretDetails[]) => {\n expect(acceptedSecrets).to.have.members([AuthSecretType.TWO_FACTOR_AUTHENTICATION_TOKEN])\n expect(previousAttempts).to.be.empty\n expect(calls++).to.equal(0)\n return { value: totp.generate(), secretType: AuthSecretType.TWO_FACTOR_AUTHENTICATION_TOKEN }\n },\n },\n {\n initialSecret: { plainSecret: userPw },\n }\n )\n const userApi = userApiWithProvider(authProvider)\n expect((await userApi.getCurrentUser()).rev).to.equal(userWithPwAnd2fa.rev)\n expect(calls).to.equal(1)\n })\n\n it('Switched provider should keep cached secrets and should be able to have elevated security context', async () => {\n const details = await createUserInMultipleGroups(env)\n let calls = 0\n const authProvider = SmartAuthProvider.initialise(authApi, details.userLogin, {\n getSecret: async (acceptedSecrets: AuthSecretType[], previousAttempts: AuthSecretDetails[]) => {\n expect(acceptedSecrets).to.have.include(AuthSecretType.PASSWORD)\n expect(previousAttempts).to.be.empty\n expect(calls++).to.equal(0)\n return { value: details.userPw12, secretType: AuthSecretType.PASSWORD }\n },\n })\n const defaultGroupUserApi = userApiWithProvider(authProvider)\n const defaultGroupUser = await defaultGroupUserApi.getCurrentUser()\n const otherGroupId = details.group1.id == defaultGroupUser.groupId ? details.group2.id : details.group1.id\n const matches = await defaultGroupUserApi.getMatchingUsers()\n const switchedUserApi = userApiWithProvider((await authProvider.switchGroup(otherGroupId!, matches)).switchedProvider)\n const switchedUser = await switchedUserApi.getCurrentUser()\n expect(switchedUser.id).to.not.equal(defaultGroupUser.id)\n expect(switchedUser.groupId).to.equal(otherGroupId)\n const updatedDefault = await switchedUserApi.modifyUser({\n ...switchedUser,\n authenticationTokens: {\n 'new-token': {\n token: randomUUID(),\n creationTime: Date.now(),\n validity: 60 * 60 * 24 * 7,\n },\n },\n })\n expect(updatedDefault.rev).to.not.equal(switchedUser.rev)\n expect(Object.keys(updatedDefault.authenticationTokens ?? {})).to.not.be.empty\n })\n})\n"]}
@@ -0,0 +1 @@
1
+ import 'isomorphic-fetch';