@pega/react-sdk-components 8.23.11-debug → 8.23.11-debug3

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.
@@ -3,225 +3,66 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
3
3
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
4
4
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
5
5
  };
6
- var _PegaAuth_instances, _PegaAuth_updateConfig, _PegaAuth_buildAuthorizeUrl, _PegaAuth_sha256Hash, _PegaAuth_encode64, _PegaAuth_base64UrlSafeEncode, _PegaAuth_getCodeChallenge;
7
- class PegaAuth {
8
- constructor(ssKeyConfig) {
6
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
7
+ if (kind === "m") throw new TypeError("Private method is not writable");
8
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
9
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
10
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
11
+ };
12
+ var _PegaAuth_instances, _PegaAuth_config, _PegaAuth_dynState, _PegaAuth_reloadSS, _PegaAuth_reloadConfig, _PegaAuth_updateConfig, _PegaAuth_importSingleLib, _PegaAuth_importNodeLibs, _PegaAuth_buildAuthorizeUrl, _PegaAuth_authCodeStart, _PegaAuth_updateSessionIndex, _PegaAuth_sha256Hash, _PegaAuth_encode64, _PegaAuth_base64UrlSafeEncode, _PegaAuth_getRandomString, _PegaAuth_getCodeChallenge, _PegaAuth_getAgent;
13
+ /* eslint-disable no-undef */
14
+ export class PegaAuth {
15
+ // Current properties within dynState structure:
16
+ // codeVerifier, state, sessionIndex, sessionIndexAttempts, acRedirectUri, silentAuthFailed
17
+ constructor(ssKeyConfig, ssKeyDynState = '') {
9
18
  _PegaAuth_instances.add(this);
10
- this.ssKeyConfig = ssKeyConfig;
11
- this.bEncodeSI = false;
12
- this.reloadConfig();
13
- }
14
- reloadConfig() {
15
- const peConfig = window.sessionStorage.getItem(this.ssKeyConfig);
16
- let obj = {};
17
- if (peConfig) {
18
- try {
19
- obj = JSON.parse(peConfig);
20
- }
21
- catch (e) {
22
- try {
23
- obj = JSON.parse(window.atob(peConfig));
24
- }
25
- catch (e2) {
26
- obj = {};
27
- }
19
+ // The properties within config structure are expected to be more static config values that are then
20
+ // used to properly make various OAuth endpoint calls.
21
+ _PegaAuth_config.set(this, null);
22
+ // Any dynamic state is stored separately in its own structure. If a sessionStorage key is passed in
23
+ // without a Dynamic State key.
24
+ _PegaAuth_dynState.set(this, {});
25
+ if (typeof ssKeyConfig === 'string') {
26
+ this.ssKeyConfig = ssKeyConfig;
27
+ this.ssKeyDynState = ssKeyDynState || `${ssKeyConfig}_DS`;
28
+ __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_reloadConfig).call(this);
29
+ }
30
+ else {
31
+ // object with config structure is passed in
32
+ __classPrivateFieldSet(this, _PegaAuth_config, ssKeyConfig, "f");
33
+ __classPrivateFieldSet(this, _PegaAuth_dynState, ssKeyDynState || {}, "f");
34
+ }
35
+ this.urlencoded = 'application/x-www-form-urlencoded';
36
+ this.tokenError = 'Token endpoint error';
37
+ this.isNode = typeof window === 'undefined';
38
+ // For isNode path the below attributes are initialized on first method invocation
39
+ if (!this.isNode) {
40
+ this.crypto = window.crypto;
41
+ this.subtle = window.crypto.subtle;
42
+ }
43
+ if (Object.keys(__classPrivateFieldGet(this, _PegaAuth_config, "f")).length > 0) {
44
+ if (!__classPrivateFieldGet(this, _PegaAuth_config, "f").serverType) {
45
+ __classPrivateFieldGet(this, _PegaAuth_config, "f").serverType = 'infinity';
28
46
  }
29
47
  }
30
- this.config = peConfig ? obj : null;
48
+ else {
49
+ throw new Error('invalid config settings');
50
+ }
31
51
  }
32
52
  async login() {
33
- const fnGetRedirectUriOrigin = () => {
34
- const redirectUri = this.config.redirectUri;
35
- const nRootOffset = redirectUri.indexOf("//");
36
- const nFirstPathOffset = nRootOffset !== -1 ? redirectUri.indexOf("/", nRootOffset + 2) : -1;
37
- return nFirstPathOffset !== -1 ? redirectUri.substring(0, nFirstPathOffset) : redirectUri;
38
- };
39
- const redirectOrigin = fnGetRedirectUriOrigin();
40
- // eslint-disable-next-line no-restricted-globals
41
- const state = window.btoa(location.origin);
42
- return new Promise((resolve, reject) => {
43
- __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_buildAuthorizeUrl).call(this, state).then((url) => {
44
- let myWindow = null; // popup or iframe
45
- let elIframe = null;
46
- let elCloseBtn = null;
47
- const iframeTimeout = this.config.silentTimeout !== undefined ? this.config.silentTimeout : 5000;
48
- let bWinIframe = iframeTimeout > 0 && ((!!this.config.userIdentifier && !!this.config.password) || this.config.iframeLoginUI || this.config.authService !== "pega");
49
- let tmrAuthComplete = null;
50
- let checkWindowClosed = null;
51
- const myWinOnLoad = () => {
52
- try {
53
- if (bWinIframe) {
54
- elIframe.contentWindow.postMessage({ type: "PegaAuth" }, redirectOrigin);
55
- // eslint-disable-next-line no-console
56
- console.log("authjs(login): loaded a page in iFrame");
57
- }
58
- else {
59
- myWindow.postMessage({ type: "PegaAuth" }, redirectOrigin);
60
- }
61
- }
62
- catch (e) {
63
- // eslint-disable-next-line no-console
64
- console.log("authjs(login): Exception trying to postMessage on load");
65
- }
66
- };
67
- const fnOpenPopup = () => {
68
- myWindow = window.open(url, '_blank', 'width=700,height=500,left=200,top=100');
69
- if (!myWindow) {
70
- // Blocked by popup-blocker
71
- // eslint-disable-next-line prefer-promise-reject-errors
72
- return reject("blocked");
73
- }
74
- checkWindowClosed = setInterval(() => {
75
- if (myWindow.closed) {
76
- clearInterval(checkWindowClosed);
77
- // eslint-disable-next-line prefer-promise-reject-errors
78
- reject("closed");
79
- }
80
- }, 500);
81
- try {
82
- myWindow.addEventListener("load", myWinOnLoad, true);
83
- }
84
- catch (e) {
85
- // eslint-disable-next-line no-console
86
- console.log("authjs(login): Exception trying to add onload handler to opened window;");
87
- }
88
- };
89
- const fnCloseIframe = () => {
90
- elIframe.parentNode.removeChild(elIframe);
91
- elCloseBtn.parentNode.removeChild(elCloseBtn);
92
- // eslint-disable-next-line no-multi-assign
93
- elIframe = elCloseBtn = null;
94
- bWinIframe = false;
95
- };
96
- const fnCloseAndReject = () => {
97
- fnCloseIframe();
98
- // eslint-disable-next-line prefer-promise-reject-errors
99
- reject("closed");
100
- };
101
- // If there is a userIdentifier and password specified or an external SSO auth service,
102
- // we can try to use this silently in an iFrame first
103
- if (bWinIframe) {
104
- const nFrameZLevel = 99999;
105
- elIframe = document.createElement('iframe');
106
- // eslint-disable-next-line prefer-template
107
- elIframe.id = 'pe' + this.config.clientId;
108
- const loginBoxWidth = 500;
109
- const loginBoxHeight = 700;
110
- const oStyle = elIframe.style;
111
- oStyle.position = 'absolute';
112
- oStyle.display = 'none';
113
- oStyle.zIndex = nFrameZLevel;
114
- oStyle.top = `${Math.round(Math.max(window.innerHeight - loginBoxHeight, 0) / 2)}px`;
115
- oStyle.left = `${Math.round(Math.max(window.innerWidth - loginBoxWidth, 0) / 2)}px`;
116
- oStyle.width = '500px';
117
- oStyle.height = '700px';
118
- // Add Iframe to top of document DOM to have it load
119
- document.body.insertBefore(elIframe, document.body.firstChild);
120
- // Add Iframe to DOM to have it load
121
- document.getElementsByTagName('body')[0].appendChild(elIframe);
122
- elIframe.addEventListener("load", myWinOnLoad, true);
123
- // Disallow iframe content attempts to navigate main window
124
- elIframe.setAttribute("sandbox", "allow-scripts allow-forms allow-same-origin");
125
- elIframe.setAttribute('src', url);
126
- const svgCloseBtn = `<?xml version="1.0" encoding="UTF-8"?>
127
- <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">
128
- <title>Dismiss - Black</title>
129
- <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
130
- <g transform="translate(1.000000, 1.000000)">
131
- <circle fill="#252C32" cx="16" cy="16" r="16"></circle>
132
- <g transform="translate(9.109375, 9.214844)" fill="#FFFFFF" fill-rule="nonzero">
133
- <path d="M12.7265625,0 L0,12.6210938 L1.0546875,13.5703125 L13.78125,1.0546875 L12.7265625,0 Z M13.7460938,12.5507812 L1.01953125,0 L0,1.01953125 L12.7617188,13.6054688 L13.7460938,12.5507812 Z"></path>
134
- </g>
135
- </g>
136
- </g>
137
- </svg>`;
138
- const bCloseWithinFrame = false;
139
- elCloseBtn = document.createElement('img');
140
- elCloseBtn.onclick = fnCloseAndReject;
141
- // eslint-disable-next-line prefer-template
142
- elCloseBtn.src = 'data:image/svg+xml;base64,' + window.btoa(svgCloseBtn);
143
- const oBtnStyle = elCloseBtn.style;
144
- oBtnStyle.cursor = 'pointer';
145
- // If svg doesn't set width and height might want to set oBtStyle width and height to something like '2em'
146
- oBtnStyle.position = 'absolute';
147
- oBtnStyle.display = 'none';
148
- oBtnStyle.zIndex = nFrameZLevel + 1;
149
- const nTopOffset = bCloseWithinFrame ? 5 : -10;
150
- const nRightOffset = bCloseWithinFrame ? -34 : -20;
151
- oBtnStyle.top = `${Math.round(Math.max(window.innerHeight - loginBoxHeight, 0) / 2) + nTopOffset}px`;
152
- oBtnStyle.left = `${Math.round(Math.max(window.innerWidth - loginBoxWidth, 0) / 2) + loginBoxWidth + nRightOffset}px`;
153
- document.body.insertBefore(elCloseBtn, document.body.firstChild);
154
- // If the password was wrong, then the login screen will be in the iframe
155
- // ..and with Pega without realization of US-372314 it may replace the top (main portal) window
156
- // For now set a timer and if the timer expires, remove the iFrame and use same url within
157
- // visible window
158
- tmrAuthComplete = setTimeout(() => {
159
- clearTimeout(tmrAuthComplete);
160
- // remove password from config
161
- if (this.config.password) {
162
- delete this.config.password;
163
- __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_updateConfig).call(this);
164
- }
165
- if (this.config.iframeLoginUI) {
166
- elIframe.style.display = "block";
167
- elCloseBtn.style.display = "block";
168
- }
169
- else {
170
- fnCloseIframe();
171
- fnOpenPopup();
172
- }
173
- }, iframeTimeout);
174
- }
175
- else {
176
- fnOpenPopup();
177
- }
178
- let authMessageReceiver = null;
179
- /* Retrieve token(s) and close login window */
180
- const fnGetTokenAndFinish = (code) => {
181
- window.removeEventListener("message", authMessageReceiver, false);
182
- this.getToken(code).then(token => {
183
- if (bWinIframe) {
184
- clearTimeout(tmrAuthComplete);
185
- fnCloseIframe();
186
- }
187
- else {
188
- clearInterval(checkWindowClosed);
189
- try {
190
- myWindow.close();
191
- }
192
- catch (e) {
193
- // eslint-disable-next-line no-console
194
- console.warn(`attempt to close opened window failed`);
195
- }
196
- }
197
- resolve(token);
198
- })
199
- .catch(e => {
200
- reject(e);
201
- });
202
- };
203
- /* Handler to receive the auth code */
204
- authMessageReceiver = (event) => {
205
- // Check origin to make sure it is the redirect origin
206
- if (event.origin !== redirectOrigin) {
207
- // eslint-disable-next-line no-console
208
- console.info(`Received event from unexpected origin: ${event.origin} (was expecting: ${redirectOrigin})`);
209
- }
210
- if (!event.data || !event.data.type || event.data.type !== "PegaAuth")
211
- return;
212
- // eslint-disable-next-line no-console
213
- console.log("authjs(login): postMessage received with code");
214
- const code = event.data.code.toString();
215
- fnGetTokenAndFinish(code);
216
- };
217
- window.addEventListener("message", authMessageReceiver, false);
218
- window.authCodeCallback = (code) => {
219
- // eslint-disable-next-line no-console
220
- console.log("authjs(login): authCodeCallback used with code");
221
- fnGetTokenAndFinish(code);
222
- };
223
- });
224
- });
53
+ if (this.isNode && !this.crypto) {
54
+ // Deferring dynamic loading of node libraries til this first method to avoid doing this in constructor
55
+ await __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_importNodeLibs).call(this);
56
+ }
57
+ const { grantType, noPKCE } = __classPrivateFieldGet(this, _PegaAuth_config, "f");
58
+ if (grantType && grantType !== 'authCode') {
59
+ return this.getToken();
60
+ }
61
+ // Make sure browser in a secure context, else PKCE will fail
62
+ if (!this.isNode && !noPKCE && !window.isSecureContext) {
63
+ throw new Error(`Authorization code grant flow failed due to insecure browser context at ${window.location.origin}. Use localhost or https.`);
64
+ }
65
+ return __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_authCodeStart).call(this);
225
66
  }
226
67
  // Login redirect
227
68
  loginRedirect() {
@@ -232,71 +73,143 @@ class PegaAuth {
232
73
  location.href = url;
233
74
  });
234
75
  }
76
+ // check state
77
+ checkStateMatch(state) {
78
+ return state === __classPrivateFieldGet(this, _PegaAuth_dynState, "f").state;
79
+ }
235
80
  // For PKCE token endpoint includes code_verifier
236
81
  getToken(authCode) {
237
82
  // Reload config to pick up the previously stored codeVerifier
238
- this.reloadConfig();
239
- const { clientId, clientSecret, redirectUri, tokenUri, codeVerifier } = this.config;
240
- // eslint-disable-next-line no-restricted-globals
241
- const queryString = location.search;
242
- const urlParams = new URLSearchParams(queryString);
243
- const code = authCode || urlParams.get("code");
83
+ __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_reloadConfig).call(this);
84
+ const { serverType, isolationId, clientId, clientSecret, tokenUri, grantType, customTokenParams, userIdentifier, password, noPKCE, secureCookie } = __classPrivateFieldGet(this, _PegaAuth_config, "f");
85
+ const { sessionIndex, acRedirectUri, codeVerifier } = __classPrivateFieldGet(this, _PegaAuth_dynState, "f");
86
+ const bAuthCode = !grantType || grantType === 'authCode';
87
+ if (bAuthCode && !authCode && !this.isNode) {
88
+ const queryString = window.location.search;
89
+ const urlParams = new URLSearchParams(queryString);
90
+ authCode = urlParams.get('code');
91
+ }
244
92
  const formData = new URLSearchParams();
245
- formData.append("client_id", clientId);
93
+ formData.append('client_id', clientId);
246
94
  if (clientSecret) {
247
- formData.append("client_secret", clientSecret);
95
+ formData.append('client_secret', clientSecret);
96
+ }
97
+ if (secureCookie) {
98
+ formData.append('send_token_as_cookie', 'true');
99
+ }
100
+ const fullGTName = {
101
+ authCode: 'authorization_code',
102
+ clientCreds: 'client_credentials',
103
+ customBearer: 'custom-bearer',
104
+ passwordCreds: 'password'
105
+ }[grantType];
106
+ formData.append('grant_type', fullGTName || grantType || 'authorization_code');
107
+ if (serverType === 'launchpad' && grantType !== 'authCode' && isolationId) {
108
+ formData.append('isolation_ids', isolationId);
109
+ }
110
+ if (bAuthCode) {
111
+ formData.append('code', authCode);
112
+ formData.append('redirect_uri', acRedirectUri);
113
+ if (!noPKCE) {
114
+ formData.append('code_verifier', codeVerifier);
115
+ }
116
+ }
117
+ else if (sessionIndex) {
118
+ formData.append('session_index', sessionIndex);
119
+ }
120
+ if (grantType === 'customBearer' && customTokenParams) {
121
+ Object.keys(customTokenParams).forEach((param) => {
122
+ formData.append(param, customTokenParams[param]);
123
+ });
124
+ }
125
+ if (grantType !== 'authCode') {
126
+ formData.append('enable_psyncId', 'true');
127
+ }
128
+ if (grantType === 'passwordCreds') {
129
+ formData.append('username', userIdentifier);
130
+ formData.append('password', atob(password));
248
131
  }
249
- formData.append("grant_type", "authorization_code");
250
- formData.append("code", code);
251
- formData.append("redirect_uri", redirectUri);
252
- formData.append("code_verifier", codeVerifier);
253
132
  return fetch(tokenUri, {
254
- method: "POST",
133
+ agent: __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_getAgent).call(this),
134
+ method: 'POST',
255
135
  headers: new Headers({
256
- "content-type": "application/x-www-form-urlencoded",
136
+ 'content-type': this.urlencoded
257
137
  }),
258
- body: formData.toString(),
138
+ credentials: secureCookie ? 'include' : 'omit',
139
+ body: formData.toString()
259
140
  })
260
- .then((response) => response.json())
261
- .then(token => {
262
- // .expires_in contains the # of seconds before access token expires
263
- // add property to keep track of current time when the token expires
264
- token.eA = Date.now() + (token.expires_in * 1000);
265
- if (this.config.codeVerifier) {
266
- delete this.config.codeVerifier;
141
+ .then((response) => {
142
+ if (response.ok) {
143
+ return response.json();
267
144
  }
268
- // If there is a session_index then move this to the peConfig structure (as used on authorize)
269
- if (token.session_index) {
270
- this.config.sessionIndex = token.session_index;
145
+ throw Error(`${this.tokenError}.`, { cause: response.status });
146
+ })
147
+ .then((token) => {
148
+ if (token.errors || token.error) {
149
+ // eslint-disable-next-line no-console
150
+ console.error(`${this.tokenError}: ${JSON.stringify(token.errors || token.error)}`);
271
151
  }
272
- // If we got a token and have a session index, then reset the sessionIndexAttempts
273
- if (this.config.sessionIndex) {
274
- this.config.sessionIndexAttempts = 0;
152
+ else {
153
+ // .expires_in contains the # of seconds before access token expires
154
+ // add property to keep track of current time when the token expires
155
+ token.eA = Date.now() + token.expires_in * 1000;
156
+ // Clear authCode related config state: state, codeVerifier, acRedirectUri
157
+ if (__classPrivateFieldGet(this, _PegaAuth_dynState, "f").state) {
158
+ delete __classPrivateFieldGet(this, _PegaAuth_dynState, "f").state;
159
+ }
160
+ if (__classPrivateFieldGet(this, _PegaAuth_dynState, "f").codeVerifier) {
161
+ delete __classPrivateFieldGet(this, _PegaAuth_dynState, "f").codeVerifier;
162
+ }
163
+ if (__classPrivateFieldGet(this, _PegaAuth_dynState, "f").acRedirectUri) {
164
+ delete __classPrivateFieldGet(this, _PegaAuth_dynState, "f").acRedirectUri;
165
+ }
166
+ // If there is a session_index then move this to the peConfig structure (as used on authorize)
167
+ if (token.session_index) {
168
+ __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_updateSessionIndex).call(this, token.session_index);
169
+ // does an #updateConfig within #updateSessionIndex
170
+ }
171
+ else {
172
+ __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_updateConfig).call(this);
173
+ }
275
174
  }
276
- __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_updateConfig).call(this);
277
175
  return token;
278
176
  })
279
- .catch(e => {
177
+ .catch((e) => {
178
+ const msg = `${e}`;
280
179
  // eslint-disable-next-line no-console
281
- console.log(e);
180
+ console.error(msg.indexOf(this.tokenError) !== -1 ? msg : `${this.tokenError}: ${msg}`);
181
+ throw e;
282
182
  });
283
183
  }
284
- /* eslint-disable camelcase */
285
- async refreshToken(refresh_token) {
286
- const { clientId, clientSecret, tokenUri } = this.config;
184
+ async refreshToken(refreshToken) {
185
+ const { clientId, clientSecret, tokenUri, secureCookie } = __classPrivateFieldGet(this, _PegaAuth_config, "f");
186
+ if (this.isNode && !this.crypto) {
187
+ // Deferring dynamic loading of node libraries til this first method to avoid doing this in constructor
188
+ await __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_importNodeLibs).call(this);
189
+ }
190
+ if (!secureCookie && !refreshToken) {
191
+ return null;
192
+ }
287
193
  const formData = new URLSearchParams();
288
- formData.append("client_id", clientId);
194
+ formData.append('client_id', clientId);
289
195
  if (clientSecret) {
290
- formData.append("client_secret", clientSecret);
196
+ formData.append('client_secret', clientSecret);
197
+ }
198
+ formData.append('grant_type', 'refresh_token');
199
+ if (secureCookie) {
200
+ formData.append('send_token_as_cookie', 'true');
201
+ }
202
+ if (refreshToken) {
203
+ formData.append('refresh_token', refreshToken);
291
204
  }
292
- formData.append("grant_type", "refresh_token");
293
- formData.append("refresh_token", refresh_token);
294
205
  return fetch(tokenUri, {
295
- method: "POST",
206
+ agent: __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_getAgent).call(this),
207
+ method: 'POST',
296
208
  headers: new Headers({
297
- "content-type": "application/x-www-form-urlencoded",
209
+ 'content-type': this.urlencoded
298
210
  }),
299
- body: formData.toString(),
211
+ credentials: secureCookie ? 'include' : 'omit',
212
+ body: formData.toString()
300
213
  })
301
214
  .then((response) => {
302
215
  if (!response.ok && response.status === 401) {
@@ -304,142 +217,628 @@ class PegaAuth {
304
217
  }
305
218
  return response.json();
306
219
  })
307
- .then(token => {
220
+ .then((token) => {
308
221
  if (token) {
309
222
  // .expires_in contains the # of seconds before access token expires
310
223
  // add property to keep track of current time when the token expires
311
- token.eA = Date.now() + (token.expires_in * 1000);
224
+ token.eA = Date.now() + token.expires_in * 1000;
312
225
  }
313
226
  return token;
314
227
  })
315
- .catch(e => {
228
+ .catch((e) => {
316
229
  // eslint-disable-next-line no-console
317
- console.log(e);
230
+ console.warn(`Refresh token failed: ${e}`);
231
+ return null;
318
232
  });
319
233
  }
320
- async revokeTokens(access_token, refresh_token = null) {
321
- if (!this.config || !this.config.revokeUri) {
322
- // Must have a config structure and revokeUri to proceed
234
+ /**
235
+ * Revokes tokens (useful as part of a logout operation). For non-secureCookie, the accessToken and
236
+ * the optional refreshToken would be passed in and the routine will generate two separate revoke
237
+ * transactions. For secureCookie scenario, will issue just one for the accessToken, but this will
238
+ * also revoke the refresh token if present.
239
+ * @param {string} accessToken - the access token (or any string value for secureCookie scenario)
240
+ * @param {string} refreshToken - optional refresh token (or any string value for non secureCookie
241
+ * scenario, when a refreshToken exists)
242
+ * @returns
243
+ */
244
+ async revokeTokens(accessToken, refreshToken = null) {
245
+ if (Object.keys(__classPrivateFieldGet(this, _PegaAuth_config, "f")).length === 0) {
246
+ // Must have a config structure to proceed
323
247
  return;
324
248
  }
325
- const { clientId, clientSecret, revokeUri } = this.config;
326
- const hdrs = { "content-type": "application/x-www-form-urlencoded" };
249
+ const { clientId, clientSecret, revokeUri, secureCookie } = __classPrivateFieldGet(this, _PegaAuth_config, "f");
250
+ if (this.isNode && !this.crypto) {
251
+ // Deferring dynamic loading of node libraries til this first method to avoid doing this in constructor
252
+ await __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_importNodeLibs).call(this);
253
+ }
254
+ const headers = { 'content-type': this.urlencoded };
327
255
  if (clientSecret) {
328
- const creds = `${clientId}:${clientSecret}`;
329
- hdrs.authorization = `Basic ${window.btoa(creds)}`;
256
+ const basicCreds = btoa(`${clientId}:${clientSecret}`);
257
+ headers.authorization = `Basic ${basicCreds}`;
330
258
  }
331
- const aTknProps = ["access_token"];
332
- if (refresh_token) {
333
- aTknProps.push("refresh_token");
259
+ // A revoke of a refresh_token will also revoke any associated access_tokens, so only one
260
+ // transaction is necessary.
261
+ const prop = refreshToken ? 'refresh_token' : 'access_token';
262
+ const formData = new URLSearchParams();
263
+ if (!clientSecret) {
264
+ formData.append('client_id', clientId);
334
265
  }
335
- aTknProps.forEach((prop) => {
336
- const formData = new URLSearchParams();
337
- if (!clientSecret) {
338
- formData.append("client_id", clientId);
339
- }
340
- formData.append("token", prop === "access_token" ? access_token : refresh_token);
341
- formData.append("token_type_hint", prop);
342
- fetch(revokeUri, {
343
- method: "POST",
344
- headers: new Headers(hdrs),
345
- body: formData.toString(),
346
- })
347
- .then((response) => {
348
- if (!response.ok) {
349
- // eslint-disable-next-line no-console
350
- console.log(`Error revoking ${prop}:${response.status}`);
351
- }
352
- })
353
- .catch(e => {
266
+ if (secureCookie) {
267
+ formData.append('send_token_as_cookie', 'true');
268
+ }
269
+ const token = prop === 'access_token' ? accessToken : refreshToken;
270
+ if (!secureCookie && token) {
271
+ formData.append('token', token);
272
+ }
273
+ formData.append('token_type_hint', prop);
274
+ return fetch(revokeUri, {
275
+ agent: __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_getAgent).call(this),
276
+ method: 'POST',
277
+ headers: new Headers(headers),
278
+ credentials: secureCookie ? 'include' : 'omit',
279
+ body: formData.toString()
280
+ })
281
+ .then((response) => {
282
+ if (!response.ok) {
354
283
  // eslint-disable-next-line no-console
355
- console.log(e);
356
- });
284
+ console.error(`Error revoking ${prop}:${response.status}`);
285
+ }
286
+ })
287
+ .catch((e) => {
288
+ // eslint-disable-next-line no-console
289
+ console.error(`Error revoking ${prop}; ${e}`);
290
+ })
291
+ .finally(() => {
292
+ __classPrivateFieldGet(this, _PegaAuth_dynState, "f").silentAuthFailed = false;
293
+ // Also clobber any sessionIndex
294
+ __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_updateSessionIndex).call(this, null);
357
295
  });
358
- // Also clobber any sessionIndex
359
- if (this.config.sessionIndex) {
360
- delete this.config.sessionIndex;
361
- __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_updateConfig).call(this);
362
- }
363
296
  }
364
297
  // For userinfo endpoint to return meaningful data, endpoint must include appAlias (if specified) and authorize must
365
298
  // specify profile and optionally email scope to get such info returned
366
- async getUserinfo(access_token) {
367
- if (!this.config || !this.config.userinfoUri) {
299
+ async getUserinfo(accessToken) {
300
+ if (!__classPrivateFieldGet(this, _PegaAuth_config, "f") || !__classPrivateFieldGet(this, _PegaAuth_config, "f").userinfoUri) {
368
301
  // Must have a config structure and userInfo to proceed
369
302
  return {};
370
303
  }
371
- const hdrs = { 'authorization': `bearer ${access_token}`, 'content-type': 'application/json;charset=UTF-8' };
372
- return fetch(this.config.userinfoUri, {
373
- method: "GET",
374
- headers: new Headers(hdrs)
304
+ const headers = {
305
+ authorization: `bearer ${accessToken}`,
306
+ 'content-type': 'application/json;charset=UTF-8'
307
+ };
308
+ return fetch(__classPrivateFieldGet(this, _PegaAuth_config, "f").userinfoUri, {
309
+ agent: __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_getAgent).call(this),
310
+ method: 'GET',
311
+ headers: new Headers(headers)
375
312
  })
376
- .then(response => {
313
+ .then((response) => {
377
314
  if (response.ok) {
378
315
  return response.json();
379
316
  }
380
- else {
381
- // eslint-disable-next-line no-console
382
- console.log(`Error invoking userinfo: ${response.status}`);
383
- }
317
+ // eslint-disable-next-line no-console
318
+ console.log(`Error invoking userinfo: ${response.status}`);
384
319
  })
385
- .then(data => {
320
+ .then((data) => {
386
321
  return data;
387
322
  })
388
- .catch(e => {
323
+ .catch((e) => {
389
324
  // eslint-disable-next-line no-console
390
325
  console.log(e);
391
326
  });
392
327
  }
393
328
  }
394
- _PegaAuth_instances = new WeakSet(), _PegaAuth_updateConfig = function _PegaAuth_updateConfig() {
395
- const sSI = JSON.stringify(this.config);
396
- window.sessionStorage.setItem(this.ssKeyConfig, this.bEncodeSI ? window.btoa(sSI) : sSI);
329
+ _PegaAuth_config = new WeakMap(), _PegaAuth_dynState = new WeakMap(), _PegaAuth_instances = new WeakSet(), _PegaAuth_reloadSS = function _PegaAuth_reloadSS(ssKey) {
330
+ const sItem = window.sessionStorage.getItem(ssKey);
331
+ let obj = {};
332
+ if (sItem) {
333
+ try {
334
+ obj = JSON.parse(sItem);
335
+ }
336
+ catch (e) {
337
+ try {
338
+ obj = JSON.parse(atob(sItem));
339
+ }
340
+ catch (err) {
341
+ obj = {};
342
+ }
343
+ }
344
+ }
345
+ if (ssKey === this.ssKeyConfig) {
346
+ __classPrivateFieldSet(this, _PegaAuth_config, sItem ? obj : {}, "f");
347
+ }
348
+ else {
349
+ __classPrivateFieldSet(this, _PegaAuth_dynState, sItem ? obj : {}, "f");
350
+ }
351
+ }, _PegaAuth_reloadConfig = function _PegaAuth_reloadConfig() {
352
+ if (this.ssKeyConfig) {
353
+ __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_reloadSS).call(this, this.ssKeyConfig);
354
+ }
355
+ if (this.ssKeyDynState) {
356
+ __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_reloadSS).call(this, this.ssKeyDynState);
357
+ }
358
+ }, _PegaAuth_updateConfig = function _PegaAuth_updateConfig() {
359
+ // transform must occur unless it is explicitly disabled
360
+ const transform = __classPrivateFieldGet(this, _PegaAuth_config, "f").transform !== false;
361
+ // May not need to write out Config info all the time, but there is a scenario where a
362
+ // non obfuscated value is passed in and then it needs to be obfuscated
363
+ if (this.ssKeyConfig) {
364
+ const sConfig = JSON.stringify(__classPrivateFieldGet(this, _PegaAuth_config, "f"));
365
+ window.sessionStorage.setItem(this.ssKeyConfig, transform ? btoa(sConfig) : sConfig);
366
+ }
367
+ if (this.ssKeyDynState) {
368
+ const sDynState = JSON.stringify(__classPrivateFieldGet(this, _PegaAuth_dynState, "f"));
369
+ window.sessionStorage.setItem(this.ssKeyDynState, transform ? btoa(sDynState) : sDynState);
370
+ }
371
+ if (__classPrivateFieldGet(this, _PegaAuth_config, "f").fnDynStateChangedCB) {
372
+ __classPrivateFieldGet(this, _PegaAuth_config, "f").fnDynStateChangedCB();
373
+ }
374
+ }, _PegaAuth_importSingleLib = async function _PegaAuth_importSingleLib(libName, libProp, bLoadAlways = false) {
375
+ if (!bLoadAlways && typeof (this.isNode ? global : window)[libProp] !== 'undefined') {
376
+ this[libProp] = (this.isNode ? global : window)[libProp];
377
+ return this[libProp];
378
+ }
379
+ // Needed to explicitly make import argument a string by using template literals to fix a compile
380
+ // error: Critical dependency: the request of a dependency is an expression
381
+ return import(/* webpackIgnore: true */ `${libName}`)
382
+ .then((mod) => {
383
+ this[libProp] = mod.default;
384
+ })
385
+ .catch((e) => {
386
+ // eslint-disable-next-line no-console
387
+ console.error(`Library ${libName} failed to load. ${e}`);
388
+ throw e;
389
+ });
390
+ }, _PegaAuth_importNodeLibs = async function _PegaAuth_importNodeLibs() {
391
+ // Also current assumption is using Node 18 or better
392
+ // With 18.3 there is now a native fetch (but may want to force use of node-fetch)
393
+ const useNodeFetch = !!__classPrivateFieldGet(this, _PegaAuth_config, "f").useNodeFetch;
394
+ return Promise.all([
395
+ __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_importSingleLib).call(this, 'node-fetch', 'fetch', useNodeFetch),
396
+ __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_importSingleLib).call(this, 'open', 'open'),
397
+ __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_importSingleLib).call(this, 'node:crypto', 'crypto', true),
398
+ __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_importSingleLib).call(this, 'node:https', 'https'),
399
+ __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_importSingleLib).call(this, 'node:http', 'http'),
400
+ __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_importSingleLib).call(this, 'node:fs', 'fs')
401
+ ]).then(() => {
402
+ this.subtle = this.crypto?.subtle || this.crypto.webcrypto.subtle;
403
+ if ((typeof fetch === 'undefined' || useNodeFetch) && this.fetch) {
404
+ /* eslint-disable-next-line no-global-assign */
405
+ fetch = this.fetch;
406
+ }
407
+ });
397
408
  }, _PegaAuth_buildAuthorizeUrl =
398
409
  // For PKCE the authorize includes a code_challenge & code_challenge_method as well
399
410
  async function _PegaAuth_buildAuthorizeUrl(state) {
400
- const { clientId, redirectUri, authorizeUri, authService, sessionIndex, appAlias, useLocking, userIdentifier, password } = this.config;
401
- // Generate random string of 64 chars for verifier. RFC 7636 says from 43-128 chars
402
- let buf = new Uint8Array(64);
403
- window.crypto.getRandomValues(buf);
404
- this.config.codeVerifier = __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_base64UrlSafeEncode).call(this, buf);
411
+ const { serverType, clientId, redirectUri, authorizeUri, userinfoUri, authService, appAlias, userIdentifier, password, noPKCE, isolationId } = __classPrivateFieldGet(this, _PegaAuth_config, "f");
412
+ const { sessionIndex } = __classPrivateFieldGet(this, _PegaAuth_dynState, "f");
413
+ const bInfinity = serverType === 'infinity';
414
+ if (!noPKCE) {
415
+ // Generate random string of 64 chars for verifier. RFC 7636 says from 43-128 chars
416
+ const buf = new Uint8Array(64);
417
+ this.crypto.getRandomValues(buf);
418
+ __classPrivateFieldGet(this, _PegaAuth_dynState, "f").codeVerifier = __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_base64UrlSafeEncode).call(this, buf);
419
+ }
405
420
  // If sessionIndex exists then increment attempts count (we will stop sending session_index after two failures)
421
+ // With Infinity '24 we can now properly detect a invalid_session_index error, but can't for earlier versions
406
422
  if (sessionIndex) {
407
- this.config.sessionIndexAttempts += 1;
423
+ __classPrivateFieldGet(this, _PegaAuth_dynState, "f").sessionIndexAttempts += 1;
408
424
  }
425
+ // We use state to verify that the received code is for the right authorize transaction
426
+ __classPrivateFieldGet(this, _PegaAuth_dynState, "f").state = `${state || ''}.${__classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_getRandomString).call(this, 32)}`;
427
+ // The same redirectUri needs to be provided to token endpoint, so save this away incase redirectUri is
428
+ // adjusted for next authorize
429
+ __classPrivateFieldGet(this, _PegaAuth_dynState, "f").acRedirectUri = redirectUri;
409
430
  // Persist codeVerifier in session storage so it survives the redirects that are to follow
410
431
  __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_updateConfig).call(this);
411
- if (!state) {
412
- // Calc random state variable
413
- buf = new Uint8Array(32);
414
- window.crypto.getRandomValues(buf);
415
- state = __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_base64UrlSafeEncode).call(this, buf);
416
- }
417
432
  // Trim alias to include just the real alias piece
418
- const addtlScope = appAlias ? `+app.alias.${appAlias.replace(/^app\//, '')}` : "";
433
+ const additionalScope = (userinfoUri ? '+profile' : '') + (appAlias ? `+app.alias.${appAlias.replace(/^app\//, '')}` : '');
434
+ const scope = bInfinity ? `openid+email${additionalScope}` : 'user_info';
419
435
  // Add explicit creds if specified to try to avoid login popup
420
- const moreAuthArgs = (authService ? `&authentication_service=${encodeURIComponent(authService)}` : "") +
421
- (sessionIndex && this.config.sessionIndexAttempts < 3 ? `&session_index=${sessionIndex}` : "") +
422
- (useLocking ? `&enable_psyncId=true` : '') +
423
- (userIdentifier ? `&UserIdentifier=${encodeURIComponent(userIdentifier)}` : '') +
424
- (userIdentifier && password ? `&Password=${encodeURIComponent(window.atob(password))}` : '');
425
- return __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_getCodeChallenge).call(this, this.config.codeVerifier).then(cc => {
426
- // Now includes new enable_psyncId=true and session_index params
427
- return `${authorizeUri}?client_id=${clientId}&response_type=code&redirect_uri=${redirectUri}&scope=openid+email+profile${addtlScope}&state=${state}&code_challenge=${cc}&code_challenge_method=S256${moreAuthArgs}`;
436
+ const authServiceArg = authService ? `&authentication_service=${encodeURIComponent(authService)}` : '';
437
+ const sessionIndexArg = sessionIndex && __classPrivateFieldGet(this, _PegaAuth_dynState, "f").sessionIndexAttempts < 3 ? `&session_index=${sessionIndex}` : '';
438
+ const userIdentifierArg = userIdentifier ? `&UserIdentifier=${encodeURIComponent(userIdentifier)}` : '';
439
+ const passwordArg = password && userIdentifier ? `&Password=${encodeURIComponent(atob(password))}` : '';
440
+ const isolationIdArg = !bInfinity && isolationId ? `&isolationID=${isolationId}` : '';
441
+ const moreAuthArgs = bInfinity
442
+ ? `&enable_psyncId=true&cookies=none${authServiceArg}${sessionIndexArg}${userIdentifierArg}${passwordArg}`
443
+ : isolationIdArg;
444
+ let pkceArgs = '';
445
+ if (!noPKCE) {
446
+ const cc = await __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_getCodeChallenge).call(this, __classPrivateFieldGet(this, _PegaAuth_dynState, "f").codeVerifier);
447
+ pkceArgs = `&code_challenge=${cc}&code_challenge_method=S256`;
448
+ }
449
+ return `${authorizeUri}?client_id=${clientId}&response_type=code&redirect_uri=${redirectUri}&scope=${scope}&state=${encodeURIComponent(__classPrivateFieldGet(this, _PegaAuth_dynState, "f").state)}${pkceArgs}${moreAuthArgs}`;
450
+ }, _PegaAuth_authCodeStart =
451
+ // authCode login issues the authorize endpoint transaction and deals with redirects
452
+ async function _PegaAuth_authCodeStart() {
453
+ const fnGetRedirectUriOrigin = () => {
454
+ const redirectUri = __classPrivateFieldGet(this, _PegaAuth_config, "f").redirectUri;
455
+ const nRootOffset = redirectUri.indexOf('//');
456
+ const nFirstPathOffset = nRootOffset !== -1 ? redirectUri.indexOf('/', nRootOffset + 2) : -1;
457
+ return nFirstPathOffset !== -1 ? redirectUri.substring(0, nFirstPathOffset) : redirectUri;
458
+ };
459
+ const redirectOrigin = fnGetRedirectUriOrigin();
460
+ const startState = this.isNode ? '' : btoa(window.location.origin);
461
+ return new Promise((resolve, reject) => {
462
+ let theUrl = null; // holds the crafted authorize url
463
+ let myWindow = null; // popup or iframe
464
+ let elIframe = null;
465
+ let elCloseBtn = null;
466
+ const iframeTimeout = __classPrivateFieldGet(this, _PegaAuth_config, "f").silentTimeout !== undefined ? __classPrivateFieldGet(this, _PegaAuth_config, "f").silentTimeout : 5000;
467
+ let bWinIframe = true;
468
+ let tmrAuthComplete = null;
469
+ let checkWindowClosed = null;
470
+ let bDisablePromptNone = false;
471
+ const myWinOnLoad = () => {
472
+ try {
473
+ if (bWinIframe) {
474
+ elIframe.contentWindow.postMessage({ type: 'PegaAuth' }, redirectOrigin);
475
+ }
476
+ else {
477
+ myWindow.postMessage({ type: 'PegaAuth' }, redirectOrigin);
478
+ }
479
+ }
480
+ catch (e) {
481
+ // Exception trying to postMessage on load (perhaps should console.warn)
482
+ }
483
+ };
484
+ const fnSetSilentAuthFailed = (bSet) => {
485
+ __classPrivateFieldGet(this, _PegaAuth_dynState, "f").silentAuthFailed = bSet;
486
+ __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_updateConfig).call(this);
487
+ };
488
+ /* eslint-disable prefer-promise-reject-errors */
489
+ const fnOpenPopup = () => {
490
+ if (__classPrivateFieldGet(this, _PegaAuth_config, "f").noPopups) {
491
+ return reject('no-popups');
492
+ }
493
+ // Since displaying a visible window, clear the silent auth failed flag
494
+ fnSetSilentAuthFailed(false);
495
+ myWindow = (this.isNode ? this.open : window.open)(theUrl, '_blank', 'width=700,height=500,left=200,top=100');
496
+ if (!myWindow) {
497
+ // Blocked by popup-blocker
498
+ return reject('blocked');
499
+ }
500
+ checkWindowClosed = setInterval(() => {
501
+ if (myWindow.closed) {
502
+ clearInterval(checkWindowClosed);
503
+ reject('closed');
504
+ }
505
+ }, 500);
506
+ if (!this.isNode) {
507
+ try {
508
+ myWindow.addEventListener('load', myWinOnLoad, true);
509
+ }
510
+ catch (e) {
511
+ // Exception trying to add onload handler to opened window
512
+ // eslint-disable-next-line no-console
513
+ console.error(`Error adding event listener on popup window: ${e}`);
514
+ }
515
+ }
516
+ };
517
+ /* eslint-enable prefer-promise-reject-errors */
518
+ const fnCloseIframe = () => {
519
+ elIframe.parentNode.removeChild(elIframe);
520
+ elCloseBtn.parentNode.removeChild(elCloseBtn);
521
+ elIframe = null;
522
+ elCloseBtn = null;
523
+ bWinIframe = false;
524
+ };
525
+ const fnCloseAndReject = () => {
526
+ fnCloseIframe();
527
+ /* eslint-disable-next-line prefer-promise-reject-errors */
528
+ reject('closed');
529
+ };
530
+ const fnAuthMessageReceiver = (event) => {
531
+ // Check origin to make sure it is the redirect origin
532
+ if (event.origin !== redirectOrigin) {
533
+ if (event.data?.type === 'PegaAuth') {
534
+ // eslint-disable-next-line no-console
535
+ console.error(`Authorization code grant flow error: Unexpected origin: ${event.origin} ... expecting: ${redirectOrigin}`);
536
+ }
537
+ return;
538
+ }
539
+ if (!event.data || !event.data.type || event.data.type !== 'PegaAuth')
540
+ return;
541
+ const aArgs = ['code', 'state', 'error', 'errorDesc'];
542
+ const aValues = [];
543
+ for (let i = 0; i < aArgs.length; i += 1) {
544
+ const arg = aArgs[i];
545
+ aValues[arg] = event.data[arg] ? event.data[arg].toString() : null;
546
+ }
547
+ const { code, state, error, errorDesc } = aValues;
548
+ if (error) {
549
+ // eslint-disable-next-line no-console
550
+ console.error(`Authorization code grant flow error (${error}): ${errorDesc}`);
551
+ }
552
+ if (code && state !== __classPrivateFieldGet(this, _PegaAuth_dynState, "f").state) {
553
+ // eslint-disable-next-line no-console
554
+ console.error(`Authorization code transfer error: state mismatch: ${state} ... expecting: ${__classPrivateFieldGet(this, _PegaAuth_dynState, "f").state}`);
555
+ }
556
+ if (error || (code && state === __classPrivateFieldGet(this, _PegaAuth_dynState, "f").state)) {
557
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
558
+ fnGetTokenAndFinish(code, error, errorDesc);
559
+ }
560
+ };
561
+ const fnEnableMessageReceiver = (bEnable) => {
562
+ if (bEnable) {
563
+ window.addEventListener('message', fnAuthMessageReceiver, false);
564
+ window.authCodeCallback = (code, state, error, errorDesc) => {
565
+ if (error) {
566
+ // eslint-disable-next-line no-console
567
+ console.error(`Authorization code grant flow error (${error}): ${errorDesc}`);
568
+ }
569
+ if (code && state !== __classPrivateFieldGet(this, _PegaAuth_dynState, "f").state) {
570
+ // eslint-disable-next-line no-console
571
+ console.error(`Authorization code transfer error: state mismatch: ${state} ... expecting: ${__classPrivateFieldGet(this, _PegaAuth_dynState, "f").state}`);
572
+ }
573
+ if (error || (code && state === __classPrivateFieldGet(this, _PegaAuth_dynState, "f").state)) {
574
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
575
+ fnGetTokenAndFinish(code, error, errorDesc);
576
+ }
577
+ };
578
+ }
579
+ else {
580
+ window.removeEventListener('message', fnAuthMessageReceiver, false);
581
+ delete window.authCodeCallback;
582
+ }
583
+ };
584
+ const doAuthorize = () => {
585
+ // If there is a userIdentifier and password specified or an external SSO auth service,
586
+ // we can try to use this silently in an iFrame first
587
+ bWinIframe =
588
+ !this.isNode &&
589
+ !__classPrivateFieldGet(this, _PegaAuth_dynState, "f").silentAuthFailed &&
590
+ iframeTimeout > 0 &&
591
+ ((!!__classPrivateFieldGet(this, _PegaAuth_config, "f").userIdentifier && !!__classPrivateFieldGet(this, _PegaAuth_config, "f").password) ||
592
+ __classPrivateFieldGet(this, _PegaAuth_config, "f").iframeLoginUI ||
593
+ __classPrivateFieldGet(this, _PegaAuth_config, "f").authService !== 'pega');
594
+ // Enable message receiver
595
+ if (!this.isNode) {
596
+ fnEnableMessageReceiver(true);
597
+ }
598
+ if (bWinIframe) {
599
+ const nFrameZLevel = 99999;
600
+ elIframe = document.createElement('iframe');
601
+ elIframe.id = `pe${__classPrivateFieldGet(this, _PegaAuth_config, "f").clientId}`;
602
+ const loginBoxWidth = 500;
603
+ const loginBoxHeight = 700;
604
+ const oStyle = elIframe.style;
605
+ oStyle.position = 'absolute';
606
+ oStyle.display = 'none';
607
+ oStyle.zIndex = nFrameZLevel;
608
+ oStyle.top = `${Math.round(Math.max(window.innerHeight - loginBoxHeight, 0) / 2)}px`;
609
+ oStyle.left = `${Math.round(Math.max(window.innerWidth - loginBoxWidth, 0) / 2)}px`;
610
+ oStyle.width = '500px';
611
+ oStyle.height = '700px';
612
+ // Add Iframe to top of document DOM to have it load
613
+ document.body.insertBefore(elIframe, document.body.firstChild);
614
+ // document.getElementsByTagName('body')[0].appendChild(elIframe);
615
+ elIframe.addEventListener('load', myWinOnLoad, true);
616
+ // Disallow iframe content attempts to navigate main window
617
+ elIframe.setAttribute('sandbox', 'allow-scripts allow-forms allow-same-origin');
618
+ // Adding prompt=none as this is standard OIDC way to communicate no UI is expected (With Infinity '23 or better, this is passed on to
619
+ // configured OIDC authentication services). cookies=none disables the temporary Pega-Rules cookie otherwise created on auth code
620
+ // grant flow. For now these two args are either both set or not set, but might have a cookies="partitioned" one day.
621
+ elIframe.setAttribute('src', bDisablePromptNone ? theUrl : `${theUrl}&prompt=none`);
622
+ const svgCloseBtn = `<?xml version="1.0" encoding="UTF-8"?>
623
+ <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">
624
+ <title>Dismiss - Black</title>
625
+ <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
626
+ <g transform="translate(1.000000, 1.000000)">
627
+ <circle fill="#252C32" cx="16" cy="16" r="16"></circle>
628
+ <g transform="translate(9.109375, 9.214844)" fill="#FFFFFF" fill-rule="nonzero">
629
+ <path d="M12.7265625,0 L0,12.6210938 L1.0546875,13.5703125 L13.78125,1.0546875 L12.7265625,0 Z M13.7460938,12.5507812 L1.01953125,0 L0,1.01953125 L12.7617188,13.6054688 L13.7460938,12.5507812 Z"></path>
630
+ </g>
631
+ </g>
632
+ </g>
633
+ </svg>`;
634
+ const bCloseWithinFrame = false;
635
+ elCloseBtn = document.createElement('img');
636
+ elCloseBtn.onclick = fnCloseAndReject;
637
+ elCloseBtn.src = `data:image/svg+xml;base64,${btoa(svgCloseBtn)}`;
638
+ const oBtnStyle = elCloseBtn.style;
639
+ oBtnStyle.cursor = 'pointer';
640
+ // If svg doesn't set width and height might want to set oBtStyle width and height to something like '2em'
641
+ oBtnStyle.position = 'absolute';
642
+ oBtnStyle.display = 'none';
643
+ oBtnStyle.zIndex = nFrameZLevel + 1;
644
+ const nTopOffset = bCloseWithinFrame ? 5 : -10;
645
+ const nRightOffset = bCloseWithinFrame ? -34 : -20;
646
+ const nTop = Math.round(Math.max(window.innerHeight - loginBoxHeight, 0) / 2) + nTopOffset;
647
+ oBtnStyle.top = `${nTop}px`;
648
+ const nLeft = Math.round(Math.max(window.innerWidth - loginBoxWidth, 0) / 2) + loginBoxWidth + nRightOffset;
649
+ oBtnStyle.left = `${nLeft}px`;
650
+ document.body.insertBefore(elCloseBtn, document.body.firstChild);
651
+ // If the password was wrong, then the login screen will be in the iframe
652
+ // ..and with Pega without realization of US-372314 it may replace the top (main portal) window
653
+ // For now set a timer and if the timer expires, remove the iFrame and use same url within
654
+ // visible window
655
+ tmrAuthComplete = setTimeout(() => {
656
+ clearTimeout(tmrAuthComplete);
657
+ /*
658
+ // remove password from config
659
+ if (this.#config.password) {
660
+ delete this.#config.password;
661
+ this.#updateConfig();
662
+ }
663
+ */
664
+ // Display the iframe where the redirects did not succeed (or invoke a popup window)
665
+ if (__classPrivateFieldGet(this, _PegaAuth_config, "f").iframeLoginUI) {
666
+ elIframe.style.display = 'block';
667
+ elCloseBtn.style.display = 'block';
668
+ }
669
+ else {
670
+ fnCloseIframe();
671
+ fnOpenPopup();
672
+ }
673
+ }, iframeTimeout);
674
+ }
675
+ else {
676
+ if (this.isNode) {
677
+ // Determine port to listen to by extracting it from redirect uri
678
+ const { redirectUri, cert, key } = __classPrivateFieldGet(this, _PegaAuth_config, "f");
679
+ const isHttp = redirectUri.startsWith('http:');
680
+ const nLocalhost = redirectUri.indexOf('localhost:');
681
+ const nSlash = redirectUri.indexOf('/', nLocalhost + 10);
682
+ const nPort = parseInt(redirectUri.substring(nLocalhost + 10, nSlash), 10);
683
+ if (nLocalhost !== -1) {
684
+ const options = key && cert && !isHttp
685
+ ? {
686
+ key: this.fs.readFileSync(key),
687
+ cert: this.fs.readFileSync(cert)
688
+ }
689
+ : {};
690
+ const server = (isHttp ? this.http : this.https).createServer(options, (req, res) => {
691
+ const { winTitle, winBodyHtml } = __classPrivateFieldGet(this, _PegaAuth_config, "f");
692
+ res.writeHead(200, { 'Content-Type': 'text/html' });
693
+ // Auto closing window for now. Can always leave it up and allow authConfig props to set title and bodyHtml
694
+ res.end(`<html><head><title>${winTitle}</title><script>window.close();</script></head><body>${winBodyHtml}</body></html>`);
695
+ const queryString = req.url.split('?')[1];
696
+ const urlParams = new URLSearchParams(queryString);
697
+ const code = urlParams.get('code');
698
+ const state = urlParams.get('state');
699
+ const error = urlParams.get('error');
700
+ const errorDesc = urlParams.get('error_description');
701
+ if (error || (code && state === __classPrivateFieldGet(this, _PegaAuth_dynState, "f").state)) {
702
+ // Stop receiving connections and close when all are handled.
703
+ server.close();
704
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
705
+ fnGetTokenAndFinish(code, error, errorDesc);
706
+ }
707
+ });
708
+ server.listen(nPort);
709
+ }
710
+ }
711
+ fnOpenPopup();
712
+ }
713
+ };
714
+ /* Retrieve token(s) and close login window */
715
+ const fnGetTokenAndFinish = (code, error, errorDesc) => {
716
+ // Can clear state in session info at this point
717
+ delete __classPrivateFieldGet(this, _PegaAuth_dynState, "f").state;
718
+ __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_updateConfig).call(this);
719
+ if (!this.isNode) {
720
+ fnEnableMessageReceiver(false);
721
+ if (bWinIframe) {
722
+ clearTimeout(tmrAuthComplete);
723
+ fnCloseIframe();
724
+ }
725
+ else {
726
+ clearInterval(checkWindowClosed);
727
+ try {
728
+ if (myWindow) {
729
+ myWindow.close();
730
+ myWindow = null;
731
+ }
732
+ }
733
+ catch (e) {
734
+ // keep going and process code or error even though issue closing popup
735
+ // eslint-disable-next-line no-console
736
+ console.warn(`Error closing window: ${e}`);
737
+ }
738
+ }
739
+ }
740
+ if (code) {
741
+ this.getToken(code)
742
+ .then((token) => {
743
+ resolve(token);
744
+ })
745
+ .catch((e) => {
746
+ reject(e);
747
+ });
748
+ }
749
+ else if (error) {
750
+ // Handle some errors in a special manner and pass others back to client
751
+ if (error === 'login_required') {
752
+ // eslint-disable-next-line no-console
753
+ console.warn('silent authentication failed...starting full authentication');
754
+ const bSpecialDebugPath = false;
755
+ if (bSpecialDebugPath) {
756
+ fnSetSilentAuthFailed(false);
757
+ bDisablePromptNone = true;
758
+ }
759
+ else {
760
+ fnSetSilentAuthFailed(true);
761
+ bDisablePromptNone = false;
762
+ }
763
+ __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_buildAuthorizeUrl).call(this, startState).then((url) => {
764
+ theUrl = url;
765
+ doAuthorize();
766
+ });
767
+ }
768
+ else if (error === 'invalid_session_index') {
769
+ // eslint-disable-next-line no-console
770
+ console.warn('auth session no longer valid...starting new session');
771
+ // In these scenarios, not much user can do without just starting a new session, so do that
772
+ __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_updateSessionIndex).call(this, null);
773
+ fnSetSilentAuthFailed(false);
774
+ __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_buildAuthorizeUrl).call(this, startState).then((url) => {
775
+ theUrl = url;
776
+ doAuthorize();
777
+ });
778
+ }
779
+ else {
780
+ // eslint-disable-next-line no-console
781
+ console.warn(`Authorize failed: ${error}. ${errorDesc}\nFailing authorize url: ${theUrl}`);
782
+ throw new Error(error, { cause: errorDesc });
783
+ }
784
+ }
785
+ };
786
+ __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_buildAuthorizeUrl).call(this, startState).then((url) => {
787
+ theUrl = url;
788
+ doAuthorize();
789
+ });
428
790
  });
791
+ }, _PegaAuth_updateSessionIndex = function _PegaAuth_updateSessionIndex(sessionIndex) {
792
+ if (sessionIndex) {
793
+ __classPrivateFieldGet(this, _PegaAuth_dynState, "f").sessionIndex = sessionIndex;
794
+ __classPrivateFieldGet(this, _PegaAuth_dynState, "f").sessionIndexAttempts = 0;
795
+ }
796
+ else if (__classPrivateFieldGet(this, _PegaAuth_dynState, "f").sessionIndex) {
797
+ delete __classPrivateFieldGet(this, _PegaAuth_dynState, "f").sessionIndex;
798
+ }
799
+ __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_updateConfig).call(this);
429
800
  }, _PegaAuth_sha256Hash = function _PegaAuth_sha256Hash(str) {
430
- return window.crypto.subtle.digest("SHA-256", new TextEncoder().encode(str));
801
+ // Found that the Node implementation of subtle.digest is yielding incorrect results
802
+ // so using a different set of apis to get expected results.
803
+ if (this.isNode) {
804
+ return new Promise((resolve) => {
805
+ resolve(this.crypto.createHash('sha256').update(str).digest());
806
+ });
807
+ }
808
+ return this.subtle.digest('SHA-256', new TextEncoder().encode(str));
431
809
  }, _PegaAuth_encode64 = function _PegaAuth_encode64(buff) {
432
- return window.btoa(new Uint8Array(buff).reduce((s, b) => s + String.fromCharCode(b), ''));
810
+ return btoa(new Uint8Array(buff).reduce((s, b) => s + String.fromCharCode(b), ''));
433
811
  }, _PegaAuth_base64UrlSafeEncode = function _PegaAuth_base64UrlSafeEncode(buf) {
434
- const s = __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_encode64).call(this, buf).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
435
- return s;
436
- }, _PegaAuth_getCodeChallenge = function _PegaAuth_getCodeChallenge(code_verifier) {
437
- return __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_sha256Hash).call(this, code_verifier).then((hashed) => {
812
+ return __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_encode64).call(this, buf).replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
813
+ }, _PegaAuth_getRandomString = function _PegaAuth_getRandomString(nSize) {
814
+ const buf = new Uint8Array(nSize);
815
+ this.crypto.getRandomValues(buf);
816
+ return __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_base64UrlSafeEncode).call(this, buf);
817
+ }, _PegaAuth_getCodeChallenge =
818
+ /*
819
+ * Calc code verifier if necessary
820
+ */
821
+ async function _PegaAuth_getCodeChallenge(codeVerifier) {
822
+ return __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_sha256Hash).call(this, codeVerifier)
823
+ .then((hashed) => {
438
824
  return __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_base64UrlSafeEncode).call(this, hashed);
439
- }).catch((error) => {
825
+ })
826
+ .catch((error) => {
440
827
  // eslint-disable-next-line no-console
441
- console.log(error);
442
- }).finally(() => { return null; });
828
+ console.error(`Error calculation code challenge for PKCE: ${error}`);
829
+ })
830
+ .finally(() => {
831
+ return null;
832
+ });
833
+ }, _PegaAuth_getAgent = function _PegaAuth_getAgent() {
834
+ if (this.isNode && __classPrivateFieldGet(this, _PegaAuth_config, "f").ignoreInvalidCerts) {
835
+ const options = { rejectUnauthorized: false };
836
+ if (__classPrivateFieldGet(this, _PegaAuth_config, "f").legacyTLS) {
837
+ options.secureOptions = this.crypto.constants.SSL_OP_LEGACY_SERVER_CONNECT;
838
+ }
839
+ return new this.https.Agent(options);
840
+ }
841
+ return undefined;
443
842
  };
444
843
  export default PegaAuth;
445
844
  //# sourceMappingURL=auth.js.map