@lifeready/core 1.0.2 → 1.0.4
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.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 +385 -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,320 +1,320 @@
|
|
|
1
|
-
import { __awaiter } from "tslib";
|
|
2
|
-
import { HttpClient } from '@angular/common/http';
|
|
3
|
-
import { Inject, Injectable } from '@angular/core';
|
|
4
|
-
import { AuthClass } from '@aws-amplify/auth/lib-esm/Auth';
|
|
5
|
-
import { ProfileService } from '../users/profile.service';
|
|
6
|
-
import { EncryptionService } from '../cryptography/encryption.service';
|
|
7
|
-
import { KeyGraphService } from '../cryptography/key-graph.service';
|
|
8
|
-
import { LR_CONFIG } from '../life-ready.config';
|
|
9
|
-
import { LrAuthException, LrBadArgumentException } from '../_common/exceptions';
|
|
10
|
-
import { LrApolloService } from './../api/lr-apollo.service';
|
|
11
|
-
import { PasswordChangeMutation, PasswordChangeRequestMutation, PasswordChangeConfigQuery, } from './auth.gql';
|
|
12
|
-
import { WebCryptoService } from '../cryptography/web-crypto.service';
|
|
13
|
-
import * as moment_ from 'moment';
|
|
14
|
-
import { IdleService } from '../auth/idle.service';
|
|
15
|
-
import { KeyFactoryService as KFS } from '../cryptography/key-factory.service';
|
|
16
|
-
import * as i0 from "@angular/core";
|
|
17
|
-
import * as i1 from "../life-ready.config";
|
|
18
|
-
import * as i2 from "@angular/common/http";
|
|
19
|
-
import * as i3 from "../api/lr-apollo.service";
|
|
20
|
-
import * as i4 from "@aws-amplify/auth/lib-esm/Auth";
|
|
21
|
-
import * as i5 from "../users/profile.service";
|
|
22
|
-
import * as i6 from "../cryptography/key-factory.service";
|
|
23
|
-
import * as i7 from "../cryptography/encryption.service";
|
|
24
|
-
import * as i8 from "../cryptography/key-graph.service";
|
|
25
|
-
import * as i9 from "../cryptography/web-crypto.service";
|
|
26
|
-
import * as i10 from "./idle.service";
|
|
27
|
-
// "why?" you ask: https://stackoverflow.com/questions/59735280/angular-8-moment-error-cannot-call-a-namespace-moment
|
|
28
|
-
const moment = moment_;
|
|
29
|
-
export class PasswordCheck {
|
|
30
|
-
}
|
|
31
|
-
export class PasswordService {
|
|
32
|
-
constructor(config, http, apollo, auth, profileService, keyFactory, encryptionService, keyGraph, webCryptoService, idleService) {
|
|
33
|
-
this.config = config;
|
|
34
|
-
this.http = http;
|
|
35
|
-
this.apollo = apollo;
|
|
36
|
-
this.auth = auth;
|
|
37
|
-
this.profileService = profileService;
|
|
38
|
-
this.keyFactory = keyFactory;
|
|
39
|
-
this.encryptionService = encryptionService;
|
|
40
|
-
this.keyGraph = keyGraph;
|
|
41
|
-
this.webCryptoService = webCryptoService;
|
|
42
|
-
this.idleService = idleService;
|
|
43
|
-
this.CLIENT_NONCE_LENGTH = 32;
|
|
44
|
-
}
|
|
45
|
-
checkPassword(password) {
|
|
46
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
47
|
-
const { years } = this.passwordStrength(password);
|
|
48
|
-
return {
|
|
49
|
-
length: password.length,
|
|
50
|
-
timeToCrack: moment.duration({ years }),
|
|
51
|
-
passwordExposed: yield this.getExposureCount(password),
|
|
52
|
-
};
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
getExposureCount(password) {
|
|
56
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
57
|
-
const sha1Password = yield this.webCryptoService.stringDigest('SHA-1', password);
|
|
58
|
-
const first5sha1 = sha1Password.substring(0, 5);
|
|
59
|
-
const response = yield this.http
|
|
60
|
-
.get(`https://api.pwnedpasswords.com/range/${first5sha1}`, {
|
|
61
|
-
responseType: 'text',
|
|
62
|
-
})
|
|
63
|
-
.toPromise();
|
|
64
|
-
const results = new RegExp(`^(?:${sha1Password.substring(5)}:)(?<count>\\d+)$`, 'im').exec(response);
|
|
65
|
-
if (results) {
|
|
66
|
-
return +results.groups.count;
|
|
67
|
-
}
|
|
68
|
-
return 0;
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
getPassIdpString(passIdp) {
|
|
72
|
-
return passIdp.toJSON(true).k;
|
|
73
|
-
}
|
|
74
|
-
createPassKeyBundle(password) {
|
|
75
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
76
|
-
const passIdpParams = yield this.keyFactory.createPassIdpParams();
|
|
77
|
-
const passIdp = (yield this.keyFactory.derivePassIdp(Object.assign({ password }, passIdpParams))).jwk;
|
|
78
|
-
const passKeyParams = yield this.keyFactory.createPassKeyParams();
|
|
79
|
-
const passKey = (yield this.keyFactory.derivePassKey(Object.assign({ password }, passKeyParams))).jwk;
|
|
80
|
-
const passIdpVerifier = yield this.keyFactory.createPkcSignKey();
|
|
81
|
-
const wrappedPassIdpVerifierPrk = yield this.encryptionService.encrypt(passKey, passIdpVerifier.toJSON(true));
|
|
82
|
-
// There are two formats that the private key can be represented in JWK:
|
|
83
|
-
// https://tools.ietf.org/html/rfc8017#page-9
|
|
84
|
-
// The second form is an optimization:
|
|
85
|
-
// https://crypto.stackexchange.com/questions/19413/what-are-dp-and-dq-in-encryption-by-rsa-in-c
|
|
86
|
-
return {
|
|
87
|
-
passKeyParams,
|
|
88
|
-
passKey,
|
|
89
|
-
passIdpParams,
|
|
90
|
-
passIdp,
|
|
91
|
-
passIdpVerifier,
|
|
92
|
-
wrappedPassIdpVerifierPrk,
|
|
93
|
-
};
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
/**
|
|
97
|
-
* We need to allow for interruption of the process at any point. Each API call can be considered
|
|
98
|
-
* atomic and either succeeds or fails.
|
|
99
|
-
*
|
|
100
|
-
* The LR server APIs use semaphore tokens for locking critical operations, so concurrent calls will
|
|
101
|
-
* fail.
|
|
102
|
-
*
|
|
103
|
-
* We assume the worst case for IdP API calls. So we use the semaphore token from LR to prevent
|
|
104
|
-
* concurrent calls to IdP APIs, but we have to assume that the IdP API calls will either succeed or
|
|
105
|
-
* fail within a reasonable amount of time.
|
|
106
|
-
*
|
|
107
|
-
* Each location where the server state changes can be a potential point of interruption.
|
|
108
|
-
* Potential points of interruption are marked with: --Potential Failure Point--
|
|
109
|
-
*
|
|
110
|
-
* Places for timeout:
|
|
111
|
-
* - Login age too old at call to: verifyPassword()
|
|
112
|
-
* - Login age too old at call to: changePasswordMutation()
|
|
113
|
-
* - Semaphore token expires at call to: changePasswordComplete()
|
|
114
|
-
*
|
|
115
|
-
* Tests:
|
|
116
|
-
* - Potential Failure Point 1: should be able to restart the process, user remains signed in.
|
|
117
|
-
* - Potential Failure Point 2: should enter recovery flow
|
|
118
|
-
* - Potential Failure Point 3: should enter recovery flow
|
|
119
|
-
* - Potential Failure Point 4: should enter recovery flow
|
|
120
|
-
*
|
|
121
|
-
*/
|
|
122
|
-
isLoginRequired() {
|
|
123
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
124
|
-
const changePasswordConfig = yield this.getChangePasswordConfig();
|
|
125
|
-
const authTime = moment(changePasswordConfig.authTime);
|
|
126
|
-
const serverTime = moment(changePasswordConfig.serverTime);
|
|
127
|
-
const duration = moment.duration(serverTime.diff(authTime));
|
|
128
|
-
const seconds = duration.asSeconds();
|
|
129
|
-
if (seconds > changePasswordConfig.maxAuthAgeSeconds) {
|
|
130
|
-
return true;
|
|
131
|
-
}
|
|
132
|
-
else {
|
|
133
|
-
return false;
|
|
134
|
-
}
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
changePassword(password, newPassword) {
|
|
138
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
139
|
-
const cognitoUser = yield this.auth.currentAuthenticatedUser();
|
|
140
|
-
// Validation
|
|
141
|
-
// todo: Add this back in
|
|
142
|
-
// Note the passIdp will always have a random salt, so will always be different to the current passIdp.
|
|
143
|
-
if (password === newPassword) {
|
|
144
|
-
throw new LrBadArgumentException('New password is the same as the current one.');
|
|
145
|
-
}
|
|
146
|
-
const { currentUser } = yield this.profileService.getCurrentUser();
|
|
147
|
-
const { passIdp, signedChallenge } = yield this.verifyPassword(password, currentUser);
|
|
148
|
-
// --Potential Failure Point 1--
|
|
149
|
-
// verifyPassword() asks for a current password challenge hence changes server state.
|
|
150
|
-
// Place break points here to test the failure scenarios.
|
|
151
|
-
// Generate the new passIdp
|
|
152
|
-
const newPassKey = yield this.createPassKeyBundle(newPassword);
|
|
153
|
-
// Re-encrypt master key with new key
|
|
154
|
-
const masterKey = yield this.keyGraph.getKey(currentUser.currentUserKey.masterKey.id);
|
|
155
|
-
const newWrappedMasterKey = yield this.encryptionService.encrypt(newPassKey.passKey, masterKey.jwk.toJSON(true));
|
|
156
|
-
// If the IdP change password failed, we need to go into recovery mode by forcing
|
|
157
|
-
// a login. We can't logout the user just yet since the IdP password change needs
|
|
158
|
-
// the user to be logged in. We _can_ removed any persisted session values for the IdP
|
|
159
|
-
// but that seems like too much trouble.
|
|
160
|
-
const { token, newPassKeyId } = yield this.changePasswordMutation(signedChallenge, currentUser.currentUserKey.masterKey.id, newWrappedMasterKey, newPassKey);
|
|
161
|
-
// --Potential Failure Point 2--
|
|
162
|
-
// changePasswordMutation() uploads new keys and obtains a semaphore lock to prevent any other
|
|
163
|
-
// clients from performing IdP password change.
|
|
164
|
-
// Now we can do the IdP password change.
|
|
165
|
-
// todo: Add this back in
|
|
166
|
-
yield this.auth.changePassword(cognitoUser, this.getPassIdpString(passIdp), this.getPassIdpString(newPassKey.passIdp));
|
|
167
|
-
// --Potential Failure Point 3--
|
|
168
|
-
// IdP password change
|
|
169
|
-
// Note that changePassword() could throw an exception for a number of reason. It could throw
|
|
170
|
-
// a network timeout for example. But we don't know if it's the response that timed out and
|
|
171
|
-
// the idp password change was actually carried out. So we have to be extra conservative and
|
|
172
|
-
// only act on a clear success. Otherwise we go into recover mode.
|
|
173
|
-
yield this.changePasswordComplete(cognitoUser.getSignInUserSession().getAccessToken().getJwtToken(), true, token);
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
changePasswordComplete(accessToken, useNewPassword, token = null) {
|
|
177
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
178
|
-
return this.http
|
|
179
|
-
.post(`${this.config.authUrl}users/password-change-complete/`, Object.assign({ use_new_password: useNewPassword }, (token && { token })), {
|
|
180
|
-
headers: {
|
|
181
|
-
Authorization: `Bearer ${accessToken}`,
|
|
182
|
-
},
|
|
183
|
-
})
|
|
184
|
-
.toPromise();
|
|
185
|
-
});
|
|
186
|
-
}
|
|
187
|
-
getVerifierPrK(passKey, wrappedPrK) {
|
|
188
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
189
|
-
try {
|
|
190
|
-
const prkJson = yield this.encryptionService.decrypt(passKey, wrappedPrK);
|
|
191
|
-
return KFS.asKey(prkJson);
|
|
192
|
-
}
|
|
193
|
-
catch (error) {
|
|
194
|
-
throw new LrAuthException('Wrong current password');
|
|
195
|
-
}
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
verifyPassword(password, currentUser) {
|
|
199
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
200
|
-
// Get information from the server to prepare for password change.
|
|
201
|
-
const passwordRequest = yield this.apollo.mutate({
|
|
202
|
-
mutation: PasswordChangeRequestMutation,
|
|
203
|
-
variables: {},
|
|
204
|
-
});
|
|
205
|
-
// Get the old passKey so we can decrypt the old password verifier
|
|
206
|
-
const passKeyResult = yield this.keyFactory.derivePassKey(Object.assign({ password }, currentUser.currentUserKey.passKey.passKeyParams));
|
|
207
|
-
const verifierPrK = yield this.getVerifierPrK(passKeyResult.jwk, currentUser.currentUserKey.passKey.wrappedPassIdpVerifierPrk);
|
|
208
|
-
// Sign the server challenge to prove to the server we can decrypt the password verifier.
|
|
209
|
-
// Generate
|
|
210
|
-
const clientNonce = this.keyFactory.randomString(this.CLIENT_NONCE_LENGTH);
|
|
211
|
-
const signedChallenge = yield this.encryptionService.sign(verifierPrK, {
|
|
212
|
-
serverNonce: passwordRequest.passwordChangeRequest.challenge.serverNonce,
|
|
213
|
-
clientNonce,
|
|
214
|
-
});
|
|
215
|
-
const passIdpResult = yield this.keyFactory.derivePassIdp(Object.assign({ password }, currentUser.currentUserKey.passKey.passIdpParams));
|
|
216
|
-
return {
|
|
217
|
-
passIdp: passIdpResult.jwk,
|
|
218
|
-
signedChallenge,
|
|
219
|
-
};
|
|
220
|
-
});
|
|
221
|
-
}
|
|
222
|
-
changePasswordMutation(signedChallenge, masterKeyId, newWrappedMasterKey, passKeyBundle) {
|
|
223
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
224
|
-
const response = yield this.apollo.mutate({
|
|
225
|
-
mutation: PasswordChangeMutation,
|
|
226
|
-
variables: {
|
|
227
|
-
input: {
|
|
228
|
-
signedChallenge: JSON.stringify(signedChallenge),
|
|
229
|
-
masterKeyId,
|
|
230
|
-
newWrappedMasterKey: JSON.stringify(newWrappedMasterKey),
|
|
231
|
-
newPassKey: {
|
|
232
|
-
passIdpParams: JSON.stringify(passKeyBundle.passIdpParams),
|
|
233
|
-
passIdpVerifierPbk: JSON.stringify(passKeyBundle.passIdpVerifier.toJSON()),
|
|
234
|
-
wrappedPassIdpVerifierPrk: JSON.stringify(passKeyBundle.wrappedPassIdpVerifierPrk),
|
|
235
|
-
passKeyParams: JSON.stringify(passKeyBundle.passKeyParams),
|
|
236
|
-
},
|
|
237
|
-
},
|
|
238
|
-
},
|
|
239
|
-
});
|
|
240
|
-
return {
|
|
241
|
-
token: response.passwordChange.token,
|
|
242
|
-
newPassKeyId: response.passwordChange.newPassKey.id,
|
|
243
|
-
};
|
|
244
|
-
});
|
|
245
|
-
}
|
|
246
|
-
getChangePasswordConfig() {
|
|
247
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
248
|
-
const res = yield this.apollo.query({
|
|
249
|
-
query: PasswordChangeConfigQuery,
|
|
250
|
-
});
|
|
251
|
-
const ret = res.passwordChangeConfig;
|
|
252
|
-
ret.authTime = new Date(ret.authTime);
|
|
253
|
-
ret.serverTime = new Date(ret.serverTime);
|
|
254
|
-
return ret;
|
|
255
|
-
});
|
|
256
|
-
}
|
|
257
|
-
passwordStrength(password) {
|
|
258
|
-
const upper = /[A-Z]/g;
|
|
259
|
-
const lower = /[a-z]/g;
|
|
260
|
-
const digit = /[0-9]/g;
|
|
261
|
-
const upperChoices = 26;
|
|
262
|
-
const lowerChoices = 26;
|
|
263
|
-
const digitChoices = 10;
|
|
264
|
-
const specialChoices = 30; // /[!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~]/g
|
|
265
|
-
function instanceCount(str, re) {
|
|
266
|
-
return ((str || '').match(re) || []).length;
|
|
267
|
-
}
|
|
268
|
-
const uppers = instanceCount(password, upper);
|
|
269
|
-
const lowers = instanceCount(password, lower);
|
|
270
|
-
const digits = instanceCount(password, digit);
|
|
271
|
-
const specials = password.length - uppers - lowers - digits;
|
|
272
|
-
let choices = 0;
|
|
273
|
-
if (uppers) {
|
|
274
|
-
choices += upperChoices;
|
|
275
|
-
}
|
|
276
|
-
if (lowers) {
|
|
277
|
-
choices += lowerChoices;
|
|
278
|
-
}
|
|
279
|
-
if (digits) {
|
|
280
|
-
choices += digitChoices;
|
|
281
|
-
}
|
|
282
|
-
if (specials) {
|
|
283
|
-
choices += specialChoices;
|
|
284
|
-
}
|
|
285
|
-
if (password.length === 0) {
|
|
286
|
-
return {
|
|
287
|
-
years: 0,
|
|
288
|
-
// bits of entropy
|
|
289
|
-
bits: 0,
|
|
290
|
-
};
|
|
291
|
-
}
|
|
292
|
-
const permutations = Math.pow(choices, password.length);
|
|
293
|
-
const years = (54000 * permutations) /
|
|
294
|
-
Math.pow(upperChoices + lowerChoices + digitChoices, 12);
|
|
295
|
-
return {
|
|
296
|
-
years,
|
|
297
|
-
// bits of entropy
|
|
298
|
-
bits: Math.round(Math.log2(permutations)),
|
|
299
|
-
};
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
PasswordService.ɵprov = i0.ɵɵdefineInjectable({ factory: function PasswordService_Factory() { return new PasswordService(i0.ɵɵinject(i1.LR_CONFIG), i0.ɵɵinject(i2.HttpClient), i0.ɵɵinject(i3.LrApolloService), i0.ɵɵinject(i4.AuthClass), i0.ɵɵinject(i5.ProfileService), i0.ɵɵinject(i6.KeyFactoryService), i0.ɵɵinject(i7.EncryptionService), i0.ɵɵinject(i8.KeyGraphService), i0.ɵɵinject(i9.WebCryptoService), i0.ɵɵinject(i10.IdleService)); }, token: PasswordService, providedIn: "root" });
|
|
303
|
-
PasswordService.decorators = [
|
|
304
|
-
{ type: Injectable, args: [{
|
|
305
|
-
providedIn: 'root',
|
|
306
|
-
},] }
|
|
307
|
-
];
|
|
308
|
-
PasswordService.ctorParameters = () => [
|
|
309
|
-
{ type: undefined, decorators: [{ type: Inject, args: [LR_CONFIG,] }] },
|
|
310
|
-
{ type: HttpClient },
|
|
311
|
-
{ type: LrApolloService },
|
|
312
|
-
{ type: AuthClass },
|
|
313
|
-
{ type: ProfileService },
|
|
314
|
-
{ type: KFS },
|
|
315
|
-
{ type: EncryptionService },
|
|
316
|
-
{ type: KeyGraphService },
|
|
317
|
-
{ type: WebCryptoService },
|
|
318
|
-
{ type: IdleService }
|
|
319
|
-
];
|
|
320
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGFzc3dvcmQuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIvb3B0L2F0bGFzc2lhbi9waXBlbGluZXMvYWdlbnQvYnVpbGQvcHJvamVjdHMvY29yZS9zcmMvIiwic291cmNlcyI6WyJsaWIvYXV0aC9wYXNzd29yZC5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDbEQsT0FBTyxFQUFFLE1BQU0sRUFBRSxVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFFbkQsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBRTNELE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUMxRCxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxvQ0FBb0MsQ0FBQztBQUN2RSxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sbUNBQW1DLENBQUM7QUFDcEUsT0FBTyxFQUFtQixTQUFTLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUNsRSxPQUFPLEVBQUUsZUFBZSxFQUFFLHNCQUFzQixFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDaEYsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQzdELE9BQU8sRUFDTCxzQkFBc0IsRUFDdEIsNkJBQTZCLEVBQzdCLHlCQUF5QixHQUMxQixNQUFNLFlBQVksQ0FBQztBQUVwQixPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxvQ0FBb0MsQ0FBQztBQUV0RSxPQUFPLEtBQUssT0FBTyxNQUFNLFFBQVEsQ0FBQztBQUVsQyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDbkQsT0FBTyxFQUFFLGlCQUFpQixJQUFJLEdBQUcsRUFBRSxNQUFNLHFDQUFxQyxDQUFDOzs7Ozs7Ozs7Ozs7QUFFL0UscUhBQXFIO0FBQ3JILE1BQU0sTUFBTSxHQUFHLE9BQU8sQ0FBQztBQXlCdkIs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QjtRQUVELElBQUksUUFBUSxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUU7WUFDekIsT0FBTztnQkFDTCxLQUFLLEVBQUUsQ0FBQztnQkFDUixrQkFBa0I7Z0JBQ2xCLElBQUksRUFBRSxDQUFDO2FBQ1IsQ0FBQztTQUNIO1FBRUQsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBRXhELE1BQU0sS0FBSyxHQUNULENBQUMsS0FBSyxHQUFHLFlBQVksQ0FBQztZQUN0QixJQUFJLENBQUMsR0FBRyxDQUFDLFlBQVksR0FBRyxZQUFZLEdBQUcsWUFBWSxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQzNELE9BQU87WUFDTCxLQUFLO1lBQ0wsa0JBQWtCO1lBQ2xCLElBQUksRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUM7U0FDMUMsQ0FBQztJQUNKLENBQUM7Ozs7WUE1WEYsVUFBVSxTQUFDO2dCQUNWLFVBQVUsRUFBRSxNQUFNO2FBQ25COzs7NENBS0ksTUFBTSxTQUFDLFNBQVM7WUEvRFosVUFBVTtZQVVWLGVBQWU7WUFQZixTQUFTO1lBRVQsY0FBYztZQWlCTyxHQUFHO1lBaEJ4QixpQkFBaUI7WUFDakIsZUFBZTtZQVVmLGdCQUFnQjtZQUloQixXQUFXIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSHR0cENsaWVudCB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbi9odHRwJztcbmltcG9ydCB7IEluamVjdCwgSW5qZWN0YWJsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgQ29nbml0b1VzZXIgfSBmcm9tICdAYXdzLWFtcGxpZnkvYXV0aCc7XG5pbXBvcnQgeyBBdXRoQ2xhc3MgfSBmcm9tICdAYXdzLWFtcGxpZnkvYXV0aC9saWItZXNtL0F1dGgnO1xuaW1wb3J0IHsgSldLLCBKV1MgfSBmcm9tICdub2RlLWpvc2UnO1xuaW1wb3J0IHsgUHJvZmlsZVNlcnZpY2UgfSBmcm9tICcuLi91c2Vycy9wcm9maWxlLnNlcnZpY2UnO1xuaW1wb3J0IHsgRW5jcnlwdGlvblNlcnZpY2UgfSBmcm9tICcuLi9jcnlwdG9ncmFwaHkvZW5jcnlwdGlvbi5zZXJ2aWNlJztcbmltcG9ydCB7IEtleUdyYXBoU2VydmljZSB9IGZyb20gJy4uL2NyeXB0b2dyYXBoeS9rZXktZ3JhcGguc2VydmljZSc7XG5pbXBvcnQgeyBMaWZlUmVhZHlDb25maWcsIExSX0NPTkZJRyB9IGZyb20gJy4uL2xpZmUtcmVhZHkuY29uZmlnJztcbmltcG9ydCB7IExyQXV0aEV4Y2VwdGlvbiwgTHJCYWRBcmd1bWVudEV4Y2VwdGlvbiB9IGZyb20gJy4uL19jb21tb24vZXhjZXB0aW9ucyc7XG5pbXBvcnQgeyBMckFwb2xsb1NlcnZpY2UgfSBmcm9tICcuLy4uL2FwaS9sci1hcG9sbG8uc2VydmljZSc7XG5pbXBvcnQge1xuICBQYXNzd29yZENoYW5nZU11dGF0aW9uLFxuICBQYXNzd29yZENoYW5nZVJlcXVlc3RNdXRhdGlvbixcbiAgUGFzc3dvcmRDaGFuZ2VDb25maWdRdWVyeSxcbn0gZnJvbSAnLi9hdXRoLmdxbCc7XG5pbXBvcnQgeyBQYXNzS2V5QnVuZGxlIH0gZnJvbSAnLi9hdXRoLnR5cGVzJztcbmltcG9ydCB7IFdlYkNyeXB0b1NlcnZpY2UgfSBmcm9tICcuLi9jcnlwdG9ncmFwaHkvd2ViLWNyeXB0by5zZXJ2aWNlJztcbmltcG9ydCB7IER1cmF0aW9uIH0gZnJvbSAnbW9tZW50JztcbmltcG9ydCAqIGFzIG1vbWVudF8gZnJvbSAnbW9tZW50JztcbmltcG9ydCB7IEFwaUN1cnJlbnRVc2VyIH0gZnJvbSAnLi4vdXNlcnMvcHJvZmlsZS50eXBlcyc7XG5pbXBvcnQgeyBJZGxlU2VydmljZSB9IGZyb20gJy4uL2F1dGgvaWRsZS5zZXJ2aWNlJztcbmltcG9ydCB7IEtleUZhY3RvcnlTZXJ2aWNlIGFzIEtGUyB9IGZyb20gJy4uL2NyeXB0b2dyYXBoeS9rZXktZmFjdG9yeS5zZXJ2aWNlJztcblxuLy8gXCJ3aHk/XCIgeW91IGFzazogaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvNTk3MzUyODAvYW5ndWxhci04LW1vbWVudC1lcnJvci1jYW5ub3QtY2FsbC1hLW5hbWVzcGFjZS1tb21lbnRcbmNvbnN0IG1vbWVudCA9IG1vbWVudF87XG5cbmludGVyZmFjZSBQYXNzd29yZENoYW5nZVJlcXVlc3RNdXRhdGlvbiB7XG4gIHBhc3N3b3JkQ2hhbmdlUmVxdWVzdDoge1xuICAgIGNoYWxsZW5nZToge1xuICAgICAgc2VydmVyTm9uY2U6IHN0cmluZztcbiAgICB9O1xuICB9O1xufVxuXG5pbnRlcmZhY2UgUGFzc3dvcmRDaGFuZ2VNdXRhdGlvbiB7XG4gIHBhc3N3b3JkQ2hhbmdlOiB7XG4gICAgdG9rZW46IHN0cmluZztcbiAgICBuZXdQYXNzS2V5OiB7XG4gICAgICBpZDogc3RyaW5nO1xuICAgIH07XG4gIH07XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUGFzc3dvcmRDaGFuZ2VDb25maWcge1xuICBtYXhBdXRoQWdlU2Vjb25kczogbnVtYmVyO1xuICBhdXRoVGltZTogc3RyaW5nIHwgRGF0ZTtcbiAgc2VydmVyVGltZTogc3RyaW5nIHwgRGF0ZTtcbn1cblxuZXhwb3J0IGNsYXNzIFBhc3N3b3JkQ2hlY2sge1xuICBsZW5ndGg/OiBudW1iZXI7XG4gIHRpbWVUb0NyYWNrPzogRHVyYXRpb247XG4gIHBhc3N3b3JkRXhwb3NlZD86IG51bWJlcjtcbn1cblxuQEluamVjdGFibGUoe1xuICBwcm92aWRlZEluOiAncm9vdCcsXG59KVxuZXhwb3J0IGNsYXNzIFBhc3N3b3JkU2VydmljZSB7XG4gIHByaXZhdGUgcmVhZG9ubHkgQ0xJRU5UX05PTkNFX0xFTkdUSCA9IDMyO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIEBJbmplY3QoTFJfQ09ORklHKSBwcml2YXRlIGNvbmZpZzogTGlmZVJlYWR5Q29uZmlnLFxuICAgIHByaXZhdGUgaHR0cDogSHR0cENsaWVudCxcbiAgICBwcml2YXRlIGFwb2xsbzogTHJBcG9sbG9TZXJ2aWNlLFxuICAgIHByaXZhdGUgYXV0aDogQXV0aENsYXNzLFxuICAgIHByaXZhdGUgcHJvZmlsZVNlcnZpY2U6IFByb2ZpbGVTZXJ2aWNlLFxuICAgIHByaXZhdGUga2V5RmFjdG9yeTogS0ZTLFxuICAgIHByaXZhdGUgZW5jcnlwdGlvblNlcnZpY2U6IEVuY3J5cHRpb25TZXJ2aWNlLFxuICAgIHByaXZhdGUga2V5R3JhcGg6IEtleUdyYXBoU2VydmljZSxcbiAgICBwcml2YXRlIHdlYkNyeXB0b1NlcnZpY2U6IFdlYkNyeXB0b1NlcnZpY2UsXG4gICAgcHJpdmF0ZSBpZGxlU2VydmljZTogSWRsZVNlcnZpY2VcbiAgKSB7fVxuXG4gIHB1YmxpYyBhc3luYyBjaGVja1Bhc3N3b3JkKHBhc3N3b3JkOiBzdHJpbmcpOiBQcm9taXNlPFBhc3N3b3JkQ2hlY2s+IHtcbiAgICBjb25zdCB7IHllYXJzIH0gPSB0aGlzLnBhc3N3b3JkU3RyZW5ndGgocGFzc3dvcmQpO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIGxlbmd0aDogcGFzc3dvcmQubGVuZ3RoLFxuICAgICAgdGltZVRvQ3JhY2s6IG1vbWVudC5kdXJhdGlvbih7IHllYXJzIH0pLFxuICAgICAgcGFzc3dvcmRFeHBvc2VkOiBhd2FpdCB0aGlzLmdldEV4cG9zdXJlQ291bnQocGFzc3dvcmQpLFxuICAgIH07XG4gIH1cblxuICBwdWJsaWMgYXN5bmMgZ2V0RXhwb3N1cmVDb3VudChwYXNzd29yZDogc3RyaW5nKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICBjb25zdCBzaGExUGFzc3dvcmQgPSBhd2FpdCB0aGlzLndlYkNyeXB0b1NlcnZpY2Uuc3RyaW5nRGlnZXN0KFxuICAgICAgJ1NIQS0xJyxcbiAgICAgIHBhc3N3b3JkXG4gICAgKTtcbiAgICBjb25zdCBmaXJzdDVzaGExID0gc2hhMVBhc3N3b3JkLnN1YnN0cmluZygwLCA1KTtcblxuICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgdGhpcy5odHRwXG4gICAgICAuZ2V0KGBodHRwczovL2FwaS5wd25lZHBhc3N3b3Jkcy5jb20vcmFuZ2UvJHtmaXJzdDVzaGExfWAsIHtcbiAgICAgICAgcmVzcG9uc2VUeXBlOiAndGV4dCcsXG4gICAgICB9KVxuICAgICAgLnRvUHJvbWlzZSgpO1xuXG4gICAgY29uc3QgcmVzdWx0cyA9IG5ldyBSZWdFeHAoXG4gICAgICBgXig/OiR7c2hhMVBhc3N3b3JkLnN1YnN0cmluZyg1KX06KSg/PGNvdW50PlxcXFxkKykkYCxcbiAgICAgICdpbSdcbiAgICApLmV4ZWMocmVzcG9uc2UpO1xuXG4gICAgaWYgKHJlc3VsdHMpIHtcbiAgICAgIHJldHVybiArcmVzdWx0cy5ncm91cHMuY291bnQ7XG4gICAgfVxuICAgIHJldHVybiAwO1xuICB9XG5cbiAgcHVibGljIGdldFBhc3NJZHBTdHJpbmcocGFzc0lkcDogSldLLktleSkge1xuICAgIHJldHVybiAocGFzc0lkcC50b0pTT04odHJ1ZSkgYXMgYW55KS5rO1xuICB9XG5cbiAgcHVibGljIGFzeW5jIGNyZWF0ZVBhc3NLZXlCdW5kbGUocGFzc3dvcmQ6IHN0cmluZyk6IFByb21pc2U8UGFzc0tleUJ1bmRsZT4ge1xuICAgIGNvbnN0IHBhc3NJZHBQYXJhbXMgPSBhd2FpdCB0aGlzLmtleUZhY3RvcnkuY3JlYXRlUGFzc0lkcFBhcmFtcygpO1xuICAgIGNvbnN0IHBhc3NJZHAgPSAoXG4gICAgICBhd2FpdCB0aGlzLmtleUZhY3RvcnkuZGVyaXZlUGFzc0lkcCh7XG4gICAgICAgIHBhc3N3b3JkLFxuICAgICAgICAuLi5wYXNzSWRwUGFyYW1zLFxuICAgICAgfSlcbiAgICApLmp3aztcblxuICAgIGNvbnN0IHBhc3NLZXlQYXJhbXMgPSBhd2FpdCB0aGlzLmtleUZhY3RvcnkuY3JlYXRlUGFzc0tleVBhcmFtcygpO1xuICAgIGNvbnN0IHBhc3NLZXkgPSAoXG4gICAgICBhd2FpdCB0aGlzLmtleUZhY3RvcnkuZGVyaXZlUGFzc0tleSh7XG4gICAgICAgIHBhc3N3b3JkLFxuICAgICAgICAuLi5wYXNzS2V5UGFyYW1zLFxuICAgICAgfSlcbiAgICApLmp3aztcblxuICAgIGNvbnN0IHBhc3NJZHBWZXJpZmllciA9IGF3YWl0IHRoaXMua2V5RmFjdG9yeS5jcmVhdGVQa2NTaWduS2V5KCk7XG5cbiAgICBjb25zdCB3cmFwcGVkUGFzc0lkcFZlcmlmaWVyUHJrID0gYXdhaXQgdGhpcy5lbmNyeXB0aW9uU2VydmljZS5lbmNyeXB0KFxuICAgICAgcGFzc0tleSxcbiAgICAgIHBhc3NJZHBWZXJpZmllci50b0pTT04odHJ1ZSlcbiAgICApO1xuXG4gICAgLy8gVGhlcmUgYXJlIHR3byBmb3JtYXRzIHRoYXQgdGhlIHByaXZhdGUga2V5IGNhbiBiZSByZXByZXNlbnRlZCBpbiBKV0s6XG4gICAgLy8gaHR0cHM6Ly90b29scy5pZXRmLm9yZy9odG1sL3JmYzgwMTcjcGFnZS05XG4gICAgLy8gVGhlIHNlY29uZCBmb3JtIGlzIGFuIG9wdGltaXphdGlvbjpcbiAgICAvLyBodHRwczovL2NyeXB0by5zdGFja2V4Y2hhbmdlLmNvbS9xdWVzdGlvbnMvMTk0MTMvd2hhdC1hcmUtZHAtYW5kLWRxLWluLWVuY3J5cHRpb24tYnktcnNhLWluLWNcblxuICAgIHJldHVybiB7XG4gICAgICBwYXNzS2V5UGFyYW1zLFxuICAgICAgcGFzc0tleSxcbiAgICAgIHBhc3NJZHBQYXJhbXMsXG4gICAgICBwYXNzSWRwLFxuICAgICAgcGFzc0lkcFZlcmlmaWVyLFxuICAgICAgd3JhcHBlZFBhc3NJZHBWZXJpZmllclByayxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIFdlIG5lZWQgdG8gYWxsb3cgZm9yIGludGVycnVwdGlvbiBvZiB0aGUgcHJvY2VzcyBhdCBhbnkgcG9pbnQuIEVhY2ggQVBJIGNhbGwgY2FuIGJlIGNvbnNpZGVyZWRcbiAgICogYXRvbWljIGFuZCBlaXRoZXIgc3VjY2VlZHMgb3IgZmFpbHMuXG4gICAqXG4gICAqIFRoZSBMUiBzZXJ2ZXIgQVBJcyB1c2Ugc2VtYXBob3JlIHRva2VucyBmb3IgbG9ja2luZyBjcml0aWNhbCBvcGVyYXRpb25zLCBzbyBjb25jdXJyZW50IGNhbGxzIHdpbGxcbiAgICogZmFpbC5cbiAgICpcbiAgICogV2UgYXNzdW1lIHRoZSB3b3JzdCBjYXNlIGZvciBJZFAgQVBJIGNhbGxzLiBTbyB3ZSB1c2UgdGhlIHNlbWFwaG9yZSB0b2tlbiBmcm9tIExSIHRvIHByZXZlbnRcbiAgICogY29uY3VycmVudCBjYWxscyB0byBJZFAgQVBJcywgYnV0IHdlIGhhdmUgdG8gYXNzdW1lIHRoYXQgdGhlIElkUCBBUEkgY2FsbHMgd2lsbCBlaXRoZXIgc3VjY2VlZCBvclxuICAgKiBmYWlsIHdpdGhpbiBhIHJlYXNvbmFibGUgYW1vdW50IG9mIHRpbWUuXG4gICAqXG4gICAqIEVhY2ggbG9jYXRpb24gd2hlcmUgdGhlIHNlcnZlciBzdGF0ZSBjaGFuZ2VzIGNhbiBiZSBhIHBvdGVudGlhbCBwb2ludCBvZiBpbnRlcnJ1cHRpb24uXG4gICAqIFBvdGVudGlhbCBwb2ludHMgb2YgaW50ZXJydXB0aW9uIGFyZSBtYXJrZWQgd2l0aDogLS1Qb3RlbnRpYWwgRmFpbHVyZSBQb2ludC0tXG4gICAqXG4gICAqIFBsYWNlcyBmb3IgdGltZW91dDpcbiAgICogLSBMb2dpbiBhZ2UgdG9vIG9sZCBhdCBjYWxsIHRvOiB2ZXJpZnlQYXNzd29yZCgpXG4gICAqIC0gTG9naW4gYWdlIHRvbyBvbGQgYXQgY2FsbCB0bzogY2hhbmdlUGFzc3dvcmRNdXRhdGlvbigpXG4gICAqIC0gU2VtYXBob3JlIHRva2VuIGV4cGlyZXMgYXQgY2FsbCB0bzogY2hhbmdlUGFzc3dvcmRDb21wbGV0ZSgpXG4gICAqXG4gICAqIFRlc3RzOlxuICAgKiAtIFBvdGVudGlhbCBGYWlsdXJlIFBvaW50IDE6IHNob3VsZCBiZSBhYmxlIHRvIHJlc3RhcnQgdGhlIHByb2Nlc3MsIHVzZXIgcmVtYWlucyBzaWduZWQgaW4uXG4gICAqIC0gUG90ZW50aWFsIEZhaWx1cmUgUG9pbnQgMjogc2hvdWxkIGVudGVyIHJlY292ZXJ5IGZsb3dcbiAgICogLSBQb3RlbnRpYWwgRmFpbHVyZSBQb2ludCAzOiBzaG91bGQgZW50ZXIgcmVjb3ZlcnkgZmxvd1xuICAgKiAtIFBvdGVudGlhbCBGYWlsdXJlIFBvaW50IDQ6IHNob3VsZCBlbnRlciByZWNvdmVyeSBmbG93XG4gICAqXG4gICAqL1xuXG4gIHB1YmxpYyBhc3luYyBpc0xvZ2luUmVxdWlyZWQoKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgY29uc3QgY2hhbmdlUGFzc3dvcmRDb25maWcgPSBhd2FpdCB0aGlzLmdldENoYW5nZVBhc3N3b3JkQ29uZmlnKCk7XG4gICAgY29uc3QgYXV0aFRpbWUgPSBtb21lbnQoY2hhbmdlUGFzc3dvcmRDb25maWcuYXV0aFRpbWUpO1xuICAgIGNvbnN0IHNlcnZlclRpbWUgPSBtb21lbnQoY2hhbmdlUGFzc3dvcmRDb25maWcuc2VydmVyVGltZSk7XG4gICAgY29uc3QgZHVyYXRpb24gPSBtb21lbnQuZHVyYXRpb24oc2VydmVyVGltZS5kaWZmKGF1dGhUaW1lKSk7XG4gICAgY29uc3Qgc2Vjb25kcyA9IGR1cmF0aW9uLmFzU2Vjb25kcygpO1xuICAgIGlmIChzZWNvbmRzID4gY2hhbmdlUGFzc3dvcmRDb25maWcubWF4QXV0aEFnZVNlY29uZHMpIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICB9XG5cbiAgcHVibGljIGFzeW5jIGNoYW5nZVBhc3N3b3JkKHBhc3N3b3JkOiBzdHJpbmcsIG5ld1Bhc3N3b3JkOiBzdHJpbmcpIHtcbiAgICBjb25zdCBjb2duaXRvVXNlcjogQ29nbml0b1VzZXIgPSBhd2FpdCB0aGlzLmF1dGguY3VycmVudEF1dGhlbnRpY2F0ZWRVc2VyKCk7XG5cbiAgICAvLyBWYWxpZGF0aW9uXG4gICAgLy8gdG9kbzogQWRkIHRoaXMgYmFjayBpblxuICAgIC8vIE5vdGUgdGhlIHBhc3NJZHAgd2lsbCBhbHdheXMgaGF2ZSBhIHJhbmRvbSBzYWx0LCBzbyB3aWxsIGFsd2F5cyBiZSBkaWZmZXJlbnQgdG8gdGhlIGN1cnJlbnQgcGFzc0lkcC5cbiAgICBpZiAocGFzc3dvcmQgPT09IG5ld1Bhc3N3b3JkKSB7XG4gICAgICB0aHJvdyBuZXcgTHJCYWRBcmd1bWVudEV4Y2VwdGlvbihcbiAgICAgICAgJ05ldyBwYXNzd29yZCBpcyB0aGUgc2FtZSBhcyB0aGUgY3VycmVudCBvbmUuJ1xuICAgICAgKTtcbiAgICB9XG5cbiAgICBjb25zdCB7IGN1cnJlbnRVc2VyIH0gPSBhd2FpdCB0aGlzLnByb2ZpbGVTZXJ2aWNlLmdldEN1cnJlbnRVc2VyKCk7XG5cbiAgICBjb25zdCB7IHBhc3NJZHAsIHNpZ25lZENoYWxsZW5nZSB9ID0gYXdhaXQgdGhpcy52ZXJpZnlQYXNzd29yZChcbiAgICAgIHBhc3N3b3JkLFxuICAgICAgY3VycmVudFVzZXJcbiAgICApO1xuXG4gICAgLy8gLS1Qb3RlbnRpYWwgRmFpbHVyZSBQb2ludCAxLS1cbiAgICAvLyB2ZXJpZnlQYXNzd29yZCgpIGFza3MgZm9yIGEgY3VycmVudCBwYXNzd29yZCBjaGFsbGVuZ2UgaGVuY2UgY2hhbmdlcyBzZXJ2ZXIgc3RhdGUuXG4gICAgLy8gUGxhY2UgYnJlYWsgcG9pbnRzIGhlcmUgdG8gdGVzdCB0aGUgZmFpbHVyZSBzY2VuYXJpb3MuXG5cbiAgICAvLyBHZW5lcmF0ZSB0aGUgbmV3IHBhc3NJZHBcbiAgICBjb25zdCBuZXdQYXNzS2V5ID0gYXdhaXQgdGhpcy5jcmVhdGVQYXNzS2V5QnVuZGxlKG5ld1Bhc3N3b3JkKTtcblxuICAgIC8vIFJlLWVuY3J5cHQgbWFzdGVyIGtleSB3aXRoIG5ldyBrZXlcbiAgICBjb25zdCBtYXN0ZXJLZXkgPSBhd2FpdCB0aGlzLmtleUdyYXBoLmdldEtleShcbiAgICAgIGN1cnJlbnRVc2VyLmN1cnJlbnRVc2VyS2V5Lm1hc3RlcktleS5pZFxuICAgICk7XG4gICAgY29uc3QgbmV3V3JhcHBlZE1hc3RlcktleSA9IGF3YWl0IHRoaXMuZW5jcnlwdGlvblNlcnZpY2UuZW5jcnlwdChcbiAgICAgIG5ld1Bhc3NLZXkucGFzc0tleSxcbiAgICAgIG1hc3RlcktleS5qd2sudG9KU09OKHRydWUpXG4gICAgKTtcblxuICAgIC8vIElmIHRoZSBJZFAgY2hhbmdlIHBhc3N3b3JkIGZhaWxlZCwgd2UgbmVlZCB0byBnbyBpbnRvIHJlY292ZXJ5IG1vZGUgYnkgZm9yY2luZ1xuICAgIC8vIGEgbG9naW4uIFdlIGNhbid0IGxvZ291dCB0aGUgdXNlciBqdXN0IHlldCBzaW5jZSB0aGUgSWRQIHBhc3N3b3JkIGNoYW5nZSBuZWVkc1xuICAgIC8vIHRoZSB1c2VyIHRvIGJlIGxvZ2dlZCBpbi4gV2UgX2Nhbl8gcmVtb3ZlZCBhbnkgcGVyc2lzdGVkIHNlc3Npb24gdmFsdWVzIGZvciB0aGUgSWRQXG4gICAgLy8gYnV0IHRoYXQgc2VlbXMgbGlrZSB0b28gbXVjaCB0cm91YmxlLlxuXG4gICAgY29uc3QgeyB0b2tlbiwgbmV3UGFzc0tleUlkIH0gPSBhd2FpdCB0aGlzLmNoYW5nZVBhc3N3b3JkTXV0YXRpb24oXG4gICAgICBzaWduZWRDaGFsbGVuZ2UsXG4gICAgICBjdXJyZW50VXNlci5jdXJyZW50VXNlcktleS5tYXN0ZXJLZXkuaWQsXG4gICAgICBuZXdXcmFwcGVkTWFzdGVyS2V5LFxuICAgICAgbmV3UGFzc0tleVxuICAgICk7XG5cbiAgICAvLyAtLVBvdGVudGlhbCBGYWlsdXJlIFBvaW50IDItLVxuICAgIC8vIGNoYW5nZVBhc3N3b3JkTXV0YXRpb24oKSB1cGxvYWRzIG5ldyBrZXlzIGFuZCBvYnRhaW5zIGEgc2VtYXBob3JlIGxvY2sgdG8gcHJldmVudCBhbnkgb3RoZXJcbiAgICAvLyBjbGllbnRzIGZyb20gcGVyZm9ybWluZyBJZFAgcGFzc3dvcmQgY2hhbmdlLlxuXG4gICAgLy8gTm93IHdlIGNhbiBkbyB0aGUgSWRQIHBhc3N3b3JkIGNoYW5nZS5cbiAgICAvLyB0b2RvOiBBZGQgdGhpcyBiYWNrIGluXG4gICAgYXdhaXQgdGhpcy5hdXRoLmNoYW5nZVBhc3N3b3JkKFxuICAgICAgY29nbml0b1VzZXIsXG4gICAgICB0aGlzLmdldFBhc3NJZHBTdHJpbmcocGFzc0lkcCksXG4gICAgICB0aGlzLmdldFBhc3NJZHBTdHJpbmcobmV3UGFzc0tleS5wYXNzSWRwKVxuICAgICk7XG5cbiAgICAvLyAtLVBvdGVudGlhbCBGYWlsdXJlIFBvaW50IDMtLVxuICAgIC8vIElkUCBwYXNzd29yZCBjaGFuZ2VcblxuICAgIC8vIE5vdGUgdGhhdCBjaGFuZ2VQYXNzd29yZCgpIGNvdWxkIHRocm93IGFuIGV4Y2VwdGlvbiBmb3IgYSBudW1iZXIgb2YgcmVhc29uLiBJdCBjb3VsZCB0aHJvd1xuICAgIC8vIGEgbmV0d29yayB0aW1lb3V0IGZvciBleGFtcGxlLiBCdXQgd2UgZG9uJ3Qga25vdyBpZiBpdCdzIHRoZSByZXNwb25zZSB0aGF0IHRpbWVkIG91dCBhbmRcbiAgICAvLyB0aGUgaWRwIHBhc3N3b3JkIGNoYW5nZSB3YXMgYWN0dWFsbHkgY2FycmllZCBvdXQuIFNvIHdlIGhhdmUgdG8gYmUgZXh0cmEgY29uc2VydmF0aXZlIGFuZFxuICAgIC8vIG9ubHkgYWN0IG9uIGEgY2xlYXIgc3VjY2Vzcy4gT3RoZXJ3aXNlIHdlIGdvIGludG8gcmVjb3ZlciBtb2RlLlxuICAgIGF3YWl0IHRoaXMuY2hhbmdlUGFzc3dvcmRDb21wbGV0ZShcbiAgICAgIGNvZ25pdG9Vc2VyLmdldFNpZ25JblVzZXJTZXNzaW9uKCkuZ2V0QWNjZXNzVG9rZW4oKS5nZXRKd3RUb2tlbigpLFxuICAgICAgdHJ1ZSxcbiAgICAgIHRva2VuXG4gICAgKTtcbiAgfVxuXG4gIHB1YmxpYyBhc3luYyBjaGFuZ2VQYXNzd29yZENvbXBsZXRlKFxuICAgIGFjY2Vzc1Rva2VuOiBzdHJpbmcsXG4gICAgdXNlTmV3UGFzc3dvcmQ6IGJvb2xlYW4sXG4gICAgdG9rZW46IHN0cmluZyA9IG51bGxcbiAgKTogUHJvbWlzZTxhbnk+IHtcbiAgICByZXR1cm4gdGhpcy5odHRwXG4gICAgICAucG9zdChcbiAgICAgICAgYCR7dGhpcy5jb25maWcuYXV0aFVybH11c2Vycy9wYXNzd29yZC1jaGFuZ2UtY29tcGxldGUvYCxcbiAgICAgICAge1xuICAgICAgICAgIHVzZV9uZXdfcGFzc3dvcmQ6IHVzZU5ld1Bhc3N3b3JkLFxuICAgICAgICAgIC4uLih0b2tlbiAmJiB7IHRva2VuIH0pLFxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICAgQXV0aG9yaXphdGlvbjogYEJlYXJlciAke2FjY2Vzc1Rva2VufWAsXG4gICAgICAgICAgfSxcbiAgICAgICAgfVxuICAgICAgKVxuICAgICAgLnRvUHJvbWlzZSgpO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBnZXRWZXJpZmllclBySyhcbiAgICBwYXNzS2V5OiBKV0suS2V5LFxuICAgIHdyYXBwZWRQcks6IG9iamVjdFxuICApOiBQcm9taXNlPEpXSy5LZXk+IHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgcHJrSnNvbiA9IGF3YWl0IHRoaXMuZW5jcnlwdGlvblNlcnZpY2UuZGVjcnlwdChwYXNzS2V5LCB3cmFwcGVkUHJLKTtcbiAgICAgIHJldHVybiBLRlMuYXNLZXkocHJrSnNvbik7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHRocm93IG5ldyBMckF1dGhFeGNlcHRpb24oJ1dyb25nIGN1cnJlbnQgcGFzc3dvcmQnKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHZlcmlmeVBhc3N3b3JkKFxuICAgIHBhc3N3b3JkOiBzdHJpbmcsXG4gICAgY3VycmVudFVzZXI6IEFwaUN1cnJlbnRVc2VyXG4gICk6IFByb21pc2U8eyBwYXNzSWRwOiBKV0suS2V5OyBzaWduZWRDaGFsbGVuZ2U6IEpXUy5DcmVhdGVTaWduUmVzdWx0IH0+IHtcbiAgICAvLyBHZXQgaW5mb3JtYXRpb24gZnJvbSB0aGUgc2VydmVyIHRvIHByZXBhcmUgZm9yIHBhc3N3b3JkIGNoYW5nZS5cbiAgICBjb25zdCBwYXNzd29yZFJlcXVlc3QgPSBhd2FpdCB0aGlzLmFwb2xsby5tdXRhdGU8UGFzc3dvcmRDaGFuZ2VSZXF1ZXN0TXV0YXRpb24+KFxuICAgICAge1xuICAgICAgICBtdXRhdGlvbjogUGFzc3dvcmRDaGFuZ2VSZXF1ZXN0TXV0YXRpb24sXG4gICAgICAgIHZhcmlhYmxlczoge30sXG4gICAgICB9XG4gICAgKTtcblxuICAgIC8vIEdldCB0aGUgb2xkIHBhc3NLZXkgc28gd2UgY2FuIGRlY3J5cHQgdGhlIG9sZCBwYXNzd29yZCB2ZXJpZmllclxuICAgIGNvbnN0IHBhc3NLZXlSZXN1bHQgPSBhd2FpdCB0aGlzLmtleUZhY3RvcnkuZGVyaXZlUGFzc0tleSh7XG4gICAgICBwYXNzd29yZCxcbiAgICAgIC4uLmN1cnJlbnRVc2VyLmN1cnJlbnRVc2VyS2V5LnBhc3NLZXkucGFzc0tleVBhcmFtcyxcbiAgICB9KTtcblxuICAgIGNvbnN0IHZlcmlmaWVyUHJLID0gYXdhaXQgdGhpcy5nZXRWZXJpZmllclBySyhcbiAgICAgIHBhc3NLZXlSZXN1bHQuandrLFxuICAgICAgY3VycmVudFVzZXIuY3VycmVudFVzZXJLZXkucGFzc0tleS53cmFwcGVkUGFzc0lkcFZlcmlmaWVyUHJrXG4gICAgKTtcblxuICAgIC8vIFNpZ24gdGhlIHNlcnZlciBjaGFsbGVuZ2UgdG8gcHJvdmUgdG8gdGhlIHNlcnZlciB3ZSBjYW4gZGVjcnlwdCB0aGUgcGFzc3dvcmQgdmVyaWZpZXIuXG4gICAgLy8gR2VuZXJhdGVcbiAgICBjb25zdCBjbGllbnROb25jZSA9IHRoaXMua2V5RmFjdG9yeS5yYW5kb21TdHJpbmcodGhpcy5DTElFTlRfTk9OQ0VfTEVOR1RIKTtcblxuICAgIGNvbnN0IHNpZ25lZENoYWxsZW5nZSA9IGF3YWl0IHRoaXMuZW5jcnlwdGlvblNlcnZpY2Uuc2lnbih2ZXJpZmllclBySywge1xuICAgICAgc2VydmVyTm9uY2U6IHBhc3N3b3JkUmVxdWVzdC5wYXNzd29yZENoYW5nZVJlcXVlc3QuY2hhbGxlbmdlLnNlcnZlck5vbmNlLFxuICAgICAgY2xpZW50Tm9uY2UsXG4gICAgfSk7XG5cbiAgICBjb25zdCBwYXNzSWRwUmVzdWx0ID0gYXdhaXQgdGhpcy5rZXlGYWN0b3J5LmRlcml2ZVBhc3NJZHAoe1xuICAgICAgcGFzc3dvcmQsXG4gICAgICAuLi5jdXJyZW50VXNlci5jdXJyZW50VXNlcktleS5wYXNzS2V5LnBhc3NJZHBQYXJhbXMsXG4gICAgfSk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgcGFzc0lkcDogcGFzc0lkcFJlc3VsdC5qd2ssXG4gICAgICBzaWduZWRDaGFsbGVuZ2UsXG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgY2hhbmdlUGFzc3dvcmRNdXRhdGlvbihcbiAgICBzaWduZWRDaGFsbGVuZ2U6IEpXUy5DcmVhdGVTaWduUmVzdWx0LFxuICAgIG1hc3RlcktleUlkOiBzdHJpbmcsXG4gICAgbmV3V3JhcHBlZE1hc3RlcktleTogb2JqZWN0LFxuICAgIHBhc3NLZXlCdW5kbGU6IFBhc3NLZXlCdW5kbGVcbiAgKTogUHJvbWlzZTx7IHRva2VuOiBzdHJpbmc7IG5ld1Bhc3NLZXlJZDogc3RyaW5nIH0+IHtcbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHRoaXMuYXBvbGxvLm11dGF0ZTxQYXNzd29yZENoYW5nZU11dGF0aW9uPih7XG4gICAgICBtdXRhdGlvbjogUGFzc3dvcmRDaGFuZ2VNdXRhdGlvbixcbiAgICAgIHZhcmlhYmxlczoge1xuICAgICAgICBpbnB1dDoge1xuICAgICAgICAgIHNpZ25lZENoYWxsZW5nZTogSlNPTi5zdHJpbmdpZnkoc2lnbmVkQ2hhbGxlbmdlKSxcbiAgICAgICAgICBtYXN0ZXJLZXlJZCxcbiAgICAgICAgICBuZXdXcmFwcGVkTWFzdGVyS2V5OiBKU09OLnN0cmluZ2lmeShuZXdXcmFwcGVkTWFzdGVyS2V5KSxcbiAgICAgICAgICBuZXdQYXNzS2V5OiB7XG4gICAgICAgICAgICBwYXNzSWRwUGFyYW1zOiBKU09OLnN0cmluZ2lmeShwYXNzS2V5QnVuZGxlLnBhc3NJZHBQYXJhbXMpLFxuICAgICAgICAgICAgcGFzc0lkcFZlcmlmaWVyUGJrOiBKU09OLnN0cmluZ2lmeShcbiAgICAgICAgICAgICAgcGFzc0tleUJ1bmRsZS5wYXNzSWRwVmVyaWZpZXIudG9KU09OKClcbiAgICAgICAgICAgICksXG4gICAgICAgICAgICB3cmFwcGVkUGFzc0lkcFZlcmlmaWVyUHJrOiBKU09OLnN0cmluZ2lmeShcbiAgICAgICAgICAgICAgcGFzc0tleUJ1bmRsZS53cmFwcGVkUGFzc0lkcFZlcmlmaWVyUHJrXG4gICAgICAgICAgICApLFxuICAgICAgICAgICAgcGFzc0tleVBhcmFtczogSlNPTi5zdHJpbmdpZnkocGFzc0tleUJ1bmRsZS5wYXNzS2V5UGFyYW1zKSxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgfSxcbiAgICB9KTtcbiAgICByZXR1cm4ge1xuICAgICAgdG9rZW46IHJlc3BvbnNlLnBhc3N3b3JkQ2hhbmdlLnRva2VuLFxuICAgICAgbmV3UGFzc0tleUlkOiByZXNwb25zZS5wYXNzd29yZENoYW5nZS5uZXdQYXNzS2V5LmlkLFxuICAgIH07XG4gIH1cblxuICBhc3luYyBnZXRDaGFuZ2VQYXNzd29yZENvbmZpZygpOiBQcm9taXNlPFBhc3N3b3JkQ2hhbmdlQ29uZmlnPiB7XG4gICAgY29uc3QgcmVzID0gYXdhaXQgdGhpcy5hcG9sbG8ucXVlcnk8YW55Pih7XG4gICAgICBxdWVyeTogUGFzc3dvcmRDaGFuZ2VDb25maWdRdWVyeSxcbiAgICB9KTtcblxuICAgIGNvbnN0IHJldCA9IHJlcy5wYXNzd29yZENoYW5nZUNvbmZpZyBhcyBQYXNzd29yZENoYW5nZUNvbmZpZztcblxuICAgIHJldC5hdXRoVGltZSA9IG5ldyBEYXRlKHJldC5hdXRoVGltZSk7XG4gICAgcmV0LnNlcnZlclRpbWUgPSBuZXcgRGF0ZShyZXQuc2VydmVyVGltZSk7XG4gICAgcmV0dXJuIHJldDtcbiAgfVxuXG4gIHB1YmxpYyBwYXNzd29yZFN0cmVuZ3RoKHBhc3N3b3JkKTogeyB5ZWFyczogbnVtYmVyOyBiaXRzOiBudW1iZXIgfSB7XG4gICAgY29uc3QgdXBwZXIgPSAvW0EtWl0vZztcbiAgICBjb25zdCBsb3dlciA9IC9bYS16XS9nO1xuICAgIGNvbnN0IGRpZ2l0ID0gL1swLTldL2c7XG5cbiAgICBjb25zdCB1cHBlckNob2ljZXMgPSAyNjtcbiAgICBjb25zdCBsb3dlckNob2ljZXMgPSAyNjtcbiAgICBjb25zdCBkaWdpdENob2ljZXMgPSAxMDtcbiAgICBjb25zdCBzcGVjaWFsQ2hvaWNlcyA9IDMwOyAvLyAvWyFcIiMkJSYnKCkqKywtLi86Ozw9Pj9AW1xcXV5fYHt8fX5dL2dcblxuICAgIGZ1bmN0aW9uIGluc3RhbmNlQ291bnQoc3RyLCByZSkge1xuICAgICAgcmV0dXJuICgoc3RyIHx8ICcnKS5tYXRjaChyZSkgfHwgW10pLmxlbmd0aDtcbiAgICB9XG5cbiAgICBjb25zdCB1cHBlcnMgPSBpbnN0YW5jZUNvdW50KHBhc3N3b3JkLCB1cHBlcik7XG4gICAgY29uc3QgbG93ZXJzID0gaW5zdGFuY2VDb3VudChwYXNzd29yZCwgbG93ZXIpO1xuICAgIGNvbnN0IGRpZ2l0cyA9IGluc3RhbmNlQ291bnQocGFzc3dvcmQsIGRpZ2l0KTtcbiAgICBjb25zdCBzcGVjaWFscyA9IHBhc3N3b3JkLmxlbmd0aCAtIHVwcGVycyAtIGxvd2VycyAtIGRpZ2l0cztcblxuICAgIGxldCBjaG9pY2VzID0gMDtcbiAgICBpZiAodXBwZXJzKSB7XG4gICAgICBjaG9pY2VzICs9IHVwcGVyQ2hvaWNlcztcbiAgICB9XG4gICAgaWYgKGxvd2Vycykge1xuICAgICAgY2hvaWNlcyArPSBsb3dlckNob2ljZXM7XG4gICAgfVxuICAgIGlmIChkaWdpdHMpIHtcbiAgICAgIGNob2ljZXMgKz0gZGlnaXRDaG9pY2VzO1xuICAgIH1cbiAgICBpZiAoc3BlY2lhbHMpIHtcbiAgICAgIGNob2ljZXMgKz0gc3BlY2lhbENob2ljZXM7XG4gICAgfVxuXG4gICAgaWYgKHBhc3N3b3JkLmxlbmd0aCA9PT0gMCkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgeWVhcnM6IDAsXG4gICAgICAgIC8vIGJpdHMgb2YgZW50cm9weVxuICAgICAgICBiaXRzOiAwLFxuICAgICAgfTtcbiAgICB9XG5cbiAgICBjb25zdCBwZXJtdXRhdGlvbnMgPSBNYXRoLnBvdyhjaG9pY2VzLCBwYXNzd29yZC5sZW5ndGgpO1xuXG4gICAgY29uc3QgeWVhcnMgPVxuICAgICAgKDU0MDAwICogcGVybXV0YXRpb25zKSAvXG4gICAgICBNYXRoLnBvdyh1cHBlckNob2ljZXMgKyBsb3dlckNob2ljZXMgKyBkaWdpdENob2ljZXMsIDEyKTtcbiAgICByZXR1cm4ge1xuICAgICAgeWVhcnMsXG4gICAgICAvLyBiaXRzIG9mIGVudHJvcHlcbiAgICAgIGJpdHM6IE1hdGgucm91bmQoTWF0aC5sb2cyKHBlcm11dGF0aW9ucykpLFxuICAgIH07XG4gIH1cbn1cbiJdfQ==
|
|
1
|
+
import { __awaiter } from "tslib";
|
|
2
|
+
import { HttpClient } from '@angular/common/http';
|
|
3
|
+
import { Inject, Injectable } from '@angular/core';
|
|
4
|
+
import { AuthClass } from '@aws-amplify/auth/lib-esm/Auth';
|
|
5
|
+
import { ProfileService } from '../users/profile.service';
|
|
6
|
+
import { EncryptionService } from '../cryptography/encryption.service';
|
|
7
|
+
import { KeyGraphService } from '../cryptography/key-graph.service';
|
|
8
|
+
import { LR_CONFIG } from '../life-ready.config';
|
|
9
|
+
import { LrAuthException, LrBadArgumentException } from '../_common/exceptions';
|
|
10
|
+
import { LrApolloService } from './../api/lr-apollo.service';
|
|
11
|
+
import { PasswordChangeMutation, PasswordChangeRequestMutation, PasswordChangeConfigQuery, } from './auth.gql';
|
|
12
|
+
import { WebCryptoService } from '../cryptography/web-crypto.service';
|
|
13
|
+
import * as moment_ from 'moment';
|
|
14
|
+
import { IdleService } from '../auth/idle.service';
|
|
15
|
+
import { KeyFactoryService as KFS } from '../cryptography/key-factory.service';
|
|
16
|
+
import * as i0 from "@angular/core";
|
|
17
|
+
import * as i1 from "../life-ready.config";
|
|
18
|
+
import * as i2 from "@angular/common/http";
|
|
19
|
+
import * as i3 from "../api/lr-apollo.service";
|
|
20
|
+
import * as i4 from "@aws-amplify/auth/lib-esm/Auth";
|
|
21
|
+
import * as i5 from "../users/profile.service";
|
|
22
|
+
import * as i6 from "../cryptography/key-factory.service";
|
|
23
|
+
import * as i7 from "../cryptography/encryption.service";
|
|
24
|
+
import * as i8 from "../cryptography/key-graph.service";
|
|
25
|
+
import * as i9 from "../cryptography/web-crypto.service";
|
|
26
|
+
import * as i10 from "./idle.service";
|
|
27
|
+
// "why?" you ask: https://stackoverflow.com/questions/59735280/angular-8-moment-error-cannot-call-a-namespace-moment
|
|
28
|
+
const moment = moment_;
|
|
29
|
+
export class PasswordCheck {
|
|
30
|
+
}
|
|
31
|
+
export class PasswordService {
|
|
32
|
+
constructor(config, http, apollo, auth, profileService, keyFactory, encryptionService, keyGraph, webCryptoService, idleService) {
|
|
33
|
+
this.config = config;
|
|
34
|
+
this.http = http;
|
|
35
|
+
this.apollo = apollo;
|
|
36
|
+
this.auth = auth;
|
|
37
|
+
this.profileService = profileService;
|
|
38
|
+
this.keyFactory = keyFactory;
|
|
39
|
+
this.encryptionService = encryptionService;
|
|
40
|
+
this.keyGraph = keyGraph;
|
|
41
|
+
this.webCryptoService = webCryptoService;
|
|
42
|
+
this.idleService = idleService;
|
|
43
|
+
this.CLIENT_NONCE_LENGTH = 32;
|
|
44
|
+
}
|
|
45
|
+
checkPassword(password) {
|
|
46
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
47
|
+
const { years } = this.passwordStrength(password);
|
|
48
|
+
return {
|
|
49
|
+
length: password.length,
|
|
50
|
+
timeToCrack: moment.duration({ years }),
|
|
51
|
+
passwordExposed: yield this.getExposureCount(password),
|
|
52
|
+
};
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
getExposureCount(password) {
|
|
56
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
57
|
+
const sha1Password = yield this.webCryptoService.stringDigest('SHA-1', password);
|
|
58
|
+
const first5sha1 = sha1Password.substring(0, 5);
|
|
59
|
+
const response = yield this.http
|
|
60
|
+
.get(`https://api.pwnedpasswords.com/range/${first5sha1}`, {
|
|
61
|
+
responseType: 'text',
|
|
62
|
+
})
|
|
63
|
+
.toPromise();
|
|
64
|
+
const results = new RegExp(`^(?:${sha1Password.substring(5)}:)(?<count>\\d+)$`, 'im').exec(response);
|
|
65
|
+
if (results) {
|
|
66
|
+
return +results.groups.count;
|
|
67
|
+
}
|
|
68
|
+
return 0;
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
getPassIdpString(passIdp) {
|
|
72
|
+
return passIdp.toJSON(true).k;
|
|
73
|
+
}
|
|
74
|
+
createPassKeyBundle(password) {
|
|
75
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
76
|
+
const passIdpParams = yield this.keyFactory.createPassIdpParams();
|
|
77
|
+
const passIdp = (yield this.keyFactory.derivePassIdp(Object.assign({ password }, passIdpParams))).jwk;
|
|
78
|
+
const passKeyParams = yield this.keyFactory.createPassKeyParams();
|
|
79
|
+
const passKey = (yield this.keyFactory.derivePassKey(Object.assign({ password }, passKeyParams))).jwk;
|
|
80
|
+
const passIdpVerifier = yield this.keyFactory.createPkcSignKey();
|
|
81
|
+
const wrappedPassIdpVerifierPrk = yield this.encryptionService.encrypt(passKey, passIdpVerifier.toJSON(true));
|
|
82
|
+
// There are two formats that the private key can be represented in JWK:
|
|
83
|
+
// https://tools.ietf.org/html/rfc8017#page-9
|
|
84
|
+
// The second form is an optimization:
|
|
85
|
+
// https://crypto.stackexchange.com/questions/19413/what-are-dp-and-dq-in-encryption-by-rsa-in-c
|
|
86
|
+
return {
|
|
87
|
+
passKeyParams,
|
|
88
|
+
passKey,
|
|
89
|
+
passIdpParams,
|
|
90
|
+
passIdp,
|
|
91
|
+
passIdpVerifier,
|
|
92
|
+
wrappedPassIdpVerifierPrk,
|
|
93
|
+
};
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* We need to allow for interruption of the process at any point. Each API call can be considered
|
|
98
|
+
* atomic and either succeeds or fails.
|
|
99
|
+
*
|
|
100
|
+
* The LR server APIs use semaphore tokens for locking critical operations, so concurrent calls will
|
|
101
|
+
* fail.
|
|
102
|
+
*
|
|
103
|
+
* We assume the worst case for IdP API calls. So we use the semaphore token from LR to prevent
|
|
104
|
+
* concurrent calls to IdP APIs, but we have to assume that the IdP API calls will either succeed or
|
|
105
|
+
* fail within a reasonable amount of time.
|
|
106
|
+
*
|
|
107
|
+
* Each location where the server state changes can be a potential point of interruption.
|
|
108
|
+
* Potential points of interruption are marked with: --Potential Failure Point--
|
|
109
|
+
*
|
|
110
|
+
* Places for timeout:
|
|
111
|
+
* - Login age too old at call to: verifyPassword()
|
|
112
|
+
* - Login age too old at call to: changePasswordMutation()
|
|
113
|
+
* - Semaphore token expires at call to: changePasswordComplete()
|
|
114
|
+
*
|
|
115
|
+
* Tests:
|
|
116
|
+
* - Potential Failure Point 1: should be able to restart the process, user remains signed in.
|
|
117
|
+
* - Potential Failure Point 2: should enter recovery flow
|
|
118
|
+
* - Potential Failure Point 3: should enter recovery flow
|
|
119
|
+
* - Potential Failure Point 4: should enter recovery flow
|
|
120
|
+
*
|
|
121
|
+
*/
|
|
122
|
+
isLoginRequired() {
|
|
123
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
124
|
+
const changePasswordConfig = yield this.getChangePasswordConfig();
|
|
125
|
+
const authTime = moment(changePasswordConfig.authTime);
|
|
126
|
+
const serverTime = moment(changePasswordConfig.serverTime);
|
|
127
|
+
const duration = moment.duration(serverTime.diff(authTime));
|
|
128
|
+
const seconds = duration.asSeconds();
|
|
129
|
+
if (seconds > changePasswordConfig.maxAuthAgeSeconds) {
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
changePassword(password, newPassword) {
|
|
138
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
139
|
+
const cognitoUser = yield this.auth.currentAuthenticatedUser();
|
|
140
|
+
// Validation
|
|
141
|
+
// todo: Add this back in
|
|
142
|
+
// Note the passIdp will always have a random salt, so will always be different to the current passIdp.
|
|
143
|
+
if (password === newPassword) {
|
|
144
|
+
throw new LrBadArgumentException('New password is the same as the current one.');
|
|
145
|
+
}
|
|
146
|
+
const { currentUser } = yield this.profileService.getCurrentUser();
|
|
147
|
+
const { passIdp, signedChallenge } = yield this.verifyPassword(password, currentUser);
|
|
148
|
+
// --Potential Failure Point 1--
|
|
149
|
+
// verifyPassword() asks for a current password challenge hence changes server state.
|
|
150
|
+
// Place break points here to test the failure scenarios.
|
|
151
|
+
// Generate the new passIdp
|
|
152
|
+
const newPassKey = yield this.createPassKeyBundle(newPassword);
|
|
153
|
+
// Re-encrypt master key with new key
|
|
154
|
+
const masterKey = yield this.keyGraph.getKey(currentUser.currentUserKey.masterKey.id);
|
|
155
|
+
const newWrappedMasterKey = yield this.encryptionService.encrypt(newPassKey.passKey, masterKey.jwk.toJSON(true));
|
|
156
|
+
// If the IdP change password failed, we need to go into recovery mode by forcing
|
|
157
|
+
// a login. We can't logout the user just yet since the IdP password change needs
|
|
158
|
+
// the user to be logged in. We _can_ removed any persisted session values for the IdP
|
|
159
|
+
// but that seems like too much trouble.
|
|
160
|
+
const { token, newPassKeyId } = yield this.changePasswordMutation(signedChallenge, currentUser.currentUserKey.masterKey.id, newWrappedMasterKey, newPassKey);
|
|
161
|
+
// --Potential Failure Point 2--
|
|
162
|
+
// changePasswordMutation() uploads new keys and obtains a semaphore lock to prevent any other
|
|
163
|
+
// clients from performing IdP password change.
|
|
164
|
+
// Now we can do the IdP password change.
|
|
165
|
+
// todo: Add this back in
|
|
166
|
+
yield this.auth.changePassword(cognitoUser, this.getPassIdpString(passIdp), this.getPassIdpString(newPassKey.passIdp));
|
|
167
|
+
// --Potential Failure Point 3--
|
|
168
|
+
// IdP password change
|
|
169
|
+
// Note that changePassword() could throw an exception for a number of reason. It could throw
|
|
170
|
+
// a network timeout for example. But we don't know if it's the response that timed out and
|
|
171
|
+
// the idp password change was actually carried out. So we have to be extra conservative and
|
|
172
|
+
// only act on a clear success. Otherwise we go into recover mode.
|
|
173
|
+
yield this.changePasswordComplete(cognitoUser.getSignInUserSession().getAccessToken().getJwtToken(), true, token);
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
changePasswordComplete(accessToken, useNewPassword, token = null) {
|
|
177
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
178
|
+
return this.http
|
|
179
|
+
.post(`${this.config.authUrl}users/password-change-complete/`, Object.assign({ use_new_password: useNewPassword }, (token && { token })), {
|
|
180
|
+
headers: {
|
|
181
|
+
Authorization: `Bearer ${accessToken}`,
|
|
182
|
+
},
|
|
183
|
+
})
|
|
184
|
+
.toPromise();
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
getVerifierPrK(passKey, wrappedPrK) {
|
|
188
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
189
|
+
try {
|
|
190
|
+
const prkJson = yield this.encryptionService.decrypt(passKey, wrappedPrK);
|
|
191
|
+
return KFS.asKey(prkJson);
|
|
192
|
+
}
|
|
193
|
+
catch (error) {
|
|
194
|
+
throw new LrAuthException('Wrong current password');
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
verifyPassword(password, currentUser) {
|
|
199
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
200
|
+
// Get information from the server to prepare for password change.
|
|
201
|
+
const passwordRequest = yield this.apollo.mutate({
|
|
202
|
+
mutation: PasswordChangeRequestMutation,
|
|
203
|
+
variables: {},
|
|
204
|
+
});
|
|
205
|
+
// Get the old passKey so we can decrypt the old password verifier
|
|
206
|
+
const passKeyResult = yield this.keyFactory.derivePassKey(Object.assign({ password }, currentUser.currentUserKey.passKey.passKeyParams));
|
|
207
|
+
const verifierPrK = yield this.getVerifierPrK(passKeyResult.jwk, currentUser.currentUserKey.passKey.wrappedPassIdpVerifierPrk);
|
|
208
|
+
// Sign the server challenge to prove to the server we can decrypt the password verifier.
|
|
209
|
+
// Generate
|
|
210
|
+
const clientNonce = this.keyFactory.randomString(this.CLIENT_NONCE_LENGTH);
|
|
211
|
+
const signedChallenge = yield this.encryptionService.sign(verifierPrK, {
|
|
212
|
+
serverNonce: passwordRequest.passwordChangeRequest.challenge.serverNonce,
|
|
213
|
+
clientNonce,
|
|
214
|
+
});
|
|
215
|
+
const passIdpResult = yield this.keyFactory.derivePassIdp(Object.assign({ password }, currentUser.currentUserKey.passKey.passIdpParams));
|
|
216
|
+
return {
|
|
217
|
+
passIdp: passIdpResult.jwk,
|
|
218
|
+
signedChallenge,
|
|
219
|
+
};
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
changePasswordMutation(signedChallenge, masterKeyId, newWrappedMasterKey, passKeyBundle) {
|
|
223
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
224
|
+
const response = yield this.apollo.mutate({
|
|
225
|
+
mutation: PasswordChangeMutation,
|
|
226
|
+
variables: {
|
|
227
|
+
input: {
|
|
228
|
+
signedChallenge: JSON.stringify(signedChallenge),
|
|
229
|
+
masterKeyId,
|
|
230
|
+
newWrappedMasterKey: JSON.stringify(newWrappedMasterKey),
|
|
231
|
+
newPassKey: {
|
|
232
|
+
passIdpParams: JSON.stringify(passKeyBundle.passIdpParams),
|
|
233
|
+
passIdpVerifierPbk: JSON.stringify(passKeyBundle.passIdpVerifier.toJSON()),
|
|
234
|
+
wrappedPassIdpVerifierPrk: JSON.stringify(passKeyBundle.wrappedPassIdpVerifierPrk),
|
|
235
|
+
passKeyParams: JSON.stringify(passKeyBundle.passKeyParams),
|
|
236
|
+
},
|
|
237
|
+
},
|
|
238
|
+
},
|
|
239
|
+
});
|
|
240
|
+
return {
|
|
241
|
+
token: response.passwordChange.token,
|
|
242
|
+
newPassKeyId: response.passwordChange.newPassKey.id,
|
|
243
|
+
};
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
getChangePasswordConfig() {
|
|
247
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
248
|
+
const res = yield this.apollo.query({
|
|
249
|
+
query: PasswordChangeConfigQuery,
|
|
250
|
+
});
|
|
251
|
+
const ret = res.passwordChangeConfig;
|
|
252
|
+
ret.authTime = new Date(ret.authTime);
|
|
253
|
+
ret.serverTime = new Date(ret.serverTime);
|
|
254
|
+
return ret;
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
passwordStrength(password) {
|
|
258
|
+
const upper = /[A-Z]/g;
|
|
259
|
+
const lower = /[a-z]/g;
|
|
260
|
+
const digit = /[0-9]/g;
|
|
261
|
+
const upperChoices = 26;
|
|
262
|
+
const lowerChoices = 26;
|
|
263
|
+
const digitChoices = 10;
|
|
264
|
+
const specialChoices = 30; // /[!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~]/g
|
|
265
|
+
function instanceCount(str, re) {
|
|
266
|
+
return ((str || '').match(re) || []).length;
|
|
267
|
+
}
|
|
268
|
+
const uppers = instanceCount(password, upper);
|
|
269
|
+
const lowers = instanceCount(password, lower);
|
|
270
|
+
const digits = instanceCount(password, digit);
|
|
271
|
+
const specials = password.length - uppers - lowers - digits;
|
|
272
|
+
let choices = 0;
|
|
273
|
+
if (uppers) {
|
|
274
|
+
choices += upperChoices;
|
|
275
|
+
}
|
|
276
|
+
if (lowers) {
|
|
277
|
+
choices += lowerChoices;
|
|
278
|
+
}
|
|
279
|
+
if (digits) {
|
|
280
|
+
choices += digitChoices;
|
|
281
|
+
}
|
|
282
|
+
if (specials) {
|
|
283
|
+
choices += specialChoices;
|
|
284
|
+
}
|
|
285
|
+
if (password.length === 0) {
|
|
286
|
+
return {
|
|
287
|
+
years: 0,
|
|
288
|
+
// bits of entropy
|
|
289
|
+
bits: 0,
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
const permutations = Math.pow(choices, password.length);
|
|
293
|
+
const years = (54000 * permutations) /
|
|
294
|
+
Math.pow(upperChoices + lowerChoices + digitChoices, 12);
|
|
295
|
+
return {
|
|
296
|
+
years,
|
|
297
|
+
// bits of entropy
|
|
298
|
+
bits: Math.round(Math.log2(permutations)),
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
PasswordService.ɵprov = i0.ɵɵdefineInjectable({ factory: function PasswordService_Factory() { return new PasswordService(i0.ɵɵinject(i1.LR_CONFIG), i0.ɵɵinject(i2.HttpClient), i0.ɵɵinject(i3.LrApolloService), i0.ɵɵinject(i4.AuthClass), i0.ɵɵinject(i5.ProfileService), i0.ɵɵinject(i6.KeyFactoryService), i0.ɵɵinject(i7.EncryptionService), i0.ɵɵinject(i8.KeyGraphService), i0.ɵɵinject(i9.WebCryptoService), i0.ɵɵinject(i10.IdleService)); }, token: PasswordService, providedIn: "root" });
|
|
303
|
+
PasswordService.decorators = [
|
|
304
|
+
{ type: Injectable, args: [{
|
|
305
|
+
providedIn: 'root',
|
|
306
|
+
},] }
|
|
307
|
+
];
|
|
308
|
+
PasswordService.ctorParameters = () => [
|
|
309
|
+
{ type: undefined, decorators: [{ type: Inject, args: [LR_CONFIG,] }] },
|
|
310
|
+
{ type: HttpClient },
|
|
311
|
+
{ type: LrApolloService },
|
|
312
|
+
{ type: AuthClass },
|
|
313
|
+
{ type: ProfileService },
|
|
314
|
+
{ type: KFS },
|
|
315
|
+
{ type: EncryptionService },
|
|
316
|
+
{ type: KeyGraphService },
|
|
317
|
+
{ type: WebCryptoService },
|
|
318
|
+
{ type: IdleService }
|
|
319
|
+
];
|
|
320
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGFzc3dvcmQuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiJDOi9Qcm9qZWN0cy9uZXdyZXBvL2tjLWNsaWVudC9wcm9qZWN0cy9jb3JlL3NyYy8iLCJzb3VyY2VzIjpbImxpYi9hdXRoL3Bhc3N3b3JkLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUNsRCxPQUFPLEVBQUUsTUFBTSxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUVuRCxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFFM0QsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQzFELE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLG9DQUFvQyxDQUFDO0FBQ3ZFLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxtQ0FBbUMsQ0FBQztBQUNwRSxPQUFPLEVBQW1CLFNBQVMsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ2xFLE9BQU8sRUFBRSxlQUFlLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUNoRixPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDN0QsT0FBTyxFQUNMLHNCQUFzQixFQUN0Qiw2QkFBNkIsRUFDN0IseUJBQXlCLEdBQzFCLE1BQU0sWUFBWSxDQUFDO0FBRXBCLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLG9DQUFvQyxDQUFDO0FBRXRFLE9BQU8sS0FBSyxPQUFPLE1BQU0sUUFBUSxDQUFDO0FBRWxDLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUNuRCxPQUFPLEVBQUUsaUJBQWlCLElBQUksR0FBRyxFQUFFLE1BQU0scUNBQXFDLENBQUM7Ozs7Ozs7Ozs7OztBQUUvRSxxSEFBcUg7QUFDckgsTUFBTSxNQUFNLEdBQUcsT0FBTyxDQUFDO0FBeUJ2QixNQUFNLE9B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SUFBSSxRQUFRLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRTtZQUN6QixPQUFPO2dCQUNMLEtBQUssRUFBRSxDQUFDO2dCQUNSLGtCQUFrQjtnQkFDbEIsSUFBSSxFQUFFLENBQUM7YUFDUixDQUFDO1NBQ0g7UUFFRCxNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxRQUFRLENBQUMsTUFBTSxDQUFDLENBQUM7UUFFeEQsTUFBTSxLQUFLLEdBQ1QsQ0FBQyxLQUFLLEdBQUcsWUFBWSxDQUFDO1lBQ3RCLElBQUksQ0FBQyxHQUFHLENBQUMsWUFBWSxHQUFHLFlBQVksR0FBRyxZQUFZLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFDM0QsT0FBTztZQUNMLEtBQUs7WUFDTCxrQkFBa0I7WUFDbEIsSUFBSSxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQztTQUMxQyxDQUFDO0lBQ0osQ0FBQzs7OztZQTVYRixVQUFVLFNBQUM7Z0JBQ1YsVUFBVSxFQUFFLE1BQU07YUFDbkI7Ozs0Q0FLSSxNQUFNLFNBQUMsU0FBUztZQS9EWixVQUFVO1lBVVYsZUFBZTtZQVBmLFNBQVM7WUFFVCxjQUFjO1lBaUJPLEdBQUc7WUFoQnhCLGlCQUFpQjtZQUNqQixlQUFlO1lBVWYsZ0JBQWdCO1lBSWhCLFdBQVciLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBIdHRwQ2xpZW50IH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uL2h0dHAnO1xyXG5pbXBvcnQgeyBJbmplY3QsIEluamVjdGFibGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgQ29nbml0b1VzZXIgfSBmcm9tICdAYXdzLWFtcGxpZnkvYXV0aCc7XHJcbmltcG9ydCB7IEF1dGhDbGFzcyB9IGZyb20gJ0Bhd3MtYW1wbGlmeS9hdXRoL2xpYi1lc20vQXV0aCc7XHJcbmltcG9ydCB7IEpXSywgSldTIH0gZnJvbSAnbm9kZS1qb3NlJztcclxuaW1wb3J0IHsgUHJvZmlsZVNlcnZpY2UgfSBmcm9tICcuLi91c2Vycy9wcm9maWxlLnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBFbmNyeXB0aW9uU2VydmljZSB9IGZyb20gJy4uL2NyeXB0b2dyYXBoeS9lbmNyeXB0aW9uLnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBLZXlHcmFwaFNlcnZpY2UgfSBmcm9tICcuLi9jcnlwdG9ncmFwaHkva2V5LWdyYXBoLnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBMaWZlUmVhZHlDb25maWcsIExSX0NPTkZJRyB9IGZyb20gJy4uL2xpZmUtcmVhZHkuY29uZmlnJztcclxuaW1wb3J0IHsgTHJBdXRoRXhjZXB0aW9uLCBMckJhZEFyZ3VtZW50RXhjZXB0aW9uIH0gZnJvbSAnLi4vX2NvbW1vbi9leGNlcHRpb25zJztcclxuaW1wb3J0IHsgTHJBcG9sbG9TZXJ2aWNlIH0gZnJvbSAnLi8uLi9hcGkvbHItYXBvbGxvLnNlcnZpY2UnO1xyXG5pbXBvcnQge1xyXG4gIFBhc3N3b3JkQ2hhbmdlTXV0YXRpb24sXHJcbiAgUGFzc3dvcmRDaGFuZ2VSZXF1ZXN0TXV0YXRpb24sXHJcbiAgUGFzc3dvcmRDaGFuZ2VDb25maWdRdWVyeSxcclxufSBmcm9tICcuL2F1dGguZ3FsJztcclxuaW1wb3J0IHsgUGFzc0tleUJ1bmRsZSB9IGZyb20gJy4vYXV0aC50eXBlcyc7XHJcbmltcG9ydCB7IFdlYkNyeXB0b1NlcnZpY2UgfSBmcm9tICcuLi9jcnlwdG9ncmFwaHkvd2ViLWNyeXB0by5zZXJ2aWNlJztcclxuaW1wb3J0IHsgRHVyYXRpb24gfSBmcm9tICdtb21lbnQnO1xyXG5pbXBvcnQgKiBhcyBtb21lbnRfIGZyb20gJ21vbWVudCc7XHJcbmltcG9ydCB7IEFwaUN1cnJlbnRVc2VyIH0gZnJvbSAnLi4vdXNlcnMvcHJvZmlsZS50eXBlcyc7XHJcbmltcG9ydCB7IElkbGVTZXJ2aWNlIH0gZnJvbSAnLi4vYXV0aC9pZGxlLnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBLZXlGYWN0b3J5U2VydmljZSBhcyBLRlMgfSBmcm9tICcuLi9jcnlwdG9ncmFwaHkva2V5LWZhY3Rvcnkuc2VydmljZSc7XHJcblxyXG4vLyBcIndoeT9cIiB5b3UgYXNrOiBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy81OTczNTI4MC9hbmd1bGFyLTgtbW9tZW50LWVycm9yLWNhbm5vdC1jYWxsLWEtbmFtZXNwYWNlLW1vbWVudFxyXG5jb25zdCBtb21lbnQgPSBtb21lbnRfO1xyXG5cclxuaW50ZXJmYWNlIFBhc3N3b3JkQ2hhbmdlUmVxdWVzdE11dGF0aW9uIHtcclxuICBwYXNzd29yZENoYW5nZVJlcXVlc3Q6IHtcclxuICAgIGNoYWxsZW5nZToge1xyXG4gICAgICBzZXJ2ZXJOb25jZTogc3RyaW5nO1xyXG4gICAgfTtcclxuICB9O1xyXG59XHJcblxyXG5pbnRlcmZhY2UgUGFzc3dvcmRDaGFuZ2VNdXRhdGlvbiB7XHJcbiAgcGFzc3dvcmRDaGFuZ2U6IHtcclxuICAgIHRva2VuOiBzdHJpbmc7XHJcbiAgICBuZXdQYXNzS2V5OiB7XHJcbiAgICAgIGlkOiBzdHJpbmc7XHJcbiAgICB9O1xyXG4gIH07XHJcbn1cclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgUGFzc3dvcmRDaGFuZ2VDb25maWcge1xyXG4gIG1heEF1dGhBZ2VTZWNvbmRzOiBudW1iZXI7XHJcbiAgYXV0aFRpbWU6IHN0cmluZyB8IERhdGU7XHJcbiAgc2VydmVyVGltZTogc3RyaW5nIHwgRGF0ZTtcclxufVxyXG5cclxuZXhwb3J0IGNsYXNzIFBhc3N3b3JkQ2hlY2sge1xyXG4gIGxlbmd0aD86IG51bWJlcjtcclxuICB0aW1lVG9DcmFjaz86IER1cmF0aW9uO1xyXG4gIHBhc3N3b3JkRXhwb3NlZD86IG51bWJlcjtcclxufVxyXG5cclxuQEluamVjdGFibGUoe1xyXG4gIHByb3ZpZGVkSW46ICdyb290JyxcclxufSlcclxuZXhwb3J0IGNsYXNzIFBhc3N3b3JkU2VydmljZSB7XHJcbiAgcHJpdmF0ZSByZWFkb25seSBDTElFTlRfTk9OQ0VfTEVOR1RIID0gMzI7XHJcblxyXG4gIGNvbnN0cnVjdG9yKFxyXG4gICAgQEluamVjdChMUl9DT05GSUcpIHByaXZhdGUgY29uZmlnOiBMaWZlUmVhZHlDb25maWcsXHJcbiAgICBwcml2YXRlIGh0dHA6IEh0dHBDbGllbnQsXHJcbiAgICBwcml2YXRlIGFwb2xsbzogTHJBcG9sbG9TZXJ2aWNlLFxyXG4gICAgcHJpdmF0ZSBhdXRoOiBBdXRoQ2xhc3MsXHJcbiAgICBwcml2YXRlIHByb2ZpbGVTZXJ2aWNlOiBQcm9maWxlU2VydmljZSxcclxuICAgIHByaXZhdGUga2V5RmFjdG9yeTogS0ZTLFxyXG4gICAgcHJpdmF0ZSBlbmNyeXB0aW9uU2VydmljZTogRW5jcnlwdGlvblNlcnZpY2UsXHJcbiAgICBwcml2YXRlIGtleUdyYXBoOiBLZXlHcmFwaFNlcnZpY2UsXHJcbiAgICBwcml2YXRlIHdlYkNyeXB0b1NlcnZpY2U6IFdlYkNyeXB0b1NlcnZpY2UsXHJcbiAgICBwcml2YXRlIGlkbGVTZXJ2aWNlOiBJZGxlU2VydmljZVxyXG4gICkge31cclxuXHJcbiAgcHVibGljIGFzeW5jIGNoZWNrUGFzc3dvcmQocGFzc3dvcmQ6IHN0cmluZyk6IFByb21pc2U8UGFzc3dvcmRDaGVjaz4ge1xyXG4gICAgY29uc3QgeyB5ZWFycyB9ID0gdGhpcy5wYXNzd29yZFN0cmVuZ3RoKHBhc3N3b3JkKTtcclxuXHJcbiAgICByZXR1cm4ge1xyXG4gICAgICBsZW5ndGg6IHBhc3N3b3JkLmxlbmd0aCxcclxuICAgICAgdGltZVRvQ3JhY2s6IG1vbWVudC5kdXJhdGlvbih7IHllYXJzIH0pLFxyXG4gICAgICBwYXNzd29yZEV4cG9zZWQ6IGF3YWl0IHRoaXMuZ2V0RXhwb3N1cmVDb3VudChwYXNzd29yZCksXHJcbiAgICB9O1xyXG4gIH1cclxuXHJcbiAgcHVibGljIGFzeW5jIGdldEV4cG9zdXJlQ291bnQocGFzc3dvcmQ6IHN0cmluZyk6IFByb21pc2U8bnVtYmVyPiB7XHJcbiAgICBjb25zdCBzaGExUGFzc3dvcmQgPSBhd2FpdCB0aGlzLndlYkNyeXB0b1NlcnZpY2Uuc3RyaW5nRGlnZXN0KFxyXG4gICAgICAnU0hBLTEnLFxyXG4gICAgICBwYXNzd29yZFxyXG4gICAgKTtcclxuICAgIGNvbnN0IGZpcnN0NXNoYTEgPSBzaGExUGFzc3dvcmQuc3Vic3RyaW5nKDAsIDUpO1xyXG5cclxuICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgdGhpcy5odHRwXHJcbiAgICAgIC5nZXQoYGh0dHBzOi8vYXBpLnB3bmVkcGFzc3dvcmRzLmNvbS9yYW5nZS8ke2ZpcnN0NXNoYTF9YCwge1xyXG4gICAgICAgIHJlc3BvbnNlVHlwZTogJ3RleHQnLFxyXG4gICAgICB9KVxyXG4gICAgICAudG9Qcm9taXNlKCk7XHJcblxyXG4gICAgY29uc3QgcmVzdWx0cyA9IG5ldyBSZWdFeHAoXHJcbiAgICAgIGBeKD86JHtzaGExUGFzc3dvcmQuc3Vic3RyaW5nKDUpfTopKD88Y291bnQ+XFxcXGQrKSRgLFxyXG4gICAgICAnaW0nXHJcbiAgICApLmV4ZWMocmVzcG9uc2UpO1xyXG5cclxuICAgIGlmIChyZXN1bHRzKSB7XHJcbiAgICAgIHJldHVybiArcmVzdWx0cy5ncm91cHMuY291bnQ7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gMDtcclxuICB9XHJcblxyXG4gIHB1YmxpYyBnZXRQYXNzSWRwU3RyaW5nKHBhc3NJZHA6IEpXSy5LZXkpIHtcclxuICAgIHJldHVybiAocGFzc0lkcC50b0pTT04odHJ1ZSkgYXMgYW55KS5rO1xyXG4gIH1cclxuXHJcbiAgcHVibGljIGFzeW5jIGNyZWF0ZVBhc3NLZXlCdW5kbGUocGFzc3dvcmQ6IHN0cmluZyk6IFByb21pc2U8UGFzc0tleUJ1bmRsZT4ge1xyXG4gICAgY29uc3QgcGFzc0lkcFBhcmFtcyA9IGF3YWl0IHRoaXMua2V5RmFjdG9yeS5jcmVhdGVQYXNzSWRwUGFyYW1zKCk7XHJcbiAgICBjb25zdCBwYXNzSWRwID0gKFxyXG4gICAgICBhd2FpdCB0aGlzLmtleUZhY3RvcnkuZGVyaXZlUGFzc0lkcCh7XHJcbiAgICAgICAgcGFzc3dvcmQsXHJcbiAgICAgICAgLi4ucGFzc0lkcFBhcmFtcyxcclxuICAgICAgfSlcclxuICAgICkuandrO1xyXG5cclxuICAgIGNvbnN0IHBhc3NLZXlQYXJhbXMgPSBhd2FpdCB0aGlzLmtleUZhY3RvcnkuY3JlYXRlUGFzc0tleVBhcmFtcygpO1xyXG4gICAgY29uc3QgcGFzc0tleSA9IChcclxuICAgICAgYXdhaXQgdGhpcy5rZXlGYWN0b3J5LmRlcml2ZVBhc3NLZXkoe1xyXG4gICAgICAgIHBhc3N3b3JkLFxyXG4gICAgICAgIC4uLnBhc3NLZXlQYXJhbXMsXHJcbiAgICAgIH0pXHJcbiAgICApLmp3aztcclxuXHJcbiAgICBjb25zdCBwYXNzSWRwVmVyaWZpZXIgPSBhd2FpdCB0aGlzLmtleUZhY3RvcnkuY3JlYXRlUGtjU2lnbktleSgpO1xyXG5cclxuICAgIGNvbnN0IHdyYXBwZWRQYXNzSWRwVmVyaWZpZXJQcmsgPSBhd2FpdCB0aGlzLmVuY3J5cHRpb25TZXJ2aWNlLmVuY3J5cHQoXHJcbiAgICAgIHBhc3NLZXksXHJcbiAgICAgIHBhc3NJZHBWZXJpZmllci50b0pTT04odHJ1ZSlcclxuICAgICk7XHJcblxyXG4gICAgLy8gVGhlcmUgYXJlIHR3byBmb3JtYXRzIHRoYXQgdGhlIHByaXZhdGUga2V5IGNhbiBiZSByZXByZXNlbnRlZCBpbiBKV0s6XHJcbiAgICAvLyBodHRwczovL3Rvb2xzLmlldGYub3JnL2h0bWwvcmZjODAxNyNwYWdlLTlcclxuICAgIC8vIFRoZSBzZWNvbmQgZm9ybSBpcyBhbiBvcHRpbWl6YXRpb246XHJcbiAgICAvLyBodHRwczovL2NyeXB0by5zdGFja2V4Y2hhbmdlLmNvbS9xdWVzdGlvbnMvMTk0MTMvd2hhdC1hcmUtZHAtYW5kLWRxLWluLWVuY3J5cHRpb24tYnktcnNhLWluLWNcclxuXHJcbiAgICByZXR1cm4ge1xyXG4gICAgICBwYXNzS2V5UGFyYW1zLFxyXG4gICAgICBwYXNzS2V5LFxyXG4gICAgICBwYXNzSWRwUGFyYW1zLFxyXG4gICAgICBwYXNzSWRwLFxyXG4gICAgICBwYXNzSWRwVmVyaWZpZXIsXHJcbiAgICAgIHdyYXBwZWRQYXNzSWRwVmVyaWZpZXJQcmssXHJcbiAgICB9O1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogV2UgbmVlZCB0byBhbGxvdyBmb3IgaW50ZXJydXB0aW9uIG9mIHRoZSBwcm9jZXNzIGF0IGFueSBwb2ludC4gRWFjaCBBUEkgY2FsbCBjYW4gYmUgY29uc2lkZXJlZFxyXG4gICAqIGF0b21pYyBhbmQgZWl0aGVyIHN1Y2NlZWRzIG9yIGZhaWxzLlxyXG4gICAqXHJcbiAgICogVGhlIExSIHNlcnZlciBBUElzIHVzZSBzZW1hcGhvcmUgdG9rZW5zIGZvciBsb2NraW5nIGNyaXRpY2FsIG9wZXJhdGlvbnMsIHNvIGNvbmN1cnJlbnQgY2FsbHMgd2lsbFxyXG4gICAqIGZhaWwuXHJcbiAgICpcclxuICAgKiBXZSBhc3N1bWUgdGhlIHdvcnN0IGNhc2UgZm9yIElkUCBBUEkgY2FsbHMuIFNvIHdlIHVzZSB0aGUgc2VtYXBob3JlIHRva2VuIGZyb20gTFIgdG8gcHJldmVudFxyXG4gICAqIGNvbmN1cnJlbnQgY2FsbHMgdG8gSWRQIEFQSXMsIGJ1dCB3ZSBoYXZlIHRvIGFzc3VtZSB0aGF0IHRoZSBJZFAgQVBJIGNhbGxzIHdpbGwgZWl0aGVyIHN1Y2NlZWQgb3JcclxuICAgKiBmYWlsIHdpdGhpbiBhIHJlYXNvbmFibGUgYW1vdW50IG9mIHRpbWUuXHJcbiAgICpcclxuICAgKiBFYWNoIGxvY2F0aW9uIHdoZXJlIHRoZSBzZXJ2ZXIgc3RhdGUgY2hhbmdlcyBjYW4gYmUgYSBwb3RlbnRpYWwgcG9pbnQgb2YgaW50ZXJydXB0aW9uLlxyXG4gICAqIFBvdGVudGlhbCBwb2ludHMgb2YgaW50ZXJydXB0aW9uIGFyZSBtYXJrZWQgd2l0aDogLS1Qb3RlbnRpYWwgRmFpbHVyZSBQb2ludC0tXHJcbiAgICpcclxuICAgKiBQbGFjZXMgZm9yIHRpbWVvdXQ6XHJcbiAgICogLSBMb2dpbiBhZ2UgdG9vIG9sZCBhdCBjYWxsIHRvOiB2ZXJpZnlQYXNzd29yZCgpXHJcbiAgICogLSBMb2dpbiBhZ2UgdG9vIG9sZCBhdCBjYWxsIHRvOiBjaGFuZ2VQYXNzd29yZE11dGF0aW9uKClcclxuICAgKiAtIFNlbWFwaG9yZSB0b2tlbiBleHBpcmVzIGF0IGNhbGwgdG86IGNoYW5nZVBhc3N3b3JkQ29tcGxldGUoKVxyXG4gICAqXHJcbiAgICogVGVzdHM6XHJcbiAgICogLSBQb3RlbnRpYWwgRmFpbHVyZSBQb2ludCAxOiBzaG91bGQgYmUgYWJsZSB0byByZXN0YXJ0IHRoZSBwcm9jZXNzLCB1c2VyIHJlbWFpbnMgc2lnbmVkIGluLlxyXG4gICAqIC0gUG90ZW50aWFsIEZhaWx1cmUgUG9pbnQgMjogc2hvdWxkIGVudGVyIHJlY292ZXJ5IGZsb3dcclxuICAgKiAtIFBvdGVudGlhbCBGYWlsdXJlIFBvaW50IDM6IHNob3VsZCBlbnRlciByZWNvdmVyeSBmbG93XHJcbiAgICogLSBQb3RlbnRpYWwgRmFpbHVyZSBQb2ludCA0OiBzaG91bGQgZW50ZXIgcmVjb3ZlcnkgZmxvd1xyXG4gICAqXHJcbiAgICovXHJcblxyXG4gIHB1YmxpYyBhc3luYyBpc0xvZ2luUmVxdWlyZWQoKTogUHJvbWlzZTxib29sZWFuPiB7XHJcbiAgICBjb25zdCBjaGFuZ2VQYXNzd29yZENvbmZpZyA9IGF3YWl0IHRoaXMuZ2V0Q2hhbmdlUGFzc3dvcmRDb25maWcoKTtcclxuICAgIGNvbnN0IGF1dGhUaW1lID0gbW9tZW50KGNoYW5nZVBhc3N3b3JkQ29uZmlnLmF1dGhUaW1lKTtcclxuICAgIGNvbnN0IHNlcnZlclRpbWUgPSBtb21lbnQoY2hhbmdlUGFzc3dvcmRDb25maWcuc2VydmVyVGltZSk7XHJcbiAgICBjb25zdCBkdXJhdGlvbiA9IG1vbWVudC5kdXJhdGlvbihzZXJ2ZXJUaW1lLmRpZmYoYXV0aFRpbWUpKTtcclxuICAgIGNvbnN0IHNlY29uZHMgPSBkdXJhdGlvbi5hc1NlY29uZHMoKTtcclxuICAgIGlmIChzZWNvbmRzID4gY2hhbmdlUGFzc3dvcmRDb25maWcubWF4QXV0aEFnZVNlY29uZHMpIHtcclxuICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBwdWJsaWMgYXN5bmMgY2hhbmdlUGFzc3dvcmQocGFzc3dvcmQ6IHN0cmluZywgbmV3UGFzc3dvcmQ6IHN0cmluZykge1xyXG4gICAgY29uc3QgY29nbml0b1VzZXI6IENvZ25pdG9Vc2VyID0gYXdhaXQgdGhpcy5hdXRoLmN1cnJlbnRBdXRoZW50aWNhdGVkVXNlcigpO1xyXG5cclxuICAgIC8vIFZhbGlkYXRpb25cclxuICAgIC8vIHRvZG86IEFkZCB0aGlzIGJhY2sgaW5cclxuICAgIC8vIE5vdGUgdGhlIHBhc3NJZHAgd2lsbCBhbHdheXMgaGF2ZSBhIHJhbmRvbSBzYWx0LCBzbyB3aWxsIGFsd2F5cyBiZSBkaWZmZXJlbnQgdG8gdGhlIGN1cnJlbnQgcGFzc0lkcC5cclxuICAgIGlmIChwYXNzd29yZCA9PT0gbmV3UGFzc3dvcmQpIHtcclxuICAgICAgdGhyb3cgbmV3IExyQmFkQXJndW1lbnRFeGNlcHRpb24oXHJcbiAgICAgICAgJ05ldyBwYXNzd29yZCBpcyB0aGUgc2FtZSBhcyB0aGUgY3VycmVudCBvbmUuJ1xyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHsgY3VycmVudFVzZXIgfSA9IGF3YWl0IHRoaXMucHJvZmlsZVNlcnZpY2UuZ2V0Q3VycmVudFVzZXIoKTtcclxuXHJcbiAgICBjb25zdCB7IHBhc3NJZHAsIHNpZ25lZENoYWxsZW5nZSB9ID0gYXdhaXQgdGhpcy52ZXJpZnlQYXNzd29yZChcclxuICAgICAgcGFzc3dvcmQsXHJcbiAgICAgIGN1cnJlbnRVc2VyXHJcbiAgICApO1xyXG5cclxuICAgIC8vIC0tUG90ZW50aWFsIEZhaWx1cmUgUG9pbnQgMS0tXHJcbiAgICAvLyB2ZXJpZnlQYXNzd29yZCgpIGFza3MgZm9yIGEgY3VycmVudCBwYXNzd29yZCBjaGFsbGVuZ2UgaGVuY2UgY2hhbmdlcyBzZXJ2ZXIgc3RhdGUuXHJcbiAgICAvLyBQbGFjZSBicmVhayBwb2ludHMgaGVyZSB0byB0ZXN0IHRoZSBmYWlsdXJlIHNjZW5hcmlvcy5cclxuXHJcbiAgICAvLyBHZW5lcmF0ZSB0aGUgbmV3IHBhc3NJZHBcclxuICAgIGNvbnN0IG5ld1Bhc3NLZXkgPSBhd2FpdCB0aGlzLmNyZWF0ZVBhc3NLZXlCdW5kbGUobmV3UGFzc3dvcmQpO1xyXG5cclxuICAgIC8vIFJlLWVuY3J5cHQgbWFzdGVyIGtleSB3aXRoIG5ldyBrZXlcclxuICAgIGNvbnN0IG1hc3RlcktleSA9IGF3YWl0IHRoaXMua2V5R3JhcGguZ2V0S2V5KFxyXG4gICAgICBjdXJyZW50VXNlci5jdXJyZW50VXNlcktleS5tYXN0ZXJLZXkuaWRcclxuICAgICk7XHJcbiAgICBjb25zdCBuZXdXcmFwcGVkTWFzdGVyS2V5ID0gYXdhaXQgdGhpcy5lbmNyeXB0aW9uU2VydmljZS5lbmNyeXB0KFxyXG4gICAgICBuZXdQYXNzS2V5LnBhc3NLZXksXHJcbiAgICAgIG1hc3RlcktleS5qd2sudG9KU09OKHRydWUpXHJcbiAgICApO1xyXG5cclxuICAgIC8vIElmIHRoZSBJZFAgY2hhbmdlIHBhc3N3b3JkIGZhaWxlZCwgd2UgbmVlZCB0byBnbyBpbnRvIHJlY292ZXJ5IG1vZGUgYnkgZm9yY2luZ1xyXG4gICAgLy8gYSBsb2dpbi4gV2UgY2FuJ3QgbG9nb3V0IHRoZSB1c2VyIGp1c3QgeWV0IHNpbmNlIHRoZSBJZFAgcGFzc3dvcmQgY2hhbmdlIG5lZWRzXHJcbiAgICAvLyB0aGUgdXNlciB0byBiZSBsb2dnZWQgaW4uIFdlIF9jYW5fIHJlbW92ZWQgYW55IHBlcnNpc3RlZCBzZXNzaW9uIHZhbHVlcyBmb3IgdGhlIElkUFxyXG4gICAgLy8gYnV0IHRoYXQgc2VlbXMgbGlrZSB0b28gbXVjaCB0cm91YmxlLlxyXG5cclxuICAgIGNvbnN0IHsgdG9rZW4sIG5ld1Bhc3NLZXlJZCB9ID0gYXdhaXQgdGhpcy5jaGFuZ2VQYXNzd29yZE11dGF0aW9uKFxyXG4gICAgICBzaWduZWRDaGFsbGVuZ2UsXHJcbiAgICAgIGN1cnJlbnRVc2VyLmN1cnJlbnRVc2VyS2V5Lm1hc3RlcktleS5pZCxcclxuICAgICAgbmV3V3JhcHBlZE1hc3RlcktleSxcclxuICAgICAgbmV3UGFzc0tleVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyAtLVBvdGVudGlhbCBGYWlsdXJlIFBvaW50IDItLVxyXG4gICAgLy8gY2hhbmdlUGFzc3dvcmRNdXRhdGlvbigpIHVwbG9hZHMgbmV3IGtleXMgYW5kIG9idGFpbnMgYSBzZW1hcGhvcmUgbG9jayB0byBwcmV2ZW50IGFueSBvdGhlclxyXG4gICAgLy8gY2xpZW50cyBmcm9tIHBlcmZvcm1pbmcgSWRQIHBhc3N3b3JkIGNoYW5nZS5cclxuXHJcbiAgICAvLyBOb3cgd2UgY2FuIGRvIHRoZSBJZFAgcGFzc3dvcmQgY2hhbmdlLlxyXG4gICAgLy8gdG9kbzogQWRkIHRoaXMgYmFjayBpblxyXG4gICAgYXdhaXQgdGhpcy5hdXRoLmNoYW5nZVBhc3N3b3JkKFxyXG4gICAgICBjb2duaXRvVXNlcixcclxuICAgICAgdGhpcy5nZXRQYXNzSWRwU3RyaW5nKHBhc3NJZHApLFxyXG4gICAgICB0aGlzLmdldFBhc3NJZHBTdHJpbmcobmV3UGFzc0tleS5wYXNzSWRwKVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyAtLVBvdGVudGlhbCBGYWlsdXJlIFBvaW50IDMtLVxyXG4gICAgLy8gSWRQIHBhc3N3b3JkIGNoYW5nZVxyXG5cclxuICAgIC8vIE5vdGUgdGhhdCBjaGFuZ2VQYXNzd29yZCgpIGNvdWxkIHRocm93IGFuIGV4Y2VwdGlvbiBmb3IgYSBudW1iZXIgb2YgcmVhc29uLiBJdCBjb3VsZCB0aHJvd1xyXG4gICAgLy8gYSBuZXR3b3JrIHRpbWVvdXQgZm9yIGV4YW1wbGUuIEJ1dCB3ZSBkb24ndCBrbm93IGlmIGl0J3MgdGhlIHJlc3BvbnNlIHRoYXQgdGltZWQgb3V0IGFuZFxyXG4gICAgLy8gdGhlIGlkcCBwYXNzd29yZCBjaGFuZ2Ugd2FzIGFjdHVhbGx5IGNhcnJpZWQgb3V0LiBTbyB3ZSBoYXZlIHRvIGJlIGV4dHJhIGNvbnNlcnZhdGl2ZSBhbmRcclxuICAgIC8vIG9ubHkgYWN0IG9uIGEgY2xlYXIgc3VjY2Vzcy4gT3RoZXJ3aXNlIHdlIGdvIGludG8gcmVjb3ZlciBtb2RlLlxyXG4gICAgYXdhaXQgdGhpcy5jaGFuZ2VQYXNzd29yZENvbXBsZXRlKFxyXG4gICAgICBjb2duaXRvVXNlci5nZXRTaWduSW5Vc2VyU2Vzc2lvbigpLmdldEFjY2Vzc1Rva2VuKCkuZ2V0Snd0VG9rZW4oKSxcclxuICAgICAgdHJ1ZSxcclxuICAgICAgdG9rZW5cclxuICAgICk7XHJcbiAgfVxyXG5cclxuICBwdWJsaWMgYXN5bmMgY2hhbmdlUGFzc3dvcmRDb21wbGV0ZShcclxuICAgIGFjY2Vzc1Rva2VuOiBzdHJpbmcsXHJcbiAgICB1c2VOZXdQYXNzd29yZDogYm9vbGVhbixcclxuICAgIHRva2VuOiBzdHJpbmcgPSBudWxsXHJcbiAgKTogUHJvbWlzZTxhbnk+IHtcclxuICAgIHJldHVybiB0aGlzLmh0dHBcclxuICAgICAgLnBvc3QoXHJcbiAgICAgICAgYCR7dGhpcy5jb25maWcuYXV0aFVybH11c2Vycy9wYXNzd29yZC1jaGFuZ2UtY29tcGxldGUvYCxcclxuICAgICAgICB7XHJcbiAgICAgICAgICB1c2VfbmV3X3Bhc3N3b3JkOiB1c2VOZXdQYXNzd29yZCxcclxuICAgICAgICAgIC4uLih0b2tlbiAmJiB7IHRva2VuIH0pLFxyXG4gICAgICAgIH0sXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgaGVhZGVyczoge1xyXG4gICAgICAgICAgICBBdXRob3JpemF0aW9uOiBgQmVhcmVyICR7YWNjZXNzVG9rZW59YCxcclxuICAgICAgICAgIH0sXHJcbiAgICAgICAgfVxyXG4gICAgICApXHJcbiAgICAgIC50b1Byb21pc2UoKTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgYXN5bmMgZ2V0VmVyaWZpZXJQcksoXHJcbiAgICBwYXNzS2V5OiBKV0suS2V5LFxyXG4gICAgd3JhcHBlZFBySzogb2JqZWN0XHJcbiAgKTogUHJvbWlzZTxKV0suS2V5PiB7XHJcbiAgICB0cnkge1xyXG4gICAgICBjb25zdCBwcmtKc29uID0gYXdhaXQgdGhpcy5lbmNyeXB0aW9uU2VydmljZS5kZWNyeXB0KHBhc3NLZXksIHdyYXBwZWRQckspO1xyXG4gICAgICByZXR1cm4gS0ZTLmFzS2V5KHBya0pzb24pO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IExyQXV0aEV4Y2VwdGlvbignV3JvbmcgY3VycmVudCBwYXNzd29yZCcpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBhc3luYyB2ZXJpZnlQYXNzd29yZChcclxuICAgIHBhc3N3b3JkOiBzdHJpbmcsXHJcbiAgICBjdXJyZW50VXNlcjogQXBpQ3VycmVudFVzZXJcclxuICApOiBQcm9taXNlPHsgcGFzc0lkcDogSldLLktleTsgc2lnbmVkQ2hhbGxlbmdlOiBKV1MuQ3JlYXRlU2lnblJlc3VsdCB9PiB7XHJcbiAgICAvLyBHZXQgaW5mb3JtYXRpb24gZnJvbSB0aGUgc2VydmVyIHRvIHByZXBhcmUgZm9yIHBhc3N3b3JkIGNoYW5nZS5cclxuICAgIGNvbnN0IHBhc3N3b3JkUmVxdWVzdCA9IGF3YWl0IHRoaXMuYXBvbGxvLm11dGF0ZTxQYXNzd29yZENoYW5nZVJlcXVlc3RNdXRhdGlvbj4oXHJcbiAgICAgIHtcclxuICAgICAgICBtdXRhdGlvbjogUGFzc3dvcmRDaGFuZ2VSZXF1ZXN0TXV0YXRpb24sXHJcbiAgICAgICAgdmFyaWFibGVzOiB7fSxcclxuICAgICAgfVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIG9sZCBwYXNzS2V5IHNvIHdlIGNhbiBkZWNyeXB0IHRoZSBvbGQgcGFzc3dvcmQgdmVyaWZpZXJcclxuICAgIGNvbnN0IHBhc3NLZXlSZXN1bHQgPSBhd2FpdCB0aGlzLmtleUZhY3RvcnkuZGVyaXZlUGFzc0tleSh7XHJcbiAgICAgIHBhc3N3b3JkLFxyXG4gICAgICAuLi5jdXJyZW50VXNlci5jdXJyZW50VXNlcktleS5wYXNzS2V5LnBhc3NLZXlQYXJhbXMsXHJcbiAgICB9KTtcclxuXHJcbiAgICBjb25zdCB2ZXJpZmllclBySyA9IGF3YWl0IHRoaXMuZ2V0VmVyaWZpZXJQcksoXHJcbiAgICAgIHBhc3NLZXlSZXN1bHQuandrLFxyXG4gICAgICBjdXJyZW50VXNlci5jdXJyZW50VXNlcktleS5wYXNzS2V5LndyYXBwZWRQYXNzSWRwVmVyaWZpZXJQcmtcclxuICAgICk7XHJcblxyXG4gICAgLy8gU2lnbiB0aGUgc2VydmVyIGNoYWxsZW5nZSB0byBwcm92ZSB0byB0aGUgc2VydmVyIHdlIGNhbiBkZWNyeXB0IHRoZSBwYXNzd29yZCB2ZXJpZmllci5cclxuICAgIC8vIEdlbmVyYXRlXHJcbiAgICBjb25zdCBjbGllbnROb25jZSA9IHRoaXMua2V5RmFjdG9yeS5yYW5kb21TdHJpbmcodGhpcy5DTElFTlRfTk9OQ0VfTEVOR1RIKTtcclxuXHJcbiAgICBjb25zdCBzaWduZWRDaGFsbGVuZ2UgPSBhd2FpdCB0aGlzLmVuY3J5cHRpb25TZXJ2aWNlLnNpZ24odmVyaWZpZXJQckssIHtcclxuICAgICAgc2VydmVyTm9uY2U6IHBhc3N3b3JkUmVxdWVzdC5wYXNzd29yZENoYW5nZVJlcXVlc3QuY2hhbGxlbmdlLnNlcnZlck5vbmNlLFxyXG4gICAgICBjbGllbnROb25jZSxcclxuICAgIH0pO1xyXG5cclxuICAgIGNvbnN0IHBhc3NJZHBSZXN1bHQgPSBhd2FpdCB0aGlzLmtleUZhY3RvcnkuZGVyaXZlUGFzc0lkcCh7XHJcbiAgICAgIHBhc3N3b3JkLFxyXG4gICAgICAuLi5jdXJyZW50VXNlci5jdXJyZW50VXNlcktleS5wYXNzS2V5LnBhc3NJZHBQYXJhbXMsXHJcbiAgICB9KTtcclxuXHJcbiAgICByZXR1cm4ge1xyXG4gICAgICBwYXNzSWRwOiBwYXNzSWRwUmVzdWx0Lmp3ayxcclxuICAgICAgc2lnbmVkQ2hhbGxlbmdlLFxyXG4gICAgfTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgYXN5bmMgY2hhbmdlUGFzc3dvcmRNdXRhdGlvbihcclxuICAgIHNpZ25lZENoYWxsZW5nZTogSldTLkNyZWF0ZVNpZ25SZXN1bHQsXHJcbiAgICBtYXN0ZXJLZXlJZDogc3RyaW5nLFxyXG4gICAgbmV3V3JhcHBlZE1hc3RlcktleTogb2JqZWN0LFxyXG4gICAgcGFzc0tleUJ1bmRsZTogUGFzc0tleUJ1bmRsZVxyXG4gICk6IFByb21pc2U8eyB0b2tlbjogc3RyaW5nOyBuZXdQYXNzS2V5SWQ6IHN0cmluZyB9PiB7XHJcbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHRoaXMuYXBvbGxvLm11dGF0ZTxQYXNzd29yZENoYW5nZU11dGF0aW9uPih7XHJcbiAgICAgIG11dGF0aW9uOiBQYXNzd29yZENoYW5nZU11dGF0aW9uLFxyXG4gICAgICB2YXJpYWJsZXM6IHtcclxuICAgICAgICBpbnB1dDoge1xyXG4gICAgICAgICAgc2lnbmVkQ2hhbGxlbmdlOiBKU09OLnN0cmluZ2lmeShzaWduZWRDaGFsbGVuZ2UpLFxyXG4gICAgICAgICAgbWFzdGVyS2V5SWQsXHJcbiAgICAgICAgICBuZXdXcmFwcGVkTWFzdGVyS2V5OiBKU09OLnN0cmluZ2lmeShuZXdXcmFwcGVkTWFzdGVyS2V5KSxcclxuICAgICAgICAgIG5ld1Bhc3NLZXk6IHtcclxuICAgICAgICAgICAgcGFzc0lkcFBhcmFtczogSlNPTi5zdHJpbmdpZnkocGFzc0tleUJ1bmRsZS5wYXNzSWRwUGFyYW1zKSxcclxuICAgICAgICAgICAgcGFzc0lkcFZlcmlmaWVyUGJrOiBKU09OLnN0cmluZ2lmeShcclxuICAgICAgICAgICAgICBwYXNzS2V5QnVuZGxlLnBhc3NJZHBWZXJpZmllci50b0pTT04oKVxyXG4gICAgICAgICAgICApLFxyXG4gICAgICAgICAgICB3cmFwcGVkUGFzc0lkcFZlcmlmaWVyUHJrOiBKU09OLnN0cmluZ2lmeShcclxuICAgICAgICAgICAgICBwYXNzS2V5QnVuZGxlLndyYXBwZWRQYXNzSWRwVmVyaWZpZXJQcmtcclxuICAgICAgICAgICAgKSxcclxuICAgICAgICAgICAgcGFzc0tleVBhcmFtczogSlNPTi5zdHJpbmdpZnkocGFzc0tleUJ1bmRsZS5wYXNzS2V5UGFyYW1zKSxcclxuICAgICAgICAgIH0sXHJcbiAgICAgICAgfSxcclxuICAgICAgfSxcclxuICAgIH0pO1xyXG4gICAgcmV0dXJuIHtcclxuICAgICAgdG9rZW46IHJlc3BvbnNlLnBhc3N3b3JkQ2hhbmdlLnRva2VuLFxyXG4gICAgICBuZXdQYXNzS2V5SWQ6IHJlc3BvbnNlLnBhc3N3b3JkQ2hhbmdlLm5ld1Bhc3NLZXkuaWQsXHJcbiAgICB9O1xyXG4gIH1cclxuXHJcbiAgYXN5bmMgZ2V0Q2hhbmdlUGFzc3dvcmRDb25maWcoKTogUHJvbWlzZTxQYXNzd29yZENoYW5nZUNvbmZpZz4ge1xyXG4gICAgY29uc3QgcmVzID0gYXdhaXQgdGhpcy5hcG9sbG8ucXVlcnk8YW55Pih7XHJcbiAgICAgIHF1ZXJ5OiBQYXNzd29yZENoYW5nZUNvbmZpZ1F1ZXJ5LFxyXG4gICAgfSk7XHJcblxyXG4gICAgY29uc3QgcmV0ID0gcmVzLnBhc3N3b3JkQ2hhbmdlQ29uZmlnIGFzIFBhc3N3b3JkQ2hhbmdlQ29uZmlnO1xyXG5cclxuICAgIHJldC5hdXRoVGltZSA9IG5ldyBEYXRlKHJldC5hdXRoVGltZSk7XHJcbiAgICByZXQuc2VydmVyVGltZSA9IG5ldyBEYXRlKHJldC5zZXJ2ZXJUaW1lKTtcclxuICAgIHJldHVybiByZXQ7XHJcbiAgfVxyXG5cclxuICBwdWJsaWMgcGFzc3dvcmRTdHJlbmd0aChwYXNzd29yZCk6IHsgeWVhcnM6IG51bWJlcjsgYml0czogbnVtYmVyIH0ge1xyXG4gICAgY29uc3QgdXBwZXIgPSAvW0EtWl0vZztcclxuICAgIGNvbnN0IGxvd2VyID0gL1thLXpdL2c7XHJcbiAgICBjb25zdCBkaWdpdCA9IC9bMC05XS9nO1xyXG5cclxuICAgIGNvbnN0IHVwcGVyQ2hvaWNlcyA9IDI2O1xyXG4gICAgY29uc3QgbG93ZXJDaG9pY2VzID0gMjY7XHJcbiAgICBjb25zdCBkaWdpdENob2ljZXMgPSAxMDtcclxuICAgIGNvbnN0IHNwZWNpYWxDaG9pY2VzID0gMzA7IC8vIC9bIVwiIyQlJicoKSorLC0uLzo7PD0+P0BbXFxdXl9ge3x9fl0vZ1xyXG5cclxuICAgIGZ1bmN0aW9uIGluc3RhbmNlQ291bnQoc3RyLCByZSkge1xyXG4gICAgICByZXR1cm4gKChzdHIgfHwgJycpLm1hdGNoKHJlKSB8fCBbXSkubGVuZ3RoO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHVwcGVycyA9IGluc3RhbmNlQ291bnQocGFzc3dvcmQsIHVwcGVyKTtcclxuICAgIGNvbnN0IGxvd2VycyA9IGluc3RhbmNlQ291bnQocGFzc3dvcmQsIGxvd2VyKTtcclxuICAgIGNvbnN0IGRpZ2l0cyA9IGluc3RhbmNlQ291bnQocGFzc3dvcmQsIGRpZ2l0KTtcclxuICAgIGNvbnN0IHNwZWNpYWxzID0gcGFzc3dvcmQubGVuZ3RoIC0gdXBwZXJzIC0gbG93ZXJzIC0gZGlnaXRzO1xyXG5cclxuICAgIGxldCBjaG9pY2VzID0gMDtcclxuICAgIGlmICh1cHBlcnMpIHtcclxuICAgICAgY2hvaWNlcyArPSB1cHBlckNob2ljZXM7XHJcbiAgICB9XHJcbiAgICBpZiAobG93ZXJzKSB7XHJcbiAgICAgIGNob2ljZXMgKz0gbG93ZXJDaG9pY2VzO1xyXG4gICAgfVxyXG4gICAgaWYgKGRpZ2l0cykge1xyXG4gICAgICBjaG9pY2VzICs9IGRpZ2l0Q2hvaWNlcztcclxuICAgIH1cclxuICAgIGlmIChzcGVjaWFscykge1xyXG4gICAgICBjaG9pY2VzICs9IHNwZWNpYWxDaG9pY2VzO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChwYXNzd29yZC5sZW5ndGggPT09IDApIHtcclxuICAgICAgcmV0dXJuIHtcclxuICAgICAgICB5ZWFyczogMCxcclxuICAgICAgICAvLyBiaXRzIG9mIGVudHJvcHlcclxuICAgICAgICBiaXRzOiAwLFxyXG4gICAgICB9O1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHBlcm11dGF0aW9ucyA9IE1hdGgucG93KGNob2ljZXMsIHBhc3N3b3JkLmxlbmd0aCk7XHJcblxyXG4gICAgY29uc3QgeWVhcnMgPVxyXG4gICAgICAoNTQwMDAgKiBwZXJtdXRhdGlvbnMpIC9cclxuICAgICAgTWF0aC5wb3codXBwZXJDaG9pY2VzICsgbG93ZXJDaG9pY2VzICsgZGlnaXRDaG9pY2VzLCAxMik7XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICB5ZWFycyxcclxuICAgICAgLy8gYml0cyBvZiBlbnRyb3B5XHJcbiAgICAgIGJpdHM6IE1hdGgucm91bmQoTWF0aC5sb2cyKHBlcm11dGF0aW9ucykpLFxyXG4gICAgfTtcclxuICB9XHJcbn1cclxuIl19
|