@pega/custom-dx-components 2.0.23 → 2.0.24
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.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pega/custom-dx-components",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.24",
|
|
4
4
|
"description": "Utility for building custom UI components",
|
|
5
5
|
"bin": "./bin/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -31,7 +31,6 @@
|
|
|
31
31
|
"file-loader": "6.2.0",
|
|
32
32
|
"fs-extra": "^10.1.0",
|
|
33
33
|
"gitignore": "^0.7.0",
|
|
34
|
-
"http": "^0.0.1-security",
|
|
35
34
|
"inquirer": "^9.1.1",
|
|
36
35
|
"listr": "^0.14.3",
|
|
37
36
|
"mini-css-extract-plugin": "2.6.1",
|
package/src/auth.js
CHANGED
|
@@ -3,8 +3,10 @@
|
|
|
3
3
|
|
|
4
4
|
import fetch from 'node-fetch';
|
|
5
5
|
import open from 'open';
|
|
6
|
-
import crypto from 'crypto';
|
|
7
|
-
import
|
|
6
|
+
import crypto from 'node:crypto';
|
|
7
|
+
import https from 'node:https';
|
|
8
|
+
import http from 'node:http';
|
|
9
|
+
import fs from 'node:fs';
|
|
8
10
|
|
|
9
11
|
|
|
10
12
|
class PegaAuth {
|
|
@@ -277,12 +279,17 @@ class PegaAuth {
|
|
|
277
279
|
} else {
|
|
278
280
|
if (this.isNode) {
|
|
279
281
|
// Determine port to listen to by extracting it from redirect uri
|
|
280
|
-
const { redirectUri } = this.config;
|
|
282
|
+
const { redirectUri, cert, key } = this.config;
|
|
283
|
+
const isHttp = redirectUri.startsWith('http:');
|
|
281
284
|
const nLocalhost = redirectUri.indexOf("localhost:");
|
|
282
285
|
const nSlash = redirectUri.indexOf('/', nLocalhost + 10);
|
|
283
286
|
const nPort = parseInt(redirectUri.substring(nLocalhost + 10, nSlash));
|
|
284
287
|
if (-1 !== nLocalhost) {
|
|
285
|
-
const
|
|
288
|
+
const options = isHttp ? {} : {
|
|
289
|
+
key: fs.readFileSync(key),
|
|
290
|
+
cert: fs.readFileSync(cert)
|
|
291
|
+
};
|
|
292
|
+
const server = (isHttp ? http : https).createServer(options, (req, res) => {
|
|
286
293
|
const { method, url } = req;
|
|
287
294
|
const { winTitle, winBodyHtml } = this.config;
|
|
288
295
|
// console.log(`HTTP request received: ${url}`);
|
|
@@ -331,7 +338,7 @@ class PegaAuth {
|
|
|
331
338
|
this.#reloadConfig();
|
|
332
339
|
|
|
333
340
|
const { serverType, isolationId, clientId, clientSecret, redirectUri, tokenUri, codeVerifier, grantType,
|
|
334
|
-
sessionIndex, customTokenParams, userIdentifier, password, noPKCE } = this.config;
|
|
341
|
+
sessionIndex, customTokenParams, userIdentifier, password, noPKCE, ignoreInvalidCerts } = this.config;
|
|
335
342
|
|
|
336
343
|
const bAuthCode = !grantType || grantType === 'authCode';
|
|
337
344
|
if (bAuthCode && !authCode && !this.isNode) {
|
|
@@ -378,6 +385,7 @@ class PegaAuth {
|
|
|
378
385
|
// console.log(`getToken form data: ${formData.toString()}`);
|
|
379
386
|
|
|
380
387
|
return fetch(tokenUri, {
|
|
388
|
+
agent: this.isNode && ignoreInvalidCerts ? new https.Agent({ rejectUnauthorized: false }) : undefined,
|
|
381
389
|
method: 'POST',
|
|
382
390
|
headers: new Headers({
|
|
383
391
|
'content-type': 'application/x-www-form-urlencoded'
|
|
@@ -418,7 +426,7 @@ class PegaAuth {
|
|
|
418
426
|
|
|
419
427
|
/* eslint-disable camelcase */
|
|
420
428
|
async refreshToken(refresh_token) {
|
|
421
|
-
const { clientId, clientSecret, tokenUri } = this.config;
|
|
429
|
+
const { clientId, clientSecret, tokenUri, ignoreInvalidCerts } = this.config;
|
|
422
430
|
|
|
423
431
|
const formData = new URLSearchParams();
|
|
424
432
|
formData.append('client_id', clientId);
|
|
@@ -429,6 +437,7 @@ class PegaAuth {
|
|
|
429
437
|
formData.append('refresh_token', refresh_token);
|
|
430
438
|
|
|
431
439
|
return fetch(tokenUri, {
|
|
440
|
+
agent: this.isNode && ignoreInvalidCerts ? new https.Agent({ rejectUnauthorized: false }) : undefined,
|
|
432
441
|
method: 'POST',
|
|
433
442
|
headers: new Headers({
|
|
434
443
|
'content-type': 'application/x-www-form-urlencoded'
|
|
@@ -460,7 +469,7 @@ class PegaAuth {
|
|
|
460
469
|
// Must have a config structure to proceed
|
|
461
470
|
return;
|
|
462
471
|
}
|
|
463
|
-
const { clientId, clientSecret, revokeUri } = this.config;
|
|
472
|
+
const { clientId, clientSecret, revokeUri, ignoreInvalidCerts } = this.config;
|
|
464
473
|
|
|
465
474
|
let hdrs = { 'content-type': 'application/x-www-form-urlencoded' };
|
|
466
475
|
if (clientSecret) {
|
|
@@ -478,6 +487,7 @@ class PegaAuth {
|
|
|
478
487
|
formData.append('token', prop === 'access_token' ? access_token : refresh_token);
|
|
479
488
|
formData.append('token_type_hint', prop);
|
|
480
489
|
fetch(revokeUri, {
|
|
490
|
+
agent: this.isNode && ignoreInvalidCerts ? new https.Agent({ rejectUnauthorized: false }) : undefined,
|
|
481
491
|
method: 'POST',
|
|
482
492
|
headers: new Headers(hdrs),
|
|
483
493
|
body: formData.toString()
|
|
@@ -3,8 +3,29 @@ import { getPegaServerConfig } from '../../util.js';
|
|
|
3
3
|
|
|
4
4
|
import { AUTHENTICATE_SCHEMA } from '../../constants.js';
|
|
5
5
|
|
|
6
|
-
export const getAuthQuestions = async () => {
|
|
7
|
-
const defaultPegaConfig =
|
|
6
|
+
export const getAuthQuestions = async (dxcbConfig) => {
|
|
7
|
+
const defaultPegaConfig = dxcbConfig;
|
|
8
|
+
const aMustAsk = dxcbConfig['questions_askAlways'] ? dxcbConfig['questions_askAlways'].split(',') : [];
|
|
9
|
+
const aNeverAsk = dxcbConfig['questions_askNever'] ? dxcbConfig['questions_askNever'].split(',') : [];
|
|
10
|
+
|
|
11
|
+
const initAnswers = (answers) => {
|
|
12
|
+
// Setup default answers (if they are present and non-empty)
|
|
13
|
+
answers.serverType = defaultPegaConfig.serverType || "infinity";
|
|
14
|
+
answers.server = defaultPegaConfig.server || undefined;
|
|
15
|
+
answers.isolationId = defaultPegaConfig.isolationId || undefined;
|
|
16
|
+
answers.clientId = defaultPegaConfig.clientId || undefined;
|
|
17
|
+
answers.grantType = defaultPegaConfig.grantType || "authCode";
|
|
18
|
+
answers.clientSecret = defaultPegaConfig.clientSecret || undefined;
|
|
19
|
+
answers.user = defaultPegaConfig.user || undefined;
|
|
20
|
+
answers.password = defaultPegaConfig.password || undefined;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const fnStandardWhen = (prop, answers) => {
|
|
24
|
+
if (aNeverAsk.includes(prop)) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
return aMustAsk.includes(prop) || !answers[prop];
|
|
28
|
+
};
|
|
8
29
|
|
|
9
30
|
return [
|
|
10
31
|
{
|
|
@@ -22,26 +43,24 @@ export const getAuthQuestions = async () => {
|
|
|
22
43
|
return 'Pega server type cannot be empty';
|
|
23
44
|
},
|
|
24
45
|
when: answers => {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
else if (!defaultPegaConfig.askServerType) {
|
|
29
|
-
answers.serverType = defaultPegaConfig.serverType;
|
|
30
|
-
}
|
|
31
|
-
return (defaultPegaConfig.askServerType ? true : false);
|
|
46
|
+
initAnswers(answers);
|
|
47
|
+
return fnStandardWhen('serverType', answers);
|
|
32
48
|
}
|
|
33
49
|
},
|
|
34
50
|
{
|
|
35
51
|
name: 'server',
|
|
36
52
|
message: 'Enter pega server url',
|
|
37
|
-
default: defaultPegaConfig.server
|
|
53
|
+
default: defaultPegaConfig.server,
|
|
54
|
+
when: answers => {
|
|
55
|
+
return fnStandardWhen('server', answers);
|
|
56
|
+
}
|
|
38
57
|
},
|
|
39
58
|
{
|
|
40
59
|
name: 'isolationId',
|
|
41
60
|
message: 'Enter isolation id',
|
|
42
61
|
default: defaultPegaConfig.isolationId,
|
|
43
62
|
when: answers => {
|
|
44
|
-
return answers.serverType === "launchpad";
|
|
63
|
+
return answers.serverType === "launchpad" && fnStandardWhen('isolationId', answers);
|
|
45
64
|
}
|
|
46
65
|
},
|
|
47
66
|
{
|
|
@@ -57,6 +76,9 @@ export const getAuthQuestions = async () => {
|
|
|
57
76
|
return true;
|
|
58
77
|
}
|
|
59
78
|
return 'Grant type cannot be empty';
|
|
79
|
+
},
|
|
80
|
+
when: answers => {
|
|
81
|
+
return fnStandardWhen('grantType', answers);
|
|
60
82
|
}
|
|
61
83
|
},
|
|
62
84
|
{
|
|
@@ -70,7 +92,7 @@ export const getAuthQuestions = async () => {
|
|
|
70
92
|
return 'Username cannot be empty';
|
|
71
93
|
},
|
|
72
94
|
when: answers => {
|
|
73
|
-
return (answers.serverType === "infinity" && answers.grantType
|
|
95
|
+
return (answers.serverType === "infinity" && answers.grantType === "passwordCreds") && fnStandardWhen('user', answers);
|
|
74
96
|
}
|
|
75
97
|
},
|
|
76
98
|
{
|
|
@@ -85,7 +107,7 @@ export const getAuthQuestions = async () => {
|
|
|
85
107
|
return 'Password cannot be empty';
|
|
86
108
|
},
|
|
87
109
|
when: answers => {
|
|
88
|
-
return (answers.user && (answers.serverType === "infinity" && answers.grantType
|
|
110
|
+
return (answers.user && (answers.serverType === "infinity" && answers.grantType === "passwordCreds") && fnStandardWhen('password', answers));
|
|
89
111
|
}
|
|
90
112
|
},
|
|
91
113
|
{
|
|
@@ -97,6 +119,9 @@ export const getAuthQuestions = async () => {
|
|
|
97
119
|
return true;
|
|
98
120
|
}
|
|
99
121
|
return 'clientId cannot be empty';
|
|
122
|
+
},
|
|
123
|
+
when: answers => {
|
|
124
|
+
return fnStandardWhen('clientId', answers);
|
|
100
125
|
}
|
|
101
126
|
},
|
|
102
127
|
{
|
|
@@ -111,7 +136,7 @@ export const getAuthQuestions = async () => {
|
|
|
111
136
|
return 'clientSecret cannot be empty';
|
|
112
137
|
},
|
|
113
138
|
when: answers => {
|
|
114
|
-
return (answers.grantType !== "authCode");
|
|
139
|
+
return (answers.grantType !== "authCode" && fnStandardWhen('clientSecret', answers));
|
|
115
140
|
}
|
|
116
141
|
}
|
|
117
142
|
];
|
|
@@ -26,16 +26,24 @@ const generateAccessToken = async config => {
|
|
|
26
26
|
const sAuthorizeUri = `${server}${serverType === 'infinity' ? INF_AUTHORIZE_URL_V1 : LP_AUTHORIZE_URL}`;
|
|
27
27
|
// console.log(`grantType: ${config.grantType}`);
|
|
28
28
|
|
|
29
|
+
const authCodeConfig = grantType === 'authCode' ? {
|
|
30
|
+
authorizeUri: sAuthorizeUri,
|
|
31
|
+
redirectUri: config.redirectUri.endsWith('/') ? config.redirectUri : `${config.redirectUri}/`,
|
|
32
|
+
cert: config.cert,
|
|
33
|
+
key: config.key,
|
|
34
|
+
winTitle: 'DX Component Dev',
|
|
35
|
+
winBodyHtml: `Authentication is complete. This browser window may be closed.`
|
|
36
|
+
} : {};
|
|
37
|
+
|
|
29
38
|
// Build auth config structure
|
|
30
39
|
const authConfig = {
|
|
31
40
|
serverType: serverType,
|
|
32
41
|
grantType: grantType,
|
|
33
|
-
authorizeUri: sAuthorizeUri,
|
|
34
42
|
tokenUri: sTokenUri,
|
|
35
43
|
clientId: clientId,
|
|
36
44
|
clientSecret: clientSecret,
|
|
37
|
-
|
|
38
|
-
|
|
45
|
+
ignoreInvalidCerts: true,
|
|
46
|
+
...authCodeConfig
|
|
39
47
|
};
|
|
40
48
|
if (serverType === 'infinity') {
|
|
41
49
|
authConfig.authService = 'pega';
|
|
@@ -48,11 +56,8 @@ const generateAccessToken = async config => {
|
|
|
48
56
|
authConfig.isolationId = isolationId;
|
|
49
57
|
// authConfig.noPKCE = true;
|
|
50
58
|
}
|
|
51
|
-
if (grantType === 'authCode') {
|
|
52
|
-
authConfig.redirectUri = 'http://localhost:4010/';
|
|
53
|
-
}
|
|
54
59
|
const auth = new PegaAuth(authConfig);
|
|
55
|
-
// console.log(`...about to
|
|
60
|
+
// console.log(`...about to invoke auth.login\n${JSON.stringify(authConfig)}`);
|
|
56
61
|
|
|
57
62
|
auth.login()
|
|
58
63
|
.then((token) => {
|
|
@@ -98,30 +103,37 @@ export default async options => {
|
|
|
98
103
|
}
|
|
99
104
|
|
|
100
105
|
const serverConfig = data['server-config'];
|
|
101
|
-
const
|
|
106
|
+
const isPwdNonEmpty = serverConfig['password'] ? true : false;
|
|
102
107
|
|
|
103
|
-
|
|
108
|
+
// console.log(`serverConfig: ${JSON.stringify(serverConfig)}`);
|
|
109
|
+
const questions = await getAuthQuestions(serverConfig);
|
|
110
|
+
// console.log(`questions: ${JSON.stringify(questions)}`);
|
|
104
111
|
const answers = await inquirer.prompt(questions);
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
112
|
+
const aProps = ['serverType', 'server', 'isolationId', 'clientId', 'grantType', 'clientSecret', 'user', 'password'];
|
|
113
|
+
const isLaunchPad = answers.serverType === "launchpad";
|
|
114
|
+
let bWriteUpdate = false;
|
|
115
|
+
for (let i = 0; i < aProps.length; i += 1) {
|
|
116
|
+
const prop = aProps[i];
|
|
117
|
+
if (serverConfig[prop] !== answers[prop]) {
|
|
118
|
+
// console.log(`property ${prop} changed from ${serverConfig[prop]} to ${answers[prop]}`);
|
|
119
|
+
serverConfig[prop] = answers[prop];
|
|
120
|
+
if (prop !== 'password' || isPwdNonEmpty) {
|
|
121
|
+
bWriteUpdate = true;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
115
124
|
}
|
|
116
|
-
serverConfig.clientId = answers.clientId;
|
|
117
|
-
serverConfig.clientSecret = answers.clientSecret;
|
|
118
125
|
|
|
119
126
|
try {
|
|
127
|
+
// console.log(`serverConfig: ${JSON.stringify(serverConfig)}`);
|
|
120
128
|
authOK = await generateAccessToken(serverConfig);
|
|
121
129
|
} catch (e) {
|
|
122
130
|
}
|
|
123
131
|
|
|
124
|
-
if (authOK) {
|
|
132
|
+
if (authOK & bWriteUpdate) {
|
|
133
|
+
// Don't write password value (unless it already had a value)
|
|
134
|
+
if (!isPwdNonEmpty) {
|
|
135
|
+
serverConfig['password'] = '';
|
|
136
|
+
}
|
|
125
137
|
console.log(`${chalk.green('Writing updated config...')}`);
|
|
126
138
|
let updCfg = null;
|
|
127
139
|
try {
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
56
|
"@pega/configs": "^0.3.4",
|
|
57
|
-
"@pega/custom-dx-components": "^2.0.
|
|
57
|
+
"@pega/custom-dx-components": "^2.0.24",
|
|
58
58
|
"@pega/eslint-config": "^0.3.2",
|
|
59
59
|
"@storybook/addon-actions": "^6.5.12",
|
|
60
60
|
"@storybook/addon-essentials": "^6.5.12",
|
|
@@ -1,17 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"components-directory-path": "src/components",
|
|
3
3
|
"server-config": {
|
|
4
|
-
"serverType": "infinity",
|
|
5
|
-
"server": "https://localhost:38764/prweb",
|
|
6
|
-
"grantType": "authCode",
|
|
7
|
-
"user": "",
|
|
8
|
-
"password": "",
|
|
9
4
|
"rulesetName": "rulesetName",
|
|
10
5
|
"rulesetVersion": "rulesetVersion",
|
|
11
6
|
"sourceOfComponents": "Server",
|
|
12
7
|
"devBuild": false,
|
|
8
|
+
"serverType": "infinity",
|
|
9
|
+
"server": "https://localhost:38764/prweb",
|
|
13
10
|
"clientId": "",
|
|
14
|
-
"
|
|
11
|
+
"clientSecret_comment": "Needed only when using 'passwordCreds' or 'clientCreds' grantType",
|
|
12
|
+
"clientSecret": "",
|
|
13
|
+
"grantType": "authCode",
|
|
14
|
+
"redirectUri": "https://localhost:4010/",
|
|
15
|
+
"cert_and_key_comment": "Path to SSL certificate file and SSL key file to use when starting local HTTPS server",
|
|
16
|
+
"cert_and_key_comment2": "Needed only when using 'authCode' grantType and redirectUri begins with 'https://localhost'",
|
|
17
|
+
"cert": "",
|
|
18
|
+
"key": "",
|
|
19
|
+
"user_and_password_comment": "useful primarily when grantType is set to 'passwordCreds'",
|
|
20
|
+
"user": "",
|
|
21
|
+
"password": "",
|
|
22
|
+
"questions_askAlways": "",
|
|
23
|
+
"questions_askNever": ""
|
|
15
24
|
},
|
|
16
25
|
"component": {
|
|
17
26
|
"library": "",
|