@lifeready/core 1.0.4 → 1.0.6
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/README.md +62 -62
- package/bundles/lifeready-core.umd.js +15445 -15445
- 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/ast.js +40 -40
- package/esm2015/lib/_common/deferred-promise.js +24 -24
- package/esm2015/lib/_common/exceptions.js +157 -157
- package/esm2015/lib/_common/queries.gql.js +190 -190
- package/esm2015/lib/_common/run-outside-angular.js +79 -79
- package/esm2015/lib/_common/types.js +1 -1
- package/esm2015/lib/_common/utils.js +44 -44
- package/esm2015/lib/api/contact-card.gql.js +79 -79
- package/esm2015/lib/api/contact-card.service.js +154 -154
- package/esm2015/lib/api/contact-card2.gql.js +60 -60
- package/esm2015/lib/api/contact-card2.service.js +103 -103
- package/esm2015/lib/api/file.service.js +74 -74
- package/esm2015/lib/api/item2.gql.js +110 -110
- package/esm2015/lib/api/item2.service.js +311 -311
- package/esm2015/lib/api/key-exchange.gql.js +188 -188
- package/esm2015/lib/api/key-exchange.service.js +442 -442
- package/esm2015/lib/api/key-exchange.types.js +18 -18
- package/esm2015/lib/api/key-exchange2.gql.js +171 -171
- package/esm2015/lib/api/key-exchange2.service.js +479 -479
- package/esm2015/lib/api/lock.gql.js +40 -40
- package/esm2015/lib/api/lock.service.js +64 -64
- package/esm2015/lib/api/lr-apollo.service.js +46 -46
- package/esm2015/lib/api/lr-graphql/index.js +6 -6
- package/esm2015/lib/api/lr-graphql/lr-graphql.service.js +155 -155
- package/esm2015/lib/api/lr-graphql/lr-merged-mutation.js +213 -213
- package/esm2015/lib/api/lr-graphql/lr-mutation-base.js +51 -51
- package/esm2015/lib/api/lr-graphql/lr-mutation.js +48 -48
- package/esm2015/lib/api/lr-graphql/lr.service.js +18 -18
- package/esm2015/lib/api/message.service.js +138 -138
- package/esm2015/lib/api/persist.service.js +181 -181
- package/esm2015/lib/api/query-processor/common-processors.service.js +93 -93
- package/esm2015/lib/api/query-processor/index.js +3 -3
- package/esm2015/lib/api/query-processor/query-processor.service.js +192 -192
- package/esm2015/lib/api/query-processor/tp-password-reset-processor.service.js +109 -109
- package/esm2015/lib/api/shared-contact-card.service.js +119 -119
- package/esm2015/lib/api/shared-contact-card2.gql.js +41 -41
- package/esm2015/lib/api/shared-contact-card2.service.js +117 -117
- package/esm2015/lib/api/time.service.js +146 -146
- package/esm2015/lib/api/types/graphql.types.js +7 -7
- package/esm2015/lib/api/types/index.js +3 -3
- package/esm2015/lib/api/types/lr-graphql.types.js +71 -71
- package/esm2015/lib/auth/auth.config.js +57 -57
- package/esm2015/lib/auth/auth.gql.js +48 -48
- package/esm2015/lib/auth/auth.types.js +27 -27
- package/esm2015/lib/auth/idle.service.js +168 -168
- package/esm2015/lib/auth/idle.types.js +7 -7
- package/esm2015/lib/auth/lbop.service.js +355 -355
- package/esm2015/lib/auth/life-ready-auth.service.js +500 -500
- package/esm2015/lib/auth/password.service.js +320 -320
- package/esm2015/lib/auth/register.service.js +172 -172
- package/esm2015/lib/auth/two-factor.service.js +74 -74
- package/esm2015/lib/category/category-meta.service.js +99 -99
- package/esm2015/lib/category/category.gql.js +406 -406
- package/esm2015/lib/category/category.service.js +390 -390
- package/esm2015/lib/category/category.types.js +29 -29
- package/esm2015/lib/cryptography/cryptography.types.js +11 -11
- package/esm2015/lib/cryptography/encryption.service.js +189 -189
- package/esm2015/lib/cryptography/key-factory.service.js +237 -237
- package/esm2015/lib/cryptography/key-graph.service.js +280 -280
- package/esm2015/lib/cryptography/key-meta.service.js +200 -200
- package/esm2015/lib/cryptography/key.service.js +124 -124
- package/esm2015/lib/cryptography/slip39.service.js +169 -169
- package/esm2015/lib/cryptography/web-crypto.service.js +29 -29
- package/esm2015/lib/life-ready.config.js +84 -84
- package/esm2015/lib/life-ready.module.js +74 -74
- package/esm2015/lib/plan/plan.gql.js +123 -123
- package/esm2015/lib/plan/plan.service.js +149 -149
- package/esm2015/lib/plan/plan.types.js +11 -11
- package/esm2015/lib/record/record-attachment.service.js +101 -101
- package/esm2015/lib/record/record.gql.js +179 -179
- package/esm2015/lib/record/record.service.js +206 -206
- package/esm2015/lib/record/record.types.js +15 -15
- package/esm2015/lib/record-type/record-type.service.js +75 -75
- package/esm2015/lib/record-type/record-type.types.js +28 -28
- package/esm2015/lib/scenario/approvals/scenario-approval.gql.js +105 -105
- package/esm2015/lib/scenario/approvals/scenario-approval.types.js +1 -1
- package/esm2015/lib/scenario/approvals/scenario-approver.service.js +300 -300
- package/esm2015/lib/scenario/claimants/scenario-claimant.gql.js +52 -52
- package/esm2015/lib/scenario/claimants/scenario-claimant.service.js +97 -97
- package/esm2015/lib/scenario/claimants/scenario-claimant.types.js +1 -1
- package/esm2015/lib/scenario/receivers/scenario-receiver.gql.js +150 -150
- package/esm2015/lib/scenario/receivers/scenario-receiver.service.js +229 -229
- package/esm2015/lib/scenario/receivers/scenario-receiver.types.js +1 -1
- package/esm2015/lib/scenario/scenario-setup.service.js +269 -269
- package/esm2015/lib/scenario/scenario.gql.js +368 -368
- package/esm2015/lib/scenario/scenario.service.js +611 -611
- package/esm2015/lib/scenario/scenario.types.js +64 -64
- package/esm2015/lib/search/search.gql.js +62 -62
- package/esm2015/lib/search/search.service.js +156 -156
- package/esm2015/lib/search/search.types.js +6 -6
- package/esm2015/lib/trusted-parties/tp-password-reset-request.service.js +112 -112
- package/esm2015/lib/trusted-parties/tp-password-reset-user.service.js +129 -129
- package/esm2015/lib/trusted-parties/tp-password-reset.constants.js +4 -4
- package/esm2015/lib/trusted-parties/tp-password-reset.gql.js +232 -232
- package/esm2015/lib/trusted-parties/tp-password-reset.service.js +299 -299
- package/esm2015/lib/trusted-parties/trusted-party.gql.js +148 -148
- package/esm2015/lib/trusted-parties/trusted-party.service.js +326 -326
- package/esm2015/lib/trusted-parties/trusted-party.types.js +41 -41
- package/esm2015/lib/trusted-parties/trusted-party2.gql.js +87 -87
- package/esm2015/lib/trusted-parties/trusted-party2.service.js +215 -215
- package/esm2015/lib/users/profile-details.service.js +214 -214
- package/esm2015/lib/users/profile.gql.js +97 -97
- package/esm2015/lib/users/profile.service.js +169 -169
- package/esm2015/lib/users/profile.types.js +34 -34
- package/esm2015/lib/users/user.gql.js +60 -60
- package/esm2015/lib/users/user.service.js +79 -79
- package/esm2015/lib/users/user.types.js +5 -5
- package/esm2015/lifeready-core.js +10 -10
- package/esm2015/public-api.js +81 -81
- package/fesm2015/lifeready-core.js +13088 -13088
- package/fesm2015/lifeready-core.js.map +1 -1
- package/lib/_common/ast.d.ts +11 -11
- package/lib/_common/deferred-promise.d.ts +12 -12
- package/lib/_common/exceptions.d.ts +109 -109
- package/lib/_common/queries.gql.d.ts +10 -10
- package/lib/_common/run-outside-angular.d.ts +14 -14
- package/lib/_common/types.d.ts +10 -10
- package/lib/_common/utils.d.ts +3 -3
- package/lib/api/contact-card.gql.d.ts +7 -7
- package/lib/api/contact-card.service.d.ts +52 -52
- package/lib/api/contact-card2.gql.d.ts +34 -34
- package/lib/api/contact-card2.service.d.ts +49 -49
- package/lib/api/file.service.d.ts +18 -18
- package/lib/api/item2.gql.d.ts +96 -96
- package/lib/api/item2.service.d.ts +177 -177
- package/lib/api/key-exchange.gql.d.ts +9 -9
- package/lib/api/key-exchange.service.d.ts +39 -39
- package/lib/api/key-exchange.types.d.ts +196 -196
- package/lib/api/key-exchange2.gql.d.ts +125 -125
- package/lib/api/key-exchange2.service.d.ts +187 -187
- package/lib/api/lock.gql.d.ts +27 -27
- package/lib/api/lock.service.d.ts +25 -25
- package/lib/api/lr-apollo.service.d.ts +15 -15
- package/lib/api/lr-graphql/index.d.ts +5 -5
- package/lib/api/lr-graphql/lr-graphql.service.d.ts +60 -60
- package/lib/api/lr-graphql/lr-merged-mutation.d.ts +27 -27
- package/lib/api/lr-graphql/lr-mutation-base.d.ts +28 -28
- package/lib/api/lr-graphql/lr-mutation.d.ts +8 -8
- package/lib/api/lr-graphql/lr.service.d.ts +9 -9
- package/lib/api/message.service.d.ts +58 -58
- package/lib/api/persist.service.d.ts +31 -31
- package/lib/api/query-processor/common-processors.service.d.ts +36 -36
- package/lib/api/query-processor/index.d.ts +2 -2
- package/lib/api/query-processor/query-processor.service.d.ts +18 -18
- package/lib/api/query-processor/tp-password-reset-processor.service.d.ts +15 -15
- package/lib/api/shared-contact-card.service.d.ts +33 -33
- package/lib/api/shared-contact-card2.gql.d.ts +36 -36
- package/lib/api/shared-contact-card2.service.d.ts +45 -45
- package/lib/api/time.service.d.ts +16 -16
- package/lib/api/types/graphql.types.d.ts +29 -29
- package/lib/api/types/index.d.ts +2 -2
- package/lib/api/types/lr-graphql.types.d.ts +393 -385
- package/lib/auth/auth.config.d.ts +5 -5
- package/lib/auth/auth.gql.d.ts +15 -15
- package/lib/auth/auth.types.d.ts +66 -66
- package/lib/auth/idle.service.d.ts +40 -40
- package/lib/auth/idle.types.d.ts +10 -10
- package/lib/auth/lbop.service.d.ts +91 -91
- package/lib/auth/life-ready-auth.service.d.ts +59 -59
- package/lib/auth/password.service.d.ts +78 -78
- package/lib/auth/register.service.d.ts +25 -25
- package/lib/auth/two-factor.service.d.ts +15 -15
- package/lib/category/category-meta.service.d.ts +23 -23
- package/lib/category/category.gql.d.ts +45 -45
- package/lib/category/category.service.d.ts +67 -67
- package/lib/category/category.types.d.ts +79 -79
- package/lib/cryptography/cryptography.types.d.ts +83 -83
- package/lib/cryptography/encryption.service.d.ts +41 -41
- package/lib/cryptography/key-factory.service.d.ts +38 -38
- package/lib/cryptography/key-graph.service.d.ts +33 -33
- package/lib/cryptography/key-meta.service.d.ts +44 -44
- package/lib/cryptography/key.service.d.ts +36 -36
- package/lib/cryptography/slip39.service.d.ts +43 -43
- package/lib/cryptography/web-crypto.service.d.ts +5 -5
- package/lib/life-ready.config.d.ts +14 -14
- package/lib/life-ready.module.d.ts +5 -5
- package/lib/plan/plan.gql.d.ts +11 -11
- package/lib/plan/plan.service.d.ts +33 -33
- package/lib/plan/plan.types.d.ts +31 -31
- package/lib/record/record-attachment.service.d.ts +16 -16
- package/lib/record/record.gql.d.ts +14 -14
- package/lib/record/record.service.d.ts +25 -25
- package/lib/record/record.types.d.ts +57 -57
- package/lib/record-type/record-type.service.d.ts +11 -11
- package/lib/record-type/record-type.types.d.ts +50 -50
- package/lib/scenario/approvals/scenario-approval.gql.d.ts +7 -7
- package/lib/scenario/approvals/scenario-approval.types.d.ts +63 -63
- package/lib/scenario/approvals/scenario-approver.service.d.ts +32 -32
- package/lib/scenario/claimants/scenario-claimant.gql.d.ts +5 -5
- package/lib/scenario/claimants/scenario-claimant.service.d.ts +17 -17
- package/lib/scenario/claimants/scenario-claimant.types.d.ts +18 -18
- package/lib/scenario/receivers/scenario-receiver.gql.d.ts +8 -8
- package/lib/scenario/receivers/scenario-receiver.service.d.ts +30 -30
- package/lib/scenario/receivers/scenario-receiver.types.d.ts +54 -54
- package/lib/scenario/scenario-setup.service.d.ts +22 -22
- package/lib/scenario/scenario.gql.d.ts +34 -34
- package/lib/scenario/scenario.service.d.ts +58 -58
- package/lib/scenario/scenario.types.d.ts +217 -217
- package/lib/search/search.gql.d.ts +1 -1
- package/lib/search/search.service.d.ts +25 -25
- package/lib/search/search.types.d.ts +20 -20
- package/lib/trusted-parties/tp-password-reset-request.service.d.ts +20 -20
- package/lib/trusted-parties/tp-password-reset-user.service.d.ts +35 -35
- package/lib/trusted-parties/tp-password-reset.constants.d.ts +3 -3
- package/lib/trusted-parties/tp-password-reset.gql.d.ts +218 -218
- package/lib/trusted-parties/tp-password-reset.service.d.ts +130 -130
- package/lib/trusted-parties/trusted-party.gql.d.ts +9 -9
- package/lib/trusted-parties/trusted-party.service.d.ts +44 -44
- package/lib/trusted-parties/trusted-party.types.d.ts +102 -102
- package/lib/trusted-parties/trusted-party2.gql.d.ts +79 -79
- package/lib/trusted-parties/trusted-party2.service.d.ts +114 -114
- package/lib/users/profile-details.service.d.ts +21 -21
- package/lib/users/profile.gql.d.ts +11 -11
- package/lib/users/profile.service.d.ts +35 -35
- package/lib/users/profile.types.d.ts +96 -96
- package/lib/users/user.gql.d.ts +9 -9
- package/lib/users/user.service.d.ts +12 -12
- package/lib/users/user.types.d.ts +23 -23
- package/lifeready-core.d.ts +9 -9
- package/package.json +1 -1
- package/public-api.d.ts +77 -77
|
@@ -1,500 +1,500 @@
|
|
|
1
|
-
import { __awaiter } from "tslib";
|
|
2
|
-
import { Inject, Injectable, isDevMode } from '@angular/core';
|
|
3
|
-
import { Hub } from '@aws-amplify/core';
|
|
4
|
-
import { ReplaySubject } from 'rxjs';
|
|
5
|
-
import { KeyGraphService } from '../cryptography/key-graph.service';
|
|
6
|
-
import { KeyService } from '../cryptography/key.service';
|
|
7
|
-
import { ProfileService } from '../users/profile.service';
|
|
8
|
-
import { PasswordChangeStatus } from '../users/profile.types';
|
|
9
|
-
import { LrConcurrentAccessException, LrBadRequestException, LrBadStateException, LrException, } from '../_common/exceptions';
|
|
10
|
-
import { RecoveryStatus, } from './auth.types';
|
|
11
|
-
import { PasswordService } from './password.service';
|
|
12
|
-
import { AuthClass } from '@aws-amplify/auth/lib-esm/Auth';
|
|
13
|
-
import { CompleteTpPasswordResetRequestMutation, CreateTpAssemblyKeyChallengeMutation, PreCompleteTpPasswordResetRequestMutation, TpPasswordResetUserQuery, } from '../trusted-parties/tp-password-reset.gql';
|
|
14
|
-
import { IdleService } from './idle.service';
|
|
15
|
-
import { KeyFactoryService } from '../cryptography/key-factory.service';
|
|
16
|
-
import { LrGraphQLService, LrMutation } from '../api/lr-graphql';
|
|
17
|
-
import { TpClaimState } from '../api/types';
|
|
18
|
-
import { TpPasswordResetProcessorService } from '../api/query-processor/tp-password-reset-processor.service';
|
|
19
|
-
import { SetSessionEncryptionKeyMutation } from './auth.gql';
|
|
20
|
-
import { PersistService } from '../api/persist.service';
|
|
21
|
-
import { JWK } from 'node-jose';
|
|
22
|
-
import { LR_CONFIG } from '../life-ready.config';
|
|
23
|
-
import { EncryptionService } from '../cryptography/encryption.service';
|
|
24
|
-
import { Slip39Service } from '../cryptography/slip39.service';
|
|
25
|
-
import { TP_PASSWORD_RESET_CLIENT_NONCE_LENGTH, TP_PASSWORD_RESET_SLIP39_PASSPHRASE, TP_PASSWORD_RESET_USERNAME_SUFFIX, } from '../trusted-parties/tp-password-reset.constants';
|
|
26
|
-
import * as i0 from "@angular/core";
|
|
27
|
-
import * as i1 from "../life-ready.config";
|
|
28
|
-
import * as i2 from "@aws-amplify/auth/lib-esm/Auth";
|
|
29
|
-
import * as i3 from "../cryptography/key-factory.service";
|
|
30
|
-
import * as i4 from "../cryptography/key.service";
|
|
31
|
-
import * as i5 from "../users/profile.service";
|
|
32
|
-
import * as i6 from "../cryptography/key-graph.service";
|
|
33
|
-
import * as i7 from "./password.service";
|
|
34
|
-
import * as i8 from "./idle.service";
|
|
35
|
-
import * as i9 from "../api/lr-graphql/lr-graphql.service";
|
|
36
|
-
import * as i10 from "../api/query-processor/tp-password-reset-processor.service";
|
|
37
|
-
import * as i11 from "../api/persist.service";
|
|
38
|
-
import * as i12 from "../cryptography/encryption.service";
|
|
39
|
-
import * as i13 from "../cryptography/slip39.service";
|
|
40
|
-
export const initialiseAuth = (authService) => {
|
|
41
|
-
return () => authService.initialise();
|
|
42
|
-
};
|
|
43
|
-
export class LifeReadyAuthService {
|
|
44
|
-
constructor(config, auth, keyFactory, keyService, profileService, keyGraphService, passwordService, idleService, lrGraphQL, tpPasswordResetProcessorService, persistService, encryptionService, slip39Service) {
|
|
45
|
-
this.config = config;
|
|
46
|
-
this.auth = auth;
|
|
47
|
-
this.keyFactory = keyFactory;
|
|
48
|
-
this.keyService = keyService;
|
|
49
|
-
this.profileService = profileService;
|
|
50
|
-
this.keyGraphService = keyGraphService;
|
|
51
|
-
this.passwordService = passwordService;
|
|
52
|
-
this.idleService = idleService;
|
|
53
|
-
this.lrGraphQL = lrGraphQL;
|
|
54
|
-
this.tpPasswordResetProcessorService = tpPasswordResetProcessorService;
|
|
55
|
-
this.persistService = persistService;
|
|
56
|
-
this.encryptionService = encryptionService;
|
|
57
|
-
this.slip39Service = slip39Service;
|
|
58
|
-
this.hubSubject = new ReplaySubject(1);
|
|
59
|
-
}
|
|
60
|
-
initialise() {
|
|
61
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
62
|
-
Hub.listen('auth', (data) => this.hubSubject.next(data.payload));
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
loginIdpImpl(emailOrPhone, password, passIdpParams, recoveryStatus) {
|
|
66
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
67
|
-
const passIdpResult = yield this.keyFactory.derivePassIdp(Object.assign({ password }, passIdpParams));
|
|
68
|
-
// Use the derived password to signin with cognito
|
|
69
|
-
const user = yield this.auth.signIn(emailOrPhone, this.passwordService.getPassIdpString(passIdpResult.jwk));
|
|
70
|
-
user.recoveryStatus = recoveryStatus;
|
|
71
|
-
return user;
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
loginIdp(emailOrPhone, password) {
|
|
75
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
76
|
-
// Download the salt needed to derive the PassIdp
|
|
77
|
-
const passIdpApiResult = yield this.profileService.getPassIdpParams(emailOrPhone);
|
|
78
|
-
if (passIdpApiResult.passwordChangeStatus === PasswordChangeStatus.InProgress) {
|
|
79
|
-
throw new LrConcurrentAccessException('A password change is in progress');
|
|
80
|
-
}
|
|
81
|
-
if (passIdpApiResult.passwordChangeStatus === PasswordChangeStatus.Recovery) {
|
|
82
|
-
console.log('In recovery mode.');
|
|
83
|
-
// Let's say we don't know if the password is the new one or the old one. We just have to try both.
|
|
84
|
-
try {
|
|
85
|
-
const user = yield this.loginIdpImpl(emailOrPhone, password, passIdpApiResult.newPassIdpParams, RecoveryStatus.NEW_PASSWORD);
|
|
86
|
-
// New password worked. Let's set to the current password
|
|
87
|
-
// --Potential Failure Point 1--
|
|
88
|
-
// if changePasswordComplete() doesn't get called, then it should remain
|
|
89
|
-
console.log('New password works!');
|
|
90
|
-
return user;
|
|
91
|
-
}
|
|
92
|
-
catch (error) {
|
|
93
|
-
// Just bubble up any other type of error.
|
|
94
|
-
if (error.code !== 'NotAuthorizedException') {
|
|
95
|
-
throw error;
|
|
96
|
-
}
|
|
97
|
-
// pass, try again assuming it's the old password
|
|
98
|
-
}
|
|
99
|
-
// Now assume it's the previous password. Any exception is allowed to bubble up.
|
|
100
|
-
try {
|
|
101
|
-
const user = yield this.loginIdpImpl(emailOrPhone, password, passIdpApiResult.currentPassIdpParams, RecoveryStatus.OLD_PASSWORD);
|
|
102
|
-
// Old password worked.
|
|
103
|
-
console.log('Old password works!');
|
|
104
|
-
return user;
|
|
105
|
-
}
|
|
106
|
-
catch (error) {
|
|
107
|
-
// Just bubble up any other type of error.
|
|
108
|
-
throw error.code === 'NotAuthorizedException'
|
|
109
|
-
? new LrBadRequestException('The password change request was interrupted, please try to login with both your new and old password')
|
|
110
|
-
: error;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
// Try against as the TP password reset account
|
|
114
|
-
if (passIdpApiResult.tpPasswordReset) {
|
|
115
|
-
try {
|
|
116
|
-
// TP password reset is in process. We need to try the password against both
|
|
117
|
-
// original account and the new reset account.
|
|
118
|
-
const reset = passIdpApiResult.tpPasswordReset;
|
|
119
|
-
const ret = yield this.loginIdpImpl(reset.resetUsername, password, reset.passIdpParams, RecoveryStatus.NONE);
|
|
120
|
-
ret.isTpPasswordResetUser = true;
|
|
121
|
-
return ret;
|
|
122
|
-
}
|
|
123
|
-
catch (err) {
|
|
124
|
-
// continue, try again as regular user.
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
// Login as regular user
|
|
128
|
-
return yield this.loginIdpImpl(emailOrPhone, password, passIdpApiResult.currentPassIdpParams, RecoveryStatus.NONE);
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
handleSessionEncryptionKey() {
|
|
132
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
133
|
-
if (this.config.disableSessionEncryptionKey) {
|
|
134
|
-
if (!isDevMode()) {
|
|
135
|
-
const msg = 'You should not set disableSessionEncryptionKey=True in mode prod. It defaults to false.';
|
|
136
|
-
console.error(msg);
|
|
137
|
-
throw new Error(msg);
|
|
138
|
-
}
|
|
139
|
-
else {
|
|
140
|
-
console.warn('You have set disableSessionEncryptionKey=True. Make sure not to do this in prod mode.');
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
else {
|
|
144
|
-
// Set the session key to a new encryption key for this session
|
|
145
|
-
const sessionEncryptionKey = yield this.keyFactory.createKey();
|
|
146
|
-
yield this.lrGraphQL.lrMutate(new LrMutation({
|
|
147
|
-
mutation: SetSessionEncryptionKeyMutation,
|
|
148
|
-
variables: {
|
|
149
|
-
input: {
|
|
150
|
-
sessionEncryptionKey: JSON.stringify(sessionEncryptionKey.toJSON(true)),
|
|
151
|
-
},
|
|
152
|
-
},
|
|
153
|
-
}), {
|
|
154
|
-
includeKeyGraph: false,
|
|
155
|
-
});
|
|
156
|
-
this.persistService.setServerSessionEncryptionKey(sessionEncryptionKey);
|
|
157
|
-
}
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
handlePostAuth(cognitoUser) {
|
|
161
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
162
|
-
yield this.handlePasswordRecovery(cognitoUser);
|
|
163
|
-
yield this.handleSessionEncryptionKey();
|
|
164
|
-
});
|
|
165
|
-
}
|
|
166
|
-
login(emailOrPhone, password, { tpPasswordResetAutoComplete = true } = {}) {
|
|
167
|
-
var _a;
|
|
168
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
169
|
-
let loginResult = yield this.loginImpl(emailOrPhone, password);
|
|
170
|
-
if (tpPasswordResetAutoComplete &&
|
|
171
|
-
((_a = loginResult.resetUser) === null || _a === void 0 ? void 0 : _a.state) === TpClaimState.APPROVED) {
|
|
172
|
-
yield this.completeRequest(password);
|
|
173
|
-
loginResult = yield this.loginImpl(emailOrPhone, password);
|
|
174
|
-
}
|
|
175
|
-
return loginResult;
|
|
176
|
-
});
|
|
177
|
-
}
|
|
178
|
-
loginImpl(emailOrPhone, password) {
|
|
179
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
180
|
-
yield this.logout();
|
|
181
|
-
const cognitoUser = yield this.loginIdp(emailOrPhone, password);
|
|
182
|
-
// todo: Meet MFA challenges.
|
|
183
|
-
if (['SMS_MFA', 'SOFTWARE_TOKEN_MFA'].includes(cognitoUser.challengeName)) {
|
|
184
|
-
return { hasChallenge: true, challenge: cognitoUser };
|
|
185
|
-
}
|
|
186
|
-
yield this.handlePostAuth(cognitoUser);
|
|
187
|
-
if (cognitoUser.isTpPasswordResetUser) {
|
|
188
|
-
// Assuming there is no MFA on the TP reset user.
|
|
189
|
-
const resetUser = yield this.loadResetUser(password);
|
|
190
|
-
return { hasChallenge: false, resetUser };
|
|
191
|
-
}
|
|
192
|
-
else {
|
|
193
|
-
const user = yield this.loadUser(cognitoUser, password);
|
|
194
|
-
yield this.idleService.start(); // Run idleService whenever user is logged in.
|
|
195
|
-
return { hasChallenge: false, user };
|
|
196
|
-
}
|
|
197
|
-
});
|
|
198
|
-
}
|
|
199
|
-
// TODO <AZ> We need to handle the isTpPasswordResetUser=True case here after MFA as well.
|
|
200
|
-
verifyLogin(challenge, password, rememberMe, code) {
|
|
201
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
202
|
-
yield this.auth.confirmSignIn(challenge, code, challenge.challengeName);
|
|
203
|
-
// TODO: this.auth.confirmSignIn() could return another challenge.
|
|
204
|
-
const cognitoUser = yield this.auth.currentAuthenticatedUser();
|
|
205
|
-
yield this.handlePostAuth(challenge);
|
|
206
|
-
const user = yield this.loadUser(cognitoUser, password);
|
|
207
|
-
if (rememberMe) {
|
|
208
|
-
cognitoUser.setDeviceStatusRemembered({
|
|
209
|
-
onSuccess: () => { },
|
|
210
|
-
onFailure: (e) => console.error(e),
|
|
211
|
-
});
|
|
212
|
-
}
|
|
213
|
-
return user;
|
|
214
|
-
});
|
|
215
|
-
}
|
|
216
|
-
handlePasswordRecovery(user) {
|
|
217
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
218
|
-
if (user.recoveryStatus !== RecoveryStatus.NONE) {
|
|
219
|
-
const jwtToken = user
|
|
220
|
-
.getSignInUserSession()
|
|
221
|
-
.getAccessToken()
|
|
222
|
-
.getJwtToken();
|
|
223
|
-
yield this.passwordService.changePasswordComplete(jwtToken, user.recoveryStatus === RecoveryStatus.NEW_PASSWORD);
|
|
224
|
-
}
|
|
225
|
-
});
|
|
226
|
-
}
|
|
227
|
-
getUserOrResetUser(reload = false) {
|
|
228
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
229
|
-
const cognitoUser = yield this.auth.currentAuthenticatedUser();
|
|
230
|
-
if (cognitoUser.getUsername().endsWith(TP_PASSWORD_RESET_USERNAME_SUFFIX)) {
|
|
231
|
-
return this.getResetUser(reload);
|
|
232
|
-
}
|
|
233
|
-
else {
|
|
234
|
-
return this.getUser(reload);
|
|
235
|
-
}
|
|
236
|
-
});
|
|
237
|
-
}
|
|
238
|
-
getResetUser(reload = false) {
|
|
239
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
240
|
-
if (!reload && this.currentResetUser) {
|
|
241
|
-
return this.currentResetUser;
|
|
242
|
-
}
|
|
243
|
-
this.currentResetUser = yield this.loadResetUser();
|
|
244
|
-
yield this.idleService.start(); // Run idleService whenever user is logged in.
|
|
245
|
-
return this.currentResetUser;
|
|
246
|
-
});
|
|
247
|
-
}
|
|
248
|
-
getUser(reload = false) {
|
|
249
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
250
|
-
if (!reload && this.currentUser) {
|
|
251
|
-
return this.currentUser;
|
|
252
|
-
}
|
|
253
|
-
this.currentUser = yield this.loadUser(yield this.auth.currentAuthenticatedUser());
|
|
254
|
-
console.log('Starting idle service.');
|
|
255
|
-
yield this.idleService.start(); // Run idleService whenever user is logged in.
|
|
256
|
-
return this.currentUser;
|
|
257
|
-
});
|
|
258
|
-
}
|
|
259
|
-
mapTPVaultAccess(features) {
|
|
260
|
-
const tpVaultFeature = features === null || features === void 0 ? void 0 : features.tpVault;
|
|
261
|
-
return ((tpVaultFeature === null || tpVaultFeature === void 0 ? void 0 : tpVaultFeature.length) > 0 &&
|
|
262
|
-
tpVaultFeature.some((feature) => feature.toUpperCase() === 'ACCESS'));
|
|
263
|
-
}
|
|
264
|
-
loadUser(cognitoUser, password) {
|
|
265
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
266
|
-
const { currentUser, contactCard, userPlans, } = yield this.profileService.getCurrentUser();
|
|
267
|
-
if (currentUser.sessionEncryptionKey) {
|
|
268
|
-
this.persistService.setServerSessionEncryptionKey(yield JWK.asKey(currentUser.sessionEncryptionKey));
|
|
269
|
-
}
|
|
270
|
-
const userAttributes = yield this.auth.userAttributes(cognitoUser);
|
|
271
|
-
if (password) {
|
|
272
|
-
const passKey = (yield this.keyFactory.derivePassKey(Object.assign({ password }, currentUser.currentUserKey.passKey.passKeyParams))).jwk;
|
|
273
|
-
yield this.idleService.persistMasterKey(yield this.keyGraphService.unwrapWithPassKey(currentUser.currentUserKey.passKey.id, passKey, currentUser.currentUserKey.masterKey.id));
|
|
274
|
-
}
|
|
275
|
-
yield this.keyGraphService.populateKeys(currentUser.currentUserKey);
|
|
276
|
-
return {
|
|
277
|
-
id: currentUser.id,
|
|
278
|
-
sub: this.getUserAttribute('sub', userAttributes),
|
|
279
|
-
username: currentUser.username,
|
|
280
|
-
currentUserKey: currentUser.currentUserKey,
|
|
281
|
-
getAccessJwtToken: () => cognitoUser.getSignInUserSession().getAccessToken().getJwtToken(),
|
|
282
|
-
email: this.getUserAttribute('email', userAttributes),
|
|
283
|
-
emailVerified: this.getUserAttribute('email_verified', userAttributes) === 'true',
|
|
284
|
-
phone: this.getUserAttribute('phone_number', userAttributes),
|
|
285
|
-
phoneVerified: this.getUserAttribute('phone_number_verified', userAttributes) ===
|
|
286
|
-
'true',
|
|
287
|
-
contactCard: Object.assign({}, (yield this.profileService.decryptContactCard(contactCard))),
|
|
288
|
-
userDelete: currentUser.userDelete,
|
|
289
|
-
userPlans,
|
|
290
|
-
hasTPVaultAccess: this.mapTPVaultAccess(currentUser.features),
|
|
291
|
-
features: currentUser.features,
|
|
292
|
-
sessionEncryptionKey: currentUser.sessionEncryptionKey,
|
|
293
|
-
};
|
|
294
|
-
});
|
|
295
|
-
}
|
|
296
|
-
watchAuth() {
|
|
297
|
-
return this.hubSubject;
|
|
298
|
-
}
|
|
299
|
-
logout() {
|
|
300
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
301
|
-
this.currentUser = null;
|
|
302
|
-
this.keyService.purgeKeys();
|
|
303
|
-
this.keyGraphService.purgeKeys();
|
|
304
|
-
yield Promise.all([this.auth.signOut(), this.profileService.signOut()]);
|
|
305
|
-
});
|
|
306
|
-
}
|
|
307
|
-
getUserAttribute(attributeName, userAttributes) {
|
|
308
|
-
const userAttribute = userAttributes.find((x) => x.getName() === attributeName);
|
|
309
|
-
return userAttribute ? userAttribute.getValue() : null;
|
|
310
|
-
}
|
|
311
|
-
loadResetUser(password) {
|
|
312
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
313
|
-
const { tpPasswordResetUser: resetUser } = yield this.lrGraphQL.query({
|
|
314
|
-
query: TpPasswordResetUserQuery,
|
|
315
|
-
});
|
|
316
|
-
if (resetUser.sessionEncryptionKey) {
|
|
317
|
-
this.persistService.setServerSessionEncryptionKey(yield JWK.asKey(resetUser.sessionEncryptionKey));
|
|
318
|
-
}
|
|
319
|
-
// Update the keys
|
|
320
|
-
if (password) {
|
|
321
|
-
const passKey = (yield this.keyFactory.derivePassKey(Object.assign({ password }, resetUser.passKey.passKeyParams))).jwk;
|
|
322
|
-
yield this.idleService.persistMasterKey(yield this.keyGraphService.unwrapWithPassKey(resetUser.passKey.id, passKey, resetUser.masterKey.id));
|
|
323
|
-
}
|
|
324
|
-
this.keyService.populateKeys({
|
|
325
|
-
passKey: {
|
|
326
|
-
id: resetUser.passKey.id,
|
|
327
|
-
},
|
|
328
|
-
masterKey: {
|
|
329
|
-
id: resetUser.masterKey.id,
|
|
330
|
-
},
|
|
331
|
-
});
|
|
332
|
-
const userAttributes = yield this.auth.userAttributes(yield this.auth.currentAuthenticatedUser());
|
|
333
|
-
const sub = this.getUserAttribute('sub', userAttributes);
|
|
334
|
-
return Object.assign(Object.assign({}, (yield this.tpPasswordResetProcessorService.processTpPasswordResetUserNode(resetUser))), { sub });
|
|
335
|
-
});
|
|
336
|
-
}
|
|
337
|
-
refreshAccessToken() {
|
|
338
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
339
|
-
const cognitoUser = yield this.auth.currentAuthenticatedUser();
|
|
340
|
-
const refreshToken = cognitoUser.getSignInUserSession().getRefreshToken();
|
|
341
|
-
return new Promise((resolve, reject) => {
|
|
342
|
-
cognitoUser.refreshSession(refreshToken, (err, data) => {
|
|
343
|
-
if (err) {
|
|
344
|
-
console.error('Error refreshing token: ', err);
|
|
345
|
-
reject(err);
|
|
346
|
-
}
|
|
347
|
-
else {
|
|
348
|
-
console.log('Token refresh complete: ', data);
|
|
349
|
-
resolve(0);
|
|
350
|
-
}
|
|
351
|
-
});
|
|
352
|
-
});
|
|
353
|
-
});
|
|
354
|
-
}
|
|
355
|
-
completeRequest(newPassword) {
|
|
356
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
357
|
-
const resetUser = yield this.getResetUser(true);
|
|
358
|
-
if (resetUser.state !== TpClaimState.APPROVED) {
|
|
359
|
-
throw new LrBadStateException('Password reset request has not been approved.');
|
|
360
|
-
}
|
|
361
|
-
// --------------------------------------------------------------
|
|
362
|
-
// Prepare all materials to ensure there are no errors.
|
|
363
|
-
// --------------------------------------------------------------
|
|
364
|
-
const assemblyKey = yield this.recoverAssemblyKey(resetUser);
|
|
365
|
-
const { rootKey } = yield this.encryptionService.decrypt(assemblyKey, resetUser.assemblyCipherData);
|
|
366
|
-
console.log(rootKey);
|
|
367
|
-
// Making sure it's a valid key.
|
|
368
|
-
const rootKeyJwk = yield JWK.asKey(rootKey);
|
|
369
|
-
const masterKey = yield this.keyGraphService.getKey(resetUser.masterKey.id);
|
|
370
|
-
const masterKeyWrappedRootKey = yield this.encryptionService.encryptToString(masterKey.jwk, rootKeyJwk.toJSON(true));
|
|
371
|
-
// The new password
|
|
372
|
-
const newPassIdpResult = yield this.keyFactory.derivePassIdp(Object.assign({ password: newPassword }, resetUser.passKey.passIdpParams));
|
|
373
|
-
const newIdpPassword = this.passwordService.getPassIdpString(newPassIdpResult.jwk);
|
|
374
|
-
// --------------------------------------------------------------
|
|
375
|
-
// Get assembly key challenge
|
|
376
|
-
// --------------------------------------------------------------
|
|
377
|
-
const challenge = (yield this.lrGraphQL.lrMutate(new LrMutation({
|
|
378
|
-
mutation: CreateTpAssemblyKeyChallengeMutation,
|
|
379
|
-
variables: {
|
|
380
|
-
input: {},
|
|
381
|
-
},
|
|
382
|
-
}), {
|
|
383
|
-
includeKeyGraph: false,
|
|
384
|
-
})).createTpAssemblyKeyChallenge.challenge;
|
|
385
|
-
console.log(challenge);
|
|
386
|
-
// Sign the challenge
|
|
387
|
-
// Generate a client side nonce that's no in the server's control.
|
|
388
|
-
challenge.clientNonce = this.keyFactory.randomString(TP_PASSWORD_RESET_CLIENT_NONCE_LENGTH);
|
|
389
|
-
console.log(challenge);
|
|
390
|
-
const assemblyKeyVerifierPrk = yield this.encryptionService.decrypt(assemblyKey, resetUser.wrappedAssemblyKeyVerifierPrk);
|
|
391
|
-
const signedChallenge = yield this.encryptionService.sign(assemblyKeyVerifierPrk, challenge);
|
|
392
|
-
// --------------------------------------------------------------
|
|
393
|
-
// Change password for the original user
|
|
394
|
-
// --------------------------------------------------------------
|
|
395
|
-
const tempIdpPassword = (yield this.lrGraphQL.lrMutate(new LrMutation({
|
|
396
|
-
mutation: PreCompleteTpPasswordResetRequestMutation,
|
|
397
|
-
variables: {
|
|
398
|
-
input: {
|
|
399
|
-
signedChallenge: JSON.stringify(signedChallenge),
|
|
400
|
-
},
|
|
401
|
-
},
|
|
402
|
-
}), {
|
|
403
|
-
includeKeyGraph: false,
|
|
404
|
-
})).preCompleteTpPasswordResetRequest.idpPassword;
|
|
405
|
-
// --------------------------------------------------------------
|
|
406
|
-
// Login as the original user using new temporary password
|
|
407
|
-
// --------------------------------------------------------------
|
|
408
|
-
// At this point, the original account's password has been changed
|
|
409
|
-
// to a temporary password. It is no longer possible for the user
|
|
410
|
-
// to use the original password to login. Any successful login
|
|
411
|
-
// can only be using the temporary password. So it's safe to assume
|
|
412
|
-
// that we want to "complete" the password reset.
|
|
413
|
-
// The maybe 2FA so we listen for the auth event from Amplify.
|
|
414
|
-
const retPromise = new Promise((resolve) => {
|
|
415
|
-
const listener = (data) => __awaiter(this, void 0, void 0, function* () {
|
|
416
|
-
if (data.payload.event !== 'signIn') {
|
|
417
|
-
return;
|
|
418
|
-
}
|
|
419
|
-
Hub.remove('auth', listener);
|
|
420
|
-
console.log(data.payload);
|
|
421
|
-
yield this.auth.signIn(resetUser.username, newIdpPassword);
|
|
422
|
-
// Switch over to the new set of keys
|
|
423
|
-
yield this.lrGraphQL.lrMutate(new LrMutation({
|
|
424
|
-
mutation: CompleteTpPasswordResetRequestMutation,
|
|
425
|
-
variables: {
|
|
426
|
-
input: {
|
|
427
|
-
masterKeyWrappedRootKey,
|
|
428
|
-
masterKeyId: masterKey.id,
|
|
429
|
-
},
|
|
430
|
-
},
|
|
431
|
-
}));
|
|
432
|
-
resolve();
|
|
433
|
-
});
|
|
434
|
-
Hub.listen('auth', listener);
|
|
435
|
-
});
|
|
436
|
-
// Signin as the original user. Password has been reset to temporary one. It should return
|
|
437
|
-
// with NEW_PASSWORD_REQUIRED
|
|
438
|
-
let user = yield this.auth.signIn(resetUser.username, tempIdpPassword, {
|
|
439
|
-
noProxy: 'true',
|
|
440
|
-
});
|
|
441
|
-
if (user.challengeName !== 'NEW_PASSWORD_REQUIRED') {
|
|
442
|
-
throw new LrException({
|
|
443
|
-
message: 'Internal error. Expecting Cognito to have done a password reset after call to PreCompleteTpPasswordResetRequestMutation.',
|
|
444
|
-
});
|
|
445
|
-
}
|
|
446
|
-
// Set new password on Idp
|
|
447
|
-
// the awsFetch() function passes NEW_PASSWORD_REQUIRED directly to AWS without
|
|
448
|
-
// going through the proxy.
|
|
449
|
-
user = yield this.auth.completeNewPassword(user, newIdpPassword, {});
|
|
450
|
-
return retPromise;
|
|
451
|
-
});
|
|
452
|
-
}
|
|
453
|
-
recoverAssemblyKey(resetUser) {
|
|
454
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
455
|
-
// Recover the assembly key.
|
|
456
|
-
let assemblyKeyParams;
|
|
457
|
-
const prk = yield this.keyGraphService.getKey(resetUser.pxk.id);
|
|
458
|
-
const shares = yield Promise.all(resetUser.approvals
|
|
459
|
-
.filter((approval) => !!approval.receiverCipherPartialAssemblyKey)
|
|
460
|
-
.map((approval) => __awaiter(this, void 0, void 0, function* () {
|
|
461
|
-
const partialAssemblyKey = yield this.encryptionService.decrypt(prk, approval.receiverCipherPartialAssemblyKey);
|
|
462
|
-
if (assemblyKeyParams) {
|
|
463
|
-
if (JSON.stringify(assemblyKeyParams) !==
|
|
464
|
-
JSON.stringify(partialAssemblyKey.assemblyKeyParams)) {
|
|
465
|
-
throw new LrBadStateException('The assembly key parameters are different between the approvals.');
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
else {
|
|
469
|
-
assemblyKeyParams = partialAssemblyKey.assemblyKeyParams;
|
|
470
|
-
}
|
|
471
|
-
return partialAssemblyKey.slip39.share.mnemonics;
|
|
472
|
-
})));
|
|
473
|
-
console.log('recoverAssemblyKey()', shares);
|
|
474
|
-
const rawAssemblyKey = yield this.slip39Service.recoverSecret(shares, TP_PASSWORD_RESET_SLIP39_PASSPHRASE);
|
|
475
|
-
return JWK.asKey(Object.assign(Object.assign({}, assemblyKeyParams), { k: rawAssemblyKey }));
|
|
476
|
-
});
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
LifeReadyAuthService.ɵprov = i0.ɵɵdefineInjectable({ factory: function LifeReadyAuthService_Factory() { return new LifeReadyAuthService(i0.ɵɵinject(i1.LR_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.Slip39Service)); }, token: LifeReadyAuthService, providedIn: "root" });
|
|
480
|
-
LifeReadyAuthService.decorators = [
|
|
481
|
-
{ type: Injectable, args: [{
|
|
482
|
-
providedIn: 'root',
|
|
483
|
-
},] }
|
|
484
|
-
];
|
|
485
|
-
LifeReadyAuthService.ctorParameters = () => [
|
|
486
|
-
{ type: undefined, decorators: [{ type: Inject, args: [LR_CONFIG,] }] },
|
|
487
|
-
{ type: AuthClass },
|
|
488
|
-
{ type: KeyFactoryService },
|
|
489
|
-
{ type: KeyService },
|
|
490
|
-
{ type: ProfileService },
|
|
491
|
-
{ type: KeyGraphService },
|
|
492
|
-
{ type: PasswordService },
|
|
493
|
-
{ type: IdleService },
|
|
494
|
-
{ type: LrGraphQLService },
|
|
495
|
-
{ type: TpPasswordResetProcessorService },
|
|
496
|
-
{ type: PersistService },
|
|
497
|
-
{ type: EncryptionService },
|
|
498
|
-
{ type: Slip39Service }
|
|
499
|
-
];
|
|
500
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGlmZS1yZWFkeS1hdXRoLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiQzovUHJvamVjdHMvbmV3cmVwby9rYy1jbGllbnQvcHJvamVjdHMvY29yZS9zcmMvIiwic291cmNlcyI6WyJsaWIvYXV0aC9saWZlLXJlYWR5LWF1dGguc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsT0FBTyxFQUFFLE1BQU0sRUFBRSxVQUFVLEVBQUUsU0FBUyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBRTlELE9BQU8sRUFBRSxHQUFHLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUV4QyxPQUFPLEVBQWMsYUFBYSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBRWpELE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxtQ0FBbUMsQ0FBQztBQUNwRSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDekQsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQzFELE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQzlELE9BQU8sRUFDTCwyQkFBMkIsRUFDM0IscUJBQXFCLEVBQ3JCLG1CQUFtQixFQUNuQixXQUFXLEdBQ1osTUFBTSx1QkFBdUIsQ0FBQztBQUMvQixPQUFPLEVBS0wsY0FBYyxHQUNmLE1BQU0sY0FBYyxDQUFDO0FBQ3RCLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUNyRCxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFDM0QsT0FBTyxFQUNMLHNDQUFzQyxFQUN0QyxvQ0FBb0MsRUFDcEMseUNBQXlDLEVBQ3pDLHdCQUF3QixHQUN6QixNQUFNLDBDQUEwQyxDQUFDO0FBQ2xELE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUM3QyxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxxQ0FBcUMsQ0FBQztBQUN4RSxPQUFPLEVB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O2dCQUVGLElBQUksaUJBQWlCLEVBQUU7b0JBQ3JCLElBQ0UsSUFBSSxDQUFDLFNBQVMsQ0FBQyxpQkFBaUIsQ0FBQzt3QkFDakMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxrQkFBa0IsQ0FBQyxpQkFBaUIsQ0FBQyxFQUNwRDt3QkFDQSxNQUFNLElBQUksbUJBQW1CLENBQzNCLGtFQUFrRSxDQUNuRSxDQUFDO3FCQUNIO2lCQUNGO3FCQUFNO29CQUNMLGlCQUFpQixHQUFHLGtCQUFrQixDQUFDLGlCQUFpQixDQUFDO2lCQUMxRDtnQkFDRCxPQUFPLGtCQUFrQixDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUFDO1lBQ25ELENBQUMsQ0FBQSxDQUFDLENBQ0wsQ0FBQztZQUVGLE9BQU8sQ0FBQyxHQUFHLENBQUMsc0JBQXNCLEVBQUUsTUFBTSxDQUFDLENBQUM7WUFFNUMsTUFBTSxjQUFjLEdBQUcsTUFBTSxJQUFJLENBQUMsYUFBYSxDQUFDLGFBQWEsQ0FDM0QsTUFBTSxFQUNOLG1DQUFtQyxDQUNwQyxDQUFDO1lBRUYsT0FBTyxHQUFHLENBQUMsS0FBSyxpQ0FDWCxpQkFBaUIsS0FDcEIsQ0FBQyxFQUFFLGNBQWMsSUFDakIsQ0FBQztRQUNMLENBQUM7S0FBQTs7OztZQXRwQkYsVUFBVSxTQUFDO2dCQUNWLFVBQVUsRUFBRSxNQUFNO2FBQ25COzs7NENBT0ksTUFBTSxTQUFDLFNBQVM7WUF6Q1osU0FBUztZQVFULGlCQUFpQjtZQXpCakIsVUFBVTtZQUNWLGNBQWM7WUFGZCxlQUFlO1lBaUJmLGVBQWU7WUFRZixXQUFXO1lBRVgsZ0JBQWdCO1lBRWhCLCtCQUErQjtZQUUvQixjQUFjO1lBR2QsaUJBQWlCO1lBQ2pCLGFBQWEiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3QsIEluamVjdGFibGUsIGlzRGV2TW9kZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyBDb2duaXRvVXNlciB9IGZyb20gJ0Bhd3MtYW1wbGlmeS9hdXRoJztcclxuaW1wb3J0IHsgSHViIH0gZnJvbSAnQGF3cy1hbXBsaWZ5L2NvcmUnO1xyXG5pbXBvcnQgeyBDb2duaXRvVXNlckF0dHJpYnV0ZSB9IGZyb20gJ2FtYXpvbi1jb2duaXRvLWlkZW50aXR5LWpzJztcclxuaW1wb3J0IHsgT2JzZXJ2YWJsZSwgUmVwbGF5U3ViamVjdCB9IGZyb20gJ3J4anMnO1xyXG5pbXBvcnQgeyBQYXNzSWRwUGFyYW1zIH0gZnJvbSAnLi4vY3J5cHRvZ3JhcGh5L2NyeXB0b2dyYXBoeS50eXBlcyc7XHJcbmltcG9ydCB7IEtleUdyYXBoU2VydmljZSB9IGZyb20gJy4uL2NyeXB0b2dyYXBoeS9rZXktZ3JhcGguc2VydmljZSc7XHJcbmltcG9ydCB7IEtleVNlcnZpY2UgfSBmcm9tICcuLi9jcnlwdG9ncmFwaHkva2V5LnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBQcm9maWxlU2VydmljZSB9IGZyb20gJy4uL3VzZXJzL3Byb2ZpbGUuc2VydmljZSc7XHJcbmltcG9ydCB7IFBhc3N3b3JkQ2hhbmdlU3RhdHVzIH0gZnJvbSAnLi4vdXNlcnMvcHJvZmlsZS50eXBlcyc7XHJcbmltcG9ydCB7XHJcbiAgTHJDb25jdXJyZW50QWNjZXNzRXhjZXB0aW9uLFxyXG4gIExyQmFkUmVxdWVzdEV4Y2VwdGlvbixcclxuICBMckJhZFN0YXRlRXhjZXB0aW9uLFxyXG4gIExyRXhjZXB0aW9uLFxyXG59IGZyb20gJy4uL19jb21tb24vZXhjZXB0aW9ucyc7XHJcbmltcG9ydCB7XHJcbiAgQ29nbml0b0NoYWxsZW5nZVVzZXIsXHJcbiAgQ3VycmVudFVzZXIsXHJcbiAgVHBQYXNzd29yZFJlc2V0VXNlcixcclxuICBMb2dpblJlc3VsdCxcclxuICBSZWNvdmVyeVN0YXR1cyxcclxufSBmcm9tICcuL2F1dGgudHlwZXMnO1xyXG5pbXBvcnQgeyBQYXNzd29yZFNlcnZpY2UgfSBmcm9tICcuL3Bhc3N3b3JkLnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBBdXRoQ2xhc3MgfSBmcm9tICdAYXdzLWFtcGxpZnkvYXV0aC9saWItZXNtL0F1dGgnO1xyXG5pbXBvcnQge1xyXG4gIENvbXBsZXRlVHBQYXNzd29yZFJlc2V0UmVxdWVzdE11dGF0aW9uLFxyXG4gIENyZWF0ZVRwQXNzZW1ibHlLZXlDaGFsbGVuZ2VNdXRhdGlvbixcclxuICBQcmVDb21wbGV0ZVRwUGFzc3dvcmRSZXNldFJlcXVlc3RNdXRhdGlvbixcclxuICBUcFBhc3N3b3JkUmVzZXRVc2VyUXVlcnksXHJcbn0gZnJvbSAnLi4vdHJ1c3RlZC1wYXJ0aWVzL3RwLXBhc3N3b3JkLXJlc2V0LmdxbCc7XHJcbmltcG9ydCB7IElkbGVTZXJ2aWNlIH0gZnJvbSAnLi9pZGxlLnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBLZXlGYWN0b3J5U2VydmljZSB9IGZyb20gJy4uL2NyeXB0b2dyYXBoeS9rZXktZmFjdG9yeS5zZXJ2aWNlJztcclxuaW1wb3J0IHsgTHJHcmFwaFFMU2VydmljZSwgTHJNdXRhdGlvbiB9IGZyb20gJy4uL2FwaS9sci1ncmFwaHFsJztcclxuaW1wb3J0IHsgVHBDbGFpbVN0YXRlLCBUcFBhc3N3b3JkUmVzZXRVc2VyTm9kZSB9IGZyb20gJy4uL2FwaS90eXBlcyc7XHJcbmltcG9ydCB7IFRwUGFzc3dvcmRSZXNldFByb2Nlc3NvclNlcnZpY2UgfSBmcm9tICcuLi9hcGkvcXVlcnktcHJvY2Vzc29yL3RwLXBhc3N3b3JkLXJlc2V0LXByb2Nlc3Nvci5zZXJ2aWNlJztcclxuaW1wb3J0IHsgU2V0U2Vzc2lvbkVuY3J5cHRpb25LZXlNdXRhdGlvbiB9IGZyb20gJy4vYXV0aC5ncWwnO1xyXG5pbXBvcnQgeyBQZXJzaXN0U2VydmljZSB9IGZyb20gJy4uL2FwaS9wZXJzaXN0LnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBKV0sgfSBmcm9tICdub2RlLWpvc2UnO1xyXG5pbXBvcnQgeyBMaWZlUmVhZHlDb25maWcsIExSX0NPTkZJRyB9IGZyb20gJy4uL2xpZmUtcmVhZHkuY29uZmlnJztcclxuaW1wb3J0IHsgRW5jcnlwdGlvblNlcnZpY2UgfSBmcm9tICcuLi9jcnlwdG9ncmFwaHkvZW5jcnlwdGlvbi5zZXJ2aWNlJztcclxuaW1wb3J0IHsgU2xpcDM5U2VydmljZSB9IGZyb20gJy4uL2NyeXB0b2dyYXBoeS9zbGlwMzkuc2VydmljZSc7XHJcbmltcG9ydCB7XHJcbiAgVFBfUEFTU1dPUkRfUkVTRVRfQ0xJRU5UX05PTkNFX0xFTkdUSCxcclxuICBUUF9QQVNTV09SRF9SRVNFVF9TTElQMzlfUEFTU1BIUkFTRSxcclxuICBUUF9QQVNTV09SRF9SRVNFVF9VU0VSTkFNRV9TVUZGSVgsXHJcbn0gZnJvbSAnLi4vdHJ1c3RlZC1wYXJ0aWVzL3RwLXBhc3N3b3JkLXJlc2V0LmNvbnN0YW50cyc7XHJcblxyXG5leHBvcnQgY29uc3QgaW5pdGlhbGlzZUF1dGggPSAoYXV0aFNlcnZpY2U6IExpZmVSZWFkeUF1dGhTZXJ2aWNlKSA9PiB7XHJcbiAgcmV0dXJuICgpID0+IGF1dGhTZXJ2aWNlLmluaXRpYWxpc2UoKTtcclxufTtcclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgTG9naW5PcHRpb25zIHtcclxuICB0cFBhc3N3b3JkUmVzZXRBdXRvQ29tcGxldGU/OiBib29sZWFuO1xyXG59XHJcblxyXG5ASW5qZWN0YWJsZSh7XHJcbiAgcHJvdmlkZWRJbjogJ3Jvb3QnLFxyXG59KVxyXG5leHBvcnQgY2xhc3MgTGlmZVJlYWR5QXV0aFNlcnZpY2Uge1xyXG4gIHByaXZhdGUgaHViU3ViamVjdDogUmVwbGF5U3ViamVjdDxhbnk+ID0gbmV3IFJlcGxheVN1YmplY3Q8YW55PigxKTtcclxuICBwcml2YXRlIGN1cnJlbnRVc2VyOiBDdXJyZW50VXNlcjtcclxuICBwcml2YXRlIGN1cnJlbnRSZXNldFVzZXI6IFRwUGFzc3dvcmRSZXNldFVzZXI7XHJcblxyXG4gIGNvbnN0cnVjdG9yKFxyXG4gICAgQEluamVjdChMUl9DT05GSUcpIHByaXZhdGUgY29uZmlnOiBMaWZlUmVhZHlDb25maWcsXHJcbiAgICBwcml2YXRlIGF1dGg6IEF1dGhDbGFzcyxcclxuICAgIHByaXZhdGUga2V5RmFjdG9yeTogS2V5RmFjdG9yeVNlcnZpY2UsXHJcbiAgICBwcml2YXRlIGtleVNlcnZpY2U6IEtleVNlcnZpY2UsXHJcbiAgICBwcml2YXRlIHByb2ZpbGVTZXJ2aWNlOiBQcm9maWxlU2VydmljZSxcclxuICAgIHByaXZhdGUga2V5R3JhcGhTZXJ2aWNlOiBLZXlHcmFwaFNlcnZpY2UsXHJcbiAgICBwcml2YXRlIHBhc3N3b3JkU2VydmljZTogUGFzc3dvcmRTZXJ2aWNlLFxyXG4gICAgcHJpdmF0ZSBpZGxlU2VydmljZTogSWRsZVNlcnZpY2UsXHJcbiAgICBwcml2YXRlIGxyR3JhcGhRTDogTHJHcmFwaFFMU2VydmljZSxcclxuICAgIHByaXZhdGUgdHBQYXNzd29yZFJlc2V0UHJvY2Vzc29yU2VydmljZTogVHBQYXNzd29yZFJlc2V0UHJvY2Vzc29yU2VydmljZSxcclxuICAgIHByaXZhdGUgcGVyc2lzdFNlcnZpY2U6IFBlcnNpc3RTZXJ2aWNlLFxyXG4gICAgcHJpdmF0ZSBlbmNyeXB0aW9uU2VydmljZTogRW5jcnlwdGlvblNlcnZpY2UsXHJcbiAgICBwcml2YXRlIHNsaXAzOVNlcnZpY2U6IFNsaXAzOVNlcnZpY2VcclxuICApIHt9XHJcblxyXG4gIHB1YmxpYyBhc3luYyBpbml0aWFsaXNlKCkge1xyXG4gICAgSHViLmxpc3RlbignYXV0aCcsIChkYXRhKSA9PiB0aGlzLmh1YlN1YmplY3QubmV4dChkYXRhLnBheWxvYWQpKTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgYXN5bmMgbG9naW5JZHBJbXBsKFxyXG4gICAgZW1haWxPclBob25lOiBzdHJpbmcsXHJcbiAgICBwYXNzd29yZDogc3RyaW5nLFxyXG4gICAgcGFzc0lkcFBhcmFtczogUGFzc0lkcFBhcmFtcyxcclxuICAgIHJlY292ZXJ5U3RhdHVzOiBSZWNvdmVyeVN0YXR1c1xyXG4gICk6IFByb21pc2U8Q29nbml0b0NoYWxsZW5nZVVzZXI+IHtcclxuICAgIGNvbnN0IHBhc3NJZHBSZXN1bHQgPSBhd2FpdCB0aGlzLmtleUZhY3RvcnkuZGVyaXZlUGFzc0lkcCh7XHJcbiAgICAgIHBhc3N3b3JkLFxyXG4gICAgICAuLi5wYXNzSWRwUGFyYW1zLFxyXG4gICAgfSk7XHJcbiAgICAvLyBVc2UgdGhlIGRlcml2ZWQgcGFzc3dvcmQgdG8gc2lnbmluIHdpdGggY29nbml0b1xyXG4gICAgY29uc3QgdXNlciA9IGF3YWl0IHRoaXMuYXV0aC5zaWduSW4oXHJcbiAgICAgIGVtYWlsT3JQaG9uZSxcclxuICAgICAgdGhpcy5wYXNzd29yZFNlcnZpY2UuZ2V0UGFzc0lkcFN0cmluZyhwYXNzSWRwUmVzdWx0Lmp3aylcclxuICAgICk7XHJcblxyXG4gICAgdXNlci5yZWNvdmVyeVN0YXR1cyA9IHJlY292ZXJ5U3RhdHVzO1xyXG5cclxuICAgIHJldHVybiB1c2VyO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBhc3luYyBsb2dpbklkcChcclxuICAgIGVtYWlsT3JQaG9uZTogc3RyaW5nLFxyXG4gICAgcGFzc3dvcmQ6IHN0cmluZ1xyXG4gICk6IFByb21pc2U8Q29nbml0b0NoYWxsZW5nZVVzZXI+IHtcclxuICAgIC8vIERvd25sb2FkIHRoZSBzYWx0IG5lZWRlZCB0byBkZXJpdmUgdGhlIFBhc3NJZHBcclxuICAgIGNvbnN0IHBhc3NJZHBBcGlSZXN1bHQgPSBhd2FpdCB0aGlzLnByb2ZpbGVTZXJ2aWNlLmdldFBhc3NJZHBQYXJhbXMoXHJcbiAgICAgIGVtYWlsT3JQaG9uZVxyXG4gICAgKTtcclxuXHJcbiAgICBpZiAoXHJcbiAgICAgIHBhc3NJZHBBcGlSZXN1bHQucGFzc3dvcmRDaGFuZ2VTdGF0dXMgPT09IFBhc3N3b3JkQ2hhbmdlU3RhdHVzLkluUHJvZ3Jlc3NcclxuICAgICkge1xyXG4gICAgICB0aHJvdyBuZXcgTHJDb25jdXJyZW50QWNjZXNzRXhjZXB0aW9uKCdBIHBhc3N3b3JkIGNoYW5nZSBpcyBpbiBwcm9ncmVzcycpO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChcclxuICAgICAgcGFzc0lkcEFwaVJlc3VsdC5wYXNzd29yZENoYW5nZVN0YXR1cyA9PT0gUGFzc3dvcmRDaGFuZ2VTdGF0dXMuUmVjb3ZlcnlcclxuICAgICkge1xyXG4gICAgICBjb25zb2xlLmxvZygnSW4gcmVjb3ZlcnkgbW9kZS4nKTtcclxuICAgICAgLy8gTGV0J3Mgc2F5IHdlIGRvbid0IGtub3cgaWYgdGhlIHBhc3N3b3JkIGlzIHRoZSBuZXcgb25lIG9yIHRoZSBvbGQgb25lLiBXZSBqdXN0IGhhdmUgdG8gdHJ5IGJvdGguXHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgY29uc3QgdXNlciA9IGF3YWl0IHRoaXMubG9naW5JZHBJbXBsKFxyXG4gICAgICAgICAgZW1haWxPclBob25lLFxyXG4gICAgICAgICAgcGFzc3dvcmQsXHJcbiAgICAgICAgICBwYXNzSWRwQXBpUmVzdWx0Lm5ld1Bhc3NJZHBQYXJhbXMsXHJcbiAgICAgICAgICBSZWNvdmVyeVN0YXR1cy5ORVdfUEFTU1dPUkRcclxuICAgICAgICApO1xyXG4gICAgICAgIC8vIE5ldyBwYXNzd29yZCB3b3JrZWQuIExldCdzIHNldCB0byB0aGUgY3VycmVudCBwYXNzd29yZFxyXG5cclxuICAgICAgICAvLyAtLVBvdGVudGlhbCBGYWlsdXJlIFBvaW50IDEtLVxyXG4gICAgICAgIC8vIGlmIGNoYW5nZVBhc3N3b3JkQ29tcGxldGUoKSBkb2Vzbid0IGdldCBjYWxsZWQsIHRoZW4gaXQgc2hvdWxkIHJlbWFpblxyXG5cclxuICAgICAgICBjb25zb2xlLmxvZygnTmV3IHBhc3N3b3JkIHdvcmtzIScpO1xyXG5cclxuICAgICAgICByZXR1cm4gdXNlcjtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAvLyBKdXN0IGJ1YmJsZSB1cCBhbnkgb3RoZXIgdHlwZSBvZiBlcnJvci5cclxuICAgICAgICBpZiAoZXJyb3IuY29kZSAhPT0gJ05vdEF1dGhvcml6ZWRFeGNlcHRpb24nKSB7XHJcbiAgICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgICB9XHJcbiAgICAgICAgLy8gcGFzcywgdHJ5IGFnYWluIGFzc3VtaW5nIGl0J3MgdGhlIG9sZCBwYXNzd29yZFxyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBOb3cgYXNzdW1lIGl0J3MgdGhlIHByZXZpb3VzIHBhc3N3b3JkLiBBbnkgZXhjZXB0aW9uIGlzIGFsbG93ZWQgdG8gYnViYmxlIHVwLlxyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGNvbnN0IHVzZXIgPSBhd2FpdCB0aGlzLmxvZ2luSWRwSW1wbChcclxuICAgICAgICAgIGVtYWlsT3JQaG9uZSxcclxuICAgICAgICAgIHBhc3N3b3JkLFxyXG4gICAgICAgICAgcGFzc0lkcEFwaVJlc3VsdC5jdXJyZW50UGFzc0lkcFBhcmFtcyxcclxuICAgICAgICAgIFJlY292ZXJ5U3RhdHVzLk9MRF9QQVNTV09SRFxyXG4gICAgICAgICk7XHJcbiAgICAgICAgLy8gT2xkIHBhc3N3b3JkIHdvcmtlZC5cclxuICAgICAgICBjb25zb2xlLmxvZygnT2xkIHBhc3N3b3JkIHdvcmtzIScpO1xyXG5cclxuICAgICAgICByZXR1cm4gdXNlcjtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAvLyBKdXN0IGJ1YmJsZSB1cCBhbnkgb3RoZXIgdHlwZSBvZiBlcnJvci5cclxuICAgICAgICB0aHJvdyBlcnJvci5jb2RlID09PSAnTm90QXV0aG9yaXplZEV4Y2VwdGlvbidcclxuICAgICAgICAgID8gbmV3IExyQmFkUmVxdWVzdEV4Y2VwdGlvbihcclxuICAgICAgICAgICAgICAnVGhlIHBhc3N3b3JkIGNoYW5nZSByZXF1ZXN0IHdhcyBpbnRlcnJ1cHRlZCwgcGxlYXNlIHRyeSB0byBsb2dpbiB3aXRoIGJvdGggeW91ciBuZXcgYW5kIG9sZCBwYXNzd29yZCdcclxuICAgICAgICAgICAgKVxyXG4gICAgICAgICAgOiBlcnJvcjtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIFRyeSBhZ2FpbnN0IGFzIHRoZSBUUCBwYXNzd29yZCByZXNldCBhY2NvdW50XHJcbiAgICBpZiAocGFzc0lkcEFwaVJlc3VsdC50cFBhc3N3b3JkUmVzZXQpIHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICAvLyBUUCBwYXNzd29yZCByZXNldCBpcyBpbiBwcm9jZXNzLiBXZSBuZWVkIHRvIHRyeSB0aGUgcGFzc3dvcmQgYWdhaW5zdCBib3RoXHJcbiAgICAgICAgLy8gb3JpZ2luYWwgYWNjb3VudCBhbmQgdGhlIG5ldyByZXNldCBhY2NvdW50LlxyXG4gICAgICAgIGNvbnN0IHJlc2V0ID0gcGFzc0lkcEFwaVJlc3VsdC50cFBhc3N3b3JkUmVzZXQ7XHJcbiAgICAgICAgY29uc3QgcmV0ID0gYXdhaXQgdGhpcy5sb2dpbklkcEltcGwoXHJcbiAgICAgICAgICByZXNldC5yZXNldFVzZXJuYW1lLFxyXG4gICAgICAgICAgcGFzc3dvcmQsXHJcbiAgICAgICAgICByZXNldC5wYXNzSWRwUGFyYW1zLFxyXG4gICAgICAgICAgUmVjb3ZlcnlTdGF0dXMuTk9ORVxyXG4gICAgICAgICk7XHJcbiAgICAgICAgcmV0LmlzVHBQYXNzd29yZFJlc2V0VXNlciA9IHRydWU7XHJcblxyXG4gICAgICAgIHJldHVybiByZXQ7XHJcbiAgICAgIH0gY2F0Y2ggKGVycikge1xyXG4gICAgICAgIC8vIGNvbnRpbnVlLCB0cnkgYWdhaW4gYXMgcmVndWxhciB1c2VyLlxyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTG9naW4gYXMgcmVndWxhciB1c2VyXHJcbiAgICByZXR1cm4gYXdhaXQgdGhpcy5sb2dpbklkcEltcGwoXHJcbiAgICAgIGVtYWlsT3JQaG9uZSxcclxuICAgICAgcGFzc3dvcmQsXHJcbiAgICAgIHBhc3NJZHBBcGlSZXN1bHQuY3VycmVudFBhc3NJZHBQYXJhbXMsXHJcbiAgICAgIFJlY292ZXJ5U3RhdHVzLk5PTkVcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICBwcm90ZWN0ZWQgYXN5bmMgaGFuZGxlU2Vzc2lvbkVuY3J5cHRpb25LZXkoKSB7XHJcbiAgICBpZiAodGhpcy5jb25maWcuZGlzYWJsZVNlc3Npb25FbmNyeXB0aW9uS2V5KSB7XHJcbiAgICAgIGlmICghaXNEZXZNb2RlKCkpIHtcclxuICAgICAgICBjb25zdCBtc2cgPVxyXG4gICAgICAgICAgJ1lvdSBzaG91bGQgbm90IHNldCBkaXNhYmxlU2Vzc2lvbkVuY3J5cHRpb25LZXk9VHJ1ZSBpbiBtb2RlIHByb2QuIEl0IGRlZmF1bHRzIHRvIGZhbHNlLic7XHJcbiAgICAgICAgY29uc29sZS5lcnJvcihtc2cpO1xyXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihtc2cpO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGNvbnNvbGUud2FybihcclxuICAgICAgICAgICdZb3UgaGF2ZSBzZXQgZGlzYWJsZVNlc3Npb25FbmNyeXB0aW9uS2V5PVRydWUuIE1ha2Ugc3VyZSBub3QgdG8gZG8gdGhpcyBpbiBwcm9kIG1vZGUuJ1xyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIFNldCB0aGUgc2Vzc2lvbiBrZXkgdG8gYSBuZXcgZW5jcnlwdGlvbiBrZXkgZm9yIHRoaXMgc2Vzc2lvblxyXG4gICAgICBjb25zdCBzZXNzaW9uRW5jcnlwdGlvbktleSA9IGF3YWl0IHRoaXMua2V5RmFjdG9yeS5jcmVhdGVLZXkoKTtcclxuICAgICAgYXdhaXQgdGhpcy5sckdyYXBoUUwubHJNdXRhdGUoXHJcbiAgICAgICAgbmV3IExyTXV0YXRpb24oe1xyXG4gICAgICAgICAgbXV0YXRpb246IFNldFNlc3Npb25FbmNyeXB0aW9uS2V5TXV0YXRpb24sXHJcbiAgICAgICAgICB2YXJpYWJsZXM6IHtcclxuICAgICAgICAgICAgaW5wdXQ6IHtcclxuICAgICAgICAgICAgICBzZXNzaW9uRW5jcnlwdGlvbktleTogSlNPTi5zdHJpbmdpZnkoXHJcbiAgICAgICAgICAgICAgICBzZXNzaW9uRW5jcnlwdGlvbktleS50b0pTT04odHJ1ZSlcclxuICAgICAgICAgICAgICApLFxyXG4gICAgICAgICAgICB9LFxyXG4gICAgICAgICAgfSxcclxuICAgICAgICB9KSxcclxuICAgICAgICB7XHJcbiAgICAgICAgICBpbmNsdWRlS2V5R3JhcGg6IGZhbHNlLFxyXG4gICAgICAgIH1cclxuICAgICAgKTtcclxuXHJcbiAgICAgIHRoaXMucGVyc2lzdFNlcnZpY2Uuc2V0U2VydmVyU2Vzc2lvbkVuY3J5cHRpb25LZXkoc2Vzc2lvbkVuY3J5cHRpb25LZXkpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJvdGVjdGVkIGFzeW5jIGhhbmRsZVBvc3RBdXRoKGNvZ25pdG9Vc2VyOiBDb2duaXRvQ2hhbGxlbmdlVXNlcikge1xyXG4gICAgYXdhaXQgdGhpcy5oYW5kbGVQYXNzd29yZFJlY292ZXJ5KGNvZ25pdG9Vc2VyKTtcclxuICAgIGF3YWl0IHRoaXMuaGFuZGxlU2Vzc2lvbkVuY3J5cHRpb25LZXkoKTtcclxuICB9XHJcblxyXG4gIHB1YmxpYyBhc3luYyBsb2dpbihcclxuICAgIGVtYWlsT3JQaG9uZTogc3RyaW5nLFxyXG4gICAgcGFzc3dvcmQ6IHN0cmluZyxcclxuICAgIHsgdHBQYXNzd29yZFJlc2V0QXV0b0NvbXBsZXRlID0gdHJ1ZSB9OiBMb2dpbk9wdGlvbnMgPSB7fVxyXG4gICkge1xyXG4gICAgbGV0IGxvZ2luUmVzdWx0ID0gYXdhaXQgdGhpcy5sb2dpbkltcGwoZW1haWxPclBob25lLCBwYXNzd29yZCk7XHJcblxyXG4gICAgaWYgKFxyXG4gICAgICB0cFBhc3N3b3JkUmVzZXRBdXRvQ29tcGxldGUgJiZcclxuICAgICAgbG9naW5SZXN1bHQucmVzZXRVc2VyPy5zdGF0ZSA9PT0gVHBDbGFpbVN0YXRlLkFQUFJPVkVEXHJcbiAgICApIHtcclxuICAgICAgYXdhaXQgdGhpcy5jb21wbGV0ZVJlcXVlc3QocGFzc3dvcmQpO1xyXG4gICAgICBsb2dpblJlc3VsdCA9IGF3YWl0IHRoaXMubG9naW5JbXBsKGVtYWlsT3JQaG9uZSwgcGFzc3dvcmQpO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiBsb2dpblJlc3VsdDtcclxuICB9XHJcblxyXG4gIHB1YmxpYyBhc3luYyBsb2dpbkltcGwoXHJcbiAgICBlbWFpbE9yUGhvbmU6IHN0cmluZyxcclxuICAgIHBhc3N3b3JkOiBzdHJpbmdcclxuICApOiBQcm9taXNlPExvZ2luUmVzdWx0PiB7XHJcbiAgICBhd2FpdCB0aGlzLmxvZ291dCgpO1xyXG4gICAgY29uc3QgY29nbml0b1VzZXIgPSBhd2FpdCB0aGlzLmxvZ2luSWRwKGVtYWlsT3JQaG9uZSwgcGFzc3dvcmQpO1xyXG5cclxuICAgIC8vIHRvZG86IE1lZXQgTUZBIGNoYWxsZW5nZXMuXHJcbiAgICBpZiAoWydTTVNfTUZBJywgJ1NPRlRXQVJFX1RPS0VOX01GQSddLmluY2x1ZGVzKGNvZ25pdG9Vc2VyLmNoYWxsZW5nZU5hbWUpKSB7XHJcbiAgICAgIHJldHVybiB7IGhhc0NoYWxsZW5nZTogdHJ1ZSwgY2hhbGxlbmdlOiBjb2duaXRvVXNlciB9O1xyXG4gICAgfVxyXG5cclxuICAgIGF3YWl0IHRoaXMuaGFuZGxlUG9zdEF1dGgoY29nbml0b1VzZXIpO1xyXG5cclxuICAgIGlmIChjb2duaXRvVXNlci5pc1RwUGFzc3dvcmRSZXNldFVzZXIpIHtcclxuICAgICAgLy8gQXNzdW1pbmcgdGhlcmUgaXMgbm8gTUZBIG9uIHRoZSBUUCByZXNldCB1c2VyLlxyXG4gICAgICBjb25zdCByZXNldFVzZXIgPSBhd2FpdCB0aGlzLmxvYWRSZXNldFVzZXIocGFzc3dvcmQpO1xyXG4gICAgICByZXR1cm4geyBoYXNDaGFsbGVuZ2U6IGZhbHNlLCByZXNldFVzZXIgfTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGNvbnN0IHVzZXIgPSBhd2FpdCB0aGlzLmxvYWRVc2VyKGNvZ25pdG9Vc2VyLCBwYXNzd29yZCk7XHJcbiAgICAgIGF3YWl0IHRoaXMuaWRsZVNlcnZpY2Uuc3RhcnQoKTsgLy8gUnVuIGlkbGVTZXJ2aWNlIHdoZW5ldmVyIHVzZXIgaXMgbG9nZ2VkIGluLlxyXG4gICAgICByZXR1cm4geyBoYXNDaGFsbGVuZ2U6IGZhbHNlLCB1c2VyIH07XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBUT0RPIDxBWj4gV2UgbmVlZCB0byBoYW5kbGUgdGhlIGlzVHBQYXNzd29yZFJlc2V0VXNlcj1UcnVlIGNhc2UgaGVyZSBhZnRlciBNRkEgYXMgd2VsbC5cclxuICBwdWJsaWMgYXN5bmMgdmVyaWZ5TG9naW4oXHJcbiAgICBjaGFsbGVuZ2U6IENvZ25pdG9DaGFsbGVuZ2VVc2VyLFxyXG4gICAgcGFzc3dvcmQ6IHN0cmluZyxcclxuICAgIHJlbWVtYmVyTWU6IGJvb2xlYW4sXHJcbiAgICBjb2RlOiBzdHJpbmdcclxuICApOiBQcm9taXNlPEN1cnJlbnRVc2VyPiB7XHJcbiAgICBhd2FpdCB0aGlzLmF1dGguY29uZmlybVNpZ25JbihjaGFsbGVuZ2UsIGNvZGUsIGNoYWxsZW5nZS5jaGFsbGVuZ2VOYW1lKTtcclxuXHJcbiAgICAvLyBUT0RPOiB0aGlzLmF1dGguY29uZmlybVNpZ25JbigpIGNvdWxkIHJldHVybiBhbm90aGVyIGNoYWxsZW5nZS5cclxuXHJcbiAgICBjb25zdCBjb2duaXRvVXNlcjogQ29nbml0b1VzZXIgPSBhd2FpdCB0aGlzLmF1dGguY3VycmVudEF1dGhlbnRpY2F0ZWRVc2VyKCk7XHJcblxyXG4gICAgYXdhaXQgdGhpcy5oYW5kbGVQb3N0QXV0aChjaGFsbGVuZ2UpO1xyXG5cclxuICAgIGNvbnN0IHVzZXIgPSBhd2FpdCB0aGlzLmxvYWRVc2VyKGNvZ25pdG9Vc2VyLCBwYXNzd29yZCk7XHJcblxyXG4gICAgaWYgKHJlbWVtYmVyTWUpIHtcclxuICAgICAgY29nbml0b1VzZXIuc2V0RGV2aWNlU3RhdHVzUmVtZW1iZXJlZCh7XHJcbiAgICAgICAgb25TdWNjZXNzOiAoKSA9PiB7fSxcclxuICAgICAgICBvbkZhaWx1cmU6IChlKSA9PiBjb25zb2xlLmVycm9yKGUpLFxyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gdXNlcjtcclxuICB9XHJcblxyXG4gIGFzeW5jIGhhbmRsZVBhc3N3b3JkUmVjb3ZlcnkodXNlcjogQ29nbml0b0NoYWxsZW5nZVVzZXIpIHtcclxuICAgIGlmICh1c2VyLnJlY292ZXJ5U3RhdHVzICE9PSBSZWNvdmVyeVN0YXR1cy5OT05FKSB7XHJcbiAgICAgIGNvbnN0IGp3dFRva2VuID0gdXNlclxyXG4gICAgICAgIC5nZXRTaWduSW5Vc2VyU2Vzc2lvbigpXHJcbiAgICAgICAgLmdldEFjY2Vzc1Rva2VuKClcclxuICAgICAgICAuZ2V0Snd0VG9rZW4oKTtcclxuICAgICAgYXdhaXQgdGhpcy5wYXNzd29yZFNlcnZpY2UuY2hhbmdlUGFzc3dvcmRDb21wbGV0ZShcclxuICAgICAgICBqd3RUb2tlbixcclxuICAgICAgICB1c2VyLnJlY292ZXJ5U3RhdHVzID09PSBSZWNvdmVyeVN0YXR1cy5ORVdfUEFTU1dPUkRcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGFzeW5jIGdldFVzZXJPclJlc2V0VXNlcihcclxuICAgIHJlbG9hZDogYm9vbGVhbiA9IGZhbHNlXHJcbiAgKTogUHJvbWlzZTxDdXJyZW50VXNlciB8IFRwUGFzc3dvcmRSZXNldFVzZXI+IHtcclxuICAgIGNvbnN0IGNvZ25pdG9Vc2VyID0gYXdhaXQgdGhpcy5hdXRoLmN1cnJlbnRBdXRoZW50aWNhdGVkVXNlcigpO1xyXG5cclxuICAgIGlmIChjb2duaXRvVXNlci5nZXRVc2VybmFtZSgpLmVuZHNXaXRoKFRQX1BBU1NXT1JEX1JFU0VUX1VTRVJOQU1FX1NVRkZJWCkpIHtcclxuICAgICAgcmV0dXJuIHRoaXMuZ2V0UmVzZXRVc2VyKHJlbG9hZCk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICByZXR1cm4gdGhpcy5nZXRVc2VyKHJlbG9hZCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBhc3luYyBnZXRSZXNldFVzZXIocmVsb2FkOiBib29sZWFuID0gZmFsc2UpOiBQcm9taXNlPFRwUGFzc3dvcmRSZXNldFVzZXI+IHtcclxuICAgIGlmICghcmVsb2FkICYmIHRoaXMuY3VycmVudFJlc2V0VXNlcikge1xyXG4gICAgICByZXR1cm4gdGhpcy5jdXJyZW50UmVzZXRVc2VyO1xyXG4gICAgfVxyXG5cclxuICAgIHRoaXMuY3VycmVudFJlc2V0VXNlciA9IGF3YWl0IHRoaXMubG9hZFJlc2V0VXNlcigpO1xyXG5cclxuICAgIGF3YWl0IHRoaXMuaWRsZVNlcnZpY2Uuc3RhcnQoKTsgLy8gUnVuIGlkbGVTZXJ2aWNlIHdoZW5ldmVyIHVzZXIgaXMgbG9nZ2VkIGluLlxyXG5cclxuICAgIHJldHVybiB0aGlzLmN1cnJlbnRSZXNldFVzZXI7XHJcbiAgfVxyXG5cclxuICBhc3luYyBnZXRVc2VyKHJlbG9hZDogYm9vbGVhbiA9IGZhbHNlKTogUHJvbWlzZTxDdXJyZW50VXNlcj4ge1xyXG4gICAgaWYgKCFyZWxvYWQgJiYgdGhpcy5jdXJyZW50VXNlcikge1xyXG4gICAgICByZXR1cm4gdGhpcy5jdXJyZW50VXNlcjtcclxuICAgIH1cclxuICAgIHRoaXMuY3VycmVudFVzZXIgPSBhd2FpdCB0aGlzLmxvYWRVc2VyKFxyXG4gICAgICBhd2FpdCB0aGlzLmF1dGguY3VycmVudEF1dGhlbnRpY2F0ZWRVc2VyKClcclxuICAgICk7XHJcbiAgICBjb25zb2xlLmxvZygnU3RhcnRpbmcgaWRsZSBzZXJ2aWNlLicpO1xyXG4gICAgYXdhaXQgdGhpcy5pZGxlU2VydmljZS5zdGFydCgpOyAvLyBSdW4gaWRsZVNlcnZpY2Ugd2hlbmV2ZXIgdXNlciBpcyBsb2dnZWQgaW4uXHJcbiAgICByZXR1cm4gdGhpcy5jdXJyZW50VXNlcjtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgbWFwVFBWYXVsdEFjY2VzcyhmZWF0dXJlcz86IGFueSk6IGJvb2xlYW4ge1xyXG4gICAgY29uc3QgdHBWYXVsdEZlYXR1cmUgPSBmZWF0dXJlcz8udHBWYXVsdDtcclxuICAgIHJldHVybiAoXHJcbiAgICAgIHRwVmF1bHRGZWF0dXJlPy5sZW5ndGggPiAwICYmXHJcbiAgICAgIHRwVmF1bHRGZWF0dXJlLnNvbWUoKGZlYXR1cmUpID0+IGZlYXR1cmUudG9VcHBlckNhc2UoKSA9PT0gJ0FDQ0VTUycpXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBhc3luYyBsb2FkVXNlcihcclxuICAgIGNvZ25pdG9Vc2VyOiBDb2duaXRvVXNlcixcclxuICAgIHBhc3N3b3JkPzogc3RyaW5nXHJcbiAgKTogUHJvbWlzZTxDdXJyZW50VXNlcj4ge1xyXG4gICAgY29uc3Qge1xyXG4gICAgICBjdXJyZW50VXNlcixcclxuICAgICAgY29udGFjdENhcmQsXHJcbiAgICAgIHVzZXJQbGFucyxcclxuICAgIH0gPSBhd2FpdCB0aGlzLnByb2ZpbGVTZXJ2aWNlLmdldEN1cnJlbnRVc2VyKCk7XHJcblxyXG4gICAgaWYgKGN1cnJlbnRVc2VyLnNlc3Npb25FbmNyeXB0aW9uS2V5KSB7XHJcbiAgICAgIHRoaXMucGVyc2lzdFNlcnZpY2Uuc2V0U2VydmVyU2Vzc2lvbkVuY3J5cHRpb25LZXkoXHJcbiAgICAgICAgYXdhaXQgSldLLmFzS2V5KGN1cnJlbnRVc2VyLnNlc3Npb25FbmNyeXB0aW9uS2V5KVxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHVzZXJBdHRyaWJ1dGVzID0gYXdhaXQgdGhpcy5hdXRoLnVzZXJBdHRyaWJ1dGVzKGNvZ25pdG9Vc2VyKTtcclxuXHJcbiAgICBpZiAocGFzc3dvcmQpIHtcclxuICAgICAgY29uc3QgcGFzc0tleSA9IChcclxuICAgICAgICBhd2FpdCB0aGlzLmtleUZhY3RvcnkuZGVyaXZlUGFzc0tleSh7XHJcbiAgICAgICAgICBwYXNzd29yZCxcclxuICAgICAgICAgIC4uLmN1cnJlbnRVc2VyLmN1cnJlbnRVc2VyS2V5LnBhc3NLZXkucGFzc0tleVBhcmFtcyxcclxuICAgICAgICB9KVxyXG4gICAgICApLmp3aztcclxuXHJcbiAgICAgIGF3YWl0IHRoaXMuaWRsZVNlcnZpY2UucGVyc2lzdE1hc3RlcktleShcclxuICAgICAgICBhd2FpdCB0aGlzLmtleUdyYXBoU2VydmljZS51bndyYXBXaXRoUGFzc0tleShcclxuICAgICAgICAgIGN1cnJlbnRVc2VyLmN1cnJlbnRVc2VyS2V5LnBhc3NLZXkuaWQsXHJcbiAgICAgICAgICBwYXNzS2V5LFxyXG4gICAgICAgICAgY3VycmVudFVzZXIuY3VycmVudFVzZXJLZXkubWFzdGVyS2V5LmlkXHJcbiAgICAgICAgKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gICAgYXdhaXQgdGhpcy5rZXlHcmFwaFNlcnZpY2UucG9wdWxhdGVLZXlzKGN1cnJlbnRVc2VyLmN1cnJlbnRVc2VyS2V5KTtcclxuXHJcbiAgICByZXR1cm4ge1xyXG4gICAgICBpZDogY3VycmVudFVzZXIuaWQsXHJcbiAgICAgIHN1YjogdGhpcy5nZXRVc2VyQXR0cmlidXRlKCdzdWInLCB1c2VyQXR0cmlidXRlcyksXHJcbiAgICAgIHVzZXJuYW1lOiBjdXJyZW50VXNlci51c2VybmFtZSxcclxuICAgICAgY3VycmVudFVzZXJLZXk6IGN1cnJlbnRVc2VyLmN1cnJlbnRVc2VyS2V5LFxyXG4gICAgICBnZXRBY2Nlc3NKd3RUb2tlbjogKCkgPT5cclxuICAgICAgICBjb2duaXRvVXNlci5nZXRTaWduSW5Vc2VyU2Vzc2lvbigpLmdldEFjY2Vzc1Rva2VuKCkuZ2V0Snd0VG9rZW4oKSxcclxuICAgICAgZW1haWw6IHRoaXMuZ2V0VXNlckF0dHJpYnV0ZSgnZW1haWwnLCB1c2VyQXR0cmlidXRlcyksXHJcbiAgICAgIGVtYWlsVmVyaWZpZWQ6XHJcbiAgICAgICAgdGhpcy5nZXRVc2VyQXR0cmlidXRlKCdlbWFpbF92ZXJpZmllZCcsIHVzZXJBdHRyaWJ1dGVzKSA9PT0gJ3RydWUnLFxyXG4gICAgICBwaG9uZTogdGhpcy5nZXRVc2VyQXR0cmlidXRlKCdwaG9uZV9udW1iZXInLCB1c2VyQXR0cmlidXRlcyksXHJcbiAgICAgIHBob25lVmVyaWZpZWQ6XHJcbiAgICAgICAgdGhpcy5nZXRVc2VyQXR0cmlidXRlKCdwaG9uZV9udW1iZXJfdmVyaWZpZWQnLCB1c2VyQXR0cmlidXRlcykgPT09XHJcbiAgICAgICAgJ3RydWUnLFxyXG4gICAgICBjb250YWN0Q2FyZDoge1xyXG4gICAgICAgIC4uLihhd2FpdCB0aGlzLnByb2ZpbGVTZXJ2aWNlLmRlY3J5cHRDb250YWN0Q2FyZChjb250YWN0Q2FyZCkpLFxyXG4gICAgICB9LFxyXG4gICAgICB1c2VyRGVsZXRlOiBjdXJyZW50VXNlci51c2VyRGVsZXRlLFxyXG4gICAgICB1c2VyUGxhbnMsXHJcbiAgICAgIGhhc1RQVmF1bHRBY2Nlc3M6IHRoaXMubWFwVFBWYXVsdEFjY2VzcyhjdXJyZW50VXNlci5mZWF0dXJlcyksXHJcbiAgICAgIGZlYXR1cmVzOiBjdXJyZW50VXNlci5mZWF0dXJlcyxcclxuICAgICAgc2Vzc2lvbkVuY3J5cHRpb25LZXk6IGN1cnJlbnRVc2VyLnNlc3Npb25FbmNyeXB0aW9uS2V5LFxyXG4gICAgfTtcclxuICB9XHJcblxyXG4gIHB1YmxpYyB3YXRjaEF1dGgoKTogT2JzZXJ2YWJsZTxhbnk+IHtcclxuICAgIHJldHVybiB0aGlzLmh1YlN1YmplY3Q7XHJcbiAgfVxyXG5cclxuICBwdWJsaWMgYXN5bmMgbG9nb3V0KCk6IFByb21pc2U8dm9pZD4ge1xyXG4gICAgdGhpcy5jdXJyZW50VXNlciA9IG51bGw7XHJcbiAgICB0aGlzLmtleVNlcnZpY2UucHVyZ2VLZXlzKCk7XHJcbiAgICB0aGlzLmtleUdyYXBoU2VydmljZS5wdXJnZUtleXMoKTtcclxuXHJcbiAgICBhd2FpdCBQcm9taXNlLmFsbChbdGhpcy5hdXRoLnNpZ25PdXQoKSwgdGhpcy5wcm9maWxlU2VydmljZS5zaWduT3V0KCldKTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgZ2V0VXNlckF0dHJpYnV0ZShcclxuICAgIGF0dHJpYnV0ZU5hbWU6IHN0cmluZyxcclxuICAgIHVzZXJBdHRyaWJ1dGVzOiBDb2duaXRvVXNlckF0dHJpYnV0ZVtdXHJcbiAgKSB7XHJcbiAgICBjb25zdCB1c2VyQXR0cmlidXRlID0gdXNlckF0dHJpYnV0ZXMuZmluZChcclxuICAgICAgKHgpID0+IHguZ2V0TmFtZSgpID09PSBhdHRyaWJ1dGVOYW1lXHJcbiAgICApO1xyXG5cclxuICAgIHJldHVybiB1c2VyQXR0cmlidXRlID8gdXNlckF0dHJpYnV0ZS5nZXRWYWx1ZSgpIDogbnVsbDtcclxuICB9XHJcblxyXG4gIHB1YmxpYyBhc3luYyBsb2FkUmVzZXRVc2VyKHBhc3N3b3JkPzogc3RyaW5nKTogUHJvbWlzZTxUcFBhc3N3b3JkUmVzZXRVc2VyPiB7XHJcbiAgICBjb25zdCB7IHRwUGFzc3dvcmRSZXNldFVzZXI6IHJlc2V0VXNlciB9ID0gYXdhaXQgdGhpcy5sckdyYXBoUUwucXVlcnkoe1xyXG4gICAgICBxdWVyeTogVHBQYXNzd29yZFJlc2V0VXNlclF1ZXJ5LFxyXG4gICAgfSk7XHJcblxyXG4gICAgaWYgKHJlc2V0VXNlci5zZXNzaW9uRW5jcnlwdGlvbktleSkge1xyXG4gICAgICB0aGlzLnBlcnNpc3RTZXJ2aWNlLnNldFNlcnZlclNlc3Npb25FbmNyeXB0aW9uS2V5KFxyXG4gICAgICAgIGF3YWl0IEpXSy5hc0tleShyZXNldFVzZXIuc2Vzc2lvbkVuY3J5cHRpb25LZXkpXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gVXBkYXRlIHRoZSBrZXlzXHJcbiAgICBpZiAocGFzc3dvcmQpIHtcclxuICAgICAgY29uc3QgcGFzc0tleSA9IChcclxuICAgICAgICBhd2FpdCB0aGlzLmtleUZhY3RvcnkuZGVyaXZlUGFzc0tleSh7XHJcbiAgICAgICAgICBwYXNzd29yZCxcclxuICAgICAgICAgIC4uLnJlc2V0VXNlci5wYXNzS2V5LnBhc3NLZXlQYXJhbXMsXHJcbiAgICAgICAgfSlcclxuICAgICAgKS5qd2s7XHJcblxyXG4gICAgICBhd2FpdCB0aGlzLmlkbGVTZXJ2aWNlLnBlcnNpc3RNYXN0ZXJLZXkoXHJcbiAgICAgICAgYXdhaXQgdGhpcy5rZXlHcmFwaFNlcnZpY2UudW53cmFwV2l0aFBhc3NLZXkoXHJcbiAgICAgICAgICByZXNldFVzZXIucGFzc0tleS5pZCxcclxuICAgICAgICAgIHBhc3NLZXksXHJcbiAgICAgICAgICByZXNldFVzZXIubWFzdGVyS2V5LmlkXHJcbiAgICAgICAgKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIHRoaXMua2V5U2VydmljZS5wb3B1bGF0ZUtleXMoe1xyXG4gICAgICBwYXNzS2V5OiB7XHJcbiAgICAgICAgaWQ6IHJlc2V0VXNlci5wYXNzS2V5LmlkLFxyXG4gICAgICB9LFxyXG4gICAgICBtYXN0ZXJLZXk6IHtcclxuICAgICAgICBpZDogcmVzZXRVc2VyLm1hc3RlcktleS5pZCxcclxuICAgICAgfSxcclxuICAgIH0pO1xyXG5cclxuICAgIGNvbnN0IHVzZXJBdHRyaWJ1dGVzID0gYXdhaXQgdGhpcy5hdXRoLnVzZXJBdHRyaWJ1dGVzKFxyXG4gICAgICBhd2FpdCB0aGlzLmF1dGguY3VycmVudEF1dGhlbnRpY2F0ZWRVc2VyKClcclxuICAgICk7XHJcbiAgICBjb25zdCBzdWIgPSB0aGlzLmdldFVzZXJBdHRyaWJ1dGUoJ3N1YicsIHVzZXJBdHRyaWJ1dGVzKTtcclxuXHJcbiAgICByZXR1cm4ge1xyXG4gICAgICAuLi4oYXdhaXQgdGhpcy50cFBhc3N3b3JkUmVzZXRQcm9jZXNzb3JTZXJ2aWNlLnByb2Nlc3NUcFBhc3N3b3JkUmVzZXRVc2VyTm9kZShcclxuICAgICAgICByZXNldFVzZXJcclxuICAgICAgKSksXHJcbiAgICAgIHN1YixcclxuICAgIH07XHJcbiAgfVxyXG5cclxuICBwdWJsaWMgYXN5bmMgcmVmcmVzaEFjY2Vzc1Rva2VuKCkge1xyXG4gICAgY29uc3QgY29nbml0b1VzZXI6IENvZ25pdG9Vc2VyID0gYXdhaXQgdGhpcy5hdXRoLmN1cnJlbnRBdXRoZW50aWNhdGVkVXNlcigpO1xyXG4gICAgY29uc3QgcmVmcmVzaFRva2VuID0gY29nbml0b1VzZXIuZ2V0U2lnbkluVXNlclNlc3Npb24oKS5nZXRSZWZyZXNoVG9rZW4oKTtcclxuXHJcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xyXG4gICAgICBjb2duaXRvVXNlci5yZWZyZXNoU2Vzc2lvbihyZWZyZXNoVG9rZW4sIChlcnIsIGRhdGEpID0+IHtcclxuICAgICAgICBpZiAoZXJyKSB7XHJcbiAgICAgICAgICBjb25zb2xlLmVycm9yKCdFcnJvciByZWZyZXNoaW5nIHRva2VuOiAnLCBlcnIpO1xyXG4gICAgICAgICAgcmVqZWN0KGVycik7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIGNvbnNvbGUubG9nKCdUb2tlbiByZWZyZXNoIGNvbXBsZXRlOiAnLCBkYXRhKTtcclxuICAgICAgICAgIHJlc29sdmUoMCk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgYXN5bmMgY29tcGxldGVSZXF1ZXN0KG5ld1Bhc3N3b3JkOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcclxuICAgIGNvbnN0IHJlc2V0VXNlciA9IGF3YWl0IHRoaXMuZ2V0UmVzZXRVc2VyKHRydWUpO1xyXG5cclxuICAgIGlmIChyZXNldFVzZXIuc3RhdGUgIT09IFRwQ2xhaW1TdGF0ZS5BUFBST1ZFRCkge1xyXG4gICAgICB0aHJvdyBuZXcgTHJCYWRTdGF0ZUV4Y2VwdGlvbihcclxuICAgICAgICAnUGFzc3dvcmQgcmVzZXQgcmVxdWVzdCBoYXMgbm90IGJlZW4gYXBwcm92ZWQuJ1xyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcbiAgICAvLyBQcmVwYXJlIGFsbCBtYXRlcmlhbHMgdG8gZW5zdXJlIHRoZXJlIGFyZSBubyBlcnJvcnMuXHJcbiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG4gICAgY29uc3QgYXNzZW1ibHlLZXkgPSBhd2FpdCB0aGlzLnJlY292ZXJBc3NlbWJseUtleShyZXNldFVzZXIpO1xyXG5cclxuICAgIGNvbnN0IHsgcm9vdEtleSB9ID0gYXdhaXQgdGhpcy5lbmNyeXB0aW9uU2VydmljZS5kZWNyeXB0KFxyXG4gICAgICBhc3NlbWJseUtleSxcclxuICAgICAgcmVzZXRVc2VyLmFzc2VtYmx5Q2lwaGVyRGF0YVxyXG4gICAgKTtcclxuICAgIGNvbnNvbGUubG9nKHJvb3RLZXkpO1xyXG5cclxuICAgIC8vIE1ha2luZyBzdXJlIGl0J3MgYSB2YWxpZCBrZXkuXHJcbiAgICBjb25zdCByb290S2V5SndrID0gYXdhaXQgSldLLmFzS2V5KHJvb3RLZXkpO1xyXG5cclxuICAgIGNvbnN0IG1hc3RlcktleSA9IGF3YWl0IHRoaXMua2V5R3JhcGhTZXJ2aWNlLmdldEtleShyZXNldFVzZXIubWFzdGVyS2V5LmlkKTtcclxuXHJcbiAgICBjb25zdCBtYXN0ZXJLZXlXcmFwcGVkUm9vdEtleSA9IGF3YWl0IHRoaXMuZW5jcnlwdGlvblNlcnZpY2UuZW5jcnlwdFRvU3RyaW5nKFxyXG4gICAgICBtYXN0ZXJLZXkuandrLFxyXG4gICAgICByb290S2V5SndrLnRvSlNPTih0cnVlKVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBUaGUgbmV3IHBhc3N3b3JkXHJcbiAgICBjb25zdCBuZXdQYXNzSWRwUmVzdWx0ID0gYXdhaXQgdGhpcy5rZXlGYWN0b3J5LmRlcml2ZVBhc3NJZHAoe1xyXG4gICAgICBwYXNzd29yZDogbmV3UGFzc3dvcmQsXHJcbiAgICAgIC4uLnJlc2V0VXNlci5wYXNzS2V5LnBhc3NJZHBQYXJhbXMsXHJcbiAgICB9KTtcclxuXHJcbiAgICBjb25zdCBuZXdJZHBQYXNzd29yZCA9IHRoaXMucGFzc3dvcmRTZXJ2aWNlLmdldFBhc3NJZHBTdHJpbmcoXHJcbiAgICAgIG5ld1Bhc3NJZHBSZXN1bHQuandrXHJcbiAgICApO1xyXG5cclxuICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcbiAgICAvLyBHZXQgYXNzZW1ibHkga2V5IGNoYWxsZW5nZVxyXG4gICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuICAgIGNvbnN0IGNoYWxsZW5nZSA9IChcclxuICAgICAgYXdhaXQgdGhpcy5sckdyYXBoUUwubHJNdXRhdGUoXHJcbiAgICAgICAgbmV3IExyTXV0YXRpb24oe1xyXG4gICAgICAgICAgbXV0YXRpb246IENyZWF0ZVRwQXNzZW1ibHlLZXlDaGFsbGVuZ2VNdXRhdGlvbixcclxuICAgICAgICAgIHZhcmlhYmxlczoge1xyXG4gICAgICAgICAgICBpbnB1dDoge30sXHJcbiAgICAgICAgICB9LFxyXG4gICAgICAgIH0pLFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIGluY2x1ZGVLZXlHcmFwaDogZmFsc2UsXHJcbiAgICAgICAgfVxyXG4gICAgICApXHJcbiAgICApLmNyZWF0ZVRwQXNzZW1ibHlLZXlDaGFsbGVuZ2UuY2hhbGxlbmdlO1xyXG5cclxuICAgIGNvbnNvbGUubG9nKGNoYWxsZW5nZSk7XHJcblxyXG4gICAgLy8gU2lnbiB0aGUgY2hhbGxlbmdlXHJcbiAgICAvLyBHZW5lcmF0ZSBhIGNsaWVudCBzaWRlIG5vbmNlIHRoYXQncyBubyBpbiB0aGUgc2VydmVyJ3MgY29udHJvbC5cclxuICAgIGNoYWxsZW5nZS5jbGllbnROb25jZSA9IHRoaXMua2V5RmFjdG9yeS5yYW5kb21TdHJpbmcoXHJcbiAgICAgIFRQX1BBU1NXT1JEX1JFU0VUX0NMSUVOVF9OT05DRV9MRU5HVEhcclxuICAgICk7XHJcbiAgICBjb25zb2xlLmxvZyhjaGFsbGVuZ2UpO1xyXG5cclxuICAgIGNvbnN0IGFzc2VtYmx5S2V5VmVyaWZpZXJQcmsgPSBhd2FpdCB0aGlzLmVuY3J5cHRpb25TZXJ2aWNlLmRlY3J5cHQoXHJcbiAgICAgIGFzc2VtYmx5S2V5LFxyXG4gICAgICByZXNldFVzZXIud3JhcHBlZEFzc2VtYmx5S2V5VmVyaWZpZXJQcmtcclxuICAgICk7XHJcbiAgICBjb25zdCBzaWduZWRDaGFsbGVuZ2UgPSBhd2FpdCB0aGlzLmVuY3J5cHRpb25TZXJ2aWNlLnNpZ24oXHJcbiAgICAgIGFzc2VtYmx5S2V5VmVyaWZpZXJQcmssXHJcbiAgICAgIGNoYWxsZW5nZVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG4gICAgLy8gQ2hhbmdlIHBhc3N3b3JkIGZvciB0aGUgb3JpZ2luYWwgdXNlclxyXG4gICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuICAgIGNvbnN0IHRlbXBJZHBQYXNzd29yZCA9IChcclxuICAgICAgYXdhaXQgdGhpcy5sckdyYXBoUUwubHJNdXRhdGUoXHJcbiAgICAgICAgbmV3IExyTXV0YXRpb24oe1xyXG4gICAgICAgICAgbXV0YXRpb246IFByZUNvbXBsZXRlVHBQYXNzd29yZFJlc2V0UmVxdWVzdE11dGF0aW9uLFxyXG4gICAgICAgICAgdmFyaWFibGVzOiB7XHJcbiAgICAgICAgICAgIGlucHV0OiB7XHJcbiAgICAgICAgICAgICAgc2lnbmVkQ2hhbGxlbmdlOiBKU09OLnN0cmluZ2lmeShzaWduZWRDaGFsbGVuZ2UpLFxyXG4gICAgICAgICAgICB9LFxyXG4gICAgICAgICAgfSxcclxuICAgICAgICB9KSxcclxuICAgICAgICB7XHJcbiAgICAgICAgICBpbmNsdWRlS2V5R3JhcGg6IGZhbHNlLFxyXG4gICAgICAgIH1cclxuICAgICAgKVxyXG4gICAgKS5wcmVDb21wbGV0ZVRwUGFzc3dvcmRSZXNldFJlcXVlc3QuaWRwUGFzc3dvcmQ7XHJcblxyXG4gICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuICAgIC8vIExvZ2luIGFzIHRoZSBvcmlnaW5hbCB1c2VyIHVzaW5nIG5ldyB0ZW1wb3JhcnkgcGFzc3dvcmRcclxuICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcbiAgICAvLyBBdCB0aGlzIHBvaW50LCB0aGUgb3JpZ2luYWwgYWNjb3VudCdzIHBhc3N3b3JkIGhhcyBiZWVuIGNoYW5nZWRcclxuICAgIC8vIHRvIGEgdGVtcG9yYXJ5IHBhc3N3b3JkLiBJdCBpcyBubyBsb25nZXIgcG9zc2libGUgZm9yIHRoZSB1c2VyXHJcbiAgICAvLyB0byB1c2UgdGhlIG9yaWdpbmFsIHBhc3N3b3JkIHRvIGxvZ2luLiBBbnkgc3VjY2Vzc2Z1bCBsb2dpblxyXG4gICAgLy8gY2FuIG9ubHkgYmUgdXNpbmcgdGhlIHRlbXBvcmFyeSBwYXNzd29yZC4gU28gaXQncyBzYWZlIHRvIGFzc3VtZVxyXG4gICAgLy8gdGhhdCB3ZSB3YW50IHRvIFwiY29tcGxldGVcIiB0aGUgcGFzc3dvcmQgcmVzZXQuXHJcblxyXG4gICAgLy8gVGhlIG1heWJlIDJGQSBzbyB3ZSBsaXN0ZW4gZm9yIHRoZSBhdXRoIGV2ZW50IGZyb20gQW1wbGlmeS5cclxuICAgIGNvbnN0IHJldFByb21pc2UgPSBuZXcgUHJvbWlzZTx2b2lkPigocmVzb2x2ZSkgPT4ge1xyXG4gICAgICBjb25zdCBsaXN0ZW5lciA9IGFzeW5jIChkYXRhKSA9PiB7XHJcbiAgICAgICAgaWYgKGRhdGEucGF5bG9hZC5ldmVudCAhPT0gJ3NpZ25JbicpIHtcclxuICAgICAgICAgIHJldHVybjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIEh1Yi5yZW1vdmUoJ2F1dGgnLCBsaXN0ZW5lcik7XHJcblxyXG4gICAgICAgIGNvbnNvbGUubG9nKGRhdGEucGF5bG9hZCk7XHJcblxyXG4gICAgICAgIGF3YWl0IHRoaXMuYXV0aC5zaWduSW4ocmVzZXRVc2VyLnVzZXJuYW1lLCBuZXdJZHBQYXNzd29yZCk7XHJcblxyXG4gICAgICAgIC8vIFN3aXRjaCBvdmVyIHRvIHRoZSBuZXcgc2V0IG9mIGtleXNcclxuICAgICAgICBhd2FpdCB0aGlzLmxyR3JhcGhRTC5sck11dGF0ZShcclxuICAgICAgICAgIG5ldyBMck11dGF0aW9uKHtcclxuICAgICAgICAgICAgbXV0YXRpb246IENvbXBsZXRlVHBQYXNzd29yZFJlc2V0UmVxdWVzdE11dGF0aW9uLFxyXG4gICAgICAgICAgICB2YXJpYWJsZXM6IHtcclxuICAgICAgICAgICAgICBpbnB1dDoge1xyXG4gICAgICAgICAgICAgICAgbWFzdGVyS2V5V3JhcHBlZFJvb3RLZXksXHJcbiAgICAgICAgICAgICAgICBtYXN0ZXJLZXlJZDogbWFzdGVyS2V5LmlkLFxyXG4gICAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICB9KVxyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIHJlc29sdmUoKTtcclxuICAgICAgfTtcclxuXHJcbiAgICAgIEh1Yi5saXN0ZW4oJ2F1dGgnLCBsaXN0ZW5lcik7XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBTaWduaW4gYXMgdGhlIG9yaWdpbmFsIHVzZXIuIFBhc3N3b3JkIGhhcyBiZWVuIHJlc2V0IHRvIHRlbXBvcmFyeSBvbmUuIEl0IHNob3VsZCByZXR1cm5cclxuICAgIC8vIHdpdGggTkVXX1BBU1NXT1JEX1JFUVVJUkVEXHJcbiAgICBsZXQgdXNlciA9IGF3YWl0IHRoaXMuYXV0aC5zaWduSW4ocmVzZXRVc2VyLnVzZXJuYW1lLCB0ZW1wSWRwUGFzc3dvcmQsIHtcclxuICAgICAgbm9Qcm94eTogJ3RydWUnLFxyXG4gICAgfSk7XHJcblxyXG4gICAgaWYgKHVzZXIuY2hhbGxlbmdlTmFtZSAhPT0gJ05FV19QQVNTV09SRF9SRVFVSVJFRCcpIHtcclxuICAgICAgdGhyb3cgbmV3IExyRXhjZXB0aW9uKHtcclxuICAgICAgICBtZXNzYWdlOlxyXG4gICAgICAgICAgJ0ludGVybmFsIGVycm9yLiBFeHBlY3RpbmcgQ29nbml0byB0byBoYXZlIGRvbmUgYSBwYXNzd29yZCByZXNldCBhZnRlciBjYWxsIHRvIFByZUNvbXBsZXRlVHBQYXNzd29yZFJlc2V0UmVxdWVzdE11dGF0aW9uLicsXHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFNldCBuZXcgcGFzc3dvcmQgb24gSWRwXHJcbiAgICAvLyB0aGUgYXdzRmV0Y2goKSBmdW5jdGlvbiBwYXNzZXMgTkVXX1BBU1NXT1JEX1JFUVVJUkVEIGRpcmVjdGx5IHRvIEFXUyB3aXRob3V0XHJcbiAgICAvLyBnb2luZyB0aHJvdWdoIHRoZSBwcm94eS5cclxuICAgIHVzZXIgPSBhd2FpdCB0aGlzLmF1dGguY29tcGxldGVOZXdQYXNzd29yZCh1c2VyLCBuZXdJZHBQYXNzd29yZCwge30pO1xyXG5cclxuICAgIHJldHVybiByZXRQcm9taXNlO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBhc3luYyByZWNvdmVyQXNzZW1ibHlLZXkoXHJcbiAgICByZXNldFVzZXI6IFRwUGFzc3dvcmRSZXNldFVzZXJOb2RlXHJcbiAgKTogUHJvbWlzZTxKV0suS2V5PiB7XHJcbiAgICAvLyBSZWNvdmVyIHRoZSBhc3NlbWJseSBrZXkuXHJcbiAgICBsZXQgYXNzZW1ibHlLZXlQYXJhbXM6IG9iamVjdDtcclxuXHJcbiAgICBjb25zdCBwcmsgPSBhd2FpdCB0aGlzLmtleUdyYXBoU2VydmljZS5nZXRLZXkocmVzZXRVc2VyLnB4ay5pZCk7XHJcblxyXG4gICAgY29uc3Qgc2hhcmVzID0gYXdhaXQgUHJvbWlzZS5hbGwoXHJcbiAgICAgIHJlc2V0VXNlci5hcHByb3ZhbHNcclxuICAgICAgICAuZmlsdGVyKChhcHByb3ZhbCkgPT4gISFhcHByb3ZhbC5yZWNlaXZlckNpcGhlclBhcnRpYWxBc3NlbWJseUtleSlcclxuICAgICAgICAubWFwKGFzeW5jIChhcHByb3ZhbCkgPT4ge1xyXG4gICAgICAgICAgY29uc3QgcGFydGlhbEFzc2VtYmx5S2V5ID0gYXdhaXQgdGhpcy5lbmNyeXB0aW9uU2VydmljZS5kZWNyeXB0KFxyXG4gICAgICAgICAgICBwcmssXHJcbiAgICAgICAgICAgIGFwcHJvdmFsLnJlY2VpdmVyQ2lwaGVyUGFydGlhbEFzc2VtYmx5S2V5XHJcbiAgICAgICAgICApO1xyXG5cclxuICAgICAgICAgIGlmIChhc3NlbWJseUtleVBhcmFtcykge1xyXG4gICAgICAgICAgICBpZiAoXHJcbiAgICAgICAgICAgICAgSlNPTi5zdHJpbmdpZnkoYXNzZW1ibHlLZXlQYXJhbXMpICE9PVxyXG4gICAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KHBhcnRpYWxBc3NlbWJseUtleS5hc3NlbWJseUtleVBhcmFtcylcclxuICAgICAgICAgICAgKSB7XHJcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IExyQmFkU3RhdGVFeGNlcHRpb24oXHJcbiAgICAgICAgICAgICAgICAnVGhlIGFzc2VtYmx5IGtleSBwYXJhbWV0ZXJzIGFyZSBkaWZmZXJlbnQgYmV0d2VlbiB0aGUgYXBwcm92YWxzLidcclxuICAgICAgICAgICAgICApO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICBhc3NlbWJseUtleVBhcmFtcyA9IHBhcnRpYWxBc3NlbWJseUtleS5hc3NlbWJseUtleVBhcmFtcztcclxuICAgICAgICAgIH1cclxuICAgICAgICAgIHJldHVybiBwYXJ0aWFsQXNzZW1ibHlLZXkuc2xpcDM5LnNoYXJlLm1uZW1vbmljcztcclxuICAgICAgICB9KVxyXG4gICAgKTtcclxuXHJcbiAgICBjb25zb2xlLmxvZygncmVjb3ZlckFzc2VtYmx5S2V5KCknLCBzaGFyZXMpO1xyXG5cclxuICAgIGNvbnN0IHJhd0Fzc2VtYmx5S2V5ID0gYXdhaXQgdGhpcy5zbGlwMzlTZXJ2aWNlLnJlY292ZXJTZWNyZXQoXHJcbiAgICAgIHNoYXJlcyxcclxuICAgICAgVFBfUEFTU1dPUkRfUkVTRVRfU0xJUDM5X1BBU1NQSFJBU0VcclxuICAgICk7XHJcblxyXG4gICAgcmV0dXJuIEpXSy5hc0tleSh7XHJcbiAgICAgIC4uLmFzc2VtYmx5S2V5UGFyYW1zLFxyXG4gICAgICBrOiByYXdBc3NlbWJseUtleSxcclxuICAgIH0pO1xyXG4gIH1cclxufVxyXG4iXX0=
|
|
1
|
+
import { __awaiter } from "tslib";
|
|
2
|
+
import { Inject, Injectable, isDevMode } from '@angular/core';
|
|
3
|
+
import { Hub } from '@aws-amplify/core';
|
|
4
|
+
import { ReplaySubject } from 'rxjs';
|
|
5
|
+
import { KeyGraphService } from '../cryptography/key-graph.service';
|
|
6
|
+
import { KeyService } from '../cryptography/key.service';
|
|
7
|
+
import { ProfileService } from '../users/profile.service';
|
|
8
|
+
import { PasswordChangeStatus } from '../users/profile.types';
|
|
9
|
+
import { LrConcurrentAccessException, LrBadRequestException, LrBadStateException, LrException, } from '../_common/exceptions';
|
|
10
|
+
import { RecoveryStatus, } from './auth.types';
|
|
11
|
+
import { PasswordService } from './password.service';
|
|
12
|
+
import { AuthClass } from '@aws-amplify/auth/lib-esm/Auth';
|
|
13
|
+
import { CompleteTpPasswordResetRequestMutation, CreateTpAssemblyKeyChallengeMutation, PreCompleteTpPasswordResetRequestMutation, TpPasswordResetUserQuery, } from '../trusted-parties/tp-password-reset.gql';
|
|
14
|
+
import { IdleService } from './idle.service';
|
|
15
|
+
import { KeyFactoryService } from '../cryptography/key-factory.service';
|
|
16
|
+
import { LrGraphQLService, LrMutation } from '../api/lr-graphql';
|
|
17
|
+
import { TpClaimState } from '../api/types';
|
|
18
|
+
import { TpPasswordResetProcessorService } from '../api/query-processor/tp-password-reset-processor.service';
|
|
19
|
+
import { SetSessionEncryptionKeyMutation } from './auth.gql';
|
|
20
|
+
import { PersistService } from '../api/persist.service';
|
|
21
|
+
import { JWK } from 'node-jose';
|
|
22
|
+
import { LR_CONFIG } from '../life-ready.config';
|
|
23
|
+
import { EncryptionService } from '../cryptography/encryption.service';
|
|
24
|
+
import { Slip39Service } from '../cryptography/slip39.service';
|
|
25
|
+
import { TP_PASSWORD_RESET_CLIENT_NONCE_LENGTH, TP_PASSWORD_RESET_SLIP39_PASSPHRASE, TP_PASSWORD_RESET_USERNAME_SUFFIX, } from '../trusted-parties/tp-password-reset.constants';
|
|
26
|
+
import * as i0 from "@angular/core";
|
|
27
|
+
import * as i1 from "../life-ready.config";
|
|
28
|
+
import * as i2 from "@aws-amplify/auth/lib-esm/Auth";
|
|
29
|
+
import * as i3 from "../cryptography/key-factory.service";
|
|
30
|
+
import * as i4 from "../cryptography/key.service";
|
|
31
|
+
import * as i5 from "../users/profile.service";
|
|
32
|
+
import * as i6 from "../cryptography/key-graph.service";
|
|
33
|
+
import * as i7 from "./password.service";
|
|
34
|
+
import * as i8 from "./idle.service";
|
|
35
|
+
import * as i9 from "../api/lr-graphql/lr-graphql.service";
|
|
36
|
+
import * as i10 from "../api/query-processor/tp-password-reset-processor.service";
|
|
37
|
+
import * as i11 from "../api/persist.service";
|
|
38
|
+
import * as i12 from "../cryptography/encryption.service";
|
|
39
|
+
import * as i13 from "../cryptography/slip39.service";
|
|
40
|
+
export const initialiseAuth = (authService) => {
|
|
41
|
+
return () => authService.initialise();
|
|
42
|
+
};
|
|
43
|
+
export class LifeReadyAuthService {
|
|
44
|
+
constructor(config, auth, keyFactory, keyService, profileService, keyGraphService, passwordService, idleService, lrGraphQL, tpPasswordResetProcessorService, persistService, encryptionService, slip39Service) {
|
|
45
|
+
this.config = config;
|
|
46
|
+
this.auth = auth;
|
|
47
|
+
this.keyFactory = keyFactory;
|
|
48
|
+
this.keyService = keyService;
|
|
49
|
+
this.profileService = profileService;
|
|
50
|
+
this.keyGraphService = keyGraphService;
|
|
51
|
+
this.passwordService = passwordService;
|
|
52
|
+
this.idleService = idleService;
|
|
53
|
+
this.lrGraphQL = lrGraphQL;
|
|
54
|
+
this.tpPasswordResetProcessorService = tpPasswordResetProcessorService;
|
|
55
|
+
this.persistService = persistService;
|
|
56
|
+
this.encryptionService = encryptionService;
|
|
57
|
+
this.slip39Service = slip39Service;
|
|
58
|
+
this.hubSubject = new ReplaySubject(1);
|
|
59
|
+
}
|
|
60
|
+
initialise() {
|
|
61
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
62
|
+
Hub.listen('auth', (data) => this.hubSubject.next(data.payload));
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
loginIdpImpl(emailOrPhone, password, passIdpParams, recoveryStatus) {
|
|
66
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
67
|
+
const passIdpResult = yield this.keyFactory.derivePassIdp(Object.assign({ password }, passIdpParams));
|
|
68
|
+
// Use the derived password to signin with cognito
|
|
69
|
+
const user = yield this.auth.signIn(emailOrPhone, this.passwordService.getPassIdpString(passIdpResult.jwk));
|
|
70
|
+
user.recoveryStatus = recoveryStatus;
|
|
71
|
+
return user;
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
loginIdp(emailOrPhone, password) {
|
|
75
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
76
|
+
// Download the salt needed to derive the PassIdp
|
|
77
|
+
const passIdpApiResult = yield this.profileService.getPassIdpParams(emailOrPhone);
|
|
78
|
+
if (passIdpApiResult.passwordChangeStatus === PasswordChangeStatus.InProgress) {
|
|
79
|
+
throw new LrConcurrentAccessException('A password change is in progress');
|
|
80
|
+
}
|
|
81
|
+
if (passIdpApiResult.passwordChangeStatus === PasswordChangeStatus.Recovery) {
|
|
82
|
+
console.log('In recovery mode.');
|
|
83
|
+
// Let's say we don't know if the password is the new one or the old one. We just have to try both.
|
|
84
|
+
try {
|
|
85
|
+
const user = yield this.loginIdpImpl(emailOrPhone, password, passIdpApiResult.newPassIdpParams, RecoveryStatus.NEW_PASSWORD);
|
|
86
|
+
// New password worked. Let's set to the current password
|
|
87
|
+
// --Potential Failure Point 1--
|
|
88
|
+
// if changePasswordComplete() doesn't get called, then it should remain
|
|
89
|
+
console.log('New password works!');
|
|
90
|
+
return user;
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
// Just bubble up any other type of error.
|
|
94
|
+
if (error.code !== 'NotAuthorizedException') {
|
|
95
|
+
throw error;
|
|
96
|
+
}
|
|
97
|
+
// pass, try again assuming it's the old password
|
|
98
|
+
}
|
|
99
|
+
// Now assume it's the previous password. Any exception is allowed to bubble up.
|
|
100
|
+
try {
|
|
101
|
+
const user = yield this.loginIdpImpl(emailOrPhone, password, passIdpApiResult.currentPassIdpParams, RecoveryStatus.OLD_PASSWORD);
|
|
102
|
+
// Old password worked.
|
|
103
|
+
console.log('Old password works!');
|
|
104
|
+
return user;
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
// Just bubble up any other type of error.
|
|
108
|
+
throw error.code === 'NotAuthorizedException'
|
|
109
|
+
? new LrBadRequestException('The password change request was interrupted, please try to login with both your new and old password')
|
|
110
|
+
: error;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// Try against as the TP password reset account
|
|
114
|
+
if (passIdpApiResult.tpPasswordReset) {
|
|
115
|
+
try {
|
|
116
|
+
// TP password reset is in process. We need to try the password against both
|
|
117
|
+
// original account and the new reset account.
|
|
118
|
+
const reset = passIdpApiResult.tpPasswordReset;
|
|
119
|
+
const ret = yield this.loginIdpImpl(reset.resetUsername, password, reset.passIdpParams, RecoveryStatus.NONE);
|
|
120
|
+
ret.isTpPasswordResetUser = true;
|
|
121
|
+
return ret;
|
|
122
|
+
}
|
|
123
|
+
catch (err) {
|
|
124
|
+
// continue, try again as regular user.
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// Login as regular user
|
|
128
|
+
return yield this.loginIdpImpl(emailOrPhone, password, passIdpApiResult.currentPassIdpParams, RecoveryStatus.NONE);
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
handleSessionEncryptionKey() {
|
|
132
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
133
|
+
if (this.config.disableSessionEncryptionKey) {
|
|
134
|
+
if (!isDevMode()) {
|
|
135
|
+
const msg = 'You should not set disableSessionEncryptionKey=True in mode prod. It defaults to false.';
|
|
136
|
+
console.error(msg);
|
|
137
|
+
throw new Error(msg);
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
console.warn('You have set disableSessionEncryptionKey=True. Make sure not to do this in prod mode.');
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
// Set the session key to a new encryption key for this session
|
|
145
|
+
const sessionEncryptionKey = yield this.keyFactory.createKey();
|
|
146
|
+
yield this.lrGraphQL.lrMutate(new LrMutation({
|
|
147
|
+
mutation: SetSessionEncryptionKeyMutation,
|
|
148
|
+
variables: {
|
|
149
|
+
input: {
|
|
150
|
+
sessionEncryptionKey: JSON.stringify(sessionEncryptionKey.toJSON(true)),
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
}), {
|
|
154
|
+
includeKeyGraph: false,
|
|
155
|
+
});
|
|
156
|
+
this.persistService.setServerSessionEncryptionKey(sessionEncryptionKey);
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
handlePostAuth(cognitoUser) {
|
|
161
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
162
|
+
yield this.handlePasswordRecovery(cognitoUser);
|
|
163
|
+
yield this.handleSessionEncryptionKey();
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
login(emailOrPhone, password, { tpPasswordResetAutoComplete = true } = {}) {
|
|
167
|
+
var _a;
|
|
168
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
169
|
+
let loginResult = yield this.loginImpl(emailOrPhone, password);
|
|
170
|
+
if (tpPasswordResetAutoComplete &&
|
|
171
|
+
((_a = loginResult.resetUser) === null || _a === void 0 ? void 0 : _a.state) === TpClaimState.APPROVED) {
|
|
172
|
+
yield this.completeRequest(password);
|
|
173
|
+
loginResult = yield this.loginImpl(emailOrPhone, password);
|
|
174
|
+
}
|
|
175
|
+
return loginResult;
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
loginImpl(emailOrPhone, password) {
|
|
179
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
180
|
+
yield this.logout();
|
|
181
|
+
const cognitoUser = yield this.loginIdp(emailOrPhone, password);
|
|
182
|
+
// todo: Meet MFA challenges.
|
|
183
|
+
if (['SMS_MFA', 'SOFTWARE_TOKEN_MFA'].includes(cognitoUser.challengeName)) {
|
|
184
|
+
return { hasChallenge: true, challenge: cognitoUser };
|
|
185
|
+
}
|
|
186
|
+
yield this.handlePostAuth(cognitoUser);
|
|
187
|
+
if (cognitoUser.isTpPasswordResetUser) {
|
|
188
|
+
// Assuming there is no MFA on the TP reset user.
|
|
189
|
+
const resetUser = yield this.loadResetUser(password);
|
|
190
|
+
return { hasChallenge: false, resetUser };
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
const user = yield this.loadUser(cognitoUser, password);
|
|
194
|
+
yield this.idleService.start(); // Run idleService whenever user is logged in.
|
|
195
|
+
return { hasChallenge: false, user };
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
// TODO <AZ> We need to handle the isTpPasswordResetUser=True case here after MFA as well.
|
|
200
|
+
verifyLogin(challenge, password, rememberMe, code) {
|
|
201
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
202
|
+
yield this.auth.confirmSignIn(challenge, code, challenge.challengeName);
|
|
203
|
+
// TODO: this.auth.confirmSignIn() could return another challenge.
|
|
204
|
+
const cognitoUser = yield this.auth.currentAuthenticatedUser();
|
|
205
|
+
yield this.handlePostAuth(challenge);
|
|
206
|
+
const user = yield this.loadUser(cognitoUser, password);
|
|
207
|
+
if (rememberMe) {
|
|
208
|
+
cognitoUser.setDeviceStatusRemembered({
|
|
209
|
+
onSuccess: () => { },
|
|
210
|
+
onFailure: (e) => console.error(e),
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
return user;
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
handlePasswordRecovery(user) {
|
|
217
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
218
|
+
if (user.recoveryStatus !== RecoveryStatus.NONE) {
|
|
219
|
+
const jwtToken = user
|
|
220
|
+
.getSignInUserSession()
|
|
221
|
+
.getAccessToken()
|
|
222
|
+
.getJwtToken();
|
|
223
|
+
yield this.passwordService.changePasswordComplete(jwtToken, user.recoveryStatus === RecoveryStatus.NEW_PASSWORD);
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
getUserOrResetUser(reload = false) {
|
|
228
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
229
|
+
const cognitoUser = yield this.auth.currentAuthenticatedUser();
|
|
230
|
+
if (cognitoUser.getUsername().endsWith(TP_PASSWORD_RESET_USERNAME_SUFFIX)) {
|
|
231
|
+
return this.getResetUser(reload);
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
return this.getUser(reload);
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
getResetUser(reload = false) {
|
|
239
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
240
|
+
if (!reload && this.currentResetUser) {
|
|
241
|
+
return this.currentResetUser;
|
|
242
|
+
}
|
|
243
|
+
this.currentResetUser = yield this.loadResetUser();
|
|
244
|
+
yield this.idleService.start(); // Run idleService whenever user is logged in.
|
|
245
|
+
return this.currentResetUser;
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
getUser(reload = false) {
|
|
249
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
250
|
+
if (!reload && this.currentUser) {
|
|
251
|
+
return this.currentUser;
|
|
252
|
+
}
|
|
253
|
+
this.currentUser = yield this.loadUser(yield this.auth.currentAuthenticatedUser());
|
|
254
|
+
console.log('Starting idle service.');
|
|
255
|
+
yield this.idleService.start(); // Run idleService whenever user is logged in.
|
|
256
|
+
return this.currentUser;
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
mapTPVaultAccess(features) {
|
|
260
|
+
const tpVaultFeature = features === null || features === void 0 ? void 0 : features.tpVault;
|
|
261
|
+
return ((tpVaultFeature === null || tpVaultFeature === void 0 ? void 0 : tpVaultFeature.length) > 0 &&
|
|
262
|
+
tpVaultFeature.some((feature) => feature.toUpperCase() === 'ACCESS'));
|
|
263
|
+
}
|
|
264
|
+
loadUser(cognitoUser, password) {
|
|
265
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
266
|
+
const { currentUser, contactCard, userPlans, } = yield this.profileService.getCurrentUser();
|
|
267
|
+
if (currentUser.sessionEncryptionKey) {
|
|
268
|
+
this.persistService.setServerSessionEncryptionKey(yield JWK.asKey(currentUser.sessionEncryptionKey));
|
|
269
|
+
}
|
|
270
|
+
const userAttributes = yield this.auth.userAttributes(cognitoUser);
|
|
271
|
+
if (password) {
|
|
272
|
+
const passKey = (yield this.keyFactory.derivePassKey(Object.assign({ password }, currentUser.currentUserKey.passKey.passKeyParams))).jwk;
|
|
273
|
+
yield this.idleService.persistMasterKey(yield this.keyGraphService.unwrapWithPassKey(currentUser.currentUserKey.passKey.id, passKey, currentUser.currentUserKey.masterKey.id));
|
|
274
|
+
}
|
|
275
|
+
yield this.keyGraphService.populateKeys(currentUser.currentUserKey);
|
|
276
|
+
return {
|
|
277
|
+
id: currentUser.id,
|
|
278
|
+
sub: this.getUserAttribute('sub', userAttributes),
|
|
279
|
+
username: currentUser.username,
|
|
280
|
+
currentUserKey: currentUser.currentUserKey,
|
|
281
|
+
getAccessJwtToken: () => cognitoUser.getSignInUserSession().getAccessToken().getJwtToken(),
|
|
282
|
+
email: this.getUserAttribute('email', userAttributes),
|
|
283
|
+
emailVerified: this.getUserAttribute('email_verified', userAttributes) === 'true',
|
|
284
|
+
phone: this.getUserAttribute('phone_number', userAttributes),
|
|
285
|
+
phoneVerified: this.getUserAttribute('phone_number_verified', userAttributes) ===
|
|
286
|
+
'true',
|
|
287
|
+
contactCard: Object.assign({}, (yield this.profileService.decryptContactCard(contactCard))),
|
|
288
|
+
userDelete: currentUser.userDelete,
|
|
289
|
+
userPlans,
|
|
290
|
+
hasTPVaultAccess: this.mapTPVaultAccess(currentUser.features),
|
|
291
|
+
features: currentUser.features,
|
|
292
|
+
sessionEncryptionKey: currentUser.sessionEncryptionKey,
|
|
293
|
+
};
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
watchAuth() {
|
|
297
|
+
return this.hubSubject;
|
|
298
|
+
}
|
|
299
|
+
logout() {
|
|
300
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
301
|
+
this.currentUser = null;
|
|
302
|
+
this.keyService.purgeKeys();
|
|
303
|
+
this.keyGraphService.purgeKeys();
|
|
304
|
+
yield Promise.all([this.auth.signOut(), this.profileService.signOut()]);
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
getUserAttribute(attributeName, userAttributes) {
|
|
308
|
+
const userAttribute = userAttributes.find((x) => x.getName() === attributeName);
|
|
309
|
+
return userAttribute ? userAttribute.getValue() : null;
|
|
310
|
+
}
|
|
311
|
+
loadResetUser(password) {
|
|
312
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
313
|
+
const { tpPasswordResetUser: resetUser } = yield this.lrGraphQL.query({
|
|
314
|
+
query: TpPasswordResetUserQuery,
|
|
315
|
+
});
|
|
316
|
+
if (resetUser.sessionEncryptionKey) {
|
|
317
|
+
this.persistService.setServerSessionEncryptionKey(yield JWK.asKey(resetUser.sessionEncryptionKey));
|
|
318
|
+
}
|
|
319
|
+
// Update the keys
|
|
320
|
+
if (password) {
|
|
321
|
+
const passKey = (yield this.keyFactory.derivePassKey(Object.assign({ password }, resetUser.passKey.passKeyParams))).jwk;
|
|
322
|
+
yield this.idleService.persistMasterKey(yield this.keyGraphService.unwrapWithPassKey(resetUser.passKey.id, passKey, resetUser.masterKey.id));
|
|
323
|
+
}
|
|
324
|
+
this.keyService.populateKeys({
|
|
325
|
+
passKey: {
|
|
326
|
+
id: resetUser.passKey.id,
|
|
327
|
+
},
|
|
328
|
+
masterKey: {
|
|
329
|
+
id: resetUser.masterKey.id,
|
|
330
|
+
},
|
|
331
|
+
});
|
|
332
|
+
const userAttributes = yield this.auth.userAttributes(yield this.auth.currentAuthenticatedUser());
|
|
333
|
+
const sub = this.getUserAttribute('sub', userAttributes);
|
|
334
|
+
return Object.assign(Object.assign({}, (yield this.tpPasswordResetProcessorService.processTpPasswordResetUserNode(resetUser))), { sub });
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
refreshAccessToken() {
|
|
338
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
339
|
+
const cognitoUser = yield this.auth.currentAuthenticatedUser();
|
|
340
|
+
const refreshToken = cognitoUser.getSignInUserSession().getRefreshToken();
|
|
341
|
+
return new Promise((resolve, reject) => {
|
|
342
|
+
cognitoUser.refreshSession(refreshToken, (err, data) => {
|
|
343
|
+
if (err) {
|
|
344
|
+
console.error('Error refreshing token: ', err);
|
|
345
|
+
reject(err);
|
|
346
|
+
}
|
|
347
|
+
else {
|
|
348
|
+
console.log('Token refresh complete: ', data);
|
|
349
|
+
resolve(0);
|
|
350
|
+
}
|
|
351
|
+
});
|
|
352
|
+
});
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
completeRequest(newPassword) {
|
|
356
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
357
|
+
const resetUser = yield this.getResetUser(true);
|
|
358
|
+
if (resetUser.state !== TpClaimState.APPROVED) {
|
|
359
|
+
throw new LrBadStateException('Password reset request has not been approved.');
|
|
360
|
+
}
|
|
361
|
+
// --------------------------------------------------------------
|
|
362
|
+
// Prepare all materials to ensure there are no errors.
|
|
363
|
+
// --------------------------------------------------------------
|
|
364
|
+
const assemblyKey = yield this.recoverAssemblyKey(resetUser);
|
|
365
|
+
const { rootKey } = yield this.encryptionService.decrypt(assemblyKey, resetUser.assemblyCipherData);
|
|
366
|
+
console.log(rootKey);
|
|
367
|
+
// Making sure it's a valid key.
|
|
368
|
+
const rootKeyJwk = yield JWK.asKey(rootKey);
|
|
369
|
+
const masterKey = yield this.keyGraphService.getKey(resetUser.masterKey.id);
|
|
370
|
+
const masterKeyWrappedRootKey = yield this.encryptionService.encryptToString(masterKey.jwk, rootKeyJwk.toJSON(true));
|
|
371
|
+
// The new password
|
|
372
|
+
const newPassIdpResult = yield this.keyFactory.derivePassIdp(Object.assign({ password: newPassword }, resetUser.passKey.passIdpParams));
|
|
373
|
+
const newIdpPassword = this.passwordService.getPassIdpString(newPassIdpResult.jwk);
|
|
374
|
+
// --------------------------------------------------------------
|
|
375
|
+
// Get assembly key challenge
|
|
376
|
+
// --------------------------------------------------------------
|
|
377
|
+
const challenge = (yield this.lrGraphQL.lrMutate(new LrMutation({
|
|
378
|
+
mutation: CreateTpAssemblyKeyChallengeMutation,
|
|
379
|
+
variables: {
|
|
380
|
+
input: {},
|
|
381
|
+
},
|
|
382
|
+
}), {
|
|
383
|
+
includeKeyGraph: false,
|
|
384
|
+
})).createTpAssemblyKeyChallenge.challenge;
|
|
385
|
+
console.log(challenge);
|
|
386
|
+
// Sign the challenge
|
|
387
|
+
// Generate a client side nonce that's no in the server's control.
|
|
388
|
+
challenge.clientNonce = this.keyFactory.randomString(TP_PASSWORD_RESET_CLIENT_NONCE_LENGTH);
|
|
389
|
+
console.log(challenge);
|
|
390
|
+
const assemblyKeyVerifierPrk = yield this.encryptionService.decrypt(assemblyKey, resetUser.wrappedAssemblyKeyVerifierPrk);
|
|
391
|
+
const signedChallenge = yield this.encryptionService.sign(assemblyKeyVerifierPrk, challenge);
|
|
392
|
+
// --------------------------------------------------------------
|
|
393
|
+
// Change password for the original user
|
|
394
|
+
// --------------------------------------------------------------
|
|
395
|
+
const tempIdpPassword = (yield this.lrGraphQL.lrMutate(new LrMutation({
|
|
396
|
+
mutation: PreCompleteTpPasswordResetRequestMutation,
|
|
397
|
+
variables: {
|
|
398
|
+
input: {
|
|
399
|
+
signedChallenge: JSON.stringify(signedChallenge),
|
|
400
|
+
},
|
|
401
|
+
},
|
|
402
|
+
}), {
|
|
403
|
+
includeKeyGraph: false,
|
|
404
|
+
})).preCompleteTpPasswordResetRequest.idpPassword;
|
|
405
|
+
// --------------------------------------------------------------
|
|
406
|
+
// Login as the original user using new temporary password
|
|
407
|
+
// --------------------------------------------------------------
|
|
408
|
+
// At this point, the original account's password has been changed
|
|
409
|
+
// to a temporary password. It is no longer possible for the user
|
|
410
|
+
// to use the original password to login. Any successful login
|
|
411
|
+
// can only be using the temporary password. So it's safe to assume
|
|
412
|
+
// that we want to "complete" the password reset.
|
|
413
|
+
// The maybe 2FA so we listen for the auth event from Amplify.
|
|
414
|
+
const retPromise = new Promise((resolve) => {
|
|
415
|
+
const listener = (data) => __awaiter(this, void 0, void 0, function* () {
|
|
416
|
+
if (data.payload.event !== 'signIn') {
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
Hub.remove('auth', listener);
|
|
420
|
+
console.log(data.payload);
|
|
421
|
+
yield this.auth.signIn(resetUser.username, newIdpPassword);
|
|
422
|
+
// Switch over to the new set of keys
|
|
423
|
+
yield this.lrGraphQL.lrMutate(new LrMutation({
|
|
424
|
+
mutation: CompleteTpPasswordResetRequestMutation,
|
|
425
|
+
variables: {
|
|
426
|
+
input: {
|
|
427
|
+
masterKeyWrappedRootKey,
|
|
428
|
+
masterKeyId: masterKey.id,
|
|
429
|
+
},
|
|
430
|
+
},
|
|
431
|
+
}));
|
|
432
|
+
resolve();
|
|
433
|
+
});
|
|
434
|
+
Hub.listen('auth', listener);
|
|
435
|
+
});
|
|
436
|
+
// Signin as the original user. Password has been reset to temporary one. It should return
|
|
437
|
+
// with NEW_PASSWORD_REQUIRED
|
|
438
|
+
let user = yield this.auth.signIn(resetUser.username, tempIdpPassword, {
|
|
439
|
+
noProxy: 'true',
|
|
440
|
+
});
|
|
441
|
+
if (user.challengeName !== 'NEW_PASSWORD_REQUIRED') {
|
|
442
|
+
throw new LrException({
|
|
443
|
+
message: 'Internal error. Expecting Cognito to have done a password reset after call to PreCompleteTpPasswordResetRequestMutation.',
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
// Set new password on Idp
|
|
447
|
+
// the awsFetch() function passes NEW_PASSWORD_REQUIRED directly to AWS without
|
|
448
|
+
// going through the proxy.
|
|
449
|
+
user = yield this.auth.completeNewPassword(user, newIdpPassword, {});
|
|
450
|
+
return retPromise;
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
recoverAssemblyKey(resetUser) {
|
|
454
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
455
|
+
// Recover the assembly key.
|
|
456
|
+
let assemblyKeyParams;
|
|
457
|
+
const prk = yield this.keyGraphService.getKey(resetUser.pxk.id);
|
|
458
|
+
const shares = yield Promise.all(resetUser.approvals
|
|
459
|
+
.filter((approval) => !!approval.receiverCipherPartialAssemblyKey)
|
|
460
|
+
.map((approval) => __awaiter(this, void 0, void 0, function* () {
|
|
461
|
+
const partialAssemblyKey = yield this.encryptionService.decrypt(prk, approval.receiverCipherPartialAssemblyKey);
|
|
462
|
+
if (assemblyKeyParams) {
|
|
463
|
+
if (JSON.stringify(assemblyKeyParams) !==
|
|
464
|
+
JSON.stringify(partialAssemblyKey.assemblyKeyParams)) {
|
|
465
|
+
throw new LrBadStateException('The assembly key parameters are different between the approvals.');
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
else {
|
|
469
|
+
assemblyKeyParams = partialAssemblyKey.assemblyKeyParams;
|
|
470
|
+
}
|
|
471
|
+
return partialAssemblyKey.slip39.share.mnemonics;
|
|
472
|
+
})));
|
|
473
|
+
console.log('recoverAssemblyKey()', shares);
|
|
474
|
+
const rawAssemblyKey = yield this.slip39Service.recoverSecret(shares, TP_PASSWORD_RESET_SLIP39_PASSPHRASE);
|
|
475
|
+
return JWK.asKey(Object.assign(Object.assign({}, assemblyKeyParams), { k: rawAssemblyKey }));
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
LifeReadyAuthService.ɵprov = i0.ɵɵdefineInjectable({ factory: function LifeReadyAuthService_Factory() { return new LifeReadyAuthService(i0.ɵɵinject(i1.LR_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.Slip39Service)); }, token: LifeReadyAuthService, providedIn: "root" });
|
|
480
|
+
LifeReadyAuthService.decorators = [
|
|
481
|
+
{ type: Injectable, args: [{
|
|
482
|
+
providedIn: 'root',
|
|
483
|
+
},] }
|
|
484
|
+
];
|
|
485
|
+
LifeReadyAuthService.ctorParameters = () => [
|
|
486
|
+
{ type: undefined, decorators: [{ type: Inject, args: [LR_CONFIG,] }] },
|
|
487
|
+
{ type: AuthClass },
|
|
488
|
+
{ type: KeyFactoryService },
|
|
489
|
+
{ type: KeyService },
|
|
490
|
+
{ type: ProfileService },
|
|
491
|
+
{ type: KeyGraphService },
|
|
492
|
+
{ type: PasswordService },
|
|
493
|
+
{ type: IdleService },
|
|
494
|
+
{ type: LrGraphQLService },
|
|
495
|
+
{ type: TpPasswordResetProcessorService },
|
|
496
|
+
{ type: PersistService },
|
|
497
|
+
{ type: EncryptionService },
|
|
498
|
+
{ type: Slip39Service }
|
|
499
|
+
];
|
|
500
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGlmZS1yZWFkeS1hdXRoLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiL29wdC9hdGxhc3NpYW4vcGlwZWxpbmVzL2FnZW50L2J1aWxkL3Byb2plY3RzL2NvcmUvc3JjLyIsInNvdXJjZXMiOlsibGliL2F1dGgvbGlmZS1yZWFkeS1hdXRoLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLE9BQU8sRUFBRSxNQUFNLEVBQUUsVUFBVSxFQUFFLFNBQVMsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUU5RCxPQUFPLEVBQUUsR0FBRyxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFFeEMsT0FBTyxFQUFjLGFBQWEsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUVqRCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sbUNBQW1DLENBQUM7QUFDcEUsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBQ3pELE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUMxRCxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUM5RCxPQUFPLEVBQ0wsMkJBQTJCLEVBQzNCLHFCQUFxQixFQUNyQixtQkFBbUIsRUFDbkIsV0FBVyxHQUNaLE1BQU0sdUJBQXVCLENBQUM7QUFDL0IsT0FBTyxFQUtMLGNBQWMsR0FDZixNQUFNLGNBQWMsQ0FBQztBQUN0QixPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDckQsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBQzNELE9BQU8sRUFDTCxzQ0FBc0MsRUFDdEMsb0NBQW9DLEVBQ3BDLHlDQUF5QyxFQUN6Qyx3QkFBd0IsR0FDekIsTUFBTSwwQ0FBMEMsQ0FBQztBQUNsRCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDN0MsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0scUNBQXFDLENBQUM7QUFDeEUs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MUMsQ0FBQztnQkFFRixJQUFJLGlCQUFpQixFQUFFO29CQUNyQixJQUNFLElBQUksQ0FBQyxTQUFTLENBQUMsaUJBQWlCLENBQUM7d0JBQ2pDLElBQUksQ0FBQyxTQUFTLENBQUMsa0JBQWtCLENBQUMsaUJBQWlCLENBQUMsRUFDcEQ7d0JBQ0EsTUFBTSxJQUFJLG1CQUFtQixDQUMzQixrRUFBa0UsQ0FDbkUsQ0FBQztxQkFDSDtpQkFDRjtxQkFBTTtvQkFDTCxpQkFBaUIsR0FBRyxrQkFBa0IsQ0FBQyxpQkFBaUIsQ0FBQztpQkFDMUQ7Z0JBQ0QsT0FBTyxrQkFBa0IsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FBQztZQUNuRCxDQUFDLENBQUEsQ0FBQyxDQUNMLENBQUM7WUFFRixPQUFPLENBQUMsR0FBRyxDQUFDLHNCQUFzQixFQUFFLE1BQU0sQ0FBQyxDQUFDO1lBRTVDLE1BQU0sY0FBYyxHQUFHLE1BQU0sSUFBSSxDQUFDLGFBQWEsQ0FBQyxhQUFhLENBQzNELE1BQU0sRUFDTixtQ0FBbUMsQ0FDcEMsQ0FBQztZQUVGLE9BQU8sR0FBRyxDQUFDLEtBQUssaUNBQ1gsaUJBQWlCLEtBQ3BCLENBQUMsRUFBRSxjQUFjLElBQ2pCLENBQUM7UUFDTCxDQUFDO0tBQUE7Ozs7WUF0cEJGLFVBQVUsU0FBQztnQkFDVixVQUFVLEVBQUUsTUFBTTthQUNuQjs7OzRDQU9JLE1BQU0sU0FBQyxTQUFTO1lBekNaLFNBQVM7WUFRVCxpQkFBaUI7WUF6QmpCLFVBQVU7WUFDVixjQUFjO1lBRmQsZUFBZTtZQWlCZixlQUFlO1lBUWYsV0FBVztZQUVYLGdCQUFnQjtZQUVoQiwrQkFBK0I7WUFFL0IsY0FBYztZQUdkLGlCQUFpQjtZQUNqQixhQUFhIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0LCBJbmplY3RhYmxlLCBpc0Rldk1vZGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IENvZ25pdG9Vc2VyIH0gZnJvbSAnQGF3cy1hbXBsaWZ5L2F1dGgnO1xuaW1wb3J0IHsgSHViIH0gZnJvbSAnQGF3cy1hbXBsaWZ5L2NvcmUnO1xuaW1wb3J0IHsgQ29nbml0b1VzZXJBdHRyaWJ1dGUgfSBmcm9tICdhbWF6b24tY29nbml0by1pZGVudGl0eS1qcyc7XG5pbXBvcnQgeyBPYnNlcnZhYmxlLCBSZXBsYXlTdWJqZWN0IH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBQYXNzSWRwUGFyYW1zIH0gZnJvbSAnLi4vY3J5cHRvZ3JhcGh5L2NyeXB0b2dyYXBoeS50eXBlcyc7XG5pbXBvcnQgeyBLZXlHcmFwaFNlcnZpY2UgfSBmcm9tICcuLi9jcnlwdG9ncmFwaHkva2V5LWdyYXBoLnNlcnZpY2UnO1xuaW1wb3J0IHsgS2V5U2VydmljZSB9IGZyb20gJy4uL2NyeXB0b2dyYXBoeS9rZXkuc2VydmljZSc7XG5pbXBvcnQgeyBQcm9maWxlU2VydmljZSB9IGZyb20gJy4uL3VzZXJzL3Byb2ZpbGUuc2VydmljZSc7XG5pbXBvcnQgeyBQYXNzd29yZENoYW5nZVN0YXR1cyB9IGZyb20gJy4uL3VzZXJzL3Byb2ZpbGUudHlwZXMnO1xuaW1wb3J0IHtcbiAgTHJDb25jdXJyZW50QWNjZXNzRXhjZXB0aW9uLFxuICBMckJhZFJlcXVlc3RFeGNlcHRpb24sXG4gIExyQmFkU3RhdGVFeGNlcHRpb24sXG4gIExyRXhjZXB0aW9uLFxufSBmcm9tICcuLi9fY29tbW9uL2V4Y2VwdGlvbnMnO1xuaW1wb3J0IHtcbiAgQ29nbml0b0NoYWxsZW5nZVVzZXIsXG4gIEN1cnJlbnRVc2VyLFxuICBUcFBhc3N3b3JkUmVzZXRVc2VyLFxuICBMb2dpblJlc3VsdCxcbiAgUmVjb3ZlcnlTdGF0dXMsXG59IGZyb20gJy4vYXV0aC50eXBlcyc7XG5pbXBvcnQgeyBQYXNzd29yZFNlcnZpY2UgfSBmcm9tICcuL3Bhc3N3b3JkLnNlcnZpY2UnO1xuaW1wb3J0IHsgQXV0aENsYXNzIH0gZnJvbSAnQGF3cy1hbXBsaWZ5L2F1dGgvbGliLWVzbS9BdXRoJztcbmltcG9ydCB7XG4gIENvbXBsZXRlVHBQYXNzd29yZFJlc2V0UmVxdWVzdE11dGF0aW9uLFxuICBDcmVhdGVUcEFzc2VtYmx5S2V5Q2hhbGxlbmdlTXV0YXRpb24sXG4gIFByZUNvbXBsZXRlVHBQYXNzd29yZFJlc2V0UmVxdWVzdE11dGF0aW9uLFxuICBUcFBhc3N3b3JkUmVzZXRVc2VyUXVlcnksXG59IGZyb20gJy4uL3RydXN0ZWQtcGFydGllcy90cC1wYXNzd29yZC1yZXNldC5ncWwnO1xuaW1wb3J0IHsgSWRsZVNlcnZpY2UgfSBmcm9tICcuL2lkbGUuc2VydmljZSc7XG5pbXBvcnQgeyBLZXlGYWN0b3J5U2VydmljZSB9IGZyb20gJy4uL2NyeXB0b2dyYXBoeS9rZXktZmFjdG9yeS5zZXJ2aWNlJztcbmltcG9ydCB7IExyR3JhcGhRTFNlcnZpY2UsIExyTXV0YXRpb24gfSBmcm9tICcuLi9hcGkvbHItZ3JhcGhxbCc7XG5pbXBvcnQgeyBUcENsYWltU3RhdGUsIFRwUGFzc3dvcmRSZXNldFVzZXJOb2RlIH0gZnJvbSAnLi4vYXBpL3R5cGVzJztcbmltcG9ydCB7IFRwUGFzc3dvcmRSZXNldFByb2Nlc3NvclNlcnZpY2UgfSBmcm9tICcuLi9hcGkvcXVlcnktcHJvY2Vzc29yL3RwLXBhc3N3b3JkLXJlc2V0LXByb2Nlc3Nvci5zZXJ2aWNlJztcbmltcG9ydCB7IFNldFNlc3Npb25FbmNyeXB0aW9uS2V5TXV0YXRpb24gfSBmcm9tICcuL2F1dGguZ3FsJztcbmltcG9ydCB7IFBlcnNpc3RTZXJ2aWNlIH0gZnJvbSAnLi4vYXBpL3BlcnNpc3Quc2VydmljZSc7XG5pbXBvcnQgeyBKV0sgfSBmcm9tICdub2RlLWpvc2UnO1xuaW1wb3J0IHsgTGlmZVJlYWR5Q29uZmlnLCBMUl9DT05GSUcgfSBmcm9tICcuLi9saWZlLXJlYWR5LmNvbmZpZyc7XG5pbXBvcnQgeyBFbmNyeXB0aW9uU2VydmljZSB9IGZyb20gJy4uL2NyeXB0b2dyYXBoeS9lbmNyeXB0aW9uLnNlcnZpY2UnO1xuaW1wb3J0IHsgU2xpcDM5U2VydmljZSB9IGZyb20gJy4uL2NyeXB0b2dyYXBoeS9zbGlwMzkuc2VydmljZSc7XG5pbXBvcnQge1xuICBUUF9QQVNTV09SRF9SRVNFVF9DTElFTlRfTk9OQ0VfTEVOR1RILFxuICBUUF9QQVNTV09SRF9SRVNFVF9TTElQMzlfUEFTU1BIUkFTRSxcbiAgVFBfUEFTU1dPUkRfUkVTRVRfVVNFUk5BTUVfU1VGRklYLFxufSBmcm9tICcuLi90cnVzdGVkLXBhcnRpZXMvdHAtcGFzc3dvcmQtcmVzZXQuY29uc3RhbnRzJztcblxuZXhwb3J0IGNvbnN0IGluaXRpYWxpc2VBdXRoID0gKGF1dGhTZXJ2aWNlOiBMaWZlUmVhZHlBdXRoU2VydmljZSkgPT4ge1xuICByZXR1cm4gKCkgPT4gYXV0aFNlcnZpY2UuaW5pdGlhbGlzZSgpO1xufTtcblxuZXhwb3J0IGludGVyZmFjZSBMb2dpbk9wdGlvbnMge1xuICB0cFBhc3N3b3JkUmVzZXRBdXRvQ29tcGxldGU/OiBib29sZWFuO1xufVxuXG5ASW5qZWN0YWJsZSh7XG4gIHByb3ZpZGVkSW46ICdyb290Jyxcbn0pXG5leHBvcnQgY2xhc3MgTGlmZVJlYWR5QXV0aFNlcnZpY2Uge1xuICBwcml2YXRlIGh1YlN1YmplY3Q6IFJlcGxheVN1YmplY3Q8YW55PiA9IG5ldyBSZXBsYXlTdWJqZWN0PGFueT4oMSk7XG4gIHByaXZhdGUgY3VycmVudFVzZXI6IEN1cnJlbnRVc2VyO1xuICBwcml2YXRlIGN1cnJlbnRSZXNldFVzZXI6IFRwUGFzc3dvcmRSZXNldFVzZXI7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgQEluamVjdChMUl9DT05GSUcpIHByaXZhdGUgY29uZmlnOiBMaWZlUmVhZHlDb25maWcsXG4gICAgcHJpdmF0ZSBhdXRoOiBBdXRoQ2xhc3MsXG4gICAgcHJpdmF0ZSBrZXlGYWN0b3J5OiBLZXlGYWN0b3J5U2VydmljZSxcbiAgICBwcml2YXRlIGtleVNlcnZpY2U6IEtleVNlcnZpY2UsXG4gICAgcHJpdmF0ZSBwcm9maWxlU2VydmljZTogUHJvZmlsZVNlcnZpY2UsXG4gICAgcHJpdmF0ZSBrZXlHcmFwaFNlcnZpY2U6IEtleUdyYXBoU2VydmljZSxcbiAgICBwcml2YXRlIHBhc3N3b3JkU2VydmljZTogUGFzc3dvcmRTZXJ2aWNlLFxuICAgIHByaXZhdGUgaWRsZVNlcnZpY2U6IElkbGVTZXJ2aWNlLFxuICAgIHByaXZhdGUgbHJHcmFwaFFMOiBMckdyYXBoUUxTZXJ2aWNlLFxuICAgIHByaXZhdGUgdHBQYXNzd29yZFJlc2V0UHJvY2Vzc29yU2VydmljZTogVHBQYXNzd29yZFJlc2V0UHJvY2Vzc29yU2VydmljZSxcbiAgICBwcml2YXRlIHBlcnNpc3RTZXJ2aWNlOiBQZXJzaXN0U2VydmljZSxcbiAgICBwcml2YXRlIGVuY3J5cHRpb25TZXJ2aWNlOiBFbmNyeXB0aW9uU2VydmljZSxcbiAgICBwcml2YXRlIHNsaXAzOVNlcnZpY2U6IFNsaXAzOVNlcnZpY2VcbiAgKSB7fVxuXG4gIHB1YmxpYyBhc3luYyBpbml0aWFsaXNlKCkge1xuICAgIEh1Yi5saXN0ZW4oJ2F1dGgnLCAoZGF0YSkgPT4gdGhpcy5odWJTdWJqZWN0Lm5leHQoZGF0YS5wYXlsb2FkKSk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGxvZ2luSWRwSW1wbChcbiAgICBlbWFpbE9yUGhvbmU6IHN0cmluZyxcbiAgICBwYXNzd29yZDogc3RyaW5nLFxuICAgIHBhc3NJZHBQYXJhbXM6IFBhc3NJZHBQYXJhbXMsXG4gICAgcmVjb3ZlcnlTdGF0dXM6IFJlY292ZXJ5U3RhdHVzXG4gICk6IFByb21pc2U8Q29nbml0b0NoYWxsZW5nZVVzZXI+IHtcbiAgICBjb25zdCBwYXNzSWRwUmVzdWx0ID0gYXdhaXQgdGhpcy5rZXlGYWN0b3J5LmRlcml2ZVBhc3NJZHAoe1xuICAgICAgcGFzc3dvcmQsXG4gICAgICAuLi5wYXNzSWRwUGFyYW1zLFxuICAgIH0pO1xuICAgIC8vIFVzZSB0aGUgZGVyaXZlZCBwYXNzd29yZCB0byBzaWduaW4gd2l0aCBjb2duaXRvXG4gICAgY29uc3QgdXNlciA9IGF3YWl0IHRoaXMuYXV0aC5zaWduSW4oXG4gICAgICBlbWFpbE9yUGhvbmUsXG4gICAgICB0aGlzLnBhc3N3b3JkU2VydmljZS5nZXRQYXNzSWRwU3RyaW5nKHBhc3NJZHBSZXN1bHQuandrKVxuICAgICk7XG5cbiAgICB1c2VyLnJlY292ZXJ5U3RhdHVzID0gcmVjb3ZlcnlTdGF0dXM7XG5cbiAgICByZXR1cm4gdXNlcjtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgbG9naW5JZHAoXG4gICAgZW1haWxPclBob25lOiBzdHJpbmcsXG4gICAgcGFzc3dvcmQ6IHN0cmluZ1xuICApOiBQcm9taXNlPENvZ25pdG9DaGFsbGVuZ2VVc2VyPiB7XG4gICAgLy8gRG93bmxvYWQgdGhlIHNhbHQgbmVlZGVkIHRvIGRlcml2ZSB0aGUgUGFzc0lkcFxuICAgIGNvbnN0IHBhc3NJZHBBcGlSZXN1bHQgPSBhd2FpdCB0aGlzLnByb2ZpbGVTZXJ2aWNlLmdldFBhc3NJZHBQYXJhbXMoXG4gICAgICBlbWFpbE9yUGhvbmVcbiAgICApO1xuXG4gICAgaWYgKFxuICAgICAgcGFzc0lkcEFwaVJlc3VsdC5wYXNzd29yZENoYW5nZVN0YXR1cyA9PT0gUGFzc3dvcmRDaGFuZ2VTdGF0dXMuSW5Qcm9ncmVzc1xuICAgICkge1xuICAgICAgdGhyb3cgbmV3IExyQ29uY3VycmVudEFjY2Vzc0V4Y2VwdGlvbignQSBwYXNzd29yZCBjaGFuZ2UgaXMgaW4gcHJvZ3Jlc3MnKTtcbiAgICB9XG5cbiAgICBpZiAoXG4gICAgICBwYXNzSWRwQXBpUmVzdWx0LnBhc3N3b3JkQ2hhbmdlU3RhdHVzID09PSBQYXNzd29yZENoYW5nZVN0YXR1cy5SZWNvdmVyeVxuICAgICkge1xuICAgICAgY29uc29sZS5sb2coJ0luIHJlY292ZXJ5IG1vZGUuJyk7XG4gICAgICAvLyBMZXQncyBzYXkgd2UgZG9uJ3Qga25vdyBpZiB0aGUgcGFzc3dvcmQgaXMgdGhlIG5ldyBvbmUgb3IgdGhlIG9sZCBvbmUuIFdlIGp1c3QgaGF2ZSB0byB0cnkgYm90aC5cbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHVzZXIgPSBhd2FpdCB0aGlzLmxvZ2luSWRwSW1wbChcbiAgICAgICAgICBlbWFpbE9yUGhvbmUsXG4gICAgICAgICAgcGFzc3dvcmQsXG4gICAgICAgICAgcGFzc0lkcEFwaVJlc3VsdC5uZXdQYXNzSWRwUGFyYW1zLFxuICAgICAgICAgIFJlY292ZXJ5U3RhdHVzLk5FV19QQVNTV09SRFxuICAgICAgICApO1xuICAgICAgICAvLyBOZXcgcGFzc3dvcmQgd29ya2VkLiBMZXQncyBzZXQgdG8gdGhlIGN1cnJlbnQgcGFzc3dvcmRcblxuICAgICAgICAvLyAtLVBvdGVudGlhbCBGYWlsdXJlIFBvaW50IDEtLVxuICAgICAgICAvLyBpZiBjaGFuZ2VQYXNzd29yZENvbXBsZXRlKCkgZG9lc24ndCBnZXQgY2FsbGVkLCB0aGVuIGl0IHNob3VsZCByZW1haW5cblxuICAgICAgICBjb25zb2xlLmxvZygnTmV3IHBhc3N3b3JkIHdvcmtzIScpO1xuXG4gICAgICAgIHJldHVybiB1c2VyO1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgLy8gSnVzdCBidWJibGUgdXAgYW55IG90aGVyIHR5cGUgb2YgZXJyb3IuXG4gICAgICAgIGlmIChlcnJvci5jb2RlICE9PSAnTm90QXV0aG9yaXplZEV4Y2VwdGlvbicpIHtcbiAgICAgICAgICB0aHJvdyBlcnJvcjtcbiAgICAgICAgfVxuICAgICAgICAvLyBwYXNzLCB0cnkgYWdhaW4gYXNzdW1pbmcgaXQncyB0aGUgb2xkIHBhc3N3b3JkXG4gICAgICB9XG5cbiAgICAgIC8vIE5vdyBhc3N1bWUgaXQncyB0aGUgcHJldmlvdXMgcGFzc3dvcmQuIEFueSBleGNlcHRpb24gaXMgYWxsb3dlZCB0byBidWJibGUgdXAuXG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCB1c2VyID0gYXdhaXQgdGhpcy5sb2dpbklkcEltcGwoXG4gICAgICAgICAgZW1haWxPclBob25lLFxuICAgICAgICAgIHBhc3N3b3JkLFxuICAgICAgICAgIHBhc3NJZHBBcGlSZXN1bHQuY3VycmVudFBhc3NJZHBQYXJhbXMsXG4gICAgICAgICAgUmVjb3ZlcnlTdGF0dXMuT0xEX1BBU1NXT1JEXG4gICAgICAgICk7XG4gICAgICAgIC8vIE9sZCBwYXNzd29yZCB3b3JrZWQuXG4gICAgICAgIGNvbnNvbGUubG9nKCdPbGQgcGFzc3dvcmQgd29ya3MhJyk7XG5cbiAgICAgICAgcmV0dXJuIHVzZXI7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAvLyBKdXN0IGJ1YmJsZSB1cCBhbnkgb3RoZXIgdHlwZSBvZiBlcnJvci5cbiAgICAgICAgdGhyb3cgZXJyb3IuY29kZSA9PT0gJ05vdEF1dGhvcml6ZWRFeGNlcHRpb24nXG4gICAgICAgICAgPyBuZXcgTHJCYWRSZXF1ZXN0RXhjZXB0aW9uKFxuICAgICAgICAgICAgICAnVGhlIHBhc3N3b3JkIGNoYW5nZSByZXF1ZXN0IHdhcyBpbnRlcnJ1cHRlZCwgcGxlYXNlIHRyeSB0byBsb2dpbiB3aXRoIGJvdGggeW91ciBuZXcgYW5kIG9sZCBwYXNzd29yZCdcbiAgICAgICAgICAgIClcbiAgICAgICAgICA6IGVycm9yO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIFRyeSBhZ2FpbnN0IGFzIHRoZSBUUCBwYXNzd29yZCByZXNldCBhY2NvdW50XG4gICAgaWYgKHBhc3NJZHBBcGlSZXN1bHQudHBQYXNzd29yZFJlc2V0KSB7XG4gICAgICB0cnkge1xuICAgICAgICAvLyBUUCBwYXNzd29yZCByZXNldCBpcyBpbiBwcm9jZXNzLiBXZSBuZWVkIHRvIHRyeSB0aGUgcGFzc3dvcmQgYWdhaW5zdCBib3RoXG4gICAgICAgIC8vIG9yaWdpbmFsIGFjY291bnQgYW5kIHRoZSBuZXcgcmVzZXQgYWNjb3VudC5cbiAgICAgICAgY29uc3QgcmVzZXQgPSBwYXNzSWRwQXBpUmVzdWx0LnRwUGFzc3dvcmRSZXNldDtcbiAgICAgICAgY29uc3QgcmV0ID0gYXdhaXQgdGhpcy5sb2dpbklkcEltcGwoXG4gICAgICAgICAgcmVzZXQucmVzZXRVc2VybmFtZSxcbiAgICAgICAgICBwYXNzd29yZCxcbiAgICAgICAgICByZXNldC5wYXNzSWRwUGFyYW1zLFxuICAgICAgICAgIFJlY292ZXJ5U3RhdHVzLk5PTkVcbiAgICAgICAgKTtcbiAgICAgICAgcmV0LmlzVHBQYXNzd29yZFJlc2V0VXNlciA9IHRydWU7XG5cbiAgICAgICAgcmV0dXJuIHJldDtcbiAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAvLyBjb250aW51ZSwgdHJ5IGFnYWluIGFzIHJlZ3VsYXIgdXNlci5cbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBMb2dpbiBhcyByZWd1bGFyIHVzZXJcbiAgICByZXR1cm4gYXdhaXQgdGhpcy5sb2dpbklkcEltcGwoXG4gICAgICBlbWFpbE9yUGhvbmUsXG4gICAgICBwYXNzd29yZCxcbiAgICAgIHBhc3NJZHBBcGlSZXN1bHQuY3VycmVudFBhc3NJZHBQYXJhbXMsXG4gICAgICBSZWNvdmVyeVN0YXR1cy5OT05FXG4gICAgKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBhc3luYyBoYW5kbGVTZXNzaW9uRW5jcnlwdGlvbktleSgpIHtcbiAgICBpZiAodGhpcy5jb25maWcuZGlzYWJsZVNlc3Npb25FbmNyeXB0aW9uS2V5KSB7XG4gICAgICBpZiAoIWlzRGV2TW9kZSgpKSB7XG4gICAgICAgIGNvbnN0IG1zZyA9XG4gICAgICAgICAgJ1lvdSBzaG91bGQgbm90IHNldCBkaXNhYmxlU2Vzc2lvbkVuY3J5cHRpb25LZXk9VHJ1ZSBpbiBtb2RlIHByb2QuIEl0IGRlZmF1bHRzIHRvIGZhbHNlLic7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IobXNnKTtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKG1zZyk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zb2xlLndhcm4oXG4gICAgICAgICAgJ1lvdSBoYXZlIHNldCBkaXNhYmxlU2Vzc2lvbkVuY3J5cHRpb25LZXk9VHJ1ZS4gTWFrZSBzdXJlIG5vdCB0byBkbyB0aGlzIGluIHByb2QgbW9kZS4nXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIFNldCB0aGUgc2Vzc2lvbiBrZXkgdG8gYSBuZXcgZW5jcnlwdGlvbiBrZXkgZm9yIHRoaXMgc2Vzc2lvblxuICAgICAgY29uc3Qgc2Vzc2lvbkVuY3J5cHRpb25LZXkgPSBhd2FpdCB0aGlzLmtleUZhY3RvcnkuY3JlYXRlS2V5KCk7XG4gICAgICBhd2FpdCB0aGlzLmxyR3JhcGhRTC5sck11dGF0ZShcbiAgICAgICAgbmV3IExyTXV0YXRpb24oe1xuICAgICAgICAgIG11dGF0aW9uOiBTZXRTZXNzaW9uRW5jcnlwdGlvbktleU11dGF0aW9uLFxuICAgICAgICAgIHZhcmlhYmxlczoge1xuICAgICAgICAgICAgaW5wdXQ6IHtcbiAgICAgICAgICAgICAgc2Vzc2lvbkVuY3J5cHRpb25LZXk6IEpTT04uc3RyaW5naWZ5KFxuICAgICAgICAgICAgICAgIHNlc3Npb25FbmNyeXB0aW9uS2V5LnRvSlNPTih0cnVlKVxuICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9LFxuICAgICAgICB9KSxcbiAgICAgICAge1xuICAgICAgICAgIGluY2x1ZGVLZXlHcmFwaDogZmFsc2UsXG4gICAgICAgIH1cbiAgICAgICk7XG5cbiAgICAgIHRoaXMucGVyc2lzdFNlcnZpY2Uuc2V0U2VydmVyU2Vzc2lvbkVuY3J5cHRpb25LZXkoc2Vzc2lvbkVuY3J5cHRpb25LZXkpO1xuICAgIH1cbiAgfVxuXG4gIHByb3RlY3RlZCBhc3luYyBoYW5kbGVQb3N0QXV0aChjb2duaXRvVXNlcjogQ29nbml0b0NoYWxsZW5nZVVzZXIpIHtcbiAgICBhd2FpdCB0aGlzLmhhbmRsZVBhc3N3b3JkUmVjb3ZlcnkoY29nbml0b1VzZXIpO1xuICAgIGF3YWl0IHRoaXMuaGFuZGxlU2Vzc2lvbkVuY3J5cHRpb25LZXkoKTtcbiAgfVxuXG4gIHB1YmxpYyBhc3luYyBsb2dpbihcbiAgICBlbWFpbE9yUGhvbmU6IHN0cmluZyxcbiAgICBwYXNzd29yZDogc3RyaW5nLFxuICAgIHsgdHBQYXNzd29yZFJlc2V0QXV0b0NvbXBsZXRlID0gdHJ1ZSB9OiBMb2dpbk9wdGlvbnMgPSB7fVxuICApIHtcbiAgICBsZXQgbG9naW5SZXN1bHQgPSBhd2FpdCB0aGlzLmxvZ2luSW1wbChlbWFpbE9yUGhvbmUsIHBhc3N3b3JkKTtcblxuICAgIGlmIChcbiAgICAgIHRwUGFzc3dvcmRSZXNldEF1dG9Db21wbGV0ZSAmJlxuICAgICAgbG9naW5SZXN1bHQucmVzZXRVc2VyPy5zdGF0ZSA9PT0gVHBDbGFpbVN0YXRlLkFQUFJPVkVEXG4gICAgKSB7XG4gICAgICBhd2FpdCB0aGlzLmNvbXBsZXRlUmVxdWVzdChwYXNzd29yZCk7XG4gICAgICBsb2dpblJlc3VsdCA9IGF3YWl0IHRoaXMubG9naW5JbXBsKGVtYWlsT3JQaG9uZSwgcGFzc3dvcmQpO1xuICAgIH1cblxuICAgIHJldHVybiBsb2dpblJlc3VsdDtcbiAgfVxuXG4gIHB1YmxpYyBhc3luYyBsb2dpbkltcGwoXG4gICAgZW1haWxPclBob25lOiBzdHJpbmcsXG4gICAgcGFzc3dvcmQ6IHN0cmluZ1xuICApOiBQcm9taXNlPExvZ2luUmVzdWx0PiB7XG4gICAgYXdhaXQgdGhpcy5sb2dvdXQoKTtcbiAgICBjb25zdCBjb2duaXRvVXNlciA9IGF3YWl0IHRoaXMubG9naW5JZHAoZW1haWxPclBob25lLCBwYXNzd29yZCk7XG5cbiAgICAvLyB0b2RvOiBNZWV0IE1GQSBjaGFsbGVuZ2VzLlxuICAgIGlmIChbJ1NNU19NRkEnLCAnU09GVFdBUkVfVE9LRU5fTUZBJ10uaW5jbHVkZXMoY29nbml0b1VzZXIuY2hhbGxlbmdlTmFtZSkpIHtcbiAgICAgIHJldHVybiB7IGhhc0NoYWxsZW5nZTogdHJ1ZSwgY2hhbGxlbmdlOiBjb2duaXRvVXNlciB9O1xuICAgIH1cblxuICAgIGF3YWl0IHRoaXMuaGFuZGxlUG9zdEF1dGgoY29nbml0b1VzZXIpO1xuXG4gICAgaWYgKGNvZ25pdG9Vc2VyLmlzVHBQYXNzd29yZFJlc2V0VXNlcikge1xuICAgICAgLy8gQXNzdW1pbmcgdGhlcmUgaXMgbm8gTUZBIG9uIHRoZSBUUCByZXNldCB1c2VyLlxuICAgICAgY29uc3QgcmVzZXRVc2VyID0gYXdhaXQgdGhpcy5sb2FkUmVzZXRVc2VyKHBhc3N3b3JkKTtcbiAgICAgIHJldHVybiB7IGhhc0NoYWxsZW5nZTogZmFsc2UsIHJlc2V0VXNlciB9O1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCB1c2VyID0gYXdhaXQgdGhpcy5sb2FkVXNlcihjb2duaXRvVXNlciwgcGFzc3dvcmQpO1xuICAgICAgYXdhaXQgdGhpcy5pZGxlU2VydmljZS5zdGFydCgpOyAvLyBSdW4gaWRsZVNlcnZpY2Ugd2hlbmV2ZXIgdXNlciBpcyBsb2dnZWQgaW4uXG4gICAgICByZXR1cm4geyBoYXNDaGFsbGVuZ2U6IGZhbHNlLCB1c2VyIH07XG4gICAgfVxuICB9XG5cbiAgLy8gVE9ETyA8QVo+IFdlIG5lZWQgdG8gaGFuZGxlIHRoZSBpc1RwUGFzc3dvcmRSZXNldFVzZXI9VHJ1ZSBjYXNlIGhlcmUgYWZ0ZXIgTUZBIGFzIHdlbGwuXG4gIHB1YmxpYyBhc3luYyB2ZXJpZnlMb2dpbihcbiAgICBjaGFsbGVuZ2U6IENvZ25pdG9DaGFsbGVuZ2VVc2VyLFxuICAgIHBhc3N3b3JkOiBzdHJpbmcsXG4gICAgcmVtZW1iZXJNZTogYm9vbGVhbixcbiAgICBjb2RlOiBzdHJpbmdcbiAgKTogUHJvbWlzZTxDdXJyZW50VXNlcj4ge1xuICAgIGF3YWl0IHRoaXMuYXV0aC5jb25maXJtU2lnbkluKGNoYWxsZW5nZSwgY29kZSwgY2hhbGxlbmdlLmNoYWxsZW5nZU5hbWUpO1xuXG4gICAgLy8gVE9ETzogdGhpcy5hdXRoLmNvbmZpcm1TaWduSW4oKSBjb3VsZCByZXR1cm4gYW5vdGhlciBjaGFsbGVuZ2UuXG5cbiAgICBjb25zdCBjb2duaXRvVXNlcjogQ29nbml0b1VzZXIgPSBhd2FpdCB0aGlzLmF1dGguY3VycmVudEF1dGhlbnRpY2F0ZWRVc2VyKCk7XG5cbiAgICBhd2FpdCB0aGlzLmhhbmRsZVBvc3RBdXRoKGNoYWxsZW5nZSk7XG5cbiAgICBjb25zdCB1c2VyID0gYXdhaXQgdGhpcy5sb2FkVXNlcihjb2duaXRvVXNlciwgcGFzc3dvcmQpO1xuXG4gICAgaWYgKHJlbWVtYmVyTWUpIHtcbiAgICAgIGNvZ25pdG9Vc2VyLnNldERldmljZVN0YXR1c1JlbWVtYmVyZWQoe1xuICAgICAgICBvblN1Y2Nlc3M6ICgpID0+IHt9LFxuICAgICAgICBvbkZhaWx1cmU6IChlKSA9PiBjb25zb2xlLmVycm9yKGUpLFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHVzZXI7XG4gIH1cblxuICBhc3luYyBoYW5kbGVQYXNzd29yZFJlY292ZXJ5KHVzZXI6IENvZ25pdG9DaGFsbGVuZ2VVc2VyKSB7XG4gICAgaWYgKHVzZXIucmVjb3ZlcnlTdGF0dXMgIT09IFJlY292ZXJ5U3RhdHVzLk5PTkUpIHtcbiAgICAgIGNvbnN0IGp3dFRva2VuID0gdXNlclxuICAgICAgICAuZ2V0U2lnbkluVXNlclNlc3Npb24oKVxuICAgICAgICAuZ2V0QWNjZXNzVG9rZW4oKVxuICAgICAgICAuZ2V0Snd0VG9rZW4oKTtcbiAgICAgIGF3YWl0IHRoaXMucGFzc3dvcmRTZXJ2aWNlLmNoYW5nZVBhc3N3b3JkQ29tcGxldGUoXG4gICAgICAgIGp3dFRva2VuLFxuICAgICAgICB1c2VyLnJlY292ZXJ5U3RhdHVzID09PSBSZWNvdmVyeVN0YXR1cy5ORVdfUEFTU1dPUkRcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgYXN5bmMgZ2V0VXNlck9yUmVzZXRVc2VyKFxuICAgIHJlbG9hZDogYm9vbGVhbiA9IGZhbHNlXG4gICk6IFByb21pc2U8Q3VycmVudFVzZXIgfCBUcFBhc3N3b3JkUmVzZXRVc2VyPiB7XG4gICAgY29uc3QgY29nbml0b1VzZXIgPSBhd2FpdCB0aGlzLmF1dGguY3VycmVudEF1dGhlbnRpY2F0ZWRVc2VyKCk7XG5cbiAgICBpZiAoY29nbml0b1VzZXIuZ2V0VXNlcm5hbWUoKS5lbmRzV2l0aChUUF9QQVNTV09SRF9SRVNFVF9VU0VSTkFNRV9TVUZGSVgpKSB7XG4gICAgICByZXR1cm4gdGhpcy5nZXRSZXNldFVzZXIocmVsb2FkKTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIHRoaXMuZ2V0VXNlcihyZWxvYWQpO1xuICAgIH1cbiAgfVxuXG4gIGFzeW5jIGdldFJlc2V0VXNlcihyZWxvYWQ6IGJvb2xlYW4gPSBmYWxzZSk6IFByb21pc2U8VHBQYXNzd29yZFJlc2V0VXNlcj4ge1xuICAgIGlmICghcmVsb2FkICYmIHRoaXMuY3VycmVudFJlc2V0VXNlcikge1xuICAgICAgcmV0dXJuIHRoaXMuY3VycmVudFJlc2V0VXNlcjtcbiAgICB9XG5cbiAgICB0aGlzLmN1cnJlbnRSZXNldFVzZXIgPSBhd2FpdCB0aGlzLmxvYWRSZXNldFVzZXIoKTtcblxuICAgIGF3YWl0IHRoaXMuaWRsZVNlcnZpY2Uuc3RhcnQoKTsgLy8gUnVuIGlkbGVTZXJ2aWNlIHdoZW5ldmVyIHVzZXIgaXMgbG9nZ2VkIGluLlxuXG4gICAgcmV0dXJuIHRoaXMuY3VycmVudFJlc2V0VXNlcjtcbiAgfVxuXG4gIGFzeW5jIGdldFVzZXIocmVsb2FkOiBib29sZWFuID0gZmFsc2UpOiBQcm9taXNlPEN1cnJlbnRVc2VyPiB7XG4gICAgaWYgKCFyZWxvYWQgJiYgdGhpcy5jdXJyZW50VXNlcikge1xuICAgICAgcmV0dXJuIHRoaXMuY3VycmVudFVzZXI7XG4gICAgfVxuICAgIHRoaXMuY3VycmVudFVzZXIgPSBhd2FpdCB0aGlzLmxvYWRVc2VyKFxuICAgICAgYXdhaXQgdGhpcy5hdXRoLmN1cnJlbnRBdXRoZW50aWNhdGVkVXNlcigpXG4gICAgKTtcbiAgICBjb25zb2xlLmxvZygnU3RhcnRpbmcgaWRsZSBzZXJ2aWNlLicpO1xuICAgIGF3YWl0IHRoaXMuaWRsZVNlcnZpY2Uuc3RhcnQoKTsgLy8gUnVuIGlkbGVTZXJ2aWNlIHdoZW5ldmVyIHVzZXIgaXMgbG9nZ2VkIGluLlxuICAgIHJldHVybiB0aGlzLmN1cnJlbnRVc2VyO1xuICB9XG5cbiAgcHJpdmF0ZSBtYXBUUFZhdWx0QWNjZXNzKGZlYXR1cmVzPzogYW55KTogYm9vbGVhbiB7XG4gICAgY29uc3QgdHBWYXVsdEZlYXR1cmUgPSBmZWF0dXJlcz8udHBWYXVsdDtcbiAgICByZXR1cm4gKFxuICAgICAgdHBWYXVsdEZlYXR1cmU/Lmxlbmd0aCA+IDAgJiZcbiAgICAgIHRwVmF1bHRGZWF0dXJlLnNvbWUoKGZlYXR1cmUpID0+IGZlYXR1cmUudG9VcHBlckNhc2UoKSA9PT0gJ0FDQ0VTUycpXG4gICAgKTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgbG9hZFVzZXIoXG4gICAgY29nbml0b1VzZXI6IENvZ25pdG9Vc2VyLFxuICAgIHBhc3N3b3JkPzogc3RyaW5nXG4gICk6IFByb21pc2U8Q3VycmVudFVzZXI+IHtcbiAgICBjb25zdCB7XG4gICAgICBjdXJyZW50VXNlcixcbiAgICAgIGNvbnRhY3RDYXJkLFxuICAgICAgdXNlclBsYW5zLFxuICAgIH0gPSBhd2FpdCB0aGlzLnByb2ZpbGVTZXJ2aWNlLmdldEN1cnJlbnRVc2VyKCk7XG5cbiAgICBpZiAoY3VycmVudFVzZXIuc2Vzc2lvbkVuY3J5cHRpb25LZXkpIHtcbiAgICAgIHRoaXMucGVyc2lzdFNlcnZpY2Uuc2V0U2VydmVyU2Vzc2lvbkVuY3J5cHRpb25LZXkoXG4gICAgICAgIGF3YWl0IEpXSy5hc0tleShjdXJyZW50VXNlci5zZXNzaW9uRW5jcnlwdGlvbktleSlcbiAgICAgICk7XG4gICAgfVxuXG4gICAgY29uc3QgdXNlckF0dHJpYnV0ZXMgPSBhd2FpdCB0aGlzLmF1dGgudXNlckF0dHJpYnV0ZXMoY29nbml0b1VzZXIpO1xuXG4gICAgaWYgKHBhc3N3b3JkKSB7XG4gICAgICBjb25zdCBwYXNzS2V5ID0gKFxuICAgICAgICBhd2FpdCB0aGlzLmtleUZhY3RvcnkuZGVyaXZlUGFzc0tleSh7XG4gICAgICAgICAgcGFzc3dvcmQsXG4gICAgICAgICAgLi4uY3VycmVudFVzZXIuY3VycmVudFVzZXJLZXkucGFzc0tleS5wYXNzS2V5UGFyYW1zLFxuICAgICAgICB9KVxuICAgICAgKS5qd2s7XG5cbiAgICAgIGF3YWl0IHRoaXMuaWRsZVNlcnZpY2UucGVyc2lzdE1hc3RlcktleShcbiAgICAgICAgYXdhaXQgdGhpcy5rZXlHcmFwaFNlcnZpY2UudW53cmFwV2l0aFBhc3NLZXkoXG4gICAgICAgICAgY3VycmVudFVzZXIuY3VycmVudFVzZXJLZXkucGFzc0tleS5pZCxcbiAgICAgICAgICBwYXNzS2V5LFxuICAgICAgICAgIGN1cnJlbnRVc2VyLmN1cnJlbnRVc2VyS2V5Lm1hc3RlcktleS5pZFxuICAgICAgICApXG4gICAgICApO1xuICAgIH1cbiAgICBhd2FpdCB0aGlzLmtleUdyYXBoU2VydmljZS5wb3B1bGF0ZUtleXMoY3VycmVudFVzZXIuY3VycmVudFVzZXJLZXkpO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIGlkOiBjdXJyZW50VXNlci5pZCxcbiAgICAgIHN1YjogdGhpcy5nZXRVc2VyQXR0cmlidXRlKCdzdWInLCB1c2VyQXR0cmlidXRlcyksXG4gICAgICB1c2VybmFtZTogY3VycmVudFVzZXIudXNlcm5hbWUsXG4gICAgICBjdXJyZW50VXNlcktleTogY3VycmVudFVzZXIuY3VycmVudFVzZXJLZXksXG4gICAgICBnZXRBY2Nlc3NKd3RUb2tlbjogKCkgPT5cbiAgICAgICAgY29nbml0b1VzZXIuZ2V0U2lnbkluVXNlclNlc3Npb24oKS5nZXRBY2Nlc3NUb2tlbigpLmdldEp3dFRva2VuKCksXG4gICAgICBlbWFpbDogdGhpcy5nZXRVc2VyQXR0cmlidXRlKCdlbWFpbCcsIHVzZXJBdHRyaWJ1dGVzKSxcbiAgICAgIGVtYWlsVmVyaWZpZWQ6XG4gICAgICAgIHRoaXMuZ2V0VXNlckF0dHJpYnV0ZSgnZW1haWxfdmVyaWZpZWQnLCB1c2VyQXR0cmlidXRlcykgPT09ICd0cnVlJyxcbiAgICAgIHBob25lOiB0aGlzLmdldFVzZXJBdHRyaWJ1dGUoJ3Bob25lX251bWJlcicsIHVzZXJBdHRyaWJ1dGVzKSxcbiAgICAgIHBob25lVmVyaWZpZWQ6XG4gICAgICAgIHRoaXMuZ2V0VXNlckF0dHJpYnV0ZSgncGhvbmVfbnVtYmVyX3ZlcmlmaWVkJywgdXNlckF0dHJpYnV0ZXMpID09PVxuICAgICAgICAndHJ1ZScsXG4gICAgICBjb250YWN0Q2FyZDoge1xuICAgICAgICAuLi4oYXdhaXQgdGhpcy5wcm9maWxlU2VydmljZS5kZWNyeXB0Q29udGFjdENhcmQoY29udGFjdENhcmQpKSxcbiAgICAgIH0sXG4gICAgICB1c2VyRGVsZXRlOiBjdXJyZW50VXNlci51c2VyRGVsZXRlLFxuICAgICAgdXNlclBsYW5zLFxuICAgICAgaGFzVFBWYXVsdEFjY2VzczogdGhpcy5tYXBUUFZhdWx0QWNjZXNzKGN1cnJlbnRVc2VyLmZlYXR1cmVzKSxcbiAgICAgIGZlYXR1cmVzOiBjdXJyZW50VXNlci5mZWF0dXJlcyxcbiAgICAgIHNlc3Npb25FbmNyeXB0aW9uS2V5OiBjdXJyZW50VXNlci5zZXNzaW9uRW5jcnlwdGlvbktleSxcbiAgICB9O1xuICB9XG5cbiAgcHVibGljIHdhdGNoQXV0aCgpOiBPYnNlcnZhYmxlPGFueT4ge1xuICAgIHJldHVybiB0aGlzLmh1YlN1YmplY3Q7XG4gIH1cblxuICBwdWJsaWMgYXN5bmMgbG9nb3V0KCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRoaXMuY3VycmVudFVzZXIgPSBudWxsO1xuICAgIHRoaXMua2V5U2VydmljZS5wdXJnZUtleXMoKTtcbiAgICB0aGlzLmtleUdyYXBoU2VydmljZS5wdXJnZUtleXMoKTtcblxuICAgIGF3YWl0IFByb21pc2UuYWxsKFt0aGlzLmF1dGguc2lnbk91dCgpLCB0aGlzLnByb2ZpbGVTZXJ2aWNlLnNpZ25PdXQoKV0pO1xuICB9XG5cbiAgcHJpdmF0ZSBnZXRVc2VyQXR0cmlidXRlKFxuICAgIGF0dHJpYnV0ZU5hbWU6IHN0cmluZyxcbiAgICB1c2VyQXR0cmlidXRlczogQ29nbml0b1VzZXJBdHRyaWJ1dGVbXVxuICApIHtcbiAgICBjb25zdCB1c2VyQXR0cmlidXRlID0gdXNlckF0dHJpYnV0ZXMuZmluZChcbiAgICAgICh4KSA9PiB4LmdldE5hbWUoKSA9PT0gYXR0cmlidXRlTmFtZVxuICAgICk7XG5cbiAgICByZXR1cm4gdXNlckF0dHJpYnV0ZSA/IHVzZXJBdHRyaWJ1dGUuZ2V0VmFsdWUoKSA6IG51bGw7XG4gIH1cblxuICBwdWJsaWMgYXN5bmMgbG9hZFJlc2V0VXNlcihwYXNzd29yZD86IHN0cmluZyk6IFByb21pc2U8VHBQYXNzd29yZFJlc2V0VXNlcj4ge1xuICAgIGNvbnN0IHsgdHBQYXNzd29yZFJlc2V0VXNlcjogcmVzZXRVc2VyIH0gPSBhd2FpdCB0aGlzLmxyR3JhcGhRTC5xdWVyeSh7XG4gICAgICBxdWVyeTogVHBQYXNzd29yZFJlc2V0VXNlclF1ZXJ5LFxuICAgIH0pO1xuXG4gICAgaWYgKHJlc2V0VXNlci5zZXNzaW9uRW5jcnlwdGlvbktleSkge1xuICAgICAgdGhpcy5wZXJzaXN0U2VydmljZS5zZXRTZXJ2ZXJTZXNzaW9uRW5jcnlwdGlvbktleShcbiAgICAgICAgYXdhaXQgSldLLmFzS2V5KHJlc2V0VXNlci5zZXNzaW9uRW5jcnlwdGlvbktleSlcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gVXBkYXRlIHRoZSBrZXlzXG4gICAgaWYgKHBhc3N3b3JkKSB7XG4gICAgICBjb25zdCBwYXNzS2V5ID0gKFxuICAgICAgICBhd2FpdCB0aGlzLmtleUZhY3RvcnkuZGVyaXZlUGFzc0tleSh7XG4gICAgICAgICAgcGFzc3dvcmQsXG4gICAgICAgICAgLi4ucmVzZXRVc2VyLnBhc3NLZXkucGFzc0tleVBhcmFtcyxcbiAgICAgICAgfSlcbiAgICAgICkuandrO1xuXG4gICAgICBhd2FpdCB0aGlzLmlkbGVTZXJ2aWNlLnBlcnNpc3RNYXN0ZXJLZXkoXG4gICAgICAgIGF3YWl0IHRoaXMua2V5R3JhcGhTZXJ2aWNlLnVud3JhcFdpdGhQYXNzS2V5KFxuICAgICAgICAgIHJlc2V0VXNlci5wYXNzS2V5LmlkLFxuICAgICAgICAgIHBhc3NLZXksXG4gICAgICAgICAgcmVzZXRVc2VyLm1hc3RlcktleS5pZFxuICAgICAgICApXG4gICAgICApO1xuICAgIH1cblxuICAgIHRoaXMua2V5U2VydmljZS5wb3B1bGF0ZUtleXMoe1xuICAgICAgcGFzc0tleToge1xuICAgICAgICBpZDogcmVzZXRVc2VyLnBhc3NLZXkuaWQsXG4gICAgICB9LFxuICAgICAgbWFzdGVyS2V5OiB7XG4gICAgICAgIGlkOiByZXNldFVzZXIubWFzdGVyS2V5LmlkLFxuICAgICAgfSxcbiAgICB9KTtcblxuICAgIGNvbnN0IHVzZXJBdHRyaWJ1dGVzID0gYXdhaXQgdGhpcy5hdXRoLnVzZXJBdHRyaWJ1dGVzKFxuICAgICAgYXdhaXQgdGhpcy5hdXRoLmN1cnJlbnRBdXRoZW50aWNhdGVkVXNlcigpXG4gICAgKTtcbiAgICBjb25zdCBzdWIgPSB0aGlzLmdldFVzZXJBdHRyaWJ1dGUoJ3N1YicsIHVzZXJBdHRyaWJ1dGVzKTtcblxuICAgIHJldHVybiB7XG4gICAgICAuLi4oYXdhaXQgdGhpcy50cFBhc3N3b3JkUmVzZXRQcm9jZXNzb3JTZXJ2aWNlLnByb2Nlc3NUcFBhc3N3b3JkUmVzZXRVc2VyTm9kZShcbiAgICAgICAgcmVzZXRVc2VyXG4gICAgICApKSxcbiAgICAgIHN1YixcbiAgICB9O1xuICB9XG5cbiAgcHVibGljIGFzeW5jIHJlZnJlc2hBY2Nlc3NUb2tlbigpIHtcbiAgICBjb25zdCBjb2duaXRvVXNlcjogQ29nbml0b1VzZXIgPSBhd2FpdCB0aGlzLmF1dGguY3VycmVudEF1dGhlbnRpY2F0ZWRVc2VyKCk7XG4gICAgY29uc3QgcmVmcmVzaFRva2VuID0gY29nbml0b1VzZXIuZ2V0U2lnbkluVXNlclNlc3Npb24oKS5nZXRSZWZyZXNoVG9rZW4oKTtcblxuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICBjb2duaXRvVXNlci5yZWZyZXNoU2Vzc2lvbihyZWZyZXNoVG9rZW4sIChlcnIsIGRhdGEpID0+IHtcbiAgICAgICAgaWYgKGVycikge1xuICAgICAgICAgIGNvbnNvbGUuZXJyb3IoJ0Vycm9yIHJlZnJlc2hpbmcgdG9rZW46ICcsIGVycik7XG4gICAgICAgICAgcmVqZWN0KGVycik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY29uc29sZS5sb2coJ1Rva2VuIHJlZnJlc2ggY29tcGxldGU6ICcsIGRhdGEpO1xuICAgICAgICAgIHJlc29sdmUoMCk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG5cbiAgYXN5bmMgY29tcGxldGVSZXF1ZXN0KG5ld1Bhc3N3b3JkOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCByZXNldFVzZXIgPSBhd2FpdCB0aGlzLmdldFJlc2V0VXNlcih0cnVlKTtcblxuICAgIGlmIChyZXNldFVzZXIuc3RhdGUgIT09IFRwQ2xhaW1TdGF0ZS5BUFBST1ZFRCkge1xuICAgICAgdGhyb3cgbmV3IExyQmFkU3RhdGVFeGNlcHRpb24oXG4gICAgICAgICdQYXNzd29yZCByZXNldCByZXF1ZXN0IGhhcyBub3QgYmVlbiBhcHByb3ZlZC4nXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgLy8gUHJlcGFyZSBhbGwgbWF0ZXJpYWxzIHRvIGVuc3VyZSB0aGVyZSBhcmUgbm8gZXJyb3JzLlxuICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgY29uc3QgYXNzZW1ibHlLZXkgPSBhd2FpdCB0aGlzLnJlY292ZXJBc3NlbWJseUtleShyZXNldFVzZXIpO1xuXG4gICAgY29uc3QgeyByb290S2V5IH0gPSBhd2FpdCB0aGlzLmVuY3J5cHRpb25TZXJ2aWNlLmRlY3J5cHQoXG4gICAgICBhc3NlbWJseUtleSxcbiAgICAgIHJlc2V0VXNlci5hc3NlbWJseUNpcGhlckRhdGFcbiAgICApO1xuICAgIGNvbnNvbGUubG9nKHJvb3RLZXkpO1xuXG4gICAgLy8gTWFraW5nIHN1cmUgaXQncyBhIHZhbGlkIGtleS5cbiAgICBjb25zdCByb290S2V5SndrID0gYXdhaXQgSldLLmFzS2V5KHJvb3RLZXkpO1xuXG4gICAgY29uc3QgbWFzdGVyS2V5ID0gYXdhaXQgdGhpcy5rZXlHcmFwaFNlcnZpY2UuZ2V0S2V5KHJlc2V0VXNlci5tYXN0ZXJLZXkuaWQpO1xuXG4gICAgY29uc3QgbWFzdGVyS2V5V3JhcHBlZFJvb3RLZXkgPSBhd2FpdCB0aGlzLmVuY3J5cHRpb25TZXJ2aWNlLmVuY3J5cHRUb1N0cmluZyhcbiAgICAgIG1hc3RlcktleS5qd2ssXG4gICAgICByb290S2V5SndrLnRvSlNPTih0cnVlKVxuICAgICk7XG5cbiAgICAvLyBUaGUgbmV3IHBhc3N3b3JkXG4gICAgY29uc3QgbmV3UGFzc0lkcFJlc3VsdCA9IGF3YWl0IHRoaXMua2V5RmFjdG9yeS5kZXJpdmVQYXNzSWRwKHtcbiAgICAgIHBhc3N3b3JkOiBuZXdQYXNzd29yZCxcbiAgICAgIC4uLnJlc2V0VXNlci5wYXNzS2V5LnBhc3NJZHBQYXJhbXMsXG4gICAgfSk7XG5cbiAgICBjb25zdCBuZXdJZHBQYXNzd29yZCA9IHRoaXMucGFzc3dvcmRTZXJ2aWNlLmdldFBhc3NJZHBTdHJpbmcoXG4gICAgICBuZXdQYXNzSWRwUmVzdWx0Lmp3a1xuICAgICk7XG5cbiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgIC8vIEdldCBhc3NlbWJseSBrZXkgY2hhbGxlbmdlXG4gICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgICBjb25zdCBjaGFsbGVuZ2UgPSAoXG4gICAgICBhd2FpdCB0aGlzLmxyR3JhcGhRTC5sck11dGF0ZShcbiAgICAgICAgbmV3IExyTXV0YXRpb24oe1xuICAgICAgICAgIG11dGF0aW9uOiBDcmVhdGVUcEFzc2VtYmx5S2V5Q2hhbGxlbmdlTXV0YXRpb24sXG4gICAgICAgICAgdmFyaWFibGVzOiB7XG4gICAgICAgICAgICBpbnB1dDoge30sXG4gICAgICAgICAgfSxcbiAgICAgICAgfSksXG4gICAgICAgIHtcbiAgICAgICAgICBpbmNsdWRlS2V5R3JhcGg6IGZhbHNlLFxuICAgICAgICB9XG4gICAgICApXG4gICAgKS5jcmVhdGVUcEFzc2VtYmx5S2V5Q2hhbGxlbmdlLmNoYWxsZW5nZTtcblxuICAgIGNvbnNvbGUubG9nKGNoYWxsZW5nZSk7XG5cbiAgICAvLyBTaWduIHRoZSBjaGFsbGVuZ2VcbiAgICAvLyBHZW5lcmF0ZSBhIGNsaWVudCBzaWRlIG5vbmNlIHRoYXQncyBubyBpbiB0aGUgc2VydmVyJ3MgY29udHJvbC5cbiAgICBjaGFsbGVuZ2UuY2xpZW50Tm9uY2UgPSB0aGlzLmtleUZhY3RvcnkucmFuZG9tU3RyaW5nKFxuICAgICAgVFBfUEFTU1dPUkRfUkVTRVRfQ0xJRU5UX05PTkNFX0xFTkdUSFxuICAgICk7XG4gICAgY29uc29sZS5sb2coY2hhbGxlbmdlKTtcblxuICAgIGNvbnN0IGFzc2VtYmx5S2V5VmVyaWZpZXJQcmsgPSBhd2FpdCB0aGlzLmVuY3J5cHRpb25TZXJ2aWNlLmRlY3J5cHQoXG4gICAgICBhc3NlbWJseUtleSxcbiAgICAgIHJlc2V0VXNlci53cmFwcGVkQXNzZW1ibHlLZXlWZXJpZmllclBya1xuICAgICk7XG4gICAgY29uc3Qgc2lnbmVkQ2hhbGxlbmdlID0gYXdhaXQgdGhpcy5lbmNyeXB0aW9uU2VydmljZS5zaWduKFxuICAgICAgYXNzZW1ibHlLZXlWZXJpZmllclByayxcbiAgICAgIGNoYWxsZW5nZVxuICAgICk7XG5cbiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgIC8vIENoYW5nZSBwYXNzd29yZCBmb3IgdGhlIG9yaWdpbmFsIHVzZXJcbiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgIGNvbnN0IHRlbXBJZHBQYXNzd29yZCA9IChcbiAgICAgIGF3YWl0IHRoaXMubHJHcmFwaFFMLmxyTXV0YXRlKFxuICAgICAgICBuZXcgTHJNdXRhdGlvbih7XG4gICAgICAgICAgbXV0YXRpb246IFByZUNvbXBsZXRlVHBQYXNzd29yZFJlc2V0UmVxdWVzdE11dGF0aW9uLFxuICAgICAgICAgIHZhcmlhYmxlczoge1xuICAgICAgICAgICAgaW5wdXQ6IHtcbiAgICAgICAgICAgICAgc2lnbmVkQ2hhbGxlbmdlOiBKU09OLnN0cmluZ2lmeShzaWduZWRDaGFsbGVuZ2UpLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9LFxuICAgICAgICB9KSxcbiAgICAgICAge1xuICAgICAgICAgIGluY2x1ZGVLZXlHcmFwaDogZmFsc2UsXG4gICAgICAgIH1cbiAgICAgIClcbiAgICApLnByZUNvbXBsZXRlVHBQYXNzd29yZFJlc2V0UmVxdWVzdC5pZHBQYXNzd29yZDtcblxuICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgLy8gTG9naW4gYXMgdGhlIG9yaWdpbmFsIHVzZXIgdXNpbmcgbmV3IHRlbXBvcmFyeSBwYXNzd29yZFxuICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgLy8gQXQgdGhpcyBwb2ludCwgdGhlIG9yaWdpbmFsIGFjY291bnQncyBwYXNzd29yZCBoYXMgYmVlbiBjaGFuZ2VkXG4gICAgLy8gdG8gYSB0ZW1wb3JhcnkgcGFzc3dvcmQuIEl0IGlzIG5vIGxvbmdlciBwb3NzaWJsZSBmb3IgdGhlIHVzZXJcbiAgICAvLyB0byB1c2UgdGhlIG9yaWdpbmFsIHBhc3N3b3JkIHRvIGxvZ2luLiBBbnkgc3VjY2Vzc2Z1bCBsb2dpblxuICAgIC8vIGNhbiBvbmx5IGJlIHVzaW5nIHRoZSB0ZW1wb3JhcnkgcGFzc3dvcmQuIFNvIGl0J3Mgc2FmZSB0byBhc3N1bWVcbiAgICAvLyB0aGF0IHdlIHdhbnQgdG8gXCJjb21wbGV0ZVwiIHRoZSBwYXNzd29yZCByZXNldC5cblxuICAgIC8vIFRoZSBtYXliZSAyRkEgc28gd2UgbGlzdGVuIGZvciB0aGUgYXV0aCBldmVudCBmcm9tIEFtcGxpZnkuXG4gICAgY29uc3QgcmV0UHJvbWlzZSA9IG5ldyBQcm9taXNlPHZvaWQ+KChyZXNvbHZlKSA9PiB7XG4gICAgICBjb25zdCBsaXN0ZW5lciA9IGFzeW5jIChkYXRhKSA9PiB7XG4gICAgICAgIGlmIChkYXRhLnBheWxvYWQuZXZlbnQgIT09ICdzaWduSW4nKSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgSHViLnJlbW92ZSgnYXV0aCcsIGxpc3RlbmVyKTtcblxuICAgICAgICBjb25zb2xlLmxvZyhkYXRhLnBheWxvYWQpO1xuXG4gICAgICAgIGF3YWl0IHRoaXMuYXV0aC5zaWduSW4ocmVzZXRVc2VyLnVzZXJuYW1lLCBuZXdJZHBQYXNzd29yZCk7XG5cbiAgICAgICAgLy8gU3dpdGNoIG92ZXIgdG8gdGhlIG5ldyBzZXQgb2Yga2V5c1xuICAgICAgICBhd2FpdCB0aGlzLmxyR3JhcGhRTC5sck11dGF0ZShcbiAgICAgICAgICBuZXcgTHJNdXRhdGlvbih7XG4gICAgICAgICAgICBtdXRhdGlvbjogQ29tcGxldGVUcFBhc3N3b3JkUmVzZXRSZXF1ZXN0TXV0YXRpb24sXG4gICAgICAgICAgICB2YXJpYWJsZXM6IHtcbiAgICAgICAgICAgICAgaW5wdXQ6IHtcbiAgICAgICAgICAgICAgICBtYXN0ZXJLZXlXcmFwcGVkUm9vdEtleSxcbiAgICAgICAgICAgICAgICBtYXN0ZXJLZXlJZDogbWFzdGVyS2V5LmlkLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9KVxuICAgICAgICApO1xuXG4gICAgICAgIHJlc29sdmUoKTtcbiAgICAgIH07XG5cbiAgICAgIEh1Yi5saXN0ZW4oJ2F1dGgnLCBsaXN0ZW5lcik7XG4gICAgfSk7XG5cbiAgICAvLyBTaWduaW4gYXMgdGhlIG9yaWdpbmFsIHVzZXIuIFBhc3N3b3JkIGhhcyBiZWVuIHJlc2V0IHRvIHRlbXBvcmFyeSBvbmUuIEl0IHNob3VsZCByZXR1cm5cbiAgICAvLyB3aXRoIE5FV19QQVNTV09SRF9SRVFVSVJFRFxuICAgIGxldCB1c2VyID0gYXdhaXQgdGhpcy5hdXRoLnNpZ25JbihyZXNldFVzZXIudXNlcm5hbWUsIHRlbXBJZHBQYXNzd29yZCwge1xuICAgICAgbm9Qcm94eTogJ3RydWUnLFxuICAgIH0pO1xuXG4gICAgaWYgKHVzZXIuY2hhbGxlbmdlTmFtZSAhPT0gJ05FV19QQVNTV09SRF9SRVFVSVJFRCcpIHtcbiAgICAgIHRocm93IG5ldyBMckV4Y2VwdGlvbih7XG4gICAgICAgIG1lc3NhZ2U6XG4gICAgICAgICAgJ0ludGVybmFsIGVycm9yLiBFeHBlY3RpbmcgQ29nbml0byB0byBoYXZlIGRvbmUgYSBwYXNzd29yZCByZXNldCBhZnRlciBjYWxsIHRvIFByZUNvbXBsZXRlVHBQYXNzd29yZFJlc2V0UmVxdWVzdE11dGF0aW9uLicsXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICAvLyBTZXQgbmV3IHBhc3N3b3JkIG9uIElkcFxuICAgIC8vIHRoZSBhd3NGZXRjaCgpIGZ1bmN0aW9uIHBhc3NlcyBORVdfUEFTU1dPUkRfUkVRVUlSRUQgZGlyZWN0bHkgdG8gQVdTIHdpdGhvdXRcbiAgICAvLyBnb2luZyB0aHJvdWdoIHRoZSBwcm94eS5cbiAgICB1c2VyID0gYXdhaXQgdGhpcy5hdXRoLmNvbXBsZXRlTmV3UGFzc3dvcmQodXNlciwgbmV3SWRwUGFzc3dvcmQsIHt9KTtcblxuICAgIHJldHVybiByZXRQcm9taXNlO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyByZWNvdmVyQXNzZW1ibHlLZXkoXG4gICAgcmVzZXRVc2VyOiBUcFBhc3N3b3JkUmVzZXRVc2VyTm9kZVxuICApOiBQcm9taXNlPEpXSy5LZXk+IHtcbiAgICAvLyBSZWNvdmVyIHRoZSBhc3NlbWJseSBrZXkuXG4gICAgbGV0IGFzc2VtYmx5S2V5UGFyYW1zOiBvYmplY3Q7XG5cbiAgICBjb25zdCBwcmsgPSBhd2FpdCB0aGlzLmtleUdyYXBoU2VydmljZS5nZXRLZXkocmVzZXRVc2VyLnB4ay5pZCk7XG5cbiAgICBjb25zdCBzaGFyZXMgPSBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgIHJlc2V0VXNlci5hcHByb3ZhbHNcbiAgICAgICAgLmZpbHRlcigoYXBwcm92YWwpID0+ICEhYXBwcm92YWwucmVjZWl2ZXJDaXBoZXJQYXJ0aWFsQXNzZW1ibHlLZXkpXG4gICAgICAgIC5tYXAoYXN5bmMgKGFwcHJvdmFsKSA9PiB7XG4gICAgICAgICAgY29uc3QgcGFydGlhbEFzc2VtYmx5S2V5ID0gYXdhaXQgdGhpcy5lbmNyeXB0aW9uU2VydmljZS5kZWNyeXB0KFxuICAgICAgICAgICAgcHJrLFxuICAgICAgICAgICAgYXBwcm92YWwucmVjZWl2ZXJDaXBoZXJQYXJ0aWFsQXNzZW1ibHlLZXlcbiAgICAgICAgICApO1xuXG4gICAgICAgICAgaWYgKGFzc2VtYmx5S2V5UGFyYW1zKSB7XG4gICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KGFzc2VtYmx5S2V5UGFyYW1zKSAhPT1cbiAgICAgICAgICAgICAgSlNPTi5zdHJpbmdpZnkocGFydGlhbEFzc2VtYmx5S2V5LmFzc2VtYmx5S2V5UGFyYW1zKVxuICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgIHRocm93IG5ldyBMckJhZFN0YXRlRXhjZXB0aW9uKFxuICAgICAgICAgICAgICAgICdUaGUgYXNzZW1ibHkga2V5IHBhcmFtZXRlcnMgYXJlIGRpZmZlcmVudCBiZXR3ZWVuIHRoZSBhcHByb3ZhbHMuJ1xuICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBhc3NlbWJseUtleVBhcmFtcyA9IHBhcnRpYWxBc3NlbWJseUtleS5hc3NlbWJseUtleVBhcmFtcztcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIHBhcnRpYWxBc3NlbWJseUtleS5zbGlwMzkuc2hhcmUubW5lbW9uaWNzO1xuICAgICAgICB9KVxuICAgICk7XG5cbiAgICBjb25zb2xlLmxvZygncmVjb3ZlckFzc2VtYmx5S2V5KCknLCBzaGFyZXMpO1xuXG4gICAgY29uc3QgcmF3QXNzZW1ibHlLZXkgPSBhd2FpdCB0aGlzLnNsaXAzOVNlcnZpY2UucmVjb3ZlclNlY3JldChcbiAgICAgIHNoYXJlcyxcbiAgICAgIFRQX1BBU1NXT1JEX1JFU0VUX1NMSVAzOV9QQVNTUEhSQVNFXG4gICAgKTtcblxuICAgIHJldHVybiBKV0suYXNLZXkoe1xuICAgICAgLi4uYXNzZW1ibHlLZXlQYXJhbXMsXG4gICAgICBrOiByYXdBc3NlbWJseUtleSxcbiAgICB9KTtcbiAgfVxufVxuIl19
|