@idea-ionic/auth 8.5.13 → 8.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/idea-ionic-auth.mjs +52 -52
- package/fesm2022/idea-ionic-auth.mjs.map +1 -1
- package/index.d.ts +358 -3
- package/package.json +13 -15
- package/esm2022/idea-ionic-auth.mjs +0 -5
- package/esm2022/public-api.mjs +0 -15
- package/esm2022/src/auth.routes.mjs +0 -22
- package/esm2022/src/auth.service.mjs +0 -521
- package/esm2022/src/commonPasswords.model.mjs +0 -1003
- package/esm2022/src/confirmPassword.page.mjs +0 -309
- package/esm2022/src/forgotPassword.page.mjs +0 -178
- package/esm2022/src/mfaChallenge.page.mjs +0 -163
- package/esm2022/src/newPassword.page.mjs +0 -210
- package/esm2022/src/okta.page.mjs +0 -150
- package/esm2022/src/passwordPolicy.component.mjs +0 -80
- package/esm2022/src/resendLink.page.mjs +0 -176
- package/esm2022/src/setupMFA/setupMFAButton.component.mjs +0 -60
- package/esm2022/src/setupMFA/setupMFAModal.component.mjs +0 -176
- package/esm2022/src/setupMFA.page.mjs +0 -83
- package/esm2022/src/signIn.page.mjs +0 -498
- package/esm2022/src/signUp.page.mjs +0 -376
- package/public-api.d.ts +0 -14
- package/src/auth.routes.d.ts +0 -2
- package/src/auth.service.d.ts +0 -152
- package/src/commonPasswords.model.d.ts +0 -1
- package/src/confirmPassword.page.d.ts +0 -26
- package/src/forgotPassword.page.d.ts +0 -13
- package/src/mfaChallenge.page.d.ts +0 -16
- package/src/newPassword.page.d.ts +0 -22
- package/src/okta.page.d.ts +0 -20
- package/src/passwordPolicy.component.d.ts +0 -8
- package/src/resendLink.page.d.ts +0 -14
- package/src/setupMFA/setupMFAButton.component.d.ts +0 -23
- package/src/setupMFA/setupMFAModal.component.d.ts +0 -16
- package/src/setupMFA.page.d.ts +0 -8
- package/src/signIn.page.d.ts +0 -36
- package/src/signUp.page.d.ts +0 -26
|
@@ -1,521 +0,0 @@
|
|
|
1
|
-
import { Injectable, inject } from '@angular/core';
|
|
2
|
-
import { AuthenticationDetails, CognitoUser, CognitoUserAttribute, CognitoUserPool, CognitoRefreshToken } from 'amazon-cognito-identity-js';
|
|
3
|
-
import { IDEAEnvironment, IDEAStorageService, IDEATranslationsService } from '@idea-ionic/common';
|
|
4
|
-
import { COMMON_PASSWORDS_TOP_1000 } from './commonPasswords.model';
|
|
5
|
-
import * as i0 from "@angular/core";
|
|
6
|
-
/**
|
|
7
|
-
* Cognito wrapper to manage the authentication flow.
|
|
8
|
-
*
|
|
9
|
-
* Note: in IDEA's Cognito users pools, the email is an alias of the username.
|
|
10
|
-
*/
|
|
11
|
-
export class IDEAAuthService {
|
|
12
|
-
constructor() {
|
|
13
|
-
this._env = inject(IDEAEnvironment);
|
|
14
|
-
this._translate = inject(IDEATranslationsService);
|
|
15
|
-
this._storage = inject(IDEAStorageService);
|
|
16
|
-
this.deviceKeyAttribute = 'custom:'.concat(this._env.idea.project);
|
|
17
|
-
this.userPool = new CognitoUserPool({
|
|
18
|
-
UserPoolId: this._env.aws.cognito.userPoolId,
|
|
19
|
-
ClientId: this._env.aws.cognito.userPoolClientId
|
|
20
|
-
});
|
|
21
|
-
this.mfaProjectName = this._env.idea.auth.title || this._env.idea.project;
|
|
22
|
-
this.passwordPolicy = this._env.idea.auth.passwordPolicy;
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Prepare the necessary structure to get authorized in Cognito.
|
|
26
|
-
*/
|
|
27
|
-
prepareAuthDetails(username, pwd) {
|
|
28
|
-
return new AuthenticationDetails({ Username: username, Password: pwd });
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Prepare the necessary structure to identify a Cognito user.
|
|
32
|
-
*/
|
|
33
|
-
prepareCognitoUser(username) {
|
|
34
|
-
return new CognitoUser({ Username: username, Pool: this.userPool });
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Prepare a user attribute (they are all strings) in Cognito's format.
|
|
38
|
-
*/
|
|
39
|
-
prepareUserAttribute(name, value) {
|
|
40
|
-
return new CognitoUserAttribute({ Name: name, Value: value });
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Perform a login through username and password.
|
|
44
|
-
*/
|
|
45
|
-
login(username, password) {
|
|
46
|
-
return new Promise((resolve, reject) => {
|
|
47
|
-
const user = this.prepareCognitoUser(username);
|
|
48
|
-
user.authenticateUser(this.prepareAuthDetails(username, password), {
|
|
49
|
-
onSuccess: () => resolve(this._env.idea.auth.forceLoginWithMFA ? LoginOutcomeActions.MFA_SETUP : LoginOutcomeActions.NONE),
|
|
50
|
-
onFailure: (err) => reject(err),
|
|
51
|
-
newPasswordRequired: () => {
|
|
52
|
-
this.challengeUsername = username;
|
|
53
|
-
this.challengePassword = password;
|
|
54
|
-
resolve(LoginOutcomeActions.NEW_PASSWORD);
|
|
55
|
-
},
|
|
56
|
-
totpRequired: () => {
|
|
57
|
-
this.challengeUsername = username;
|
|
58
|
-
this.challengePassword = password;
|
|
59
|
-
resolve(LoginOutcomeActions.MFA_CHALLENGE);
|
|
60
|
-
}
|
|
61
|
-
});
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Complete the new password flow in the authentication.
|
|
66
|
-
*/
|
|
67
|
-
confirmNewPassword(newPassword) {
|
|
68
|
-
return new Promise((resolve, reject) => {
|
|
69
|
-
const user = this.prepareCognitoUser(this.challengeUsername);
|
|
70
|
-
user.authenticateUser(this.prepareAuthDetails(this.challengeUsername, this.challengePassword), {
|
|
71
|
-
onSuccess: () => resolve(),
|
|
72
|
-
onFailure: (err) => reject(err),
|
|
73
|
-
newPasswordRequired: () => user.completeNewPasswordChallenge(newPassword, {}, {
|
|
74
|
-
onSuccess: () => {
|
|
75
|
-
this.challengeUsername = null;
|
|
76
|
-
this.challengePassword = null;
|
|
77
|
-
resolve();
|
|
78
|
-
},
|
|
79
|
-
onFailure: (err) => reject(err)
|
|
80
|
-
})
|
|
81
|
-
});
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
/**
|
|
85
|
-
* Complete the MFA challenge flow in the authentication.
|
|
86
|
-
*/
|
|
87
|
-
completeMFAChallenge(otpCode) {
|
|
88
|
-
return new Promise((resolve, reject) => {
|
|
89
|
-
const user = this.prepareCognitoUser(this.challengeUsername);
|
|
90
|
-
user.authenticateUser(this.prepareAuthDetails(this.challengeUsername, this.challengePassword), {
|
|
91
|
-
onSuccess: () => resolve(),
|
|
92
|
-
onFailure: (err) => reject(err),
|
|
93
|
-
totpRequired: (challengeName) => user.sendMFACode(otpCode, {
|
|
94
|
-
onSuccess: () => {
|
|
95
|
-
this.challengeUsername = null;
|
|
96
|
-
this.challengePassword = null;
|
|
97
|
-
resolve();
|
|
98
|
-
},
|
|
99
|
-
onFailure: err => reject(err)
|
|
100
|
-
}, challengeName)
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
/**
|
|
105
|
-
* Register a new user a set its default attributes.
|
|
106
|
-
*/
|
|
107
|
-
register(username, password, attributes) {
|
|
108
|
-
attributes = attributes || {};
|
|
109
|
-
return new Promise((resolve, reject) => {
|
|
110
|
-
// add attributes like the email address and the fullname
|
|
111
|
-
const attrs = [];
|
|
112
|
-
for (const prop in attributes)
|
|
113
|
-
if (attributes[prop])
|
|
114
|
-
attrs.push(this.prepareUserAttribute(prop, attributes[prop]));
|
|
115
|
-
// add the email, which is equal to the username for most of our Pools
|
|
116
|
-
if (!attributes.email)
|
|
117
|
-
attrs.push(this.prepareUserAttribute('email', username));
|
|
118
|
-
// register the new user to the pool
|
|
119
|
-
this.userPool.signUp(username, password, attrs, null, (err, res) => {
|
|
120
|
-
if (err)
|
|
121
|
-
return reject(err);
|
|
122
|
-
this.newAccountJustRegistered = username;
|
|
123
|
-
resolve(res.user);
|
|
124
|
-
});
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
/**
|
|
128
|
-
* In case a new account has just been registered, return the username.
|
|
129
|
-
*/
|
|
130
|
-
getNewAccountJustRegistered() {
|
|
131
|
-
return this.newAccountJustRegistered;
|
|
132
|
-
}
|
|
133
|
-
/**
|
|
134
|
-
* Confirm a new registration through the confirmation code sent by Cognito.
|
|
135
|
-
*/
|
|
136
|
-
confirmRegistration(username, code) {
|
|
137
|
-
return new Promise((resolve, reject) => {
|
|
138
|
-
this.prepareCognitoUser(username).confirmRegistration(code, true, (err) => err ? reject(err) : resolve());
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
|
-
/**
|
|
142
|
-
* Send again a confirmation code for a new registration.
|
|
143
|
-
*/
|
|
144
|
-
resendConfirmationCode(username) {
|
|
145
|
-
return new Promise((resolve, reject) => {
|
|
146
|
-
this.prepareCognitoUser(username).resendConfirmationCode((err) => (err ? reject(err) : resolve()));
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
/**
|
|
150
|
-
* Logout the currently signed-in user.
|
|
151
|
-
*/
|
|
152
|
-
logout(options) {
|
|
153
|
-
options = Object.assign({ global: false }, options);
|
|
154
|
-
return new Promise((resolve, reject) => {
|
|
155
|
-
// remove the refresh token previosly saved
|
|
156
|
-
this._storage.remove('AuthRefreshToken').then(() =>
|
|
157
|
-
// remove the optional auth details
|
|
158
|
-
this._storage.remove('AuthUserDetails').then(() => {
|
|
159
|
-
// get the user and the session
|
|
160
|
-
const user = this.userPool.getCurrentUser();
|
|
161
|
-
user.getSession(async (err) => {
|
|
162
|
-
// if the session is active, run the online sign-out; otherwise, only the local data has been deleted
|
|
163
|
-
if (err)
|
|
164
|
-
return resolve();
|
|
165
|
-
// if a reference to the device was saved, forget it
|
|
166
|
-
if (this._env.idea.auth.singleSimultaneousSession)
|
|
167
|
-
await this.setCurrentDeviceForProject(null);
|
|
168
|
-
// sign-out from the pool (terminate the current session or all the sessions)
|
|
169
|
-
if (options.global)
|
|
170
|
-
user.globalSignOut({ onSuccess: () => resolve(), onFailure: err => reject(err) });
|
|
171
|
-
else {
|
|
172
|
-
user.signOut();
|
|
173
|
-
resolve();
|
|
174
|
-
}
|
|
175
|
-
});
|
|
176
|
-
}));
|
|
177
|
-
});
|
|
178
|
-
}
|
|
179
|
-
/**
|
|
180
|
-
* Send a password reset request.
|
|
181
|
-
*/
|
|
182
|
-
forgotPassword(username) {
|
|
183
|
-
return new Promise((resolve, reject) => {
|
|
184
|
-
this.prepareCognitoUser(username).forgotPassword({
|
|
185
|
-
onSuccess: () => resolve(),
|
|
186
|
-
onFailure: (err) => reject(err)
|
|
187
|
-
});
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
/**
|
|
191
|
-
* Confirm a new password after a password reset request.
|
|
192
|
-
*/
|
|
193
|
-
confirmPassword(username, code, newPwd) {
|
|
194
|
-
return new Promise((resolve, reject) => {
|
|
195
|
-
this.prepareCognitoUser(username).confirmPassword(code, newPwd, {
|
|
196
|
-
onSuccess: () => resolve(),
|
|
197
|
-
onFailure: (err) => reject(err)
|
|
198
|
-
});
|
|
199
|
-
});
|
|
200
|
-
}
|
|
201
|
-
/**
|
|
202
|
-
* Gets the URL for enabling MFA. This URL can be used to generate a QR Code to read with an authenticator app.
|
|
203
|
-
*/
|
|
204
|
-
getURLForEnablingMFA() {
|
|
205
|
-
return new Promise((resolve, reject) => {
|
|
206
|
-
const user = this.userPool.getCurrentUser();
|
|
207
|
-
if (!user)
|
|
208
|
-
return reject();
|
|
209
|
-
user.getSession((err) => {
|
|
210
|
-
if (err)
|
|
211
|
-
return reject(err);
|
|
212
|
-
user.associateSoftwareToken({
|
|
213
|
-
associateSecretCode: (secretCode) => resolve(`otpauth://totp/${encodeURI(this.mfaProjectName)}?secret=${secretCode}`),
|
|
214
|
-
onFailure: (err) => reject(err)
|
|
215
|
-
});
|
|
216
|
-
});
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
|
-
/**
|
|
220
|
-
* Check whether the user has MFA enabled.
|
|
221
|
-
*/
|
|
222
|
-
checkIfUserHasMFAEnabled(bypassCache = false) {
|
|
223
|
-
return new Promise((resolve, reject) => {
|
|
224
|
-
const user = this.userPool.getCurrentUser();
|
|
225
|
-
if (!user)
|
|
226
|
-
return reject();
|
|
227
|
-
user.getSession((err) => {
|
|
228
|
-
if (err)
|
|
229
|
-
return reject(err);
|
|
230
|
-
user.getUserData((err, data) => {
|
|
231
|
-
if (err)
|
|
232
|
-
return reject(err);
|
|
233
|
-
const isMFAEnabled = !!(data.UserMFASettingList && data.UserMFASettingList.includes('SOFTWARE_TOKEN_MFA'));
|
|
234
|
-
resolve(isMFAEnabled);
|
|
235
|
-
}, { bypassCache });
|
|
236
|
-
});
|
|
237
|
-
});
|
|
238
|
-
}
|
|
239
|
-
/**
|
|
240
|
-
* Configure a MFA device for the user.
|
|
241
|
-
*/
|
|
242
|
-
setMFADevice(otp, mfaDeviceName, enabled = true, preferred = true) {
|
|
243
|
-
return new Promise((resolve, reject) => {
|
|
244
|
-
const user = this.userPool.getCurrentUser();
|
|
245
|
-
if (!user)
|
|
246
|
-
return reject();
|
|
247
|
-
user.getSession((err) => {
|
|
248
|
-
if (err)
|
|
249
|
-
return reject(err);
|
|
250
|
-
user.verifySoftwareToken(otp, mfaDeviceName, {
|
|
251
|
-
onSuccess: () => user.setUserMfaPreference(null, { Enabled: enabled, PreferredMfa: preferred }, (err) => err ? reject(err) : resolve()),
|
|
252
|
-
onFailure: (err) => reject(err)
|
|
253
|
-
});
|
|
254
|
-
});
|
|
255
|
-
});
|
|
256
|
-
}
|
|
257
|
-
/**
|
|
258
|
-
* Enable a new MFA device for the user by inserting an OTP code generated by it.
|
|
259
|
-
*/
|
|
260
|
-
enableMFA(otp, mfaDeviceName = 'default') {
|
|
261
|
-
return this.setMFADevice(otp, mfaDeviceName, true, true);
|
|
262
|
-
}
|
|
263
|
-
/**
|
|
264
|
-
* Disable MFA for a user by inserting an OTP code generated by it.
|
|
265
|
-
*/
|
|
266
|
-
disableMFA(otp, mfaDeviceName = 'default') {
|
|
267
|
-
return this.setMFADevice(otp, mfaDeviceName, false, false);
|
|
268
|
-
}
|
|
269
|
-
/**
|
|
270
|
-
* Check if a user is currently authenticated.
|
|
271
|
-
* @param offlineAllowed if set and if offline, skip authentication and retrieve data locally
|
|
272
|
-
* @param getFreshIdTokenOnExp cb function to execute when the idToken is refreshed
|
|
273
|
-
*/
|
|
274
|
-
isAuthenticated(offlineAllowed, getFreshIdTokenOnExp) {
|
|
275
|
-
return new Promise((resolve, reject) => {
|
|
276
|
-
if (offlineAllowed && !navigator.onLine) {
|
|
277
|
-
this._storage.get('AuthUserDetails').then(userDetails => resolve({ idToken: null, userDetails }));
|
|
278
|
-
// re-execute the method when back online, so that you can retrieve a token to make requests
|
|
279
|
-
window.addEventListener('online', () => this.isAuthenticated(true, getFreshIdTokenOnExp)
|
|
280
|
-
// set the new token as if it was refreshed
|
|
281
|
-
.then(result => getFreshIdTokenOnExp(result.idToken)));
|
|
282
|
-
}
|
|
283
|
-
else {
|
|
284
|
-
const user = this.userPool.getCurrentUser();
|
|
285
|
-
if (!user)
|
|
286
|
-
return reject();
|
|
287
|
-
user.getSession((err, session) => {
|
|
288
|
-
if (err)
|
|
289
|
-
return reject(err);
|
|
290
|
-
user.getUserData((err, data) => {
|
|
291
|
-
if (err)
|
|
292
|
-
return reject(err);
|
|
293
|
-
const isMFAEnabled = !!(data.UserMFASettingList && data.UserMFASettingList.includes('SOFTWARE_TOKEN_MFA'));
|
|
294
|
-
if (!isMFAEnabled && this._env.idea.auth.forceLoginWithMFA)
|
|
295
|
-
return reject(new Error(LoginOutcomeActions.MFA_SETUP));
|
|
296
|
-
user.getUserAttributes((e, attributes) => {
|
|
297
|
-
if (e)
|
|
298
|
-
return reject(e);
|
|
299
|
-
// remap user attributes
|
|
300
|
-
const userDetails = {};
|
|
301
|
-
attributes.forEach((a) => (userDetails[a.getName()] = a.getValue()));
|
|
302
|
-
// add the user's groups to the attributes
|
|
303
|
-
const sessionInfo = session.getAccessToken().decodePayload();
|
|
304
|
-
const groups = sessionInfo['cognito:groups'] || [];
|
|
305
|
-
userDetails['groups'] = groups;
|
|
306
|
-
// run some checks considering the user's groups and devices (based on the project's configuration)
|
|
307
|
-
this.runPostAuthChecks(userDetails, err => {
|
|
308
|
-
// in case some check failed, reject the authorisation flow
|
|
309
|
-
if (err)
|
|
310
|
-
return reject(err);
|
|
311
|
-
// (async) save the refresh token so it can be accessed by other procedures
|
|
312
|
-
this._storage.set('AuthRefreshToken', session.getRefreshToken().getToken());
|
|
313
|
-
// set a timer to manage the autorefresh of the idToken (through the refreshToken)
|
|
314
|
-
setTimeout(() => this.refreshSession(user, session.getRefreshToken().getToken(), getFreshIdTokenOnExp), 15 * 60 * 1000); // every 15 minutes
|
|
315
|
-
// (async) if offlineAllowed, save data locally, to use it next time we'll be offline
|
|
316
|
-
if (offlineAllowed)
|
|
317
|
-
this._storage.set('AuthUserDetails', userDetails);
|
|
318
|
-
// return the idToken (to use with API)
|
|
319
|
-
resolve({ idToken: session.getIdToken().getJwtToken(), userDetails });
|
|
320
|
-
});
|
|
321
|
-
});
|
|
322
|
-
}, { bypassCache: true });
|
|
323
|
-
});
|
|
324
|
-
}
|
|
325
|
-
});
|
|
326
|
-
}
|
|
327
|
-
/**
|
|
328
|
-
* Helper to refresh the session every N minutes.
|
|
329
|
-
*/
|
|
330
|
-
refreshSession(user, refreshToken, callback) {
|
|
331
|
-
user.refreshSession(new CognitoRefreshToken({ RefreshToken: refreshToken }), (err, session) => {
|
|
332
|
-
if (err) {
|
|
333
|
-
// try again in 1 minute
|
|
334
|
-
setTimeout(() => this.refreshSession(user, refreshToken, callback), 1 * 60 * 1000);
|
|
335
|
-
}
|
|
336
|
-
else {
|
|
337
|
-
// (async) save the refresh token so it can be accessed by other procedures
|
|
338
|
-
this._storage.set('AuthRefreshToken', session.getRefreshToken().getToken());
|
|
339
|
-
// repeat every 15 minutes
|
|
340
|
-
setTimeout(() => this.refreshSession(user, session.getRefreshToken().getToken(), callback), 15 * 60 * 1000);
|
|
341
|
-
// run the callback action, if set
|
|
342
|
-
if (callback)
|
|
343
|
-
callback(session.getIdToken().getJwtToken());
|
|
344
|
-
}
|
|
345
|
-
});
|
|
346
|
-
}
|
|
347
|
-
/**
|
|
348
|
-
* Run some post-auth checks, based on the users groups and on the app's configuration:
|
|
349
|
-
* - users in the Cognito's "admins" grup skip all the following rules.
|
|
350
|
-
* - users in the Cognito's "robots" group can't sign-into front-ends (they serve only back-end purposes).
|
|
351
|
-
* - if `env.idea.auth.singleSimultaneousSession` is on, make sure there is only one active session per user.
|
|
352
|
-
*/
|
|
353
|
-
runPostAuthChecks(userDetails, callback) {
|
|
354
|
-
const groups = userDetails['groups'];
|
|
355
|
-
// skip checks if the user is in the "admins" group
|
|
356
|
-
const isAdmin = groups.some(x => x === 'admins');
|
|
357
|
-
if (isAdmin)
|
|
358
|
-
return callback();
|
|
359
|
-
// users in the "robots" group can't sign-into front-ends (they serve only back-end purposes)
|
|
360
|
-
const isRobot = groups.some(x => x === 'robots');
|
|
361
|
-
if (isRobot)
|
|
362
|
-
return callback(new Error('ROBOT_USER'));
|
|
363
|
-
// in case the project limits each account to only one simultaneous session, run a check
|
|
364
|
-
if (this._env.idea.auth.singleSimultaneousSession)
|
|
365
|
-
return this.checkForSimultaneousSessions(userDetails, callback);
|
|
366
|
-
// otherwise, we're done
|
|
367
|
-
callback();
|
|
368
|
-
}
|
|
369
|
-
/**
|
|
370
|
-
* Check whether the user signed-into multiple devices.
|
|
371
|
-
*/
|
|
372
|
-
async checkForSimultaneousSessions(userDetails, callback) {
|
|
373
|
-
// get or create a key for the current device (~random)
|
|
374
|
-
let currentDeviceKey = await this._storage.get('AuthDeviceKey');
|
|
375
|
-
if (!currentDeviceKey) {
|
|
376
|
-
const randomKey = Math.random().toString(36).substring(10);
|
|
377
|
-
currentDeviceKey = randomKey.concat(String(Date.now()));
|
|
378
|
-
await this._storage.set('AuthDeviceKey', currentDeviceKey);
|
|
379
|
-
}
|
|
380
|
-
// check whether the last device to sign-into this project (if any) is the current one
|
|
381
|
-
const lastDeviceToSignIntoThisProject = userDetails[this.deviceKeyAttribute];
|
|
382
|
-
// if it's the first user's device to sign-in, save the reference in Cognito and resolve
|
|
383
|
-
if (!lastDeviceToSignIntoThisProject) {
|
|
384
|
-
this.setCurrentDeviceForProject(currentDeviceKey)
|
|
385
|
-
.then(() => callback())
|
|
386
|
-
.catch(() => callback(new Error('CANT_SET_DEVICE')));
|
|
387
|
-
// if the device didn't change, resolve
|
|
388
|
-
}
|
|
389
|
-
else if (lastDeviceToSignIntoThisProject === currentDeviceKey)
|
|
390
|
-
callback();
|
|
391
|
-
// othwerwise, report there is more than one simultaneous session
|
|
392
|
-
else
|
|
393
|
-
callback(new Error('SIMULTANEOUS_SESSION'));
|
|
394
|
-
}
|
|
395
|
-
/**
|
|
396
|
-
* Set (or reset) the current user's device (by key) in the current project (stored in Cognito).
|
|
397
|
-
*/
|
|
398
|
-
setCurrentDeviceForProject(deviceKey) {
|
|
399
|
-
const attributes = {};
|
|
400
|
-
// note: an empty string will remove the attribute from Cognito
|
|
401
|
-
attributes[this.deviceKeyAttribute] = deviceKey || '';
|
|
402
|
-
return this.updateUserAttributes(attributes);
|
|
403
|
-
}
|
|
404
|
-
/**
|
|
405
|
-
* Update the currently logged in user's attributes.
|
|
406
|
-
*/
|
|
407
|
-
updateUserAttributes(attributes) {
|
|
408
|
-
return new Promise((resolve, reject) => {
|
|
409
|
-
// prepare the attributes we want to change
|
|
410
|
-
const attrs = new Array();
|
|
411
|
-
for (const prop in attributes)
|
|
412
|
-
if (attributes[prop] !== undefined)
|
|
413
|
-
attrs.push(this.prepareUserAttribute(prop, attributes[prop]));
|
|
414
|
-
const user = this.userPool.getCurrentUser();
|
|
415
|
-
if (!user)
|
|
416
|
-
return reject();
|
|
417
|
-
// we need to get the session before to make changes
|
|
418
|
-
user.getSession((err) => {
|
|
419
|
-
if (err)
|
|
420
|
-
reject(err);
|
|
421
|
-
else
|
|
422
|
-
user.updateAttributes(attrs, (e) => (e ? reject(e) : resolve()));
|
|
423
|
-
});
|
|
424
|
-
});
|
|
425
|
-
}
|
|
426
|
-
/**
|
|
427
|
-
* Validate the password against the policy set in the environments configuration.
|
|
428
|
-
* In case there are errors, they are returned as an array of strings.
|
|
429
|
-
*/
|
|
430
|
-
validatePasswordAgainstPolicy(password) {
|
|
431
|
-
const errors = [];
|
|
432
|
-
if (password?.trim().length < this.passwordPolicy.minLength)
|
|
433
|
-
errors.push('MIN_LENGTH');
|
|
434
|
-
if (this.passwordPolicy.requireDigits && !/\d/.test(password))
|
|
435
|
-
errors.push('REQUIRE_DIGITS');
|
|
436
|
-
if (this.passwordPolicy.requireLowercase && !/[a-z]/.test(password))
|
|
437
|
-
errors.push('REQUIRE_LOWERCASE');
|
|
438
|
-
if (this.passwordPolicy.requireSymbols && !/[\^\$\*\.\_\~\`\+\=@\!\?\>\<\:\;\\\,\#\%\&]/.test(password))
|
|
439
|
-
errors.push('REQUIRE_SYMBOLS');
|
|
440
|
-
if (this.passwordPolicy.requireUppercase && !/[A-Z]/.test(password))
|
|
441
|
-
errors.push('REQUIRE_UPPERCASE');
|
|
442
|
-
return errors;
|
|
443
|
-
}
|
|
444
|
-
/**
|
|
445
|
-
* Validate the password against offline and online databases, to avoid common and exploited passwords.
|
|
446
|
-
*/
|
|
447
|
-
async validatePasswordAgainstDatabases(password, customStringsToAvoid) {
|
|
448
|
-
const errors = [];
|
|
449
|
-
let pwd = (password || '').trim().toLowerCase();
|
|
450
|
-
const pwdContains = (str) => pwd.includes((str || '').trim().toLowerCase());
|
|
451
|
-
const projectReferencesToAvoid = [
|
|
452
|
-
this._env.idea.project,
|
|
453
|
-
this._env.idea.auth.title,
|
|
454
|
-
this._translate._('COMMON.APP_NAME')
|
|
455
|
-
];
|
|
456
|
-
if (projectReferencesToAvoid.some(x => pwdContains(x)))
|
|
457
|
-
errors.push('COMMON_PASSWORD_PROJECT');
|
|
458
|
-
if (customStringsToAvoid && customStringsToAvoid.some(x => pwdContains(x)))
|
|
459
|
-
errors.push('COMMON_PASSWORD_CUSTOM');
|
|
460
|
-
if (COMMON_PASSWORDS_TOP_1000.some(x => pwdContains(x)))
|
|
461
|
-
errors.push('COMMON_PASSWORD_INTERNAL');
|
|
462
|
-
if (errors.length === 0) {
|
|
463
|
-
const pwdSHA1 = await SHA1(password);
|
|
464
|
-
if (pwdSHA1) {
|
|
465
|
-
const res = await fetch('https://api.pwnedpasswords.com/range/'.concat(pwdSHA1.slice(0, 5)));
|
|
466
|
-
if (res.status === 200) {
|
|
467
|
-
const pwnedPasswordsRawSuffixes = await res.text();
|
|
468
|
-
if (pwnedPasswordsRawSuffixes.includes(pwdSHA1.slice(5)))
|
|
469
|
-
errors.push('COMMON_PASSWORD_EXTERNAL');
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
return errors;
|
|
474
|
-
}
|
|
475
|
-
/**
|
|
476
|
-
* Get a complete password policy pattern, based on the environments configuration, to use on password input fields.
|
|
477
|
-
* Note: some of the symbols couldn't be included because unsupported by the input[pattern] attribute.
|
|
478
|
-
*/
|
|
479
|
-
getPasswordPolicyPatternForInput() {
|
|
480
|
-
let pattern = '';
|
|
481
|
-
if (this.passwordPolicy.requireDigits)
|
|
482
|
-
pattern += `(?=.*[0-9])`;
|
|
483
|
-
if (this.passwordPolicy.requireLowercase)
|
|
484
|
-
pattern += `(?=.*[a-z])`;
|
|
485
|
-
if (this.passwordPolicy.requireSymbols)
|
|
486
|
-
pattern += `(?=.*[\^\$\*\.\_\~\`\+\=@\!\?\>\<\:\;\\\,\#\%\&])`;
|
|
487
|
-
if (this.passwordPolicy.requireUppercase)
|
|
488
|
-
pattern += `(?=.*[A-Z])`;
|
|
489
|
-
pattern += `.{${this.passwordPolicy.minLength},}`;
|
|
490
|
-
return pattern;
|
|
491
|
-
}
|
|
492
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: IDEAAuthService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
493
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: IDEAAuthService, providedIn: 'root' }); }
|
|
494
|
-
}
|
|
495
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: IDEAAuthService, decorators: [{
|
|
496
|
-
type: Injectable,
|
|
497
|
-
args: [{ providedIn: 'root' }]
|
|
498
|
-
}], ctorParameters: () => [] });
|
|
499
|
-
/**
|
|
500
|
-
* The possible actions following a successful login.
|
|
501
|
-
*/
|
|
502
|
-
export var LoginOutcomeActions;
|
|
503
|
-
(function (LoginOutcomeActions) {
|
|
504
|
-
LoginOutcomeActions["NONE"] = "none";
|
|
505
|
-
LoginOutcomeActions["NEW_PASSWORD"] = "newPassword";
|
|
506
|
-
LoginOutcomeActions["MFA_CHALLENGE"] = "mfaChallenge";
|
|
507
|
-
LoginOutcomeActions["MFA_SETUP"] = "mfaSetup";
|
|
508
|
-
})(LoginOutcomeActions || (LoginOutcomeActions = {}));
|
|
509
|
-
/**
|
|
510
|
-
* Get the SHA1 hex uppercase hash of a string, using web crypto.
|
|
511
|
-
*/
|
|
512
|
-
const SHA1 = async (str) => {
|
|
513
|
-
if (!window.crypto)
|
|
514
|
-
return null;
|
|
515
|
-
const msgUint8 = new TextEncoder().encode(str);
|
|
516
|
-
const hashBuffer = await window.crypto.subtle.digest('SHA-1', msgUint8);
|
|
517
|
-
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
518
|
-
const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
|
|
519
|
-
return hashHex.toUpperCase();
|
|
520
|
-
};
|
|
521
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0aC5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vbW9kdWxlcy9hdXRoL3NyYy9hdXRoLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDbkQsT0FBTyxFQUNMLHFCQUFxQixFQUNyQixXQUFXLEVBQ1gsb0JBQW9CLEVBQ3BCLGVBQWUsRUFDZixtQkFBbUIsRUFJcEIsTUFBTSw0QkFBNEIsQ0FBQztBQUNwQyxPQUFPLEVBQUUsZUFBZSxFQUFFLGtCQUFrQixFQUFFLHVCQUF1QixFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFFbEcsT0FBTyxFQUFFLHlCQUF5QixFQUFFLE1BQU0seUJBQXlCLENBQUM7O0FBRXBFOzs7O0dBSUc7QUFFSCxNQUFNLE9BQU8sZUFBZTtJQXFCMUI7UUFwQlUsU0FBSSxHQUFHLE1BQU0sQ0FBQyxlQUFlLENBQUMsQ0FBQztRQUMvQixlQUFVLEdBQUcsTUFBTSxDQUFDLHVCQUF1QixDQUFDLENBQUM7UUFDN0MsYUFBUSxHQUFHLE1BQU0sQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDO1FBbUI5QyxJQUFJLENBQUMsa0JBQWtCLEdBQUcsU0FBUyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUNuRSxJQUFJLENBQUMsUUFBUSxHQUFHLElBQUksZUFBZSxDQUFDO1lBQ2xDLFVBQVUsRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsVUFBVTtZQUM1QyxRQUFRLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLGdCQUFnQjtTQUNqRCxDQUFDLENBQUM7UUFDSCxJQUFJLENBQUMsY0FBYyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxL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QUFHLEtBQUssRUFBRSxHQUFXLEVBQTBCLEVBQUU7SUFDekQsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNO1FBQUUsT0FBTyxJQUFJLENBQUM7SUFDaEMsTUFBTSxRQUFRLEdBQUcsSUFBSSxXQUFXLEVBQUUsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDL0MsTUFBTSxVQUFVLEdBQUcsTUFBTSxNQUFNLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsT0FBTyxFQUFFLFFBQVEsQ0FBQyxDQUFDO0lBQ3hFLE1BQU0sU0FBUyxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxVQUFVLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQztJQUN6RCxNQUFNLE9BQU8sR0FBRyxTQUFTLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQzdFLE9BQU8sT0FBTyxDQUFDLFdBQVcsRUFBRSxDQUFDO0FBQy9CLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGFibGUsIGluamVjdCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHtcbiAgQXV0aGVudGljYXRpb25EZXRhaWxzLFxuICBDb2duaXRvVXNlcixcbiAgQ29nbml0b1VzZXJBdHRyaWJ1dGUsXG4gIENvZ25pdG9Vc2VyUG9vbCxcbiAgQ29nbml0b1JlZnJlc2hUb2tlbixcbiAgQ29nbml0b1VzZXJTZXNzaW9uLFxuICBJU2lnblVwUmVzdWx0LFxuICBDaGFsbGVuZ2VOYW1lXG59IGZyb20gJ2FtYXpvbi1jb2duaXRvLWlkZW50aXR5LWpzJztcbmltcG9ydCB7IElERUFFbnZpcm9ubWVudCwgSURFQVN0b3JhZ2VTZXJ2aWNlLCBJREVBVHJhbnNsYXRpb25zU2VydmljZSB9IGZyb20gJ0BpZGVhLWlvbmljL2NvbW1vbic7XG5cbmltcG9ydCB7IENPTU1PTl9QQVNTV09SRFNfVE9QXzEwMDAgfSBmcm9tICcuL2NvbW1vblBhc3N3b3Jkcy5tb2RlbCc7XG5cbi8qKlxuICogQ29nbml0byB3cmFwcGVyIHRvIG1hbmFnZSB0aGUgYXV0aGVudGljYXRpb24gZmxvdy5cbiAqXG4gKiBOb3RlOiBpbiBJREVBJ3MgQ29nbml0byB1c2VycyBwb29scywgdGhlIGVtYWlsIGlzIGFuIGFsaWFzIG9mIHRoZSB1c2VybmFtZS5cbiAqL1xuQEluamVjdGFibGUoeyBwcm92aWRlZEluOiAncm9vdCcgfSlcbmV4cG9ydCBjbGFzcyBJREVBQXV0aFNlcnZpY2Uge1xuICBwcm90ZWN0ZWQgX2VudiA9IGluamVjdChJREVBRW52aXJvbm1lbnQpO1xuICBwcm90ZWN0ZWQgX3RyYW5zbGF0ZSA9IGluamVjdChJREVBVHJhbnNsYXRpb25zU2VydmljZSk7XG4gIHByb3RlY3RlZCBfc3RvcmFnZSA9IGluamVjdChJREVBU3RvcmFnZVNlcnZpY2UpO1xuXG4gIC8qKlxuICAgKiBUaGUgbmFtZSBvZiB0aGUgQ29nbml0bydzIHVzZXIgYXR0cmlidXRlIHdoaWNoIGNvbnRhaW5zIHRoZSBrZXkgb2YgdGhlIGxhc3QgZGV2aWNlIHRvIGxvZ2luIGluIHRoaXMgcHJvamVjdC5cbiAgICovXG4gIHByb3RlY3RlZCBkZXZpY2VLZXlBdHRyaWJ1dGU6IHN0cmluZztcblxuICBwcml2YXRlIHVzZXJQb29sOiBDb2duaXRvVXNlclBvb2w7XG5cbiAgY2hhbGxlbmdlVXNlcm5hbWU6IHN0cmluZztcbiAgcHJpdmF0ZSBjaGFsbGVuZ2VQYXNzd29yZDogc3RyaW5nO1xuXG4gIHByaXZhdGUgbmV3QWNjb3VudEp1c3RSZWdpc3RlcmVkOiBzdHJpbmc7XG5cbiAgcHJpdmF0ZSBtZmFQcm9qZWN0TmFtZTogc3RyaW5nO1xuXG4gIHByaXZhdGUgcGFzc3dvcmRQb2xpY3k6IGFueTtcblxuICBjb25zdHJ1Y3RvcigpIHtcbiAgICB0aGlzLmRldmljZUtleUF0dHJpYnV0ZSA9ICdjdXN0b206Jy5jb25jYXQodGhpcy5fZW52LmlkZWEucHJvamVjdCk7XG4gICAgdGhpcy51c2VyUG9vbCA9IG5ldyBDb2duaXRvVXNlclBvb2woe1xuICAgICAgVXNlclBvb2xJZDogdGhpcy5fZW52LmF3cy5jb2duaXRvLnVzZXJQb29sSWQsXG4gICAgICBDbGllbnRJZDogdGhpcy5fZW52LmF3cy5jb2duaXRvLnVzZXJQb29sQ2xpZW50SWRcbiAgICB9KTtcbiAgICB0aGlzLm1mYVByb2plY3ROYW1lID0gdGhpcy5fZW52LmlkZWEuYXV0aC50aXRsZSB8fCB0aGlzLl9lbnYuaWRlYS5wcm9qZWN0O1xuICAgIHRoaXMucGFzc3dvcmRQb2xpY3kgPSB0aGlzLl9lbnYuaWRlYS5hdXRoLnBhc3N3b3JkUG9saWN5O1xuICB9XG5cbiAgLyoqXG4gICAqIFByZXBhcmUgdGhlIG5lY2Vzc2FyeSBzdHJ1Y3R1cmUgdG8gZ2V0IGF1dGhvcml6ZWQgaW4gQ29nbml0by5cbiAgICovXG4gIHByaXZhdGUgcHJlcGFyZUF1dGhEZXRhaWxzKHVzZXJuYW1lOiBzdHJpbmcsIHB3ZDogc3RyaW5nKTogQXV0aGVudGljYXRpb25EZXRhaWxzIHtcbiAgICByZXR1cm4gbmV3IEF1dGhlbnRpY2F0aW9uRGV0YWlscyh7IFVzZXJuYW1lOiB1c2VybmFtZSwgUGFzc3dvcmQ6IHB3ZCB9KTtcbiAgfVxuICAvKipcbiAgICogUHJlcGFyZSB0aGUgbmVjZXNzYXJ5IHN0cnVjdHVyZSB0byBpZGVudGlmeSBhIENvZ25pdG8gdXNlci5cbiAgICovXG4gIHByZXBhcmVDb2duaXRvVXNlcih1c2VybmFtZTogc3RyaW5nKTogQ29nbml0b1VzZXIge1xuICAgIHJldHVybiBuZXcgQ29nbml0b1VzZXIoeyBVc2VybmFtZTogdXNlcm5hbWUsIFBvb2w6IHRoaXMudXNlclBvb2wgfSk7XG4gIH1cbiAgLyoqXG4gICAqIFByZXBhcmUgYSB1c2VyIGF0dHJpYnV0ZSAodGhleSBhcmUgYWxsIHN0cmluZ3MpIGluIENvZ25pdG8ncyBmb3JtYXQuXG4gICAqL1xuICBwcml2YXRlIHByZXBhcmVVc2VyQXR0cmlidXRlKG5hbWU6IHN0cmluZywgdmFsdWU6IHN0cmluZyk6IENvZ25pdG9Vc2VyQXR0cmlidXRlIHtcbiAgICByZXR1cm4gbmV3IENvZ25pdG9Vc2VyQXR0cmlidXRlKHsgTmFtZTogbmFtZSwgVmFsdWU6IHZhbHVlIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFBlcmZvcm0gYSBsb2dpbiB0aHJvdWdoIHVzZXJuYW1lIGFuZCBwYXNzd29yZC5cbiAgICovXG4gIGxvZ2luKHVzZXJuYW1lOiBzdHJpbmcsIHBhc3N3b3JkOiBzdHJpbmcpOiBQcm9taXNlPExvZ2luT3V0Y29tZUFjdGlvbnM+IHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCk6IHZvaWQgPT4ge1xuICAgICAgY29uc3QgdXNlciA9IHRoaXMucHJlcGFyZUNvZ25pdG9Vc2VyKHVzZXJuYW1lKTtcbiAgICAgIHVzZXIuYXV0aGVudGljYXRlVXNlcih0aGlzLnByZXBhcmVBdXRoRGV0YWlscyh1c2VybmFtZSwgcGFzc3dvcmQpLCB7XG4gICAgICAgIG9uU3VjY2VzczogKCk6IHZvaWQgPT5cbiAgICAgICAgICByZXNvbHZlKHRoaXMuX2Vudi5pZGVhLmF1dGguZm9yY2VMb2dpbldpdGhNRkEgPyBMb2dpbk91dGNvbWVBY3Rpb25zLk1GQV9TRVRVUCA6IExvZ2luT3V0Y29tZUFjdGlvbnMuTk9ORSksXG4gICAgICAgIG9uRmFpbHVyZTogKGVycjogRXJyb3IpOiB2b2lkID0+IHJlamVjdChlcnIpLFxuICAgICAgICBuZXdQYXNzd29yZFJlcXVpcmVkOiAoKTogdm9pZCA9PiB7XG4gICAgICAgICAgdGhpcy5jaGFsbGVuZ2VVc2VybmFtZSA9IHVzZXJuYW1lO1xuICAgICAgICAgIHRoaXMuY2hhbGxlbmdlUGFzc3dvcmQgPSBwYXNzd29yZDtcbiAgICAgICAgICByZXNvbHZlKExvZ2luT3V0Y29tZUFjdGlvbnMuTkVXX1BBU1NXT1JEKTtcbiAgICAgICAgfSxcbiAgICAgICAgdG90cFJlcXVpcmVkOiAoKTogdm9pZCA9PiB7XG4gICAgICAgICAgdGhpcy5jaGFsbGVuZ2VVc2VybmFtZSA9IHVzZXJuYW1lO1xuICAgICAgICAgIHRoaXMuY2hhbGxlbmdlUGFzc3dvcmQgPSBwYXNzd29yZDtcbiAgICAgICAgICByZXNvbHZlKExvZ2luT3V0Y29tZUFjdGlvbnMuTUZBX0NIQUxMRU5HRSk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG4gIC8qKlxuICAgKiBDb21wbGV0ZSB0aGUgbmV3IHBhc3N3b3JkIGZsb3cgaW4gdGhlIGF1dGhlbnRpY2F0aW9uLlxuICAgKi9cbiAgY29uZmlybU5ld1Bhc3N3b3JkKG5ld1Bhc3N3b3JkOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCk6IHZvaWQgPT4ge1xuICAgICAgY29uc3QgdXNlciA9IHRoaXMucHJlcGFyZUNvZ25pdG9Vc2VyKHRoaXMuY2hhbGxlbmdlVXNlcm5hbWUpO1xuICAgICAgdXNlci5hdXRoZW50aWNhdGVVc2VyKHRoaXMucHJlcGFyZUF1dGhEZXRhaWxzKHRoaXMuY2hhbGxlbmdlVXNlcm5hbWUsIHRoaXMuY2hhbGxlbmdlUGFzc3dvcmQpLCB7XG4gICAgICAgIG9uU3VjY2VzczogKCk6IHZvaWQgPT4gcmVzb2x2ZSgpLFxuICAgICAgICBvbkZhaWx1cmU6IChlcnI6IEVycm9yKTogdm9pZCA9PiByZWplY3QoZXJyKSxcbiAgICAgICAgbmV3UGFzc3dvcmRSZXF1aXJlZDogKCk6IHZvaWQgPT5cbiAgICAgICAgICB1c2VyLmNvbXBsZXRlTmV3UGFzc3dvcmRDaGFsbGVuZ2UoXG4gICAgICAgICAgICBuZXdQYXNzd29yZCxcbiAgICAgICAgICAgIHt9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICBvblN1Y2Nlc3M6ICgpOiB2b2lkID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLmNoYWxsZW5nZVVzZXJuYW1lID0gbnVsbDtcbiAgICAgICAgICAgICAgICB0aGlzLmNoYWxsZW5nZVBhc3N3b3JkID0gbnVsbDtcbiAgICAgICAgICAgICAgICByZXNvbHZlKCk7XG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIG9uRmFpbHVyZTogKGVycjogRXJyb3IpOiB2b2lkID0+IHJlamVjdChlcnIpXG4gICAgICAgICAgICB9XG4gICAgICAgICAgKVxuICAgICAgfSk7XG4gICAgfSk7XG4gIH1cbiAgLyoqXG4gICAqICBDb21wbGV0ZSB0aGUgTUZBIGNoYWxsZW5nZSBmbG93IGluIHRoZSBhdXRoZW50aWNhdGlvbi5cbiAgICovXG4gIGNvbXBsZXRlTUZBQ2hhbGxlbmdlKG90cENvZGU6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KTogdm9pZCA9PiB7XG4gICAgICBjb25zdCB1c2VyID0gdGhpcy5wcmVwYXJlQ29nbml0b1VzZXIodGhpcy5jaGFsbGVuZ2VVc2VybmFtZSk7XG4gICAgICB1c2VyLmF1dGhlbnRpY2F0ZVVzZXIodGhpcy5wcmVwYXJlQXV0aERldGFpbHModGhpcy5jaGFsbGVuZ2VVc2VybmFtZSwgdGhpcy5jaGFsbGVuZ2VQYXNzd29yZCksIHtcbiAgICAgICAgb25TdWNjZXNzOiAoKTogdm9pZCA9PiByZXNvbHZlKCksXG4gICAgICAgIG9uRmFpbHVyZTogKGVycjogRXJyb3IpOiB2b2lkID0+IHJlamVjdChlcnIpLFxuICAgICAgICB0b3RwUmVxdWlyZWQ6IChjaGFsbGVuZ2VOYW1lOiBDaGFsbGVuZ2VOYW1lKTogdm9pZCA9PlxuICAgICAgICAgIHVzZXIuc2VuZE1GQUNvZGUoXG4gICAgICAgICAgICBvdHBDb2RlLFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICBvblN1Y2Nlc3M6ICgpOiB2b2lkID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLmNoYWxsZW5nZVVzZXJuYW1lID0gbnVsbDtcbiAgICAgICAgICAgICAgICB0aGlzLmNoYWxsZW5nZVBhc3N3b3JkID0gbnVsbDtcbiAgICAgICAgICAgICAgICByZXNvbHZlKCk7XG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIG9uRmFpbHVyZTogZXJyID0+IHJlamVjdChlcnIpXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgY2hhbGxlbmdlTmFtZVxuICAgICAgICAgIClcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG4gIC8qKlxuICAgKiBSZWdpc3RlciBhIG5ldyB1c2VyIGEgc2V0IGl0cyBkZWZhdWx0IGF0dHJpYnV0ZXMuXG4gICAqL1xuICByZWdpc3Rlcih1c2VybmFtZTogc3RyaW5nLCBwYXNzd29yZDogc3RyaW5nLCBhdHRyaWJ1dGVzPzogYW55KTogUHJvbWlzZTxDb2duaXRvVXNlcj4ge1xuICAgIGF0dHJpYnV0ZXMgPSBhdHRyaWJ1dGVzIHx8IHt9O1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KTogdm9pZCA9PiB7XG4gICAgICAvLyBhZGQgYXR0cmlidXRlcyBsaWtlIHRoZSBlbWFpbCBhZGRyZXNzIGFuZCB0aGUgZnVsbG5hbWVcbiAgICAgIGNvbnN0IGF0dHJzID0gW107XG4gICAgICBmb3IgKGNvbnN0IHByb3AgaW4gYXR0cmlidXRlcylcbiAgICAgICAgaWYgKGF0dHJpYnV0ZXNbcHJvcF0pIGF0dHJzLnB1c2godGhpcy5wcmVwYXJlVXNlckF0dHJpYnV0ZShwcm9wLCBhdHRyaWJ1dGVzW3Byb3BdKSk7XG4gICAgICAvLyBhZGQgdGhlIGVtYWlsLCB3aGljaCBpcyBlcXVhbCB0byB0aGUgdXNlcm5hbWUgZm9yIG1vc3Qgb2Ygb3VyIFBvb2xzXG4gICAgICBpZiAoIWF0dHJpYnV0ZXMuZW1haWwpIGF0dHJzLnB1c2godGhpcy5wcmVwYXJlVXNlckF0dHJpYnV0ZSgnZW1haWwnLCB1c2VybmFtZSkpO1xuICAgICAgLy8gcmVnaXN0ZXIgdGhlIG5ldyB1c2VyIHRvIHRoZSBwb29sXG4gICAgICB0aGlzLnVzZXJQb29sLnNpZ25VcCh1c2VybmFtZSwgcGFzc3dvcmQsIGF0dHJzLCBudWxsLCAoZXJyOiBFcnJvciwgcmVzOiBJU2lnblVwUmVzdWx0KTogdm9pZCA9PiB7XG4gICAgICAgIGlmIChlcnIpIHJldHVybiByZWplY3QoZXJyKTtcbiAgICAgICAgdGhpcy5uZXdBY2NvdW50SnVzdFJlZ2lzdGVyZWQgPSB1c2VybmFtZTtcbiAgICAgICAgcmVzb2x2ZShyZXMudXNlcik7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuICAvKipcbiAgICogSW4gY2FzZSBhIG5ldyBhY2NvdW50IGhhcyBqdXN0IGJlZW4gcmVnaXN0ZXJlZCwgcmV0dXJuIHRoZSB1c2VybmFtZS5cbiAgICovXG4gIGdldE5ld0FjY291bnRKdXN0UmVnaXN0ZXJlZCgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLm5ld0FjY291bnRKdXN0UmVnaXN0ZXJlZDtcbiAgfVxuICAvKipcbiAgICogQ29uZmlybSBhIG5ldyByZWdpc3RyYXRpb24gdGhyb3VnaCB0aGUgY29uZmlybWF0aW9uIGNvZGUgc2VudCBieSBDb2duaXRvLlxuICAgKi9cbiAgY29uZmlybVJlZ2lzdHJhdGlvbih1c2VybmFtZTogc3RyaW5nLCBjb2RlOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCk6IHZvaWQgPT4ge1xuICAgICAgdGhpcy5wcmVwYXJlQ29nbml0b1VzZXIodXNlcm5hbWUpLmNvbmZpcm1SZWdpc3RyYXRpb24oY29kZSwgdHJ1ZSwgKGVycjogRXJyb3IpOiB2b2lkID0+XG4gICAgICAgIGVyciA/IHJlamVjdChlcnIpIDogcmVzb2x2ZSgpXG4gICAgICApO1xuICAgIH0pO1xuICB9XG4gIC8qKlxuICAgKiBTZW5kIGFnYWluIGEgY29uZmlybWF0aW9uIGNvZGUgZm9yIGEgbmV3IHJlZ2lzdHJhdGlvbi5cbiAgICovXG4gIHJlc2VuZENvbmZpcm1hdGlvbkNvZGUodXNlcm5hbWU6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KTogdm9pZCA9PiB7XG4gICAgICB0aGlzLnByZXBhcmVDb2duaXRvVXNlcih1c2VybmFtZSkucmVzZW5kQ29uZmlybWF0aW9uQ29kZSgoZXJyOiBFcnJvcik6IHZvaWQgPT4gKGVyciA/IHJlamVjdChlcnIpIDogcmVzb2x2ZSgpKSk7XG4gICAgfSk7XG4gIH1cbiAgLyoqXG4gICAqIExvZ291dCB0aGUgY3VycmVudGx5IHNpZ25lZC1pbiB1c2VyLlxuICAgKi9cbiAgbG9nb3V0KG9wdGlvbnM/OiB7IGdsb2JhbDogYm9vbGVhbiB9KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgb3B0aW9ucyA9IE9iamVjdC5hc3NpZ24oeyBnbG9iYWw6IGZhbHNlIH0sIG9wdGlvbnMpO1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KTogdm9pZCA9PiB7XG4gICAgICAvLyByZW1vdmUgdGhlIHJlZnJlc2ggdG9rZW4gcHJldmlvc2x5IHNhdmVkXG4gICAgICB0aGlzLl9zdG9yYWdlLnJlbW92ZSgnQXV0aFJlZnJlc2hUb2tlbicpLnRoZW4oXG4gICAgICAgICgpOiBQcm9taXNlPHZvaWQ+ID0+XG4gICAgICAgICAgLy8gcmVtb3ZlIHRoZSBvcHRpb25hbCBhdXRoIGRldGFpbHNcbiAgICAgICAgICB0aGlzLl9zdG9yYWdlLnJlbW92ZSgnQXV0aFVzZXJEZXRhaWxzJykudGhlbigoKTogdm9pZCA9PiB7XG4gICAgICAgICAgICAvLyBnZXQgdGhlIHVzZXIgYW5kIHRoZSBzZXNzaW9uXG4gICAgICAgICAgICBjb25zdCB1c2VyID0gdGhpcy51c2VyUG9vbC5nZXRDdXJyZW50VXNlcigpO1xuICAgICAgICAgICAgdXNlci5nZXRTZXNzaW9uKGFzeW5jIChlcnI6IEVycm9yKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgICAgICAgICAgIC8vIGlmIHRoZSBzZXNzaW9uIGlzIGFjdGl2ZSwgcnVuIHRoZSBvbmxpbmUgc2lnbi1vdXQ7IG90aGVyd2lzZSwgb25seSB0aGUgbG9jYWwgZGF0YSBoYXMgYmVlbiBkZWxldGVkXG4gICAgICAgICAgICAgIGlmIChlcnIpIHJldHVybiByZXNvbHZlKCk7XG4gICAgICAgICAgICAgIC8vIGlmIGEgcmVmZXJlbmNlIHRvIHRoZSBkZXZpY2Ugd2FzIHNhdmVkLCBmb3JnZXQgaXRcbiAgICAgICAgICAgICAgaWYgKHRoaXMuX2Vudi5pZGVhLmF1dGguc2luZ2xlU2ltdWx0YW5lb3VzU2Vzc2lvbikgYXdhaXQgdGhpcy5zZXRDdXJyZW50RGV2aWNlRm9yUHJvamVjdChudWxsKTtcbiAgICAgICAgICAgICAgLy8gc2lnbi1vdXQgZnJvbSB0aGUgcG9vbCAodGVybWluYXRlIHRoZSBjdXJyZW50IHNlc3Npb24gb3IgYWxsIHRoZSBzZXNzaW9ucylcbiAgICAgICAgICAgICAgaWYgKG9wdGlvbnMuZ2xvYmFsKVxuICAgICAgICAgICAgICAgIHVzZXIuZ2xvYmFsU2lnbk91dCh7IG9uU3VjY2VzczogKCk6IHZvaWQgPT4gcmVzb2x2ZSgpLCBvbkZhaWx1cmU6IGVyciA9PiByZWplY3QoZXJyKSB9KTtcbiAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgdXNlci5zaWduT3V0KCk7XG4gICAgICAgICAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9KVxuICAgICAgKTtcbiAgICB9KTtcbiAgfVxuICAvKipcbiAgICogU2VuZCBhIHBhc3N3b3JkIHJlc2V0IHJlcXVlc3QuXG4gICAqL1xuICBmb3Jnb3RQYXNzd29yZCh1c2VybmFtZTogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpOiB2b2lkID0+IHtcbiAgICAgIHRoaXMucHJlcGFyZUNvZ25pdG9Vc2VyKHVzZXJuYW1lKS5mb3Jnb3RQYXNzd29yZCh7XG4gICAgICAgIG9uU3VjY2VzczogKCk6IHZvaWQgPT4gcmVzb2x2ZSgpLFxuICAgICAgICBvbkZhaWx1cmU6IChlcnI6IEVycm9yKTogdm9pZCA9PiByZWplY3QoZXJyKVxuICAgICAgfSk7XG4gICAgfSk7XG4gIH1cbiAgLyoqXG4gICAqIENvbmZpcm0gYSBuZXcgcGFzc3dvcmQgYWZ0ZXIgYSBwYXNzd29yZCByZXNldCByZXF1ZXN0LlxuICAgKi9cbiAgY29uZmlybVBhc3N3b3JkKHVzZXJuYW1lOiBzdHJpbmcsIGNvZGU6IHN0cmluZywgbmV3UHdkOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCk6IHZvaWQgPT4ge1xuICAgICAgdGhpcy5wcmVwYXJlQ29nbml0b1VzZXIodXNlcm5hbWUpLmNvbmZpcm1QYXNzd29yZChjb2RlLCBuZXdQd2QsIHtcbiAgICAgICAgb25TdWNjZXNzOiAoKTogdm9pZCA9PiByZXNvbHZlKCksXG4gICAgICAgIG9uRmFpbHVyZTogKGVycjogRXJyb3IpOiB2b2lkID0+IHJlamVjdChlcnIpXG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuICAvKipcbiAgICogR2V0cyB0aGUgVVJMIGZvciBlbmFibGluZyBNRkEuIFRoaXMgVVJMIGNhbiBiZSB1c2VkIHRvIGdlbmVyYXRlIGEgUVIgQ29kZSB0byByZWFkIHdpdGggYW4gYXV0aGVudGljYXRvciBhcHAuXG4gICAqL1xuICBnZXRVUkxGb3JFbmFibGluZ01GQSgpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KTogdm9pZCA9PiB7XG4gICAgICBjb25zdCB1c2VyID0gdGhpcy51c2VyUG9vbC5nZXRDdXJyZW50VXNlcigpO1xuICAgICAgaWYgKCF1c2VyKSByZXR1cm4gcmVqZWN0KCk7XG4gICAgICB1c2VyLmdldFNlc3Npb24oKGVycjogRXJyb3IpOiB2b2lkID0+IHtcbiAgICAgICAgaWYgKGVycikgcmV0dXJuIHJlamVjdChlcnIpO1xuICAgICAgICB1c2VyLmFzc29jaWF0ZVNvZnR3YXJlVG9rZW4oe1xuICAgICAgICAgIGFzc29jaWF0ZVNlY3JldENvZGU6IChzZWNyZXRDb2RlOiBzdHJpbmcpOiB2b2lkID0+XG4gICAgICAgICAgICByZXNvbHZlKGBvdHBhdXRoOi8vdG90cC8ke2VuY29kZVVSSSh0aGlzLm1mYVByb2plY3ROYW1lKX0/c2VjcmV0PSR7c2VjcmV0Q29kZX1gKSxcbiAgICAgICAgICBvbkZhaWx1cmU6IChlcnI6IGFueSk6IHZvaWQgPT4gcmVqZWN0KGVycilcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuICAvKipcbiAgICogQ2hlY2sgd2hldGhlciB0aGUgdXNlciBoYXMgTUZBIGVuYWJsZWQuXG4gICAqL1xuICBjaGVja0lmVXNlckhhc01GQUVuYWJsZWQoYnlwYXNzQ2FjaGUgPSBmYWxzZSk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KTogdm9pZCA9PiB7XG4gICAgICBjb25zdCB1c2VyID0gdGhpcy51c2VyUG9vbC5nZXRDdXJyZW50VXNlcigpO1xuICAgICAgaWYgKCF1c2VyKSByZXR1cm4gcmVqZWN0KCk7XG4gICAgICB1c2VyLmdldFNlc3Npb24oKGVycjogRXJyb3IpOiB2b2lkID0+IHtcbiAgICAgICAgaWYgKGVycikgcmV0dXJuIHJlamVjdChlcnIpO1xuICAgICAgICB1c2VyLmdldFVzZXJEYXRhKFxuICAgICAgICAgIChlcnIsIGRhdGEpOiB2b2lkID0+IHtcbiAgICAgICAgICAgIGlmIChlcnIpIHJldHVybiByZWplY3QoZXJyKTtcbiAgICAgICAgICAgIGNvbnN0IGlzTUZBRW5hYmxlZCA9ICEhKGRhdGEuVXNlck1GQVNldHRpbmdMaXN0ICYmIGRhdGEuVXNlck1GQVNldHRpbmdMaXN0LmluY2x1ZGVzKCdTT0ZUV0FSRV9UT0tFTl9NRkEnKSk7XG4gICAgICAgICAgICByZXNvbHZlKGlzTUZBRW5hYmxlZCk7XG4gICAgICAgICAgfSxcbiAgICAgICAgICB7IGJ5cGFzc0NhY2hlIH1cbiAgICAgICAgKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG4gIC8qKlxuICAgKiBDb25maWd1cmUgYSBNRkEgZGV2aWNlIGZvciB0aGUgdXNlci5cbiAgICovXG4gIHByaXZhdGUgc2V0TUZBRGV2aWNlKG90cDogc3RyaW5nLCBtZmFEZXZpY2VOYW1lOiBzdHJpbmcsIGVuYWJsZWQgPSB0cnVlLCBwcmVmZXJyZWQgPSB0cnVlKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpOiB2b2lkID0+IHtcbiAgICAgIGNvbnN0IHVzZXIgPSB0aGlzLnVzZXJQb29sLmdldEN1cnJlbnRVc2VyKCk7XG4gICAgICBpZiAoIXVzZXIpIHJldHVybiByZWplY3QoKTtcbiAgICAgIHVzZXIuZ2V0U2Vzc2lvbigoZXJyOiBFcnJvcik6IHZvaWQgPT4ge1xuICAgICAgICBpZiAoZXJyKSByZXR1cm4gcmVqZWN0KGVycik7XG4gICAgICAgIHVzZXIudmVyaWZ5U29mdHdhcmVUb2tlbihvdHAsIG1mYURldmljZU5hbWUsIHtcbiAgICAgICAgICBvblN1Y2Nlc3M6ICgpOiB2b2lkID0+XG4gICAgICAgICAgICB1c2VyLnNldFVzZXJNZmFQcmVmZXJlbmNlKG51bGwsIHsgRW5hYmxlZDogZW5hYmxlZCwgUHJlZmVycmVkTWZhOiBwcmVmZXJyZWQgfSwgKGVycjogRXJyb3IpOiB2b2lkID0+XG4gICAgICAgICAgICAgIGVyciA/IHJlamVjdChlcnIpIDogcmVzb2x2ZSgpXG4gICAgICAgICAgICApLFxuICAgICAgICAgIG9uRmFpbHVyZTogKGVycik6IHZvaWQgPT4gcmVqZWN0KGVycilcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuICAvKipcbiAgICogRW5hYmxlIGEgbmV3IE1GQSBkZXZpY2UgZm9yIHRoZSB1c2VyIGJ5IGluc2VydGluZyBhbiBPVFAgY29kZSBnZW5lcmF0ZWQgYnkgaXQuXG4gICAqL1xuICBlbmFibGVNRkEob3RwOiBzdHJpbmcsIG1mYURldmljZU5hbWUgPSAnZGVmYXVsdCcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICByZXR1cm4gdGhpcy5zZXRNRkFEZXZpY2Uob3RwLCBtZmFEZXZpY2VOYW1lLCB0cnVlLCB0cnVlKTtcbiAgfVxuICAvKipcbiAgICogRGlzYWJsZSBNRkEgZm9yIGEgdXNlciBieSBpbnNlcnRpbmcgYW4gT1RQIGNvZGUgZ2VuZXJhdGVkIGJ5IGl0LlxuICAgKi9cbiAgZGlzYWJsZU1GQShvdHA6IHN0cmluZywgbWZhRGV2aWNlTmFtZSA9ICdkZWZhdWx0Jyk6IFByb21pc2U8dm9pZD4ge1xuICAgIHJldHVybiB0aGlzLnNldE1GQURldmljZShvdHAsIG1mYURldmljZU5hbWUsIGZhbHNlLCBmYWxzZSk7XG4gIH1cbiAgLyoqXG4gICAqIENoZWNrIGlmIGEgdXNlciBpcyBjdXJyZW50bHkgYXV0aGVudGljYXRlZC5cbiAgICogQHBhcmFtIG9mZmxpbmVBbGxvd2VkIGlmIHNldCBhbmQgaWYgb2ZmbGluZSwgc2tpcCBhdXRoZW50aWNhdGlvbiBhbmQgcmV0cmlldmUgZGF0YSBsb2NhbGx5XG4gICAqIEBwYXJhbSBnZXRGcmVzaElkVG9rZW5PbkV4cCBjYiBmdW5jdGlvbiB0byBleGVjdXRlIHdoZW4gdGhlIGlkVG9rZW4gaXMgcmVmcmVzaGVkXG4gICAqL1xuICBpc0F1dGhlbnRpY2F0ZWQob2ZmbGluZUFsbG93ZWQ6IGJvb2xlYW4sIGdldEZyZXNoSWRUb2tlbk9uRXhwPzogKGZyZXNoSWRUb2tlbjogc3RyaW5nKSA9PiB2b2lkKTogUHJvbWlzZTxhbnk+IHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCk6IHZvaWQgPT4ge1xuICAgICAgaWYgKG9mZmxpbmVBbGxvd2VkICYmICFuYXZpZ2F0b3Iub25MaW5lKSB7XG4gICAgICAgIHRoaXMuX3N0b3JhZ2UuZ2V0KCdBdXRoVXNlckRldGFpbHMnKS50aGVuKHVzZXJEZXRhaWxzID0+IHJlc29sdmUoeyBpZFRva2VuOiBudWxsLCB1c2VyRGV0YWlscyB9KSk7XG4gICAgICAgIC8vIHJlLWV4ZWN1dGUgdGhlIG1ldGhvZCB3aGVuIGJhY2sgb25saW5lLCBzbyB0aGF0IHlvdSBjYW4gcmV0cmlldmUgYSB0b2tlbiB0byBtYWtlIHJlcXVlc3RzXG4gICAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKFxuICAgICAgICAgICdvbmxpbmUnLFxuICAgICAgICAgICgpOiBQcm9taXNlPHZvaWQ+ID0+XG4gICAgICAgICAgICB0aGlzLmlzQXV0aGVudGljYXRlZCh0cnVlLCBnZXRGcmVzaElkVG9rZW5PbkV4cClcbiAgICAgICAgICAgICAgLy8gc2V0IHRoZSBuZXcgdG9rZW4gYXMgaWYgaXQgd2FzIHJlZnJlc2hlZFxuICAgICAgICAgICAgICAudGhlbihyZXN1bHQgPT4gZ2V0RnJlc2hJZFRva2VuT25FeHAocmVzdWx0LmlkVG9rZW4pKVxuICAgICAgICApO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc3QgdXNlciA9IHRoaXMudXNlclBvb2wuZ2V0Q3VycmVudFVzZXIoKTtcbiAgICAgICAgaWYgKCF1c2VyKSByZXR1cm4gcmVqZWN0KCk7XG4gICAgICAgIHVzZXIuZ2V0U2Vzc2lvbigoZXJyOiBFcnJvciwgc2Vzc2lvbjogQ29nbml0b1VzZXJTZXNzaW9uKTogdm9pZCA9PiB7XG4gICAgICAgICAgaWYgKGVycikgcmV0dXJuIHJlamVjdChlcnIpO1xuICAgICAgICAgIHVzZXIuZ2V0VXNlckRhdGEoXG4gICAgICAgICAgICAoZXJyLCBkYXRhKTogdm9pZCA9PiB7XG4gICAgICAgICAgICAgIGlmIChlcnIpIHJldHVybiByZWplY3QoZXJyKTtcbiAgICAgICAgICAgICAgY29uc3QgaXNNRkFFbmFibGVkID0gISEoXG4gICAgICAgICAgICAgICAgZGF0YS5Vc2VyTUZBU2V0dGluZ0xpc3QgJiYgZGF0YS5Vc2VyTUZBU2V0dGluZ0xpc3QuaW5jbHVkZXMoJ1NPRlRXQVJFX1RPS0VOX01GQScpXG4gICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgIGlmICghaXNNRkFFbmFibGVkICYmIHRoaXMuX2Vudi5pZGVhLmF1dGguZm9yY2VMb2dpbldpdGhNRkEpXG4gICAgICAgICAgICAgICAgcmV0dXJuIHJlamVjdChuZXcgRXJyb3IoTG9naW5PdXRjb21lQWN0aW9ucy5NRkFfU0VUVVApKTtcbiAgICAgICAgICAgICAgdXNlci5nZXRVc2VyQXR0cmlidXRlcygoZTogRXJyb3IsIGF0dHJpYnV0ZXM6IENvZ25pdG9Vc2VyQXR0cmlidXRlW10pOiB2b2lkID0+IHtcbiAgICAgICAgICAgICAgICBpZiAoZSkgcmV0dXJuIHJlamVjdChlKTtcbiAgICAgICAgICAgICAgICAvLyByZW1hcCB1c2VyIGF0dHJpYnV0ZXNcbiAgICAgICAgICAgICAgICBjb25zdCB1c2VyRGV0YWlsczogYW55ID0ge307XG4gICAgICAgICAgICAgICAgYXR0cmlidXRlcy5mb3JFYWNoKChhOiBDb2duaXRvVXNlckF0dHJpYnV0ZSk6IHN0cmluZyA9PiAodXNlckRldGFpbHNbYS5nZXROYW1lKCldID0gYS5nZXRWYWx1ZSgpKSk7XG4gICAgICAgICAgICAgICAgLy8gYWRkIHRoZSB1c2VyJ3MgZ3JvdXBzIHRvIHRoZSBhdHRyaWJ1dGVzXG4gICAgICAgICAgICAgICAgY29uc3Qgc2Vzc2lvbkluZm8gPSBzZXNzaW9uLmdldEFjY2Vzc1Rva2VuKCkuZGVjb2RlUGF5bG9hZCgpO1xuICAgICAgICAgICAgICAgIGNvbnN0IGdyb3Vwczogc3RyaW5nW10gPSBzZXNzaW9uSW5mb1snY29nbml0bzpncm91cHMnXSB8fCBbXTtcbiAgICAgICAgICAgICAgICB1c2VyRGV0YWlsc1snZ3JvdXBzJ10gPSBncm91cHM7XG4gICAgICAgICAgICAgICAgLy8gcnVuIHNvbWUgY2hlY2tzIGNvbnNpZGVyaW5nIHRoZSB1c2VyJ3MgZ3JvdXBzIGFuZCBkZXZpY2VzIChiYXNlZCBvbiB0aGUgcHJvamVjdCdzIGNvbmZpZ3VyYXRpb24pXG4gICAgICAgICAgICAgICAgdGhpcy5ydW5Qb3N0QXV0aENoZWNrcyh1c2VyRGV0YWlscywgZXJyID0+IHtcbiAgICAgICAgICAgICAgICAgIC8vIGluIGNhc2Ugc29tZSBjaGVjayBmYWlsZWQsIHJlamVjdCB0aGUgYXV0aG9yaXNhdGlvbiBmbG93XG4gICAgICAgICAgICAgICAgICBpZiAoZXJyKSByZXR1cm4gcmVqZWN0KGVycik7XG4gICAgICAgICAgICAgICAgICAvLyAoYXN5bmMpIHNhdmUgdGhlIHJlZnJlc2ggdG9rZW4gc28gaXQgY2FuIGJlIGFjY2Vzc2VkIGJ5IG90aGVyIHByb2NlZHVyZXNcbiAgICAgICAgICAgICAgICAgIHRoaXMuX3N0b3JhZ2Uuc2V0KCdBdXRoUmVmcmVzaFRva2VuJywgc2Vzc2lvbi5nZXRSZWZyZXNoVG9rZW4oKS5nZXRUb2tlbigpKTtcbiAgICAgICAgICAgICAgICAgIC8vIHNldCBhIHRpbWVyIHRvIG1hbmFnZSB0aGUgYXV0b3JlZnJlc2ggb2YgdGhlIGlkVG9rZW4gKHRocm91Z2ggdGhlIHJlZnJlc2hUb2tlbilcbiAgICAgICAgICAgICAgICAgIHNldFRpbWVvdXQoXG4gICAgICAgICAgICAgICAgICAgICgpOiB2b2lkID0+IHRoaXMucmVmcmVzaFNlc3Npb24odXNlciwgc2Vzc2lvbi5nZXRSZWZyZXNoVG9rZW4oKS5nZXRUb2tlbigpLCBnZXRGcmVzaElkVG9rZW5PbkV4cCksXG4gICAgICAgICAgICAgICAgICAgIDE1ICogNjAgKiAxMDAwXG4gICAgICAgICAgICAgICAgICApOyAvLyBldmVyeSAxNSBtaW51dGVzXG4gICAgICAgICAgICAgICAgICAvLyAoYXN5bmMpIGlmIG9mZmxpbmVBbGxvd2VkLCBzYXZlIGRhdGEgbG9jYWxseSwgdG8gdXNlIGl0IG5leHQgdGltZSB3ZSdsbCBiZSBvZmZsaW5lXG4gICAgICAgICAgICAgICAgICBpZiAob2ZmbGluZUFsbG93ZWQpIHRoaXMuX3N0b3JhZ2Uuc2V0KCdBdXRoVXNlckRldGFpbHMnLCB1c2VyRGV0YWlscyk7XG4gICAgICAgICAgICAgICAgICAvLyByZXR1cm4gdGhlIGlkVG9rZW4gKHRvIHVzZSB3aXRoIEFQSSlcbiAgICAgICAgICAgICAgICAgIHJlc29sdmUoeyBpZFRva2VuOiBzZXNzaW9uLmdldElkVG9rZW4oKS5nZXRKd3RUb2tlbigpLCB1c2VyRGV0YWlscyB9KTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgeyBieXBhc3NDYWNoZTogdHJ1ZSB9XG4gICAgICAgICAgKTtcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cbiAgLyoqXG4gICAqIEhlbHBlciB0byByZWZyZXNoIHRoZSBzZXNzaW9uIGV2ZXJ5IE4gbWludXRlcy5cbiAgICovXG4gIHByaXZhdGUgcmVmcmVzaFNlc3Npb24odXNlcjogQ29nbml0b1VzZXIsIHJlZnJlc2hUb2tlbjogc3RyaW5nLCBjYWxsYmFjazogKGZyZXNoSWRUb2tlbjogc3RyaW5nKSA9PiB2b2lkKTogdm9pZCB7XG4gICAgdXNlci5yZWZyZXNoU2Vzc2lvbihcbiAgICAgIG5ldyBDb2duaXRvUmVmcmVzaFRva2VuKHsgUmVmcmVzaFRva2VuOiByZWZyZXNoVG9rZW4gfSksXG4gICAgICAoZXJyOiBFcnJvciwgc2Vzc2lvbjogQ29nbml0b1VzZXJTZXNzaW9uKTogdm9pZCA9PiB7XG4gICAgICAgIGlmIChlcnIpIHtcbiAgICAgICAgICAvLyB0cnkgYWdhaW4gaW4gMSBtaW51dGVcbiAgICAgICAgICBzZXRUaW1lb3V0KCgpOiB2b2lkID0+IHRoaXMucmVmcmVzaFNlc3Npb24odXNlciwgcmVmcmVzaFRva2VuLCBjYWxsYmFjayksIDEgKiA2MCAqIDEwMDApO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIChhc3luYykgc2F2ZSB0aGUgcmVmcmVzaCB0b2tlbiBzbyBpdCBjYW4gYmUgYWNjZXNzZWQgYnkgb3RoZXIgcHJvY2VkdXJlc1xuICAgICAgICAgIHRoaXMuX3N0b3JhZ2Uuc2V0KCdBdXRoUmVmcmVzaFRva2VuJywgc2Vzc2lvbi5nZXRSZWZyZXNoVG9rZW4oKS5nZXRUb2tlbigpKTtcbiAgICAgICAgICAvLyByZXBlYXQgZXZlcnkgMTUgbWludXRlc1xuICAgICAgICAgIHNldFRpbWVvdXQoXG4gICAgICAgICAgICAoKTogdm9pZCA9PiB0aGlzLnJlZnJlc2hTZXNzaW9uKHVzZXIsIHNlc3Npb24uZ2V0UmVmcmVzaFRva2VuKCkuZ2V0VG9rZW4oKSwgY2FsbGJhY2spLFxuICAgICAgICAgICAgMTUgKiA2MCAqIDEwMDBcbiAgICAgICAgICApO1xuICAgICAgICAgIC8vIHJ1biB0aGUgY2FsbGJhY2sgYWN0aW9uLCBpZiBzZXRcbiAgICAgICAgICBpZiAoY2FsbGJhY2spIGNhbGxiYWNrKHNlc3Npb24uZ2V0SWRUb2tlbigpLmdldEp3dFRva2VuKCkpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgKTtcbiAgfVxuICAvKipcbiAgICogUnVuIHNvbWUgcG9zdC1hdXRoIGNoZWNrcywgYmFzZWQgb24gdGhlIHVzZXJzIGdyb3VwcyBhbmQgb24gdGhlIGFwcCdzIGNvbmZpZ3VyYXRpb246XG4gICAqICAtIHVzZXJzIGluIHRoZSBDb2duaXRvJ3MgXCJhZG1pbnNcIiBncnVwIHNraXAgYWxsIHRoZSBmb2xsb3dpbmcgcnVsZXMuXG4gICAqICAtIHVzZXJzIGluIHRoZSBDb2duaXRvJ3MgXCJyb2JvdHNcIiBncm91cCBjYW4ndCBzaWduLWludG8gZnJvbnQtZW5kcyAodGhleSBzZXJ2ZSBvbmx5IGJhY2stZW5kIHB1cnBvc2VzKS5cbiAgICogIC0gaWYgYGVudi5pZGVhLmF1dGguc2luZ2xlU2ltdWx0YW5lb3VzU2Vzc2lvbmAgaXMgb24sIG1ha2Ugc3VyZSB0aGVyZSBpcyBvbmx5IG9uZSBhY3RpdmUgc2Vzc2lvbiBwZXIgdXNlci5cbiAgICovXG4gIHByaXZhdGUgcnVuUG9zdEF1dGhDaGVja3ModXNlckRldGFpbHM6IGFueSwgY2FsbGJhY2s6IChlcnI/OiBFcnJvcikgPT4gdm9pZCk6IHZvaWQgfCBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBncm91cHM6IHN0cmluZ1tdID0gdXNlckRldGFpbHNbJ2dyb3VwcyddO1xuICAgIC8vIHNraXAgY2hlY2tzIGlmIHRoZSB1c2VyIGlzIGluIHRoZSBcImFkbWluc1wiIGdyb3VwXG4gICAgY29uc3QgaXNBZG1pbiA9IGdyb3Vwcy5zb21lKHggPT4geCA9PT0gJ2FkbWlucycpO1xuICAgIGlmIChpc0FkbWluKSByZXR1cm4gY2FsbGJhY2soKTtcbiAgICAvLyB1c2VycyBpbiB0aGUgXCJyb2JvdHNcIiBncm91cCBjYW4ndCBzaWduLWludG8gZnJvbnQtZW5kcyAodGhleSBzZXJ2ZSBvbmx5IGJhY2stZW5kIHB1cnBvc2VzKVxuICAgIGNvbnN0IGlzUm9ib3QgPSBncm91cHMuc29tZSh4ID0+IHggPT09ICdyb2JvdHMnKTtcbiAgICBpZiAoaXNSb2JvdCkgcmV0dXJuIGNhbGxiYWNrKG5ldyBFcnJvcignUk9CT1RfVVNFUicpKTtcbiAgICAvLyBpbiBjYXNlIHRoZSBwcm9qZWN0IGxpbWl0cyBlYWNoIGFjY291bnQgdG8gb25seSBvbmUgc2ltdWx0YW5lb3VzIHNlc3Npb24sIHJ1biBhIGNoZWNrXG4gICAgaWYgKHRoaXMuX2Vudi5pZGVhLmF1dGguc2luZ2xlU2ltdWx0YW5lb3VzU2Vzc2lvbikgcmV0dXJuIHRoaXMuY2hlY2tGb3JTaW11bHRhbmVvdXNTZXNzaW9ucyh1c2VyRGV0YWlscywgY2FsbGJhY2spO1xuICAgIC8vIG90aGVyd2lzZSwgd2UncmUgZG9uZVxuICAgIGNhbGxiYWNrKCk7XG4gIH1cbiAgLyoqXG4gICAqIENoZWNrIHdoZXRoZXIgdGhlIHVzZXIgc2lnbmVkLWludG8gbXVsdGlwbGUgZGV2aWNlcy5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgY2hlY2tGb3JTaW11bHRhbmVvdXNTZXNzaW9ucyh1c2VyRGV0YWlsczogYW55LCBjYWxsYmFjazogKGVycj86IEVycm9yKSA9PiB2b2lkKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgLy8gZ2V0IG9yIGNyZWF0ZSBhIGtleSBmb3IgdGhlIGN1cnJlbnQgZGV2aWNlICh+cmFuZG9tKVxuICAgIGxldCBjdXJyZW50RGV2aWNlS2V5ID0gYXdhaXQgdGhpcy5fc3RvcmFnZS5nZXQoJ0F1dGhEZXZpY2VLZXknKTtcbiAgICBpZiAoIWN1cnJlbnREZXZpY2VLZXkpIHtcbiAgICAgIGNvbnN0IHJhbmRvbUtleSA9IE1hdGgucmFuZG9tKCkudG9TdHJpbmcoMzYpLnN1YnN0cmluZygxMCk7XG4gICAgICBjdXJyZW50RGV2aWNlS2V5ID0gcmFuZG9tS2V5LmNvbmNhdChTdHJpbmcoRGF0ZS5ub3coKSkpO1xuICAgICAgYXdhaXQgdGhpcy5fc3RvcmFnZS5zZXQoJ0F1dGhEZXZpY2VLZXknLCBjdXJyZW50RGV2aWNlS2V5KTtcbiAgICB9XG4gICAgLy8gY2hlY2sgd2hldGhlciB0aGUgbGFzdCBkZXZpY2UgdG8gc2lnbi1pbnRvIHRoaXMgcHJvamVjdCAoaWYgYW55KSBpcyB0aGUgY3VycmVudCBvbmVcbiAgICBjb25zdCBsYXN0RGV2aWNlVG9TaWduSW50b1RoaXNQcm9qZWN0ID0gdXNlckRldGFpbHNbdGhpcy5kZXZpY2VLZXlBdHRyaWJ1dGVdO1xuICAgIC8vIGlmIGl0J3MgdGhlIGZpcnN0IHVzZXIncyBkZXZpY2UgdG8gc2lnbi1pbiwgc2F2ZSB0aGUgcmVmZXJlbmNlIGluIENvZ25pdG8gYW5kIHJlc29sdmVcbiAgICBpZiAoIWxhc3REZXZpY2VUb1NpZ25JbnRvVGhpc1Byb2plY3QpIHtcbiAgICAgIHRoaXMuc2V0Q3VycmVudERldmljZUZvclByb2plY3QoY3VycmVudERldmljZUtleSlcbiAgICAgICAgLnRoZW4oKCk6IHZvaWQgPT4gY2FsbGJhY2soKSlcbiAgICAgICAgLmNhdGNoKCgpOiB2b2lkID0+IGNhbGxiYWNrKG5ldyBFcnJvcignQ0FOVF9TRVRfREVWSUNFJykpKTtcbiAgICAgIC8vIGlmIHRoZSBkZXZpY2UgZGlkbid0IGNoYW5nZSwgcmVzb2x2ZVxuICAgIH0gZWxzZSBpZiAobGFzdERldmljZVRvU2lnbkludG9UaGlzUHJvamVjdCA9PT0gY3VycmVudERldmljZUtleSkgY2FsbGJhY2soKTtcbiAgICAvLyBvdGh3ZXJ3aXNlLCByZXBvcnQgdGhlcmUgaXMgbW9yZSB0aGFuIG9uZSBzaW11bHRhbmVvdXMgc2Vzc2lvblxuICAgIGVsc2UgY2FsbGJhY2sobmV3IEVycm9yKCdTSU1VTFRBTkVPVVNfU0VTU0lPTicpKTtcbiAgfVxuICAvKipcbiAgICogU2V0IChvciByZXNldCkgdGhlIGN1cnJlbnQgdXNlcidzIGRldmljZSAoYnkga2V5KSBpbiB0aGUgY3VycmVudCBwcm9qZWN0IChzdG9yZWQgaW4gQ29nbml0bykuXG4gICAqL1xuICBwcml2YXRlIHNldEN1cnJlbnREZXZpY2VGb3JQcm9qZWN0KGRldmljZUtleT86IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IGF0dHJpYnV0ZXM6IGFueSA9IHt9O1xuICAgIC8vIG5vdGU6IGFuIGVtcHR5IHN0cmluZyB3aWxsIHJlbW92ZSB0aGUgYXR0cmlidXRlIGZyb20gQ29nbml0b1xuICAgIGF0dHJpYnV0ZXNbdGhpcy5kZXZpY2VLZXlBdHRyaWJ1dGVdID0gZGV2aWNlS2V5IHx8ICcnO1xuICAgIHJldHVybiB0aGlzLnVwZGF0ZVVzZXJBdHRyaWJ1dGVzKGF0dHJpYnV0ZXMpO1xuICB9XG4gIC8qKlxuICAgKiBVcGRhdGUgdGhlIGN1cnJlbnRseSBsb2dnZWQgaW4gdXNlcidzIGF0dHJpYnV0ZXMuXG4gICAqL1xuICB1cGRhdGVVc2VyQXR0cmlidXRlcyhhdHRyaWJ1dGVzOiBhbnkpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCk6IHZvaWQgPT4ge1xuICAgICAgLy8gcHJlcGFyZSB0aGUgYXR0cmlidXRlcyB3ZSB3YW50IHRvIGNoYW5nZVxuICAgICAgY29uc3QgYXR0cnMgPSBuZXcgQXJyYXk8YW55PigpO1xuICAgICAgZm9yIChjb25zdCBwcm9wIGluIGF0dHJpYnV0ZXMpXG4gICAgICAgIGlmIChhdHRyaWJ1dGVzW3Byb3BdICE9PSB1bmRlZmluZWQpIGF0dHJzLnB1c2godGhpcy5wcmVwYXJlVXNlckF0dHJpYnV0ZShwcm9wLCBhdHRyaWJ1dGVzW3Byb3BdKSk7XG4gICAgICBjb25zdCB1c2VyID0gdGhpcy51c2VyUG9vbC5nZXRDdXJyZW50VXNlcigpO1xuICAgICAgaWYgKCF1c2VyKSByZXR1cm4gcmVqZWN0KCk7XG4gICAgICAvLyB3ZSBuZWVkIHRvIGdldCB0aGUgc2Vzc2lvbiBiZWZvcmUgdG8gbWFrZSBjaGFuZ2VzXG4gICAgICB1c2VyLmdldFNlc3Npb24oKGVycjogRXJyb3IpOiB2b2lkID0+IHtcbiAgICAgICAgaWYgKGVycikgcmVqZWN0KGVycik7XG4gICAgICAgIGVsc2UgdXNlci51cGRhdGVBdHRyaWJ1dGVzKGF0dHJzLCAoZTogRXJyb3IpOiB2b2lkID0+IChlID8gcmVqZWN0KGUpIDogcmVzb2x2ZSgpKSk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSB0aGUgcGFzc3dvcmQgYWdhaW5zdCB0aGUgcG9saWN5IHNldCBpbiB0aGUgZW52aXJvbm1lbnRzIGNvbmZpZ3VyYXRpb24uXG4gICAqIEluIGNhc2UgdGhlcmUgYXJlIGVycm9ycywgdGhleSBhcmUgcmV0dXJuZWQgYXMgYW4gYXJyYXkgb2Ygc3RyaW5ncy5cbiAgICovXG4gIHZhbGlkYXRlUGFzc3dvcmRBZ2FpbnN0UG9saWN5KHBhc3N3b3JkOiBzdHJpbmcpOiBzdHJpbmdbXSB7XG4gICAgY29uc3QgZXJyb3JzOiBzdHJpbmdbXSA9IFtdO1xuICAgIGlmIChwYXNzd29yZD8udHJpbSgpLmxlbmd0aCA8IHRoaXMucGFzc3dvcmRQb2xpY3kubWluTGVuZ3RoKSBlcnJvcnMucHVzaCgnTUlOX0xFTkdUSCcpO1xuICAgIGlmICh0aGlzLnBhc3N3b3JkUG9saWN5LnJlcXVpcmVEaWdpdHMgJiYgIS9cXGQvLnRlc3QocGFzc3dvcmQpKSBlcnJvcnMucHVzaCgnUkVRVUlSRV9ESUdJVFMnKTtcbiAgICBpZiAodGhpcy5wYXNzd29yZFBvbGljeS5yZXF1aXJlTG93ZXJjYXNlICYmICEvW2Etel0vLnRlc3QocGFzc3dvcmQpKSBlcnJvcnMucHVzaCgnUkVRVUlSRV9MT1dFUkNBU0UnKTtcbiAgICBpZiAodGhpcy5wYXNzd29yZFBvbGljeS5yZXF1aXJlU3ltYm9scyAmJiAhL1tcXF5cXCRcXCpcXC5cXF9cXH5cXGBcXCtcXD1AXFwhXFw/XFw+XFw8XFw6XFw7XFxcXFxcLFxcI1xcJVxcJl0vLnRlc3QocGFzc3dvcmQpKVxuICAgICAgZXJyb3JzLnB1c2goJ1JFUVVJUkVfU1lNQk9MUycpO1xuICAgIGlmICh0aGlzLnBhc3N3b3JkUG9saWN5LnJlcXVpcmVVcHBlcmNhc2UgJiYgIS9bQS1aXS8udGVzdChwYXNzd29yZCkpIGVycm9ycy5wdXNoKCdSRVFVSVJFX1VQUEVSQ0FTRScpO1xuICAgIHJldHVybiBlcnJvcnM7XG4gIH1cbiAgLyoqXG4gICAqIFZhbGlkYXRlIHRoZSBwYXNzd29yZCBhZ2FpbnN0IG9mZmxpbmUgYW5kIG9ubGluZSBkYXRhYmFzZXMsIHRvIGF2b2lkIGNvbW1vbiBhbmQgZXhwbG9pdGVkIHBhc3N3b3Jkcy5cbiAgICovXG4gIGFzeW5jIHZhbGlkYXRlUGFzc3dvcmRBZ2FpbnN0RGF0YWJhc2VzKHBhc3N3b3JkOiBzdHJpbmcsIGN1c3RvbVN0cmluZ3NUb0F2b2lkPzogc3RyaW5nW10pOiBQcm9taXNlPHN0cmluZ1tdPiB7XG4gICAgY29uc3QgZXJyb3JzOiBzdHJpbmdbXSA9IFtdO1xuICAgIGxldCBwd2QgPSAocGFzc3dvcmQgfHwgJycpLnRyaW0oKS50b0xvd2VyQ2FzZSgpO1xuICAgIGNvbnN0IHB3ZENvbnRhaW5zID0gKHN0cjogc3RyaW5nKTogYm9vbGVhbiA9PiBwd2QuaW5jbHVkZXMoKHN0ciB8fCAnJykudHJpbSgpLnRvTG93ZXJDYXNlKCkpO1xuICAgIGNvbnN0IHByb2plY3RSZWZlcmVuY2VzVG9Bdm9pZCA9IFtcbiAgICAgIHRoaXMuX2Vudi5pZGVhLnByb2plY3QsXG4gICAgICB0aGlzLl9lbnYuaWRlYS5hdXRoLnRpdGxlLFxuICAgICAgdGhpcy5fdHJhbnNsYXRlLl8oJ0NPTU1PTi5BUFBfTkFNRScpXG4gICAgXTtcbiAgICBpZiAocHJvamVjdFJlZmVyZW5jZXNUb0F2b2lkLnNvbWUoeCA9PiBwd2RDb250YWlucyh4KSkpIGVycm9ycy5wdXNoKCdDT01NT05fUEFTU1dPUkRfUFJPSkVDVCcpO1xuICAgIGlmIChjdXN0b21TdHJpbmdzVG9Bdm9pZCAmJiBjdXN0b21TdHJpbmdzVG9Bdm9pZC5zb21lKHggPT4gcHdkQ29udGFpbnMoeCkpKSBlcnJvcnMucHVzaCgnQ09NTU9OX1BBU1NXT1JEX0NVU1RPTScpO1xuICAgIGlmIChDT01NT05fUEFTU1dPUkRTX1RPUF8xMDAwLnNvbWUoeCA9PiBwd2RDb250YWlucyh4KSkpIGVycm9ycy5wdXNoKCdDT01NT05fUEFTU1dPUkRfSU5URVJOQUwnKTtcbiAgICBpZiAoZXJyb3JzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgY29uc3QgcHdkU0hBMSA9IGF3YWl0IFNIQTEocGFzc3dvcmQpO1xuICAgICAgaWYgKHB3ZFNIQTEpIHtcbiAgICAgICAgY29uc3QgcmVzID0gYXdhaXQgZmV0Y2goJ2h0dHBzOi8vYXBpLnB3bmVkcGFzc3dvcmRzLmNvbS9yYW5nZS8nLmNvbmNhdChwd2RTSEExLnNsaWNlKDAsIDUpKSk7XG4gICAgICAgIGlmIChyZXMuc3RhdHVzID09PSAyMDApIHtcbiAgICAgICAgICBjb25zdCBwd25lZFBhc3N3b3Jkc1Jhd1N1ZmZpeGVzID0gYXdhaXQgcmVzLnRleHQoKTtcbiAgICAgICAgICBpZiAocHduZWRQYXNzd29yZHNSYXdTdWZmaXhlcy5pbmNsdWRlcyhwd2RTSEExLnNsaWNlKDUpKSkgZXJyb3JzLnB1c2goJ0NPTU1PTl9QQVNTV09SRF9FWFRFUk5BTCcpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBlcnJvcnM7XG4gIH1cbiAgLyoqXG4gICAqIEdldCBhIGNvbXBsZXRlIHBhc3N3b3JkIHBvbGljeSBwYXR0ZXJuLCBiYXNlZCBvbiB0aGUgZW52aXJvbm1lbnRzIGNvbmZpZ3VyYXRpb24sIHRvIHVzZSBvbiBwYXNzd29yZCBpbnB1dCBmaWVsZHMuXG4gICAqIE5vdGU6IHNvbWUgb2YgdGhlIHN5bWJvbHMgY291bGRuJ3QgYmUgaW5jbHVkZWQgYmVjYXVzZSB1bnN1cHBvcnRlZCBieSB0aGUgaW5wdXRbcGF0dGVybl0gYXR0cmlidXRlLlxuICAgKi9cbiAgZ2V0UGFzc3dvcmRQb2xpY3lQYXR0ZXJuRm9ySW5wdXQoKTogc3RyaW5nIHtcbiAgICBsZXQgcGF0dGVybiA9ICcnO1xuICAgIGlmICh0aGlzLnBhc3N3b3JkUG9saWN5LnJlcXVpcmVEaWdpdHMpIHBhdHRlcm4gKz0gYCg/PS4qWzAtOV0pYDtcbiAgICBpZiAodGhpcy5wYXNzd29yZFBvbGljeS5yZXF1aXJlTG93ZXJjYXNlKSBwYXR0ZXJuICs9IGAoPz0uKlthLXpdKWA7XG4gICAgaWYgKHRoaXMucGFzc3dvcmRQb2xpY3kucmVxdWlyZVN5bWJvbHMpIHBhdHRlcm4gKz0gYCg/PS4qW1xcXlxcJFxcKlxcLlxcX1xcflxcYFxcK1xcPUBcXCFcXD9cXD5cXDxcXDpcXDtcXFxcXFwsXFwjXFwlXFwmXSlgO1xuICAgIGlmICh0aGlzLnBhc3N3b3JkUG9saWN5LnJlcXVpcmVVcHBlcmNhc2UpIHBhdHRlcm4gKz0gYCg/PS4qW0EtWl0pYDtcbiAgICBwYXR0ZXJuICs9IGAueyR7dGhpcy5wYXNzd29yZFBvbGljeS5taW5MZW5ndGh9LH1gO1xuICAgIHJldHVybiBwYXR0ZXJuO1xuICB9XG59XG5cbi8qKlxuICogVGhlIHBvc3NpYmxlIGFjdGlvbnMgZm9sbG93aW5nIGEgc3VjY2Vzc2Z1bCBsb2dpbi5cbiAqL1xuZXhwb3J0IGVudW0gTG9naW5PdXRjb21lQWN0aW9ucyB7XG4gIE5PTkUgPSAnbm9uZScsXG4gIE5FV19QQVNTV09SRCA9ICduZXdQYXNzd29yZCcsXG4gIE1GQV9DSEFMTEVOR0UgPSAnbWZhQ2hhbGxlbmdlJyxcbiAgTUZBX1NFVFVQID0gJ21mYVNldHVwJ1xufVxuXG4vKipcbiAqIEdldCB0aGUgU0hBMSBoZXggdXBwZXJjYXNlIGhhc2ggb2YgYSBzdHJpbmcsIHVzaW5nIHdlYiBjcnlwdG8uXG4gKi9cbmNvbnN0IFNIQTEgPSBhc3luYyAoc3RyOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZyB8IG51bGw+ID0+IHtcbiAgaWYgKCF3aW5kb3cuY3J5cHRvKSByZXR1cm4gbnVsbDtcbiAgY29uc3QgbXNnVWludDggPSBuZXcgVGV4dEVuY29kZXIoKS5lbmNvZGUoc3RyKTtcbiAgY29uc3QgaGFzaEJ1ZmZlciA9IGF3YWl0IHdpbmRvdy5jcnlwdG8uc3VidGxlLmRpZ2VzdCgnU0hBLTEnLCBtc2dVaW50OCk7XG4gIGNvbnN0IGhhc2hBcnJheSA9IEFycmF5LmZyb20obmV3IFVpbnQ4QXJyYXkoaGFzaEJ1ZmZlcikpO1xuICBjb25zdCBoYXNoSGV4ID0gaGFzaEFycmF5Lm1hcChiID0+IGIudG9TdHJpbmcoMTYpLnBhZFN0YXJ0KDIsICcwJykpLmpvaW4oJycpO1xuICByZXR1cm4gaGFzaEhleC50b1VwcGVyQ2FzZSgpO1xufTtcbiJdfQ==
|