@pega/custom-dx-components 8.8.8 → 8.8.10

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 (27) hide show
  1. package/package.json +2 -3
  2. package/src/auth.js +126 -91
  3. package/src/tasks/create/templates/Constellation/Field/Text-Phone/index.jsx.mustache +0 -1
  4. package/src/tasks/create/templates/Constellation/Template/DETAILS/demo.stories.jsx.mustache +20 -6
  5. package/src/tasks/create/templates/Constellation/Template/DETAILS/mock.stories.js.mustache +20 -10
  6. package/src/tasks/create/templates/Constellation/Template/DETAILS-region/demo.stories.jsx.mustache +20 -7
  7. package/src/tasks/create/templates/Constellation/Template/DETAILS-region/mock.stories.js.mustache +28 -13
  8. package/src/tasks/create/templates/Constellation/Template/FORM/demo.stories.jsx.mustache +90 -14
  9. package/src/tasks/create/templates/Constellation/Template/FORM/mock.stories.js.mustache +24 -12
  10. package/src/tasks/create/templates/Constellation/Template/FORM-region/demo.stories.jsx.mustache +89 -11
  11. package/src/tasks/create/templates/Constellation/Template/FORM-region/mock.stories.js.mustache +24 -12
  12. package/src/tasks/create/templates/Constellation/Template/PAGE/demo.stories.jsx.mustache +1 -0
  13. package/src/tasks/init/template/README.md +2 -204
  14. package/src/tasks/init/template/package.json.mustache +1 -1
  15. package/src/tasks/init/template/src/components/_components.md +1 -0
  16. package/src/tasks/init/template/tasks.config.json +5 -5
  17. package/src/tasks/init/template/src/components/Organization_Library_MediaURL/MediaURL.stories.tsx +0 -19
  18. package/src/tasks/init/template/src/components/Organization_Library_MediaURL/MediaURL.styles.ts +0 -5
  19. package/src/tasks/init/template/src/components/Organization_Library_MediaURL/MediaURL.types.ts +0 -10
  20. package/src/tasks/init/template/src/components/Organization_Library_MediaURL/MediaURLDisplay.tsx +0 -25
  21. package/src/tasks/init/template/src/components/Organization_Library_MediaURL/MediaURLInput.tsx +0 -24
  22. package/src/tasks/init/template/src/components/Organization_Library_MediaURL/config.json +0 -13
  23. package/src/tasks/init/template/src/components/Organization_Library_MediaURL/index.ts +0 -2
  24. package/src/tasks/init/template/src/components/Organization_Library_VideoPlayer/config.json +0 -44
  25. package/src/tasks/init/template/src/components/Organization_Library_VideoPlayer/demo.stories.jsx +0 -40
  26. package/src/tasks/init/template/src/components/Organization_Library_VideoPlayer/index.jsx +0 -42
  27. package/src/tasks/init/template/src/components/Organization_Library_VideoPlayer/styles.js +0 -5
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pega/custom-dx-components",
3
- "version": "8.8.8",
3
+ "version": "8.8.10",
4
4
  "description": "Utility for building custom UI components",
5
5
  "bin": "./bin/index.js",
6
6
  "scripts": {
@@ -24,9 +24,8 @@
24
24
  "babel-loader": "^8.2.5",
25
25
  "chalk": "^5.0.1",
26
26
  "compression-webpack-plugin": "^10.0.0",
27
- "crypto": "^1.0.1",
28
27
  "css-loader": "6.7.1",
29
- "css-minimizer-webpack-plugin": "^4.1.0",
28
+ "css-minimizer-webpack-plugin": "^5.0.0",
30
29
  "eslint": "^8.4.1",
31
30
  "execa": "^6.1.0",
32
31
  "file-loader": "6.2.0",
package/src/auth.js CHANGED
@@ -1,14 +1,3 @@
1
- // Below imports needed for when this file is used for a Node apps/Jest tests
2
- // (can't do conditional imports...so should remove them for regular browser scenarios)
3
-
4
- import fetch from 'node-fetch';
5
- import open from 'open';
6
- import crypto from 'node:crypto';
7
- import https from 'node:https';
8
- import http from 'node:http';
9
- import fs from 'node:fs';
10
-
11
-
12
1
  class PegaAuth {
13
2
  constructor(ssKeyConfig) {
14
3
  if (typeof ssKeyConfig === "string") {
@@ -18,16 +7,17 @@ class PegaAuth {
18
7
  // object with config structure is passed in
19
8
  this.config = ssKeyConfig;
20
9
  }
10
+ this.urlencoded = 'application/x-www-form-urlencoded';
21
11
  this.isNode = typeof window === 'undefined';
22
- this.crypto = this.isNode ? crypto : window.crypto;
23
-
24
- // Tried both preferring the subtle and the webcrypto but both still yileded different behavior on digest
25
12
 
26
- // Prefer webcrypto.subtle over regular subtle
27
- // this.subtle = this.isNode ? (crypto.webcrypto ? crypto.webcrypto.subtle : crypto.subtle) : window.crypto.subtle;
28
-
29
- // Prefer regular subtle over webcrypto.suble for now
30
- this.subtle = this.isNode ? (crypto.subtle ? crypto.subtle : crypto.webcrypto.subtle) : window.crypto.subtle;
13
+ // For isNode path the below attributes are initialized on first method invocation
14
+ if (!this.isNode) {
15
+ this.crypto = window.crypto;
16
+ this.subtle = window.crypto.subtle;
17
+ }
18
+ if (!this.config.serverType) {
19
+ this.config.serverType = 'infinity';
20
+ }
31
21
  }
32
22
 
33
23
  #reloadConfig() {
@@ -42,7 +32,7 @@ class PegaAuth {
42
32
  } catch (e) {
43
33
  try {
44
34
  obj = JSON.parse(this.#atob(peConfig));
45
- } catch (e) {
35
+ } catch (err) {
46
36
  obj = {};
47
37
  }
48
38
  }
@@ -56,10 +46,35 @@ class PegaAuth {
56
46
  }
57
47
  }
58
48
 
49
+ async #importSingleLib(libName, libProp) {
50
+ return import(libName).then((mod) => {
51
+ this[libProp] = mod.default;
52
+ }).catch((e) => {
53
+ console.error(`Library ${libName} failed to load`);
54
+ });
55
+ }
56
+
57
+ async #importNodeLibs() {
58
+ // Also current assumption is using Node 18 or better
59
+ return Promise.all([
60
+ this.#importSingleLib('node-fetch', 'fetch'),
61
+ this.#importSingleLib('open', 'open'),
62
+ this.#importSingleLib('node:crypto', 'crypto'),
63
+ this.#importSingleLib('node:https', 'https'),
64
+ this.#importSingleLib('node:http', 'http'),
65
+ this.#importSingleLib('node:fs', 'fs')
66
+ ]).then(() => {
67
+ this.subtle = this.crypto.subtle || this.crypto.webcrypto.subtle;
68
+ /* eslint-disable-next-line no-global-assign */
69
+ fetch = this.fetch;
70
+ });
71
+ }
72
+
59
73
  // For PKCE the authorize includes a code_challenge & code_challenge_method as well
60
74
  async #buildAuthorizeUrl(state) {
61
75
  const { serverType, clientId, redirectUri, authorizeUri, authService, sessionIndex, appAlias,
62
76
  userIdentifier, password, noPKCE, isolationId } = this.config;
77
+ const bInfinity = serverType === 'infinity';
63
78
 
64
79
  if (!noPKCE) {
65
80
  // Generate random string of 64 chars for verifier. RFC 7636 says from 43-128 chars
@@ -83,63 +98,64 @@ class PegaAuth {
83
98
  }
84
99
 
85
100
  // Trim alias to include just the real alias piece
86
- const addtlScope = appAlias ? '+app.alias.' + appAlias.replace(/^app\//, '') : '';
87
- const scope = (serverType === 'infinity' ? `openid${addtlScope}` : 'user_info');
101
+ const addtlScope = appAlias ? `+app.alias.${appAlias.replace(/^app\//, '')}` : '';
102
+ const scope = (bInfinity ? `openid${addtlScope}` : 'user_info');
88
103
 
89
104
  // Add explicit creds if specified to try to avoid login popup
90
- const moreAuthArgs = (serverType === 'infinity' ?
91
- '&enable_psyncid=true' +
92
- (authService ? `&authentication_service=${encodeURIComponent(authService)}` : '') +
93
- (sessionIndex && this.config.sessionIndexAttempts < 3 ? `&session_index=${sessionIndex}` : '') +
94
- (userIdentifier
95
- ? `&UserIdentifier=${encodeURIComponent(userIdentifier)}${password ? `&Password=${encodeURIComponent(this.#atob(password))}` : ''}` : '')
96
- : `&isolationID=${isolationId}`);
105
+ const authServiceArg = authService ? `&authentication_service=${encodeURIComponent(authService)}` : '';
106
+ const sessionIndexArg = sessionIndex && this.config.sessionIndexAttempts < 3 ? `&session_index=${sessionIndex}` : '';
107
+ const userIdentifierArg = userIdentifier ? `&UserIdentifier=${encodeURIComponent(userIdentifier)}` : '';
108
+ const passwordArg = password && userIdentifier ? `&Password=${encodeURIComponent(window.atob(password))}` : '';
109
+ const moreAuthArgs = bInfinity
110
+ ? `&enable_psyncid=true${authServiceArg}${sessionIndexArg}${userIdentifierArg}${passwordArg}`
111
+ : `&isolationID=${isolationId}`;
97
112
 
98
113
  let pkceArgs = '';
99
114
  if (!noPKCE) {
100
115
  const cc = await this.#getCodeChallenge(this.config.codeVerifier);
101
116
  pkceArgs = `&code_challenge=${cc}&code_challenge_method=S256`;
102
117
  }
103
- const authUrl = `${authorizeUri}?client_id=${clientId}&response_type=code&redirect_uri=${redirectUri}&scope=${scope}&state=${state}${pkceArgs}${moreAuthArgs}`;
104
- // console.log(`authUrl: ${authUrl}`);
105
- return authUrl;
118
+ return `${authorizeUri}?client_id=${clientId}&response_type=code&redirect_uri=${redirectUri}&scope=${scope}&state=${state}${pkceArgs}${moreAuthArgs}`;
106
119
  }
107
120
 
108
121
  async login() {
122
+ if (this.isNode && !this.crypto) {
123
+ // Deferring dynamic loading of node libraries til this first method to avoid doing this in constructor
124
+ await this.#importNodeLibs();
125
+ }
109
126
  const { grantType } = this.config;
110
127
  if (grantType && grantType !== 'authCode') {
111
128
  return this.getToken();
112
- } else {
113
- return this.#authCodeStart();
114
129
  }
130
+ return this.#authCodeStart();
115
131
  }
116
132
 
117
133
  // authCode login issues the authorize endpoint transaction and deals with redirects
134
+ /* eslint-disable-next-line sonarjs/cognitive-complexity */
118
135
  async #authCodeStart() {
119
136
  const fnGetRedirectUriOrigin = () => {
120
- let redirectUri = this.config.redirectUri;
121
- let nRootOffset = redirectUri.indexOf("//");
122
- let nFirstPathOffset = nRootOffset !== -1 ? redirectUri.indexOf("/", nRootOffset + 2) : -1;
137
+ const redirectUri = this.config.redirectUri;
138
+ const nRootOffset = redirectUri.indexOf("//");
139
+ const nFirstPathOffset = nRootOffset !== -1 ? redirectUri.indexOf("/", nRootOffset + 2) : -1;
123
140
  return nFirstPathOffset !== -1 ? redirectUri.substring(0, nFirstPathOffset) : redirectUri;
124
141
  };
125
142
 
126
143
  const redirectOrigin = fnGetRedirectUriOrigin();
127
- const state = this.isNode ? '' : this.#btoa(location.origin);
144
+ const state = this.isNode ? '' : this.#btoa(window.location.origin);
128
145
 
129
146
  return new Promise((resolve, reject) => {
130
- /* eslint-disable consistent-return */
131
147
  this.#buildAuthorizeUrl(state).then((url) => {
132
148
  let myWindow = null; // popup or iframe
133
- let elIframe = null,
134
- elCloseBtn = null;
149
+ let elIframe = null;
150
+ let elCloseBtn = null;
135
151
  const iframeTimeout = this.config.silentTimeout !== undefined ? this.config.silentTimeout : 5000;
136
152
  let bWinIframe = !this.isNode &&
137
153
  iframeTimeout > 0 &&
138
154
  ((!!this.config.userIdentifier && !!this.config.password) ||
139
155
  this.config.iframeLoginUI ||
140
156
  this.config.authService !== 'pega');
141
- let tmrAuthComplete = null,
142
- checkWindowClosed = null;
157
+ let tmrAuthComplete = null;
158
+ let checkWindowClosed = null;
143
159
  const myWinOnLoad = () => {
144
160
  try {
145
161
  if (bWinIframe) {
@@ -152,8 +168,12 @@ class PegaAuth {
152
168
  console.log("authjs(login): Exception trying to postMessage on load");
153
169
  }
154
170
  };
171
+ /* eslint-disable prefer-promise-reject-errors */
155
172
  const fnOpenPopup = () => {
156
- myWindow = (this.isNode ? open : window.open)(url, '_blank', 'width=700,height=500,left=200,top=100');
173
+ if (this.config.noPopups) {
174
+ return reject("no-popups");
175
+ }
176
+ myWindow = (this.isNode ? this.open : window.open)(url, '_blank', 'width=700,height=500,left=200,top=100');
157
177
  if (!myWindow) {
158
178
  // Blocked by popup-blocker
159
179
  return reject("blocked");
@@ -172,14 +192,17 @@ class PegaAuth {
172
192
  }
173
193
  }
174
194
  };
195
+ /* eslint-enable prefer-promise-reject-errors */
175
196
  const fnCloseIframe = () => {
176
197
  elIframe.parentNode.removeChild(elIframe);
177
198
  elCloseBtn.parentNode.removeChild(elCloseBtn);
178
- elIframe = elCloseBtn = null;
199
+ elIframe = null;
200
+ elCloseBtn = null;
179
201
  bWinIframe = false;
180
202
  };
181
203
  const fnCloseAndReject = () => {
182
204
  fnCloseIframe();
205
+ /* eslint-disable-next-line prefer-promise-reject-errors */
183
206
  reject("closed");
184
207
  };
185
208
  let authMessageReceiver = null;
@@ -192,11 +215,9 @@ class PegaAuth {
192
215
  if (bWinIframe) {
193
216
  clearTimeout(tmrAuthComplete);
194
217
  fnCloseIframe();
195
- } else {
196
- if (!this.isNode) {
197
- clearInterval(checkWindowClosed);
198
- myWindow.close();
199
- }
218
+ } else if (!this.isNode) {
219
+ clearInterval(checkWindowClosed);
220
+ myWindow.close();
200
221
  }
201
222
  resolve(token);
202
223
  })
@@ -209,9 +230,9 @@ class PegaAuth {
209
230
  if (bWinIframe) {
210
231
  const nFrameZLevel = 99999;
211
232
  elIframe = document.createElement('iframe');
212
- elIframe.id = 'pe' + this.config.clientId;
213
- const loginBoxWidth = 500,
214
- loginBoxHeight = 700;
233
+ elIframe.id = `pe${this.config.clientId}`;
234
+ const loginBoxWidth = 500;
235
+ const loginBoxHeight = 700;
215
236
  const oStyle = elIframe.style;
216
237
  oStyle.position = 'absolute';
217
238
  oStyle.display = 'none';
@@ -226,7 +247,8 @@ class PegaAuth {
226
247
  elIframe.addEventListener('load', myWinOnLoad, true);
227
248
  // Disallow iframe content attempts to navigate main window
228
249
  elIframe.setAttribute('sandbox', 'allow-scripts allow-forms allow-same-origin');
229
- elIframe.setAttribute('src', url);
250
+ // Adding prompt=none as this is standard OIDC way to communicate no UI is expected (expecting Pega security to support this one day)
251
+ elIframe.setAttribute('src', `${url}&prompt=none`);
230
252
 
231
253
  const svgCloseBtn = `<?xml version="1.0" encoding="UTF-8"?>
232
254
  <svg width="34px" height="34px" viewBox="0 0 34 34" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
@@ -283,20 +305,19 @@ class PegaAuth {
283
305
  const isHttp = redirectUri.startsWith('http:');
284
306
  const nLocalhost = redirectUri.indexOf("localhost:");
285
307
  const nSlash = redirectUri.indexOf('/', nLocalhost + 10);
286
- const nPort = parseInt(redirectUri.substring(nLocalhost + 10, nSlash));
287
- if (-1 !== nLocalhost) {
308
+ const nPort = parseInt(redirectUri.substring(nLocalhost + 10, nSlash), 10);
309
+ if (nLocalhost !== -1) {
288
310
  const options = key && cert && !isHttp ? {
289
- key: fs.readFileSync(key),
290
- cert: fs.readFileSync(cert)
311
+ key: this.fs.readFileSync(key),
312
+ cert: this.fs.readFileSync(cert)
291
313
  } : {};
292
- const server = (isHttp ? http : https).createServer(options, (req, res) => {
293
- const { method, url } = req;
314
+ const server = (isHttp ? this.http : this.https).createServer(options, (req, res) => {
294
315
  const { winTitle, winBodyHtml } = this.config;
295
- // console.log(`HTTP request received: ${url}`);
316
+ // console.log(`HTTP request received: ${req.url}`);
296
317
  res.writeHead(200, { 'Content-Type': 'text/html' });
297
318
  // Auto closing window for now. Can always leave it up and allow authConfig props to set title and bodyHtml
298
319
  res.end(`<html><head><title>${winTitle}</title><script>window.close();</script></head><body>${winBodyHtml}</body></html>`);
299
- const queryString = url.split('?')[1];
320
+ const queryString = req.url.split('?')[1];
300
321
  const urlParams = new URLSearchParams(queryString);
301
322
  const code = urlParams.get('code');
302
323
  if (code) {
@@ -306,6 +327,7 @@ class PegaAuth {
306
327
  fnGetTokenAndFinish(code);
307
328
  }
308
329
  });
330
+ /* eslint-enable no-undef */
309
331
  server.listen(nPort);
310
332
  }
311
333
  }
@@ -323,7 +345,7 @@ class PegaAuth {
323
345
  fnGetTokenAndFinish(code);
324
346
  };
325
347
  window.addEventListener('message', authMessageReceiver, false);
326
- window.authCodeCallback = function (code) {
348
+ window.authCodeCallback = (code) => {
327
349
  console.log('authjs(login): authCodeCallback used with code');
328
350
  fnGetTokenAndFinish(code);
329
351
  };
@@ -333,12 +355,13 @@ class PegaAuth {
333
355
  }
334
356
 
335
357
  // For PKCE token endpoint includes code_verifier
358
+ /* eslint-disable-next-line sonarjs/cognitive-complexity */
336
359
  getToken(authCode) {
337
360
  // Reload config to pick up the previously stored codeVerifier
338
361
  this.#reloadConfig();
339
362
 
340
363
  const { serverType, isolationId, clientId, clientSecret, redirectUri, tokenUri, codeVerifier, grantType,
341
- sessionIndex, customTokenParams, userIdentifier, password, noPKCE, ignoreInvalidCerts } = this.config;
364
+ sessionIndex, customTokenParams, userIdentifier, password, noPKCE } = this.config;
342
365
 
343
366
  const bAuthCode = !grantType || grantType === 'authCode';
344
367
  if (bAuthCode && !authCode && !this.isNode) {
@@ -352,14 +375,14 @@ class PegaAuth {
352
375
  if (clientSecret) {
353
376
  formData.append('client_secret', clientSecret);
354
377
  }
378
+ /* eslint-disable camelcase */
355
379
  const fullGTName = {
356
380
  "authCode": "authorization_code",
357
381
  "clientCreds": "client_credentials",
358
382
  "customBearer": "custom-bearer",
359
383
  "passwordCreds": "password"
360
384
  }[grantType];
361
- const grant_type = fullGTName ? fullGTName :
362
- (grantType ? grantType : 'authorization_code');
385
+ const grant_type = fullGTName || grantType || 'authorization_code';
363
386
  formData.append('grant_type', grant_type);
364
387
  if (serverType === 'launchpad' && grantType !== 'authCode') {
365
388
  formData.append('isolation_ids', isolationId);
@@ -373,6 +396,7 @@ class PegaAuth {
373
396
  } else if (sessionIndex) {
374
397
  formData.append('session_index', sessionIndex);
375
398
  }
399
+ /* eslint-enable camelcase */
376
400
  if (grantType === 'customBearer' && customTokenParams) {
377
401
  Object.keys(customTokenParams).forEach((param) => {
378
402
  formData.append(param, customTokenParams[param]);
@@ -382,13 +406,12 @@ class PegaAuth {
382
406
  formData.append('username', userIdentifier);
383
407
  formData.append('password', this.#atob(password));
384
408
  }
385
- // console.log(`getToken form data: ${formData.toString()}`);
386
409
 
387
410
  return fetch(tokenUri, {
388
- agent: this.isNode && ignoreInvalidCerts ? new https.Agent({ rejectUnauthorized: false }) : undefined,
411
+ agent: this.#getAgent(),
389
412
  method: 'POST',
390
413
  headers: new Headers({
391
- 'content-type': 'application/x-www-form-urlencoded'
414
+ 'content-type': this.urlencoded
392
415
  }),
393
416
 
394
417
  body: formData.toString()
@@ -397,11 +420,10 @@ class PegaAuth {
397
420
  .then((token) => {
398
421
  if (token.errors || token.error) {
399
422
  // console.log(`formData: ${formData.toString()}`);
400
- // console.log(`Token endpoint error: ${JSON.stringify(token.errors ? token.errors : token)}`);
423
+ console.log(`Token endpoint error: ${JSON.stringify(token.errors || token.error)}`);
401
424
  } else {
402
425
  // .expires_in contains the # of seconds before access token expires
403
426
  // add property to keep track of current time when the token expires
404
- /* eslint-disable camelcase */
405
427
  token.eA = Date.now() + token.expires_in * 1000;
406
428
  if (this.config.codeVerifier) {
407
429
  delete this.config.codeVerifier;
@@ -417,7 +439,6 @@ class PegaAuth {
417
439
  this.#updateConfig();
418
440
  }
419
441
  return token;
420
- /* eslint-enable camelcase */
421
442
  })
422
443
  .catch((e) => {
423
444
  console.log(e);
@@ -426,7 +447,12 @@ class PegaAuth {
426
447
 
427
448
  /* eslint-disable camelcase */
428
449
  async refreshToken(refresh_token) {
429
- const { clientId, clientSecret, tokenUri, ignoreInvalidCerts } = this.config;
450
+ const { clientId, clientSecret, tokenUri } = this.config;
451
+
452
+ if (this.isNode && !this.crypto) {
453
+ // Deferring dynamic loading of node libraries til this first method to avoid doing this in constructor
454
+ await this.#importNodeLibs();
455
+ }
430
456
 
431
457
  const formData = new URLSearchParams();
432
458
  formData.append('client_id', clientId);
@@ -437,16 +463,16 @@ class PegaAuth {
437
463
  formData.append('refresh_token', refresh_token);
438
464
 
439
465
  return fetch(tokenUri, {
440
- agent: this.isNode && ignoreInvalidCerts ? new https.Agent({ rejectUnauthorized: false }) : undefined,
466
+ agent: this.#getAgent(),
441
467
  method: 'POST',
442
468
  headers: new Headers({
443
- 'content-type': 'application/x-www-form-urlencoded'
469
+ 'content-type': this.urlencoded
444
470
  }),
445
471
 
446
472
  body: formData.toString()
447
473
  })
448
474
  .then((response) => {
449
- if (!response.ok && 401 === response.status) {
475
+ if (!response.ok && response.status === 401) {
450
476
  return null;
451
477
  }
452
478
  return response.json();
@@ -469,13 +495,19 @@ class PegaAuth {
469
495
  // Must have a config structure to proceed
470
496
  return;
471
497
  }
472
- const { clientId, clientSecret, revokeUri, ignoreInvalidCerts } = this.config;
498
+ const { clientId, clientSecret, revokeUri } = this.config;
499
+
500
+ if (this.isNode && !this.crypto) {
501
+ // Deferring dynamic loading of node libraries til this first method to avoid doing this in constructor
502
+ await this.#importNodeLibs();
503
+ }
473
504
 
474
- let hdrs = { 'content-type': 'application/x-www-form-urlencoded' };
505
+ const hdrs = { 'content-type': this.urlencoded };
475
506
  if (clientSecret) {
476
- hdrs['authorization'] = 'Basic ' + this.#btoa(clientId + ':' + clientSecret);
507
+ const basicCreds = window.btoa(`${clientId}:${clientSecret}`);
508
+ hdrs.authorization = `Basic ${basicCreds}`;
477
509
  }
478
- let aTknProps = ['access_token'];
510
+ const aTknProps = ['access_token'];
479
511
  if (refresh_token) {
480
512
  aTknProps.push('refresh_token');
481
513
  }
@@ -487,14 +519,14 @@ class PegaAuth {
487
519
  formData.append('token', prop === 'access_token' ? access_token : refresh_token);
488
520
  formData.append('token_type_hint', prop);
489
521
  fetch(revokeUri, {
490
- agent: this.isNode && ignoreInvalidCerts ? new https.Agent({ rejectUnauthorized: false }) : undefined,
522
+ agent: this.#getAgent(),
491
523
  method: 'POST',
492
524
  headers: new Headers(hdrs),
493
525
  body: formData.toString()
494
526
  })
495
527
  .then((response) => {
496
528
  if (!response.ok) {
497
- console.log('Error revoking ' + prop + ':' + response.status);
529
+ console.log(`Error revoking ${prop}:${response.status}`);
498
530
  }
499
531
  })
500
532
  .catch((e) => {
@@ -516,31 +548,27 @@ class PegaAuth {
516
548
  return new Promise((resolve) => {
517
549
  return resolve(this.crypto.createHash("sha256").update(str).digest());
518
550
  });
519
- } else {
520
- return this.subtle.digest('SHA-256', new TextEncoder().encode(str));
521
551
  }
552
+ return this.subtle.digest('SHA-256', new TextEncoder().encode(str));
522
553
  }
523
554
 
524
- /* btoa to work with node or browser - create B64 string*/
555
+ /* btoa to work with node or browser - create B64 string */
525
556
  #btoa(str) {
526
557
  if (this.isNode) {
527
558
  return Buffer.from(str, 'binary').toString('base64');
528
- } else {
529
- return window.btoa(str);
530
559
  }
560
+ return window.btoa(str);
531
561
  }
532
562
 
533
563
  /* atoa to work with node or browser - convert B64 to binary */
534
564
  #atob(str) {
535
565
  if (this.isNode) {
536
566
  return Buffer.from(str, 'base64').toString('binary');
537
- } else {
538
- return window.atob(str);
539
567
  }
568
+ return window.atob(str);
540
569
  }
541
570
 
542
571
  // Base64 encode
543
- /* eslint-disable-next-line class-methods-use-this */
544
572
  #encode64(buff) {
545
573
  return this.#btoa(new Uint8Array(buff).reduce((s, b) => s + String.fromCharCode(b), ''));
546
574
  }
@@ -555,7 +583,7 @@ class PegaAuth {
555
583
  /* Calc code verifier if necessary
556
584
  */
557
585
  /* eslint-disable camelcase */
558
- #getCodeChallenge(code_verifier) {
586
+ async #getCodeChallenge(code_verifier) {
559
587
  return this.#sha256Hash(code_verifier)
560
588
  .then((hashed) => {
561
589
  return this.#base64UrlSafeEncode(hashed);
@@ -568,6 +596,13 @@ class PegaAuth {
568
596
  });
569
597
  }
570
598
  /* eslint-enable camelcase */
599
+
600
+ /*
601
+ * Return agent value for POST commands
602
+ */
603
+ #getAgent() {
604
+ return this.isNode && this.config.ignoreInvalidCerts ? new this.https.Agent({ rejectUnauthorized: false }) : undefined;
605
+ }
571
606
  }
572
607
 
573
608
  export default PegaAuth;
@@ -14,7 +14,6 @@ import handleEvent from "./event-utils";
14
14
  import { suggestionsHandler } from './suggestions-handler';
15
15
 
16
16
  import Styled{{COMPONENT_CLASS_NAME}}Wrapper from './styles';
17
- import { } from "@pega/cosmos-react-core";
18
17
 
19
18
  export const formatExists = (formatterVal) => {
20
19
  const formatterValues = [
@@ -14,6 +14,7 @@ const renderField = resolvedProps => {
14
14
  displayMode,
15
15
  value = '',
16
16
  label = '',
17
+ key,
17
18
  // eslint-disable-next-line react-hooks/rules-of-hooks
18
19
  theme = useTheme()
19
20
  } = resolvedProps;
@@ -22,7 +23,7 @@ const renderField = resolvedProps => {
22
23
 
23
24
  let val =
24
25
  value !== '' ? (
25
- <Text variant='h1' as='span'>
26
+ <Text variant='h1' as='span' key={key}>
26
27
  {value}
27
28
  </Text>
28
29
  ) : (
@@ -30,13 +31,22 @@ const renderField = resolvedProps => {
30
31
  );
31
32
 
32
33
  if (label === 'Create date/time')
33
- val = <DateTimeDisplay value={value} variant='datetime' format='long' clockFormat={null} />;
34
+ val = (
35
+ <DateTimeDisplay
36
+ value={value}
37
+ variant='datetime'
38
+ format='long'
39
+ clockFormat={null}
40
+ key={key}
41
+ />
42
+ );
34
43
 
35
- if (displayAsStatus === true) val = <StatusWorkRenderer value={value} />;
44
+ if (displayAsStatus === true) val = <StatusWorkRenderer value={value} key={key} />;
36
45
 
37
46
  if (label === 'Create Operator')
38
47
  val = (
39
48
  <Button
49
+ key={key}
40
50
  variant='link'
41
51
  style={
42
52
  label !== null
@@ -49,15 +59,19 @@ const renderField = resolvedProps => {
49
59
  );
50
60
 
51
61
  if (variant === 'inline') {
52
- val = value || <span aria-hidden='true'>&ndash;&ndash;</span>;
62
+ val = value || (
63
+ <span aria-hidden='true' key={key}>
64
+ &ndash;&ndash;
65
+ </span>
66
+ );
53
67
  } else {
54
68
  val = (
55
- <Text variant='h1' as='span'>
69
+ <Text variant='h1' as='span' key={key}>
56
70
  {val}
57
71
  </Text>
58
72
  );
59
73
  }
60
- return <FieldValueList variant={variant} fields={[{ name: label, value: val }]} />;
74
+ return <FieldValueList variant={variant} fields={[{ name: label, value: val }]} key={key} />;
61
75
  };
62
76
 
63
77
  export const base{{COMPONENT_CLASS_NAME}} = () => {