@lifeready/core 5.0.9 → 5.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundles/lifeready-core.umd.js +1515 -734
- package/bundles/lifeready-core.umd.js.map +1 -1
- package/bundles/lifeready-core.umd.min.js +1 -1
- package/bundles/lifeready-core.umd.min.js.map +1 -1
- package/esm2015/lib/_common/key.js +28 -0
- package/esm2015/lib/_common/types.js +1 -1
- package/esm2015/lib/api/types/lr-graphql.types.js +1 -1
- package/esm2015/lib/auth/auth.types.js +1 -3
- package/esm2015/lib/auth2/auth2.gql.private.js +78 -0
- package/esm2015/lib/auth2/auth2.service.js +591 -0
- package/esm2015/lib/auth2/auth2.types.js +21 -0
- package/esm2015/lib/contact-card/contact-card.service.js +3 -3
- package/esm2015/lib/contact-card/contact-card2.service.js +3 -3
- package/esm2015/lib/item2/item2.service.js +9 -9
- package/esm2015/lib/key/key-factory.service.js +1 -1
- package/esm2015/lib/key/key-graph.service.js +2 -2
- package/esm2015/lib/key/key-meta.service.js +2 -2
- package/esm2015/lib/key/key.service.js +6 -6
- package/esm2015/lib/key-exchange/key-exchange.service.js +24 -29
- package/esm2015/lib/key-exchange/key-exchange2.service.js +16 -17
- package/esm2015/lib/lbop/lbop.service.js +13 -14
- package/esm2015/lib/profile/profile.service.js +2 -2
- package/esm2015/lib/profile/profile.types.js +1 -1
- package/esm2015/lib/register/register.service.js +1 -1
- package/esm2015/lib/register/register.types.js +3 -0
- package/esm2015/lib/server-config/server-config.gql.js +1 -1
- package/esm2015/lib/shared-contact-card/shared-contact-card.service.js +3 -3
- package/esm2015/lib/shared-contact-card/shared-contact-card2.service.js +2 -2
- package/esm2015/lib/tp-assembly/tp-assembly.js +3 -3
- package/esm2015/lib/trusted-party/trusted-party2.service.js +4 -4
- package/esm2015/public-api.js +4 -1
- package/fesm2015/lifeready-core.js +876 -199
- package/fesm2015/lifeready-core.js.map +1 -1
- package/lib/_common/key.d.ts +14 -0
- package/lib/_common/types.d.ts +6 -0
- package/lib/api/types/lr-graphql.types.d.ts +1 -0
- package/lib/auth/auth.types.d.ts +0 -6
- package/lib/auth2/auth2.gql.private.d.ts +12 -0
- package/lib/auth2/auth2.service.d.ts +70 -0
- package/lib/auth2/auth2.types.d.ts +50 -0
- package/lib/item2/item2.service.d.ts +3 -3
- package/lib/key/key-factory.service.d.ts +1 -0
- package/lib/key/key-graph.service.d.ts +2 -3
- package/lib/key/key.service.d.ts +5 -5
- package/lib/key-exchange/key-exchange.service.d.ts +3 -5
- package/lib/lbop/lbop.service.d.ts +3 -3
- package/lib/profile/profile.types.d.ts +2 -2
- package/lib/register/register.service.d.ts +1 -1
- package/lib/register/register.types.d.ts +6 -0
- package/lib/server-config/server-config.gql.d.ts +1 -1
- package/lib/server-config/server-config.service.d.ts +1 -1
- package/lib/shared-contact-card/shared-contact-card.service.d.ts +2 -2
- package/lifeready-core.metadata.json +1 -1
- package/package.json +1 -1
- package/public-api.d.ts +3 -0
|
@@ -0,0 +1,591 @@
|
|
|
1
|
+
var Auth2Service_1;
|
|
2
|
+
import { __awaiter, __decorate } from "tslib";
|
|
3
|
+
import { HttpClient } from '@angular/common/http';
|
|
4
|
+
import { Inject, Injectable, Injector, isDevMode, NgZone } from '@angular/core';
|
|
5
|
+
import { AuthClass } from '@aws-amplify/auth/lib-esm/Auth';
|
|
6
|
+
import { Hub } from '@aws-amplify/core';
|
|
7
|
+
import { JWK } from 'node-jose';
|
|
8
|
+
import { LrGraphQLService, LrMutation, LrService } from '../api/lr-graphql';
|
|
9
|
+
import { TpClaimState } from '../api/types';
|
|
10
|
+
import { SetSessionEncryptionKeyMutation } from '../auth/auth.gql';
|
|
11
|
+
import { EncryptionService } from '../encryption/encryption.service';
|
|
12
|
+
import { IdleService } from '../idle/idle.service';
|
|
13
|
+
import { KeyFactoryService } from '../key/key-factory.service';
|
|
14
|
+
import { KeyGraphService } from '../key/key-graph.service';
|
|
15
|
+
import { KeyService } from '../key/key.service';
|
|
16
|
+
import { KC_CONFIG } from '../life-ready.config';
|
|
17
|
+
import { PasswordService } from '../password/password.service';
|
|
18
|
+
import { PersistService } from '../persist/persist.service';
|
|
19
|
+
import { TP_PASSWORD_RESET_CLIENT_NONCE_LENGTH, TP_PASSWORD_RESET_USERNAME_SUFFIX, } from '../tp-password-reset/tp-password-reset.constants';
|
|
20
|
+
import { TpPasswordResetAssemblyController } from '../tp-password-reset/tp-password-reset.controller';
|
|
21
|
+
import { CompleteTpPasswordResetRequestMutation, CreateTpAssemblyKeyChallengeMutation, PreCompleteTpPasswordResetRequestMutation, } from '../tp-password-reset/tp-password-reset.gql';
|
|
22
|
+
import { KcBadRequestException, KcBadStateException, KcConcurrentAccessException, KcInternalErrorException, } from '../_common/exceptions';
|
|
23
|
+
import { KeyContainer } from '../_common/key';
|
|
24
|
+
import { RunOutsideAngular } from '../_common/run-outside-angular';
|
|
25
|
+
import { CurrentUserQuery, } from './auth2.gql.private';
|
|
26
|
+
import { CognitoChallengeName, PasswordChangeStatus, RecoveryStatus, } from './auth2.types';
|
|
27
|
+
import * as i0 from "@angular/core";
|
|
28
|
+
import * as i1 from "@angular/common/http";
|
|
29
|
+
import * as i2 from "@aws-amplify/auth/lib-esm/Auth";
|
|
30
|
+
import * as i3 from "../api/lr-graphql/lr-graphql.service";
|
|
31
|
+
import * as i4 from "../key/key.service";
|
|
32
|
+
import * as i5 from "../key/key-graph.service";
|
|
33
|
+
import * as i6 from "../key/key-factory.service";
|
|
34
|
+
import * as i7 from "../password/password.service";
|
|
35
|
+
import * as i8 from "../idle/idle.service";
|
|
36
|
+
import * as i9 from "../persist/persist.service";
|
|
37
|
+
import * as i10 from "../encryption/encryption.service";
|
|
38
|
+
import * as i11 from "../tp-password-reset/tp-password-reset.controller";
|
|
39
|
+
import * as i12 from "../life-ready.config";
|
|
40
|
+
let Auth2Service = Auth2Service_1 = class Auth2Service extends LrService {
|
|
41
|
+
constructor(ngZone, injector, http, cognito, api, keyService, keyGraphService, keyFactoryService, passwordService, idleService, persistService, encryptionService, assemblyController, kcConfig) {
|
|
42
|
+
super(injector);
|
|
43
|
+
this.ngZone = ngZone;
|
|
44
|
+
this.injector = injector;
|
|
45
|
+
this.http = http;
|
|
46
|
+
this.cognito = cognito;
|
|
47
|
+
this.api = api;
|
|
48
|
+
this.keyService = keyService;
|
|
49
|
+
this.keyGraphService = keyGraphService;
|
|
50
|
+
this.keyFactoryService = keyFactoryService;
|
|
51
|
+
this.passwordService = passwordService;
|
|
52
|
+
this.idleService = idleService;
|
|
53
|
+
this.persistService = persistService;
|
|
54
|
+
this.encryptionService = encryptionService;
|
|
55
|
+
this.assemblyController = assemblyController;
|
|
56
|
+
this.kcConfig = kcConfig;
|
|
57
|
+
// Could use rxjs observables here. But trying to have kc-client use as little angular
|
|
58
|
+
// features as possible. Rxjs is not used anywhere else in kc-client.
|
|
59
|
+
this.logoutListeners = new Set();
|
|
60
|
+
// Stores the password for use after mfa verification to decrypt masterKey.
|
|
61
|
+
this.password = null;
|
|
62
|
+
if (!isDevMode()) {
|
|
63
|
+
if (this.kcConfig.debug != null) {
|
|
64
|
+
throw new KcBadRequestException('In production mode, "KcConfig.debug" must be set to null');
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
importPassword(plainPassword) {
|
|
69
|
+
return this.keyFactoryService.importPassword(plainPassword);
|
|
70
|
+
}
|
|
71
|
+
logout() {
|
|
72
|
+
var _a;
|
|
73
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
74
|
+
// Notify all listeners to clean up.
|
|
75
|
+
yield Promise.all([...this.logoutListeners].map((callback) => callback()));
|
|
76
|
+
this.user = null;
|
|
77
|
+
this.keyService.purgeKeys();
|
|
78
|
+
this.keyGraphService.purgeKeys();
|
|
79
|
+
// Sign out on both cognito and kc-server
|
|
80
|
+
yield Promise.all([this.cognito.signOut(), this.kcLogout()]);
|
|
81
|
+
if ((_a = this.kcConfig.debug) === null || _a === void 0 ? void 0 : _a.username) {
|
|
82
|
+
this.kcConfig.debug.username = null;
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
addLogoutListener(callback) {
|
|
87
|
+
this.logoutListeners.add(callback);
|
|
88
|
+
}
|
|
89
|
+
removeLogoutListener(callback) {
|
|
90
|
+
this.logoutListeners.delete(callback);
|
|
91
|
+
}
|
|
92
|
+
login(emailOrPhone, password, { tpPasswordResetAutoComplete = true } = {}) {
|
|
93
|
+
var _a;
|
|
94
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
95
|
+
let loginResult = yield this.loginImpl(emailOrPhone, password);
|
|
96
|
+
// Save the password for use after meeting challenge.
|
|
97
|
+
if (loginResult.challenge) {
|
|
98
|
+
this.password = new KeyContainer(password, Auth2Service_1.CHALLENGE_TIMEOUT);
|
|
99
|
+
return loginResult;
|
|
100
|
+
}
|
|
101
|
+
if (tpPasswordResetAutoComplete &&
|
|
102
|
+
((_a = loginResult.user.resetUser) === null || _a === void 0 ? void 0 : _a.state) === TpClaimState.APPROVED) {
|
|
103
|
+
yield this.completeResetRequest(password);
|
|
104
|
+
loginResult = yield this.loginImpl(emailOrPhone, password);
|
|
105
|
+
}
|
|
106
|
+
return loginResult;
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
verifyLogin(options) {
|
|
110
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
111
|
+
const { challenge, code, rememberMe } = options;
|
|
112
|
+
const VALID_CHALLENGE_NAMES = [
|
|
113
|
+
CognitoChallengeName.SMS_MFA,
|
|
114
|
+
CognitoChallengeName.SOFTWARE_TOKEN_MFA,
|
|
115
|
+
];
|
|
116
|
+
if (!VALID_CHALLENGE_NAMES.includes(challenge.cognitoUser.challengeName)) {
|
|
117
|
+
throw new KcBadRequestException(`challengeName must be one of ${VALID_CHALLENGE_NAMES}`);
|
|
118
|
+
}
|
|
119
|
+
// TODO: this.auth.confirmSignIn() could return another challenge.
|
|
120
|
+
const cognitoUser = yield this.cognito.confirmSignIn(challenge.cognitoUser, code, challenge.cognitoUser.challengeName);
|
|
121
|
+
yield this.handlePostAuth(challenge.recoveryStatus);
|
|
122
|
+
const user = yield this.loadUser(cognitoUser, this.password.pop());
|
|
123
|
+
// This is not strictly necessary since the this.password.pop() already clears the
|
|
124
|
+
// password inside the container. But doesn't hurt either.
|
|
125
|
+
this.password = null;
|
|
126
|
+
if (rememberMe) {
|
|
127
|
+
cognitoUser.setDeviceStatusRemembered({
|
|
128
|
+
onSuccess: () => {
|
|
129
|
+
return;
|
|
130
|
+
},
|
|
131
|
+
onFailure: (e) => console.error(e),
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
return {
|
|
135
|
+
user,
|
|
136
|
+
};
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
getUser() {
|
|
140
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
141
|
+
if (this.user) {
|
|
142
|
+
return this.user;
|
|
143
|
+
}
|
|
144
|
+
const cognitoUser = yield this.cognito.currentAuthenticatedUser();
|
|
145
|
+
return this.loadUser(cognitoUser);
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
refreshAccessToken() {
|
|
149
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
150
|
+
const cognitoUser = yield this.cognito.currentAuthenticatedUser();
|
|
151
|
+
const refreshToken = cognitoUser.getSignInUserSession().getRefreshToken();
|
|
152
|
+
console.log('Token refresh...');
|
|
153
|
+
return new Promise((resolve, reject) => {
|
|
154
|
+
cognitoUser.refreshSession(refreshToken, (err) => {
|
|
155
|
+
if (err) {
|
|
156
|
+
console.error('Error refreshing token: ', err);
|
|
157
|
+
reject(err);
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
console.log('Token refresh complete');
|
|
161
|
+
resolve(0);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
// ----------------------------------------------------------------------------------------------------
|
|
168
|
+
// Helpers
|
|
169
|
+
// ----------------------------------------------------------------------------------------------------
|
|
170
|
+
fetchCurrentUser() {
|
|
171
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
172
|
+
return (yield this.api.query({
|
|
173
|
+
query: CurrentUserQuery,
|
|
174
|
+
processorOptions: {
|
|
175
|
+
hasKeys: false,
|
|
176
|
+
},
|
|
177
|
+
})).currentUser;
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
fetchResetUser() {
|
|
181
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
182
|
+
return (yield this.api.query({
|
|
183
|
+
query: CurrentUserQuery,
|
|
184
|
+
processorOptions: {
|
|
185
|
+
hasKeys: false,
|
|
186
|
+
},
|
|
187
|
+
})).tpPasswordResetUser;
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
kcLogout() {
|
|
191
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
192
|
+
yield this.http
|
|
193
|
+
.post(`${this.kcConfig.authUrl}auth/sign-out/`, null, {
|
|
194
|
+
withCredentials: true,
|
|
195
|
+
responseType: 'text',
|
|
196
|
+
})
|
|
197
|
+
.toPromise();
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
fetchPassIdpParams(emailOrPhone) {
|
|
201
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
202
|
+
return yield this.http
|
|
203
|
+
.get(`${this.kcConfig.authUrl}users/pass-idp-params/?login_name=${encodeURIComponent(emailOrPhone)}`)
|
|
204
|
+
.toPromise();
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
loginImpl(emailOrPhone, password) {
|
|
208
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
209
|
+
yield this.logout();
|
|
210
|
+
const loginIdpResult = yield this.loginIdp(emailOrPhone, password);
|
|
211
|
+
// Can't get the user yet because we still ned to meet MFA challenges
|
|
212
|
+
if ([
|
|
213
|
+
CognitoChallengeName.SMS_MFA,
|
|
214
|
+
CognitoChallengeName.SOFTWARE_TOKEN_MFA,
|
|
215
|
+
].includes(loginIdpResult.cognitoUser.challengeName)) {
|
|
216
|
+
return {
|
|
217
|
+
challenge: {
|
|
218
|
+
cognitoUser: loginIdpResult.cognitoUser,
|
|
219
|
+
recoveryStatus: loginIdpResult.recoveryStatus,
|
|
220
|
+
},
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
yield this.handlePostAuth(loginIdpResult.recoveryStatus);
|
|
224
|
+
// There should be no MFA on the TP reset user.
|
|
225
|
+
const user = yield this.loadUser(loginIdpResult.cognitoUser, password);
|
|
226
|
+
return {
|
|
227
|
+
user,
|
|
228
|
+
};
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
loginIdp(emailOrPhone, password) {
|
|
232
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
233
|
+
// Download the salt needed to derive the PassIdp
|
|
234
|
+
const passIdpApiResult = yield this.fetchPassIdpParams(emailOrPhone);
|
|
235
|
+
if (passIdpApiResult.passwordChangeStatus === PasswordChangeStatus.IN_PROGRESS) {
|
|
236
|
+
throw new KcConcurrentAccessException('A password change is in progress');
|
|
237
|
+
}
|
|
238
|
+
if (passIdpApiResult.passwordChangeStatus === PasswordChangeStatus.RECOVERY) {
|
|
239
|
+
console.log('In recovery mode.');
|
|
240
|
+
// Let's say we don't know if the password is the new one or the old one. We just have to try both.
|
|
241
|
+
try {
|
|
242
|
+
const user = {
|
|
243
|
+
cognitoUser: yield this.loginIdpImpl(emailOrPhone, password, passIdpApiResult.newPassIdpParams),
|
|
244
|
+
recoveryStatus: RecoveryStatus.NEW_PASSWORD,
|
|
245
|
+
};
|
|
246
|
+
// New password worked. Let's set to the current password
|
|
247
|
+
// --Potential Failure Point 1--
|
|
248
|
+
// if changePasswordComplete() doesn't get called, then it should remain
|
|
249
|
+
console.log('New password works!');
|
|
250
|
+
return user;
|
|
251
|
+
}
|
|
252
|
+
catch (error) {
|
|
253
|
+
// Just bubble up any other type of error.
|
|
254
|
+
if (error.code !== 'NotAuthorizedException') {
|
|
255
|
+
throw error;
|
|
256
|
+
}
|
|
257
|
+
// pass, try again assuming it's the old password
|
|
258
|
+
}
|
|
259
|
+
// Now assume it's the previous password. Any exception is allowed to bubble up.
|
|
260
|
+
try {
|
|
261
|
+
const user = {
|
|
262
|
+
cognitoUser: yield this.loginIdpImpl(emailOrPhone, password, passIdpApiResult.currentPassIdpParams),
|
|
263
|
+
recoveryStatus: RecoveryStatus.OLD_PASSWORD,
|
|
264
|
+
};
|
|
265
|
+
// Old password worked.
|
|
266
|
+
console.log('Old password works!');
|
|
267
|
+
return user;
|
|
268
|
+
}
|
|
269
|
+
catch (error) {
|
|
270
|
+
// Just bubble up any other type of error.
|
|
271
|
+
throw error.code === 'NotAuthorizedException'
|
|
272
|
+
? new KcBadRequestException('The password change request was interrupted, please try to login with both your new and old password')
|
|
273
|
+
: error;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
// Try again as the TP password reset account
|
|
277
|
+
if (passIdpApiResult.tpPasswordReset) {
|
|
278
|
+
try {
|
|
279
|
+
// TP password reset is in process. We need to try the password against both
|
|
280
|
+
// original account and the new reset account.
|
|
281
|
+
const reset = passIdpApiResult.tpPasswordReset;
|
|
282
|
+
const user = {
|
|
283
|
+
cognitoUser: yield this.loginIdpImpl(reset.resetUsername, password, reset.passIdpParams),
|
|
284
|
+
recoveryStatus: RecoveryStatus.NONE,
|
|
285
|
+
};
|
|
286
|
+
return user;
|
|
287
|
+
}
|
|
288
|
+
catch (err) {
|
|
289
|
+
// continue, try again as regular user.
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
// Login as regular user
|
|
293
|
+
const user = {
|
|
294
|
+
cognitoUser: yield this.loginIdpImpl(emailOrPhone, password, passIdpApiResult.currentPassIdpParams),
|
|
295
|
+
recoveryStatus: RecoveryStatus.NONE,
|
|
296
|
+
};
|
|
297
|
+
return user;
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
loginIdpImpl(emailOrPhone, password, passIdpParams) {
|
|
301
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
302
|
+
const passIdpResult = yield this.keyFactoryService.derivePassIdp(Object.assign({ password }, passIdpParams));
|
|
303
|
+
// Use the derived password to signin with cognito
|
|
304
|
+
return this.cognito.signIn(emailOrPhone, this.passwordService.getPassIdpString(passIdpResult.jwk));
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
handlePostAuth(recoveryStatus) {
|
|
308
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
309
|
+
yield this.handlePasswordRecovery(recoveryStatus);
|
|
310
|
+
yield this.handleSessionEncryptionKey();
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
handlePasswordRecovery(recoveryStatus) {
|
|
314
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
315
|
+
if (recoveryStatus !== RecoveryStatus.NONE) {
|
|
316
|
+
yield this.passwordService.changePasswordComplete({
|
|
317
|
+
useNewPassword: recoveryStatus === RecoveryStatus.NEW_PASSWORD,
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
handleSessionEncryptionKey() {
|
|
323
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
324
|
+
if (this.kcConfig.disableSessionEncryptionKey) {
|
|
325
|
+
if (!isDevMode()) {
|
|
326
|
+
const msg = 'You should not set disableSessionEncryptionKey=True in mode prod. It defaults to false.';
|
|
327
|
+
console.error(msg);
|
|
328
|
+
throw new KcInternalErrorException(msg);
|
|
329
|
+
}
|
|
330
|
+
else {
|
|
331
|
+
console.warn('You have set disableSessionEncryptionKey=True. Make sure not to do this in prod mode.');
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
else {
|
|
335
|
+
// Set the session key to a new encryption key for this session
|
|
336
|
+
const sessionEncryptionKey = yield this.keyFactoryService.createKey();
|
|
337
|
+
yield this.lrGraphQL.lrMutate(new LrMutation({
|
|
338
|
+
mutation: SetSessionEncryptionKeyMutation,
|
|
339
|
+
variables: {
|
|
340
|
+
input: {
|
|
341
|
+
sessionEncryptionKey: JSON.stringify(sessionEncryptionKey.toJSON(true)),
|
|
342
|
+
},
|
|
343
|
+
},
|
|
344
|
+
}), {
|
|
345
|
+
includeKeyGraph: false,
|
|
346
|
+
});
|
|
347
|
+
this.persistService.setServerSessionEncryptionKey(sessionEncryptionKey);
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
getCognitoUserAttribute(attributeName, userAttributes) {
|
|
352
|
+
const userAttribute = userAttributes.find((x) => x.getName() === attributeName);
|
|
353
|
+
return userAttribute ? userAttribute.getValue() : null;
|
|
354
|
+
}
|
|
355
|
+
loadUserKeys(options) {
|
|
356
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
357
|
+
const { userKeys, password, sessionEncryptionKey } = options;
|
|
358
|
+
if (sessionEncryptionKey) {
|
|
359
|
+
this.persistService.setServerSessionEncryptionKey(yield JWK.asKey(sessionEncryptionKey));
|
|
360
|
+
}
|
|
361
|
+
// password is not needed if the master key is already persisted.
|
|
362
|
+
if (password) {
|
|
363
|
+
const passKey = (yield this.keyFactoryService.derivePassKey(Object.assign({ password }, userKeys.passKey.passKeyParams))).jwk;
|
|
364
|
+
yield this.idleService.persistMasterKey(yield this.keyGraphService.unwrapWithPassKey(userKeys.passKey.id, passKey, userKeys.masterKey.id));
|
|
365
|
+
}
|
|
366
|
+
yield this.keyGraphService.populateKeys(userKeys);
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
loadUser(cognitoUser, password) {
|
|
370
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
371
|
+
if (cognitoUser.getUsername().endsWith(TP_PASSWORD_RESET_USERNAME_SUFFIX)) {
|
|
372
|
+
this.user = yield this.loadResetUser(cognitoUser, password);
|
|
373
|
+
}
|
|
374
|
+
else {
|
|
375
|
+
this.user = yield this.loadRegularUser(cognitoUser, password);
|
|
376
|
+
}
|
|
377
|
+
yield this.idleService.start(); // Run idleService whenever user is logged in.
|
|
378
|
+
return this.user;
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
loadRegularUser(cognitoUser, password) {
|
|
382
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
383
|
+
const currentUser = yield this.fetchCurrentUser();
|
|
384
|
+
yield this.loadUserKeys({
|
|
385
|
+
userKeys: currentUser.currentUserKey,
|
|
386
|
+
password,
|
|
387
|
+
sessionEncryptionKey: currentUser.sessionEncryptionKey,
|
|
388
|
+
});
|
|
389
|
+
const { username } = currentUser;
|
|
390
|
+
const userAttributes = yield this.cognito.userAttributes(cognitoUser);
|
|
391
|
+
return {
|
|
392
|
+
username,
|
|
393
|
+
sub: this.getCognitoUserAttribute('sub', userAttributes),
|
|
394
|
+
loginEmail: this.getCognitoUserAttribute('email', userAttributes),
|
|
395
|
+
resetUser: null,
|
|
396
|
+
};
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
loadResetUser(cognitoUser, password) {
|
|
400
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
401
|
+
const resetUser = yield this.fetchResetUser();
|
|
402
|
+
this.loadUserKeys({
|
|
403
|
+
userKeys: {
|
|
404
|
+
passKey: {
|
|
405
|
+
id: resetUser.passKey.id,
|
|
406
|
+
},
|
|
407
|
+
masterKey: {
|
|
408
|
+
id: resetUser.masterKey.id,
|
|
409
|
+
},
|
|
410
|
+
},
|
|
411
|
+
password,
|
|
412
|
+
sessionEncryptionKey: resetUser.sessionEncryptionKey,
|
|
413
|
+
});
|
|
414
|
+
const { username } = resetUser;
|
|
415
|
+
const userAttributes = yield this.cognito.userAttributes(cognitoUser);
|
|
416
|
+
return {
|
|
417
|
+
username,
|
|
418
|
+
sub: this.getCognitoUserAttribute('sub', userAttributes),
|
|
419
|
+
loginEmail: this.getCognitoUserAttribute('email', userAttributes),
|
|
420
|
+
resetUser: {
|
|
421
|
+
state: resetUser.state,
|
|
422
|
+
},
|
|
423
|
+
};
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
recoverAssemblyKey(resetUser) {
|
|
427
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
428
|
+
const prk = yield this.keyGraphService.getKey(resetUser.pxk.id);
|
|
429
|
+
const partials = yield Promise.all(resetUser.approvals
|
|
430
|
+
.filter((approval) => !!approval.receiverCipherPartialAssemblyKey)
|
|
431
|
+
.map((approval) => this.encryptionService.decrypt(prk, approval.receiverCipherPartialAssemblyKey)));
|
|
432
|
+
return this.assemblyController.recoverAssemblyKey(partials);
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
completeResetRequest(newPassword) {
|
|
436
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
437
|
+
const resetUser = yield this.fetchResetUser();
|
|
438
|
+
if (resetUser.state !== TpClaimState.APPROVED) {
|
|
439
|
+
throw new KcBadStateException('Password reset request has not been approved.');
|
|
440
|
+
}
|
|
441
|
+
// --------------------------------------------------------------
|
|
442
|
+
// Prepare all materials to ensure there are no errors.
|
|
443
|
+
// --------------------------------------------------------------
|
|
444
|
+
const assemblyKey = yield this.recoverAssemblyKey(resetUser);
|
|
445
|
+
const { rootKey } = yield this.encryptionService.decrypt(assemblyKey, resetUser.assemblyCipherData);
|
|
446
|
+
// Making sure it's a valid key.
|
|
447
|
+
const rootKeyJwk = yield JWK.asKey(rootKey);
|
|
448
|
+
const masterKey = yield this.keyGraphService.getKey(resetUser.masterKey.id);
|
|
449
|
+
const masterKeyWrappedRootKey = yield this.encryptionService.encryptToString(masterKey.jwk, rootKeyJwk.toJSON(true));
|
|
450
|
+
// The new password
|
|
451
|
+
const newPassIdpResult = yield this.keyFactoryService.derivePassIdp(Object.assign({ password: newPassword }, resetUser.passKey.passIdpParams));
|
|
452
|
+
const newIdpPassword = this.passwordService.getPassIdpString(newPassIdpResult.jwk);
|
|
453
|
+
// --------------------------------------------------------------
|
|
454
|
+
// Get assembly key challenge
|
|
455
|
+
// --------------------------------------------------------------
|
|
456
|
+
const challenge = (yield this.lrGraphQL.lrMutate(new LrMutation({
|
|
457
|
+
mutation: CreateTpAssemblyKeyChallengeMutation,
|
|
458
|
+
variables: {
|
|
459
|
+
input: {},
|
|
460
|
+
},
|
|
461
|
+
}), {
|
|
462
|
+
includeKeyGraph: false,
|
|
463
|
+
})).createTpAssemblyKeyChallenge.challenge;
|
|
464
|
+
// Sign the challenge
|
|
465
|
+
// Generate a client side nonce that's no in the server's control.
|
|
466
|
+
challenge.clientNonce = this.keyFactoryService.randomString(TP_PASSWORD_RESET_CLIENT_NONCE_LENGTH);
|
|
467
|
+
const assemblyKeyVerifierPrk = yield this.encryptionService.decrypt(assemblyKey, resetUser.wrappedAssemblyKeyVerifierPrk);
|
|
468
|
+
const signedChallenge = yield this.encryptionService.sign(assemblyKeyVerifierPrk, challenge);
|
|
469
|
+
// --------------------------------------------------------------
|
|
470
|
+
// Change password for the original user
|
|
471
|
+
// --------------------------------------------------------------
|
|
472
|
+
const tempIdpPassword = (yield this.lrGraphQL.lrMutate(new LrMutation({
|
|
473
|
+
mutation: PreCompleteTpPasswordResetRequestMutation,
|
|
474
|
+
variables: {
|
|
475
|
+
input: {
|
|
476
|
+
signedChallenge: JSON.stringify(signedChallenge),
|
|
477
|
+
},
|
|
478
|
+
},
|
|
479
|
+
}), {
|
|
480
|
+
includeKeyGraph: false,
|
|
481
|
+
})).preCompleteTpPasswordResetRequest.idpPassword;
|
|
482
|
+
// --------------------------------------------------------------
|
|
483
|
+
// Login as the original user using new temporary password
|
|
484
|
+
// --------------------------------------------------------------
|
|
485
|
+
// At this point, the original account's password has been changed
|
|
486
|
+
// to a temporary password. It is no longer possible for the user
|
|
487
|
+
// to use the original password to login. Any successful login
|
|
488
|
+
// can only be using the temporary password. So it's safe to assume
|
|
489
|
+
// that we want to "complete" the password reset.
|
|
490
|
+
// There maybe 2FA so we listen for the auth event from Amplify.
|
|
491
|
+
const retPromise = new Promise((resolve) => {
|
|
492
|
+
const listener = (data) => __awaiter(this, void 0, void 0, function* () {
|
|
493
|
+
if (data.payload.event !== 'signIn') {
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
Hub.remove('auth', listener);
|
|
497
|
+
yield this.cognito.signIn(resetUser.username, newIdpPassword);
|
|
498
|
+
// Switch over to the new set of keys
|
|
499
|
+
yield this.lrGraphQL.lrMutate(new LrMutation({
|
|
500
|
+
mutation: CompleteTpPasswordResetRequestMutation,
|
|
501
|
+
variables: {
|
|
502
|
+
input: {
|
|
503
|
+
masterKeyWrappedRootKey,
|
|
504
|
+
masterKeyId: masterKey.id,
|
|
505
|
+
},
|
|
506
|
+
},
|
|
507
|
+
}));
|
|
508
|
+
resolve();
|
|
509
|
+
});
|
|
510
|
+
Hub.listen('auth', listener);
|
|
511
|
+
});
|
|
512
|
+
// Signin as the original user. Password has been reset to temporary one. It should return
|
|
513
|
+
// with NEW_PASSWORD_REQUIRED
|
|
514
|
+
let user = yield this.cognito.signIn(resetUser.username, tempIdpPassword, {
|
|
515
|
+
noProxy: 'true',
|
|
516
|
+
});
|
|
517
|
+
if (user.challengeName !== 'NEW_PASSWORD_REQUIRED') {
|
|
518
|
+
throw new KcInternalErrorException('Expecting Cognito to have done a password reset after call to PreCompleteTpPasswordResetRequestMutation.');
|
|
519
|
+
}
|
|
520
|
+
// Set new password on Idp
|
|
521
|
+
// the awsFetch() function passes NEW_PASSWORD_REQUIRED directly to AWS without
|
|
522
|
+
// going through the proxy.
|
|
523
|
+
user = yield this.cognito.completeNewPassword(user, newIdpPassword, {});
|
|
524
|
+
return retPromise;
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
// ------------------------------------------------------
|
|
528
|
+
// Debug utilities
|
|
529
|
+
// ------------------------------------------------------
|
|
530
|
+
debugLogin(username, password) {
|
|
531
|
+
// This will fail if debug is null. But when debug is null, this function
|
|
532
|
+
// should not be called.
|
|
533
|
+
this.kcConfig.debug.username = username;
|
|
534
|
+
return this.debugLoadUser(password);
|
|
535
|
+
}
|
|
536
|
+
debugLoadUser(password) {
|
|
537
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
538
|
+
const currentUser = yield this.fetchCurrentUser();
|
|
539
|
+
const { username, currentUserKey } = currentUser;
|
|
540
|
+
// Debug mode can not deal with session encryption key yet.
|
|
541
|
+
// NO SESSION ENCRYPTION KEY.
|
|
542
|
+
const passKey = (yield this.keyFactoryService.derivePassKey(Object.assign({ password }, currentUserKey.passKey.passKeyParams))).jwk;
|
|
543
|
+
const masterKey = yield this.keyGraphService.unwrapWithPassKey(currentUserKey.passKey.id, passKey, currentUserKey.masterKey.id);
|
|
544
|
+
yield this.idleService.persistMasterKey(masterKey);
|
|
545
|
+
yield this.keyGraphService.populateKeys(currentUserKey);
|
|
546
|
+
this.user = {
|
|
547
|
+
username,
|
|
548
|
+
resetUser: null,
|
|
549
|
+
sub: 'DEBUG_MODE',
|
|
550
|
+
loginEmail: 'DEBUG_MODE',
|
|
551
|
+
};
|
|
552
|
+
return this.user;
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
/**
|
|
556
|
+
* Clears the caches user. So we can simulate a page refresh and test getUser().
|
|
557
|
+
*/
|
|
558
|
+
debugClearUser() {
|
|
559
|
+
this.user = null;
|
|
560
|
+
}
|
|
561
|
+
};
|
|
562
|
+
Auth2Service.CHALLENGE_TIMEOUT = 1000 * 60 * 5;
|
|
563
|
+
Auth2Service.ɵprov = i0.ɵɵdefineInjectable({ factory: function Auth2Service_Factory() { return new Auth2Service(i0.ɵɵinject(i0.NgZone), i0.ɵɵinject(i0.INJECTOR), i0.ɵɵinject(i1.HttpClient), i0.ɵɵinject(i2.AuthClass), i0.ɵɵinject(i3.LrGraphQLService), i0.ɵɵinject(i4.KeyService), i0.ɵɵinject(i5.KeyGraphService), i0.ɵɵinject(i6.KeyFactoryService), i0.ɵɵinject(i7.PasswordService), i0.ɵɵinject(i8.IdleService), i0.ɵɵinject(i9.PersistService), i0.ɵɵinject(i10.EncryptionService), i0.ɵɵinject(i11.TpPasswordResetAssemblyController), i0.ɵɵinject(i12.KC_CONFIG)); }, token: Auth2Service, providedIn: "root" });
|
|
564
|
+
Auth2Service.decorators = [
|
|
565
|
+
{ type: Injectable, args: [{
|
|
566
|
+
providedIn: 'root',
|
|
567
|
+
},] }
|
|
568
|
+
];
|
|
569
|
+
Auth2Service.ctorParameters = () => [
|
|
570
|
+
{ type: NgZone },
|
|
571
|
+
{ type: Injector },
|
|
572
|
+
{ type: HttpClient },
|
|
573
|
+
{ type: AuthClass },
|
|
574
|
+
{ type: LrGraphQLService },
|
|
575
|
+
{ type: KeyService },
|
|
576
|
+
{ type: KeyGraphService },
|
|
577
|
+
{ type: KeyFactoryService },
|
|
578
|
+
{ type: PasswordService },
|
|
579
|
+
{ type: IdleService },
|
|
580
|
+
{ type: PersistService },
|
|
581
|
+
{ type: EncryptionService },
|
|
582
|
+
{ type: TpPasswordResetAssemblyController },
|
|
583
|
+
{ type: undefined, decorators: [{ type: Inject, args: [KC_CONFIG,] }] }
|
|
584
|
+
];
|
|
585
|
+
Auth2Service = Auth2Service_1 = __decorate([
|
|
586
|
+
RunOutsideAngular({
|
|
587
|
+
ngZoneName: 'ngZone',
|
|
588
|
+
})
|
|
589
|
+
], Auth2Service);
|
|
590
|
+
export { Auth2Service };
|
|
591
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0aDIuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2NvcmUvc3JjL2xpYi9hdXRoMi9hdXRoMi5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ2xELE9BQU8sRUFBRSxNQUFNLEVBQUUsVUFBVSxFQUFFLFFBQVEsRUFBRSxTQUFTLEVBQUUsTUFBTSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBRWhGLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUMzRCxPQUFPLEVBQUUsR0FBRyxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFFeEMsT0FBTyxFQUFFLEdBQUcsRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUNoQyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsVUFBVSxFQUFFLFNBQVMsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQzVFLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDNUMsT0FBTyxFQUFFLCtCQUErQixFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDbkUsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sa0NBQWtDLENBQUM7QUFDckUsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ25ELE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQy9ELE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUMzRCxPQUFPLEVBQUUsVUFBVSxFQUFZLE1BQU0sb0JBQW9CLENBQUM7QUFFMUQsT0FBTyxFQUFZLFNBQVMsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQzNELE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUMvRCxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sNEJBQTRC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SSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUM7SUFDbkIsQ0FBQztDQUNGLENBQUE7QUEvdUJRLDhCQUFpQixHQUFHLElBQUksR0FBRyxFQUFFLEdBQUcsQ0FBQyxDQUFDOzs7WUFKMUMsVUFBVSxTQUFDO2dCQUNWLFVBQVUsRUFBRSxNQUFNO2FBQ25COzs7WUEzRGlELE1BQU07WUFBM0IsUUFBUTtZQUQ1QixVQUFVO1lBR1YsU0FBUztZQUlULGdCQUFnQjtZQU9oQixVQUFVO1lBRFYsZUFBZTtZQURmLGlCQUFpQjtZQUtqQixlQUFlO1lBTmYsV0FBVztZQU9YLGNBQWM7WUFSZCxpQkFBaUI7WUFhakIsaUNBQWlDOzRDQThEckMsTUFBTSxTQUFDLFNBQVM7O0FBeEJSLFlBQVk7SUFOeEIsaUJBQWlCLENBQUM7UUFDakIsVUFBVSxFQUFFLFFBQVE7S0FDckIsQ0FBQztHQUlXLFlBQVksQ0FndkJ4QjtTQWh2QlksWUFBWSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEh0dHBDbGllbnQgfSBmcm9tICdAYW5ndWxhci9jb21tb24vaHR0cCc7XG5pbXBvcnQgeyBJbmplY3QsIEluamVjdGFibGUsIEluamVjdG9yLCBpc0Rldk1vZGUsIE5nWm9uZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgQ29nbml0b1VzZXIgfSBmcm9tICdAYXdzLWFtcGxpZnkvYXV0aCc7XG5pbXBvcnQgeyBBdXRoQ2xhc3MgfSBmcm9tICdAYXdzLWFtcGxpZnkvYXV0aC9saWItZXNtL0F1dGgnO1xuaW1wb3J0IHsgSHViIH0gZnJvbSAnQGF3cy1hbXBsaWZ5L2NvcmUnO1xuaW1wb3J0IHsgQ29nbml0b1VzZXJBdHRyaWJ1dGUgfSBmcm9tICdhbWF6b24tY29nbml0by1pZGVudGl0eS1qcyc7XG5pbXBvcnQgeyBKV0sgfSBmcm9tICdub2RlLWpvc2UnO1xuaW1wb3J0IHsgTHJHcmFwaFFMU2VydmljZSwgTHJNdXRhdGlvbiwgTHJTZXJ2aWNlIH0gZnJvbSAnLi4vYXBpL2xyLWdyYXBocWwnO1xuaW1wb3J0IHsgVHBDbGFpbVN0YXRlIH0gZnJvbSAnLi4vYXBpL3R5cGVzJztcbmltcG9ydCB7IFNldFNlc3Npb25FbmNyeXB0aW9uS2V5TXV0YXRpb24gfSBmcm9tICcuLi9hdXRoL2F1dGguZ3FsJztcbmltcG9ydCB7IEVuY3J5cHRpb25TZXJ2aWNlIH0gZnJvbSAnLi4vZW5jcnlwdGlvbi9lbmNyeXB0aW9uLnNlcnZpY2UnO1xuaW1wb3J0IHsgSWRsZVNlcnZpY2UgfSBmcm9tICcuLi9pZGxlL2lkbGUuc2VydmljZSc7XG5pbXBvcnQgeyBLZXlGYWN0b3J5U2VydmljZSB9IGZyb20gJy4uL2tleS9rZXktZmFjdG9yeS5zZXJ2aWNlJztcbmltcG9ydCB7IEtleUdyYXBoU2VydmljZSB9IGZyb20gJy4uL2tleS9rZXktZ3JhcGguc2VydmljZSc7XG5pbXBvcnQgeyBLZXlTZXJ2aWNlLCBVc2VyS2V5cyB9IGZyb20gJy4uL2tleS9rZXkuc2VydmljZSc7XG5pbXBvcnQgeyBQYXNzSWRwUGFyYW1zIH0gZnJvbSAnLi4va2V5L2tleS50eXBlcyc7XG5pbXBvcnQgeyBLY0NvbmZpZywgS0NfQ09ORklHIH0gZnJvbSAnLi4vbGlmZS1yZWFkeS5jb25maWcnO1xuaW1wb3J0IHsgUGFzc3dvcmRTZXJ2aWNlIH0gZnJvbSAnLi4vcGFzc3dvcmQvcGFzc3dvcmQuc2VydmljZSc7XG5pbXBvcnQgeyBQZXJzaXN0U2VydmljZSB9IGZyb20gJy4uL3BlcnNpc3QvcGVyc2lzdC5zZXJ2aWNlJztcbmltcG9ydCB7XG4gIFRQX1BBU1NXT1JEX1JFU0VUX0NMSUVOVF9OT05DRV9MRU5HVEgsXG4gIFRQX1BBU1NXT1JEX1JFU0VUX1VTRVJOQU1FX1NVRkZJWCxcbn0gZnJvbSAnLi4vdHAtcGFzc3dvcmQtcmVzZXQvdHAtcGFzc3dvcmQtcmVzZXQuY29uc3RhbnRzJztcbmltcG9ydCB7IFRwUGFzc3dvcmRSZXNldEFzc2VtYmx5Q29udHJvbGxlciB9IGZyb20gJy4uL3RwLXBhc3N3b3JkLXJlc2V0L3RwLXBhc3N3b3JkLXJlc2V0LmNvbnRyb2xsZXInO1xuaW1wb3J0IHtcbiAgQ29tcGxldGVUcFBhc3N3b3JkUmVzZXRSZXF1ZXN0TXV0YXRpb24sXG4gIENyZWF0ZVRwQXNzZW1ibHlLZXlDaGFsbGVuZ2VNdXRhdGlvbixcbiAgUHJlQ29tcGxldGVUcFBhc3N3b3JkUmVzZXRSZXF1ZXN0TXV0YXRpb24sXG59IGZyb20gJy4uL3RwLXBhc3N3b3JkLXJlc2V0L3RwLXBhc3N3b3JkLXJlc2V0LmdxbCc7XG5pbXBvcnQge1xuICBLY0JhZFJlcXVlc3RFeGNlcHRpb24sXG4gIEtjQmFkU3RhdGVFeGNlcHRpb24sXG4gIEtjQ29uY3VycmVudEFjY2Vzc0V4Y2VwdGlvbixcbiAgS2NJbnRlcm5hbEVycm9yRXhjZXB0aW9uLFxufSBmcm9tICcuLi9fY29tbW9uL2V4Y2VwdGlvbnMnO1xuaW1wb3J0IHsgS2V5Q29udGFpbmVyIH0gZnJvbSAnLi4vX2NvbW1vbi9rZXknO1xuaW1wb3J0IHsgUnVuT3V0c2lkZUFuZ3VsYXIgfSBmcm9tICcuLi9fY29tbW9uL3J1bi1vdXRzaWRlLWFuZ3VsYXInO1xuaW1wb3J0IHtcbiAgQ3VycmVudFVzZXJRdWVyeSxcbiAgQ3VycmVudFVzZXJRdWVyeVJlc3VsdCxcbiAgUmVzZXRVc2VyUXVlcnlSZXN1bHQsXG59IGZyb20gJy4vYXV0aDIuZ3FsLnByaXZhdGUnO1xuaW1wb3J0IHtcbiAgQXV0aFVzZXIsXG4gIENvZ25pdG9DaGFsbGVuZ2VOYW1lLFxuICBMb2dpbkNoYWxsZW5nZSxcbiAgTG9naW5PcHRpb25zLFxuICBMb2dpblJlc3VsdCxcbiAgTG9nb3V0TGlzdGVuZXIsXG4gIExyQ29nbml0b1VzZXIsXG4gIFBhc3NJZHBSZXN1bHQsXG4gIFBhc3N3b3JkQ2hhbmdlU3RhdHVzLFxuICBSZWNvdmVyeVN0YXR1cyxcbn0gZnJvbSAnLi9hdXRoMi50eXBlcyc7XG5cbkBSdW5PdXRzaWRlQW5ndWxhcih7XG4gIG5nWm9uZU5hbWU6ICduZ1pvbmUnLFxufSlcbkBJbmplY3RhYmxlKHtcbiAgcHJvdmlkZWRJbjogJ3Jvb3QnLFxufSlcbmV4cG9ydCBjbGFzcyBBdXRoMlNlcnZpY2UgZXh0ZW5kcyBMclNlcnZpY2Uge1xuICBzdGF0aWMgQ0hBTExFTkdFX1RJTUVPVVQgPSAxMDAwICogNjAgKiA1O1xuXG4gIC8vIENvdWxkIHVzZSByeGpzIG9ic2VydmFibGVzIGhlcmUuIEJ1dCB0cnlpbmcgdG8gaGF2ZSBrYy1jbGllbnQgdXNlIGFzIGxpdHRsZSBhbmd1bGFyXG4gIC8vIGZlYXR1cmVzIGFzIHBvc3NpYmxlLiBSeGpzIGlzIG5vdCB1c2VkIGFueXdoZXJlIGVsc2UgaW4ga2MtY2xpZW50LlxuICBwcml2YXRlIGxvZ291dExpc3RlbmVycyA9IG5ldyBTZXQ8TG9nb3V0TGlzdGVuZXI+KCk7XG4gIHByaXZhdGUgdXNlcjogQXV0aFVzZXI7XG4gIC8vIFN0b3JlcyB0aGUgcGFzc3dvcmQgZm9yIHVzZSBhZnRlciBtZmEgdmVyaWZpY2F0aW9uIHRvIGRlY3J5cHQgbWFzdGVyS2V5LlxuICBwcml2YXRlIHBhc3N3b3JkOiBLZXlDb250YWluZXIgPSBudWxsO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgbmdab25lOiBOZ1pvbmUsXG4gICAgcHJpdmF0ZSBpbmplY3RvcjogSW5qZWN0b3IsXG4gICAgcHJpdmF0ZSBodHRwOiBIdHRwQ2xpZW50LFxuICAgIHByaXZhdGUgY29nbml0bzogQXV0aENsYXNzLFxuICAgIHByaXZhdGUgYXBpOiBMckdyYXBoUUxTZXJ2aWNlLFxuICAgIHByaXZhdGUga2V5U2VydmljZTogS2V5U2VydmljZSxcbiAgICBwcml2YXRlIGtleUdyYXBoU2VydmljZTogS2V5R3JhcGhTZXJ2aWNlLFxuICAgIHByaXZhdGUga2V5RmFjdG9yeVNlcnZpY2U6IEtleUZhY3RvcnlTZXJ2aWNlLFxuICAgIHByaXZhdGUgcGFzc3dvcmRTZXJ2aWNlOiBQYXNzd29yZFNlcnZpY2UsXG4gICAgcHJpdmF0ZSBpZGxlU2VydmljZTogSWRsZVNlcnZpY2UsXG4gICAgcHJpdmF0ZSBwZXJzaXN0U2VydmljZTogUGVyc2lzdFNlcnZpY2UsXG4gICAgcHJpdmF0ZSBlbmNyeXB0aW9uU2VydmljZTogRW5jcnlwdGlvblNlcnZpY2UsXG4gICAgcHJpdmF0ZSBhc3NlbWJseUNvbnRyb2xsZXI6IFRwUGFzc3dvcmRSZXNldEFzc2VtYmx5Q29udHJvbGxlcixcbiAgICBASW5qZWN0KEtDX0NPTkZJRykgcHJpdmF0ZSBrY0NvbmZpZzogS2NDb25maWdcbiAgKSB7XG4gICAgc3VwZXIoaW5qZWN0b3IpO1xuICAgIGlmICghaXNEZXZNb2RlKCkpIHtcbiAgICAgIGlmICh0aGlzLmtjQ29uZmlnLmRlYnVnICE9IG51bGwpIHtcbiAgICAgICAgdGhyb3cgbmV3IEtjQmFkUmVxdWVzdEV4Y2VwdGlvbihcbiAgICAgICAgICAnSW4gcHJvZHVjdGlvbiBtb2RlLCBcIktjQ29uZmlnLmRlYnVnXCIgbXVzdCBiZSBzZXQgdG8gbnVsbCdcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBpbXBvcnRQYXNzd29yZChwbGFpblBhc3N3b3JkOiBzdHJpbmcpOiBQcm9taXNlPENyeXB0b0tleT4ge1xuICAgIHJldHVybiB0aGlzLmtleUZhY3RvcnlTZXJ2aWNlLmltcG9ydFBhc3N3b3JkKHBsYWluUGFzc3dvcmQpO1xuICB9XG5cbiAgYXN5bmMgbG9nb3V0KCk6IFByb21pc2U8dm9pZD4ge1xuICAgIC8vIE5vdGlmeSBhbGwgbGlzdGVuZXJzIHRvIGNsZWFuIHVwLlxuICAgIGF3YWl0IFByb21pc2UuYWxsKFsuLi50aGlzLmxvZ291dExpc3RlbmVyc10ubWFwKChjYWxsYmFjaykgPT4gY2FsbGJhY2soKSkpO1xuXG4gICAgdGhpcy51c2VyID0gbnVsbDtcbiAgICB0aGlzLmtleVNlcnZpY2UucHVyZ2VLZXlzKCk7XG4gICAgdGhpcy5rZXlHcmFwaFNlcnZpY2UucHVyZ2VLZXlzKCk7XG5cbiAgICAvLyBTaWduIG91dCBvbiBib3RoIGNvZ25pdG8gYW5kIGtjLXNlcnZlclxuICAgIGF3YWl0IFByb21pc2UuYWxsKFt0aGlzLmNvZ25pdG8uc2lnbk91dCgpLCB0aGlzLmtjTG9nb3V0KCldKTtcblxuICAgIGlmICh0aGlzLmtjQ29uZmlnLmRlYnVnPy51c2VybmFtZSkge1xuICAgICAgdGhpcy5rY0NvbmZpZy5kZWJ1Zy51c2VybmFtZSA9IG51bGw7XG4gICAgfVxuICB9XG5cbiAgYWRkTG9nb3V0TGlzdGVuZXIoY2FsbGJhY2s6IExvZ291dExpc3RlbmVyKSB7XG4gICAgdGhpcy5sb2dvdXRMaXN0ZW5lcnMuYWRkKGNhbGxiYWNrKTtcbiAgfVxuXG4gIHJlbW92ZUxvZ291dExpc3RlbmVyKGNhbGxiYWNrOiBMb2dvdXRMaXN0ZW5lcikge1xuICAgIHRoaXMubG9nb3V0TGlzdGVuZXJzLmRlbGV0ZShjYWxsYmFjayk7XG4gIH1cblxuICBhc3luYyBsb2dpbihcbiAgICBlbWFpbE9yUGhvbmU6IHN0cmluZyxcbiAgICBwYXNzd29yZDogQ3J5cHRvS2V5LFxuICAgIHsgdHBQYXNzd29yZFJlc2V0QXV0b0NvbXBsZXRlID0gdHJ1ZSB9OiBMb2dpbk9wdGlvbnMgPSB7fVxuICApOiBQcm9taXNlPExvZ2luUmVzdWx0PiB7XG4gICAgbGV0IGxvZ2luUmVzdWx0OiBMb2dpblJlc3VsdCA9IGF3YWl0IHRoaXMubG9naW5JbXBsKGVtYWlsT3JQaG9uZSwgcGFzc3dvcmQpO1xuXG4gICAgLy8gU2F2ZSB0aGUgcGFzc3dvcmQgZm9yIHVzZSBhZnRlciBtZWV0aW5nIGNoYWxsZW5nZS5cbiAgICBpZiAobG9naW5SZXN1bHQuY2hhbGxlbmdlKSB7XG4gICAgICB0aGlzLnBhc3N3b3JkID0gbmV3IEtleUNvbnRhaW5lcihcbiAgICAgICAgcGFzc3dvcmQsXG4gICAgICAgIEF1dGgyU2VydmljZS5DSEFMTEVOR0VfVElNRU9VVFxuICAgICAgKTtcblxuICAgICAgcmV0dXJuIGxvZ2luUmVzdWx0O1xuICAgIH1cblxuICAgIGlmIChcbiAgICAgIHRwUGFzc3dvcmRSZXNldEF1dG9Db21wbGV0ZSAmJlxuICAgICAgbG9naW5SZXN1bHQudXNlci5yZXNldFVzZXI/LnN0YXRlID09PSBUcENsYWltU3RhdGUuQVBQUk9WRURcbiAgICApIHtcbiAgICAgIGF3YWl0IHRoaXMuY29tcGxldGVSZXNldFJlcXVlc3QocGFzc3dvcmQpO1xuICAgICAgbG9naW5SZXN1bHQgPSBhd2FpdCB0aGlzLmxvZ2luSW1wbChlbWFpbE9yUGhvbmUsIHBhc3N3b3JkKTtcbiAgICB9XG5cbiAgICByZXR1cm4gbG9naW5SZXN1bHQ7XG4gIH1cblxuICBhc3luYyB2ZXJpZnlMb2dpbihvcHRpb25zOiB7XG4gICAgY2hhbGxlbmdlOiBMb2dpbkNoYWxsZW5nZTtcbiAgICBjb2RlOiBzdHJpbmc7XG4gICAgcmVtZW1iZXJNZTogYm9vbGVhbjtcbiAgfSk6IFByb21pc2U8TG9naW5SZXN1bHQ+IHtcbiAgICBjb25zdCB7IGNoYWxsZW5nZSwgY29kZSwgcmVtZW1iZXJNZSB9ID0gb3B0aW9ucztcblxuICAgIGNvbnN0IFZBTElEX0NIQUxMRU5HRV9OQU1FUyA9IFtcbiAgICAgIENvZ25pdG9DaGFsbGVuZ2VOYW1lLlNNU19NRkEsXG4gICAgICBDb2duaXRvQ2hhbGxlbmdlTmFtZS5TT0ZUV0FSRV9UT0tFTl9NRkEsXG4gICAgXTtcblxuICAgIGlmICghVkFMSURfQ0hBTExFTkdFX05BTUVTLmluY2x1ZGVzKGNoYWxsZW5nZS5jb2duaXRvVXNlci5jaGFsbGVuZ2VOYW1lKSkge1xuICAgICAgdGhyb3cgbmV3IEtjQmFkUmVxdWVzdEV4Y2VwdGlvbihcbiAgICAgICAgYGNoYWxsZW5nZU5hbWUgbXVzdCBiZSBvbmUgb2YgJHtWQUxJRF9DSEFMTEVOR0VfTkFNRVN9YFxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBUT0RPOiB0aGlzLmF1dGguY29uZmlybVNpZ25JbigpIGNvdWxkIHJldHVybiBhbm90aGVyIGNoYWxsZW5nZS5cbiAgICBjb25zdCBjb2duaXRvVXNlciA9IGF3YWl0IHRoaXMuY29nbml0by5jb25maXJtU2lnbkluKFxuICAgICAgY2hhbGxlbmdlLmNvZ25pdG9Vc2VyLFxuICAgICAgY29kZSxcbiAgICAgIGNoYWxsZW5nZS5jb2duaXRvVXNlci5jaGFsbGVuZ2VOYW1lIGFzXG4gICAgICAgIHwgQ29nbml0b0NoYWxsZW5nZU5hbWUuU01TX01GQVxuICAgICAgICB8IENvZ25pdG9DaGFsbGVuZ2VOYW1lLlNPRlRXQVJFX1RPS0VOX01GQVxuICAgICk7XG5cbiAgICBhd2FpdCB0aGlzLmhhbmRsZVBvc3RBdXRoKGNoYWxsZW5nZS5yZWNvdmVyeVN0YXR1cyk7XG5cbiAgICBjb25zdCB1c2VyID0gYXdhaXQgdGhpcy5sb2FkVXNlcihjb2duaXRvVXNlciwgdGhpcy5wYXNzd29yZC5wb3AoKSk7XG5cbiAgICAvLyBUaGlzIGlzIG5vdCBzdHJpY3RseSBuZWNlc3Nhcnkgc2luY2UgdGhlIHRoaXMucGFzc3dvcmQucG9wKCkgYWxyZWFkeSBjbGVhcnMgdGhlXG4gICAgLy8gcGFzc3dvcmQgaW5zaWRlIHRoZSBjb250YWluZXIuIEJ1dCBkb2Vzbid0IGh1cnQgZWl0aGVyLlxuICAgIHRoaXMucGFzc3dvcmQgPSBudWxsO1xuXG4gICAgaWYgKHJlbWVtYmVyTWUpIHtcbiAgICAgIGNvZ25pdG9Vc2VyLnNldERldmljZVN0YXR1c1JlbWVtYmVyZWQoe1xuICAgICAgICBvblN1Y2Nlc3M6ICgpID0+IHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH0sXG4gICAgICAgIG9uRmFpbHVyZTogKGUpID0+IGNvbnNvbGUuZXJyb3IoZSksXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgdXNlcixcbiAgICB9O1xuICB9XG5cbiAgYXN5bmMgZ2V0VXNlcigpOiBQcm9taXNlPEF1dGhVc2VyPiB7XG4gICAgaWYgKHRoaXMudXNlcikge1xuICAgICAgcmV0dXJuIHRoaXMudXNlcjtcbiAgICB9XG5cbiAgICBjb25zdCBjb2duaXRvVXNlciA9IGF3YWl0IHRoaXMuY29nbml0by5jdXJyZW50QXV0aGVudGljYXRlZFVzZXIoKTtcblxuICAgIHJldHVybiB0aGlzLmxvYWRVc2VyKGNvZ25pdG9Vc2VyKTtcbiAgfVxuXG4gIGFzeW5jIHJlZnJlc2hBY2Nlc3NUb2tlbigpIHtcbiAgICBjb25zdCBjb2duaXRvVXNlcjogQ29nbml0b1VzZXIgPVxuICAgICAgYXdhaXQgdGhpcy5jb2duaXRvLmN1cnJlbnRBdXRoZW50aWNhdGVkVXNlcigpO1xuICAgIGNvbnN0IHJlZnJlc2hUb2tlbiA9IGNvZ25pdG9Vc2VyLmdldFNpZ25JblVzZXJTZXNzaW9uKCkuZ2V0UmVmcmVzaFRva2VuKCk7XG5cbiAgICBjb25zb2xlLmxvZygnVG9rZW4gcmVmcmVzaC4uLicpO1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICBjb2duaXRvVXNlci5yZWZyZXNoU2Vzc2lvbihyZWZyZXNoVG9rZW4sIChlcnIpID0+IHtcbiAgICAgICAgaWYgKGVycikge1xuICAgICAgICAgIGNvbnNvbGUuZXJyb3IoJ0Vycm9yIHJlZnJlc2hpbmcgdG9rZW46ICcsIGVycik7XG4gICAgICAgICAgcmVqZWN0KGVycik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY29uc29sZS5sb2coJ1Rva2VuIHJlZnJlc2ggY29tcGxldGUnKTtcbiAgICAgICAgICByZXNvbHZlKDApO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgLy8gSGVscGVyc1xuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbiAgcHJpdmF0ZSBhc3luYyBmZXRjaEN1cnJlbnRVc2VyKCkge1xuICAgIHJldHVybiAoXG4gICAgICBhd2FpdCB0aGlzLmFwaS5xdWVyeTxDdXJyZW50VXNlclF1ZXJ5UmVzdWx0Pih7XG4gICAgICAgIHF1ZXJ5OiBDdXJyZW50VXNlclF1ZXJ5LFxuICAgICAgICBwcm9jZXNzb3JPcHRpb25zOiB7XG4gICAgICAgICAgaGFzS2V5czogZmFsc2UsIC8vIERvbid0IHRyeSB0byBkZWNyeXB0IGFueXRoaW5nIGJlY2F1c2Uga2V5cyBoYXZlIG5vdCBiZWVuIHNldHVwIHlldFxuICAgICAgICB9LFxuICAgICAgfSlcbiAgICApLmN1cnJlbnRVc2VyO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBmZXRjaFJlc2V0VXNlcigpIHtcbiAgICByZXR1cm4gKFxuICAgICAgYXdhaXQgdGhpcy5hcGkucXVlcnk8UmVzZXRVc2VyUXVlcnlSZXN1bHQ+KHtcbiAgICAgICAgcXVlcnk6IEN1cnJlbnRVc2VyUXVlcnksXG4gICAgICAgIHByb2Nlc3Nvck9wdGlvbnM6IHtcbiAgICAgICAgICBoYXNLZXlzOiBmYWxzZSwgLy8gRG9uJ3QgdHJ5IHRvIGRlY3J5cHQgYW55dGhpbmcgYmVjYXVzZSBrZXlzIGhhdmUgbm90IGJlZW4gc2V0dXAgeWV0XG4gICAgICAgIH0sXG4gICAgICB9KVxuICAgICkudHBQYXNzd29yZFJlc2V0VXNlcjtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMga2NMb2dvdXQoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgdGhpcy5odHRwXG4gICAgICAucG9zdChgJHt0aGlzLmtjQ29uZmlnLmF1dGhVcmx9YXV0aC9zaWduLW91dC9gLCBudWxsLCB7XG4gICAgICAgIHdpdGhDcmVkZW50aWFsczogdHJ1ZSxcbiAgICAgICAgcmVzcG9uc2VUeXBlOiAndGV4dCcsXG4gICAgICB9KVxuICAgICAgLnRvUHJvbWlzZSgpO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBmZXRjaFBhc3NJZHBQYXJhbXMoXG4gICAgZW1haWxPclBob25lOiBzdHJpbmdcbiAgKTogUHJvbWlzZTxQYXNzSWRwUmVzdWx0PiB7XG4gICAgcmV0dXJuIGF3YWl0IHRoaXMuaHR0cFxuICAgICAgLmdldDxQYXNzSWRwUmVzdWx0PihcbiAgICAgICAgYCR7XG4gICAgICAgICAgdGhpcy5rY0NvbmZpZy5hdXRoVXJsXG4gICAgICAgIH11c2Vycy9wYXNzLWlkcC1wYXJhbXMvP2xvZ2luX25hbWU9JHtlbmNvZGVVUklDb21wb25lbnQoZW1haWxPclBob25lKX1gXG4gICAgICApXG4gICAgICAudG9Qcm9taXNlKCk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGxvZ2luSW1wbChcbiAgICBlbWFpbE9yUGhvbmU6IHN0cmluZyxcbiAgICBwYXNzd29yZDogQ3J5cHRvS2V5XG4gICk6IFByb21pc2U8TG9naW5SZXN1bHQ+IHtcbiAgICBhd2FpdCB0aGlzLmxvZ291dCgpO1xuICAgIGNvbnN0IGxvZ2luSWRwUmVzdWx0ID0gYXdhaXQgdGhpcy5sb2dpbklkcChlbWFpbE9yUGhvbmUsIHBhc3N3b3JkKTtcblxuICAgIC8vIENhbid0IGdldCB0aGUgdXNlciB5ZXQgYmVjYXVzZSB3ZSBzdGlsbCBuZWQgdG8gbWVldCBNRkEgY2hhbGxlbmdlc1xuICAgIGlmIChcbiAgICAgIFtcbiAgICAgICAgQ29nbml0b0NoYWxsZW5nZU5hbWUuU01TX01GQSxcbiAgICAgICAgQ29nbml0b0NoYWxsZW5nZU5hbWUuU09GVFdBUkVfVE9LRU5fTUZBLFxuICAgICAgXS5pbmNsdWRlcyhsb2dpbklkcFJlc3VsdC5jb2duaXRvVXNlci5jaGFsbGVuZ2VOYW1lKVxuICAgICkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgY2hhbGxlbmdlOiB7XG4gICAgICAgICAgY29nbml0b1VzZXI6IGxvZ2luSWRwUmVzdWx0LmNvZ25pdG9Vc2VyLFxuICAgICAgICAgIHJlY292ZXJ5U3RhdHVzOiBsb2dpbklkcFJlc3VsdC5yZWNvdmVyeVN0YXR1cyxcbiAgICAgICAgfSxcbiAgICAgIH07XG4gICAgfVxuXG4gICAgYXdhaXQgdGhpcy5oYW5kbGVQb3N0QXV0aChsb2dpbklkcFJlc3VsdC5yZWNvdmVyeVN0YXR1cyk7XG5cbiAgICAvLyBUaGVyZSBzaG91bGQgYmUgbm8gTUZBIG9uIHRoZSBUUCByZXNldCB1c2VyLlxuICAgIGNvbnN0IHVzZXIgPSBhd2FpdCB0aGlzLmxvYWRVc2VyKGxvZ2luSWRwUmVzdWx0LmNvZ25pdG9Vc2VyLCBwYXNzd29yZCk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgdXNlcixcbiAgICB9O1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBsb2dpbklkcChcbiAgICBlbWFpbE9yUGhvbmU6IHN0cmluZyxcbiAgICBwYXNzd29yZDogQ3J5cHRvS2V5XG4gICk6IFByb21pc2U8TG9naW5DaGFsbGVuZ2U+IHtcbiAgICAvLyBEb3dubG9hZCB0aGUgc2FsdCBuZWVkZWQgdG8gZGVyaXZlIHRoZSBQYXNzSWRwXG4gICAgY29uc3QgcGFzc0lkcEFwaVJlc3VsdCA9IGF3YWl0IHRoaXMuZmV0Y2hQYXNzSWRwUGFyYW1zKGVtYWlsT3JQaG9uZSk7XG5cbiAgICBpZiAoXG4gICAgICBwYXNzSWRwQXBpUmVzdWx0LnBhc3N3b3JkQ2hhbmdlU3RhdHVzID09PSBQYXNzd29yZENoYW5nZVN0YXR1cy5JTl9QUk9HUkVTU1xuICAgICkge1xuICAgICAgdGhyb3cgbmV3IEtjQ29uY3VycmVudEFjY2Vzc0V4Y2VwdGlvbignQSBwYXNzd29yZCBjaGFuZ2UgaXMgaW4gcHJvZ3Jlc3MnKTtcbiAgICB9XG5cbiAgICBpZiAoXG4gICAgICBwYXNzSWRwQXBpUmVzdWx0LnBhc3N3b3JkQ2hhbmdlU3RhdHVzID09PSBQYXNzd29yZENoYW5nZVN0YXR1cy5SRUNPVkVSWVxuICAgICkge1xuICAgICAgY29uc29sZS5sb2coJ0luIHJlY292ZXJ5IG1vZGUuJyk7XG5cbiAgICAgIC8vIExldCdzIHNheSB3ZSBkb24ndCBrbm93IGlmIHRoZSBwYXNzd29yZCBpcyB0aGUgbmV3IG9uZSBvciB0aGUgb2xkIG9uZS4gV2UganVzdCBoYXZlIHRvIHRyeSBib3RoLlxuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgdXNlcjogTG9naW5DaGFsbGVuZ2UgPSB7XG4gICAgICAgICAgY29nbml0b1VzZXI6IGF3YWl0IHRoaXMubG9naW5JZHBJbXBsKFxuICAgICAgICAgICAgZW1haWxPclBob25lLFxuICAgICAgICAgICAgcGFzc3dvcmQsXG4gICAgICAgICAgICBwYXNzSWRwQXBpUmVzdWx0Lm5ld1Bhc3NJZHBQYXJhbXNcbiAgICAgICAgICApLFxuICAgICAgICAgIHJlY292ZXJ5U3RhdHVzOiBSZWNvdmVyeVN0YXR1cy5ORVdfUEFTU1dPUkQsXG4gICAgICAgIH07XG4gICAgICAgIC8vIE5ldyBwYXNzd29yZCB3b3JrZWQuIExldCdzIHNldCB0byB0aGUgY3VycmVudCBwYXNzd29yZFxuXG4gICAgICAgIC8vIC0tUG90ZW50aWFsIEZhaWx1cmUgUG9pbnQgMS0tXG4gICAgICAgIC8vIGlmIGNoYW5nZVBhc3N3b3JkQ29tcGxldGUoKSBkb2Vzbid0IGdldCBjYWxsZWQsIHRoZW4gaXQgc2hvdWxkIHJlbWFpblxuXG4gICAgICAgIGNvbnNvbGUubG9nKCdOZXcgcGFzc3dvcmQgd29ya3MhJyk7XG5cbiAgICAgICAgcmV0dXJuIHVzZXI7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAvLyBKdXN0IGJ1YmJsZSB1cCBhbnkgb3RoZXIgdHlwZSBvZiBlcnJvci5cbiAgICAgICAgaWYgKGVycm9yLmNvZGUgIT09ICdOb3RBdXRob3JpemVkRXhjZXB0aW9uJykge1xuICAgICAgICAgIHRocm93IGVycm9yO1xuICAgICAgICB9XG4gICAgICAgIC8vIHBhc3MsIHRyeSBhZ2FpbiBhc3N1bWluZyBpdCdzIHRoZSBvbGQgcGFzc3dvcmRcbiAgICAgIH1cblxuICAgICAgLy8gTm93IGFzc3VtZSBpdCdzIHRoZSBwcmV2aW91cyBwYXNzd29yZC4gQW55IGV4Y2VwdGlvbiBpcyBhbGxvd2VkIHRvIGJ1YmJsZSB1cC5cbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHVzZXI6IExvZ2luQ2hhbGxlbmdlID0ge1xuICAgICAgICAgIGNvZ25pdG9Vc2VyOiBhd2FpdCB0aGlzLmxvZ2luSWRwSW1wbChcbiAgICAgICAgICAgIGVtYWlsT3JQaG9uZSxcbiAgICAgICAgICAgIHBhc3N3b3JkLFxuICAgICAgICAgICAgcGFzc0lkcEFwaVJlc3VsdC5jdXJyZW50UGFzc0lkcFBhcmFtc1xuICAgICAgICAgICksXG4gICAgICAgICAgcmVjb3ZlcnlTdGF0dXM6IFJlY292ZXJ5U3RhdHVzLk9MRF9QQVNTV09SRCxcbiAgICAgICAgfTtcbiAgICAgICAgLy8gT2xkIHBhc3N3b3JkIHdvcmtlZC5cbiAgICAgICAgY29uc29sZS5sb2coJ09sZCBwYXNzd29yZCB3b3JrcyEnKTtcblxuICAgICAgICByZXR1cm4gdXNlcjtcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIC8vIEp1c3QgYnViYmxlIHVwIGFueSBvdGhlciB0eXBlIG9mIGVycm9yLlxuICAgICAgICB0aHJvdyBlcnJvci5jb2RlID09PSAnTm90QXV0aG9yaXplZEV4Y2VwdGlvbidcbiAgICAgICAgICA/IG5ldyBLY0JhZFJlcXVlc3RFeGNlcHRpb24oXG4gICAgICAgICAgICAgICdUaGUgcGFzc3dvcmQgY2hhbmdlIHJlcXVlc3Qgd2FzIGludGVycnVwdGVkLCBwbGVhc2UgdHJ5IHRvIGxvZ2luIHdpdGggYm90aCB5b3VyIG5ldyBhbmQgb2xkIHBhc3N3b3JkJ1xuICAgICAgICAgICAgKVxuICAgICAgICAgIDogZXJyb3I7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gVHJ5IGFnYWluIGFzIHRoZSBUUCBwYXNzd29yZCByZXNldCBhY2NvdW50XG4gICAgaWYgKHBhc3NJZHBBcGlSZXN1bHQudHBQYXNzd29yZFJlc2V0KSB7XG4gICAgICB0cnkge1xuICAgICAgICAvLyBUUCBwYXNzd29yZCByZXNldCBpcyBpbiBwcm9jZXNzLiBXZSBuZWVkIHRvIHRyeSB0aGUgcGFzc3dvcmQgYWdhaW5zdCBib3RoXG4gICAgICAgIC8vIG9yaWdpbmFsIGFjY291bnQgYW5kIHRoZSBuZXcgcmVzZXQgYWNjb3VudC5cbiAgICAgICAgY29uc3QgcmVzZXQgPSBwYXNzSWRwQXBpUmVzdWx0LnRwUGFzc3dvcmRSZXNldDtcbiAgICAgICAgY29uc3QgdXNlcjogTG9naW5DaGFsbGVuZ2UgPSB7XG4gICAgICAgICAgY29nbml0b1VzZXI6IGF3YWl0IHRoaXMubG9naW5JZHBJbXBsKFxuICAgICAgICAgICAgcmVzZXQucmVzZXRVc2VybmFtZSxcbiAgICAgICAgICAgIHBhc3N3b3JkLFxuICAgICAgICAgICAgcmVzZXQucGFzc0lkcFBhcmFtc1xuICAgICAgICAgICksXG4gICAgICAgICAgcmVjb3ZlcnlTdGF0dXM6IFJlY292ZXJ5U3RhdHVzLk5PTkUsXG4gICAgICAgIH07XG5cbiAgICAgICAgcmV0dXJuIHVzZXI7XG4gICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgLy8gY29udGludWUsIHRyeSBhZ2FpbiBhcyByZWd1bGFyIHVzZXIuXG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gTG9naW4gYXMgcmVndWxhciB1c2VyXG4gICAgY29uc3QgdXNlcjogTG9naW5DaGFsbGVuZ2UgPSB7XG4gICAgICBjb2duaXRvVXNlcjogYXdhaXQgdGhpcy5sb2dpbklkcEltcGwoXG4gICAgICAgIGVtYWlsT3JQaG9uZSxcbiAgICAgICAgcGFzc3dvcmQsXG4gICAgICAgIHBhc3NJZHBBcGlSZXN1bHQuY3VycmVudFBhc3NJZHBQYXJhbXNcbiAgICAgICksXG4gICAgICByZWNvdmVyeVN0YXR1czogUmVjb3ZlcnlTdGF0dXMuTk9ORSxcbiAgICB9O1xuXG4gICAgcmV0dXJuIHVzZXI7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGxvZ2luSWRwSW1wbChcbiAgICBlbWFpbE9yUGhvbmU6IHN0cmluZyxcbiAgICBwYXNzd29yZDogQ3J5cHRvS2V5LFxuICAgIHBhc3NJZHBQYXJhbXM6IFBhc3NJZHBQYXJhbXNcbiAgKTogUHJvbWlzZTxMckNvZ25pdG9Vc2VyPiB7XG4gICAgY29uc3QgcGFzc0lkcFJlc3VsdCA9IGF3YWl0IHRoaXMua2V5RmFjdG9yeVNlcnZpY2UuZGVyaXZlUGFzc0lkcCh7XG4gICAgICBwYXNzd29yZCxcbiAgICAgIC4uLnBhc3NJZHBQYXJhbXMsXG4gICAgfSk7XG5cbiAgICAvLyBVc2UgdGhlIGRlcml2ZWQgcGFzc3dvcmQgdG8gc2lnbmluIHdpdGggY29nbml0b1xuICAgIHJldHVybiB0aGlzLmNvZ25pdG8uc2lnbkluKFxuICAgICAgZW1haWxPclBob25lLFxuICAgICAgdGhpcy5wYXNzd29yZFNlcnZpY2UuZ2V0UGFzc0lkcFN0cmluZyhwYXNzSWRwUmVzdWx0Lmp3aylcbiAgICApO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBoYW5kbGVQb3N0QXV0aChyZWNvdmVyeVN0YXR1czogUmVjb3ZlcnlTdGF0dXMpIHtcbiAgICBhd2FpdCB0aGlzLmhhbmRsZVBhc3N3b3JkUmVjb3ZlcnkocmVjb3ZlcnlTdGF0dXMpO1xuICAgIGF3YWl0IHRoaXMuaGFuZGxlU2Vzc2lvbkVuY3J5cHRpb25LZXkoKTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgaGFuZGxlUGFzc3dvcmRSZWNvdmVyeShyZWNvdmVyeVN0YXR1czogUmVjb3ZlcnlTdGF0dXMpIHtcbiAgICBpZiAocmVjb3ZlcnlTdGF0dXMgIT09IFJlY292ZXJ5U3RhdHVzLk5PTkUpIHtcbiAgICAgIGF3YWl0IHRoaXMucGFzc3dvcmRTZXJ2aWNlLmNoYW5nZVBhc3N3b3JkQ29tcGxldGUoe1xuICAgICAgICB1c2VOZXdQYXNzd29yZDogcmVjb3ZlcnlTdGF0dXMgPT09IFJlY292ZXJ5U3RhdHVzLk5FV19QQVNTV09SRCxcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgaGFuZGxlU2Vzc2lvbkVuY3J5cHRpb25LZXkoKSB7XG4gICAgaWYgKHRoaXMua2NDb25maWcuZGlzYWJsZVNlc3Npb25FbmNyeXB0aW9uS2V5KSB7XG4gICAgICBpZiAoIWlzRGV2TW9kZSgpKSB7XG4gICAgICAgIGNvbnN0IG1zZyA9XG4gICAgICAgICAgJ1lvdSBzaG91bGQgbm90IHNldCBkaXNhYmxlU2Vzc2lvbkVuY3J5cHRpb25LZXk9VHJ1ZSBpbiBtb2RlIHByb2QuIEl0IGRlZmF1bHRzIHRvIGZhbHNlLic7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IobXNnKTtcbiAgICAgICAgdGhyb3cgbmV3IEtjSW50ZXJuYWxFcnJvckV4Y2VwdGlvbihtc2cpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc29sZS53YXJuKFxuICAgICAgICAgICdZb3UgaGF2ZSBzZXQgZGlzYWJsZVNlc3Npb25FbmNyeXB0aW9uS2V5PVRydWUuIE1ha2Ugc3VyZSBub3QgdG8gZG8gdGhpcyBpbiBwcm9kIG1vZGUuJ1xuICAgICAgICApO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICAvLyBTZXQgdGhlIHNlc3Npb24ga2V5IHRvIGEgbmV3IGVuY3J5cHRpb24ga2V5IGZvciB0aGlzIHNlc3Npb25cbiAgICAgIGNvbnN0IHNlc3Npb25FbmNyeXB0aW9uS2V5ID0gYXdhaXQgdGhpcy5rZXlGYWN0b3J5U2VydmljZS5jcmVhdGVLZXkoKTtcbiAgICAgIGF3YWl0IHRoaXMubHJHcmFwaFFMLmxyTXV0YXRlKFxuICAgICAgICBuZXcgTHJNdXRhdGlvbih7XG4gICAgICAgICAgbXV0YXRpb246IFNldFNlc3Npb25FbmNyeXB0aW9uS2V5TXV0YXRpb24sXG4gICAgICAgICAgdmFyaWFibGVzOiB7XG4gICAgICAgICAgICBpbnB1dDoge1xuICAgICAgICAgICAgICBzZXNzaW9uRW5jcnlwdGlvbktleTogSlNPTi5zdHJpbmdpZnkoXG4gICAgICAgICAgICAgICAgc2Vzc2lvbkVuY3J5cHRpb25LZXkudG9KU09OKHRydWUpXG4gICAgICAgICAgICAgICksXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0sXG4gICAgICAgIH0pLFxuICAgICAgICB7XG4gICAgICAgICAgaW5jbHVkZUtleUdyYXBoOiBmYWxzZSxcbiAgICAgICAgfVxuICAgICAgKTtcblxuICAgICAgdGhpcy5wZXJzaXN0U2VydmljZS5zZXRTZXJ2ZXJTZXNzaW9uRW5jcnlwdGlvbktleShzZXNzaW9uRW5jcnlwdGlvbktleSk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBnZXRDb2duaXRvVXNlckF0dHJpYnV0ZShcbiAgICBhdHRyaWJ1dGVOYW1lOiBzdHJpbmcsXG4gICAgdXNlckF0dHJpYnV0ZXM6IENvZ25pdG9Vc2VyQXR0cmlidXRlW11cbiAgKSB7XG4gICAgY29uc3QgdXNlckF0dHJpYnV0ZSA9IHVzZXJBdHRyaWJ1dGVzLmZpbmQoXG4gICAgICAoeCkgPT4geC5nZXROYW1lKCkgPT09IGF0dHJpYnV0ZU5hbWVcbiAgICApO1xuXG4gICAgcmV0dXJuIHVzZXJBdHRyaWJ1dGUgPyB1c2VyQXR0cmlidXRlLmdldFZhbHVlKCkgOiBudWxsO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBsb2FkVXNlcktleXMob3B0aW9uczoge1xuICAgIHVzZXJLZXlzOiBVc2VyS2V5cztcbiAgICBwYXNzd29yZD86IENyeXB0b0tleTtcbiAgICBzZXNzaW9uRW5jcnlwdGlvbktleT86IHN0cmluZztcbiAgfSkge1xuICAgIGNvbnN0IHsgdXNlcktleXMsIHBhc3N3b3JkLCBzZXNzaW9uRW5jcnlwdGlvbktleSB9ID0gb3B0aW9ucztcblxuICAgIGlmIChzZXNzaW9uRW5jcnlwdGlvbktleSkge1xuICAgICAgdGhpcy5wZXJzaXN0U2VydmljZS5zZXRTZXJ2ZXJTZXNzaW9uRW5jcnlwdGlvbktleShcbiAgICAgICAgYXdhaXQgSldLLmFzS2V5KHNlc3Npb25FbmNyeXB0aW9uS2V5KVxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBwYXNzd29yZCBpcyBub3QgbmVlZGVkIGlmIHRoZSBtYXN0ZXIga2V5IGlzIGFscmVhZHkgcGVyc2lzdGVkLlxuICAgIGlmIChwYXNzd29yZCkge1xuICAgICAgY29uc3QgcGFzc0tleSA9IChcbiAgICAgICAgYXdhaXQgdGhpcy5rZXlGYWN0b3J5U2VydmljZS5kZXJpdmVQYXNzS2V5KHtcbiAgICAgICAgICBwYXNzd29yZCxcbiAgICAgICAgICAuLi51c2VyS2V5cy5wYXNzS2V5LnBhc3NLZXlQYXJhbXMsXG4gICAgICAgIH0pXG4gICAgICApLmp3aztcblxuICAgICAgYXdhaXQgdGhpcy5pZGxlU2VydmljZS5wZXJzaXN0TWFzdGVyS2V5KFxuICAgICAgICBhd2FpdCB0aGlzLmtleUdyYXBoU2VydmljZS51bndyYXBXaXRoUGFzc0tleShcbiAgICAgICAgICB1c2VyS2V5cy5wYXNzS2V5LmlkLFxuICAgICAgICAgIHBhc3NLZXksXG4gICAgICAgICAgdXNlcktleXMubWFzdGVyS2V5LmlkXG4gICAgICAgIClcbiAgICAgICk7XG4gICAgfVxuXG4gICAgYXdhaXQgdGhpcy5rZXlHcmFwaFNlcnZpY2UucG9wdWxhdGVLZXlzKHVzZXJLZXlzKTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgbG9hZFVzZXIoXG4gICAgY29nbml0b1VzZXI6IENvZ25pdG9Vc2VyLFxuICAgIHBhc3N3b3JkPzogQ3J5cHRvS2V5XG4gICk6IFByb21pc2U8QXV0aFVzZXI+IHtcbiAgICBpZiAoY29nbml0b1VzZXIuZ2V0VXNlcm5hbWUoKS5lbmRzV2l0aChUUF9QQVNTV09SRF9SRVNFVF9VU0VSTkFNRV9TVUZGSVgpKSB7XG4gICAgICB0aGlzLnVzZXIgPSBhd2FpdCB0aGlzLmxvYWRSZXNldFVzZXIoY29nbml0b1VzZXIsIHBhc3N3b3JkKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy51c2VyID0gYXdhaXQgdGhpcy5sb2FkUmVndWxhclVzZXIoY29nbml0b1VzZXIsIHBhc3N3b3JkKTtcbiAgICB9XG5cbiAgICBhd2FpdCB0aGlzLmlkbGVTZXJ2aWNlLnN0YXJ0KCk7IC8vIFJ1biBpZGxlU2VydmljZSB3aGVuZXZlciB1c2VyIGlzIGxvZ2dlZCBpbi5cblxuICAgIHJldHVybiB0aGlzLnVzZXI7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGxvYWRSZWd1bGFyVXNlcihcbiAgICBjb2duaXRvVXNlcjogQ29nbml0b1VzZXIsXG4gICAgcGFzc3dvcmQ/OiBDcnlwdG9LZXlcbiAgKTogUHJvbWlzZTxBdXRoVXNlcj4ge1xuICAgIGNvbnN0IGN1cnJlbnRVc2VyID0gYXdhaXQgdGhpcy5mZXRjaEN1cnJlbnRVc2VyKCk7XG5cbiAgICBhd2FpdCB0aGlzLmxvYWRVc2VyS2V5cyh7XG4gICAgICB1c2VyS2V5czogY3VycmVudFVzZXIuY3VycmVudFVzZXJLZXksXG4gICAgICBwYXNzd29yZCxcbiAgICAgIHNlc3Npb25FbmNyeXB0aW9uS2V5OiBjdXJyZW50VXNlci5zZXNzaW9uRW5jcnlwdGlvbktleSxcbiAgICB9KTtcblxuICAgIGNvbnN0IHsgdXNlcm5hbWUgfSA9IGN1cnJlbnRVc2VyO1xuICAgIGNvbnN0IHVzZXJBdHRyaWJ1dGVzID0gYXdhaXQgdGhpcy5jb2duaXRvLnVzZXJBdHRyaWJ1dGVzKGNvZ25pdG9Vc2VyKTtcblxuICAgIHJldHVybiB7XG4gICAgICB1c2VybmFtZSxcbiAgICAgIHN1YjogdGhpcy5nZXRDb2duaXRvVXNlckF0dHJpYnV0ZSgnc3ViJywgdXNlckF0dHJpYnV0ZXMpLFxuICAgICAgbG9naW5FbWFpbDogdGhpcy5nZXRDb2duaXRvVXNlckF0dHJpYnV0ZSgnZW1haWwnLCB1c2VyQXR0cmlidXRlcyksXG4gICAgICByZXNldFVzZXI6IG51bGwsXG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgbG9hZFJlc2V0VXNlcihcbiAgICBjb2duaXRvVXNlcjogQ29nbml0b1VzZXIsXG4gICAgcGFzc3dvcmQ/OiBDcnlwdG9LZXlcbiAgKTogUHJvbWlzZTxBdXRoVXNlcj4ge1xuICAgIGNvbnN0IHJlc2V0VXNlciA9IGF3YWl0IHRoaXMuZmV0Y2hSZXNldFVzZXIoKTtcblxuICAgIHRoaXMubG9hZFVzZXJLZXlzKHtcbiAgICAgIHVzZXJLZXlzOiB7XG4gICAgICAgIHBhc3NLZXk6IHtcbiAgICAgICAgICBpZDogcmVzZXRVc2VyLnBhc3NLZXkuaWQsXG4gICAgICAgIH0sXG4gICAgICAgIG1hc3RlcktleToge1xuICAgICAgICAgIGlkOiByZXNldFVzZXIubWFzdGVyS2V5LmlkLFxuICAgICAgICB9LFxuICAgICAgfSxcbiAgICAgIHBhc3N3b3JkLFxuICAgICAgc2Vzc2lvbkVuY3J5cHRpb25LZXk6IHJlc2V0VXNlci5zZXNzaW9uRW5jcnlwdGlvbktleSxcbiAgICB9KTtcblxuICAgIGNvbnN0IHsgdXNlcm5hbWUgfSA9IHJlc2V0VXNlcjtcbiAgICBjb25zdCB1c2VyQXR0cmlidXRlcyA9IGF3YWl0IHRoaXMuY29nbml0by51c2VyQXR0cmlidXRlcyhjb2duaXRvVXNlcik7XG5cbiAgICByZXR1cm4ge1xuICAgICAgdXNlcm5hbWUsXG4gICAgICBzdWI6IHRoaXMuZ2V0Q29nbml0b1VzZXJBdHRyaWJ1dGUoJ3N1YicsIHVzZXJBdHRyaWJ1dGVzKSxcbiAgICAgIGxvZ2luRW1haWw6IHRoaXMuZ2V0Q29nbml0b1VzZXJBdHRyaWJ1dGUoJ2VtYWlsJywgdXNlckF0dHJpYnV0ZXMpLFxuICAgICAgcmVzZXRVc2VyOiB7XG4gICAgICAgIHN0YXRlOiByZXNldFVzZXIuc3RhdGUsXG4gICAgICB9LFxuICAgIH07XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHJlY292ZXJBc3NlbWJseUtleShcbiAgICByZXNldFVzZXI6IFJlc2V0VXNlclF1ZXJ5UmVzdWx0Wyd0cFBhc3N3b3JkUmVzZXRVc2VyJ11cbiAgKTogUHJvbWlzZTxKV0suS2V5PiB7XG4gICAgY29uc3QgcHJrID0gYXdhaXQgdGhpcy5rZXlHcmFwaFNlcnZpY2UuZ2V0S2V5KHJlc2V0VXNlci5weGsuaWQpO1xuXG4gICAgY29uc3QgcGFydGlhbHMgPSBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgIHJlc2V0VXNlci5hcHByb3ZhbHNcbiAgICAgICAgLmZpbHRlcigoYXBwcm92YWwpID0+ICEhYXBwcm92YWwucmVjZWl2ZXJDaXBoZXJQYXJ0aWFsQXNzZW1ibHlLZXkpXG4gICAgICAgIC5tYXAoKGFwcHJvdmFsKSA9PlxuICAgICAgICAgIHRoaXMuZW5jcnlwdGlvblNlcnZpY2UuZGVjcnlwdChcbiAgICAgICAgICAgIHByayxcbiAgICAgICAgICAgIGFwcHJvdmFsLnJlY2VpdmVyQ2lwaGVyUGFydGlhbEFzc2VtYmx5S2V5XG4gICAgICAgICAgKVxuICAgICAgICApXG4gICAgKTtcblxuICAgIHJldHVybiB0aGlzLmFzc2VtYmx5Q29udHJvbGxlci5yZWNvdmVyQXNzZW1ibHlLZXkocGFydGlhbHMpO1xuICB9XG5cbiAgYXN5bmMgY29tcGxldGVSZXNldFJlcXVlc3QobmV3UGFzc3dvcmQ6IENyeXB0b0tleSk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IHJlc2V0VXNlciA9IGF3YWl0IHRoaXMuZmV0Y2hSZXNldFVzZXIoKTtcblxuICAgIGlmIChyZXNldFVzZXIuc3RhdGUgIT09IFRwQ2xhaW1TdGF0ZS5BUFBST1ZFRCkge1xuICAgICAgdGhyb3cgbmV3IEtjQmFkU3RhdGVFeGNlcHRpb24oXG4gICAgICAgICdQYXNzd29yZCByZXNldCByZXF1ZXN0IGhhcyBub3QgYmVlbiBhcHByb3ZlZC4nXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgLy8gUHJlcGFyZSBhbGwgbWF0ZXJpYWxzIHRvIGVuc3VyZSB0aGVyZSBhcmUgbm8gZXJyb3JzLlxuICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgY29uc3QgYXNzZW1ibHlLZXkgPSBhd2FpdCB0aGlzLnJlY292ZXJBc3NlbWJseUtleShyZXNldFVzZXIpO1xuXG4gICAgY29uc3QgeyByb290S2V5IH0gPSBhd2FpdCB0aGlzLmVuY3J5cHRpb25TZXJ2aWNlLmRlY3J5cHQoXG4gICAgICBhc3NlbWJseUtleSxcbiAgICAgIHJlc2V0VXNlci5hc3NlbWJseUNpcGhlckRhdGFcbiAgICApO1xuXG4gICAgLy8gTWFraW5nIHN1cmUgaXQncyBhIHZhbGlkIGtleS5cbiAgICBjb25zdCByb290S2V5SndrID0gYXdhaXQgSldLLmFzS2V5KHJvb3RLZXkpO1xuXG4gICAgY29uc3QgbWFzdGVyS2V5ID0gYXdhaXQgdGhpcy5rZXlHcmFwaFNlcnZpY2UuZ2V0S2V5KHJlc2V0VXNlci5tYXN0ZXJLZXkuaWQpO1xuXG4gICAgY29uc3QgbWFzdGVyS2V5V3JhcHBlZFJvb3RLZXkgPVxuICAgICAgYXdhaXQgdGhpcy5lbmNyeXB0aW9uU2VydmljZS5lbmNyeXB0VG9TdHJpbmcoXG4gICAgICAgIG1hc3RlcktleS5qd2ssXG4gICAgICAgIHJvb3RLZXlKd2sudG9KU09OKHRydWUpXG4gICAgICApO1xuXG4gICAgLy8gVGhlIG5ldyBwYXNzd29yZFxuICAgIGNvbnN0IG5ld1Bhc3NJZHBSZXN1bHQgPSBhd2FpdCB0aGlzLmtleUZhY3RvcnlTZXJ2aWNlLmRlcml2ZVBhc3NJZHAoe1xuICAgICAgcGFzc3dvcmQ6IG5ld1Bhc3N3b3JkLFxuICAgICAgLi4ucmVzZXRVc2VyLnBhc3NLZXkucGFzc0lkcFBhcmFtcyxcbiAgICB9KTtcblxuICAgIGNvbnN0IG5ld0lkcFBhc3N3b3JkID0gdGhpcy5wYXNzd29yZFNlcnZpY2UuZ2V0UGFzc0lkcFN0cmluZyhcbiAgICAgIG5ld1Bhc3NJZHBSZXN1bHQuandrXG4gICAgKTtcblxuICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgLy8gR2V0IGFzc2VtYmx5IGtleSBjaGFsbGVuZ2VcbiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgIGNvbnN0IGNoYWxsZW5nZSA9IChcbiAgICAgIGF3YWl0IHRoaXMubHJHcmFwaFFMLmxyTXV0YXRlKFxuICAgICAgICBuZXcgTHJNdXRhdGlvbih7XG4gICAgICAgICAgbXV0YXRpb246IENyZWF0ZVRwQXNzZW1ibHlLZXlDaGFsbGVuZ2VNdXRhdGlvbixcbiAgICAgICAgICB2YXJpYWJsZXM6IHtcbiAgICAgICAgICAgIGlucHV0OiB7fSxcbiAgICAgICAgICB9LFxuICAgICAgICB9KSxcbiAgICAgICAge1xuICAgICAgICAgIGluY2x1ZGVLZXlHcmFwaDogZmFsc2UsXG4gICAgICAgIH1cbiAgICAgIClcbiAgICApLmNyZWF0ZVRwQXNzZW1ibHlLZXlDaGFsbGVuZ2UuY2hhbGxlbmdlO1xuXG4gICAgLy8gU2lnbiB0aGUgY2hhbGxlbmdlXG4gICAgLy8gR2VuZXJhdGUgYSBjbGllbnQgc2lkZSBub25jZSB0aGF0J3Mgbm8gaW4gdGhlIHNlcnZlcidzIGNvbnRyb2wuXG4gICAgY2hhbGxlbmdlLmNsaWVudE5vbmNlID0gdGhpcy5rZXlGYWN0b3J5U2VydmljZS5yYW5kb21TdHJpbmcoXG4gICAgICBUUF9QQVNTV09SRF9SRVNFVF9DTElFTlRfTk9OQ0VfTEVOR1RIXG4gICAgKTtcblxuICAgIGNvbnN0IGFzc2VtYmx5S2V5VmVyaWZpZXJQcmsgPSBhd2FpdCB0aGlzLmVuY3J5cHRpb25TZXJ2aWNlLmRlY3J5cHQoXG4gICAgICBhc3NlbWJseUtleSxcbiAgICAgIHJlc2V0VXNlci53cmFwcGVkQXNzZW1ibHlLZXlWZXJpZmllclBya1xuICAgICk7XG4gICAgY29uc3Qgc2lnbmVkQ2hhbGxlbmdlID0gYXdhaXQgdGhpcy5lbmNyeXB0aW9uU2VydmljZS5zaWduKFxuICAgICAgYXNzZW1ibHlLZXlWZXJpZmllclByayxcbiAgICAgIGNoYWxsZW5nZVxuICAgICk7XG5cbiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgIC8vIENoYW5nZSBwYXNzd29yZCBmb3IgdGhlIG9yaWdpbmFsIHVzZXJcbiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgIGNvbnN0IHRlbXBJZHBQYXNzd29yZCA9IChcbiAgICAgIGF3YWl0IHRoaXMubHJHcmFwaFFMLmxyTXV0YXRlKFxuICAgICAgICBuZXcgTHJNdXRhdGlvbih7XG4gICAgICAgICAgbXV0YXRpb246IFByZUNvbXBsZXRlVHBQYXNzd29yZFJlc2V0UmVxdWVzdE11dGF0aW9uLFxuICAgICAgICAgIHZhcmlhYmxlczoge1xuICAgICAgICAgICAgaW5wdXQ6IHtcbiAgICAgICAgICAgICAgc2lnbmVkQ2hhbGxlbmdlOiBKU09OLnN0cmluZ2lmeShzaWduZWRDaGFsbGVuZ2UpLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9LFxuICAgICAgICB9KSxcbiAgICAgICAge1xuICAgICAgICAgIGluY2x1ZGVLZXlHcmFwaDogZmFsc2UsXG4gICAgICAgIH1cbiAgICAgIClcbiAgICApLnByZUNvbXBsZXRlVHBQYXNzd29yZFJlc2V0UmVxdWVzdC5pZHBQYXNzd29yZDtcblxuICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgLy8gTG9naW4gYXMgdGhlIG9yaWdpbmFsIHVzZXIgdXNpbmcgbmV3IHRlbXBvcmFyeSBwYXNzd29yZFxuICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgLy8gQXQgdGhpcyBwb2ludCwgdGhlIG9yaWdpbmFsIGFjY291bnQncyBwYXNzd29yZCBoYXMgYmVlbiBjaGFuZ2VkXG4gICAgLy8gdG8gYSB0ZW1wb3JhcnkgcGFzc3dvcmQuIEl0IGlzIG5vIGxvbmdlciBwb3NzaWJsZSBmb3IgdGhlIHVzZXJcbiAgICAvLyB0byB1c2UgdGhlIG9yaWdpbmFsIHBhc3N3b3JkIHRvIGxvZ2luLiBBbnkgc3VjY2Vzc2Z1bCBsb2dpblxuICAgIC8vIGNhbiBvbmx5IGJlIHVzaW5nIHRoZSB0ZW1wb3JhcnkgcGFzc3dvcmQuIFNvIGl0J3Mgc2FmZSB0byBhc3N1bWVcbiAgICAvLyB0aGF0IHdlIHdhbnQgdG8gXCJjb21wbGV0ZVwiIHRoZSBwYXNzd29yZCByZXNldC5cblxuICAgIC8vIFRoZXJlIG1heWJlIDJGQSBzbyB3ZSBsaXN0ZW4gZm9yIHRoZSBhdXRoIGV2ZW50IGZyb20gQW1wbGlmeS5cbiAgICBjb25zdCByZXRQcm9taXNlID0gbmV3IFByb21pc2U8dm9pZD4oKHJlc29sdmUpID0+IHtcbiAgICAgIGNvbnN0IGxpc3RlbmVyID0gYXN5bmMgKGRhdGEpID0+IHtcbiAgICAgICAgaWYgKGRhdGEucGF5bG9hZC5ldmVudCAhPT0gJ3NpZ25JbicpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBIdWIucmVtb3ZlKCdhdXRoJywgbGlzdGVuZXIpO1xuXG4gICAgICAgIGF3YWl0IHRoaXMuY29nbml0by5zaWduSW4ocmVzZXRVc2VyLnVzZXJuYW1lLCBuZXdJZHBQYXNzd29yZCk7XG5cbiAgICAgICAgLy8gU3dpdGNoIG92ZXIgdG8gdGhlIG5ldyBzZXQgb2Yga2V5c1xuICAgICAgICBhd2FpdCB0aGlzLmxyR3JhcGhRTC5sck11dGF0ZShcbiAgICAgICAgICBuZXcgTHJNdXRhdGlvbih7XG4gICAgICAgICAgICBtdXRhdGlvbjogQ29tcGxldGVUcFBhc3N3b3JkUmVzZXRSZXF1ZXN0TXV0YXRpb24sXG4gICAgICAgICAgICB2YXJpYWJsZXM6IHtcbiAgICAgICAgICAgICAgaW5wdXQ6IHtcbiAgICAgICAgICAgICAgICBtYXN0ZXJLZXlXcmFwcGVkUm9vdEtleSxcbiAgICAgICAgICAgICAgICBtYXN0ZXJLZXlJZDogbWFzdGVyS2V5LmlkLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9KVxuICAgICAgICApO1xuXG4gICAgICAgIHJlc29sdmUoKTtcbiAgICAgIH07XG5cbiAgICAgIEh1Yi5saXN0ZW4oJ2F1dGgnLCBsaXN0ZW5lcik7XG4gICAgfSk7XG5cbiAgICAvLyBTaWduaW4gYXMgdGhlIG9yaWdpbmFsIHVzZXIuIFBhc3N3b3JkIGhhcyBiZWVuIHJlc2V0IHRvIHRlbXBvcmFyeSBvbmUuIEl0IHNob3VsZCByZXR1cm5cbiAgICAvLyB3aXRoIE5FV19QQVNTV09SRF9SRVFVSVJFRFxuICAgIGxldCB1c2VyID0gYXdhaXQgdGhpcy5jb2duaXRvLnNpZ25JbihyZXNldFVzZXIudXNlcm5hbWUsIHRlbXBJZHBQYXNzd29yZCwge1xuICAgICAgbm9Qcm94eTogJ3RydWUnLFxuICAgIH0pO1xuXG4gICAgaWYgKHVzZXIuY2hhbGxlbmdlTmFtZSAhPT0gJ05FV19QQVNTV09SRF9SRVFVSVJFRCcpIHtcbiAgICAgIHRocm93IG5ldyBLY0ludGVybmFsRXJyb3JFeGNlcHRpb24oXG4gICAgICAgICdFeHBlY3RpbmcgQ29nbml0byB0byBoYXZlIGRvbmUgYSBwYXNzd29yZCByZXNldCBhZnRlciBjYWxsIHRvIFByZUNvbXBsZXRlVHBQYXNzd29yZFJlc2V0UmVxdWVzdE11dGF0aW9uLidcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gU2V0IG5ldyBwYXNzd29yZCBvbiBJZHBcbiAgICAvLyB0aGUgYXdzRmV0Y2goKSBmdW5jdGlvbiBwYXNzZXMgTkVXX1BBU1NXT1JEX1JFUVVJUkVEIGRpcmVjdGx5IHRvIEFXUyB3aXRob3V0XG4gICAgLy8gZ29pbmcgdGhyb3VnaCB0aGUgcHJveHkuXG4gICAgdXNlciA9IGF3YWl0IHRoaXMuY29nbml0by5jb21wbGV0ZU5ld1Bhc3N3b3JkKHVzZXIsIG5ld0lkcFBhc3N3b3JkLCB7fSk7XG5cbiAgICByZXR1cm4gcmV0UHJvbWlzZTtcbiAgfVxuXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAvLyBEZWJ1ZyB1dGlsaXRpZXNcbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gIGRlYnVnTG9naW4odXNlcm5hbWU6IHN0cmluZywgcGFzc3dvcmQ6IENyeXB0b0tleSk6IFByb21pc2U8QXV0aFVzZXI+IHtcbiAgICAvLyBUaGlzIHdpbGwgZmFpbCBpZiBkZWJ1ZyBpcyBudWxsLiBCdXQgd2hlbiBkZWJ1ZyBpcyBudWxsLCB0aGlzIGZ1bmN0aW9uXG4gICAgLy8gc2hvdWxkIG5vdCBiZSBjYWxsZWQuXG4gICAgdGhpcy5rY0NvbmZpZy5kZWJ1Zy51c2VybmFtZSA9IHVzZXJuYW1lO1xuXG4gICAgcmV0dXJuIHRoaXMuZGVidWdMb2FkVXNlcihwYXNzd29yZCk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGRlYnVnTG9hZFVzZXIocGFzc3dvcmQ6IENyeXB0b0tleSk6IFByb21pc2U8QXV0aFVzZXI+IHtcbiAgICBjb25zdCBjdXJyZW50VXNlciA9IGF3YWl0IHRoaXMuZmV0Y2hDdXJyZW50VXNlcigpO1xuXG4gICAgY29uc3QgeyB1c2VybmFtZSwgY3VycmVudFVzZXJLZXkgfSA9IGN1cnJlbnRVc2VyO1xuXG4gICAgLy8gRGVidWcgbW9kZSBjYW4gbm90IGRlYWwgd2l0aCBzZXNzaW9uIGVuY3J5cHRpb24ga2V5IHlldC5cbiAgICAvLyBOTyBTRVNTSU9OIEVOQ1JZUFRJT04gS0VZLlxuXG4gICAgY29uc3QgcGFzc0tleSA9IChcbiAgICAgIGF3YWl0IHRoaXMua2V5RmFjdG9yeVNlcnZpY2UuZGVyaXZlUGFzc0tleSh7XG4gICAgICAgIHBhc3N3b3JkLFxuICAgICAgICAuLi5jdXJyZW50VXNlcktleS5wYXNzS2V5LnBhc3NLZXlQYXJhbXMsXG4gICAgICB9KVxuICAgICkuandrO1xuXG4gICAgY29uc3QgbWFzdGVyS2V5ID0gYXdhaXQgdGhpcy5rZXlHcmFwaFNlcnZpY2UudW53cmFwV2l0aFBhc3NLZXkoXG4gICAgICBjdXJyZW50VXNlcktleS5wYXNzS2V5LmlkLFxuICAgICAgcGFzc0tleSxcbiAgICAgIGN1cnJlbnRVc2VyS2V5Lm1hc3RlcktleS5pZFxuICAgICk7XG5cbiAgICBhd2FpdCB0aGlzLmlkbGVTZXJ2aWNlLnBlcnNpc3RNYXN0ZXJLZXkobWFzdGVyS2V5KTtcblxuICAgIGF3YWl0IHRoaXMua2V5R3JhcGhTZXJ2aWNlLnBvcHVsYXRlS2V5cyhjdXJyZW50VXNlcktleSk7XG5cbiAgICB0aGlzLnVzZXIgPSB7XG4gICAgICB1c2VybmFtZSxcbiAgICAgIHJlc2V0VXNlcjogbnVsbCxcbiAgICAgIHN1YjogJ0RFQlVHX01PREUnLFxuICAgICAgbG9naW5FbWFpbDogJ0RFQlVHX01PREUnLFxuICAgIH07XG5cbiAgICByZXR1cm4gdGhpcy51c2VyO1xuICB9XG5cbiAgLyoqXG4gICAqIENsZWFycyB0aGUgY2FjaGVzIHVzZXIuIFNvIHdlIGNhbiBzaW11bGF0ZSBhIHBhZ2UgcmVmcmVzaCBhbmQgdGVzdCBnZXRVc2VyKCkuXG4gICAqL1xuICBkZWJ1Z0NsZWFyVXNlcigpIHtcbiAgICB0aGlzLnVzZXIgPSBudWxsO1xuICB9XG59XG4iXX0=
|