@pega/react-sdk-components 8.23.11-debug2 → 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,227 +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
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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
|
-
|
|
48
|
+
else {
|
|
49
|
+
throw new Error('invalid config settings');
|
|
50
|
+
}
|
|
31
51
|
}
|
|
32
52
|
async login() {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
-
// eslint-disable-next-line no-console
|
|
61
|
-
console.log(`authjs(login): loaded a page in popup window...sending 'PegaAuth' message. redirectOrigin: ${redirectOrigin}`);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
catch (e) {
|
|
65
|
-
// eslint-disable-next-line no-console
|
|
66
|
-
console.log("authjs(login): Exception trying to postMessage on load");
|
|
67
|
-
}
|
|
68
|
-
};
|
|
69
|
-
const fnOpenPopup = () => {
|
|
70
|
-
myWindow = window.open(url, '_blank', 'width=700,height=500,left=200,top=100');
|
|
71
|
-
if (!myWindow) {
|
|
72
|
-
// Blocked by popup-blocker
|
|
73
|
-
// eslint-disable-next-line prefer-promise-reject-errors
|
|
74
|
-
return reject("blocked");
|
|
75
|
-
}
|
|
76
|
-
checkWindowClosed = setInterval(() => {
|
|
77
|
-
if (myWindow.closed) {
|
|
78
|
-
clearInterval(checkWindowClosed);
|
|
79
|
-
// eslint-disable-next-line prefer-promise-reject-errors
|
|
80
|
-
reject("closed");
|
|
81
|
-
}
|
|
82
|
-
}, 500);
|
|
83
|
-
try {
|
|
84
|
-
myWindow.addEventListener("load", myWinOnLoad, true);
|
|
85
|
-
}
|
|
86
|
-
catch (e) {
|
|
87
|
-
// eslint-disable-next-line no-console
|
|
88
|
-
console.log("authjs(login): Exception trying to add onload handler to opened window;");
|
|
89
|
-
}
|
|
90
|
-
};
|
|
91
|
-
const fnCloseIframe = () => {
|
|
92
|
-
elIframe.parentNode.removeChild(elIframe);
|
|
93
|
-
elCloseBtn.parentNode.removeChild(elCloseBtn);
|
|
94
|
-
// eslint-disable-next-line no-multi-assign
|
|
95
|
-
elIframe = elCloseBtn = null;
|
|
96
|
-
bWinIframe = false;
|
|
97
|
-
};
|
|
98
|
-
const fnCloseAndReject = () => {
|
|
99
|
-
fnCloseIframe();
|
|
100
|
-
// eslint-disable-next-line prefer-promise-reject-errors
|
|
101
|
-
reject("closed");
|
|
102
|
-
};
|
|
103
|
-
// If there is a userIdentifier and password specified or an external SSO auth service,
|
|
104
|
-
// we can try to use this silently in an iFrame first
|
|
105
|
-
if (bWinIframe) {
|
|
106
|
-
const nFrameZLevel = 99999;
|
|
107
|
-
elIframe = document.createElement('iframe');
|
|
108
|
-
// eslint-disable-next-line prefer-template
|
|
109
|
-
elIframe.id = 'pe' + this.config.clientId;
|
|
110
|
-
const loginBoxWidth = 500;
|
|
111
|
-
const loginBoxHeight = 700;
|
|
112
|
-
const oStyle = elIframe.style;
|
|
113
|
-
oStyle.position = 'absolute';
|
|
114
|
-
oStyle.display = 'none';
|
|
115
|
-
oStyle.zIndex = nFrameZLevel;
|
|
116
|
-
oStyle.top = `${Math.round(Math.max(window.innerHeight - loginBoxHeight, 0) / 2)}px`;
|
|
117
|
-
oStyle.left = `${Math.round(Math.max(window.innerWidth - loginBoxWidth, 0) / 2)}px`;
|
|
118
|
-
oStyle.width = '500px';
|
|
119
|
-
oStyle.height = '700px';
|
|
120
|
-
// Add Iframe to top of document DOM to have it load
|
|
121
|
-
document.body.insertBefore(elIframe, document.body.firstChild);
|
|
122
|
-
// Add Iframe to DOM to have it load
|
|
123
|
-
document.getElementsByTagName('body')[0].appendChild(elIframe);
|
|
124
|
-
elIframe.addEventListener("load", myWinOnLoad, true);
|
|
125
|
-
// Disallow iframe content attempts to navigate main window
|
|
126
|
-
elIframe.setAttribute("sandbox", "allow-scripts allow-forms allow-same-origin");
|
|
127
|
-
elIframe.setAttribute('src', url);
|
|
128
|
-
const svgCloseBtn = `<?xml version="1.0" encoding="UTF-8"?>
|
|
129
|
-
<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">
|
|
130
|
-
<title>Dismiss - Black</title>
|
|
131
|
-
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
|
132
|
-
<g transform="translate(1.000000, 1.000000)">
|
|
133
|
-
<circle fill="#252C32" cx="16" cy="16" r="16"></circle>
|
|
134
|
-
<g transform="translate(9.109375, 9.214844)" fill="#FFFFFF" fill-rule="nonzero">
|
|
135
|
-
<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>
|
|
136
|
-
</g>
|
|
137
|
-
</g>
|
|
138
|
-
</g>
|
|
139
|
-
</svg>`;
|
|
140
|
-
const bCloseWithinFrame = false;
|
|
141
|
-
elCloseBtn = document.createElement('img');
|
|
142
|
-
elCloseBtn.onclick = fnCloseAndReject;
|
|
143
|
-
// eslint-disable-next-line prefer-template
|
|
144
|
-
elCloseBtn.src = 'data:image/svg+xml;base64,' + window.btoa(svgCloseBtn);
|
|
145
|
-
const oBtnStyle = elCloseBtn.style;
|
|
146
|
-
oBtnStyle.cursor = 'pointer';
|
|
147
|
-
// If svg doesn't set width and height might want to set oBtStyle width and height to something like '2em'
|
|
148
|
-
oBtnStyle.position = 'absolute';
|
|
149
|
-
oBtnStyle.display = 'none';
|
|
150
|
-
oBtnStyle.zIndex = nFrameZLevel + 1;
|
|
151
|
-
const nTopOffset = bCloseWithinFrame ? 5 : -10;
|
|
152
|
-
const nRightOffset = bCloseWithinFrame ? -34 : -20;
|
|
153
|
-
oBtnStyle.top = `${Math.round(Math.max(window.innerHeight - loginBoxHeight, 0) / 2) + nTopOffset}px`;
|
|
154
|
-
oBtnStyle.left = `${Math.round(Math.max(window.innerWidth - loginBoxWidth, 0) / 2) + loginBoxWidth + nRightOffset}px`;
|
|
155
|
-
document.body.insertBefore(elCloseBtn, document.body.firstChild);
|
|
156
|
-
// If the password was wrong, then the login screen will be in the iframe
|
|
157
|
-
// ..and with Pega without realization of US-372314 it may replace the top (main portal) window
|
|
158
|
-
// For now set a timer and if the timer expires, remove the iFrame and use same url within
|
|
159
|
-
// visible window
|
|
160
|
-
tmrAuthComplete = setTimeout(() => {
|
|
161
|
-
clearTimeout(tmrAuthComplete);
|
|
162
|
-
// remove password from config
|
|
163
|
-
if (this.config.password) {
|
|
164
|
-
delete this.config.password;
|
|
165
|
-
__classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_updateConfig).call(this);
|
|
166
|
-
}
|
|
167
|
-
if (this.config.iframeLoginUI) {
|
|
168
|
-
elIframe.style.display = "block";
|
|
169
|
-
elCloseBtn.style.display = "block";
|
|
170
|
-
}
|
|
171
|
-
else {
|
|
172
|
-
fnCloseIframe();
|
|
173
|
-
fnOpenPopup();
|
|
174
|
-
}
|
|
175
|
-
}, iframeTimeout);
|
|
176
|
-
}
|
|
177
|
-
else {
|
|
178
|
-
fnOpenPopup();
|
|
179
|
-
}
|
|
180
|
-
let authMessageReceiver = null;
|
|
181
|
-
/* Retrieve token(s) and close login window */
|
|
182
|
-
const fnGetTokenAndFinish = (code) => {
|
|
183
|
-
window.removeEventListener("message", authMessageReceiver, false);
|
|
184
|
-
this.getToken(code).then(token => {
|
|
185
|
-
if (bWinIframe) {
|
|
186
|
-
clearTimeout(tmrAuthComplete);
|
|
187
|
-
fnCloseIframe();
|
|
188
|
-
}
|
|
189
|
-
else {
|
|
190
|
-
clearInterval(checkWindowClosed);
|
|
191
|
-
try {
|
|
192
|
-
myWindow.close();
|
|
193
|
-
}
|
|
194
|
-
catch (e) {
|
|
195
|
-
// eslint-disable-next-line no-console
|
|
196
|
-
console.warn(`attempt to close opened window failed`);
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
resolve(token);
|
|
200
|
-
})
|
|
201
|
-
.catch(e => {
|
|
202
|
-
reject(e);
|
|
203
|
-
});
|
|
204
|
-
};
|
|
205
|
-
/* Handler to receive the auth code */
|
|
206
|
-
authMessageReceiver = (event) => {
|
|
207
|
-
// Check origin to make sure it is the redirect origin
|
|
208
|
-
if (event.origin !== redirectOrigin) {
|
|
209
|
-
// eslint-disable-next-line no-console
|
|
210
|
-
console.info(`Received event from unexpected origin: ${event.origin} (was expecting: ${redirectOrigin})`);
|
|
211
|
-
}
|
|
212
|
-
if (!event.data || !event.data.type || event.data.type !== "PegaAuth")
|
|
213
|
-
return;
|
|
214
|
-
// eslint-disable-next-line no-console
|
|
215
|
-
console.log("authjs(login): postMessage received with code");
|
|
216
|
-
const code = event.data.code.toString();
|
|
217
|
-
fnGetTokenAndFinish(code);
|
|
218
|
-
};
|
|
219
|
-
window.addEventListener("message", authMessageReceiver, false);
|
|
220
|
-
window.authCodeCallback = (code) => {
|
|
221
|
-
// eslint-disable-next-line no-console
|
|
222
|
-
console.log("authjs(login): authCodeCallback used with code");
|
|
223
|
-
fnGetTokenAndFinish(code);
|
|
224
|
-
};
|
|
225
|
-
});
|
|
226
|
-
});
|
|
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);
|
|
227
66
|
}
|
|
228
67
|
// Login redirect
|
|
229
68
|
loginRedirect() {
|
|
@@ -234,71 +73,143 @@ class PegaAuth {
|
|
|
234
73
|
location.href = url;
|
|
235
74
|
});
|
|
236
75
|
}
|
|
76
|
+
// check state
|
|
77
|
+
checkStateMatch(state) {
|
|
78
|
+
return state === __classPrivateFieldGet(this, _PegaAuth_dynState, "f").state;
|
|
79
|
+
}
|
|
237
80
|
// For PKCE token endpoint includes code_verifier
|
|
238
81
|
getToken(authCode) {
|
|
239
82
|
// Reload config to pick up the previously stored codeVerifier
|
|
240
|
-
this.
|
|
241
|
-
const { clientId, clientSecret,
|
|
242
|
-
|
|
243
|
-
const
|
|
244
|
-
|
|
245
|
-
|
|
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
|
+
}
|
|
246
92
|
const formData = new URLSearchParams();
|
|
247
|
-
formData.append(
|
|
93
|
+
formData.append('client_id', clientId);
|
|
248
94
|
if (clientSecret) {
|
|
249
|
-
formData.append(
|
|
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));
|
|
250
131
|
}
|
|
251
|
-
formData.append("grant_type", "authorization_code");
|
|
252
|
-
formData.append("code", code);
|
|
253
|
-
formData.append("redirect_uri", redirectUri);
|
|
254
|
-
formData.append("code_verifier", codeVerifier);
|
|
255
132
|
return fetch(tokenUri, {
|
|
256
|
-
|
|
133
|
+
agent: __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_getAgent).call(this),
|
|
134
|
+
method: 'POST',
|
|
257
135
|
headers: new Headers({
|
|
258
|
-
|
|
136
|
+
'content-type': this.urlencoded
|
|
259
137
|
}),
|
|
260
|
-
|
|
138
|
+
credentials: secureCookie ? 'include' : 'omit',
|
|
139
|
+
body: formData.toString()
|
|
261
140
|
})
|
|
262
|
-
.then((response) =>
|
|
263
|
-
.
|
|
264
|
-
|
|
265
|
-
// add property to keep track of current time when the token expires
|
|
266
|
-
token.eA = Date.now() + (token.expires_in * 1000);
|
|
267
|
-
if (this.config.codeVerifier) {
|
|
268
|
-
delete this.config.codeVerifier;
|
|
141
|
+
.then((response) => {
|
|
142
|
+
if (response.ok) {
|
|
143
|
+
return response.json();
|
|
269
144
|
}
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
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)}`);
|
|
273
151
|
}
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
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
|
+
}
|
|
277
174
|
}
|
|
278
|
-
__classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_updateConfig).call(this);
|
|
279
175
|
return token;
|
|
280
176
|
})
|
|
281
|
-
.catch(e => {
|
|
177
|
+
.catch((e) => {
|
|
178
|
+
const msg = `${e}`;
|
|
282
179
|
// eslint-disable-next-line no-console
|
|
283
|
-
console.
|
|
180
|
+
console.error(msg.indexOf(this.tokenError) !== -1 ? msg : `${this.tokenError}: ${msg}`);
|
|
181
|
+
throw e;
|
|
284
182
|
});
|
|
285
183
|
}
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
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
|
+
}
|
|
289
193
|
const formData = new URLSearchParams();
|
|
290
|
-
formData.append(
|
|
194
|
+
formData.append('client_id', clientId);
|
|
291
195
|
if (clientSecret) {
|
|
292
|
-
formData.append(
|
|
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);
|
|
293
204
|
}
|
|
294
|
-
formData.append("grant_type", "refresh_token");
|
|
295
|
-
formData.append("refresh_token", refresh_token);
|
|
296
205
|
return fetch(tokenUri, {
|
|
297
|
-
|
|
206
|
+
agent: __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_getAgent).call(this),
|
|
207
|
+
method: 'POST',
|
|
298
208
|
headers: new Headers({
|
|
299
|
-
|
|
209
|
+
'content-type': this.urlencoded
|
|
300
210
|
}),
|
|
301
|
-
|
|
211
|
+
credentials: secureCookie ? 'include' : 'omit',
|
|
212
|
+
body: formData.toString()
|
|
302
213
|
})
|
|
303
214
|
.then((response) => {
|
|
304
215
|
if (!response.ok && response.status === 401) {
|
|
@@ -306,142 +217,628 @@ class PegaAuth {
|
|
|
306
217
|
}
|
|
307
218
|
return response.json();
|
|
308
219
|
})
|
|
309
|
-
.then(token => {
|
|
220
|
+
.then((token) => {
|
|
310
221
|
if (token) {
|
|
311
222
|
// .expires_in contains the # of seconds before access token expires
|
|
312
223
|
// add property to keep track of current time when the token expires
|
|
313
|
-
token.eA = Date.now() +
|
|
224
|
+
token.eA = Date.now() + token.expires_in * 1000;
|
|
314
225
|
}
|
|
315
226
|
return token;
|
|
316
227
|
})
|
|
317
|
-
.catch(e => {
|
|
228
|
+
.catch((e) => {
|
|
318
229
|
// eslint-disable-next-line no-console
|
|
319
|
-
console.
|
|
230
|
+
console.warn(`Refresh token failed: ${e}`);
|
|
231
|
+
return null;
|
|
320
232
|
});
|
|
321
233
|
}
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
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
|
|
325
247
|
return;
|
|
326
248
|
}
|
|
327
|
-
const { clientId, clientSecret, revokeUri } = this
|
|
328
|
-
|
|
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 };
|
|
329
255
|
if (clientSecret) {
|
|
330
|
-
const
|
|
331
|
-
|
|
256
|
+
const basicCreds = btoa(`${clientId}:${clientSecret}`);
|
|
257
|
+
headers.authorization = `Basic ${basicCreds}`;
|
|
332
258
|
}
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
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);
|
|
336
265
|
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
formData.append(
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
})
|
|
355
|
-
.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) {
|
|
356
283
|
// eslint-disable-next-line no-console
|
|
357
|
-
console.
|
|
358
|
-
}
|
|
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);
|
|
359
295
|
});
|
|
360
|
-
// Also clobber any sessionIndex
|
|
361
|
-
if (this.config.sessionIndex) {
|
|
362
|
-
delete this.config.sessionIndex;
|
|
363
|
-
__classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_updateConfig).call(this);
|
|
364
|
-
}
|
|
365
296
|
}
|
|
366
297
|
// For userinfo endpoint to return meaningful data, endpoint must include appAlias (if specified) and authorize must
|
|
367
298
|
// specify profile and optionally email scope to get such info returned
|
|
368
|
-
async getUserinfo(
|
|
369
|
-
if (!this
|
|
299
|
+
async getUserinfo(accessToken) {
|
|
300
|
+
if (!__classPrivateFieldGet(this, _PegaAuth_config, "f") || !__classPrivateFieldGet(this, _PegaAuth_config, "f").userinfoUri) {
|
|
370
301
|
// Must have a config structure and userInfo to proceed
|
|
371
302
|
return {};
|
|
372
303
|
}
|
|
373
|
-
const
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
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)
|
|
377
312
|
})
|
|
378
|
-
.then(response => {
|
|
313
|
+
.then((response) => {
|
|
379
314
|
if (response.ok) {
|
|
380
315
|
return response.json();
|
|
381
316
|
}
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
console.log(`Error invoking userinfo: ${response.status}`);
|
|
385
|
-
}
|
|
317
|
+
// eslint-disable-next-line no-console
|
|
318
|
+
console.log(`Error invoking userinfo: ${response.status}`);
|
|
386
319
|
})
|
|
387
|
-
.then(data => {
|
|
320
|
+
.then((data) => {
|
|
388
321
|
return data;
|
|
389
322
|
})
|
|
390
|
-
.catch(e => {
|
|
323
|
+
.catch((e) => {
|
|
391
324
|
// eslint-disable-next-line no-console
|
|
392
325
|
console.log(e);
|
|
393
326
|
});
|
|
394
327
|
}
|
|
395
328
|
}
|
|
396
|
-
_PegaAuth_instances = new WeakSet(),
|
|
397
|
-
const
|
|
398
|
-
|
|
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
|
+
});
|
|
399
408
|
}, _PegaAuth_buildAuthorizeUrl =
|
|
400
409
|
// For PKCE the authorize includes a code_challenge & code_challenge_method as well
|
|
401
410
|
async function _PegaAuth_buildAuthorizeUrl(state) {
|
|
402
|
-
const { clientId, redirectUri, authorizeUri,
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
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
|
+
}
|
|
407
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
|
|
408
422
|
if (sessionIndex) {
|
|
409
|
-
this.
|
|
423
|
+
__classPrivateFieldGet(this, _PegaAuth_dynState, "f").sessionIndexAttempts += 1;
|
|
410
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;
|
|
411
430
|
// Persist codeVerifier in session storage so it survives the redirects that are to follow
|
|
412
431
|
__classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_updateConfig).call(this);
|
|
413
|
-
if (!state) {
|
|
414
|
-
// Calc random state variable
|
|
415
|
-
buf = new Uint8Array(32);
|
|
416
|
-
window.crypto.getRandomValues(buf);
|
|
417
|
-
state = __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_base64UrlSafeEncode).call(this, buf);
|
|
418
|
-
}
|
|
419
432
|
// Trim alias to include just the real alias piece
|
|
420
|
-
const
|
|
433
|
+
const additionalScope = (userinfoUri ? '+profile' : '') + (appAlias ? `+app.alias.${appAlias.replace(/^app\//, '')}` : '');
|
|
434
|
+
const scope = bInfinity ? `openid+email${additionalScope}` : 'user_info';
|
|
421
435
|
// Add explicit creds if specified to try to avoid login popup
|
|
422
|
-
const
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
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
|
+
});
|
|
430
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);
|
|
431
800
|
}, _PegaAuth_sha256Hash = function _PegaAuth_sha256Hash(str) {
|
|
432
|
-
|
|
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));
|
|
433
809
|
}, _PegaAuth_encode64 = function _PegaAuth_encode64(buff) {
|
|
434
|
-
return
|
|
810
|
+
return btoa(new Uint8Array(buff).reduce((s, b) => s + String.fromCharCode(b), ''));
|
|
435
811
|
}, _PegaAuth_base64UrlSafeEncode = function _PegaAuth_base64UrlSafeEncode(buf) {
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
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) => {
|
|
440
824
|
return __classPrivateFieldGet(this, _PegaAuth_instances, "m", _PegaAuth_base64UrlSafeEncode).call(this, hashed);
|
|
441
|
-
})
|
|
825
|
+
})
|
|
826
|
+
.catch((error) => {
|
|
442
827
|
// eslint-disable-next-line no-console
|
|
443
|
-
console.
|
|
444
|
-
})
|
|
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;
|
|
445
842
|
};
|
|
446
843
|
export default PegaAuth;
|
|
447
844
|
//# sourceMappingURL=auth.js.map
|