@rockcarver/frodo-lib 0.11.0

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 (112) hide show
  1. package/.eslintrc +32 -0
  2. package/.github/ISSUE_TEMPLATE/bug_report.md +30 -0
  3. package/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  4. package/.github/README.md +121 -0
  5. package/.github/workflows/pipeline.yml +287 -0
  6. package/.prettierrc +6 -0
  7. package/CHANGELOG.md +512 -0
  8. package/CODE_OF_CONDUCT.md +128 -0
  9. package/LICENSE +21 -0
  10. package/README.md +8 -0
  11. package/docs/CONTRIBUTE.md +96 -0
  12. package/docs/PIPELINE.md +169 -0
  13. package/docs/images/npm_versioning_guidelines.png +0 -0
  14. package/docs/images/release_pipeline.png +0 -0
  15. package/jsconfig.json +6 -0
  16. package/package.json +95 -0
  17. package/resources/sampleEntitiesFile.json +8 -0
  18. package/resources/sampleEnvFile.env +2 -0
  19. package/src/api/AuthenticateApi.js +33 -0
  20. package/src/api/BaseApi.js +242 -0
  21. package/src/api/CirclesOfTrustApi.js +87 -0
  22. package/src/api/EmailTemplateApi.js +37 -0
  23. package/src/api/IdmConfigApi.js +88 -0
  24. package/src/api/LogApi.js +45 -0
  25. package/src/api/ManagedObjectApi.js +62 -0
  26. package/src/api/OAuth2ClientApi.js +69 -0
  27. package/src/api/OAuth2OIDCApi.js +73 -0
  28. package/src/api/OAuth2ProviderApi.js +32 -0
  29. package/src/api/RealmApi.js +99 -0
  30. package/src/api/Saml2Api.js +176 -0
  31. package/src/api/ScriptApi.js +84 -0
  32. package/src/api/SecretsApi.js +151 -0
  33. package/src/api/ServerInfoApi.js +41 -0
  34. package/src/api/SocialIdentityProvidersApi.js +114 -0
  35. package/src/api/StartupApi.js +45 -0
  36. package/src/api/ThemeApi.js +181 -0
  37. package/src/api/TreeApi.js +207 -0
  38. package/src/api/VariablesApi.js +104 -0
  39. package/src/api/utils/ApiUtils.js +77 -0
  40. package/src/api/utils/ApiUtils.test.js +96 -0
  41. package/src/api/utils/Base64.js +62 -0
  42. package/src/index.js +32 -0
  43. package/src/index.test.js +13 -0
  44. package/src/ops/AdminOps.js +901 -0
  45. package/src/ops/AuthenticateOps.js +342 -0
  46. package/src/ops/CirclesOfTrustOps.js +350 -0
  47. package/src/ops/ConnectionProfileOps.js +254 -0
  48. package/src/ops/EmailTemplateOps.js +326 -0
  49. package/src/ops/IdmOps.js +227 -0
  50. package/src/ops/IdpOps.js +342 -0
  51. package/src/ops/JourneyOps.js +2026 -0
  52. package/src/ops/LogOps.js +357 -0
  53. package/src/ops/ManagedObjectOps.js +34 -0
  54. package/src/ops/OAuth2ClientOps.js +151 -0
  55. package/src/ops/OrganizationOps.js +85 -0
  56. package/src/ops/RealmOps.js +139 -0
  57. package/src/ops/SamlOps.js +541 -0
  58. package/src/ops/ScriptOps.js +211 -0
  59. package/src/ops/SecretsOps.js +288 -0
  60. package/src/ops/StartupOps.js +114 -0
  61. package/src/ops/ThemeOps.js +379 -0
  62. package/src/ops/VariablesOps.js +185 -0
  63. package/src/ops/templates/OAuth2ClientTemplate.json +270 -0
  64. package/src/ops/templates/OrgModelUserAttributesTemplate.json +149 -0
  65. package/src/ops/templates/cloud/GenericExtensionAttributesTemplate.json +392 -0
  66. package/src/ops/templates/cloud/managed.json +4119 -0
  67. package/src/ops/utils/Console.js +434 -0
  68. package/src/ops/utils/DataProtection.js +92 -0
  69. package/src/ops/utils/DataProtection.test.js +28 -0
  70. package/src/ops/utils/ExportImportUtils.js +146 -0
  71. package/src/ops/utils/ExportImportUtils.test.js +119 -0
  72. package/src/ops/utils/OpsUtils.js +76 -0
  73. package/src/ops/utils/Wordwrap.js +11 -0
  74. package/src/storage/SessionStorage.js +45 -0
  75. package/src/storage/StaticStorage.js +15 -0
  76. package/test/e2e/journey/baseline/ForgottenUsername.journey.json +216 -0
  77. package/test/e2e/journey/baseline/Login.journey.json +205 -0
  78. package/test/e2e/journey/baseline/PasswordGrant.journey.json +139 -0
  79. package/test/e2e/journey/baseline/ProgressiveProfile.journey.json +198 -0
  80. package/test/e2e/journey/baseline/Registration.journey.json +249 -0
  81. package/test/e2e/journey/baseline/ResetPassword.journey.json +268 -0
  82. package/test/e2e/journey/baseline/UpdatePassword.journey.json +323 -0
  83. package/test/e2e/journey/baseline/allAlphaJourneys.journeys.json +1520 -0
  84. package/test/e2e/journey/delete/ForgottenUsername.journey.json +216 -0
  85. package/test/e2e/journey/delete/Login.journey.json +205 -0
  86. package/test/e2e/journey/delete/PasswordGrant.journey.json +139 -0
  87. package/test/e2e/journey/delete/ProgressiveProfile.journey.json +198 -0
  88. package/test/e2e/journey/delete/Registration.journey.json +249 -0
  89. package/test/e2e/journey/delete/ResetPassword.journey.json +268 -0
  90. package/test/e2e/journey/delete/UpdatePassword.journey.json +323 -0
  91. package/test/e2e/journey/delete/deleteMe.journey.json +230 -0
  92. package/test/e2e/journey/list/Disabled.journey.json +43 -0
  93. package/test/e2e/journey/list/ForgottenUsername.journey.json +216 -0
  94. package/test/e2e/journey/list/Login.journey.json +205 -0
  95. package/test/e2e/journey/list/PasswordGrant.journey.json +139 -0
  96. package/test/e2e/journey/list/ProgressiveProfile.journey.json +198 -0
  97. package/test/e2e/journey/list/Registration.journey.json +249 -0
  98. package/test/e2e/journey/list/ResetPassword.journey.json +268 -0
  99. package/test/e2e/journey/list/UpdatePassword.journey.json +323 -0
  100. package/test/e2e/setup.js +107 -0
  101. package/test/e2e/theme/baseline/Contrast.theme.json +95 -0
  102. package/test/e2e/theme/baseline/Highlander.theme.json +95 -0
  103. package/test/e2e/theme/baseline/Robroy.theme.json +95 -0
  104. package/test/e2e/theme/baseline/Starter-Theme.theme.json +94 -0
  105. package/test/e2e/theme/baseline/Zardoz.theme.json +95 -0
  106. package/test/e2e/theme/import/Contrast.theme.json +95 -0
  107. package/test/e2e/theme/import/Highlander.theme.json +95 -0
  108. package/test/e2e/theme/import/Robroy.theme.json +95 -0
  109. package/test/e2e/theme/import/Starter-Theme.theme.json +94 -0
  110. package/test/e2e/theme/import/Zardoz.default.theme.json +95 -0
  111. package/test/fs_tmp/.gitkeep +2 -0
  112. package/test/global/setup.js +65 -0
@@ -0,0 +1,227 @@
1
+ import fs from 'fs';
2
+ import fse from 'fs-extra';
3
+ import replaceall from 'replaceall';
4
+ import propertiesReader from 'properties-reader';
5
+ import {
6
+ getAllConfigEntities,
7
+ getConfigEntity,
8
+ queryAllManagedObjectsByType,
9
+ } from '../api/IdmConfigApi.js';
10
+ import { printMessage, showSpinner, succeedSpinner } from './utils/Console.js';
11
+ import { getTypedFilename } from './utils/ExportImportUtils.js';
12
+
13
+ /**
14
+ * List all IDM configuration objects
15
+ */
16
+ export async function listAllConfigEntities() {
17
+ let configEntities = [];
18
+ try {
19
+ configEntities = (await getAllConfigEntities()).data;
20
+ } catch (getAllConfigEntitiesError) {
21
+ printMessage(getAllConfigEntitiesError, 'error');
22
+ printMessage(
23
+ `Error getting config entities: ${getAllConfigEntitiesError}`,
24
+ 'error'
25
+ );
26
+ }
27
+ if ('configurations' in configEntities) {
28
+ configEntities.configurations.forEach((configEntity) => {
29
+ printMessage(`${configEntity._id}`, 'data');
30
+ });
31
+ }
32
+ }
33
+
34
+ /**
35
+ * Export an IDM configuration object.
36
+ * @param {String} id the desired configuration object
37
+ * @param {String} file optional export file
38
+ */
39
+ export async function exportConfigEntity(id, file) {
40
+ let fileName = file;
41
+ if (!fileName) {
42
+ fileName = getTypedFilename(`${id}`, 'idm');
43
+ }
44
+ const configEntity = (await getConfigEntity(id)).data;
45
+ fs.writeFile(fileName, JSON.stringify(configEntity, null, 2), (err) => {
46
+ if (err) {
47
+ return printMessage(`ERROR - can't save ${id} export to file`, 'error');
48
+ }
49
+ return '';
50
+ });
51
+ }
52
+
53
+ /**
54
+ * Export all IDM configuration objects into separate JSON files in a directory specified by <directory>
55
+ * @param {String} directory export directory
56
+ */
57
+ export async function exportAllRawConfigEntities(directory) {
58
+ let configEntities = [];
59
+ try {
60
+ configEntities = (await getAllConfigEntities()).data;
61
+ } catch (getAllConfigEntitiesError) {
62
+ printMessage(getAllConfigEntitiesError, 'error');
63
+ printMessage(
64
+ `Error getting config entities: ${getAllConfigEntitiesError}`,
65
+ 'error'
66
+ );
67
+ }
68
+ if ('configurations' in configEntities) {
69
+ if (!fs.existsSync(directory)) {
70
+ fs.mkdirSync(directory);
71
+ }
72
+ showSpinner('Exporting config objects...');
73
+ const entityPromises = [];
74
+ configEntities.configurations.forEach((x) => {
75
+ entityPromises.push(
76
+ getConfigEntity(x._id)
77
+ .then((response) => response.data)
78
+ .catch((getConfigEntityError) => {
79
+ if (
80
+ !(
81
+ getConfigEntityError.response.status === 403 &&
82
+ getConfigEntityError.response.data.message ===
83
+ 'This operation is not available in ForgeRock Identity Cloud.'
84
+ )
85
+ ) {
86
+ printMessage(getConfigEntityError, 'error');
87
+ printMessage(
88
+ `Error getting config entity: ${getConfigEntityError}`,
89
+ 'error'
90
+ );
91
+ }
92
+ })
93
+ );
94
+ });
95
+ Promise.all(entityPromises).then((result) => {
96
+ // console.log(result);
97
+ result.forEach((item) => {
98
+ if (item != null) {
99
+ fse.outputFile(
100
+ `${directory}/${item._id}.json`,
101
+ JSON.stringify(item, null, 2),
102
+ // eslint-disable-next-line consistent-return
103
+ (err) => {
104
+ if (err) {
105
+ return printMessage(
106
+ `ERROR - can't save config ${item._id} to file - ${err}`,
107
+ 'error'
108
+ );
109
+ }
110
+ }
111
+ );
112
+ }
113
+ });
114
+ succeedSpinner();
115
+ });
116
+ }
117
+ }
118
+
119
+ /**
120
+ * Export all IDM configuration objects
121
+ * @param {String} directory export directory
122
+ * @param {String} entitiesFile JSON file that specifies the config entities to export/import
123
+ * @param {String} envFile File that defines environment specific variables for replacement during configuration export/import
124
+ */
125
+ export async function exportAllConfigEntities(
126
+ directory,
127
+ entitiesFile,
128
+ envFile
129
+ ) {
130
+ let entriesToExport = [];
131
+ // read list of entities to export
132
+ fs.readFile(entitiesFile, 'utf8', async (err, data) => {
133
+ if (err) throw err;
134
+ const entriesData = JSON.parse(data);
135
+ entriesToExport = entriesData.idm;
136
+ // console.log(`entriesToExport ${entriesToExport}`);
137
+
138
+ // read list of configs to parameterize for environment specific values
139
+ const envParams = propertiesReader(envFile);
140
+
141
+ let configEntities = [];
142
+ try {
143
+ configEntities = (await getAllConfigEntities()).data;
144
+ } catch (getAllConfigEntitiesError) {
145
+ printMessage(getAllConfigEntitiesError, 'error');
146
+ printMessage(
147
+ `Error getting config entities: ${getAllConfigEntitiesError}`,
148
+ 'error'
149
+ );
150
+ }
151
+ if ('configurations' in configEntities) {
152
+ // create export directory if not exist
153
+ if (!fs.existsSync(directory)) {
154
+ fs.mkdirSync(directory);
155
+ }
156
+ showSpinner('Exporting config objects...');
157
+ const entityPromises = [];
158
+ configEntities.configurations.forEach((x) => {
159
+ if (entriesToExport.includes(x._id)) {
160
+ // console.log(`- ${x._id}`);
161
+ entityPromises.push(
162
+ getConfigEntity(x._id).then((response) => response.data)
163
+ );
164
+ }
165
+ });
166
+ Promise.all(entityPromises).then((result) => {
167
+ // console.log(result);
168
+ result.forEach((item) => {
169
+ if (item != null) {
170
+ let configEntityString = JSON.stringify(item, null, 2);
171
+ envParams.each((key, value) => {
172
+ configEntityString = replaceall(
173
+ value,
174
+ `\${${key}}`,
175
+ configEntityString
176
+ );
177
+ });
178
+ fse.outputFile(
179
+ `${directory}/${item._id}.json`,
180
+ JSON.stringify(item, null, 2),
181
+ // eslint-disable-next-line consistent-return
182
+ (error) => {
183
+ if (err) {
184
+ return printMessage(
185
+ `ERROR - can't save config ${item._id} to file - ${error}`,
186
+ 'error'
187
+ );
188
+ }
189
+ }
190
+ );
191
+ }
192
+ });
193
+ succeedSpinner();
194
+ });
195
+ }
196
+ });
197
+ }
198
+
199
+ /**
200
+ * Count number of managed objects of a given type
201
+ * @param {String} type managed object type, e.g. alpha_user
202
+ */
203
+ export async function countManagedObjects(type) {
204
+ let count = 0;
205
+ let result = {
206
+ result: [],
207
+ resultCount: 0,
208
+ pagedResultsCookie: null,
209
+ totalPagedResultsPolicy: 'NONE',
210
+ totalPagedResults: -1,
211
+ remainingPagedResults: -1,
212
+ };
213
+ try {
214
+ do {
215
+ // eslint-disable-next-line no-await-in-loop
216
+ result = (
217
+ await queryAllManagedObjectsByType(type, [], result.pagedResultsCookie)
218
+ ).data;
219
+ count += result.resultCount;
220
+ // printMessage(result);
221
+ } while (result.pagedResultsCookie);
222
+ printMessage(`${type}: ${count}`);
223
+ } catch (error) {
224
+ printMessage(error.response.data, 'error');
225
+ printMessage(`Error querying managed objects by type: ${error}`, 'error');
226
+ }
227
+ }
@@ -0,0 +1,342 @@
1
+ import fs from 'fs';
2
+ import {
3
+ getSocialIdentityProviders,
4
+ putProviderByTypeAndId,
5
+ } from '../api/SocialIdentityProvidersApi.js';
6
+ import { getScript } from '../api/ScriptApi.js';
7
+ import { createOrUpdateScript } from './ScriptOps.js';
8
+ import {
9
+ convertBase64TextToArray,
10
+ convertTextArrayToBase64,
11
+ getRealmString,
12
+ getTypedFilename,
13
+ saveJsonToFile,
14
+ validateImport,
15
+ } from './utils/ExportImportUtils.js';
16
+ import {
17
+ printMessage,
18
+ createProgressBar,
19
+ updateProgressBar,
20
+ stopProgressBar,
21
+ } from './utils/Console.js';
22
+
23
+ // use a function vs a template variable to avoid problems in loops
24
+ function getFileDataTemplate() {
25
+ return {
26
+ meta: {},
27
+ script: {},
28
+ idp: {},
29
+ };
30
+ }
31
+
32
+ /**
33
+ * List providers
34
+ */
35
+ export async function listProviders() {
36
+ getSocialIdentityProviders()
37
+ .then((response) => {
38
+ response.data.result.sort((a, b) => a._id.localeCompare(b._id));
39
+ response.data.result.forEach((socialIdentityProvider) => {
40
+ printMessage(`${socialIdentityProvider._id}`, 'data');
41
+ });
42
+ })
43
+ .catch((err) => {
44
+ printMessage(`listProviders ERROR: ${err.message}`, 'error');
45
+ printMessage(err, 'error');
46
+ });
47
+ }
48
+
49
+ /**
50
+ * Get social identity provider by id
51
+ * @param {String} id social identity provider id/name
52
+ * @returns {Promise} a promise that resolves a social identity provider object
53
+ */
54
+ export async function getSocialIdentityProviderById(id) {
55
+ return getSocialIdentityProviders().then((response) => {
56
+ const foundProviders = response.data.result.filter(
57
+ (provider) => provider._id === id
58
+ );
59
+ switch (foundProviders.length) {
60
+ case 1:
61
+ return foundProviders[0];
62
+ case 0:
63
+ throw new Error(`Provider '${id}' not found`);
64
+ default:
65
+ throw new Error(`${foundProviders.length} providers '${id}' found`);
66
+ }
67
+ });
68
+ }
69
+
70
+ /**
71
+ * Export provider by id
72
+ * @param {String} id provider id/name
73
+ * @param {String} file optional export file name
74
+ */
75
+ export async function exportProvider(id, file = null) {
76
+ let fileName = file;
77
+ if (!fileName) {
78
+ fileName = getTypedFilename(id, 'idp');
79
+ }
80
+ createProgressBar(1, `Exporting ${id}`);
81
+ try {
82
+ const idpData = await getSocialIdentityProviderById(id);
83
+ updateProgressBar(`Writing file ${fileName}`);
84
+ const fileData = getFileDataTemplate();
85
+ fileData.idp[idpData._id] = idpData;
86
+ if (idpData.transform) {
87
+ const scriptData = (await getScript(idpData.transform)).data;
88
+ scriptData.script = convertBase64TextToArray(scriptData.script);
89
+ fileData.script[idpData.transform] = scriptData;
90
+ }
91
+ saveJsonToFile(fileData, fileName);
92
+ stopProgressBar(`Exported ${id.brightCyan} to ${fileName.brightCyan}.`);
93
+ } catch (err) {
94
+ stopProgressBar(`${err}`);
95
+ printMessage(`${err}`, 'error');
96
+ }
97
+ }
98
+
99
+ /**
100
+ * Export all providers
101
+ * @param {String} file optional export file name
102
+ */
103
+ export async function exportProvidersToFile(file) {
104
+ let fileName = file;
105
+ if (!fileName) {
106
+ fileName = getTypedFilename(`all${getRealmString()}Providers`, 'idp');
107
+ }
108
+ const fileData = getFileDataTemplate();
109
+ const allIdpsData = (await getSocialIdentityProviders()).data.result;
110
+ createProgressBar(allIdpsData.length, 'Exporting providers');
111
+ for (const idpData of allIdpsData) {
112
+ updateProgressBar(`Exporting provider ${idpData._id}`);
113
+ fileData.idp[idpData._id] = idpData;
114
+ if (idpData.transform) {
115
+ // eslint-disable-next-line no-await-in-loop
116
+ const scriptData = (await getScript(idpData.transform)).data;
117
+ scriptData.script = convertBase64TextToArray(scriptData.script);
118
+ fileData.script[idpData.transform] = scriptData;
119
+ }
120
+ }
121
+ saveJsonToFile(fileData, fileName);
122
+ stopProgressBar(`${allIdpsData.length} providers exported to ${fileName}.`);
123
+ }
124
+
125
+ /**
126
+ * Export all providers to individual files
127
+ */
128
+ export async function exportProvidersToFiles() {
129
+ const allIdpsData = await (await getSocialIdentityProviders()).data.result;
130
+ // printMessage(allIdpsData, 'data');
131
+ createProgressBar(allIdpsData.length, 'Exporting providers');
132
+ for (const idpData of allIdpsData) {
133
+ updateProgressBar(`Writing provider ${idpData._id}`);
134
+ const fileName = getTypedFilename(idpData._id, 'idp');
135
+ const fileData = getFileDataTemplate();
136
+ fileData.idp[idpData._id] = idpData;
137
+ if (idpData.transform) {
138
+ // eslint-disable-next-line no-await-in-loop
139
+ const scriptData = (await getScript(idpData.transform)).data;
140
+ scriptData.script = convertBase64TextToArray(scriptData.script);
141
+ fileData.script[idpData.transform] = scriptData;
142
+ }
143
+ saveJsonToFile(fileData, fileName);
144
+ }
145
+ stopProgressBar(`${allIdpsData.length} providers exported.`);
146
+ }
147
+
148
+ /**
149
+ * Import provider by id/name
150
+ * @param {String} id provider id/name
151
+ * @param {String} file import file name
152
+ */
153
+ export async function importProviderById(id, file) {
154
+ fs.readFile(file, 'utf8', async (err, data) => {
155
+ if (err) throw err;
156
+ const fileData = JSON.parse(data);
157
+ if (validateImport(fileData.meta)) {
158
+ createProgressBar(1, 'Importing provider...');
159
+ let found = false;
160
+ for (const idpId in fileData.idp) {
161
+ if ({}.hasOwnProperty.call(fileData.idp, idpId)) {
162
+ if (idpId === id) {
163
+ found = true;
164
+ updateProgressBar(`Importing ${fileData.idp[idpId]._id}`);
165
+ const scriptId = fileData.idp[idpId].transform;
166
+ const scriptData = fileData.script[scriptId];
167
+ if (scriptId && scriptData) {
168
+ scriptData.script = convertTextArrayToBase64(scriptData.script);
169
+ // eslint-disable-next-line no-await-in-loop
170
+ await createOrUpdateScript(
171
+ fileData.idp[idpId].transform,
172
+ fileData.script[fileData.idp[idpId].transform]
173
+ );
174
+ }
175
+ putProviderByTypeAndId(
176
+ fileData.idp[idpId]._type._id,
177
+ idpId,
178
+ fileData.idp[idpId]
179
+ )
180
+ .then(() => {
181
+ stopProgressBar(`Successfully imported provider ${id}.`);
182
+ })
183
+ .catch((importProviderErr) => {
184
+ stopProgressBar(
185
+ `Error importing provider ${fileData.idp[idpId]._id}`
186
+ );
187
+ printMessage(`\nError importing provider ${id}`, 'error');
188
+ printMessage(importProviderErr.response.data, 'error');
189
+ });
190
+ break;
191
+ }
192
+ }
193
+ }
194
+ if (!found) {
195
+ stopProgressBar(
196
+ `Provider ${id.brightCyan} not found in ${file.brightCyan}!`
197
+ );
198
+ }
199
+ } else {
200
+ printMessage('Import validation failed...', 'error');
201
+ }
202
+ });
203
+ }
204
+
205
+ /**
206
+ * Import first provider from file
207
+ * @param {String} file import file name
208
+ */
209
+ export async function importFirstProvider(file) {
210
+ fs.readFile(file, 'utf8', async (err, data) => {
211
+ if (err) throw err;
212
+ const fileData = JSON.parse(data);
213
+ if (validateImport(fileData.meta)) {
214
+ createProgressBar(1, 'Importing provider...');
215
+ for (const idpId in fileData.idp) {
216
+ if ({}.hasOwnProperty.call(fileData.idp, idpId)) {
217
+ updateProgressBar(`Importing ${fileData.idp[idpId]._id}`);
218
+ const scriptId = fileData.idp[idpId].transform;
219
+ const scriptData = fileData.script[scriptId];
220
+ if (scriptId && scriptData) {
221
+ scriptData.script = convertTextArrayToBase64(scriptData.script);
222
+ // eslint-disable-next-line no-await-in-loop
223
+ await createOrUpdateScript(
224
+ fileData.idp[idpId].transform,
225
+ fileData.script[fileData.idp[idpId].transform]
226
+ );
227
+ }
228
+ putProviderByTypeAndId(
229
+ fileData.idp[idpId]._type._id,
230
+ idpId,
231
+ fileData.idp[idpId]
232
+ ).then((result) => {
233
+ if (result == null) {
234
+ stopProgressBar(
235
+ `Error importing provider ${fileData.idp[idpId]._id}`
236
+ );
237
+ printMessage(
238
+ `Error importing provider ${fileData.idp[idpId]._id}`,
239
+ 'error'
240
+ );
241
+ } else {
242
+ stopProgressBar(
243
+ `Successfully imported provider ${fileData.idp[idpId]._id}.`
244
+ );
245
+ }
246
+ });
247
+ break;
248
+ }
249
+ }
250
+ } else {
251
+ printMessage('Import validation failed...', 'error');
252
+ }
253
+ });
254
+ }
255
+
256
+ /**
257
+ * Import all providers from file
258
+ * @param {String} file import file name
259
+ */
260
+ export async function importProvidersFromFile(file) {
261
+ fs.readFile(file, 'utf8', async (err, data) => {
262
+ if (err) throw err;
263
+ const fileData = JSON.parse(data);
264
+ if (validateImport(fileData.meta)) {
265
+ createProgressBar(
266
+ Object.keys(fileData.idp).length,
267
+ 'Importing providers...'
268
+ );
269
+ for (const idpId in fileData.idp) {
270
+ if ({}.hasOwnProperty.call(fileData.idp, idpId)) {
271
+ const scriptId = fileData.idp[idpId].transform;
272
+ const scriptData = fileData.script[scriptId];
273
+ if (scriptId && scriptData) {
274
+ scriptData.script = convertTextArrayToBase64(scriptData.script);
275
+ // eslint-disable-next-line no-await-in-loop
276
+ await createOrUpdateScript(
277
+ fileData.idp[idpId].transform,
278
+ fileData.script[fileData.idp[idpId].transform]
279
+ );
280
+ }
281
+ // eslint-disable-next-line no-await-in-loop
282
+ const result = await putProviderByTypeAndId(
283
+ fileData.idp[idpId]._type._id,
284
+ idpId,
285
+ fileData.idp[idpId]
286
+ );
287
+ if (!result) {
288
+ updateProgressBar(
289
+ `Successfully imported ${fileData.idp[idpId].name}`
290
+ );
291
+ }
292
+ }
293
+ }
294
+ stopProgressBar(`Providers imported.`);
295
+ } else {
296
+ printMessage('Import validation failed...', 'error');
297
+ }
298
+ });
299
+ }
300
+
301
+ /**
302
+ * Import providers from *.idp.json files in current working directory
303
+ */
304
+ export async function importProvidersFromFiles() {
305
+ const names = fs.readdirSync('.');
306
+ const jsonFiles = names.filter((name) =>
307
+ name.toLowerCase().endsWith('.idp.json')
308
+ );
309
+
310
+ createProgressBar(jsonFiles.length, 'Importing providers...');
311
+ let total = 0;
312
+ for (const file of jsonFiles) {
313
+ const data = fs.readFileSync(file, 'utf8');
314
+ const fileData = JSON.parse(data);
315
+ if (validateImport(fileData.meta)) {
316
+ const count = Object.keys(fileData.idp).length;
317
+ total += count;
318
+ for (const idpId in fileData.idp) {
319
+ if ({}.hasOwnProperty.call(fileData.idp, idpId)) {
320
+ // eslint-disable-next-line no-await-in-loop
321
+ const result = await putProviderByTypeAndId(
322
+ fileData.idp[idpId]._type._id,
323
+ idpId,
324
+ fileData.idp[idpId]
325
+ );
326
+ if (result == null) {
327
+ printMessage(
328
+ `Error importing ${count} providers from ${file}`,
329
+ 'error'
330
+ );
331
+ }
332
+ }
333
+ }
334
+ updateProgressBar(`Imported ${count} provider(s) from ${file}`);
335
+ } else {
336
+ printMessage(`Validation of ${file} failed!`, 'error');
337
+ }
338
+ }
339
+ stopProgressBar(
340
+ `Finished importing ${total} provider(s) from ${jsonFiles.length} file(s).`
341
+ );
342
+ }