@lifeready/core 0.6.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +62 -0
- package/bundles/lifeready-core.umd.js +15939 -0
- package/bundles/lifeready-core.umd.js.map +1 -0
- package/bundles/lifeready-core.umd.min.js +2 -0
- package/bundles/lifeready-core.umd.min.js.map +1 -0
- package/esm2015/lib/_common/ast.js +40 -0
- package/esm2015/lib/_common/deferred-promise.js +24 -0
- package/esm2015/lib/_common/exceptions.js +157 -0
- package/esm2015/lib/_common/queries.gql.js +190 -0
- package/esm2015/lib/_common/run-outside-angular.js +79 -0
- package/esm2015/lib/_common/types.js +1 -0
- package/esm2015/lib/_common/utils.js +44 -0
- package/esm2015/lib/api/contact-card.gql.js +79 -0
- package/esm2015/lib/api/contact-card.service.js +154 -0
- package/esm2015/lib/api/contact-card2.gql.js +60 -0
- package/esm2015/lib/api/contact-card2.service.js +103 -0
- package/esm2015/lib/api/file.service.js +74 -0
- package/esm2015/lib/api/item2.gql.js +110 -0
- package/esm2015/lib/api/item2.service.js +311 -0
- package/esm2015/lib/api/key-exchange.gql.js +188 -0
- package/esm2015/lib/api/key-exchange.service.js +442 -0
- package/esm2015/lib/api/key-exchange.types.js +18 -0
- package/esm2015/lib/api/key-exchange2.gql.js +171 -0
- package/esm2015/lib/api/key-exchange2.service.js +479 -0
- package/esm2015/lib/api/lock.gql.js +40 -0
- package/esm2015/lib/api/lock.service.js +64 -0
- package/esm2015/lib/api/lr-apollo.service.js +46 -0
- package/esm2015/lib/api/lr-graphql/index.js +6 -0
- package/esm2015/lib/api/lr-graphql/lr-graphql.service.js +155 -0
- package/esm2015/lib/api/lr-graphql/lr-merged-mutation.js +213 -0
- package/esm2015/lib/api/lr-graphql/lr-mutation-base.js +51 -0
- package/esm2015/lib/api/lr-graphql/lr-mutation.js +48 -0
- package/esm2015/lib/api/lr-graphql/lr.service.js +18 -0
- package/esm2015/lib/api/message.service.js +138 -0
- package/esm2015/lib/api/persist.service.js +181 -0
- package/esm2015/lib/api/query-processor/common-processors.service.js +93 -0
- package/esm2015/lib/api/query-processor/index.js +3 -0
- package/esm2015/lib/api/query-processor/query-processor.service.js +192 -0
- package/esm2015/lib/api/query-processor/tp-password-reset-processor.service.js +109 -0
- package/esm2015/lib/api/shared-contact-card.service.js +119 -0
- package/esm2015/lib/api/shared-contact-card2.gql.js +41 -0
- package/esm2015/lib/api/shared-contact-card2.service.js +117 -0
- package/esm2015/lib/api/time.service.js +146 -0
- package/esm2015/lib/api/types/graphql.types.js +7 -0
- package/esm2015/lib/api/types/index.js +3 -0
- package/esm2015/lib/api/types/lr-graphql.types.js +71 -0
- package/esm2015/lib/auth/auth.config.js +57 -0
- package/esm2015/lib/auth/auth.gql.js +48 -0
- package/esm2015/lib/auth/auth.types.js +27 -0
- package/esm2015/lib/auth/idle.service.js +168 -0
- package/esm2015/lib/auth/idle.types.js +7 -0
- package/esm2015/lib/auth/lbop.service.js +355 -0
- package/esm2015/lib/auth/life-ready-auth.service.js +333 -0
- package/esm2015/lib/auth/password.service.js +320 -0
- package/esm2015/lib/auth/register.service.js +172 -0
- package/esm2015/lib/auth/two-factor.service.js +74 -0
- package/esm2015/lib/category/category-meta.service.js +99 -0
- package/esm2015/lib/category/category.gql.js +406 -0
- package/esm2015/lib/category/category.service.js +390 -0
- package/esm2015/lib/category/category.types.js +29 -0
- package/esm2015/lib/cryptography/cryptography.types.js +11 -0
- package/esm2015/lib/cryptography/encryption.service.js +189 -0
- package/esm2015/lib/cryptography/key-factory.service.js +237 -0
- package/esm2015/lib/cryptography/key-graph.service.js +280 -0
- package/esm2015/lib/cryptography/key-meta.service.js +200 -0
- package/esm2015/lib/cryptography/key.service.js +124 -0
- package/esm2015/lib/cryptography/slip39.service.js +169 -0
- package/esm2015/lib/cryptography/web-crypto.service.js +29 -0
- package/esm2015/lib/life-ready.config.js +84 -0
- package/esm2015/lib/life-ready.module.js +74 -0
- package/esm2015/lib/plan/plan.gql.js +123 -0
- package/esm2015/lib/plan/plan.service.js +149 -0
- package/esm2015/lib/plan/plan.types.js +11 -0
- package/esm2015/lib/record/record-attachment.service.js +101 -0
- package/esm2015/lib/record/record.gql.js +179 -0
- package/esm2015/lib/record/record.service.js +206 -0
- package/esm2015/lib/record/record.types.js +15 -0
- package/esm2015/lib/record-type/record-type.service.js +75 -0
- package/esm2015/lib/record-type/record-type.types.js +28 -0
- package/esm2015/lib/scenario/approvals/scenario-approval.gql.js +105 -0
- package/esm2015/lib/scenario/approvals/scenario-approval.types.js +1 -0
- package/esm2015/lib/scenario/approvals/scenario-approver.service.js +300 -0
- package/esm2015/lib/scenario/claimants/scenario-claimant.gql.js +52 -0
- package/esm2015/lib/scenario/claimants/scenario-claimant.service.js +97 -0
- package/esm2015/lib/scenario/claimants/scenario-claimant.types.js +1 -0
- package/esm2015/lib/scenario/receivers/scenario-receiver.gql.js +150 -0
- package/esm2015/lib/scenario/receivers/scenario-receiver.service.js +229 -0
- package/esm2015/lib/scenario/receivers/scenario-receiver.types.js +1 -0
- package/esm2015/lib/scenario/scenario-setup.service.js +269 -0
- package/esm2015/lib/scenario/scenario.gql.js +368 -0
- package/esm2015/lib/scenario/scenario.service.js +611 -0
- package/esm2015/lib/scenario/scenario.types.js +64 -0
- package/esm2015/lib/search/search.gql.js +62 -0
- package/esm2015/lib/search/search.service.js +156 -0
- package/esm2015/lib/search/search.types.js +6 -0
- package/esm2015/lib/trusted-parties/tp-password-reset-request.service.js +112 -0
- package/esm2015/lib/trusted-parties/tp-password-reset-user.service.js +266 -0
- package/esm2015/lib/trusted-parties/tp-password-reset.gql.js +232 -0
- package/esm2015/lib/trusted-parties/tp-password-reset.service.js +300 -0
- package/esm2015/lib/trusted-parties/trusted-party.gql.js +148 -0
- package/esm2015/lib/trusted-parties/trusted-party.service.js +326 -0
- package/esm2015/lib/trusted-parties/trusted-party.types.js +41 -0
- package/esm2015/lib/trusted-parties/trusted-party2.gql.js +87 -0
- package/esm2015/lib/trusted-parties/trusted-party2.service.js +215 -0
- package/esm2015/lib/users/profile-details.service.js +214 -0
- package/esm2015/lib/users/profile.gql.js +97 -0
- package/esm2015/lib/users/profile.service.js +169 -0
- package/esm2015/lib/users/profile.types.js +34 -0
- package/esm2015/lib/users/user.gql.js +60 -0
- package/esm2015/lib/users/user.service.js +79 -0
- package/esm2015/lib/users/user.types.js +5 -0
- package/esm2015/lifeready-core.js +10 -0
- package/esm2015/public-api.js +81 -0
- package/fesm2015/lifeready-core.js +13290 -0
- package/fesm2015/lifeready-core.js.map +1 -0
- package/lib/_common/ast.d.ts +11 -0
- package/lib/_common/deferred-promise.d.ts +12 -0
- package/lib/_common/exceptions.d.ts +109 -0
- package/lib/_common/queries.gql.d.ts +10 -0
- package/lib/_common/run-outside-angular.d.ts +14 -0
- package/lib/_common/types.d.ts +10 -0
- package/lib/_common/utils.d.ts +3 -0
- package/lib/api/contact-card.gql.d.ts +7 -0
- package/lib/api/contact-card.service.d.ts +52 -0
- package/lib/api/contact-card2.gql.d.ts +34 -0
- package/lib/api/contact-card2.service.d.ts +49 -0
- package/lib/api/file.service.d.ts +18 -0
- package/lib/api/item2.gql.d.ts +96 -0
- package/lib/api/item2.service.d.ts +177 -0
- package/lib/api/key-exchange.gql.d.ts +9 -0
- package/lib/api/key-exchange.service.d.ts +39 -0
- package/lib/api/key-exchange.types.d.ts +196 -0
- package/lib/api/key-exchange2.gql.d.ts +125 -0
- package/lib/api/key-exchange2.service.d.ts +187 -0
- package/lib/api/lock.gql.d.ts +27 -0
- package/lib/api/lock.service.d.ts +25 -0
- package/lib/api/lr-apollo.service.d.ts +15 -0
- package/lib/api/lr-graphql/index.d.ts +5 -0
- package/lib/api/lr-graphql/lr-graphql.service.d.ts +60 -0
- package/lib/api/lr-graphql/lr-merged-mutation.d.ts +27 -0
- package/lib/api/lr-graphql/lr-mutation-base.d.ts +28 -0
- package/lib/api/lr-graphql/lr-mutation.d.ts +8 -0
- package/lib/api/lr-graphql/lr.service.d.ts +9 -0
- package/lib/api/message.service.d.ts +58 -0
- package/lib/api/persist.service.d.ts +31 -0
- package/lib/api/query-processor/common-processors.service.d.ts +36 -0
- package/lib/api/query-processor/index.d.ts +2 -0
- package/lib/api/query-processor/query-processor.service.d.ts +18 -0
- package/lib/api/query-processor/tp-password-reset-processor.service.d.ts +15 -0
- package/lib/api/shared-contact-card.service.d.ts +33 -0
- package/lib/api/shared-contact-card2.gql.d.ts +36 -0
- package/lib/api/shared-contact-card2.service.d.ts +45 -0
- package/lib/api/time.service.d.ts +16 -0
- package/lib/api/types/graphql.types.d.ts +29 -0
- package/lib/api/types/index.d.ts +2 -0
- package/lib/api/types/lr-graphql.types.d.ts +385 -0
- package/lib/auth/auth.config.d.ts +5 -0
- package/lib/auth/auth.gql.d.ts +15 -0
- package/lib/auth/auth.types.d.ts +66 -0
- package/lib/auth/idle.service.d.ts +40 -0
- package/lib/auth/idle.types.d.ts +10 -0
- package/lib/auth/lbop.service.d.ts +91 -0
- package/lib/auth/life-ready-auth.service.d.ts +46 -0
- package/lib/auth/password.service.d.ts +78 -0
- package/lib/auth/register.service.d.ts +25 -0
- package/lib/auth/two-factor.service.d.ts +15 -0
- package/lib/category/category-meta.service.d.ts +23 -0
- package/lib/category/category.gql.d.ts +45 -0
- package/lib/category/category.service.d.ts +67 -0
- package/lib/category/category.types.d.ts +79 -0
- package/lib/cryptography/cryptography.types.d.ts +83 -0
- package/lib/cryptography/encryption.service.d.ts +41 -0
- package/lib/cryptography/key-factory.service.d.ts +38 -0
- package/lib/cryptography/key-graph.service.d.ts +33 -0
- package/lib/cryptography/key-meta.service.d.ts +44 -0
- package/lib/cryptography/key.service.d.ts +36 -0
- package/lib/cryptography/slip39.service.d.ts +43 -0
- package/lib/cryptography/web-crypto.service.d.ts +5 -0
- package/lib/life-ready.config.d.ts +14 -0
- package/lib/life-ready.module.d.ts +5 -0
- package/lib/plan/plan.gql.d.ts +11 -0
- package/lib/plan/plan.service.d.ts +33 -0
- package/lib/plan/plan.types.d.ts +31 -0
- package/lib/record/record-attachment.service.d.ts +16 -0
- package/lib/record/record.gql.d.ts +14 -0
- package/lib/record/record.service.d.ts +25 -0
- package/lib/record/record.types.d.ts +57 -0
- package/lib/record-type/record-type.service.d.ts +11 -0
- package/lib/record-type/record-type.types.d.ts +50 -0
- package/lib/scenario/approvals/scenario-approval.gql.d.ts +7 -0
- package/lib/scenario/approvals/scenario-approval.types.d.ts +63 -0
- package/lib/scenario/approvals/scenario-approver.service.d.ts +32 -0
- package/lib/scenario/claimants/scenario-claimant.gql.d.ts +5 -0
- package/lib/scenario/claimants/scenario-claimant.service.d.ts +17 -0
- package/lib/scenario/claimants/scenario-claimant.types.d.ts +18 -0
- package/lib/scenario/receivers/scenario-receiver.gql.d.ts +8 -0
- package/lib/scenario/receivers/scenario-receiver.service.d.ts +30 -0
- package/lib/scenario/receivers/scenario-receiver.types.d.ts +54 -0
- package/lib/scenario/scenario-setup.service.d.ts +22 -0
- package/lib/scenario/scenario.gql.d.ts +34 -0
- package/lib/scenario/scenario.service.d.ts +58 -0
- package/lib/scenario/scenario.types.d.ts +217 -0
- package/lib/search/search.gql.d.ts +1 -0
- package/lib/search/search.service.d.ts +25 -0
- package/lib/search/search.types.d.ts +20 -0
- package/lib/trusted-parties/tp-password-reset-request.service.d.ts +20 -0
- package/lib/trusted-parties/tp-password-reset-user.service.d.ts +41 -0
- package/lib/trusted-parties/tp-password-reset.gql.d.ts +218 -0
- package/lib/trusted-parties/tp-password-reset.service.d.ts +131 -0
- package/lib/trusted-parties/trusted-party.gql.d.ts +9 -0
- package/lib/trusted-parties/trusted-party.service.d.ts +44 -0
- package/lib/trusted-parties/trusted-party.types.d.ts +102 -0
- package/lib/trusted-parties/trusted-party2.gql.d.ts +79 -0
- package/lib/trusted-parties/trusted-party2.service.d.ts +114 -0
- package/lib/users/profile-details.service.d.ts +21 -0
- package/lib/users/profile.gql.d.ts +11 -0
- package/lib/users/profile.service.d.ts +35 -0
- package/lib/users/profile.types.d.ts +96 -0
- package/lib/users/user.gql.d.ts +9 -0
- package/lib/users/user.service.d.ts +12 -0
- package/lib/users/user.types.d.ts +23 -0
- package/lifeready-core.d.ts +9 -0
- package/lifeready-core.metadata.json +1 -0
- package/package.json +29 -0
- package/public-api.d.ts +77 -0
|
@@ -0,0 +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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGFzc3dvcmQuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiJDOi9Qcm9qZWN0cy90ZXN0L3Byb2plY3RzL2NvcmUvc3JjLyIsInNvdXJjZXMiOlsibGliL2F1dGgvcGFzc3dvcmQuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ2xELE9BQU8sRUFBRSxNQUFNLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBRW5ELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUUzRCxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDMUQsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sb0NBQW9DLENBQUM7QUFDdkUsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLG1DQUFtQyxDQUFDO0FBQ3BFLE9BQU8sRUFBbUIsU0FBUyxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDbEUsT0FBTyxFQUFFLGVBQWUsRUFBRSxzQkFBc0IsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQ2hGLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUM3RCxPQUFPLEVBQ0wsc0JBQXNCLEVBQ3RCLDZCQUE2QixFQUM3Qix5QkFBeUIsR0FDMUIsTUFBTSxZQUFZLENBQUM7QUFFcEIsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sb0NBQW9DLENBQUM7QUFFdEUsT0FBTyxLQUFLLE9BQU8sTUFBTSxRQUFRLENBQUM7QUFFbEMsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ25ELE9BQU8sRUFBRSxpQkFBaUIsSUFBSSxHQUFHLEVBQUUsTUFBTSxxQ0FBcUMsQ0FBQzs7Ozs7Ozs7Ozs7O0FBRS9FLHFIQUFxSDtBQUNySCxNQUFNLE1BQU0sR0FBRyxPQUFPLENBQUM7QUF5QnZCLE1BQU0sT0FBTyxhQUFhO0NBSXpCO0FBS0QsTUFBTSxPQUFPLGVBQWU7SUFHMUIsWUFDNkIsTUFBdUIsRUFDMUMsSUFBZ0IsRUFDaEIsTUFBdUIsRUFDdkIsSUFBZSxFQUNmLGNBQThCLEVBQzlCLFVBQWUsRUFDZixpQkFBb0MsRUFDcEMsUUFBeUIsRUFDekIsZ0JBQWtDLEVBQ2xDLFdBQXdCO1FBVEwsV0FBTSxHQUFOLE1BQU0sQ0FBaUI7UUFDMUMsU0FBSSxHQUFKLElBQUksQ0FBWTtRQUNoQixXQUFNLEdBQU4sTUFBTSxDQUFpQjtRQUN2QixTQUFJLEdBQUosSUFBSSxDQUFXO1FBQ2YsbUJBQWMsR0FBZCxjQUFjLENBQWdCO1FBQzlCLGVBQVUsR0FBVixVQUFVLENBQUs7UUFDZixzQkFBaUIsR0FBakIsaUJBQWlCLENBQW1CO1FBQ3BDLGFBQVEsR0FBUixRQUFRLENBQWlCO1FBQ3pCLHFCQUFnQixHQUFoQixnQkFBZ0IsQ0FBa0I7UUFDbEMsZ0JBQVcsR0FBWCxXQUFXLENBQWE7UUFaakIsd0JBQW1CLEdBQUcsRUFBRSxDQUFDO0lBYXZDLENBQUM7SUFFUyxhQUFhLENBQUMsUUFBZ0I7O1lBQ3pDLE1BQU0sRUFBRSxLQUFLLEVBQUUsR0FBRyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsUUFBUSxDQUFDLENBQUM7WUFFbEQsT0FBTztnQkFDTCxNQUFNLEVBQUUsUUFBUSxDQUFDLE1BQU07Z0JBQ3ZCLFdBQVcsRUFBRSxNQUFNLENBQUMsUUFBUSxDQUFDLEVBQUUsS0FBSyxFQUFFLENBQUM7Z0JBQ3ZDLGVBQWUsRUFBRSxNQUFNLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxRQUFRLENBQUM7YUFDdkQsQ0FBQztRQUNKLENBQUM7S0FBQTtJQUVZLGdCQUFnQixDQUFDLFFBQWdCOztZQUM1QyxNQUFNLFlBQVksR0FBRyxNQUFNLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxZQUFZLENBQzNELE9BQU8sRUFDUCxRQUFRLENBQ1QsQ0FBQztZQUNGLE1BQU0sVUFBVSxHQUFHLFlBQVksQ0FBQyxTQUFTLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO1lBRWhELE1BQU0sUUFBUSxHQUFHLE1BQU0sSUFBSSxDQUFDLElBQUk7aUJBQzdCLEdBQUcsQ0FBQyx3Q0FBd0MsVUFBVSxFQUFFLEVBQUU7Z0JBQ3pELFlBQVksRUFBRSxNQUFNO2FBQ3JCLENBQUM7aUJBQ0QsU0FBUyxFQUFFLENBQUM7WUFFZixNQUFNLE9BQU8sR0FBRyxJQUFJLE1BQU0sQ0FDeEIsT0FBTyxZQUFZLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxtQkFBbUIsRUFDbkQsSUFBSSxDQUNMLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1lBRWpCLElBQUksT0FBTyxFQUFFO2dCQUNYLE9BQU8sQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQzthQUM5QjtZQUNELE9BQU8sQ0FBQyxDQUFDO1FBQ1gsQ0FBQztLQUFBO0lBRU0sZ0JBQWdCLENBQUMsT0FBZ0I7UUFDdEMsT0FBUSxPQUFPLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBUyxDQUFDLENBQUMsQ0FBQztJQUN6QyxDQUFDO0lBRVksbUJBQW1CLENBQUMsUUFBZ0I7O1lBQy9DLE1BQU0sYUFBYSxHQUFHLE1BQU0sSUFBSSxDQUFDLFVBQVUsQ0FBQyxtQkFBbUIsRUFBRSxDQUFDO1lBQ2xFLE1BQU0sT0FBTyxHQUFHLENBQ2QsTUFBTSxJQUFJLENBQUMsVUFBVSxDQUFDLGFBQWEsaUJBQ2pDLFFBQVEsSUFDTCxhQUFhLEVBQ2hCLENBQ0gsQ0FBQyxHQUFHLENBQUM7WUFFTixNQUFNLGFBQWEsR0FBRyxNQUFNLElBQUksQ0FBQyxVQUFVLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztZQUNsRSxNQUFNLE9BQU8sR0FBRyxDQUNkLE1BQU0sSUFBSSxDQUFDLFVBQVUsQ0FBQyxhQUFhLGlCQUNqQyxRQUFRLElBQ0wsYUFBYSxFQUNoQixDQUNILENBQUMsR0FBRyxDQUFDO1lBRU4sTUFBTSxlQUFlLEdBQUcsTUFBTSxJQUFJLENBQUMsVUFBVSxDQUFDLGdCQUFnQixFQUFFLENBQUM7WUFFakUsTUFBTSx5QkFBeUIsR0FBRyxNQUFNLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxPQUFPLENBQ3BFLE9BQU8sRUFDUCxlQUFlLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUM3QixDQUFDO1lBRUYsd0VBQXdFO1lBQ3hFLDZDQUE2QztZQUM3QyxzQ0FBc0M7WUFDdEMsZ0dBQWdHO1lBRWhHLE9BQU87Z0JBQ0wsYUFBYTtnQkFDYixPQUFPO2dCQUNQLGFBQWE7Z0JBQ2IsT0FBTztnQkFDUCxlQUFlO2dCQUNmLHlCQUF5QjthQUMxQixDQUFDO1FBQ0osQ0FBQztLQUFBO0lBRUQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7T0F5Qkc7SUFFVSxlQUFlOztZQUMxQixNQUFNLG9CQUFvQixHQUFHLE1BQU0sSUFBSSxDQUFDLHVCQUF1QixFQUFFLENBQUM7WUFDbEUsTUFBTSxRQUFRLEdBQUcsTUFBTSxDQUFDLG9CQUFvQixDQUFDLFFBQVEsQ0FBQyxDQUFDO1lBQ3ZELE1BQU0sVUFBVSxHQUFHLE1BQU0sQ0FBQyxvQkFBb0IsQ0FBQyxVQUFVLENBQUMsQ0FBQztZQUMzRCxNQUFNLFFBQVEsR0FBRyxNQUFNLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQztZQUM1RCxNQUFNLE9BQU8sR0FBRyxRQUFRLENBQUMsU0FBUyxFQUFFLENBQUM7WUFDckMsSUFBSSxPQUFPLEdBQUcsb0JBQW9CLENBQUMsaUJBQWlCLEVBQUU7Z0JBQ3BELE9BQU8sSUFBSSxDQUFDO2FBQ2I7aUJBQU07Z0JBQ0wsT0FBTyxLQUFLLENBQUM7YUFDZDtRQUNILENBQUM7S0FBQTtJQUVZLGNBQWMsQ0FBQyxRQUFnQixFQUFFLFdBQW1COztZQUMvRCxNQUFNLFdBQVcsR0FBZ0IsTUFBTSxJQUFJLENBQUMsSUFBSSxDQUFDLHdCQUF3QixFQUFFLENBQUM7WUFFNUUsYUFBYTtZQUNiLHlCQUF5QjtZQUN6Qix1R0FBdUc7WUFDdkcsSUFBSSxRQUFRLEtBQUssV0FBVyxFQUFFO2dCQUM1QixNQUFNLElBQUksc0JBQXNCLENBQzlCLDhDQUE4QyxDQUMvQyxDQUFDO2FBQ0g7WUFFRCxNQUFNLEVBQUUsV0FBVyxFQUFFLEdBQUcsTUFBTSxJQUFJLENBQUMsY0FBYyxDQUFDLGNBQWMsRUFBRSxDQUFDO1lBRW5FLE1BQU0sRUFBRSxPQUFPLEVBQUUsZUFBZSxFQUFFLEdBQUcsTUFBTSxJQUFJLENBQUMsY0FBYyxDQUM1RCxRQUFRLEVBQ1IsV0FBVyxDQUNaLENBQUM7WUFFRixnQ0FBZ0M7WUFDaEMscUZBQXFGO1lBQ3JGLHlEQUF5RDtZQUV6RCwyQkFBMkI7WUFDM0IsTUFBTSxVQUFVLEdBQUcsTUFBTSxJQUFJLENBQUMsbUJBQW1CLENBQUMsV0FBVyxDQUFDLENBQUM7WUFFL0QscUNBQXFDO1lBQ3JDLE1BQU0sU0FBUyxHQUFHLE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQzFDLFdBQVcsQ0FBQyxjQUFjLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FDeEMsQ0FBQztZQUNGLE1BQU0sbUJBQW1CLEdBQUcsTUFBTSxJQUFJLENBQUMsaUJBQWlCLENBQUMsT0FBTyxDQUM5RCxVQUFVLENBQUMsT0FBTyxFQUNsQixTQUFTLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FDM0IsQ0FBQztZQUVGLGlGQUFpRjtZQUNqRixpRkFBaUY7WUFDakYsc0ZBQXNGO1lBQ3RGLHdDQUF3QztZQUV4QyxNQUFNLEVBQUUsS0FBSyxFQUFFLFlBQVksRUFBRSxHQUFHLE1BQU0sSUFBSSxDQUFDLHNCQUFzQixDQUMvRCxlQUFlLEVBQ2YsV0FBVyxDQUFDLGNBQWMsQ0FBQyxTQUFTLENBQUMsRUFBRSxFQUN2QyxtQkFBbUIsRUFDbkIsVUFBVSxDQUNYLENBQUM7WUFFRixnQ0FBZ0M7WUFDaEMsOEZBQThGO1lBQzlGLCtDQUErQztZQUUvQyx5Q0FBeUM7WUFDekMseUJBQXlCO1lBQ3pCLE1BQU0sSUFBSSxDQUFDLElBQUksQ0FBQyxjQUFjLENBQzVCLFdBQVcsRUFDWCxJQUFJLENBQUMsZ0JBQWdCLENBQUMsT0FBTyxDQUFDLEVBQzlCLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDLENBQzFDLENBQUM7WUFFRixnQ0FBZ0M7WUFDaEMsc0JBQXNCO1lBRXRCLDZGQUE2RjtZQUM3RiwyRkFBMkY7WUFDM0YsNEZBQTRGO1lBQzVGLGtFQUFrRTtZQUNsRSxNQUFNLElBQUksQ0FBQyxzQkFBc0IsQ0FDL0IsV0FBVyxDQUFDLG9CQUFvQixFQUFFLENBQUMsY0FBYyxFQUFFLENBQUMsV0FBVyxFQUFFLEVBQ2pFLElBQUksRUFDSixLQUFLLENBQ04sQ0FBQztRQUNKLENBQUM7S0FBQTtJQUVZLHNCQUFzQixDQUNqQyxXQUFtQixFQUNuQixjQUF1QixFQUN2QixRQUFnQixJQUFJOztZQUVwQixPQUFPLElBQUksQ0FBQyxJQUFJO2lCQUNiLElBQUksQ0FDSCxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTyxpQ0FBaUMsa0JBRXJELGdCQUFnQixFQUFFLGNBQWMsSUFDN0IsQ0FBQyxLQUFLLElBQUksRUFBRSxLQUFLLEVBQUUsQ0FBQyxHQUV6QjtnQkFDRSxPQUFPLEVBQUU7b0JBQ1AsYUFBYSxFQUFFLFVBQVUsV0FBVyxFQUFFO2lCQUN2QzthQUNGLENBQ0Y7aUJBQ0EsU0FBUyxFQUFFLENBQUM7UUFDakIsQ0FBQztLQUFBO0lBRWEsY0FBYyxDQUMxQixPQUFnQixFQUNoQixVQUFrQjs7WUFFbEIsSUFBSTtnQkFDRixNQUFNLE9BQU8sR0FBRyxNQUFNLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxPQUFPLENBQUMsT0FBTyxFQUFFLFVBQVUsQ0FBQyxDQUFDO2dCQUMxRSxPQUFPLEdBQUcsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7YUFDM0I7WUFBQyxPQUFPLEtBQUssRUFBRTtnQkFDZCxNQUFNLElBQUksZUFBZSxDQUFDLHdCQUF3QixDQUFDLENBQUM7YUFDckQ7UUFDSCxDQUFDO0tBQUE7SUFFYSxjQUFjLENBQzFCLFFBQWdCLEVBQ2hCLFdBQTJCOztZQUUzQixrRUFBa0U7WUFDbEUsTUFBTSxlQUFlLEdBQUcsTUFBTSxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FDOUM7Z0JBQ0UsUUFBUSxFQUFFLDZCQUE2QjtnQkFDdkMsU0FBUyxFQUFFLEVBQUU7YUFDZCxDQUNGLENBQUM7WUFFRixrRUFBa0U7WUFDbEUsTUFBTSxhQUFhLEdBQUcsTUFBTSxJQUFJLENBQUMsVUFBVSxDQUFDLGFBQWEsaUJBQ3ZELFFBQVEsSUFDTCxXQUFXLENBQUMsY0FBYyxDQUFDLE9BQU8sQ0FBQyxhQUFhLEVBQ25ELENBQUM7WUFFSCxNQUFNLFdBQVcsR0FBRyxNQUFNLElBQUksQ0FBQyxjQUFjLENBQzNDLGFBQWEsQ0FBQyxHQUFHLEVBQ2pCLFdBQVcsQ0FBQyxjQUFjLENBQUMsT0FBTyxDQUFDLHlCQUF5QixDQUM3RCxDQUFDO1lBRUYseUZBQXlGO1lBQ3pGLFdBQVc7WUFDWCxNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsbUJBQW1CLENBQUMsQ0FBQztZQUUzRSxNQUFNLGVBQWUsR0FBRyxNQUFNLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFO2dCQUNyRSxXQUFXLEVBQUUsZUFBZSxDQUFDLHFCQUFxQixDQUFDLFNBQVMsQ0FBQyxXQUFXO2dCQUN4RSxXQUFXO2FBQ1osQ0FBQyxDQUFDO1lBRUgsTUFBTSxhQUFhLEdBQUcsTUFBTSxJQUFJLENBQUMsVUFBVSxDQUFDLGFBQWEsaUJBQ3ZELFFBQVEsSUFDTCxXQUFXLENBQUMsY0FBYyxDQUFDLE9BQU8sQ0FBQyxhQUFhLEVBQ25ELENBQUM7WUFFSCxPQUFPO2dCQUNMLE9BQU8sRUFBRSxhQUFhLENBQUMsR0FBRztnQkFDMUIsZUFBZTthQUNoQixDQUFDO1FBQ0osQ0FBQztLQUFBO0lBRWEsc0JBQXNCLENBQ2xDLGVBQXFDLEVBQ3JDLFdBQW1CLEVBQ25CLG1CQUEyQixFQUMzQixhQUE0Qjs7WUFFNUIsTUFBTSxRQUFRLEdBQUcsTUFBTSxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBeUI7Z0JBQ2hFLFFBQVEsRUFBRSxzQkFBc0I7Z0JBQ2hDLFNBQVMsRUFBRTtvQkFDVCxLQUFLLEVBQUU7d0JBQ0wsZUFBZSxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsZUFBZSxDQUFDO3dCQUNoRCxXQUFXO3dCQUNYLG1CQUFtQixFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsbUJBQW1CLENBQUM7d0JBQ3hELFVBQVUsRUFBRTs0QkFDVixhQUFhLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxhQUFhLENBQUMsYUFBYSxDQUFDOzRCQUMxRCxrQkFBa0IsRUFBRSxJQUFJLENBQUMsU0FBUyxDQUNoQyxhQUFhLENBQUMsZUFBZSxDQUFDLE1BQU0sRUFBRSxDQUN2Qzs0QkFDRCx5QkFBeUIsRUFBRSxJQUFJLENBQUMsU0FBUyxDQUN2QyxhQUFhLENBQUMseUJBQXlCLENBQ3hDOzRCQUNELGFBQWEsRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLGFBQWEsQ0FBQyxhQUFhLENBQUM7eUJBQzNEO3FCQUNGO2lCQUNGO2FBQ0YsQ0FBQyxDQUFDO1lBQ0gsT0FBTztnQkFDTCxLQUFLLEVBQUUsUUFBUSxDQUFDLGNBQWMsQ0FBQyxLQUFLO2dCQUNwQyxZQUFZLEVBQUUsUUFBUSxDQUFDLGNBQWMsQ0FBQyxVQUFVLENBQUMsRUFBRTthQUNwRCxDQUFDO1FBQ0osQ0FBQztLQUFBO0lBRUssdUJBQXVCOztZQUMzQixNQUFNLEdBQUcsR0FBRyxNQUFNLElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFNO2dCQUN2QyxLQUFLLEVBQUUseUJBQXlCO2FBQ2pDLENBQUMsQ0FBQztZQUVILE1BQU0sR0FBRyxHQUFHLEdBQUcsQ0FBQyxvQkFBNEMsQ0FBQztZQUU3RCxHQUFHLENBQUMsUUFBUSxHQUFHLElBQUksSUFBSSxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsQ0FBQztZQUN0QyxHQUFHLENBQUMsVUFBVSxHQUFHLElBQUksSUFBSSxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsQ0FBQztZQUMxQyxPQUFPLEdBQUcsQ0FBQztRQUNiLENBQUM7S0FBQTtJQUVNLGdCQUFnQixDQUFDLFFBQVE7UUFDOUIsTUFBTSxLQUFLLEdBQUcsUUFBUSxDQUFDO1FBQ3ZCLE1BQU0sS0FBSyxHQUFHLFFBQVEsQ0FBQztRQUN2QixNQUFNLEtBQUssR0FBRyxRQUFRLENBQUM7UUFFdkIsTUFBTSxZQUFZLEdBQUcsRUFBRSxDQUFDO1FBQ3hCLE1BQU0sWUFBWSxHQUFHLEVBQUUsQ0FBQztRQUN4QixNQUFNLFlBQVksR0FBRyxFQUFFLENBQUM7UUFDeEIsTUFBTSxjQUFjLEdBQUcsRUFBRSxDQUFDLENBQUMsd0NBQXdDO1FBRW5FLFNBQVMsYUFBYSxDQUFDLEdBQUcsRUFBRSxFQUFFO1lBQzVCLE9BQU8sQ0FBQyxDQUFDLEdBQUcsSUFBSSxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsTUFBTSxDQUFDO1FBQzlDLENBQUM7UUFFRCxNQUFNLE1BQU0sR0FBRyxhQUFhLENBQUMsUUFBUSxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBQzlDLE1BQU0sTUFBTSxHQUFHLGFBQWEsQ0FBQyxRQUFRLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDOUMsTUFBTSxNQUFNLEdBQUcsYUFBYSxDQUFDLFFBQVEsRUFBRSxLQUFLLENBQUMsQ0FBQztRQUM5QyxNQUFNLFFBQVEsR0FBRyxRQUFRLENBQUMsTUFBTSxHQUFHLE1BQU0sR0FBRyxNQUFNLEdBQUcsTUFBTSxDQUFDO1FBRTVELElBQUksT0FBTyxHQUFHLENBQUMsQ0FBQztRQUNoQixJQUFJLE1BQU0sRUFBRTtZQUNWLE9BQU8sSUFBSSxZQUFZLENBQUM7U0FDekI7UUFDRCxJQUFJLE1BQU0sRUFBRTtZQUNWLE9BQU8sSUFBSSxZQUFZLENBQUM7U0FDekI7UUFDRCxJQUFJLE1BQU0sRUFBRTtZQUNWLE9BQU8sSUFBSSxZQUFZLENBQUM7U0FDekI7UUFDRCxJQUFJLFFBQVEsRUFBRTtZQUNaLE9BQU8sSUFBSSxjQUFjLENBQUM7U0FDM0I7UUFFRCxJQUFJLFFBQVEsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFO1lBQ3pCLE9BQU87Z0JBQ0wsS0FBSyxFQUFFLENBQUM7Z0JBQ1Isa0JBQWtCO2dCQUNsQixJQUFJLEVBQUUsQ0FBQzthQUNSLENBQUM7U0FDSDtRQUVELE1BQU0sWUFBWSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLFFBQVEsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUV4RCxNQUFNLEtBQUssR0FDVCxDQUFDLEtBQUssR0FBRyxZQUFZLENBQUM7WUFDdEIsSUFBSSxDQUFDLEdBQUcsQ0FBQyxZQUFZLEdBQUcsWUFBWSxHQUFHLFlBQVksRUFBRSxFQUFFLENBQUMsQ0FBQztRQUMzRCxPQUFPO1lBQ0wsS0FBSztZQUNMLGtCQUFrQjtZQUNsQixJQUFJLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxDQUFDO1NBQzFDLENBQUM7SUFDSixDQUFDOzs7O1lBNVhGLFVBQVUsU0FBQztnQkFDVixVQUFVLEVBQUUsTUFBTTthQUNuQjs7OzRDQUtJLE1BQU0sU0FBQyxTQUFTO1lBL0RaLFVBQVU7WUFVVixlQUFlO1lBUGYsU0FBUztZQUVULGNBQWM7WUFpQk8sR0FBRztZQWhCeEIsaUJBQWlCO1lBQ2pCLGVBQWU7WUFVZixnQkFBZ0I7WUFJaEIsV0FBVyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEh0dHBDbGllbnQgfSBmcm9tICdAYW5ndWxhci9jb21tb24vaHR0cCc7XHJcbmltcG9ydCB7IEluamVjdCwgSW5qZWN0YWJsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyBDb2duaXRvVXNlciB9IGZyb20gJ0Bhd3MtYW1wbGlmeS9hdXRoJztcclxuaW1wb3J0IHsgQXV0aENsYXNzIH0gZnJvbSAnQGF3cy1hbXBsaWZ5L2F1dGgvbGliLWVzbS9BdXRoJztcclxuaW1wb3J0IHsgSldLLCBKV1MgfSBmcm9tICdub2RlLWpvc2UnO1xyXG5pbXBvcnQgeyBQcm9maWxlU2VydmljZSB9IGZyb20gJy4uL3VzZXJzL3Byb2ZpbGUuc2VydmljZSc7XHJcbmltcG9ydCB7IEVuY3J5cHRpb25TZXJ2aWNlIH0gZnJvbSAnLi4vY3J5cHRvZ3JhcGh5L2VuY3J5cHRpb24uc2VydmljZSc7XHJcbmltcG9ydCB7IEtleUdyYXBoU2VydmljZSB9IGZyb20gJy4uL2NyeXB0b2dyYXBoeS9rZXktZ3JhcGguc2VydmljZSc7XHJcbmltcG9ydCB7IExpZmVSZWFkeUNvbmZpZywgTFJfQ09ORklHIH0gZnJvbSAnLi4vbGlmZS1yZWFkeS5jb25maWcnO1xyXG5pbXBvcnQgeyBMckF1dGhFeGNlcHRpb24sIExyQmFkQXJndW1lbnRFeGNlcHRpb24gfSBmcm9tICcuLi9fY29tbW9uL2V4Y2VwdGlvbnMnO1xyXG5pbXBvcnQgeyBMckFwb2xsb1NlcnZpY2UgfSBmcm9tICcuLy4uL2FwaS9sci1hcG9sbG8uc2VydmljZSc7XHJcbmltcG9ydCB7XHJcbiAgUGFzc3dvcmRDaGFuZ2VNdXRhdGlvbixcclxuICBQYXNzd29yZENoYW5nZVJlcXVlc3RNdXRhdGlvbixcclxuICBQYXNzd29yZENoYW5nZUNvbmZpZ1F1ZXJ5LFxyXG59IGZyb20gJy4vYXV0aC5ncWwnO1xyXG5pbXBvcnQgeyBQYXNzS2V5QnVuZGxlIH0gZnJvbSAnLi9hdXRoLnR5cGVzJztcclxuaW1wb3J0IHsgV2ViQ3J5cHRvU2VydmljZSB9IGZyb20gJy4uL2NyeXB0b2dyYXBoeS93ZWItY3J5cHRvLnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBEdXJhdGlvbiB9IGZyb20gJ21vbWVudCc7XHJcbmltcG9ydCAqIGFzIG1vbWVudF8gZnJvbSAnbW9tZW50JztcclxuaW1wb3J0IHsgQXBpQ3VycmVudFVzZXIgfSBmcm9tICcuLi91c2Vycy9wcm9maWxlLnR5cGVzJztcclxuaW1wb3J0IHsgSWRsZVNlcnZpY2UgfSBmcm9tICcuLi9hdXRoL2lkbGUuc2VydmljZSc7XHJcbmltcG9ydCB7IEtleUZhY3RvcnlTZXJ2aWNlIGFzIEtGUyB9IGZyb20gJy4uL2NyeXB0b2dyYXBoeS9rZXktZmFjdG9yeS5zZXJ2aWNlJztcclxuXHJcbi8vIFwid2h5P1wiIHlvdSBhc2s6IGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzU5NzM1MjgwL2FuZ3VsYXItOC1tb21lbnQtZXJyb3ItY2Fubm90LWNhbGwtYS1uYW1lc3BhY2UtbW9tZW50XHJcbmNvbnN0IG1vbWVudCA9IG1vbWVudF87XHJcblxyXG5pbnRlcmZhY2UgUGFzc3dvcmRDaGFuZ2VSZXF1ZXN0TXV0YXRpb24ge1xyXG4gIHBhc3N3b3JkQ2hhbmdlUmVxdWVzdDoge1xyXG4gICAgY2hhbGxlbmdlOiB7XHJcbiAgICAgIHNlcnZlck5vbmNlOiBzdHJpbmc7XHJcbiAgICB9O1xyXG4gIH07XHJcbn1cclxuXHJcbmludGVyZmFjZSBQYXNzd29yZENoYW5nZU11dGF0aW9uIHtcclxuICBwYXNzd29yZENoYW5nZToge1xyXG4gICAgdG9rZW46IHN0cmluZztcclxuICAgIG5ld1Bhc3NLZXk6IHtcclxuICAgICAgaWQ6IHN0cmluZztcclxuICAgIH07XHJcbiAgfTtcclxufVxyXG5cclxuZXhwb3J0IGludGVyZmFjZSBQYXNzd29yZENoYW5nZUNvbmZpZyB7XHJcbiAgbWF4QXV0aEFnZVNlY29uZHM6IG51bWJlcjtcclxuICBhdXRoVGltZTogc3RyaW5nIHwgRGF0ZTtcclxuICBzZXJ2ZXJUaW1lOiBzdHJpbmcgfCBEYXRlO1xyXG59XHJcblxyXG5leHBvcnQgY2xhc3MgUGFzc3dvcmRDaGVjayB7XHJcbiAgbGVuZ3RoPzogbnVtYmVyO1xyXG4gIHRpbWVUb0NyYWNrPzogRHVyYXRpb247XHJcbiAgcGFzc3dvcmRFeHBvc2VkPzogbnVtYmVyO1xyXG59XHJcblxyXG5ASW5qZWN0YWJsZSh7XHJcbiAgcHJvdmlkZWRJbjogJ3Jvb3QnLFxyXG59KVxyXG5leHBvcnQgY2xhc3MgUGFzc3dvcmRTZXJ2aWNlIHtcclxuICBwcml2YXRlIHJlYWRvbmx5IENMSUVOVF9OT05DRV9MRU5HVEggPSAzMjtcclxuXHJcbiAgY29uc3RydWN0b3IoXHJcbiAgICBASW5qZWN0KExSX0NPTkZJRykgcHJpdmF0ZSBjb25maWc6IExpZmVSZWFkeUNvbmZpZyxcclxuICAgIHByaXZhdGUgaHR0cDogSHR0cENsaWVudCxcclxuICAgIHByaXZhdGUgYXBvbGxvOiBMckFwb2xsb1NlcnZpY2UsXHJcbiAgICBwcml2YXRlIGF1dGg6IEF1dGhDbGFzcyxcclxuICAgIHByaXZhdGUgcHJvZmlsZVNlcnZpY2U6IFByb2ZpbGVTZXJ2aWNlLFxyXG4gICAgcHJpdmF0ZSBrZXlGYWN0b3J5OiBLRlMsXHJcbiAgICBwcml2YXRlIGVuY3J5cHRpb25TZXJ2aWNlOiBFbmNyeXB0aW9uU2VydmljZSxcclxuICAgIHByaXZhdGUga2V5R3JhcGg6IEtleUdyYXBoU2VydmljZSxcclxuICAgIHByaXZhdGUgd2ViQ3J5cHRvU2VydmljZTogV2ViQ3J5cHRvU2VydmljZSxcclxuICAgIHByaXZhdGUgaWRsZVNlcnZpY2U6IElkbGVTZXJ2aWNlXHJcbiAgKSB7fVxyXG5cclxuICBwdWJsaWMgYXN5bmMgY2hlY2tQYXNzd29yZChwYXNzd29yZDogc3RyaW5nKTogUHJvbWlzZTxQYXNzd29yZENoZWNrPiB7XHJcbiAgICBjb25zdCB7IHllYXJzIH0gPSB0aGlzLnBhc3N3b3JkU3RyZW5ndGgocGFzc3dvcmQpO1xyXG5cclxuICAgIHJldHVybiB7XHJcbiAgICAgIGxlbmd0aDogcGFzc3dvcmQubGVuZ3RoLFxyXG4gICAgICB0aW1lVG9DcmFjazogbW9tZW50LmR1cmF0aW9uKHsgeWVhcnMgfSksXHJcbiAgICAgIHBhc3N3b3JkRXhwb3NlZDogYXdhaXQgdGhpcy5nZXRFeHBvc3VyZUNvdW50KHBhc3N3b3JkKSxcclxuICAgIH07XHJcbiAgfVxyXG5cclxuICBwdWJsaWMgYXN5bmMgZ2V0RXhwb3N1cmVDb3VudChwYXNzd29yZDogc3RyaW5nKTogUHJvbWlzZTxudW1iZXI+IHtcclxuICAgIGNvbnN0IHNoYTFQYXNzd29yZCA9IGF3YWl0IHRoaXMud2ViQ3J5cHRvU2VydmljZS5zdHJpbmdEaWdlc3QoXHJcbiAgICAgICdTSEEtMScsXHJcbiAgICAgIHBhc3N3b3JkXHJcbiAgICApO1xyXG4gICAgY29uc3QgZmlyc3Q1c2hhMSA9IHNoYTFQYXNzd29yZC5zdWJzdHJpbmcoMCwgNSk7XHJcblxyXG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCB0aGlzLmh0dHBcclxuICAgICAgLmdldChgaHR0cHM6Ly9hcGkucHduZWRwYXNzd29yZHMuY29tL3JhbmdlLyR7Zmlyc3Q1c2hhMX1gLCB7XHJcbiAgICAgICAgcmVzcG9uc2VUeXBlOiAndGV4dCcsXHJcbiAgICAgIH0pXHJcbiAgICAgIC50b1Byb21pc2UoKTtcclxuXHJcbiAgICBjb25zdCByZXN1bHRzID0gbmV3IFJlZ0V4cChcclxuICAgICAgYF4oPzoke3NoYTFQYXNzd29yZC5zdWJzdHJpbmcoNSl9OikoPzxjb3VudD5cXFxcZCspJGAsXHJcbiAgICAgICdpbSdcclxuICAgICkuZXhlYyhyZXNwb25zZSk7XHJcblxyXG4gICAgaWYgKHJlc3VsdHMpIHtcclxuICAgICAgcmV0dXJuICtyZXN1bHRzLmdyb3Vwcy5jb3VudDtcclxuICAgIH1cclxuICAgIHJldHVybiAwO1xyXG4gIH1cclxuXHJcbiAgcHVibGljIGdldFBhc3NJZHBTdHJpbmcocGFzc0lkcDogSldLLktleSkge1xyXG4gICAgcmV0dXJuIChwYXNzSWRwLnRvSlNPTih0cnVlKSBhcyBhbnkpLms7XHJcbiAgfVxyXG5cclxuICBwdWJsaWMgYXN5bmMgY3JlYXRlUGFzc0tleUJ1bmRsZShwYXNzd29yZDogc3RyaW5nKTogUHJvbWlzZTxQYXNzS2V5QnVuZGxlPiB7XHJcbiAgICBjb25zdCBwYXNzSWRwUGFyYW1zID0gYXdhaXQgdGhpcy5rZXlGYWN0b3J5LmNyZWF0ZVBhc3NJZHBQYXJhbXMoKTtcclxuICAgIGNvbnN0IHBhc3NJZHAgPSAoXHJcbiAgICAgIGF3YWl0IHRoaXMua2V5RmFjdG9yeS5kZXJpdmVQYXNzSWRwKHtcclxuICAgICAgICBwYXNzd29yZCxcclxuICAgICAgICAuLi5wYXNzSWRwUGFyYW1zLFxyXG4gICAgICB9KVxyXG4gICAgKS5qd2s7XHJcblxyXG4gICAgY29uc3QgcGFzc0tleVBhcmFtcyA9IGF3YWl0IHRoaXMua2V5RmFjdG9yeS5jcmVhdGVQYXNzS2V5UGFyYW1zKCk7XHJcbiAgICBjb25zdCBwYXNzS2V5ID0gKFxyXG4gICAgICBhd2FpdCB0aGlzLmtleUZhY3RvcnkuZGVyaXZlUGFzc0tleSh7XHJcbiAgICAgICAgcGFzc3dvcmQsXHJcbiAgICAgICAgLi4ucGFzc0tleVBhcmFtcyxcclxuICAgICAgfSlcclxuICAgICkuandrO1xyXG5cclxuICAgIGNvbnN0IHBhc3NJZHBWZXJpZmllciA9IGF3YWl0IHRoaXMua2V5RmFjdG9yeS5jcmVhdGVQa2NTaWduS2V5KCk7XHJcblxyXG4gICAgY29uc3Qgd3JhcHBlZFBhc3NJZHBWZXJpZmllclByayA9IGF3YWl0IHRoaXMuZW5jcnlwdGlvblNlcnZpY2UuZW5jcnlwdChcclxuICAgICAgcGFzc0tleSxcclxuICAgICAgcGFzc0lkcFZlcmlmaWVyLnRvSlNPTih0cnVlKVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBUaGVyZSBhcmUgdHdvIGZvcm1hdHMgdGhhdCB0aGUgcHJpdmF0ZSBrZXkgY2FuIGJlIHJlcHJlc2VudGVkIGluIEpXSzpcclxuICAgIC8vIGh0dHBzOi8vdG9vbHMuaWV0Zi5vcmcvaHRtbC9yZmM4MDE3I3BhZ2UtOVxyXG4gICAgLy8gVGhlIHNlY29uZCBmb3JtIGlzIGFuIG9wdGltaXphdGlvbjpcclxuICAgIC8vIGh0dHBzOi8vY3J5cHRvLnN0YWNrZXhjaGFuZ2UuY29tL3F1ZXN0aW9ucy8xOTQxMy93aGF0LWFyZS1kcC1hbmQtZHEtaW4tZW5jcnlwdGlvbi1ieS1yc2EtaW4tY1xyXG5cclxuICAgIHJldHVybiB7XHJcbiAgICAgIHBhc3NLZXlQYXJhbXMsXHJcbiAgICAgIHBhc3NLZXksXHJcbiAgICAgIHBhc3NJZHBQYXJhbXMsXHJcbiAgICAgIHBhc3NJZHAsXHJcbiAgICAgIHBhc3NJZHBWZXJpZmllcixcclxuICAgICAgd3JhcHBlZFBhc3NJZHBWZXJpZmllclByayxcclxuICAgIH07XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBXZSBuZWVkIHRvIGFsbG93IGZvciBpbnRlcnJ1cHRpb24gb2YgdGhlIHByb2Nlc3MgYXQgYW55IHBvaW50LiBFYWNoIEFQSSBjYWxsIGNhbiBiZSBjb25zaWRlcmVkXHJcbiAgICogYXRvbWljIGFuZCBlaXRoZXIgc3VjY2VlZHMgb3IgZmFpbHMuXHJcbiAgICpcclxuICAgKiBUaGUgTFIgc2VydmVyIEFQSXMgdXNlIHNlbWFwaG9yZSB0b2tlbnMgZm9yIGxvY2tpbmcgY3JpdGljYWwgb3BlcmF0aW9ucywgc28gY29uY3VycmVudCBjYWxscyB3aWxsXHJcbiAgICogZmFpbC5cclxuICAgKlxyXG4gICAqIFdlIGFzc3VtZSB0aGUgd29yc3QgY2FzZSBmb3IgSWRQIEFQSSBjYWxscy4gU28gd2UgdXNlIHRoZSBzZW1hcGhvcmUgdG9rZW4gZnJvbSBMUiB0byBwcmV2ZW50XHJcbiAgICogY29uY3VycmVudCBjYWxscyB0byBJZFAgQVBJcywgYnV0IHdlIGhhdmUgdG8gYXNzdW1lIHRoYXQgdGhlIElkUCBBUEkgY2FsbHMgd2lsbCBlaXRoZXIgc3VjY2VlZCBvclxyXG4gICAqIGZhaWwgd2l0aGluIGEgcmVhc29uYWJsZSBhbW91bnQgb2YgdGltZS5cclxuICAgKlxyXG4gICAqIEVhY2ggbG9jYXRpb24gd2hlcmUgdGhlIHNlcnZlciBzdGF0ZSBjaGFuZ2VzIGNhbiBiZSBhIHBvdGVudGlhbCBwb2ludCBvZiBpbnRlcnJ1cHRpb24uXHJcbiAgICogUG90ZW50aWFsIHBvaW50cyBvZiBpbnRlcnJ1cHRpb24gYXJlIG1hcmtlZCB3aXRoOiAtLVBvdGVudGlhbCBGYWlsdXJlIFBvaW50LS1cclxuICAgKlxyXG4gICAqIFBsYWNlcyBmb3IgdGltZW91dDpcclxuICAgKiAtIExvZ2luIGFnZSB0b28gb2xkIGF0IGNhbGwgdG86IHZlcmlmeVBhc3N3b3JkKClcclxuICAgKiAtIExvZ2luIGFnZSB0b28gb2xkIGF0IGNhbGwgdG86IGNoYW5nZVBhc3N3b3JkTXV0YXRpb24oKVxyXG4gICAqIC0gU2VtYXBob3JlIHRva2VuIGV4cGlyZXMgYXQgY2FsbCB0bzogY2hhbmdlUGFzc3dvcmRDb21wbGV0ZSgpXHJcbiAgICpcclxuICAgKiBUZXN0czpcclxuICAgKiAtIFBvdGVudGlhbCBGYWlsdXJlIFBvaW50IDE6IHNob3VsZCBiZSBhYmxlIHRvIHJlc3RhcnQgdGhlIHByb2Nlc3MsIHVzZXIgcmVtYWlucyBzaWduZWQgaW4uXHJcbiAgICogLSBQb3RlbnRpYWwgRmFpbHVyZSBQb2ludCAyOiBzaG91bGQgZW50ZXIgcmVjb3ZlcnkgZmxvd1xyXG4gICAqIC0gUG90ZW50aWFsIEZhaWx1cmUgUG9pbnQgMzogc2hvdWxkIGVudGVyIHJlY292ZXJ5IGZsb3dcclxuICAgKiAtIFBvdGVudGlhbCBGYWlsdXJlIFBvaW50IDQ6IHNob3VsZCBlbnRlciByZWNvdmVyeSBmbG93XHJcbiAgICpcclxuICAgKi9cclxuXHJcbiAgcHVibGljIGFzeW5jIGlzTG9naW5SZXF1aXJlZCgpOiBQcm9taXNlPGJvb2xlYW4+IHtcclxuICAgIGNvbnN0IGNoYW5nZVBhc3N3b3JkQ29uZmlnID0gYXdhaXQgdGhpcy5nZXRDaGFuZ2VQYXNzd29yZENvbmZpZygpO1xyXG4gICAgY29uc3QgYXV0aFRpbWUgPSBtb21lbnQoY2hhbmdlUGFzc3dvcmRDb25maWcuYXV0aFRpbWUpO1xyXG4gICAgY29uc3Qgc2VydmVyVGltZSA9IG1vbWVudChjaGFuZ2VQYXNzd29yZENvbmZpZy5zZXJ2ZXJUaW1lKTtcclxuICAgIGNvbnN0IGR1cmF0aW9uID0gbW9tZW50LmR1cmF0aW9uKHNlcnZlclRpbWUuZGlmZihhdXRoVGltZSkpO1xyXG4gICAgY29uc3Qgc2Vjb25kcyA9IGR1cmF0aW9uLmFzU2Vjb25kcygpO1xyXG4gICAgaWYgKHNlY29uZHMgPiBjaGFuZ2VQYXNzd29yZENvbmZpZy5tYXhBdXRoQWdlU2Vjb25kcykge1xyXG4gICAgICByZXR1cm4gdHJ1ZTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHB1YmxpYyBhc3luYyBjaGFuZ2VQYXNzd29yZChwYXNzd29yZDogc3RyaW5nLCBuZXdQYXNzd29yZDogc3RyaW5nKSB7XHJcbiAgICBjb25zdCBjb2duaXRvVXNlcjogQ29nbml0b1VzZXIgPSBhd2FpdCB0aGlzLmF1dGguY3VycmVudEF1dGhlbnRpY2F0ZWRVc2VyKCk7XHJcblxyXG4gICAgLy8gVmFsaWRhdGlvblxyXG4gICAgLy8gdG9kbzogQWRkIHRoaXMgYmFjayBpblxyXG4gICAgLy8gTm90ZSB0aGUgcGFzc0lkcCB3aWxsIGFsd2F5cyBoYXZlIGEgcmFuZG9tIHNhbHQsIHNvIHdpbGwgYWx3YXlzIGJlIGRpZmZlcmVudCB0byB0aGUgY3VycmVudCBwYXNzSWRwLlxyXG4gICAgaWYgKHBhc3N3b3JkID09PSBuZXdQYXNzd29yZCkge1xyXG4gICAgICB0aHJvdyBuZXcgTHJCYWRBcmd1bWVudEV4Y2VwdGlvbihcclxuICAgICAgICAnTmV3IHBhc3N3b3JkIGlzIHRoZSBzYW1lIGFzIHRoZSBjdXJyZW50IG9uZS4nXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgeyBjdXJyZW50VXNlciB9ID0gYXdhaXQgdGhpcy5wcm9maWxlU2VydmljZS5nZXRDdXJyZW50VXNlcigpO1xyXG5cclxuICAgIGNvbnN0IHsgcGFzc0lkcCwgc2lnbmVkQ2hhbGxlbmdlIH0gPSBhd2FpdCB0aGlzLnZlcmlmeVBhc3N3b3JkKFxyXG4gICAgICBwYXNzd29yZCxcclxuICAgICAgY3VycmVudFVzZXJcclxuICAgICk7XHJcblxyXG4gICAgLy8gLS1Qb3RlbnRpYWwgRmFpbHVyZSBQb2ludCAxLS1cclxuICAgIC8vIHZlcmlmeVBhc3N3b3JkKCkgYXNrcyBmb3IgYSBjdXJyZW50IHBhc3N3b3JkIGNoYWxsZW5nZSBoZW5jZSBjaGFuZ2VzIHNlcnZlciBzdGF0ZS5cclxuICAgIC8vIFBsYWNlIGJyZWFrIHBvaW50cyBoZXJlIHRvIHRlc3QgdGhlIGZhaWx1cmUgc2NlbmFyaW9zLlxyXG5cclxuICAgIC8vIEdlbmVyYXRlIHRoZSBuZXcgcGFzc0lkcFxyXG4gICAgY29uc3QgbmV3UGFzc0tleSA9IGF3YWl0IHRoaXMuY3JlYXRlUGFzc0tleUJ1bmRsZShuZXdQYXNzd29yZCk7XHJcblxyXG4gICAgLy8gUmUtZW5jcnlwdCBtYXN0ZXIga2V5IHdpdGggbmV3IGtleVxyXG4gICAgY29uc3QgbWFzdGVyS2V5ID0gYXdhaXQgdGhpcy5rZXlHcmFwaC5nZXRLZXkoXHJcbiAgICAgIGN1cnJlbnRVc2VyLmN1cnJlbnRVc2VyS2V5Lm1hc3RlcktleS5pZFxyXG4gICAgKTtcclxuICAgIGNvbnN0IG5ld1dyYXBwZWRNYXN0ZXJLZXkgPSBhd2FpdCB0aGlzLmVuY3J5cHRpb25TZXJ2aWNlLmVuY3J5cHQoXHJcbiAgICAgIG5ld1Bhc3NLZXkucGFzc0tleSxcclxuICAgICAgbWFzdGVyS2V5Lmp3ay50b0pTT04odHJ1ZSlcclxuICAgICk7XHJcblxyXG4gICAgLy8gSWYgdGhlIElkUCBjaGFuZ2UgcGFzc3dvcmQgZmFpbGVkLCB3ZSBuZWVkIHRvIGdvIGludG8gcmVjb3ZlcnkgbW9kZSBieSBmb3JjaW5nXHJcbiAgICAvLyBhIGxvZ2luLiBXZSBjYW4ndCBsb2dvdXQgdGhlIHVzZXIganVzdCB5ZXQgc2luY2UgdGhlIElkUCBwYXNzd29yZCBjaGFuZ2UgbmVlZHNcclxuICAgIC8vIHRoZSB1c2VyIHRvIGJlIGxvZ2dlZCBpbi4gV2UgX2Nhbl8gcmVtb3ZlZCBhbnkgcGVyc2lzdGVkIHNlc3Npb24gdmFsdWVzIGZvciB0aGUgSWRQXHJcbiAgICAvLyBidXQgdGhhdCBzZWVtcyBsaWtlIHRvbyBtdWNoIHRyb3VibGUuXHJcblxyXG4gICAgY29uc3QgeyB0b2tlbiwgbmV3UGFzc0tleUlkIH0gPSBhd2FpdCB0aGlzLmNoYW5nZVBhc3N3b3JkTXV0YXRpb24oXHJcbiAgICAgIHNpZ25lZENoYWxsZW5nZSxcclxuICAgICAgY3VycmVudFVzZXIuY3VycmVudFVzZXJLZXkubWFzdGVyS2V5LmlkLFxyXG4gICAgICBuZXdXcmFwcGVkTWFzdGVyS2V5LFxyXG4gICAgICBuZXdQYXNzS2V5XHJcbiAgICApO1xyXG5cclxuICAgIC8vIC0tUG90ZW50aWFsIEZhaWx1cmUgUG9pbnQgMi0tXHJcbiAgICAvLyBjaGFuZ2VQYXNzd29yZE11dGF0aW9uKCkgdXBsb2FkcyBuZXcga2V5cyBhbmQgb2J0YWlucyBhIHNlbWFwaG9yZSBsb2NrIHRvIHByZXZlbnQgYW55IG90aGVyXHJcbiAgICAvLyBjbGllbnRzIGZyb20gcGVyZm9ybWluZyBJZFAgcGFzc3dvcmQgY2hhbmdlLlxyXG5cclxuICAgIC8vIE5vdyB3ZSBjYW4gZG8gdGhlIElkUCBwYXNzd29yZCBjaGFuZ2UuXHJcbiAgICAvLyB0b2RvOiBBZGQgdGhpcyBiYWNrIGluXHJcbiAgICBhd2FpdCB0aGlzLmF1dGguY2hhbmdlUGFzc3dvcmQoXHJcbiAgICAgIGNvZ25pdG9Vc2VyLFxyXG4gICAgICB0aGlzLmdldFBhc3NJZHBTdHJpbmcocGFzc0lkcCksXHJcbiAgICAgIHRoaXMuZ2V0UGFzc0lkcFN0cmluZyhuZXdQYXNzS2V5LnBhc3NJZHApXHJcbiAgICApO1xyXG5cclxuICAgIC8vIC0tUG90ZW50aWFsIEZhaWx1cmUgUG9pbnQgMy0tXHJcbiAgICAvLyBJZFAgcGFzc3dvcmQgY2hhbmdlXHJcblxyXG4gICAgLy8gTm90ZSB0aGF0IGNoYW5nZVBhc3N3b3JkKCkgY291bGQgdGhyb3cgYW4gZXhjZXB0aW9uIGZvciBhIG51bWJlciBvZiByZWFzb24uIEl0IGNvdWxkIHRocm93XHJcbiAgICAvLyBhIG5ldHdvcmsgdGltZW91dCBmb3IgZXhhbXBsZS4gQnV0IHdlIGRvbid0IGtub3cgaWYgaXQncyB0aGUgcmVzcG9uc2UgdGhhdCB0aW1lZCBvdXQgYW5kXHJcbiAgICAvLyB0aGUgaWRwIHBhc3N3b3JkIGNoYW5nZSB3YXMgYWN0dWFsbHkgY2FycmllZCBvdXQuIFNvIHdlIGhhdmUgdG8gYmUgZXh0cmEgY29uc2VydmF0aXZlIGFuZFxyXG4gICAgLy8gb25seSBhY3Qgb24gYSBjbGVhciBzdWNjZXNzLiBPdGhlcndpc2Ugd2UgZ28gaW50byByZWNvdmVyIG1vZGUuXHJcbiAgICBhd2FpdCB0aGlzLmNoYW5nZVBhc3N3b3JkQ29tcGxldGUoXHJcbiAgICAgIGNvZ25pdG9Vc2VyLmdldFNpZ25JblVzZXJTZXNzaW9uKCkuZ2V0QWNjZXNzVG9rZW4oKS5nZXRKd3RUb2tlbigpLFxyXG4gICAgICB0cnVlLFxyXG4gICAgICB0b2tlblxyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIHB1YmxpYyBhc3luYyBjaGFuZ2VQYXNzd29yZENvbXBsZXRlKFxyXG4gICAgYWNjZXNzVG9rZW46IHN0cmluZyxcclxuICAgIHVzZU5ld1Bhc3N3b3JkOiBib29sZWFuLFxyXG4gICAgdG9rZW46IHN0cmluZyA9IG51bGxcclxuICApOiBQcm9taXNlPGFueT4ge1xyXG4gICAgcmV0dXJuIHRoaXMuaHR0cFxyXG4gICAgICAucG9zdChcclxuICAgICAgICBgJHt0aGlzLmNvbmZpZy5hdXRoVXJsfXVzZXJzL3Bhc3N3b3JkLWNoYW5nZS1jb21wbGV0ZS9gLFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHVzZV9uZXdfcGFzc3dvcmQ6IHVzZU5ld1Bhc3N3b3JkLFxyXG4gICAgICAgICAgLi4uKHRva2VuICYmIHsgdG9rZW4gfSksXHJcbiAgICAgICAgfSxcclxuICAgICAgICB7XHJcbiAgICAgICAgICBoZWFkZXJzOiB7XHJcbiAgICAgICAgICAgIEF1dGhvcml6YXRpb246IGBCZWFyZXIgJHthY2Nlc3NUb2tlbn1gLFxyXG4gICAgICAgICAgfSxcclxuICAgICAgICB9XHJcbiAgICAgIClcclxuICAgICAgLnRvUHJvbWlzZSgpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBhc3luYyBnZXRWZXJpZmllclBySyhcclxuICAgIHBhc3NLZXk6IEpXSy5LZXksXHJcbiAgICB3cmFwcGVkUHJLOiBvYmplY3RcclxuICApOiBQcm9taXNlPEpXSy5LZXk+IHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGNvbnN0IHBya0pzb24gPSBhd2FpdCB0aGlzLmVuY3J5cHRpb25TZXJ2aWNlLmRlY3J5cHQocGFzc0tleSwgd3JhcHBlZFBySyk7XHJcbiAgICAgIHJldHVybiBLRlMuYXNLZXkocHJrSnNvbik7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBuZXcgTHJBdXRoRXhjZXB0aW9uKCdXcm9uZyBjdXJyZW50IHBhc3N3b3JkJyk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGFzeW5jIHZlcmlmeVBhc3N3b3JkKFxyXG4gICAgcGFzc3dvcmQ6IHN0cmluZyxcclxuICAgIGN1cnJlbnRVc2VyOiBBcGlDdXJyZW50VXNlclxyXG4gICk6IFByb21pc2U8eyBwYXNzSWRwOiBKV0suS2V5OyBzaWduZWRDaGFsbGVuZ2U6IEpXUy5DcmVhdGVTaWduUmVzdWx0IH0+IHtcclxuICAgIC8vIEdldCBpbmZvcm1hdGlvbiBmcm9tIHRoZSBzZXJ2ZXIgdG8gcHJlcGFyZSBmb3IgcGFzc3dvcmQgY2hhbmdlLlxyXG4gICAgY29uc3QgcGFzc3dvcmRSZXF1ZXN0ID0gYXdhaXQgdGhpcy5hcG9sbG8ubXV0YXRlPFBhc3N3b3JkQ2hhbmdlUmVxdWVzdE11dGF0aW9uPihcclxuICAgICAge1xyXG4gICAgICAgIG11dGF0aW9uOiBQYXNzd29yZENoYW5nZVJlcXVlc3RNdXRhdGlvbixcclxuICAgICAgICB2YXJpYWJsZXM6IHt9LFxyXG4gICAgICB9XHJcbiAgICApO1xyXG5cclxuICAgIC8vIEdldCB0aGUgb2xkIHBhc3NLZXkgc28gd2UgY2FuIGRlY3J5cHQgdGhlIG9sZCBwYXNzd29yZCB2ZXJpZmllclxyXG4gICAgY29uc3QgcGFzc0tleVJlc3VsdCA9IGF3YWl0IHRoaXMua2V5RmFjdG9yeS5kZXJpdmVQYXNzS2V5KHtcclxuICAgICAgcGFzc3dvcmQsXHJcbiAgICAgIC4uLmN1cnJlbnRVc2VyLmN1cnJlbnRVc2VyS2V5LnBhc3NLZXkucGFzc0tleVBhcmFtcyxcclxuICAgIH0pO1xyXG5cclxuICAgIGNvbnN0IHZlcmlmaWVyUHJLID0gYXdhaXQgdGhpcy5nZXRWZXJpZmllclBySyhcclxuICAgICAgcGFzc0tleVJlc3VsdC5qd2ssXHJcbiAgICAgIGN1cnJlbnRVc2VyLmN1cnJlbnRVc2VyS2V5LnBhc3NLZXkud3JhcHBlZFBhc3NJZHBWZXJpZmllclBya1xyXG4gICAgKTtcclxuXHJcbiAgICAvLyBTaWduIHRoZSBzZXJ2ZXIgY2hhbGxlbmdlIHRvIHByb3ZlIHRvIHRoZSBzZXJ2ZXIgd2UgY2FuIGRlY3J5cHQgdGhlIHBhc3N3b3JkIHZlcmlmaWVyLlxyXG4gICAgLy8gR2VuZXJhdGVcclxuICAgIGNvbnN0IGNsaWVudE5vbmNlID0gdGhpcy5rZXlGYWN0b3J5LnJhbmRvbVN0cmluZyh0aGlzLkNMSUVOVF9OT05DRV9MRU5HVEgpO1xyXG5cclxuICAgIGNvbnN0IHNpZ25lZENoYWxsZW5nZSA9IGF3YWl0IHRoaXMuZW5jcnlwdGlvblNlcnZpY2Uuc2lnbih2ZXJpZmllclBySywge1xyXG4gICAgICBzZXJ2ZXJOb25jZTogcGFzc3dvcmRSZXF1ZXN0LnBhc3N3b3JkQ2hhbmdlUmVxdWVzdC5jaGFsbGVuZ2Uuc2VydmVyTm9uY2UsXHJcbiAgICAgIGNsaWVudE5vbmNlLFxyXG4gICAgfSk7XHJcblxyXG4gICAgY29uc3QgcGFzc0lkcFJlc3VsdCA9IGF3YWl0IHRoaXMua2V5RmFjdG9yeS5kZXJpdmVQYXNzSWRwKHtcclxuICAgICAgcGFzc3dvcmQsXHJcbiAgICAgIC4uLmN1cnJlbnRVc2VyLmN1cnJlbnRVc2VyS2V5LnBhc3NLZXkucGFzc0lkcFBhcmFtcyxcclxuICAgIH0pO1xyXG5cclxuICAgIHJldHVybiB7XHJcbiAgICAgIHBhc3NJZHA6IHBhc3NJZHBSZXN1bHQuandrLFxyXG4gICAgICBzaWduZWRDaGFsbGVuZ2UsXHJcbiAgICB9O1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBhc3luYyBjaGFuZ2VQYXNzd29yZE11dGF0aW9uKFxyXG4gICAgc2lnbmVkQ2hhbGxlbmdlOiBKV1MuQ3JlYXRlU2lnblJlc3VsdCxcclxuICAgIG1hc3RlcktleUlkOiBzdHJpbmcsXHJcbiAgICBuZXdXcmFwcGVkTWFzdGVyS2V5OiBvYmplY3QsXHJcbiAgICBwYXNzS2V5QnVuZGxlOiBQYXNzS2V5QnVuZGxlXHJcbiAgKTogUHJvbWlzZTx7IHRva2VuOiBzdHJpbmc7IG5ld1Bhc3NLZXlJZDogc3RyaW5nIH0+IHtcclxuICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgdGhpcy5hcG9sbG8ubXV0YXRlPFBhc3N3b3JkQ2hhbmdlTXV0YXRpb24+KHtcclxuICAgICAgbXV0YXRpb246IFBhc3N3b3JkQ2hhbmdlTXV0YXRpb24sXHJcbiAgICAgIHZhcmlhYmxlczoge1xyXG4gICAgICAgIGlucHV0OiB7XHJcbiAgICAgICAgICBzaWduZWRDaGFsbGVuZ2U6IEpTT04uc3RyaW5naWZ5KHNpZ25lZENoYWxsZW5nZSksXHJcbiAgICAgICAgICBtYXN0ZXJLZXlJZCxcclxuICAgICAgICAgIG5ld1dyYXBwZWRNYXN0ZXJLZXk6IEpTT04uc3RyaW5naWZ5KG5ld1dyYXBwZWRNYXN0ZXJLZXkpLFxyXG4gICAgICAgICAgbmV3UGFzc0tleToge1xyXG4gICAgICAgICAgICBwYXNzSWRwUGFyYW1zOiBKU09OLnN0cmluZ2lmeShwYXNzS2V5QnVuZGxlLnBhc3NJZHBQYXJhbXMpLFxyXG4gICAgICAgICAgICBwYXNzSWRwVmVyaWZpZXJQYms6IEpTT04uc3RyaW5naWZ5KFxyXG4gICAgICAgICAgICAgIHBhc3NLZXlCdW5kbGUucGFzc0lkcFZlcmlmaWVyLnRvSlNPTigpXHJcbiAgICAgICAgICAgICksXHJcbiAgICAgICAgICAgIHdyYXBwZWRQYXNzSWRwVmVyaWZpZXJQcms6IEpTT04uc3RyaW5naWZ5KFxyXG4gICAgICAgICAgICAgIHBhc3NLZXlCdW5kbGUud3JhcHBlZFBhc3NJZHBWZXJpZmllclBya1xyXG4gICAgICAgICAgICApLFxyXG4gICAgICAgICAgICBwYXNzS2V5UGFyYW1zOiBKU09OLnN0cmluZ2lmeShwYXNzS2V5QnVuZGxlLnBhc3NLZXlQYXJhbXMpLFxyXG4gICAgICAgICAgfSxcclxuICAgICAgICB9LFxyXG4gICAgICB9LFxyXG4gICAgfSk7XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICB0b2tlbjogcmVzcG9uc2UucGFzc3dvcmRDaGFuZ2UudG9rZW4sXHJcbiAgICAgIG5ld1Bhc3NLZXlJZDogcmVzcG9uc2UucGFzc3dvcmRDaGFuZ2UubmV3UGFzc0tleS5pZCxcclxuICAgIH07XHJcbiAgfVxyXG5cclxuICBhc3luYyBnZXRDaGFuZ2VQYXNzd29yZENvbmZpZygpOiBQcm9taXNlPFBhc3N3b3JkQ2hhbmdlQ29uZmlnPiB7XHJcbiAgICBjb25zdCByZXMgPSBhd2FpdCB0aGlzLmFwb2xsby5xdWVyeTxhbnk+KHtcclxuICAgICAgcXVlcnk6IFBhc3N3b3JkQ2hhbmdlQ29uZmlnUXVlcnksXHJcbiAgICB9KTtcclxuXHJcbiAgICBjb25zdCByZXQgPSByZXMucGFzc3dvcmRDaGFuZ2VDb25maWcgYXMgUGFzc3dvcmRDaGFuZ2VDb25maWc7XHJcblxyXG4gICAgcmV0LmF1dGhUaW1lID0gbmV3IERhdGUocmV0LmF1dGhUaW1lKTtcclxuICAgIHJldC5zZXJ2ZXJUaW1lID0gbmV3IERhdGUocmV0LnNlcnZlclRpbWUpO1xyXG4gICAgcmV0dXJuIHJldDtcclxuICB9XHJcblxyXG4gIHB1YmxpYyBwYXNzd29yZFN0cmVuZ3RoKHBhc3N3b3JkKTogeyB5ZWFyczogbnVtYmVyOyBiaXRzOiBudW1iZXIgfSB7XHJcbiAgICBjb25zdCB1cHBlciA9IC9bQS1aXS9nO1xyXG4gICAgY29uc3QgbG93ZXIgPSAvW2Etel0vZztcclxuICAgIGNvbnN0IGRpZ2l0ID0gL1swLTldL2c7XHJcblxyXG4gICAgY29uc3QgdXBwZXJDaG9pY2VzID0gMjY7XHJcbiAgICBjb25zdCBsb3dlckNob2ljZXMgPSAyNjtcclxuICAgIGNvbnN0IGRpZ2l0Q2hvaWNlcyA9IDEwO1xyXG4gICAgY29uc3Qgc3BlY2lhbENob2ljZXMgPSAzMDsgLy8gL1shXCIjJCUmJygpKissLS4vOjs8PT4/QFtcXF1eX2B7fH1+XS9nXHJcblxyXG4gICAgZnVuY3Rpb24gaW5zdGFuY2VDb3VudChzdHIsIHJlKSB7XHJcbiAgICAgIHJldHVybiAoKHN0ciB8fCAnJykubWF0Y2gocmUpIHx8IFtdKS5sZW5ndGg7XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgdXBwZXJzID0gaW5zdGFuY2VDb3VudChwYXNzd29yZCwgdXBwZXIpO1xyXG4gICAgY29uc3QgbG93ZXJzID0gaW5zdGFuY2VDb3VudChwYXNzd29yZCwgbG93ZXIpO1xyXG4gICAgY29uc3QgZGlnaXRzID0gaW5zdGFuY2VDb3VudChwYXNzd29yZCwgZGlnaXQpO1xyXG4gICAgY29uc3Qgc3BlY2lhbHMgPSBwYXNzd29yZC5sZW5ndGggLSB1cHBlcnMgLSBsb3dlcnMgLSBkaWdpdHM7XHJcblxyXG4gICAgbGV0IGNob2ljZXMgPSAwO1xyXG4gICAgaWYgKHVwcGVycykge1xyXG4gICAgICBjaG9pY2VzICs9IHVwcGVyQ2hvaWNlcztcclxuICAgIH1cclxuICAgIGlmIChsb3dlcnMpIHtcclxuICAgICAgY2hvaWNlcyArPSBsb3dlckNob2ljZXM7XHJcbiAgICB9XHJcbiAgICBpZiAoZGlnaXRzKSB7XHJcbiAgICAgIGNob2ljZXMgKz0gZGlnaXRDaG9pY2VzO1xyXG4gICAgfVxyXG4gICAgaWYgKHNwZWNpYWxzKSB7XHJcbiAgICAgIGNob2ljZXMgKz0gc3BlY2lhbENob2ljZXM7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHBhc3N3b3JkLmxlbmd0aCA9PT0gMCkge1xyXG4gICAgICByZXR1cm4ge1xyXG4gICAgICAgIHllYXJzOiAwLFxyXG4gICAgICAgIC8vIGJpdHMgb2YgZW50cm9weVxyXG4gICAgICAgIGJpdHM6IDAsXHJcbiAgICAgIH07XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgcGVybXV0YXRpb25zID0gTWF0aC5wb3coY2hvaWNlcywgcGFzc3dvcmQubGVuZ3RoKTtcclxuXHJcbiAgICBjb25zdCB5ZWFycyA9XHJcbiAgICAgICg1NDAwMCAqIHBlcm11dGF0aW9ucykgL1xyXG4gICAgICBNYXRoLnBvdyh1cHBlckNob2ljZXMgKyBsb3dlckNob2ljZXMgKyBkaWdpdENob2ljZXMsIDEyKTtcclxuICAgIHJldHVybiB7XHJcbiAgICAgIHllYXJzLFxyXG4gICAgICAvLyBiaXRzIG9mIGVudHJvcHlcclxuICAgICAgYml0czogTWF0aC5yb3VuZChNYXRoLmxvZzIocGVybXV0YXRpb25zKSksXHJcbiAgICB9O1xyXG4gIH1cclxufVxyXG4iXX0=
|
|
@@ -0,0 +1,172 @@
|
|
|
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 { EncryptionService } from '../cryptography/encryption.service';
|
|
6
|
+
import { KeyFactoryService } from '../cryptography/key-factory.service';
|
|
7
|
+
import { LR_CONFIG } from '../life-ready.config';
|
|
8
|
+
import { PasswordService } from './password.service';
|
|
9
|
+
import * as i0 from "@angular/core";
|
|
10
|
+
import * as i1 from "../life-ready.config";
|
|
11
|
+
import * as i2 from "@aws-amplify/auth/lib-esm/Auth";
|
|
12
|
+
import * as i3 from "@angular/common/http";
|
|
13
|
+
import * as i4 from "../cryptography/key-factory.service";
|
|
14
|
+
import * as i5 from "../cryptography/encryption.service";
|
|
15
|
+
import * as i6 from "./password.service";
|
|
16
|
+
export class RegisterService {
|
|
17
|
+
constructor(config, auth, http, keyFactory, encryptionService, passwordService) {
|
|
18
|
+
this.config = config;
|
|
19
|
+
this.auth = auth;
|
|
20
|
+
this.http = http;
|
|
21
|
+
this.keyFactory = keyFactory;
|
|
22
|
+
this.encryptionService = encryptionService;
|
|
23
|
+
this.passwordService = passwordService;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Request a verification code to be sent out to an email.
|
|
27
|
+
* @return Info needed to be submitted along with the verification code
|
|
28
|
+
*/
|
|
29
|
+
verifyEmail(email) {
|
|
30
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
31
|
+
const { claim_id } = yield this.http
|
|
32
|
+
.post(`${this.config.authUrl}cove/claim/email/`, {
|
|
33
|
+
address: email,
|
|
34
|
+
context: 'signup',
|
|
35
|
+
})
|
|
36
|
+
.toPromise();
|
|
37
|
+
return claim_id;
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
verifyPhone(phoneNumber) {
|
|
41
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
42
|
+
const { claim_id } = yield this.http
|
|
43
|
+
.post(`${this.config.authUrl}cove/claim/sms/`, {
|
|
44
|
+
address: phoneNumber,
|
|
45
|
+
context: 'signup',
|
|
46
|
+
})
|
|
47
|
+
.toPromise();
|
|
48
|
+
return claim_id;
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
confirmVerificationCode(verificationId, verificationCode) {
|
|
52
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
53
|
+
const { token } = yield this.http
|
|
54
|
+
.post(`${this.config.authUrl}cove/respond/`, {
|
|
55
|
+
claim_id: verificationId,
|
|
56
|
+
v_code: verificationCode,
|
|
57
|
+
})
|
|
58
|
+
.toPromise();
|
|
59
|
+
return token;
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
register(email, password, verificationId, verificationToken, verificationType = 'email') {
|
|
63
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
64
|
+
// Generate the key material needed for PassIdp which will be the password used for Cognito.
|
|
65
|
+
const passKeyBundle = yield this.passwordService.createPassKeyBundle(password);
|
|
66
|
+
const masterKey = yield this.keyFactory.createKey();
|
|
67
|
+
const wrappedMasterKey = yield this.encryptionService.encrypt(passKeyBundle.passKey, masterKey.toJSON(true));
|
|
68
|
+
const rootKey = yield this.keyFactory.createKey();
|
|
69
|
+
const wrappedRootKey = yield this.encryptionService.encrypt(masterKey, rootKey.toJSON(true));
|
|
70
|
+
// Encryption PKC key
|
|
71
|
+
const prk = yield this.keyFactory.createPkcKey();
|
|
72
|
+
const wrappedPrk = yield this.encryptionService.encrypt(rootKey, prk.toJSON(true));
|
|
73
|
+
// Signing PKC key
|
|
74
|
+
const sigPrk = yield this.keyFactory.createPkcSignKey();
|
|
75
|
+
const wrappedSigPrk = yield this.encryptionService.encrypt(rootKey, sigPrk.toJSON(true));
|
|
76
|
+
// API call to setup profile
|
|
77
|
+
const user = yield this.http
|
|
78
|
+
.post(`${this.config.authUrl}users/`, {
|
|
79
|
+
claims: [
|
|
80
|
+
{
|
|
81
|
+
type: verificationType,
|
|
82
|
+
token: verificationToken,
|
|
83
|
+
claim_id: verificationId,
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
pass_idp_params: passKeyBundle.passIdpParams,
|
|
87
|
+
pass_idp_verifier_pbk: passKeyBundle.passIdpVerifier.toJSON(),
|
|
88
|
+
wrapped_pass_idp_verifier_prk: passKeyBundle.wrappedPassIdpVerifierPrk,
|
|
89
|
+
pass_key_params: passKeyBundle.passKeyParams,
|
|
90
|
+
wrapped_master_key: wrappedMasterKey,
|
|
91
|
+
wrapped_root_key: wrappedRootKey,
|
|
92
|
+
pbk: prk.toJSON(),
|
|
93
|
+
wrapped_prk: wrappedPrk,
|
|
94
|
+
sig_pbk: sigPrk.toJSON(),
|
|
95
|
+
wrapped_sig_prk: wrappedSigPrk,
|
|
96
|
+
})
|
|
97
|
+
.toPromise();
|
|
98
|
+
// API call to create user on cognito
|
|
99
|
+
const attributes = {};
|
|
100
|
+
user.claims.forEach((claim) => {
|
|
101
|
+
attributes[claim.type] = claim.value;
|
|
102
|
+
});
|
|
103
|
+
// Random suffix for uniqueness. If there's a duplicate, then used just needs to
|
|
104
|
+
// sign up again. But chances of collision is low.
|
|
105
|
+
const suffix = this.keyFactory.randomDigitsNoZeros(4);
|
|
106
|
+
const cognitoUser = yield this.auth.signUp({
|
|
107
|
+
username: `${email.split('@')[0]}.${suffix}`,
|
|
108
|
+
password: this.passwordService.getPassIdpString(passKeyBundle.passIdp),
|
|
109
|
+
attributes,
|
|
110
|
+
// Unfortunately, validationData is not passed to the post
|
|
111
|
+
// confirmation cognito trigger. So can can't do the association there.
|
|
112
|
+
// The current workflow will create a new user on LR before signing up
|
|
113
|
+
// with Cognito. Then Cognito can use the user.id and user.pre_sign_up_token to
|
|
114
|
+
// do the validation of the attributes.
|
|
115
|
+
// validationData: [
|
|
116
|
+
// new CognitoUserAttribute({
|
|
117
|
+
// Name: "user_id",
|
|
118
|
+
// Value: String(user.id)
|
|
119
|
+
// }),
|
|
120
|
+
// new CognitoUserAttribute({
|
|
121
|
+
// Name: "user_pre_sign_up_token",
|
|
122
|
+
// Value: user.pre_sign_up_token
|
|
123
|
+
// })
|
|
124
|
+
// ]
|
|
125
|
+
clientMetadata: {
|
|
126
|
+
user_id: String(user.id),
|
|
127
|
+
user_pre_sign_up_token: String(user.pre_sign_up_token),
|
|
128
|
+
},
|
|
129
|
+
});
|
|
130
|
+
return {
|
|
131
|
+
username: cognitoUser.user.getUsername(),
|
|
132
|
+
userId: user.id,
|
|
133
|
+
preSignUpToken: user.pre_sign_up_token,
|
|
134
|
+
userSub: cognitoUser.userSub,
|
|
135
|
+
};
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
hibpBreachedAccounts(account) {
|
|
139
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
140
|
+
// The account is just the email
|
|
141
|
+
try {
|
|
142
|
+
const response = yield this.http
|
|
143
|
+
.get(`${this.config.authUrl}users/hibp/breachedaccount/${account}/?truncateResponse=false`)
|
|
144
|
+
.toPromise();
|
|
145
|
+
return response;
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
if (error.status === 404) {
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
throw error;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
RegisterService.ɵprov = i0.ɵɵdefineInjectable({ factory: function RegisterService_Factory() { return new RegisterService(i0.ɵɵinject(i1.LR_CONFIG), i0.ɵɵinject(i2.AuthClass), i0.ɵɵinject(i3.HttpClient), i0.ɵɵinject(i4.KeyFactoryService), i0.ɵɵinject(i5.EncryptionService), i0.ɵɵinject(i6.PasswordService)); }, token: RegisterService, providedIn: "root" });
|
|
159
|
+
RegisterService.decorators = [
|
|
160
|
+
{ type: Injectable, args: [{
|
|
161
|
+
providedIn: 'root',
|
|
162
|
+
},] }
|
|
163
|
+
];
|
|
164
|
+
RegisterService.ctorParameters = () => [
|
|
165
|
+
{ type: undefined, decorators: [{ type: Inject, args: [LR_CONFIG,] }] },
|
|
166
|
+
{ type: AuthClass },
|
|
167
|
+
{ type: HttpClient },
|
|
168
|
+
{ type: KeyFactoryService },
|
|
169
|
+
{ type: EncryptionService },
|
|
170
|
+
{ type: PasswordService }
|
|
171
|
+
];
|
|
172
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVnaXN0ZXIuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiJDOi9Qcm9qZWN0cy90ZXN0L3Byb2plY3RzL2NvcmUvc3JjLyIsInNvdXJjZXMiOlsibGliL2F1dGgvcmVnaXN0ZXIuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ2xELE9BQU8sRUFBRSxNQUFNLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ25ELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUMzRCxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxvQ0FBb0MsQ0FBQztBQUN2RSxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxxQ0FBcUMsQ0FBQztBQUN4RSxPQUFPLEVBQW1CLFNBQVMsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ2xFLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQzs7Ozs7Ozs7QUFNckQsTUFBTSxPQUFPLGVBQWU7SUFDMUIsWUFDNkIsTUFBdUIsRUFDMUMsSUFBZSxFQUNmLElBQWdCLEVBQ2hCLFVBQTZCLEVBQzdCLGlCQUFvQyxFQUNwQyxlQUFnQztRQUxiLFdBQU0sR0FBTixNQUFNLENBQWlCO1FBQzFDLFNBQUksR0FBSixJQUFJLENBQVc7UUFDZixTQUFJLEdBQUosSUFBSSxDQUFZO1FBQ2hCLGVBQVUsR0FBVixVQUFVLENBQW1CO1FBQzdCLHNCQUFpQixHQUFqQixpQkFBaUIsQ0FBbUI7UUFDcEMsb0JBQWUsR0FBZixlQUFlLENBQWlCO0lBQ3ZDLENBQUM7SUFFSjs7O09BR0c7SUFDVSxXQUFXLENBQUMsS0FBYTs7WUFDcEMsTUFBTSxFQUFFLFFBQVEsRUFBRSxHQUFHLE1BQU0sSUFBSSxDQUFDLElBQUk7aUJBQ2pDLElBQUksQ0FBZSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTyxtQkFBbUIsRUFBRTtnQkFD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bW1vbi9odHRwJztcclxuaW1wb3J0IHsgSW5qZWN0LCBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7IEF1dGhDbGFzcyB9IGZyb20gJ0Bhd3MtYW1wbGlmeS9hdXRoL2xpYi1lc20vQXV0aCc7XHJcbmltcG9ydCB7IEVuY3J5cHRpb25TZXJ2aWNlIH0gZnJvbSAnLi4vY3J5cHRvZ3JhcGh5L2VuY3J5cHRpb24uc2VydmljZSc7XHJcbmltcG9ydCB7IEtleUZhY3RvcnlTZXJ2aWNlIH0gZnJvbSAnLi4vY3J5cHRvZ3JhcGh5L2tleS1mYWN0b3J5LnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBMaWZlUmVhZHlDb25maWcsIExSX0NPTkZJRyB9IGZyb20gJy4uL2xpZmUtcmVhZHkuY29uZmlnJztcclxuaW1wb3J0IHsgUGFzc3dvcmRTZXJ2aWNlIH0gZnJvbSAnLi9wYXNzd29yZC5zZXJ2aWNlJztcclxuaW1wb3J0IHsgUmVnaXN0ZXJSZXN1bHQgfSBmcm9tICcuL2F1dGgudHlwZXMnO1xyXG5cclxuQEluamVjdGFibGUoe1xyXG4gIHByb3ZpZGVkSW46ICdyb290JyxcclxufSlcclxuZXhwb3J0IGNsYXNzIFJlZ2lzdGVyU2VydmljZSB7XHJcbiAgY29uc3RydWN0b3IoXHJcbiAgICBASW5qZWN0KExSX0NPTkZJRykgcHJpdmF0ZSBjb25maWc6IExpZmVSZWFkeUNvbmZpZyxcclxuICAgIHByaXZhdGUgYXV0aDogQXV0aENsYXNzLFxyXG4gICAgcHJpdmF0ZSBodHRwOiBIdHRwQ2xpZW50LFxyXG4gICAgcHJpdmF0ZSBrZXlGYWN0b3J5OiBLZXlGYWN0b3J5U2VydmljZSxcclxuICAgIHByaXZhdGUgZW5jcnlwdGlvblNlcnZpY2U6IEVuY3J5cHRpb25TZXJ2aWNlLFxyXG4gICAgcHJpdmF0ZSBwYXNzd29yZFNlcnZpY2U6IFBhc3N3b3JkU2VydmljZVxyXG4gICkge31cclxuXHJcbiAgLyoqXHJcbiAgICogUmVxdWVzdCBhIHZlcmlmaWNhdGlvbiBjb2RlIHRvIGJlIHNlbnQgb3V0IHRvIGFuIGVtYWlsLlxyXG4gICAqIEByZXR1cm4gSW5mbyBuZWVkZWQgdG8gYmUgc3VibWl0dGVkIGFsb25nIHdpdGggdGhlIHZlcmlmaWNhdGlvbiBjb2RlXHJcbiAgICovXHJcbiAgcHVibGljIGFzeW5jIHZlcmlmeUVtYWlsKGVtYWlsOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xyXG4gICAgY29uc3QgeyBjbGFpbV9pZCB9ID0gYXdhaXQgdGhpcy5odHRwXHJcbiAgICAgIC5wb3N0PHsgY2xhaW1faWQgfT4oYCR7dGhpcy5jb25maWcuYXV0aFVybH1jb3ZlL2NsYWltL2VtYWlsL2AsIHtcclxuICAgICAgICBhZGRyZXNzOiBlbWFpbCxcclxuICAgICAgICBjb250ZXh0OiAnc2lnbnVwJyxcclxuICAgICAgfSlcclxuICAgICAgLnRvUHJvbWlzZSgpO1xyXG4gICAgcmV0dXJuIGNsYWltX2lkO1xyXG4gIH1cclxuXHJcbiAgcHVibGljIGFzeW5jIHZlcmlmeVBob25lKHBob25lTnVtYmVyOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xyXG4gICAgY29uc3QgeyBjbGFpbV9pZCB9ID0gYXdhaXQgdGhpcy5odHRwXHJcbiAgICAgIC5wb3N0PHsgY2xhaW1faWQgfT4oYCR7dGhpcy5jb25maWcuYXV0aFVybH1jb3ZlL2NsYWltL3Ntcy9gLCB7XHJcbiAgICAgICAgYWRkcmVzczogcGhvbmVOdW1iZXIsXHJcbiAgICAgICAgY29udGV4dDogJ3NpZ251cCcsXHJcbiAgICAgIH0pXHJcbiAgICAgIC50b1Byb21pc2UoKTtcclxuICAgIHJldHVybiBjbGFpbV9pZDtcclxuICB9XHJcblxyXG4gIHB1YmxpYyBhc3luYyBjb25maXJtVmVyaWZpY2F0aW9uQ29kZShcclxuICAgIHZlcmlmaWNhdGlvbklkOiBzdHJpbmcsXHJcbiAgICB2ZXJpZmljYXRpb25Db2RlOiBzdHJpbmdcclxuICApOiBQcm9taXNlPHN0cmluZz4ge1xyXG4gICAgY29uc3QgeyB0b2tlbiB9ID0gYXdhaXQgdGhpcy5odHRwXHJcbiAgICAgIC5wb3N0PHsgdG9rZW4gfT4oYCR7dGhpcy5jb25maWcuYXV0aFVybH1jb3ZlL3Jlc3BvbmQvYCwge1xyXG4gICAgICAgIGNsYWltX2lkOiB2ZXJpZmljYXRpb25JZCxcclxuICAgICAgICB2X2NvZGU6IHZlcmlmaWNhdGlvbkNvZGUsXHJcbiAgICAgIH0pXHJcbiAgICAgIC50b1Byb21pc2UoKTtcclxuICAgIHJldHVybiB0b2tlbjtcclxuICB9XHJcblxyXG4gIHB1YmxpYyBhc3luYyByZWdpc3RlcihcclxuICAgIGVtYWlsOiBzdHJpbmcsXHJcbiAgICBwYXNzd29yZDogc3RyaW5nLFxyXG4gICAgdmVyaWZpY2F0aW9uSWQ6IHN0cmluZyxcclxuICAgIHZlcmlmaWNhdGlvblRva2VuOiBzdHJpbmcsXHJcbiAgICB2ZXJpZmljYXRpb25UeXBlOiAnZW1haWwnIHwgJ3Bob25lJyA9ICdlbWFpbCdcclxuICApOiBQcm9taXNlPFJlZ2lzdGVyUmVzdWx0PiB7XHJcbiAgICAvLyBHZW5lcmF0ZSB0aGUga2V5IG1hdGVyaWFsIG5lZWRlZCBmb3IgUGFzc0lkcCB3aGljaCB3aWxsIGJlIHRoZSBwYXNzd29yZCB1c2VkIGZvciBDb2duaXRvLlxyXG4gICAgY29uc3QgcGFzc0tleUJ1bmRsZSA9IGF3YWl0IHRoaXMucGFzc3dvcmRTZXJ2aWNlLmNyZWF0ZVBhc3NLZXlCdW5kbGUoXHJcbiAgICAgIHBhc3N3b3JkXHJcbiAgICApO1xyXG5cclxuICAgIGNvbnN0IG1hc3RlcktleSA9IGF3YWl0IHRoaXMua2V5RmFjdG9yeS5jcmVhdGVLZXkoKTtcclxuICAgIGNvbnN0IHdyYXBwZWRNYXN0ZXJLZXkgPSBhd2FpdCB0aGlzLmVuY3J5cHRpb25TZXJ2aWNlLmVuY3J5cHQoXHJcbiAgICAgIHBhc3NLZXlCdW5kbGUucGFzc0tleSxcclxuICAgICAgbWFzdGVyS2V5LnRvSlNPTih0cnVlKVxyXG4gICAgKTtcclxuXHJcbiAgICBjb25zdCByb290S2V5ID0gYXdhaXQgdGhpcy5rZXlGYWN0b3J5LmNyZWF0ZUtleSgpO1xyXG4gICAgY29uc3Qgd3JhcHBlZFJvb3RLZXkgPSBhd2FpdCB0aGlzLmVuY3J5cHRpb25TZXJ2aWNlLmVuY3J5cHQoXHJcbiAgICAgIG1hc3RlcktleSxcclxuICAgICAgcm9vdEtleS50b0pTT04odHJ1ZSlcclxuICAgICk7XHJcblxyXG4gICAgLy8gRW5jcnlwdGlvbiBQS0Mga2V5XHJcbiAgICBjb25zdCBwcmsgPSBhd2FpdCB0aGlzLmtleUZhY3RvcnkuY3JlYXRlUGtjS2V5KCk7XHJcbiAgICBjb25zdCB3cmFwcGVkUHJrID0gYXdhaXQgdGhpcy5lbmNyeXB0aW9uU2VydmljZS5lbmNyeXB0KFxyXG4gICAgICByb290S2V5LFxyXG4gICAgICBwcmsudG9KU09OKHRydWUpXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFNpZ25pbmcgUEtDIGtleVxyXG4gICAgY29uc3Qgc2lnUHJrID0gYXdhaXQgdGhpcy5rZXlGYWN0b3J5LmNyZWF0ZVBrY1NpZ25LZXkoKTtcclxuICAgIGNvbnN0IHdyYXBwZWRTaWdQcmsgPSBhd2FpdCB0aGlzLmVuY3J5cHRpb25TZXJ2aWNlLmVuY3J5cHQoXHJcbiAgICAgIHJvb3RLZXksXHJcbiAgICAgIHNpZ1Byay50b0pTT04odHJ1ZSlcclxuICAgICk7XHJcblxyXG4gICAgLy8gQVBJIGNhbGwgdG8gc2V0dXAgcHJvZmlsZVxyXG4gICAgY29uc3QgdXNlciA9IGF3YWl0IHRoaXMuaHR0cFxyXG4gICAgICAucG9zdDxhbnk+KGAke3RoaXMuY29uZmlnLmF1dGhVcmx9dXNlcnMvYCwge1xyXG4gICAgICAgIGNsYWltczogW1xyXG4gICAgICAgICAge1xyXG4gICAgICAgICAgICB0eXBlOiB2ZXJpZmljYXRpb25UeXBlLFxyXG4gICAgICAgICAgICB0b2tlbjogdmVyaWZpY2F0aW9uVG9rZW4sXHJcbiAgICAgICAgICAgIGNsYWltX2lkOiB2ZXJpZmljYXRpb25JZCxcclxuICAgICAgICAgIH0sXHJcbiAgICAgICAgXSxcclxuICAgICAgICBwYXNzX2lkcF9wYXJhbXM6IHBhc3NLZXlCdW5kbGUucGFzc0lkcFBhcmFtcyxcclxuICAgICAgICBwYXNzX2lkcF92ZXJpZmllcl9wYms6IHBhc3NLZXlCdW5kbGUucGFzc0lkcFZlcmlmaWVyLnRvSlNPTigpLFxyXG4gICAgICAgIHdyYXBwZWRfcGFzc19pZHBfdmVyaWZpZXJfcHJrOiBwYXNzS2V5QnVuZGxlLndyYXBwZWRQYXNzSWRwVmVyaWZpZXJQcmssXHJcbiAgICAgICAgcGFzc19rZXlfcGFyYW1zOiBwYXNzS2V5QnVuZGxlLnBhc3NLZXlQYXJhbXMsXHJcbiAgICAgICAgd3JhcHBlZF9tYXN0ZXJfa2V5OiB3cmFwcGVkTWFzdGVyS2V5LFxyXG4gICAgICAgIHdyYXBwZWRfcm9vdF9rZXk6IHdyYXBwZWRSb290S2V5LFxyXG4gICAgICAgIHBiazogcHJrLnRvSlNPTigpLCAvLyBwdWJsaWMgZW5jcnlwdGlvbiBrZXlcclxuICAgICAgICB3cmFwcGVkX3Byazogd3JhcHBlZFByayxcclxuICAgICAgICBzaWdfcGJrOiBzaWdQcmsudG9KU09OKCksIC8vIHB1YmxpYyBzaWduaW5nIGtleVxyXG4gICAgICAgIHdyYXBwZWRfc2lnX3Byazogd3JhcHBlZFNpZ1ByayxcclxuICAgICAgfSlcclxuICAgICAgLnRvUHJvbWlzZSgpO1xyXG5cclxuICAgIC8vIEFQSSBjYWxsIHRvIGNyZWF0ZSB1c2VyIG9uIGNvZ25pdG9cclxuICAgIGNvbnN0IGF0dHJpYnV0ZXMgPSB7fTtcclxuICAgIHVzZXIuY2xhaW1zLmZvckVhY2goKGNsYWltKSA9PiB7XHJcbiAgICAgIGF0dHJpYnV0ZXNbY2xhaW0udHlwZV0gPSBjbGFpbS52YWx1ZTtcclxuICAgIH0pO1xyXG5cclxuICAgIC8vIFJhbmRvbSBzdWZmaXggZm9yIHVuaXF1ZW5lc3MuIElmIHRoZXJlJ3MgYSBkdXBsaWNhdGUsIHRoZW4gdXNlZCBqdXN0IG5lZWRzIHRvXHJcbiAgICAvLyBzaWduIHVwIGFnYWluLiBCdXQgY2hhbmNlcyBvZiBjb2xsaXNpb24gaXMgbG93LlxyXG4gICAgY29uc3Qgc3VmZml4ID0gdGhpcy5rZXlGYWN0b3J5LnJhbmRvbURpZ2l0c05vWmVyb3MoNCk7XHJcblxyXG4gICAgY29uc3QgY29nbml0b1VzZXIgPSBhd2FpdCB0aGlzLmF1dGguc2lnblVwKHtcclxuICAgICAgdXNlcm5hbWU6IGAke2VtYWlsLnNwbGl0KCdAJylbMF19LiR7c3VmZml4fWAsXHJcbiAgICAgIHBhc3N3b3JkOiB0aGlzLnBhc3N3b3JkU2VydmljZS5nZXRQYXNzSWRwU3RyaW5nKHBhc3NLZXlCdW5kbGUucGFzc0lkcCksXHJcbiAgICAgIGF0dHJpYnV0ZXMsXHJcbiAgICAgIC8vIFVuZm9ydHVuYXRlbHksIHZhbGlkYXRpb25EYXRhIGlzIG5vdCBwYXNzZWQgdG8gdGhlIHBvc3RcclxuICAgICAgLy8gY29uZmlybWF0aW9uIGNvZ25pdG8gdHJpZ2dlci4gU28gY2FuIGNhbid0IGRvIHRoZSBhc3NvY2lhdGlvbiB0aGVyZS5cclxuICAgICAgLy8gVGhlIGN1cnJlbnQgd29ya2Zsb3cgd2lsbCBjcmVhdGUgYSBuZXcgdXNlciBvbiBMUiBiZWZvcmUgc2lnbmluZyB1cFxyXG4gICAgICAvLyB3aXRoIENvZ25pdG8uIFRoZW4gQ29nbml0byBjYW4gdXNlIHRoZSB1c2VyLmlkIGFuZCB1c2VyLnByZV9zaWduX3VwX3Rva2VuIHRvXHJcbiAgICAgIC8vIGRvIHRoZSB2YWxpZGF0aW9uIG9mIHRoZSBhdHRyaWJ1dGVzLlxyXG4gICAgICAvLyB2YWxpZGF0aW9uRGF0YTogW1xyXG4gICAgICAvLyAgIG5ldyBDb2duaXRvVXNlckF0dHJpYnV0ZSh7XHJcbiAgICAgIC8vICAgICBOYW1lOiBcInVzZXJfaWRcIixcclxuICAgICAgLy8gICAgIFZhbHVlOiBTdHJpbmcodXNlci5pZClcclxuICAgICAgLy8gICB9KSxcclxuICAgICAgLy8gICBuZXcgQ29nbml0b1VzZXJBdHRyaWJ1dGUoe1xyXG4gICAgICAvLyAgICAgTmFtZTogXCJ1c2VyX3ByZV9zaWduX3VwX3Rva2VuXCIsXHJcbiAgICAgIC8vICAgICBWYWx1ZTogdXNlci5wcmVfc2lnbl91cF90b2tlblxyXG4gICAgICAvLyAgIH0pXHJcbiAgICAgIC8vIF1cclxuICAgICAgY2xpZW50TWV0YWRhdGE6IHtcclxuICAgICAgICB1c2VyX2lkOiBTdHJpbmcodXNlci5pZCksXHJcbiAgICAgICAgdXNlcl9wcmVfc2lnbl91cF90b2tlbjogU3RyaW5nKHVzZXIucHJlX3NpZ25fdXBfdG9rZW4pLFxyXG4gICAgICB9LFxyXG4gICAgfSk7XHJcblxyXG4gICAgcmV0dXJuIHtcclxuICAgICAgdXNlcm5hbWU6IGNvZ25pdG9Vc2VyLnVzZXIuZ2V0VXNlcm5hbWUoKSxcclxuICAgICAgdXNlcklkOiB1c2VyLmlkLFxyXG4gICAgICBwcmVTaWduVXBUb2tlbjogdXNlci5wcmVfc2lnbl91cF90b2tlbixcclxuICAgICAgdXNlclN1YjogY29nbml0b1VzZXIudXNlclN1YixcclxuICAgIH07XHJcbiAgfVxyXG5cclxuICBwdWJsaWMgYXN5bmMgaGlicEJyZWFjaGVkQWNjb3VudHMoYWNjb3VudDogc3RyaW5nKTogUHJvbWlzZTxhbnk+IHtcclxuICAgIC8vIFRoZSBhY2NvdW50IGlzIGp1c3QgdGhlIGVtYWlsXHJcbiAgICB0cnkge1xyXG4gICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHRoaXMuaHR0cFxyXG4gICAgICAgIC5nZXQoXHJcbiAgICAgICAgICBgJHt0aGlzLmNvbmZpZy5hdXRoVXJsfXVzZXJzL2hpYnAvYnJlYWNoZWRhY2NvdW50LyR7YWNjb3VudH0vP3RydW5jYXRlUmVzcG9uc2U9ZmFsc2VgXHJcbiAgICAgICAgKVxyXG4gICAgICAgIC50b1Byb21pc2UoKTtcclxuICAgICAgcmV0dXJuIHJlc3BvbnNlO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgaWYgKGVycm9yLnN0YXR1cyA9PT0gNDA0KSB7XHJcbiAgICAgICAgcmV0dXJuIG51bGw7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcbn1cclxuIl19
|