@lifeready/core 6.0.5 → 6.1.2
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 +3485 -7369
- 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/auth2/auth.config.js +57 -0
- package/esm2015/lib/auth2/auth2.gql.private.js +8 -1
- package/esm2015/lib/auth2/auth2.service.js +3 -4
- package/esm2015/lib/auth2/auth2.types.js +1 -1
- package/esm2015/lib/encryption/encryption.service.js +7 -6
- package/esm2015/lib/file-upload/file-upload.service.js +4 -4
- package/esm2015/lib/idle/idle.service.js +1 -2
- package/esm2015/lib/item2/item2.service.js +17 -46
- package/esm2015/lib/key/key-graph.service.js +3 -3
- package/esm2015/lib/key/key-meta.service.js +16 -64
- package/esm2015/lib/key/key.types.js +6 -1
- package/esm2015/lib/key-exchange/key-exchange2.service.js +6 -25
- package/esm2015/lib/life-ready.module.js +2 -9
- package/esm2015/lib/password/password.service.js +1 -1
- package/esm2015/lib/profile/profile-details.service.js +120 -75
- package/esm2015/lib/profile/profile.gql.js +134 -1
- package/esm2015/lib/profile/profile.service.js +8 -5
- package/esm2015/lib/profile/profile.types.js +14 -3
- package/esm2015/lib/shared-contact-card/shared-contact-card.service.js +2 -2
- package/esm2015/lib/tp-password-reset/tp-password-reset.types.js +1 -1
- package/esm2015/lib/trusted-party/trusted-party2.service.js +3 -7
- package/esm2015/lifeready-core.js +7 -9
- package/esm2015/public-api.js +2 -20
- package/fesm2015/lifeready-core.js +3223 -6588
- package/fesm2015/lifeready-core.js.map +1 -1
- package/lib/auth2/auth2.gql.private.d.ts +15 -2
- package/lib/auth2/auth2.service.d.ts +1 -1
- package/lib/auth2/auth2.types.d.ts +19 -2
- package/lib/file-upload/file-upload.service.d.ts +2 -2
- package/lib/item2/item2.service.d.ts +12 -75
- package/lib/key/key-meta.service.d.ts +8 -1
- package/lib/key/key.types.d.ts +4 -1
- package/lib/key-exchange/key-exchange2.service.d.ts +5 -66
- package/lib/password/password.service.d.ts +1 -1
- package/lib/profile/profile-details.service.d.ts +10 -11
- package/lib/profile/profile.gql.d.ts +12 -0
- package/lib/profile/profile.service.d.ts +1 -3
- package/lib/profile/profile.types.d.ts +31 -4
- package/lib/shared-contact-card/shared-contact-card.service.d.ts +1 -2
- package/lib/tp-password-reset/tp-password-reset.types.d.ts +3 -3
- package/lib/trusted-party/trusted-party2.service.d.ts +2 -7
- package/lifeready-core.d.ts +6 -8
- package/lifeready-core.metadata.json +1 -1
- package/package.json +1 -1
- package/public-api.d.ts +1 -19
- package/esm2015/lib/auth/auth.config.js +0 -57
- package/esm2015/lib/auth/auth.gql.js +0 -16
- package/esm2015/lib/auth/auth.types.js +0 -18
- package/esm2015/lib/auth/life-ready-auth.service.js +0 -568
- package/esm2015/lib/category/category-meta.service.js +0 -99
- package/esm2015/lib/category/category.gql.js +0 -385
- package/esm2015/lib/category/category.service.js +0 -361
- package/esm2015/lib/category/category.types.js +0 -29
- package/esm2015/lib/key-exchange/key-exchange.gql.js +0 -188
- package/esm2015/lib/key-exchange/key-exchange.service.js +0 -436
- package/esm2015/lib/key-exchange/key-exchange.types.js +0 -7
- package/esm2015/lib/message/message.gql.js +0 -32
- package/esm2015/lib/message/message.service.js +0 -118
- package/esm2015/lib/message/message.types.js +0 -2
- package/esm2015/lib/plan/plan.gql.js +0 -123
- package/esm2015/lib/plan/plan.service.js +0 -150
- package/esm2015/lib/plan/plan.types.js +0 -11
- package/esm2015/lib/record/record-attachment.service.js +0 -102
- package/esm2015/lib/record/record.gql.js +0 -182
- package/esm2015/lib/record/record.service.js +0 -194
- package/esm2015/lib/record/record.types.js +0 -15
- package/esm2015/lib/record-type/record-type.service.js +0 -75
- package/esm2015/lib/record-type/record-type.types.js +0 -28
- package/esm2015/lib/trusted-party/trusted-party.gql.js +0 -148
- package/esm2015/lib/trusted-party/trusted-party.service.js +0 -308
- package/esm2015/lib/trusted-party/trusted-party.types.js +0 -41
- package/lib/auth/auth.gql.d.ts +0 -12
- package/lib/auth/auth.types.d.ts +0 -52
- package/lib/auth/life-ready-auth.service.d.ts +0 -73
- package/lib/category/category-meta.service.d.ts +0 -23
- package/lib/category/category.gql.d.ts +0 -44
- package/lib/category/category.service.d.ts +0 -66
- package/lib/category/category.types.d.ts +0 -75
- package/lib/key-exchange/key-exchange.gql.d.ts +0 -9
- package/lib/key-exchange/key-exchange.service.d.ts +0 -37
- package/lib/key-exchange/key-exchange.types.d.ts +0 -188
- package/lib/message/message.gql.d.ts +0 -13
- package/lib/message/message.service.d.ts +0 -36
- package/lib/message/message.types.d.ts +0 -12
- package/lib/plan/plan.gql.d.ts +0 -11
- package/lib/plan/plan.service.d.ts +0 -34
- package/lib/plan/plan.types.d.ts +0 -32
- package/lib/record/record-attachment.service.d.ts +0 -16
- package/lib/record/record.gql.d.ts +0 -14
- package/lib/record/record.service.d.ts +0 -25
- package/lib/record/record.types.d.ts +0 -56
- package/lib/record-type/record-type.service.d.ts +0 -11
- package/lib/record-type/record-type.types.d.ts +0 -50
- package/lib/trusted-party/trusted-party.gql.d.ts +0 -9
- package/lib/trusted-party/trusted-party.service.d.ts +0 -43
- package/lib/trusted-party/trusted-party.types.d.ts +0 -101
- /package/lib/{auth → auth2}/auth.config.d.ts +0 -0
|
@@ -1,568 +0,0 @@
|
|
|
1
|
-
import { __awaiter } from "tslib";
|
|
2
|
-
import { HttpClient } from '@angular/common/http';
|
|
3
|
-
import { Inject, Injectable, isDevMode } from '@angular/core';
|
|
4
|
-
import { AuthClass } from '@aws-amplify/auth/lib-esm/Auth';
|
|
5
|
-
import { Hub } from '@aws-amplify/core';
|
|
6
|
-
import { JWK } from 'node-jose';
|
|
7
|
-
import { ReplaySubject } from 'rxjs';
|
|
8
|
-
import { LrGraphQLService, LrMutation } from '../api/lr-graphql';
|
|
9
|
-
import { TpPasswordResetProcessorService } from '../api/query-processor/tp-password-reset-processor.service';
|
|
10
|
-
import { TpClaimState } from '../api/types';
|
|
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 { ProfileService } from '../profile/profile.service';
|
|
20
|
-
import { PasswordChangeStatus } from '../profile/profile.types';
|
|
21
|
-
import { TP_PASSWORD_RESET_CLIENT_NONCE_LENGTH, TP_PASSWORD_RESET_USERNAME_SUFFIX, } from '../tp-password-reset/tp-password-reset.constants';
|
|
22
|
-
import { TpPasswordResetAssemblyController } from '../tp-password-reset/tp-password-reset.controller';
|
|
23
|
-
import { CompleteTpPasswordResetRequestMutation, CreateTpAssemblyKeyChallengeMutation, PreCompleteTpPasswordResetRequestMutation, } from '../tp-password-reset/tp-password-reset.gql';
|
|
24
|
-
import { TpPasswordResetUserQuery } from '../tp-password-reset/tp-password-reset.private.gql';
|
|
25
|
-
import { KcBadRequestException, KcBadStateException, KcConcurrentAccessException, KcInternalErrorException, } from '../_common/exceptions';
|
|
26
|
-
import { getAccessJwtToken } from '../_common/utils';
|
|
27
|
-
import { SetSessionEncryptionKeyMutation } from './auth.gql';
|
|
28
|
-
import { RecoveryStatus, } from './auth.types';
|
|
29
|
-
import * as i0 from "@angular/core";
|
|
30
|
-
import * as i1 from "../life-ready.config";
|
|
31
|
-
import * as i2 from "@aws-amplify/auth/lib-esm/Auth";
|
|
32
|
-
import * as i3 from "../key/key-factory.service";
|
|
33
|
-
import * as i4 from "../key/key.service";
|
|
34
|
-
import * as i5 from "../profile/profile.service";
|
|
35
|
-
import * as i6 from "../key/key-graph.service";
|
|
36
|
-
import * as i7 from "../password/password.service";
|
|
37
|
-
import * as i8 from "../idle/idle.service";
|
|
38
|
-
import * as i9 from "../api/lr-graphql/lr-graphql.service";
|
|
39
|
-
import * as i10 from "../api/query-processor/tp-password-reset-processor.service";
|
|
40
|
-
import * as i11 from "../persist/persist.service";
|
|
41
|
-
import * as i12 from "../encryption/encryption.service";
|
|
42
|
-
import * as i13 from "../tp-password-reset/tp-password-reset.controller";
|
|
43
|
-
import * as i14 from "@angular/common/http";
|
|
44
|
-
export const initialiseAuth = (authService) => {
|
|
45
|
-
return () => authService.initialise();
|
|
46
|
-
};
|
|
47
|
-
export class LifeReadyAuthService {
|
|
48
|
-
constructor(config, auth, keyFactory, keyService, profileService, keyGraphService, passwordService, idleService, lrGraphQL, tpPasswordResetProcessorService, persistService, encryptionService, assemblyController, http) {
|
|
49
|
-
this.config = config;
|
|
50
|
-
this.auth = auth;
|
|
51
|
-
this.keyFactory = keyFactory;
|
|
52
|
-
this.keyService = keyService;
|
|
53
|
-
this.profileService = profileService;
|
|
54
|
-
this.keyGraphService = keyGraphService;
|
|
55
|
-
this.passwordService = passwordService;
|
|
56
|
-
this.idleService = idleService;
|
|
57
|
-
this.lrGraphQL = lrGraphQL;
|
|
58
|
-
this.tpPasswordResetProcessorService = tpPasswordResetProcessorService;
|
|
59
|
-
this.persistService = persistService;
|
|
60
|
-
this.encryptionService = encryptionService;
|
|
61
|
-
this.assemblyController = assemblyController;
|
|
62
|
-
this.http = http;
|
|
63
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
64
|
-
this.hubSubject = new ReplaySubject(1);
|
|
65
|
-
// Could use rxjs observables here. But trying to have kc-client use as little angular
|
|
66
|
-
// features as possible. Rxjs is not used anywhere else in kc-client.
|
|
67
|
-
this.logoutListeners = new Set();
|
|
68
|
-
if (!isDevMode()) {
|
|
69
|
-
if (this.config.debug != null) {
|
|
70
|
-
throw new KcBadRequestException('In production mode, "config.debug" must be set to null');
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
initialise() {
|
|
75
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
76
|
-
Hub.listen('auth', (data) => this.hubSubject.next(data.payload));
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
debugLogin(username, password) {
|
|
80
|
-
// This will fail if debug is null. But when debug is null, this function
|
|
81
|
-
// should not be called.
|
|
82
|
-
this.config.debug.username = username;
|
|
83
|
-
return this.debugLoadUser(password);
|
|
84
|
-
}
|
|
85
|
-
// ------------------------------------------------------------------------
|
|
86
|
-
// ------------------------------------------------------------------------
|
|
87
|
-
// ------------------------------------------------------------------------
|
|
88
|
-
/**
|
|
89
|
-
* Login using the server side session method.
|
|
90
|
-
*/
|
|
91
|
-
debugLoginUsingSession(username) {
|
|
92
|
-
return this.http
|
|
93
|
-
.get(this.config.apiUrl +
|
|
94
|
-
'debug_only/users/login/?username=' +
|
|
95
|
-
encodeURIComponent(username), {
|
|
96
|
-
// Non-obvious alert: if you want the cookies to be set, you must use the
|
|
97
|
-
// "withCredentials" header. I would have thought the withCredentials header
|
|
98
|
-
// is only used to send the cookies with the requests. But, if you don't include
|
|
99
|
-
// the "withCredentials" header, the cookies in the response DOES NOT get set!
|
|
100
|
-
//
|
|
101
|
-
// ref: https://github.com/github/fetch/issues/386#issuecomment-243229388
|
|
102
|
-
withCredentials: true,
|
|
103
|
-
})
|
|
104
|
-
.toPromise();
|
|
105
|
-
}
|
|
106
|
-
debugLoadUser(password) {
|
|
107
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
108
|
-
const { currentUser, contactCard, userPlans } = yield this.profileService.getCurrentUser();
|
|
109
|
-
// Debug mode can not deal with session encryption key yet.
|
|
110
|
-
// NO SESSION ENCRYPTION KEY.
|
|
111
|
-
const passKey = (yield this.keyFactory.derivePassKey(Object.assign({ password }, currentUser.currentUserKey.passKey.passKeyParams))).jwk;
|
|
112
|
-
const masterKey = yield this.keyGraphService.unwrapWithPassKey(currentUser.currentUserKey.passKey.id, passKey, currentUser.currentUserKey.masterKey.id);
|
|
113
|
-
yield this.idleService.persistMasterKey(masterKey);
|
|
114
|
-
yield this.keyGraphService.populateKeys(currentUser.currentUserKey);
|
|
115
|
-
return {
|
|
116
|
-
id: currentUser.id,
|
|
117
|
-
sub: 'DEBUG_MODE',
|
|
118
|
-
username: currentUser.username,
|
|
119
|
-
currentUserKey: currentUser.currentUserKey,
|
|
120
|
-
email: 'DEBUG_MODE',
|
|
121
|
-
emailVerified: false,
|
|
122
|
-
phone: 'DEBUG_MODE',
|
|
123
|
-
phoneVerified: false,
|
|
124
|
-
contactCard: Object.assign({}, (yield this.profileService.decryptContactCard(contactCard))),
|
|
125
|
-
userDelete: currentUser.userDelete,
|
|
126
|
-
userPlans,
|
|
127
|
-
hasTPVaultAccess: this.mapTPVaultAccess(currentUser.features),
|
|
128
|
-
features: currentUser.features,
|
|
129
|
-
sessionEncryptionKey: currentUser.sessionEncryptionKey,
|
|
130
|
-
dateJoined: currentUser.dateJoined,
|
|
131
|
-
};
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
getAccessJwtToken() {
|
|
135
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
136
|
-
return getAccessJwtToken(this.auth);
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
importPassword(plainPassword) {
|
|
140
|
-
return this.keyFactory.importPassword(plainPassword);
|
|
141
|
-
}
|
|
142
|
-
addLogoutListener(callback) {
|
|
143
|
-
this.logoutListeners.add(callback);
|
|
144
|
-
}
|
|
145
|
-
removeLogoutListener(callback) {
|
|
146
|
-
this.logoutListeners.delete(callback);
|
|
147
|
-
}
|
|
148
|
-
loginIdpImpl(emailOrPhone, password, passIdpParams, recoveryStatus) {
|
|
149
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
150
|
-
const passIdpResult = yield this.keyFactory.derivePassIdp(Object.assign({ password }, passIdpParams));
|
|
151
|
-
// Use the derived password to signin with cognito
|
|
152
|
-
const user = yield this.auth.signIn(emailOrPhone, this.passwordService.getPassIdpString(passIdpResult.jwk));
|
|
153
|
-
user.recoveryStatus = recoveryStatus;
|
|
154
|
-
return user;
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
|
-
loginIdp(emailOrPhone, password) {
|
|
158
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
159
|
-
// Download the salt needed to derive the PassIdp
|
|
160
|
-
const passIdpApiResult = yield this.profileService.getPassIdpParams(emailOrPhone);
|
|
161
|
-
if (passIdpApiResult.passwordChangeStatus === PasswordChangeStatus.InProgress) {
|
|
162
|
-
throw new KcConcurrentAccessException('A password change is in progress');
|
|
163
|
-
}
|
|
164
|
-
if (passIdpApiResult.passwordChangeStatus === PasswordChangeStatus.Recovery) {
|
|
165
|
-
console.log('In recovery mode.');
|
|
166
|
-
// Let's say we don't know if the password is the new one or the old one. We just have to try both.
|
|
167
|
-
try {
|
|
168
|
-
const user = yield this.loginIdpImpl(emailOrPhone, password, passIdpApiResult.newPassIdpParams, RecoveryStatus.NEW_PASSWORD);
|
|
169
|
-
// New password worked. Let's set to the current password
|
|
170
|
-
// --Potential Failure Point 1--
|
|
171
|
-
// if changePasswordComplete() doesn't get called, then it should remain
|
|
172
|
-
console.log('New password works!');
|
|
173
|
-
return user;
|
|
174
|
-
}
|
|
175
|
-
catch (error) {
|
|
176
|
-
// Just bubble up any other type of error.
|
|
177
|
-
if (error.code !== 'NotAuthorizedException') {
|
|
178
|
-
throw error;
|
|
179
|
-
}
|
|
180
|
-
// pass, try again assuming it's the old password
|
|
181
|
-
}
|
|
182
|
-
// Now assume it's the previous password. Any exception is allowed to bubble up.
|
|
183
|
-
try {
|
|
184
|
-
const user = yield this.loginIdpImpl(emailOrPhone, password, passIdpApiResult.currentPassIdpParams, RecoveryStatus.OLD_PASSWORD);
|
|
185
|
-
// Old password worked.
|
|
186
|
-
console.log('Old password works!');
|
|
187
|
-
return user;
|
|
188
|
-
}
|
|
189
|
-
catch (error) {
|
|
190
|
-
// Just bubble up any other type of error.
|
|
191
|
-
throw error.code === 'NotAuthorizedException'
|
|
192
|
-
? new KcBadRequestException('The password change request was interrupted, please try to login with both your new and old password')
|
|
193
|
-
: error;
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
// Try against as the TP password reset account
|
|
197
|
-
if (passIdpApiResult.tpPasswordReset) {
|
|
198
|
-
try {
|
|
199
|
-
// TP password reset is in process. We need to try the password against both
|
|
200
|
-
// original account and the new reset account.
|
|
201
|
-
const reset = passIdpApiResult.tpPasswordReset;
|
|
202
|
-
const ret = yield this.loginIdpImpl(reset.resetUsername, password, reset.passIdpParams, RecoveryStatus.NONE);
|
|
203
|
-
ret.isTpPasswordResetUser = true;
|
|
204
|
-
return ret;
|
|
205
|
-
}
|
|
206
|
-
catch (err) {
|
|
207
|
-
// continue, try again as regular user.
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
// Login as regular user
|
|
211
|
-
return yield this.loginIdpImpl(emailOrPhone, password, passIdpApiResult.currentPassIdpParams, RecoveryStatus.NONE);
|
|
212
|
-
});
|
|
213
|
-
}
|
|
214
|
-
handleSessionEncryptionKey() {
|
|
215
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
216
|
-
if (this.config.disableSessionEncryptionKey) {
|
|
217
|
-
if (!isDevMode()) {
|
|
218
|
-
const msg = 'You should not set disableSessionEncryptionKey=True in mode prod. It defaults to false.';
|
|
219
|
-
console.error(msg);
|
|
220
|
-
throw new Error(msg);
|
|
221
|
-
}
|
|
222
|
-
else {
|
|
223
|
-
console.warn('You have set disableSessionEncryptionKey=True. Make sure not to do this in prod mode.');
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
else {
|
|
227
|
-
// Set the session key to a new encryption key for this session
|
|
228
|
-
const sessionEncryptionKey = yield this.keyFactory.createKey();
|
|
229
|
-
yield this.lrGraphQL.lrMutate(new LrMutation({
|
|
230
|
-
mutation: SetSessionEncryptionKeyMutation,
|
|
231
|
-
variables: {
|
|
232
|
-
input: {
|
|
233
|
-
sessionEncryptionKey: JSON.stringify(sessionEncryptionKey.toJSON(true)),
|
|
234
|
-
},
|
|
235
|
-
},
|
|
236
|
-
}), {
|
|
237
|
-
includeKeyGraph: false,
|
|
238
|
-
});
|
|
239
|
-
this.persistService.setServerSessionEncryptionKey(sessionEncryptionKey);
|
|
240
|
-
}
|
|
241
|
-
});
|
|
242
|
-
}
|
|
243
|
-
handlePostAuth(cognitoUser) {
|
|
244
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
245
|
-
yield this.handlePasswordRecovery(cognitoUser);
|
|
246
|
-
yield this.handleSessionEncryptionKey();
|
|
247
|
-
});
|
|
248
|
-
}
|
|
249
|
-
login(emailOrPhone, password, { tpPasswordResetAutoComplete = true } = {}) {
|
|
250
|
-
var _a;
|
|
251
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
252
|
-
let loginResult = yield this.loginImpl(emailOrPhone, password);
|
|
253
|
-
if (tpPasswordResetAutoComplete &&
|
|
254
|
-
((_a = loginResult.resetUser) === null || _a === void 0 ? void 0 : _a.state) === TpClaimState.APPROVED) {
|
|
255
|
-
yield this.completeRequest(password);
|
|
256
|
-
loginResult = yield this.loginImpl(emailOrPhone, password);
|
|
257
|
-
}
|
|
258
|
-
return loginResult;
|
|
259
|
-
});
|
|
260
|
-
}
|
|
261
|
-
loginImpl(emailOrPhone, password) {
|
|
262
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
263
|
-
yield this.logout();
|
|
264
|
-
const cognitoUser = yield this.loginIdp(emailOrPhone, password);
|
|
265
|
-
// todo: Meet MFA challenges.
|
|
266
|
-
if (['SMS_MFA', 'SOFTWARE_TOKEN_MFA'].includes(cognitoUser.challengeName)) {
|
|
267
|
-
return { hasChallenge: true, challenge: cognitoUser };
|
|
268
|
-
}
|
|
269
|
-
yield this.handlePostAuth(cognitoUser);
|
|
270
|
-
if (cognitoUser.isTpPasswordResetUser) {
|
|
271
|
-
// Assuming there is no MFA on the TP reset user.
|
|
272
|
-
const resetUser = yield this.loadResetUser(password);
|
|
273
|
-
return { hasChallenge: false, resetUser };
|
|
274
|
-
}
|
|
275
|
-
else {
|
|
276
|
-
const user = yield this.loadUser(cognitoUser, password);
|
|
277
|
-
yield this.idleService.start(); // Run idleService whenever user is logged in.
|
|
278
|
-
return { hasChallenge: false, user };
|
|
279
|
-
}
|
|
280
|
-
});
|
|
281
|
-
}
|
|
282
|
-
// TODO <AZ> We need to handle the isTpPasswordResetUser=True case here after MFA as well.
|
|
283
|
-
verifyLogin(challenge, password, rememberMe, code) {
|
|
284
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
285
|
-
yield this.auth.confirmSignIn(challenge, code, challenge.challengeName);
|
|
286
|
-
// TODO: this.auth.confirmSignIn() could return another challenge.
|
|
287
|
-
const cognitoUser = yield this.auth.currentAuthenticatedUser();
|
|
288
|
-
yield this.handlePostAuth(challenge);
|
|
289
|
-
const user = yield this.loadUser(cognitoUser, password);
|
|
290
|
-
if (rememberMe) {
|
|
291
|
-
cognitoUser.setDeviceStatusRemembered({
|
|
292
|
-
onSuccess: () => {
|
|
293
|
-
return;
|
|
294
|
-
},
|
|
295
|
-
onFailure: (e) => console.error(e),
|
|
296
|
-
});
|
|
297
|
-
}
|
|
298
|
-
return user;
|
|
299
|
-
});
|
|
300
|
-
}
|
|
301
|
-
handlePasswordRecovery(user) {
|
|
302
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
303
|
-
if (user.recoveryStatus !== RecoveryStatus.NONE) {
|
|
304
|
-
yield this.passwordService.changePasswordComplete({
|
|
305
|
-
useNewPassword: user.recoveryStatus === RecoveryStatus.NEW_PASSWORD,
|
|
306
|
-
});
|
|
307
|
-
}
|
|
308
|
-
});
|
|
309
|
-
}
|
|
310
|
-
getUserOrResetUser(reload = false) {
|
|
311
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
312
|
-
const cognitoUser = yield this.auth.currentAuthenticatedUser();
|
|
313
|
-
if (cognitoUser.getUsername().endsWith(TP_PASSWORD_RESET_USERNAME_SUFFIX)) {
|
|
314
|
-
return this.getResetUser(reload);
|
|
315
|
-
}
|
|
316
|
-
else {
|
|
317
|
-
return this.getUser(reload);
|
|
318
|
-
}
|
|
319
|
-
});
|
|
320
|
-
}
|
|
321
|
-
getResetUser(reload = false) {
|
|
322
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
323
|
-
if (!reload && this.currentResetUser) {
|
|
324
|
-
return this.currentResetUser;
|
|
325
|
-
}
|
|
326
|
-
this.currentResetUser = yield this.loadResetUser();
|
|
327
|
-
yield this.idleService.start(); // Run idleService whenever user is logged in.
|
|
328
|
-
return this.currentResetUser;
|
|
329
|
-
});
|
|
330
|
-
}
|
|
331
|
-
getUser(reload = false) {
|
|
332
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
333
|
-
if (!reload && this.currentUser) {
|
|
334
|
-
return this.currentUser;
|
|
335
|
-
}
|
|
336
|
-
this.currentUser = yield this.loadUser(yield this.auth.currentAuthenticatedUser());
|
|
337
|
-
console.log('Starting idle service.');
|
|
338
|
-
yield this.idleService.start(); // Run idleService whenever user is logged in.
|
|
339
|
-
return this.currentUser;
|
|
340
|
-
});
|
|
341
|
-
}
|
|
342
|
-
mapTPVaultAccess(features) {
|
|
343
|
-
const tpVaultFeature = features === null || features === void 0 ? void 0 : features.tpVault;
|
|
344
|
-
return ((tpVaultFeature === null || tpVaultFeature === void 0 ? void 0 : tpVaultFeature.length) > 0 &&
|
|
345
|
-
tpVaultFeature.some((feature) => feature.toUpperCase() === 'ACCESS'));
|
|
346
|
-
}
|
|
347
|
-
loadUser(cognitoUser, password) {
|
|
348
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
349
|
-
const { currentUser, contactCard, userPlans } = yield this.profileService.getCurrentUser();
|
|
350
|
-
if (currentUser.sessionEncryptionKey) {
|
|
351
|
-
this.persistService.setServerSessionEncryptionKey(yield JWK.asKey(currentUser.sessionEncryptionKey));
|
|
352
|
-
}
|
|
353
|
-
const userAttributes = yield this.auth.userAttributes(cognitoUser);
|
|
354
|
-
if (password) {
|
|
355
|
-
const passKey = (yield this.keyFactory.derivePassKey(Object.assign({ password }, currentUser.currentUserKey.passKey.passKeyParams))).jwk;
|
|
356
|
-
yield this.idleService.persistMasterKey(yield this.keyGraphService.unwrapWithPassKey(currentUser.currentUserKey.passKey.id, passKey, currentUser.currentUserKey.masterKey.id));
|
|
357
|
-
}
|
|
358
|
-
yield this.keyGraphService.populateKeys(currentUser.currentUserKey);
|
|
359
|
-
return {
|
|
360
|
-
id: currentUser.id,
|
|
361
|
-
sub: this.getUserAttribute('sub', userAttributes),
|
|
362
|
-
username: currentUser.username,
|
|
363
|
-
currentUserKey: currentUser.currentUserKey,
|
|
364
|
-
email: this.getUserAttribute('email', userAttributes),
|
|
365
|
-
emailVerified: this.getUserAttribute('email_verified', userAttributes) === 'true',
|
|
366
|
-
phone: this.getUserAttribute('phone_number', userAttributes),
|
|
367
|
-
phoneVerified: this.getUserAttribute('phone_number_verified', userAttributes) ===
|
|
368
|
-
'true',
|
|
369
|
-
contactCard: Object.assign({}, (yield this.profileService.decryptContactCard(contactCard))),
|
|
370
|
-
userDelete: currentUser.userDelete,
|
|
371
|
-
userPlans,
|
|
372
|
-
hasTPVaultAccess: this.mapTPVaultAccess(currentUser.features),
|
|
373
|
-
features: currentUser.features,
|
|
374
|
-
sessionEncryptionKey: currentUser.sessionEncryptionKey,
|
|
375
|
-
dateJoined: currentUser.dateJoined,
|
|
376
|
-
};
|
|
377
|
-
});
|
|
378
|
-
}
|
|
379
|
-
watchAuth() {
|
|
380
|
-
return this.hubSubject;
|
|
381
|
-
}
|
|
382
|
-
logout() {
|
|
383
|
-
var _a;
|
|
384
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
385
|
-
// Notify all listeners to clean up.
|
|
386
|
-
yield Promise.all([...this.logoutListeners].map((callback) => callback()));
|
|
387
|
-
this.currentUser = null;
|
|
388
|
-
this.keyService.purgeKeys();
|
|
389
|
-
this.keyGraphService.purgeKeys();
|
|
390
|
-
yield Promise.all([this.auth.signOut(), this.profileService.signOut()]);
|
|
391
|
-
if ((_a = this.config.debug) === null || _a === void 0 ? void 0 : _a.username) {
|
|
392
|
-
this.config.debug.username = null;
|
|
393
|
-
}
|
|
394
|
-
});
|
|
395
|
-
}
|
|
396
|
-
getUserAttribute(attributeName, userAttributes) {
|
|
397
|
-
const userAttribute = userAttributes.find((x) => x.getName() === attributeName);
|
|
398
|
-
return userAttribute ? userAttribute.getValue() : null;
|
|
399
|
-
}
|
|
400
|
-
loadResetUser(password) {
|
|
401
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
402
|
-
const { tpPasswordResetUser: resetUser } = yield this.lrGraphQL.query({
|
|
403
|
-
query: TpPasswordResetUserQuery,
|
|
404
|
-
});
|
|
405
|
-
if (resetUser.sessionEncryptionKey) {
|
|
406
|
-
this.persistService.setServerSessionEncryptionKey(yield JWK.asKey(resetUser.sessionEncryptionKey));
|
|
407
|
-
}
|
|
408
|
-
// Update the keys
|
|
409
|
-
if (password) {
|
|
410
|
-
const passKey = (yield this.keyFactory.derivePassKey(Object.assign({ password }, resetUser.passKey.passKeyParams))).jwk;
|
|
411
|
-
yield this.idleService.persistMasterKey(yield this.keyGraphService.unwrapWithPassKey(resetUser.passKey.id, passKey, resetUser.masterKey.id));
|
|
412
|
-
}
|
|
413
|
-
this.keyService.setKeys({
|
|
414
|
-
passKey: {
|
|
415
|
-
id: resetUser.passKey.id,
|
|
416
|
-
},
|
|
417
|
-
masterKey: {
|
|
418
|
-
id: resetUser.masterKey.id,
|
|
419
|
-
},
|
|
420
|
-
});
|
|
421
|
-
const userAttributes = yield this.auth.userAttributes(yield this.auth.currentAuthenticatedUser());
|
|
422
|
-
const sub = this.getUserAttribute('sub', userAttributes);
|
|
423
|
-
return Object.assign(Object.assign({}, (yield this.tpPasswordResetProcessorService.processTpPasswordResetUserNode(resetUser))), { sub });
|
|
424
|
-
});
|
|
425
|
-
}
|
|
426
|
-
refreshAccessToken() {
|
|
427
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
428
|
-
const cognitoUser = yield this.auth.currentAuthenticatedUser();
|
|
429
|
-
const refreshToken = cognitoUser.getSignInUserSession().getRefreshToken();
|
|
430
|
-
return new Promise((resolve, reject) => {
|
|
431
|
-
cognitoUser.refreshSession(refreshToken, (err) => {
|
|
432
|
-
if (err) {
|
|
433
|
-
console.error('Error refreshing token: ', err);
|
|
434
|
-
reject(err);
|
|
435
|
-
}
|
|
436
|
-
else {
|
|
437
|
-
console.log('Token refresh complete');
|
|
438
|
-
resolve(0);
|
|
439
|
-
}
|
|
440
|
-
});
|
|
441
|
-
});
|
|
442
|
-
});
|
|
443
|
-
}
|
|
444
|
-
completeRequest(newPassword) {
|
|
445
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
446
|
-
const resetUser = yield this.getResetUser(true);
|
|
447
|
-
if (resetUser.state !== TpClaimState.APPROVED) {
|
|
448
|
-
throw new KcBadStateException('Password reset request has not been approved.');
|
|
449
|
-
}
|
|
450
|
-
// --------------------------------------------------------------
|
|
451
|
-
// Prepare all materials to ensure there are no errors.
|
|
452
|
-
// --------------------------------------------------------------
|
|
453
|
-
const assemblyKey = yield this.recoverAssemblyKey(resetUser);
|
|
454
|
-
const { rootKey } = yield this.encryptionService.decrypt(assemblyKey, resetUser.assemblyCipherData);
|
|
455
|
-
// Making sure it's a valid key.
|
|
456
|
-
const rootKeyJwk = yield JWK.asKey(rootKey);
|
|
457
|
-
const masterKey = yield this.keyGraphService.getKey(resetUser.masterKey.id);
|
|
458
|
-
const masterKeyWrappedRootKey = yield this.encryptionService.encryptToString(masterKey.jwk, rootKeyJwk.toJSON(true));
|
|
459
|
-
// The new password
|
|
460
|
-
const newPassIdpResult = yield this.keyFactory.derivePassIdp(Object.assign({ password: newPassword }, resetUser.passKey.passIdpParams));
|
|
461
|
-
const newIdpPassword = this.passwordService.getPassIdpString(newPassIdpResult.jwk);
|
|
462
|
-
// --------------------------------------------------------------
|
|
463
|
-
// Get assembly key challenge
|
|
464
|
-
// --------------------------------------------------------------
|
|
465
|
-
const challenge = (yield this.lrGraphQL.lrMutate(new LrMutation({
|
|
466
|
-
mutation: CreateTpAssemblyKeyChallengeMutation,
|
|
467
|
-
variables: {
|
|
468
|
-
input: {},
|
|
469
|
-
},
|
|
470
|
-
}), {
|
|
471
|
-
includeKeyGraph: false,
|
|
472
|
-
})).createTpAssemblyKeyChallenge.challenge;
|
|
473
|
-
// Sign the challenge
|
|
474
|
-
// Generate a client side nonce that's no in the server's control.
|
|
475
|
-
challenge.clientNonce = this.keyFactory.randomString(TP_PASSWORD_RESET_CLIENT_NONCE_LENGTH);
|
|
476
|
-
const assemblyKeyVerifierPrk = yield this.encryptionService.decrypt(assemblyKey, resetUser.wrappedAssemblyKeyVerifierPrk);
|
|
477
|
-
const signedChallenge = yield this.encryptionService.sign(assemblyKeyVerifierPrk, challenge);
|
|
478
|
-
// --------------------------------------------------------------
|
|
479
|
-
// Change password for the original user
|
|
480
|
-
// --------------------------------------------------------------
|
|
481
|
-
const tempIdpPassword = (yield this.lrGraphQL.lrMutate(new LrMutation({
|
|
482
|
-
mutation: PreCompleteTpPasswordResetRequestMutation,
|
|
483
|
-
variables: {
|
|
484
|
-
input: {
|
|
485
|
-
signedChallenge: JSON.stringify(signedChallenge),
|
|
486
|
-
},
|
|
487
|
-
},
|
|
488
|
-
}), {
|
|
489
|
-
includeKeyGraph: false,
|
|
490
|
-
})).preCompleteTpPasswordResetRequest.idpPassword;
|
|
491
|
-
// --------------------------------------------------------------
|
|
492
|
-
// Login as the original user using new temporary password
|
|
493
|
-
// --------------------------------------------------------------
|
|
494
|
-
// At this point, the original account's password has been changed
|
|
495
|
-
// to a temporary password. It is no longer possible for the user
|
|
496
|
-
// to use the original password to login. Any successful login
|
|
497
|
-
// can only be using the temporary password. So it's safe to assume
|
|
498
|
-
// that we want to "complete" the password reset.
|
|
499
|
-
// The maybe 2FA so we listen for the auth event from Amplify.
|
|
500
|
-
const retPromise = new Promise((resolve) => {
|
|
501
|
-
const listener = (data) => __awaiter(this, void 0, void 0, function* () {
|
|
502
|
-
if (data.payload.event !== 'signIn') {
|
|
503
|
-
return;
|
|
504
|
-
}
|
|
505
|
-
Hub.remove('auth', listener);
|
|
506
|
-
yield this.auth.signIn(resetUser.username, newIdpPassword);
|
|
507
|
-
// Switch over to the new set of keys
|
|
508
|
-
yield this.lrGraphQL.lrMutate(new LrMutation({
|
|
509
|
-
mutation: CompleteTpPasswordResetRequestMutation,
|
|
510
|
-
variables: {
|
|
511
|
-
input: {
|
|
512
|
-
masterKeyWrappedRootKey,
|
|
513
|
-
masterKeyId: masterKey.id,
|
|
514
|
-
},
|
|
515
|
-
},
|
|
516
|
-
}));
|
|
517
|
-
resolve();
|
|
518
|
-
});
|
|
519
|
-
Hub.listen('auth', listener);
|
|
520
|
-
});
|
|
521
|
-
// Signin as the original user. Password has been reset to temporary one. It should return
|
|
522
|
-
// with NEW_PASSWORD_REQUIRED
|
|
523
|
-
let user = yield this.auth.signIn(resetUser.username, tempIdpPassword, {
|
|
524
|
-
noProxy: 'true',
|
|
525
|
-
});
|
|
526
|
-
if (user.challengeName !== 'NEW_PASSWORD_REQUIRED') {
|
|
527
|
-
throw new KcInternalErrorException('Expecting Cognito to have done a password reset after call to PreCompleteTpPasswordResetRequestMutation.');
|
|
528
|
-
}
|
|
529
|
-
// Set new password on Idp
|
|
530
|
-
// the awsFetch() function passes NEW_PASSWORD_REQUIRED directly to AWS without
|
|
531
|
-
// going through the proxy.
|
|
532
|
-
user = yield this.auth.completeNewPassword(user, newIdpPassword, {});
|
|
533
|
-
return retPromise;
|
|
534
|
-
});
|
|
535
|
-
}
|
|
536
|
-
recoverAssemblyKey(resetUser) {
|
|
537
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
538
|
-
const prk = yield this.keyGraphService.getKey(resetUser.pxk.id);
|
|
539
|
-
const partials = yield Promise.all(resetUser.approvals
|
|
540
|
-
.filter((approval) => !!approval.receiverCipherPartialAssemblyKey)
|
|
541
|
-
.map((approval) => this.encryptionService.decrypt(prk, approval.receiverCipherPartialAssemblyKey)));
|
|
542
|
-
return this.assemblyController.recoverAssemblyKey(partials);
|
|
543
|
-
});
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
LifeReadyAuthService.ɵprov = i0.ɵɵdefineInjectable({ factory: function LifeReadyAuthService_Factory() { return new LifeReadyAuthService(i0.ɵɵinject(i1.KC_CONFIG), i0.ɵɵinject(i2.AuthClass), i0.ɵɵinject(i3.KeyFactoryService), i0.ɵɵinject(i4.KeyService), i0.ɵɵinject(i5.ProfileService), i0.ɵɵinject(i6.KeyGraphService), i0.ɵɵinject(i7.PasswordService), i0.ɵɵinject(i8.IdleService), i0.ɵɵinject(i9.LrGraphQLService), i0.ɵɵinject(i10.TpPasswordResetProcessorService), i0.ɵɵinject(i11.PersistService), i0.ɵɵinject(i12.EncryptionService), i0.ɵɵinject(i13.TpPasswordResetAssemblyController), i0.ɵɵinject(i14.HttpClient)); }, token: LifeReadyAuthService, providedIn: "root" });
|
|
547
|
-
LifeReadyAuthService.decorators = [
|
|
548
|
-
{ type: Injectable, args: [{
|
|
549
|
-
providedIn: 'root',
|
|
550
|
-
},] }
|
|
551
|
-
];
|
|
552
|
-
LifeReadyAuthService.ctorParameters = () => [
|
|
553
|
-
{ type: undefined, decorators: [{ type: Inject, args: [KC_CONFIG,] }] },
|
|
554
|
-
{ type: AuthClass },
|
|
555
|
-
{ type: KeyFactoryService },
|
|
556
|
-
{ type: KeyService },
|
|
557
|
-
{ type: ProfileService },
|
|
558
|
-
{ type: KeyGraphService },
|
|
559
|
-
{ type: PasswordService },
|
|
560
|
-
{ type: IdleService },
|
|
561
|
-
{ type: LrGraphQLService },
|
|
562
|
-
{ type: TpPasswordResetProcessorService },
|
|
563
|
-
{ type: PersistService },
|
|
564
|
-
{ type: EncryptionService },
|
|
565
|
-
{ type: TpPasswordResetAssemblyController },
|
|
566
|
-
{ type: HttpClient }
|
|
567
|
-
];
|
|
568
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGlmZS1yZWFkeS1hdXRoLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9jb3JlL3NyYy9saWIvYXV0aC9saWZlLXJlYWR5LWF1dGguc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ2xELE9BQU8sRUFBRSxNQUFNLEVBQUUsVUFBVSxFQUFFLFNBQVMsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUU5RCxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFDM0QsT0FBTyxFQUFFLEdBQUcsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBRXhDLE9BQU8sRUFBRSxHQUFHLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFDaEMsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUNyQyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsVUFBVSxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDakUsT0FBTyxFQUFFLCtCQUErQixFQUFFLE1BQU0sNERBQTRELENBQUM7QUFDN0csT0FBTyxFQUFFLFlBQVksRUFBMkIsTUFBTSxjQUFjLENBQUM7QUFDckUsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sa0NBQWtDLENBQUM7QUFDckUsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ25ELE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQy9ELE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUMzRCxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFFaEQsT0FBTyxFQUFZLFNBQVMsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQzNELE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUMvRCxP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TUFBTSxHQUFHLEdBQUcsTUFBTSxJQUFJLENBQUMsZUFBZSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBRWhFLE1BQU0sUUFBUSxHQUFHLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FDaEMsU0FBUyxDQUFDLFNBQVM7aUJBQ2hCLE1BQU0sQ0FBQyxDQUFDLFFBQVEsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxnQ0FBZ0MsQ0FBQztpQkFDakUsR0FBRyxDQUFDLENBQUMsUUFBUSxFQUFFLEVBQUUsQ0FDaEIsSUFBSSxDQUFDLGlCQUFpQixDQUFDLE9BQU8sQ0FDNUIsR0FBRyxFQUNILFFBQVEsQ0FBQyxnQ0FBZ0MsQ0FDMUMsQ0FDRixDQUNKLENBQUM7WUFFRixPQUFPLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxrQkFBa0IsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUM5RCxDQUFDO0tBQUE7Ozs7WUFsdUJGLFVBQVUsU0FBQztnQkFDVixVQUFVLEVBQUUsTUFBTTthQUNuQjs7OzRDQVdJLE1BQU0sU0FBQyxTQUFTO1lBckVaLFNBQVM7WUFVVCxpQkFBaUI7WUFFakIsVUFBVTtZQUtWLGNBQWM7WUFOZCxlQUFlO1lBSWYsZUFBZTtZQU5mLFdBQVc7WUFKWCxnQkFBZ0I7WUFDaEIsK0JBQStCO1lBVS9CLGNBQWM7WUFSZCxpQkFBaUI7WUFlakIsaUNBQWlDO1lBMUJqQyxVQUFVIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSHR0cENsaWVudCB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbi9odHRwJztcbmltcG9ydCB7IEluamVjdCwgSW5qZWN0YWJsZSwgaXNEZXZNb2RlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBDb2duaXRvVXNlciB9IGZyb20gJ0Bhd3MtYW1wbGlmeS9hdXRoJztcbmltcG9ydCB7IEF1dGhDbGFzcyB9IGZyb20gJ0Bhd3MtYW1wbGlmeS9hdXRoL2xpYi1lc20vQXV0aCc7XG5pbXBvcnQgeyBIdWIgfSBmcm9tICdAYXdzLWFtcGxpZnkvY29yZSc7XG5pbXBvcnQgeyBDb2duaXRvVXNlckF0dHJpYnV0ZSB9IGZyb20gJ2FtYXpvbi1jb2duaXRvLWlkZW50aXR5LWpzJztcbmltcG9ydCB7IEpXSyB9IGZyb20gJ25vZGUtam9zZSc7XG5pbXBvcnQgeyBSZXBsYXlTdWJqZWN0IH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBMckdyYXBoUUxTZXJ2aWNlLCBMck11dGF0aW9uIH0gZnJvbSAnLi4vYXBpL2xyLWdyYXBocWwnO1xuaW1wb3J0IHsgVHBQYXNzd29yZFJlc2V0UHJvY2Vzc29yU2VydmljZSB9IGZyb20gJy4uL2FwaS9xdWVyeS1wcm9jZXNzb3IvdHAtcGFzc3dvcmQtcmVzZXQtcHJvY2Vzc29yLnNlcnZpY2UnO1xuaW1wb3J0IHsgVHBDbGFpbVN0YXRlLCBUcFBhc3N3b3JkUmVzZXRVc2VyTm9kZSB9IGZyb20gJy4uL2FwaS90eXBlcyc7XG5pbXBvcnQgeyBFbmNyeXB0aW9uU2VydmljZSB9IGZyb20gJy4uL2VuY3J5cHRpb24vZW5jcnlwdGlvbi5zZXJ2aWNlJztcbmltcG9ydCB7IElkbGVTZXJ2aWNlIH0gZnJvbSAnLi4vaWRsZS9pZGxlLnNlcnZpY2UnO1xuaW1wb3J0IHsgS2V5RmFjdG9yeVNlcnZpY2UgfSBmcm9tICcuLi9rZXkva2V5LWZhY3Rvcnkuc2VydmljZSc7XG5pbXBvcnQgeyBLZXlHcmFwaFNlcnZpY2UgfSBmcm9tICcuLi9rZXkva2V5LWdyYXBoLnNlcnZpY2UnO1xuaW1wb3J0IHsgS2V5U2VydmljZSB9IGZyb20gJy4uL2tleS9rZXkuc2VydmljZSc7XG5pbXBvcnQgeyBQYXNzSWRwUGFyYW1zIH0gZnJvbSAnLi4va2V5L2tleS50eXBlcyc7XG5pbXBvcnQgeyBLY0NvbmZpZywgS0NfQ09ORklHIH0gZnJvbSAnLi4vbGlmZS1yZWFkeS5jb25maWcnO1xuaW1wb3J0IHsgUGFzc3dvcmRTZXJ2aWNlIH0gZnJvbSAnLi4vcGFzc3dvcmQvcGFzc3dvcmQuc2VydmljZSc7XG5pbXBvcnQgeyBQZXJzaXN0U2VydmljZSB9IGZyb20gJy4uL3BlcnNpc3QvcGVyc2lzdC5zZXJ2aWNlJztcbmltcG9ydCB7IFByb2ZpbGVTZXJ2aWNlIH0gZnJvbSAnLi4vcHJvZmlsZS9wcm9maWxlLnNlcnZpY2UnO1xuaW1wb3J0IHsgRmVhdHVyZXMsIFBhc3N3b3JkQ2hhbmdlU3RhdHVzIH0gZnJvbSAnLi4vcHJvZmlsZS9wcm9maWxlLnR5cGVzJztcbmltcG9ydCB7XG4gIFRQX1BBU1NXT1JEX1JFU0VUX0NMSUVOVF9OT05DRV9MRU5HVEgsXG4gIFRQX1BBU1NXT1JEX1JFU0VUX1VTRVJOQU1FX1NVRkZJWCxcbn0gZnJvbSAnLi4vdHAtcGFzc3dvcmQtcmVzZXQvdHAtcGFzc3dvcmQtcmVzZXQuY29uc3RhbnRzJztcbmltcG9ydCB7IFRwUGFzc3dvcmRSZXNldEFzc2VtYmx5Q29udHJvbGxlciB9IGZyb20gJy4uL3RwLXBhc3N3b3JkLXJlc2V0L3RwLXBhc3N3b3JkLXJlc2V0LmNvbnRyb2xsZXInO1xuaW1wb3J0IHtcbiAgQ29tcGxldGVUcFBhc3N3b3JkUmVzZXRSZXF1ZXN0TXV0YXRpb24sXG4gIENyZWF0ZVRwQXNzZW1ibHlLZXlDaGFsbGVuZ2VNdXRhdGlvbixcbiAgUHJlQ29tcGxldGVUcFBhc3N3b3JkUmVzZXRSZXF1ZXN0TXV0YXRpb24sXG59IGZyb20gJy4uL3RwLXBhc3N3b3JkLXJlc2V0L3RwLXBhc3N3b3JkLXJlc2V0LmdxbCc7XG5pbXBvcnQgeyBUcFBhc3N3b3JkUmVzZXRVc2VyUXVlcnkgfSBmcm9tICcuLi90cC1wYXNzd29yZC1yZXNldC90cC1wYXNzd29yZC1yZXNldC5wcml2YXRlLmdxbCc7XG5pbXBvcnQge1xuICBLY0JhZFJlcXVlc3RFeGNlcHRpb24sXG4gIEtjQmFkU3RhdGVFeGNlcHRpb24sXG4gIEtjQ29uY3VycmVudEFjY2Vzc0V4Y2VwdGlvbixcbiAgS2NJbnRlcm5hbEVycm9yRXhjZXB0aW9uLFxufSBmcm9tICcuLi9fY29tbW9uL2V4Y2VwdGlvbnMnO1xuaW1wb3J0IHsgZ2V0QWNjZXNzSnd0VG9rZW4gfSBmcm9tICcuLi9fY29tbW9uL3V0aWxzJztcbmltcG9ydCB7IFNldFNlc3Npb25FbmNyeXB0aW9uS2V5TXV0YXRpb24gfSBmcm9tICcuL2F1dGguZ3FsJztcbmltcG9ydCB7XG4gIENvZ25pdG9DaGFsbGVuZ2VVc2VyLFxuICBDdXJyZW50VXNlcixcbiAgTG9naW5SZXN1bHQsXG4gIFJlY292ZXJ5U3RhdHVzLFxuICBUcFBhc3N3b3JkUmVzZXRVc2VyLFxufSBmcm9tICcuL2F1dGgudHlwZXMnO1xuXG5leHBvcnQgY29uc3QgaW5pdGlhbGlzZUF1dGggPSAoYXV0aFNlcnZpY2U6IExpZmVSZWFkeUF1dGhTZXJ2aWNlKSA9PiB7XG4gIHJldHVybiAoKSA9PiBhdXRoU2VydmljZS5pbml0aWFsaXNlKCk7XG59O1xuXG5leHBvcnQgaW50ZXJmYWNlIExvZ2luT3B0aW9ucyB7XG4gIHRwUGFzc3dvcmRSZXNldEF1dG9Db21wbGV0ZT86IGJvb2xlYW47XG59XG5cbmV4cG9ydCB0eXBlIExvZ291dExpc3RlbmVyID0gKCkgPT4gdm9pZCB8IFByb21pc2U8dm9pZD47XG5cbkBJbmplY3RhYmxlKHtcbiAgcHJvdmlkZWRJbjogJ3Jvb3QnLFxufSlcbmV4cG9ydCBjbGFzcyBMaWZlUmVhZHlBdXRoU2VydmljZSB7XG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tZXhwbGljaXQtYW55XG4gIHByaXZhdGUgaHViU3ViamVjdDogUmVwbGF5U3ViamVjdDxhbnk+ID0gbmV3IFJlcGxheVN1YmplY3Q8YW55PigxKTtcbiAgcHJpdmF0ZSBjdXJyZW50VXNlcjogQ3VycmVudFVzZXI7XG4gIHByaXZhdGUgY3VycmVudFJlc2V0VXNlcjogVHBQYXNzd29yZFJlc2V0VXNlcjtcbiAgLy8gQ291bGQgdXNlIHJ4anMgb2JzZXJ2YWJsZXMgaGVyZS4gQnV0IHRyeWluZyB0byBoYXZlIGtjLWNsaWVudCB1c2UgYXMgbGl0dGxlIGFuZ3VsYXJcbiAgLy8gZmVhdHVyZXMgYXMgcG9zc2libGUuIFJ4anMgaXMgbm90IHVzZWQgYW55d2hlcmUgZWxzZSBpbiBrYy1jbGllbnQuXG4gIHByaXZhdGUgbG9nb3V0TGlzdGVuZXJzID0gbmV3IFNldDxMb2dvdXRMaXN0ZW5lcj4oKTtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBASW5qZWN0KEtDX0NPTkZJRykgcHJpdmF0ZSBjb25maWc6IEtjQ29uZmlnLFxuICAgIHByaXZhdGUgYXV0aDogQXV0aENsYXNzLFxuICAgIHByaXZhdGUga2V5RmFjdG9yeTogS2V5RmFjdG9yeVNlcnZpY2UsXG4gICAgcHJpdmF0ZSBrZXlTZXJ2aWNlOiBLZXlTZXJ2aWNlLFxuICAgIHByaXZhdGUgcHJvZmlsZVNlcnZpY2U6IFByb2ZpbGVTZXJ2aWNlLFxuICAgIHByaXZhdGUga2V5R3JhcGhTZXJ2aWNlOiBLZXlHcmFwaFNlcnZpY2UsXG4gICAgcHJpdmF0ZSBwYXNzd29yZFNlcnZpY2U6IFBhc3N3b3JkU2VydmljZSxcbiAgICBwcml2YXRlIGlkbGVTZXJ2aWNlOiBJZGxlU2VydmljZSxcbiAgICBwcml2YXRlIGxyR3JhcGhRTDogTHJHcmFwaFFMU2VydmljZSxcbiAgICBwcml2YXRlIHRwUGFzc3dvcmRSZXNldFByb2Nlc3NvclNlcnZpY2U6IFRwUGFzc3dvcmRSZXNldFByb2Nlc3NvclNlcnZpY2UsXG4gICAgcHJpdmF0ZSBwZXJzaXN0U2VydmljZTogUGVyc2lzdFNlcnZpY2UsXG4gICAgcHJpdmF0ZSBlbmNyeXB0aW9uU2VydmljZTogRW5jcnlwdGlvblNlcnZpY2UsXG4gICAgcHJpdmF0ZSBhc3NlbWJseUNvbnRyb2xsZXI6IFRwUGFzc3dvcmRSZXNldEFzc2VtYmx5Q29udHJvbGxlcixcbiAgICBwcml2YXRlIGh0dHA6IEh0dHBDbGllbnRcbiAgKSB7XG4gICAgaWYgKCFpc0Rldk1vZGUoKSkge1xuICAgICAgaWYgKHRoaXMuY29uZmlnLmRlYnVnICE9IG51bGwpIHtcbiAgICAgICAgdGhyb3cgbmV3IEtjQmFkUmVxdWVzdEV4Y2VwdGlvbihcbiAgICAgICAgICAnSW4gcHJvZHVjdGlvbiBtb2RlLCBcImNvbmZpZy5kZWJ1Z1wiIG11c3QgYmUgc2V0IHRvIG51bGwnXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgYXN5bmMgaW5pdGlhbGlzZSgpIHtcbiAgICBIdWIubGlzdGVuKCdhdXRoJywgKGRhdGEpID0+IHRoaXMuaHViU3ViamVjdC5uZXh0KGRhdGEucGF5bG9hZCkpO1xuICB9XG5cbiAgcHVibGljIGRlYnVnTG9naW4odXNlcm5hbWU6IHN0cmluZywgcGFzc3dvcmQ6IENyeXB0b0tleSkge1xuICAgIC8vIFRoaXMgd2lsbCBmYWlsIGlmIGRlYnVnIGlzIG51bGwuIEJ1dCB3aGVuIGRlYnVnIGlzIG51bGwsIHRoaXMgZnVuY3Rpb25cbiAgICAvLyBzaG91bGQgbm90IGJlIGNhbGxlZC5cbiAgICB0aGlzLmNvbmZpZy5kZWJ1Zy51c2VybmFtZSA9IHVzZXJuYW1lO1xuXG4gICAgcmV0dXJuIHRoaXMuZGVidWdMb2FkVXNlcihwYXNzd29yZCk7XG4gIH1cblxuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAvKipcbiAgICogTG9naW4gdXNpbmcgdGhlIHNlcnZlciBzaWRlIHNlc3Npb24gbWV0aG9kLlxuICAgKi9cbiAgcHJpdmF0ZSBkZWJ1Z0xvZ2luVXNpbmdTZXNzaW9uKHVzZXJuYW1lOiBzdHJpbmcpIHtcbiAgICByZXR1cm4gdGhpcy5odHRwXG4gICAgICAuZ2V0KFxuICAgICAgICB0aGlzLmNvbmZpZy5hcGlVcmwgK1xuICAgICAgICAgICdkZWJ1Z19vbmx5L3VzZXJzL2xvZ2luLz91c2VybmFtZT0nICtcbiAgICAgICAgICBlbmNvZGVVUklDb21wb25lbnQodXNlcm5hbWUpLFxuICAgICAgICB7XG4gICAgICAgICAgLy8gTm9uLW9idmlvdXMgYWxlcnQ6IGlmIHlvdSB3YW50IHRoZSBjb29raWVzIHRvIGJlIHNldCwgeW91IG11c3QgdXNlIHRoZVxuICAgICAgICAgIC8vIFwid2l0aENyZWRlbnRpYWxzXCIgaGVhZGVyLiBJIHdvdWxkIGhhdmUgdGhvdWdodCB0aGUgd2l0aENyZWRlbnRpYWxzIGhlYWRlclxuICAgICAgICAgIC8vIGlzIG9ubHkgdXNlZCB0byBzZW5kIHRoZSBjb29raWVzIHdpdGggdGhlIHJlcXVlc3RzLiBCdXQsIGlmIHlvdSBkb24ndCBpbmNsdWRlXG4gICAgICAgICAgLy8gdGhlIFwid2l0aENyZWRlbnRpYWxzXCIgaGVhZGVyLCB0aGUgY29va2llcyBpbiB0aGUgcmVzcG9uc2UgRE9FUyBOT1QgZ2V0IHNldCFcbiAgICAgICAgICAvL1xuICAgICAgICAgIC8vIHJlZjogaHR0cHM6Ly9naXRodWIuY29tL2dpdGh1Yi9mZXRjaC9pc3N1ZXMvMzg2I2lzc3VlY29tbWVudC0yNDMyMjkzODhcbiAgICAgICAgICB3aXRoQ3JlZGVudGlhbHM6IHRydWUsXG4gICAgICAgIH1cbiAgICAgIClcbiAgICAgIC50b1Byb21pc2UoKTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgZGVidWdMb2FkVXNlcihwYXNzd29yZDogQ3J5cHRvS2V5KTogUHJvbWlzZTxDdXJyZW50VXNlcj4ge1xuICAgIGNvbnN0IHsgY3VycmVudFVzZXIsIGNvbnRhY3RDYXJkLCB1c2VyUGxhbnMgfSA9XG4gICAgICBhd2FpdCB0aGlzLnByb2ZpbGVTZXJ2aWNlLmdldEN1cnJlbnRVc2VyKCk7XG5cbiAgICAvLyBEZWJ1ZyBtb2RlIGNhbiBub3QgZGVhbCB3aXRoIHNlc3Npb24gZW5jcnlwdGlvbiBrZXkgeWV0LlxuICAgIC8vIE5PIFNFU1NJT04gRU5DUllQVElPTiBLRVkuXG5cbiAgICBjb25zdCBwYXNzS2V5ID0gKFxuICAgICAgYXdhaXQgdGhpcy5rZXlGYWN0b3J5LmRlcml2ZVBhc3NLZXkoe1xuICAgICAgICBwYXNzd29yZCxcbiAgICAgICAgLi4uY3VycmVudFVzZXIuY3VycmVudFVzZXJLZXkucGFzc0tleS5wYXNzS2V5UGFyYW1zLFxuICAgICAgfSlcbiAgICApLmp3aztcblxuICAgIGNvbnN0IG1hc3RlcktleSA9IGF3YWl0IHRoaXMua2V5R3JhcGhTZXJ2aWNlLnVud3JhcFdpdGhQYXNzS2V5KFxuICAgICAgY3VycmVudFVzZXIuY3VycmVudFVzZXJLZXkucGFzc0tleS5pZCxcbiAgICAgIHBhc3NLZXksXG4gICAgICBjdXJyZW50VXNlci5jdXJyZW50VXNlcktleS5tYXN0ZXJLZXkuaWRcbiAgICApO1xuXG4gICAgYXdhaXQgdGhpcy5pZGxlU2VydmljZS5wZXJzaXN0TWFzdGVyS2V5KG1hc3RlcktleSk7XG5cbiAgICBhd2FpdCB0aGlzLmtleUdyYXBoU2VydmljZS5wb3B1bGF0ZUtleXMoY3VycmVudFVzZXIuY3VycmVudFVzZXJLZXkpO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIGlkOiBjdXJyZW50VXNlci5pZCxcbiAgICAgIHN1YjogJ0RFQlVHX01PREUnLFxuICAgICAgdXNlcm5hbWU6IGN1cnJlbnRVc2VyLnVzZXJuYW1lLFxuICAgICAgY3VycmVudFVzZXJLZXk6IGN1cnJlbnRVc2VyLmN1cnJlbnRVc2VyS2V5LFxuICAgICAgZW1haWw6ICdERUJVR19NT0RFJyxcbiAgICAgIGVtYWlsVmVyaWZpZWQ6IGZhbHNlLFxuICAgICAgcGhvbmU6ICdERUJVR19NT0RFJyxcbiAgICAgIHBob25lVmVyaWZpZWQ6IGZhbHNlLFxuICAgICAgY29udGFjdENhcmQ6IHtcbiAgICAgICAgLi4uKGF3YWl0IHRoaXMucHJvZmlsZVNlcnZpY2UuZGVjcnlwdENvbnRhY3RDYXJkKGNvbnRhY3RDYXJkKSksXG4gICAgICB9LFxuICAgICAgdXNlckRlbGV0ZTogY3VycmVudFVzZXIudXNlckRlbGV0ZSxcbiAgICAgIHVzZXJQbGFucyxcbiAgICAgIGhhc1RQVmF1bHRBY2Nlc3M6IHRoaXMubWFwVFBWYXVsdEFjY2VzcyhjdXJyZW50VXNlci5mZWF0dXJlcyksXG4gICAgICBmZWF0dXJlczogY3VycmVudFVzZXIuZmVhdHVyZXMsXG4gICAgICBzZXNzaW9uRW5jcnlwdGlvbktleTogY3VycmVudFVzZXIuc2Vzc2lvbkVuY3J5cHRpb25LZXksXG4gICAgICBkYXRlSm9pbmVkOiBjdXJyZW50VXNlci5kYXRlSm9pbmVkLFxuICAgIH07XG4gIH1cblxuICBhc3luYyBnZXRBY2Nlc3NKd3RUb2tlbigpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIHJldHVybiBnZXRBY2Nlc3NKd3RUb2tlbih0aGlzLmF1dGgpO1xuICB9XG5cbiAgaW1wb3J0UGFzc3dvcmQocGxhaW5QYXNzd29yZDogc3RyaW5nKTogUHJvbWlzZTxDcnlwdG9LZXk+IHtcbiAgICByZXR1cm4gdGhpcy5rZXlGYWN0b3J5LmltcG9ydFBhc3N3b3JkKHBsYWluUGFzc3dvcmQpO1xuICB9XG5cbiAgYWRkTG9nb3V0TGlzdGVuZXIoY2FsbGJhY2s6IExvZ291dExpc3RlbmVyKSB7XG4gICAgdGhpcy5sb2dvdXRMaXN0ZW5lcnMuYWRkKGNhbGxiYWNrKTtcbiAgfVxuXG4gIHJlbW92ZUxvZ291dExpc3RlbmVyKGNhbGxiYWNrOiBMb2dvdXRMaXN0ZW5lcikge1xuICAgIHRoaXMubG9nb3V0TGlzdGVuZXJzLmRlbGV0ZShjYWxsYmFjayk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGxvZ2luSWRwSW1wbChcbiAgICBlbWFpbE9yUGhvbmU6IHN0cmluZyxcbiAgICBwYXNzd29yZDogQ3J5cHRvS2V5LFxuICAgIHBhc3NJZHBQYXJhbXM6IFBhc3NJZHBQYXJhbXMsXG4gICAgcmVjb3ZlcnlTdGF0dXM6IFJlY292ZXJ5U3RhdHVzXG4gICk6IFByb21pc2U8Q29nbml0b0NoYWxsZW5nZVVzZXI+IHtcbiAgICBjb25zdCBwYXNzSWRwUmVzdWx0ID0gYXdhaXQgdGhpcy5rZXlGYWN0b3J5LmRlcml2ZVBhc3NJZHAoe1xuICAgICAgcGFzc3dvcmQsXG4gICAgICAuLi5wYXNzSWRwUGFyYW1zLFxuICAgIH0pO1xuICAgIC8vIFVzZSB0aGUgZGVyaXZlZCBwYXNzd29yZCB0byBzaWduaW4gd2l0aCBjb2duaXRvXG4gICAgY29uc3QgdXNlciA9IGF3YWl0IHRoaXMuYXV0aC5zaWduSW4oXG4gICAgICBlbWFpbE9yUGhvbmUsXG4gICAgICB0aGlzLnBhc3N3b3JkU2VydmljZS5nZXRQYXNzSWRwU3RyaW5nKHBhc3NJZHBSZXN1bHQuandrKVxuICAgICk7XG5cbiAgICB1c2VyLnJlY292ZXJ5U3RhdHVzID0gcmVjb3ZlcnlTdGF0dXM7XG5cbiAgICByZXR1cm4gdXNlcjtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgbG9naW5JZHAoXG4gICAgZW1haWxPclBob25lOiBzdHJpbmcsXG4gICAgcGFzc3dvcmQ6IENyeXB0b0tleVxuICApOiBQcm9taXNlPENvZ25pdG9DaGFsbGVuZ2VVc2VyPiB7XG4gICAgLy8gRG93bmxvYWQgdGhlIHNhbHQgbmVlZGVkIHRvIGRlcml2ZSB0aGUgUGFzc0lkcFxuICAgIGNvbnN0IHBhc3NJZHBBcGlSZXN1bHQgPSBhd2FpdCB0aGlzLnByb2ZpbGVTZXJ2aWNlLmdldFBhc3NJZHBQYXJhbXMoXG4gICAgICBlbWFpbE9yUGhvbmVcbiAgICApO1xuXG4gICAgaWYgKFxuICAgICAgcGFzc0lkcEFwaVJlc3VsdC5wYXNzd29yZENoYW5nZVN0YXR1cyA9PT0gUGFzc3dvcmRDaGFuZ2VTdGF0dXMuSW5Qcm9ncmVzc1xuICAgICkge1xuICAgICAgdGhyb3cgbmV3IEtjQ29uY3VycmVudEFjY2Vzc0V4Y2VwdGlvbignQSBwYXNzd29yZCBjaGFuZ2UgaXMgaW4gcHJvZ3Jlc3MnKTtcbiAgICB9XG5cbiAgICBpZiAoXG4gICAgICBwYXNzSWRwQXBpUmVzdWx0LnBhc3N3b3JkQ2hhbmdlU3RhdHVzID09PSBQYXNzd29yZENoYW5nZVN0YXR1cy5SZWNvdmVyeVxuICAgICkge1xuICAgICAgY29uc29sZS5sb2coJ0luIHJlY292ZXJ5IG1vZGUuJyk7XG4gICAgICAvLyBMZXQncyBzYXkgd2UgZG9uJ3Qga25vdyBpZiB0aGUgcGFzc3dvcmQgaXMgdGhlIG5ldyBvbmUgb3IgdGhlIG9sZCBvbmUuIFdlIGp1c3QgaGF2ZSB0byB0cnkgYm90aC5cbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHVzZXIgPSBhd2FpdCB0aGlzLmxvZ2luSWRwSW1wbChcbiAgICAgICAgICBlbWFpbE9yUGhvbmUsXG4gICAgICAgICAgcGFzc3dvcmQsXG4gICAgICAgICAgcGFzc0lkcEFwaVJlc3VsdC5uZXdQYXNzSWRwUGFyYW1zLFxuICAgICAgICAgIFJlY292ZXJ5U3RhdHVzLk5FV19QQVNTV09SRFxuICAgICAgICApO1xuICAgICAgICAvLyBOZXcgcGFzc3dvcmQgd29ya2VkLiBMZXQncyBzZXQgdG8gdGhlIGN1cnJlbnQgcGFzc3dvcmRcblxuICAgICAgICAvLyAtLVBvdGVudGlhbCBGYWlsdXJlIFBvaW50IDEtLVxuICAgICAgICAvLyBpZiBjaGFuZ2VQYXNzd29yZENvbXBsZXRlKCkgZG9lc24ndCBnZXQgY2FsbGVkLCB0aGVuIGl0IHNob3VsZCByZW1haW5cblxuICAgICAgICBjb25zb2xlLmxvZygnTmV3IHBhc3N3b3JkIHdvcmtzIScpO1xuXG4gICAgICAgIHJldHVybiB1c2VyO1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgLy8gSnVzdCBidWJibGUgdXAgYW55IG90aGVyIHR5cGUgb2YgZXJyb3IuXG4gICAgICAgIGlmIChlcnJvci5jb2RlICE9PSAnTm90QXV0aG9yaXplZEV4Y2VwdGlvbicpIHtcbiAgICAgICAgICB0aHJvdyBlcnJvcjtcbiAgICAgICAgfVxuICAgICAgICAvLyBwYXNzLCB0cnkgYWdhaW4gYXNzdW1pbmcgaXQncyB0aGUgb2xkIHBhc3N3b3JkXG4gICAgICB9XG5cbiAgICAgIC8vIE5vdyBhc3N1bWUgaXQncyB0aGUgcHJldmlvdXMgcGFzc3dvcmQuIEFueSBleGNlcHRpb24gaXMgYWxsb3dlZCB0byBidWJibGUgdXAuXG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCB1c2VyID0gYXdhaXQgdGhpcy5sb2dpbklkcEltcGwoXG4gICAgICAgICAgZW1haWxPclBob25lLFxuICAgICAgICAgIHBhc3N3b3JkLFxuICAgICAgICAgIHBhc3NJZHBBcGlSZXN1bHQuY3VycmVudFBhc3NJZHBQYXJhbXMsXG4gICAgICAgICAgUmVjb3ZlcnlTdGF0dXMuT0xEX1BBU1NXT1JEXG4gICAgICAgICk7XG4gICAgICAgIC8vIE9sZCBwYXNzd29yZCB3b3JrZWQuXG4gICAgICAgIGNvbnNvbGUubG9nKCdPbGQgcGFzc3dvcmQgd29ya3MhJyk7XG5cbiAgICAgICAgcmV0dXJuIHVzZXI7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAvLyBKdXN0IGJ1YmJsZSB1cCBhbnkgb3RoZXIgdHlwZSBvZiBlcnJvci5cbiAgICAgICAgdGhyb3cgZXJyb3IuY29kZSA9PT0gJ05vdEF1dGhvcml6ZWRFeGNlcHRpb24nXG4gICAgICAgICAgPyBuZXcgS2NCYWRSZXF1ZXN0RXhjZXB0aW9uKFxuICAgICAgICAgICAgICAnVGhlIHBhc3N3b3JkIGNoYW5nZSByZXF1ZXN0IHdhcyBpbnRlcnJ1cHRlZCwgcGxlYXNlIHRyeSB0byBsb2dpbiB3aXRoIGJvdGggeW91ciBuZXcgYW5kIG9sZCBwYXNzd29yZCdcbiAgICAgICAgICAgIClcbiAgICAgICAgICA6IGVycm9yO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIFRyeSBhZ2FpbnN0IGFzIHRoZSBUUCBwYXNzd29yZCByZXNldCBhY2NvdW50XG4gICAgaWYgKHBhc3NJZHBBcGlSZXN1bHQudHBQYXNzd29yZFJlc2V0KSB7XG4gICAgICB0cnkge1xuICAgICAgICAvLyBUUCBwYXNzd29yZCByZXNldCBpcyBpbiBwcm9jZXNzLiBXZSBuZWVkIHRvIHRyeSB0aGUgcGFzc3dvcmQgYWdhaW5zdCBib3RoXG4gICAgICAgIC8vIG9yaWdpbmFsIGFjY291bnQgYW5kIHRoZSBuZXcgcmVzZXQgYWNjb3VudC5cbiAgICAgICAgY29uc3QgcmVzZXQgPSBwYXNzSWRwQXBpUmVzdWx0LnRwUGFzc3dvcmRSZXNldDtcbiAgICAgICAgY29uc3QgcmV0ID0gYXdhaXQgdGhpcy5sb2dpbklkcEltcGwoXG4gICAgICAgICAgcmVzZXQucmVzZXRVc2VybmFtZSxcbiAgICAgICAgICBwYXNzd29yZCxcbiAgICAgICAgICByZXNldC5wYXNzSWRwUGFyYW1zLFxuICAgICAgICAgIFJlY292ZXJ5U3RhdHVzLk5PTkVcbiAgICAgICAgKTtcbiAgICAgICAgcmV0LmlzVHBQYXNzd29yZFJlc2V0VXNlciA9IHRydWU7XG5cbiAgICAgICAgcmV0dXJuIHJldDtcbiAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAvLyBjb250aW51ZSwgdHJ5IGFnYWluIGFzIHJlZ3VsYXIgdXNlci5cbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBMb2dpbiBhcyByZWd1bGFyIHVzZXJcbiAgICByZXR1cm4gYXdhaXQgdGhpcy5sb2dpbklkcEltcGwoXG4gICAgICBlbWFpbE9yUGhvbmUsXG4gICAgICBwYXNzd29yZCxcbiAgICAgIHBhc3NJZHBBcGlSZXN1bHQuY3VycmVudFBhc3NJZHBQYXJhbXMsXG4gICAgICBSZWNvdmVyeVN0YXR1cy5OT05FXG4gICAgKTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgaGFuZGxlU2Vzc2lvbkVuY3J5cHRpb25LZXkoKSB7XG4gICAgaWYgKHRoaXMuY29uZmlnLmRpc2FibGVTZXNzaW9uRW5jcnlwdGlvbktleSkge1xuICAgICAgaWYgKCFpc0Rldk1vZGUoKSkge1xuICAgICAgICBjb25zdCBtc2cgPVxuICAgICAgICAgICdZb3Ugc2hvdWxkIG5vdCBzZXQgZGlzYWJsZVNlc3Npb25FbmNyeXB0aW9uS2V5PVRydWUgaW4gbW9kZSBwcm9kLiBJdCBkZWZhdWx0cyB0byBmYWxzZS4nO1xuICAgICAgICBjb25zb2xlLmVycm9yKG1zZyk7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihtc2cpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc29sZS53YXJuKFxuICAgICAgICAgICdZb3UgaGF2ZSBzZXQgZGlzYWJsZVNlc3Npb25FbmNyeXB0aW9uS2V5PVRydWUuIE1ha2Ugc3VyZSBub3QgdG8gZG8gdGhpcyBpbiBwcm9kIG1vZGUuJ1xuICAgICAgICApO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICAvLyBTZXQgdGhlIHNlc3Npb24ga2V5IHRvIGEgbmV3IGVuY3J5cHRpb24ga2V5IGZvciB0aGlzIHNlc3Npb25cbiAgICAgIGNvbnN0IHNlc3Npb25FbmNyeXB0aW9uS2V5ID0gYXdhaXQgdGhpcy5rZXlGYWN0b3J5LmNyZWF0ZUtleSgpO1xuICAgICAgYXdhaXQgdGhpcy5sckdyYXBoUUwubHJNdXRhdGUoXG4gICAgICAgIG5ldyBMck11dGF0aW9uKHtcbiAgICAgICAgICBtdXRhdGlvbjogU2V0U2Vzc2lvbkVuY3J5cHRpb25LZXlNdXRhdGlvbixcbiAgICAgICAgICB2YXJpYWJsZXM6IHtcbiAgICAgICAgICAgIGlucHV0OiB7XG4gICAgICAgICAgICAgIHNlc3Npb25FbmNyeXB0aW9uS2V5OiBKU09OLnN0cmluZ2lmeShcbiAgICAgICAgICAgICAgICBzZXNzaW9uRW5jcnlwdGlvbktleS50b0pTT04odHJ1ZSlcbiAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfSxcbiAgICAgICAgfSksXG4gICAgICAgIHtcbiAgICAgICAgICBpbmNsdWRlS2V5R3JhcGg6IGZhbHNlLFxuICAgICAgICB9XG4gICAgICApO1xuXG4gICAgICB0aGlzLnBlcnNpc3RTZXJ2aWNlLnNldFNlcnZlclNlc3Npb25FbmNyeXB0aW9uS2V5KHNlc3Npb25FbmNyeXB0aW9uS2V5KTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGhhbmRsZVBvc3RBdXRoKGNvZ25pdG9Vc2VyOiBDb2duaXRvQ2hhbGxlbmdlVXNlcikge1xuICAgIGF3YWl0IHRoaXMuaGFuZGxlUGFzc3dvcmRSZWNvdmVyeShjb2duaXRvVXNlcik7XG4gICAgYXdhaXQgdGhpcy5oYW5kbGVTZXNzaW9uRW5jcnlwdGlvbktleSgpO1xuICB9XG5cbiAgcHVibGljIGFzeW5jIGxvZ2luKFxuICAgIGVtYWlsT3JQaG9uZTogc3RyaW5nLFxuICAgIHBhc3N3b3JkOiBDcnlwdG9LZXksXG4gICAgeyB0cFBhc3N3b3JkUmVzZXRBdXRvQ29tcGxldGUgPSB0cnVlIH06IExvZ2luT3B0aW9ucyA9IHt9XG4gICkge1xuICAgIGxldCBsb2dpblJlc3VsdCA9IGF3YWl0IHRoaXMubG9naW5JbXBsKGVtYWlsT3JQaG9uZSwgcGFzc3dvcmQpO1xuXG4gICAgaWYgKFxuICAgICAgdHBQYXNzd29yZFJlc2V0QXV0b0NvbXBsZXRlICYmXG4gICAgICBsb2dpblJlc3VsdC5yZXNldFVzZXI/LnN0YXRlID09PSBUcENsYWltU3RhdGUuQVBQUk9WRURcbiAgICApIHtcbiAgICAgIGF3YWl0IHRoaXMuY29tcGxldGVSZXF1ZXN0KHBhc3N3b3JkKTtcbiAgICAgIGxvZ2luUmVzdWx0ID0gYXdhaXQgdGhpcy5sb2dpbkltcGwoZW1haWxPclBob25lLCBwYXNzd29yZCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGxvZ2luUmVzdWx0O1xuICB9XG5cbiAgcHVibGljIGFzeW5jIGxvZ2luSW1wbChcbiAgICBlbWFpbE9yUGhvbmU6IHN0cmluZyxcbiAgICBwYXNzd29yZDogQ3J5cHRvS2V5XG4gICk6IFByb21pc2U8TG9naW5SZXN1bHQ+IHtcbiAgICBhd2FpdCB0aGlzLmxvZ291dCgpO1xuICAgIGNvbnN0IGNvZ25pdG9Vc2VyID0gYXdhaXQgdGhpcy5sb2dpbklkcChlbWFpbE9yUGhvbmUsIHBhc3N3b3JkKTtcblxuICAgIC8vIHRvZG86IE1lZXQgTUZBIGNoYWxsZW5nZXMuXG4gICAgaWYgKFsnU01TX01GQScsICdTT0ZUV0FSRV9UT0tFTl9NRkEnXS5pbmNsdWRlcyhjb2duaXRvVXNlci5jaGFsbGVuZ2VOYW1lKSkge1xuICAgICAgcmV0dXJuIHsgaGFzQ2hhbGxlbmdlOiB0cnVlLCBjaGFsbGVuZ2U6IGNvZ25pdG9Vc2VyIH07XG4gICAgfVxuXG4gICAgYXdhaXQgdGhpcy5oYW5kbGVQb3N0QXV0aChjb2duaXRvVXNlcik7XG5cbiAgICBpZiAoY29nbml0b1VzZXIuaXNUcFBhc3N3b3JkUmVzZXRVc2VyKSB7XG4gICAgICAvLyBBc3N1bWluZyB0aGVyZSBpcyBubyBNRkEgb24gdGhlIFRQIHJlc2V0IHVzZXIuXG4gICAgICBjb25zdCByZXNldFVzZXIgPSBhd2FpdCB0aGlzLmxvYWRSZXNldFVzZXIocGFzc3dvcmQpO1xuICAgICAgcmV0dXJuIHsgaGFzQ2hhbGxlbmdlOiBmYWxzZSwgcmVzZXRVc2VyIH07XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IHVzZXIgPSBhd2FpdCB0aGlzLmxvYWRVc2VyKGNvZ25pdG9Vc2VyLCBwYXNzd29yZCk7XG4gICAgICBhd2FpdCB0aGlzLmlkbGVTZXJ2aWNlLnN0YXJ0KCk7IC8vIFJ1biBpZGxlU2VydmljZSB3aGVuZXZlciB1c2VyIGlzIGxvZ2dlZCBpbi5cbiAgICAgIHJldHVybiB7IGhhc0NoYWxsZW5nZTogZmFsc2UsIHVzZXIgfTtcbiAgICB9XG4gIH1cblxuICAvLyBUT0RPIDxBWj4gV2UgbmVlZCB0byBoYW5kbGUgdGhlIGlzVHBQYXNzd29yZFJlc2V0VXNlcj1UcnVlIGNhc2UgaGVyZSBhZnRlciBNRkEgYXMgd2VsbC5cbiAgcHVibGljIGFzeW5jIHZlcmlmeUxvZ2luKFxuICAgIGNoYWxsZW5nZTogQ29nbml0b0NoYWxsZW5nZVVzZXIsXG4gICAgcGFzc3dvcmQ6IENyeXB0b0tleSxcbiAgICByZW1lbWJlck1lOiBib29sZWFuLFxuICAgIGNvZGU6IHN0cmluZ1xuICApOiBQcm9taXNlPEN1cnJlbnRVc2VyPiB7XG4gICAgYXdhaXQgdGhpcy5hdXRoLmNvbmZpcm1TaWduSW4oY2hhbGxlbmdlLCBjb2RlLCBjaGFsbGVuZ2UuY2hhbGxlbmdlTmFtZSk7XG5cbiAgICAvLyBUT0RPOiB0aGlzLmF1dGguY29uZmlybVNpZ25JbigpIGNvdWxkIHJldHVybiBhbm90aGVyIGNoYWxsZW5nZS5cblxuICAgIGNvbnN0IGNvZ25pdG9Vc2VyOiBDb2duaXRvVXNlciA9IGF3YWl0IHRoaXMuYXV0aC5jdXJyZW50QXV0aGVudGljYXRlZFVzZXIoKTtcblxuICAgIGF3YWl0IHRoaXMuaGFuZGxlUG9zdEF1dGgoY2hhbGxlbmdlKTtcblxuICAgIGNvbnN0IHVzZXIgPSBhd2FpdCB0aGlzLmxvYWRVc2VyKGNvZ25pdG9Vc2VyLCBwYXNzd29yZCk7XG5cbiAgICBpZiAocmVtZW1iZXJNZSkge1xuICAgICAgY29nbml0b1VzZXIuc2V0RGV2aWNlU3RhdHVzUmVtZW1iZXJlZCh7XG4gICAgICAgIG9uU3VjY2VzczogKCkgPT4ge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfSxcbiAgICAgICAgb25GYWlsdXJlOiAoZSkgPT4gY29uc29sZS5lcnJvcihlKSxcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIHJldHVybiB1c2VyO1xuICB9XG5cbiAgYXN5bmMgaGFuZGxlUGFzc3dvcmRSZWNvdmVyeSh1c2VyOiBDb2duaXRvQ2hhbGxlbmdlVXNlcikge1xuICAgIGlmICh1c2VyLnJlY292ZXJ5U3RhdHVzICE9PSBSZWNvdmVyeVN0YXR1cy5OT05FKSB7XG4gICAgICBhd2FpdCB0aGlzLnBhc3N3b3JkU2VydmljZS5jaGFuZ2VQYXNzd29yZENvbXBsZXRlKHtcbiAgICAgICAgdXNlTmV3UGFzc3dvcmQ6IHVzZXIucmVjb3ZlcnlTdGF0dXMgPT09IFJlY292ZXJ5U3RhdHVzLk5FV19QQVNTV09SRCxcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIGFzeW5jIGdldFVzZXJPclJlc2V0VXNlcihcbiAgICByZWxvYWQgPSBmYWxzZVxuICApOiBQcm9taXNlPEN1cnJlbnRVc2VyIHwgVHBQYXNzd29yZFJlc2V0VXNlcj4ge1xuICAgIGNvbnN0IGNvZ25pdG9Vc2VyID0gYXdhaXQgdGhpcy5hdXRoLmN1cnJlbnRBdXRoZW50aWNhdGVkVXNlcigpO1xuXG4gICAgaWYgKGNvZ25pdG9Vc2VyLmdldFVzZXJuYW1lKCkuZW5kc1dpdGgoVFBfUEFTU1dPUkRfUkVTRVRfVVNFUk5BTUVfU1VGRklYKSkge1xuICAgICAgcmV0dXJuIHRoaXMuZ2V0UmVzZXRVc2VyKHJlbG9hZCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiB0aGlzLmdldFVzZXIocmVsb2FkKTtcbiAgICB9XG4gIH1cblxuICBhc3luYyBnZXRSZXNldFVzZXIocmVsb2FkID0gZmFsc2UpOiBQcm9taXNlPFRwUGFzc3dvcmRSZXNldFVzZXI+IHtcbiAgICBpZiAoIXJlbG9hZCAmJiB0aGlzLmN1cnJlbnRSZXNldFVzZXIpIHtcbiAgICAgIHJldHVybiB0aGlzLmN1cnJlbnRSZXNldFVzZXI7XG4gICAgfVxuXG4gICAgdGhpcy5jdXJyZW50UmVzZXRVc2VyID0gYXdhaXQgdGhpcy5sb2FkUmVzZXRVc2VyKCk7XG5cbiAgICBhd2FpdCB0aGlzLmlkbGVTZXJ2aWNlLnN0YXJ0KCk7IC8vIFJ1biBpZGxlU2VydmljZSB3aGVuZXZlciB1c2VyIGlzIGxvZ2dlZCBpbi5cblxuICAgIHJldHVybiB0aGlzLmN1cnJlbnRSZXNldFVzZXI7XG4gIH1cblxuICBhc3luYyBnZXRVc2VyKHJlbG9hZCA9IGZhbHNlKTogUHJvbWlzZTxDdXJyZW50VXNlcj4ge1xuICAgIGlmICghcmVsb2FkICYmIHRoaXMuY3VycmVudFVzZXIpIHtcbiAgICAgIHJldHVybiB0aGlzLmN1cnJlbnRVc2VyO1xuICAgIH1cbiAgICB0aGlzLmN1cnJlbnRVc2VyID0gYXdhaXQgdGhpcy5sb2FkVXNlcihcbiAgICAgIGF3YWl0IHRoaXMuYXV0aC5jdXJyZW50QXV0aGVudGljYXRlZFVzZXIoKVxuICAgICk7XG4gICAgY29uc29sZS5sb2coJ1N0YXJ0aW5nIGlkbGUgc2VydmljZS4nKTtcbiAgICBhd2FpdCB0aGlzLmlkbGVTZXJ2aWNlLnN0YXJ0KCk7IC8vIFJ1biBpZGxlU2VydmljZSB3aGVuZXZlciB1c2VyIGlzIGxvZ2dlZCBpbi5cbiAgICByZXR1cm4gdGhpcy5jdXJyZW50VXNlcjtcbiAgfVxuXG4gIHByaXZhdGUgbWFwVFBWYXVsdEFjY2VzcyhmZWF0dXJlcz86IEZlYXR1cmVzKTogYm9vbGVhbiB7XG4gICAgY29uc3QgdHBWYXVsdEZlYXR1cmUgPSBmZWF0dXJlcz8udHBWYXVsdDtcbiAgICByZXR1cm4gKFxuICAgICAgdHBWYXVsdEZlYXR1cmU/Lmxlbmd0aCA+IDAgJiZcbiAgICAgIHRwVmF1bHRGZWF0dXJlLnNvbWUoKGZlYXR1cmUpID0+IGZlYXR1cmUudG9VcHBlckNhc2UoKSA9PT0gJ0FDQ0VTUycpXG4gICAgKTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgbG9hZFVzZXIoXG4gICAgY29nbml0b1VzZXI6IENvZ25pdG9Vc2VyLFxuICAgIHBhc3N3b3JkPzogQ3J5cHRvS2V5XG4gICk6IFByb21pc2U8Q3VycmVudFVzZXI+IHtcbiAgICBjb25zdCB7IGN1cnJlbnRVc2VyLCBjb250YWN0Q2FyZCwgdXNlclBsYW5zIH0gPVxuICAgICAgYXdhaXQgdGhpcy5wcm9maWxlU2VydmljZS5nZXRDdXJyZW50VXNlcigpO1xuXG4gICAgaWYgKGN1cnJlbnRVc2VyLnNlc3Npb25FbmNyeXB0aW9uS2V5KSB7XG4gICAgICB0aGlzLnBlcnNpc3RTZXJ2aWNlLnNldFNlcnZlclNlc3Npb25FbmNyeXB0aW9uS2V5KFxuICAgICAgICBhd2FpdCBKV0suYXNLZXkoY3VycmVudFVzZXIuc2Vzc2lvbkVuY3J5cHRpb25LZXkpXG4gICAgICApO1xuICAgIH1cblxuICAgIGNvbnN0IHVzZXJBdHRyaWJ1dGVzID0gYXdhaXQgdGhpcy5hdXRoLnVzZXJBdHRyaWJ1dGVzKGNvZ25pdG9Vc2VyKTtcblxuICAgIGlmIChwYXNzd29yZCkge1xuICAgICAgY29uc3QgcGFzc0tleSA9IChcbiAgICAgICAgYXdhaXQgdGhpcy5rZXlGYWN0b3J5LmRlcml2ZVBhc3NLZXkoe1xuICAgICAgICAgIHBhc3N3b3JkLFxuICAgICAgICAgIC4uLmN1cnJlbnRVc2VyLmN1cnJlbnRVc2VyS2V5LnBhc3NLZXkucGFzc0tleVBhcmFtcyxcbiAgICAgICAgfSlcbiAgICAgICkuandrO1xuXG4gICAgICBhd2FpdCB0aGlzLmlkbGVTZXJ2aWNlLnBlcnNpc3RNYXN0ZXJLZXkoXG4gICAgICAgIGF3YWl0IHRoaXMua2V5R3JhcGhTZXJ2aWNlLnVud3JhcFdpdGhQYXNzS2V5KFxuICAgICAgICAgIGN1cnJlbnRVc2VyLmN1cnJlbnRVc2VyS2V5LnBhc3NLZXkuaWQsXG4gICAgICAgICAgcGFzc0tleSxcbiAgICAgICAgICBjdXJyZW50VXNlci5jdXJyZW50VXNlcktleS5tYXN0ZXJLZXkuaWRcbiAgICAgICAgKVxuICAgICAgKTtcbiAgICB9XG4gICAgYXdhaXQgdGhpcy5rZXlHcmFwaFNlcnZpY2UucG9wdWxhdGVLZXlzKGN1cnJlbnRVc2VyLmN1cnJlbnRVc2VyS2V5KTtcblxuICAgIHJldHVybiB7XG4gICAgICBpZDogY3VycmVudFVzZXIuaWQsXG4gICAgICBzdWI6IHRoaXMuZ2V0VXNlckF0dHJpYnV0ZSgnc3ViJywgdXNlckF0dHJpYnV0ZXMpLFxuICAgICAgdXNlcm5hbWU6IGN1cnJlbnRVc2VyLnVzZXJuYW1lLFxuICAgICAgY3VycmVudFVzZXJLZXk6IGN1cnJlbnRVc2VyLmN1cnJlbnRVc2VyS2V5LFxuICAgICAgZW1haWw6IHRoaXMuZ2V0VXNlckF0dHJpYnV0ZSgnZW1haWwnLCB1c2VyQXR0cmlidXRlcyksXG4gICAgICBlbWFpbFZlcmlmaWVkOlxuICAgICAgICB0aGlzLmdldFVzZXJBdHRyaWJ1dGUoJ2VtYWlsX3ZlcmlmaWVkJywgdXNlckF0dHJpYnV0ZXMpID09PSAndHJ1ZScsXG4gICAgICBwaG9uZTogdGhpcy5nZXRVc2VyQXR0cmlidXRlKCdwaG9uZV9udW1iZXInLCB1c2VyQXR0cmlidXRlcyksXG4gICAgICBwaG9uZVZlcmlmaWVkOlxuICAgICAgICB0aGlzLmdldFVzZXJBdHRyaWJ1dGUoJ3Bob25lX251bWJlcl92ZXJpZmllZCcsIHVzZXJBdHRyaWJ1dGVzKSA9PT1cbiAgICAgICAgJ3RydWUnLFxuICAgICAgY29udGFjdENhcmQ6IHtcbiAgICAgICAgLi4uKGF3YWl0IHRoaXMucHJvZmlsZVNlcnZpY2UuZGVjcnlwdENvbnRhY3RDYXJkKGNvbnRhY3RDYXJkKSksXG4gICAgICB9LFxuICAgICAgdXNlckRlbGV0ZTogY3VycmVudFVzZXIudXNlckRlbGV0ZSxcbiAgICAgIHVzZXJQbGFucyxcbiAgICAgIGhhc1RQVmF1bHRBY2Nlc3M6IHRoaXMubWFwVFBWYXVsdEFjY2VzcyhjdXJyZW50VXNlci5mZWF0dXJlcyksXG4gICAgICBmZWF0dXJlczogY3VycmVudFVzZXIuZmVhdHVyZXMsXG4gICAgICBzZXNzaW9uRW5jcnlwdGlvbktleTogY3VycmVudFVzZXIuc2Vzc2lvbkVuY3J5cHRpb25LZXksXG4gICAgICBkYXRlSm9pbmVkOiBjdXJyZW50VXNlci5kYXRlSm9pbmVkLFxuICAgIH07XG4gIH1cblxuICBwdWJsaWMgd2F0Y2hBdXRoKCkge1xuICAgIHJldHVybiB0aGlzLmh1YlN1YmplY3Q7XG4gIH1cblxuICBwdWJsaWMgYXN5bmMgbG9nb3V0KCk6IFByb21pc2U8dm9pZD4ge1xuICAgIC8vIE5vdGlmeSBhbGwgbGlzdGVuZXJzIHRvIGNsZWFuIHVwLlxuICAgIGF3YWl0IFByb21pc2UuYWxsKFsuLi50aGlzLmxvZ291dExpc3RlbmVyc10ubWFwKChjYWxsYmFjaykgPT4gY2FsbGJhY2soKSkpO1xuXG4gICAgdGhpcy5jdXJyZW50VXNlciA9IG51bGw7XG4gICAgdGhpcy5rZXlTZXJ2aWNlLnB1cmdlS2V5cygpO1xuICAgIHRoaXMua2V5R3JhcGhTZXJ2aWNlLnB1cmdlS2V5cygpO1xuXG4gICAgYXdhaXQgUHJvbWlzZS5hbGwoW3RoaXMuYXV0aC5zaWduT3V0KCksIHRoaXMucHJvZmlsZVNlcnZpY2Uuc2lnbk91dCgpXSk7XG5cbiAgICBpZiAodGhpcy5jb25maWcuZGVidWc/LnVzZXJuYW1lKSB7XG4gICAgICB0aGlzLmNvbmZpZy5kZWJ1Zy51c2VybmFtZSA9IG51bGw7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBnZXRVc2VyQXR0cmlidXRlKFxuICAgIGF0dHJpYnV0ZU5hbWU6IHN0cmluZyxcbiAgICB1c2VyQXR0cmlidXRlczogQ29nbml0b1VzZXJBdHRyaWJ1dGVbXVxuICApIHtcbiAgICBjb25zdCB1c2VyQXR0cmlidXRlID0gdXNlckF0dHJpYnV0ZXMuZmluZChcbiAgICAgICh4KSA9PiB4LmdldE5hbWUoKSA9PT0gYXR0cmlidXRlTmFtZVxuICAgICk7XG5cbiAgICByZXR1cm4gdXNlckF0dHJpYnV0ZSA/IHVzZXJBdHRyaWJ1dGUuZ2V0VmFsdWUoKSA6IG51bGw7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGxvYWRSZXNldFVzZXIoXG4gICAgcGFzc3dvcmQ/OiBDcnlwdG9LZXlcbiAgKTogUHJvbWlzZTxUcFBhc3N3b3JkUmVzZXRVc2VyPiB7XG4gICAgY29uc3QgeyB0cFBhc3N3b3JkUmVzZXRVc2VyOiByZXNldFVzZXIgfSA9IGF3YWl0IHRoaXMubHJHcmFwaFFMLnF1ZXJ5KHtcbiAgICAgIHF1ZXJ5OiBUcFBhc3N3b3JkUmVzZXRVc2VyUXVlcnksXG4gICAgfSk7XG5cbiAgICBpZiAocmVzZXRVc2VyLnNlc3Npb25FbmNyeXB0aW9uS2V5KSB7XG4gICAgICB0aGlzLnBlcnNpc3RTZXJ2aWNlLnNldFNlcnZlclNlc3Npb25FbmNyeXB0aW9uS2V5KFxuICAgICAgICBhd2FpdCBKV0suYXNLZXkocmVzZXRVc2VyLnNlc3Npb25FbmNyeXB0aW9uS2V5KVxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBVcGRhdGUgdGhlIGtleXNcbiAgICBpZiAocGFzc3dvcmQpIHtcbiAgICAgIGNvbnN0IHBhc3NLZXkgPSAoXG4gICAgICAgIGF3YWl0IHRoaXMua2V5RmFjdG9yeS5kZXJpdmVQYXNzS2V5KHtcbiAgICAgICAgICBwYXNzd29yZCxcbiAgICAgICAgICAuLi5yZXNldFVzZXIucGFzc0tleS5wYXNzS2V5UGFyYW1zLFxuICAgICAgICB9KVxuICAgICAgKS5qd2s7XG5cbiAgICAgIGF3YWl0IHRoaXMuaWRsZVNlcnZpY2UucGVyc2lzdE1hc3RlcktleShcbiAgICAgICAgYXdhaXQgdGhpcy5rZXlHcmFwaFNlcnZpY2UudW53cmFwV2l0aFBhc3NLZXkoXG4gICAgICAgICAgcmVzZXRVc2VyLnBhc3NLZXkuaWQsXG4gICAgICAgICAgcGFzc0tleSxcbiAgICAgICAgICByZXNldFVzZXIubWFzdGVyS2V5LmlkXG4gICAgICAgIClcbiAgICAgICk7XG4gICAgfVxuXG4gICAgdGhpcy5rZXlTZXJ2aWNlLnNldEtleXMoe1xuICAgICAgcGFzc0tleToge1xuICAgICAgICBpZDogcmVzZXRVc2VyLnBhc3NLZXkuaWQsXG4gICAgICB9LFxuICAgICAgbWFzdGVyS2V5OiB7XG4gICAgICAgIGlkOiByZXNldFVzZXIubWFzdGVyS2V5LmlkLFxuICAgICAgfSxcbiAgICB9KTtcblxuICAgIGNvbnN0IHVzZXJBdHRyaWJ1dGVzID0gYXdhaXQgdGhpcy5hdXRoLnVzZXJBdHRyaWJ1dGVzKFxuICAgICAgYXdhaXQgdGhpcy5hdXRoLmN1cnJlbnRBdXRoZW50aWNhdGVkVXNlcigpXG4gICAgKTtcbiAgICBjb25zdCBzdWIgPSB0aGlzLmdldFVzZXJBdHRyaWJ1dGUoJ3N1YicsIHVzZXJBdHRyaWJ1dGVzKTtcblxuICAgIHJldHVybiB7XG4gICAgICAuLi4oYXdhaXQgdGhpcy50cFBhc3N3b3JkUmVzZXRQcm9jZXNzb3JTZXJ2aWNlLnByb2Nlc3NUcFBhc3N3b3JkUmVzZXRVc2VyTm9kZShcbiAgICAgICAgcmVzZXRVc2VyXG4gICAgICApKSxcbiAgICAgIHN1YixcbiAgICB9O1xuICB9XG5cbiAgcHVibGljIGFzeW5jIHJlZnJlc2hBY2Nlc3NUb2tlbigpIHtcbiAgICBjb25zdCBjb2duaXRvVXNlcjogQ29nbml0b1VzZXIgPSBhd2FpdCB0aGlzLmF1dGguY3VycmVudEF1dGhlbnRpY2F0ZWRVc2VyKCk7XG4gICAgY29uc3QgcmVmcmVzaFRva2VuID0gY29nbml0b1VzZXIuZ2V0U2lnbkluVXNlclNlc3Npb24oKS5nZXRSZWZyZXNoVG9rZW4oKTtcblxuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICBjb2duaXRvVXNlci5yZWZyZXNoU2Vzc2lvbihyZWZyZXNoVG9rZW4sIChlcnIpID0+IHtcbiAgICAgICAgaWYgKGVycikge1xuICAgICAgICAgIGNvbnNvbGUuZXJyb3IoJ0Vycm9yIHJlZnJlc2hpbmcgdG9rZW46ICcsIGVycik7XG4gICAgICAgICAgcmVqZWN0KGVycik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY29uc29sZS5sb2coJ1Rva2VuIHJlZnJlc2ggY29tcGxldGUnKTtcbiAgICAgICAgICByZXNvbHZlKDApO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuXG4gIGFzeW5jIGNvbXBsZXRlUmVxdWVzdChuZXdQYXNzd29yZDogQ3J5cHRvS2V5KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgcmVzZXRVc2VyID0gYXdhaXQgdGhpcy5nZXRSZXNldFVzZXIodHJ1ZSk7XG5cbiAgICBpZiAocmVzZXRVc2VyLnN0YXRlICE9PSBUcENsYWltU3RhdGUuQVBQUk9WRUQpIHtcbiAgICAgIHRocm93IG5ldyBLY0JhZFN0YXRlRXhjZXB0aW9uKFxuICAgICAgICAnUGFzc3dvcmQgcmVzZXQgcmVxdWVzdCBoYXMgbm90IGJlZW4gYXBwcm92ZWQuJ1xuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgIC8vIFByZXBhcmUgYWxsIG1hdGVyaWFscyB0byBlbnN1cmUgdGhlcmUgYXJlIG5vIGVycm9ycy5cbiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgIGNvbnN0IGFzc2VtYmx5S2V5ID0gYXdhaXQgdGhpcy5yZWNvdmVyQXNzZW1ibHlLZXkocmVzZXRVc2VyKTtcblxuICAgIGNvbnN0IHsgcm9vdEtleSB9ID0gYXdhaXQgdGhpcy5lbmNyeXB0aW9uU2VydmljZS5kZWNyeXB0KFxuICAgICAgYXNzZW1ibHlLZXksXG4gICAgICByZXNldFVzZXIuYXNzZW1ibHlDaXBoZXJEYXRhXG4gICAgKTtcblxuICAgIC8vIE1ha2luZyBzdXJlIGl0J3MgYSB2YWxpZCBrZXkuXG4gICAgY29uc3Qgcm9vdEtleUp3ayA9IGF3YWl0IEpXSy5hc0tleShyb290S2V5KTtcblxuICAgIGNvbnN0IG1hc3RlcktleSA9IGF3YWl0IHRoaXMua2V5R3JhcGhTZXJ2aWNlLmdldEtleShyZXNldFVzZXIubWFzdGVyS2V5LmlkKTtcblxuICAgIGNvbnN0IG1hc3RlcktleVdyYXBwZWRSb290S2V5ID1cbiAgICAgIGF3YWl0IHRoaXMuZW5jcnlwdGlvblNlcnZpY2UuZW5jcnlwdFRvU3RyaW5nKFxuICAgICAgICBtYXN0ZXJLZXkuandrLFxuICAgICAgICByb290S2V5SndrLnRvSlNPTih0cnVlKVxuICAgICAgKTtcblxuICAgIC8vIFRoZSBuZXcgcGFzc3dvcmRcbiAgICBjb25zdCBuZXdQYXNzSWRwUmVzdWx0ID0gYXdhaXQgdGhpcy5rZXlGYWN0b3J5LmRlcml2ZVBhc3NJZHAoe1xuICAgICAgcGFzc3dvcmQ6IG5ld1Bhc3N3b3JkLFxuICAgICAgLi4ucmVzZXRVc2VyLnBhc3NLZXkucGFzc0lkcFBhcmFtcyxcbiAgICB9KTtcblxuICAgIGNvbnN0IG5ld0lkcFBhc3N3b3JkID0gdGhpcy5wYXNzd29yZFNlcnZpY2UuZ2V0UGFzc0lkcFN0cmluZyhcbiAgICAgIG5ld1Bhc3NJZHBSZXN1bHQuandrXG4gICAgKTtcblxuICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgLy8gR2V0IGFzc2VtYmx5IGtleSBjaGFsbGVuZ2VcbiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgIGNvbnN0IGNoYWxsZW5nZSA9IChcbiAgICAgIGF3YWl0IHRoaXMubHJHcmFwaFFMLmxyTXV0YXRlKFxuICAgICAgICBuZXcgTHJNdXRhdGlvbih7XG4gICAgICAgICAgbXV0YXRpb246IENyZWF0ZVRwQXNzZW1ibHlLZXlDaGFsbGVuZ2VNdXRhdGlvbixcbiAgICAgICAgICB2YXJpYWJsZXM6IHtcbiAgICAgICAgICAgIGlucHV0OiB7fSxcbiAgICAgICAgICB9LFxuICAgICAgICB9KSxcbiAgICAgICAge1xuICAgICAgICAgIGluY2x1ZGVLZXlHcmFwaDogZmFsc2UsXG4gICAgICAgIH1cbiAgICAgIClcbiAgICApLmNyZWF0ZVRwQXNzZW1ibHlLZXlDaGFsbGVuZ2UuY2hhbGxlbmdlO1xuXG4gICAgLy8gU2lnbiB0aGUgY2hhbGxlbmdlXG4gICAgLy8gR2VuZXJhdGUgYSBjbGllbnQgc2lkZSBub25jZSB0aGF0J3Mgbm8gaW4gdGhlIHNlcnZlcidzIGNvbnRyb2wuXG4gICAgY2hhbGxlbmdlLmNsaWVudE5vbmNlID0gdGhpcy5rZXlGYWN0b3J5LnJhbmRvbVN0cmluZyhcbiAgICAgIFRQX1BBU1NXT1JEX1JFU0VUX0NMSUVOVF9OT05DRV9MRU5HVEhcbiAgICApO1xuXG4gICAgY29uc3QgYXNzZW1ibHlLZXlWZXJpZmllclByayA9IGF3YWl0IHRoaXMuZW5jcnlwdGlvblNlcnZpY2UuZGVjcnlwdChcbiAgICAgIGFzc2VtYmx5S2V5LFxuICAgICAgcmVzZXRVc2VyLndyYXBwZWRBc3NlbWJseUtleVZlcmlmaWVyUHJrXG4gICAgKTtcbiAgICBjb25zdCBzaWduZWRDaGFsbGVuZ2UgPSBhd2FpdCB0aGlzLmVuY3J5cHRpb25TZXJ2aWNlLnNpZ24oXG4gICAgICBhc3NlbWJseUtleVZlcmlmaWVyUHJrLFxuICAgICAgY2hhbGxlbmdlXG4gICAgKTtcblxuICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgLy8gQ2hhbmdlIHBhc3N3b3JkIGZvciB0aGUgb3JpZ2luYWwgdXNlclxuICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgY29uc3QgdGVtcElkcFBhc3N3b3JkID0gKFxuICAgICAgYXdhaXQgdGhpcy5sckdyYXBoUUwubHJNdXRhdGUoXG4gICAgICAgIG5ldyBMck11dGF0aW9uKHtcbiAgICAgICAgICBtdXRhdGlvbjogUHJlQ29tcGxldGVUcFBhc3N3b3JkUmVzZXRSZXF1ZXN0TXV0YXRpb24sXG4gICAgICAgICAgdmFyaWFibGVzOiB7XG4gICAgICAgICAgICBpbnB1dDoge1xuICAgICAgICAgICAgICBzaWduZWRDaGFsbGVuZ2U6IEpTT04uc3RyaW5naWZ5KHNpZ25lZENoYWxsZW5nZSksXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0sXG4gICAgICAgIH0pLFxuICAgICAgICB7XG4gICAgICAgICAgaW5jbHVkZUtleUdyYXBoOiBmYWxzZSxcbiAgICAgICAgfVxuICAgICAgKVxuICAgICkucHJlQ29tcGxldGVUcFBhc3N3b3JkUmVzZXRSZXF1ZXN0LmlkcFBhc3N3b3JkO1xuXG4gICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgICAvLyBMb2dpbiBhcyB0aGUgb3JpZ2luYWwgdXNlciB1c2luZyBuZXcgdGVtcG9yYXJ5IHBhc3N3b3JkXG4gICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgICAvLyBBdCB0aGlzIHBvaW50LCB0aGUgb3JpZ2luYWwgYWNjb3VudCdzIHBhc3N3b3JkIGhhcyBiZWVuIGNoYW5nZWRcbiAgICAvLyB0byBhIHRlbXBvcmFyeSBwYXNzd29yZC4gSXQgaXMgbm8gbG9uZ2VyIHBvc3NpYmxlIGZvciB0aGUgdXNlclxuICAgIC8vIHRvIHVzZSB0aGUgb3JpZ2luYWwgcGFzc3dvcmQgdG8gbG9naW4uIEFueSBzdWNjZXNzZnVsIGxvZ2luXG4gICAgLy8gY2FuIG9ubHkgYmUgdXNpbmcgdGhlIHRlbXBvcmFyeSBwYXNzd29yZC4gU28gaXQncyBzYWZlIHRvIGFzc3VtZVxuICAgIC8vIHRoYXQgd2Ugd2FudCB0byBcImNvbXBsZXRlXCIgdGhlIHBhc3N3b3JkIHJlc2V0LlxuXG4gICAgLy8gVGhlIG1heWJlIDJGQSBzbyB3ZSBsaXN0ZW4gZm9yIHRoZSBhdXRoIGV2ZW50IGZyb20gQW1wbGlmeS5cbiAgICBjb25zdCByZXRQcm9taXNlID0gbmV3IFByb21pc2U8dm9pZD4oKHJlc29sdmUpID0+IHtcbiAgICAgIGNvbnN0IGxpc3RlbmVyID0gYXN5bmMgKGRhdGEpID0+IHtcbiAgICAgICAgaWYgKGRhdGEucGF5bG9hZC5ldmVudCAhPT0gJ3NpZ25JbicpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBIdWIucmVtb3ZlKCdhdXRoJywgbGlzdGVuZXIpO1xuXG4gICAgICAgIGF3YWl0IHRoaXMuYXV0aC5zaWduSW4ocmVzZXRVc2VyLnVzZXJuYW1lLCBuZXdJZHBQYXNzd29yZCk7XG5cbiAgICAgICAgLy8gU3dpdGNoIG92ZXIgdG8gdGhlIG5ldyBzZXQgb2Yga2V5c1xuICAgICAgICBhd2FpdCB0aGlzLmxyR3JhcGhRTC5sck11dGF0ZShcbiAgICAgICAgICBuZXcgTHJNdXRhdGlvbih7XG4gICAgICAgICAgICBtdXRhdGlvbjogQ29tcGxldGVUcFBhc3N3b3JkUmVzZXRSZXF1ZXN0TXV0YXRpb24sXG4gICAgICAgICAgICB2YXJpYWJsZXM6IHtcbiAgICAgICAgICAgICAgaW5wdXQ6IHtcbiAgICAgICAgICAgICAgICBtYXN0ZXJLZXlXcmFwcGVkUm9vdEtleSxcbiAgICAgICAgICAgICAgICBtYXN0ZXJLZXlJZDogbWFzdGVyS2V5LmlkLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9KVxuICAgICAgICApO1xuXG4gICAgICAgIHJlc29sdmUoKTtcbiAgICAgIH07XG5cbiAgICAgIEh1Yi5saXN0ZW4oJ2F1dGgnLCBsaXN0ZW5lcik7XG4gICAgfSk7XG5cbiAgICAvLyBTaWduaW4gYXMgdGhlIG9yaWdpbmFsIHVzZXIuIFBhc3N3b3JkIGhhcyBiZWVuIHJlc2V0IHRvIHRlbXBvcmFyeSBvbmUuIEl0IHNob3VsZCByZXR1cm5cbiAgICAvLyB3aXRoIE5FV19QQVNTV09SRF9SRVFVSVJFRFxuICAgIGxldCB1c2VyID0gYXdhaXQgdGhpcy5hdXRoLnNpZ25JbihyZXNldFVzZXIudXNlcm5hbWUsIHRlbXBJZHBQYXNzd29yZCwge1xuICAgICAgbm9Qcm94eTogJ3RydWUnLFxuICAgIH0pO1xuXG4gICAgaWYgKHVzZXIuY2hhbGxlbmdlTmFtZSAhPT0gJ05FV19QQVNTV09SRF9SRVFVSVJFRCcpIHtcbiAgICAgIHRocm93IG5ldyBLY0ludGVybmFsRXJyb3JFeGNlcHRpb24oXG4gICAgICAgICdFeHBlY3RpbmcgQ29nbml0byB0byBoYXZlIGRvbmUgYSBwYXNzd29yZCByZXNldCBhZnRlciBjYWxsIHRvIFByZUNvbXBsZXRlVHBQYXNzd29yZFJlc2V0UmVxdWVzdE11dGF0aW9uLidcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gU2V0IG5ldyBwYXNzd29yZCBvbiBJZHBcbiAgICAvLyB0aGUgYXdzRmV0Y2goKSBmdW5jdGlvbiBwYXNzZXMgTkVXX1BBU1NXT1JEX1JFUVVJUkVEIGRpcmVjdGx5IHRvIEFXUyB3aXRob3V0XG4gICAgLy8gZ29pbmcgdGhyb3VnaCB0aGUgcHJveHkuXG4gICAgdXNlciA9IGF3YWl0IHRoaXMuYXV0aC5jb21wbGV0ZU5ld1Bhc3N3b3JkKHVzZXIsIG5ld0lkcFBhc3N3b3JkLCB7fSk7XG5cbiAgICByZXR1cm4gcmV0UHJvbWlzZTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgcmVjb3ZlckFzc2VtYmx5S2V5KFxuICAgIHJlc2V0VXNlcjogVHBQYXNzd29yZFJlc2V0VXNlck5vZGVcbiAgKTogUHJvbWlzZTxKV0suS2V5PiB7XG4gICAgY29uc3QgcHJrID0gYXdhaXQgdGhpcy5rZXlHcmFwaFNlcnZpY2UuZ2V0S2V5KHJlc2V0VXNlci5weGsuaWQpO1xuXG4gICAgY29uc3QgcGFydGlhbHMgPSBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgIHJlc2V0VXNlci5hcHByb3ZhbHNcbiAgICAgICAgLmZpbHRlcigoYXBwcm92YWwpID0+ICEhYXBwcm92YWwucmVjZWl2ZXJDaXBoZXJQYXJ0aWFsQXNzZW1ibHlLZXkpXG4gICAgICAgIC5tYXAoKGFwcHJvdmFsKSA9PlxuICAgICAgICAgIHRoaXMuZW5jcnlwdGlvblNlcnZpY2UuZGVjcnlwdChcbiAgICAgICAgICAgIHByayxcbiAgICAgICAgICAgIGFwcHJvdmFsLnJlY2VpdmVyQ2lwaGVyUGFydGlhbEFzc2VtYmx5S2V5XG4gICAgICAgICAgKVxuICAgICAgICApXG4gICAgKTtcblxuICAgIHJldHVybiB0aGlzLmFzc2VtYmx5Q29udHJvbGxlci5yZWNvdmVyQXNzZW1ibHlLZXkocGFydGlhbHMpO1xuICB9XG59XG4iXX0=
|