@bitgo/abstract-utxo 1.0.1-rc.0
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/.eslintignore +5 -0
- package/CHANGELOG.md +11 -0
- package/LICENSE +191 -0
- package/README.md +1 -0
- package/dist/src/abstractUtxoCoin.d.ts +388 -0
- package/dist/src/abstractUtxoCoin.d.ts.map +1 -0
- package/dist/src/abstractUtxoCoin.js +955 -0
- package/dist/src/config.d.ts +7 -0
- package/dist/src/config.d.ts.map +1 -0
- package/dist/src/config.js +12 -0
- package/dist/src/index.d.ts +6 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +18 -0
- package/dist/src/parseOutput.d.ts +22 -0
- package/dist/src/parseOutput.d.ts.map +1 -0
- package/dist/src/parseOutput.js +169 -0
- package/dist/src/recovery/RecoveryProvider.d.ts +18 -0
- package/dist/src/recovery/RecoveryProvider.d.ts.map +1 -0
- package/dist/src/recovery/RecoveryProvider.js +23 -0
- package/dist/src/recovery/backupKeyRecovery.d.ts +56 -0
- package/dist/src/recovery/backupKeyRecovery.d.ts.map +1 -0
- package/dist/src/recovery/backupKeyRecovery.js +273 -0
- package/dist/src/recovery/baseApi.d.ts +27 -0
- package/dist/src/recovery/baseApi.d.ts.map +1 -0
- package/dist/src/recovery/baseApi.js +73 -0
- package/dist/src/recovery/coingeckoApi.d.ts +9 -0
- package/dist/src/recovery/coingeckoApi.d.ts.map +1 -0
- package/dist/src/recovery/coingeckoApi.js +47 -0
- package/dist/src/recovery/crossChainRecovery.d.ts +95 -0
- package/dist/src/recovery/crossChainRecovery.d.ts.map +1 -0
- package/dist/src/recovery/crossChainRecovery.js +318 -0
- package/dist/src/recovery/index.d.ts +8 -0
- package/dist/src/recovery/index.d.ts.map +1 -0
- package/dist/src/recovery/index.js +20 -0
- package/dist/src/recovery/mempoolApi.d.ts +7 -0
- package/dist/src/recovery/mempoolApi.d.ts.map +1 -0
- package/dist/src/recovery/mempoolApi.js +33 -0
- package/dist/src/recovery/smartbitApi.d.ts +11 -0
- package/dist/src/recovery/smartbitApi.d.ts.map +1 -0
- package/dist/src/recovery/smartbitApi.js +36 -0
- package/dist/src/replayProtection.d.ts +5 -0
- package/dist/src/replayProtection.d.ts.map +1 -0
- package/dist/src/replayProtection.js +21 -0
- package/dist/src/sign.d.ts +29 -0
- package/dist/src/sign.d.ts.map +1 -0
- package/dist/src/sign.js +104 -0
- package/dist/tsconfig.tsbuildinfo +7371 -0
- package/package.json +55 -0
|
@@ -0,0 +1,955 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AbstractUtxoCoin = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* @prettier
|
|
6
|
+
*/
|
|
7
|
+
const bip32 = require("bip32");
|
|
8
|
+
const utxolib = require("@bitgo/utxo-lib");
|
|
9
|
+
const bitgo_1 = require("@bitgo/utxo-lib/dist/src/bitgo");
|
|
10
|
+
const bitcoinMessage = require("bitcoinjs-message");
|
|
11
|
+
const crypto_1 = require("crypto");
|
|
12
|
+
const debugLib = require("debug");
|
|
13
|
+
const _ = require("lodash");
|
|
14
|
+
const backupKeyRecovery_1 = require("./recovery/backupKeyRecovery");
|
|
15
|
+
const recovery_1 = require("./recovery");
|
|
16
|
+
const sdk_core_1 = require("@bitgo/sdk-core");
|
|
17
|
+
const parseOutput_1 = require("./parseOutput");
|
|
18
|
+
const debug = debugLib('bitgo:v2:utxo');
|
|
19
|
+
const replayProtection_1 = require("./replayProtection");
|
|
20
|
+
const sign_1 = require("./sign");
|
|
21
|
+
const config_1 = require("./config");
|
|
22
|
+
class AbstractUtxoCoin extends sdk_core_1.BaseCoin {
|
|
23
|
+
constructor(bitgo, network) {
|
|
24
|
+
super(bitgo);
|
|
25
|
+
if (!_.isObject(network)) {
|
|
26
|
+
throw new Error('network must be an object');
|
|
27
|
+
}
|
|
28
|
+
this._network = network;
|
|
29
|
+
}
|
|
30
|
+
get network() {
|
|
31
|
+
return this._network;
|
|
32
|
+
}
|
|
33
|
+
sweepWithSendMany() {
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
/** @deprecated */
|
|
37
|
+
static get validAddressTypes() {
|
|
38
|
+
return [...bitgo_1.outputScripts.scriptTypes2Of3];
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Returns the factor between the base unit and its smallest subdivison
|
|
42
|
+
* @return {number}
|
|
43
|
+
*/
|
|
44
|
+
getBaseFactor() {
|
|
45
|
+
return 1e8;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* @deprecated
|
|
49
|
+
*/
|
|
50
|
+
getCoinLibrary() {
|
|
51
|
+
return utxolib;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Helper to get the version number for an address
|
|
55
|
+
*/
|
|
56
|
+
getAddressVersion(address) {
|
|
57
|
+
// try decoding as base58 first
|
|
58
|
+
try {
|
|
59
|
+
const { version } = utxolib.address.fromBase58Check(address, this.network);
|
|
60
|
+
return version;
|
|
61
|
+
}
|
|
62
|
+
catch (e) {
|
|
63
|
+
// try next format
|
|
64
|
+
}
|
|
65
|
+
// if coin does not support script types with bech32 encoding, do not attempt to parse
|
|
66
|
+
if (!this.supportsAddressType('p2wsh') && !this.supportsAddressType('p2tr')) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
// otherwise, try decoding as bech32
|
|
70
|
+
try {
|
|
71
|
+
const { version, prefix } = utxolib.address.fromBech32(address);
|
|
72
|
+
if (_.isString(this.network.bech32) && prefix === this.network.bech32) {
|
|
73
|
+
return version;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
catch (e) {
|
|
77
|
+
// ignore errors, just fall through and return undefined
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Helper to get the bech32 prefix for an address
|
|
82
|
+
*/
|
|
83
|
+
getAddressPrefix(address) {
|
|
84
|
+
// otherwise, try decoding as bech32
|
|
85
|
+
try {
|
|
86
|
+
const { prefix } = utxolib.address.fromBech32(address);
|
|
87
|
+
return prefix;
|
|
88
|
+
}
|
|
89
|
+
catch (e) {
|
|
90
|
+
// ignore errors, just fall through and return undefined
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Check if an address is valid
|
|
95
|
+
* @param address
|
|
96
|
+
* @param forceAltScriptSupport
|
|
97
|
+
*/
|
|
98
|
+
isValidAddress(address, forceAltScriptSupport = false) {
|
|
99
|
+
const validVersions = [this.network.pubKeyHash, this.network.scriptHash];
|
|
100
|
+
if (this.altScriptHash && (forceAltScriptSupport || this.supportAltScriptDestination)) {
|
|
101
|
+
validVersions.push(this.altScriptHash);
|
|
102
|
+
}
|
|
103
|
+
const addressVersion = this.getAddressVersion(address);
|
|
104
|
+
// the address version needs to be among the valid ones
|
|
105
|
+
const addressVersionValid = _.isNumber(addressVersion) && validVersions.includes(addressVersion);
|
|
106
|
+
const addressPrefix = this.getAddressPrefix(address);
|
|
107
|
+
if (!this.supportsAddressType('p2wsh') || _.isUndefined(addressPrefix)) {
|
|
108
|
+
return addressVersionValid;
|
|
109
|
+
}
|
|
110
|
+
// address has a potential bech32 prefix, validate that
|
|
111
|
+
return (_.isString(this.network.bech32) && this.network.bech32 === addressPrefix && address === address.toLowerCase());
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Return boolean indicating whether input is valid public key for the coin.
|
|
115
|
+
*
|
|
116
|
+
* @param {String} pub the pub to be checked
|
|
117
|
+
* @returns {Boolean} is it valid?
|
|
118
|
+
*/
|
|
119
|
+
isValidPub(pub) {
|
|
120
|
+
try {
|
|
121
|
+
return bip32.fromBase58(pub).isNeutered();
|
|
122
|
+
}
|
|
123
|
+
catch (e) {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Get the latest block height
|
|
129
|
+
* @param reqId
|
|
130
|
+
*/
|
|
131
|
+
async getLatestBlockHeight(reqId) {
|
|
132
|
+
if (reqId) {
|
|
133
|
+
this.bitgo.setRequestTracer(reqId);
|
|
134
|
+
}
|
|
135
|
+
const chainhead = await this.bitgo.get(this.url('/public/block/latest')).result();
|
|
136
|
+
return chainhead.height;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Run custom coin logic after a transaction prebuild has been received from BitGo
|
|
140
|
+
* @param prebuild
|
|
141
|
+
*/
|
|
142
|
+
async postProcessPrebuild(prebuild) {
|
|
143
|
+
if (_.isUndefined(prebuild.txHex)) {
|
|
144
|
+
throw new Error('missing required txPrebuild property txHex');
|
|
145
|
+
}
|
|
146
|
+
const transaction = this.createTransactionFromHex(prebuild.txHex);
|
|
147
|
+
if (_.isUndefined(prebuild.blockHeight)) {
|
|
148
|
+
prebuild.blockHeight = (await this.getLatestBlockHeight());
|
|
149
|
+
}
|
|
150
|
+
// Lock transaction to the next block to discourage fee sniping
|
|
151
|
+
// See: https://github.com/bitcoin/bitcoin/blob/fb0ac482eee761ec17ed2c11df11e054347a026d/src/wallet/wallet.cpp#L2133
|
|
152
|
+
transaction.locktime = prebuild.blockHeight;
|
|
153
|
+
return _.extend({}, prebuild, { txHex: transaction.toHex() });
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Find outputs that are within expected outputs but not within actual outputs, including duplicates
|
|
157
|
+
* @param expectedOutputs
|
|
158
|
+
* @param actualOutputs
|
|
159
|
+
* @returns {Array}
|
|
160
|
+
*/
|
|
161
|
+
static findMissingOutputs(expectedOutputs, actualOutputs) {
|
|
162
|
+
const keyFunc = ({ address, amount }) => `${address}:${Number(amount)}`;
|
|
163
|
+
const groupedOutputs = _.groupBy(expectedOutputs, keyFunc);
|
|
164
|
+
actualOutputs.forEach((output) => {
|
|
165
|
+
const group = groupedOutputs[keyFunc(output)];
|
|
166
|
+
if (group) {
|
|
167
|
+
group.pop();
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
return _.flatten(_.values(groupedOutputs));
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Determine an address' type based on its witness and redeem script presence
|
|
174
|
+
* @param addressDetails
|
|
175
|
+
*/
|
|
176
|
+
static inferAddressType(addressDetails) {
|
|
177
|
+
return bitgo_1.isChainCode(addressDetails.chain) ? bitgo_1.scriptTypeForChain(addressDetails.chain) : null;
|
|
178
|
+
}
|
|
179
|
+
createTransactionFromHex(hex) {
|
|
180
|
+
return utxolib.bitgo.createTransactionFromHex(hex, this.network);
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Extract and fill transaction details such as internal/change spend, external spend (explicit vs. implicit), etc.
|
|
184
|
+
* @param params
|
|
185
|
+
* @returns {*}
|
|
186
|
+
*/
|
|
187
|
+
async parseTransaction(params) {
|
|
188
|
+
const { txParams, txPrebuild, wallet, verification = {}, reqId } = params;
|
|
189
|
+
if (!_.isUndefined(verification.disableNetworking) && !_.isBoolean(verification.disableNetworking)) {
|
|
190
|
+
throw new Error('verification.disableNetworking must be a boolean');
|
|
191
|
+
}
|
|
192
|
+
const disableNetworking = verification.disableNetworking;
|
|
193
|
+
const fetchKeychains = async (wallet) => {
|
|
194
|
+
return sdk_core_1.promiseProps({
|
|
195
|
+
user: this.keychains().get({ id: wallet.keyIds()[sdk_core_1.KeyIndices.USER], reqId }),
|
|
196
|
+
backup: this.keychains().get({ id: wallet.keyIds()[sdk_core_1.KeyIndices.BACKUP], reqId }),
|
|
197
|
+
bitgo: this.keychains().get({ id: wallet.keyIds()[sdk_core_1.KeyIndices.BITGO], reqId }),
|
|
198
|
+
});
|
|
199
|
+
};
|
|
200
|
+
// obtain the keychains and key signatures
|
|
201
|
+
let keychains = verification.keychains;
|
|
202
|
+
if (!keychains) {
|
|
203
|
+
if (disableNetworking) {
|
|
204
|
+
throw new Error('cannot fetch keychains without networking');
|
|
205
|
+
}
|
|
206
|
+
keychains = await fetchKeychains(wallet);
|
|
207
|
+
}
|
|
208
|
+
if (!keychains || !keychains.user || !keychains.backup || !keychains.bitgo) {
|
|
209
|
+
throw new Error('keychains are required, but could not be fetched');
|
|
210
|
+
}
|
|
211
|
+
const keychainArray = [keychains.user, keychains.backup, keychains.bitgo];
|
|
212
|
+
const keySignatures = _.get(wallet, '_wallet.keySignatures');
|
|
213
|
+
if (_.isUndefined(txPrebuild.txHex)) {
|
|
214
|
+
throw new Error('missing required txPrebuild property txHex');
|
|
215
|
+
}
|
|
216
|
+
// obtain all outputs
|
|
217
|
+
const explanation = await this.explainTransaction({
|
|
218
|
+
txHex: txPrebuild.txHex,
|
|
219
|
+
txInfo: txPrebuild.txInfo,
|
|
220
|
+
pubs: keychainArray.map((k) => k.pub),
|
|
221
|
+
});
|
|
222
|
+
const allOutputs = [...explanation.outputs, ...explanation.changeOutputs];
|
|
223
|
+
// verify that each recipient from txParams has their own output
|
|
224
|
+
const expectedOutputs = _.get(txParams, 'recipients', []).map((output) => {
|
|
225
|
+
return { ...output, address: this.canonicalAddress(output.address) };
|
|
226
|
+
});
|
|
227
|
+
const missingOutputs = AbstractUtxoCoin.findMissingOutputs(expectedOutputs, allOutputs);
|
|
228
|
+
// get the keychains from the custom change wallet if needed
|
|
229
|
+
let customChange;
|
|
230
|
+
const { customChangeWalletId = undefined } = wallet.coinSpecific() || {};
|
|
231
|
+
if (customChangeWalletId) {
|
|
232
|
+
// fetch keychains from custom change wallet for deriving addresses.
|
|
233
|
+
// These keychains should be signed and this should be verified in verifyTransaction
|
|
234
|
+
const customChangeKeySignatures = _.get(wallet, '_wallet.customChangeKeySignatures', {});
|
|
235
|
+
const customChangeWallet = await this.wallets().get({ id: customChangeWalletId });
|
|
236
|
+
const customChangeKeys = await fetchKeychains(customChangeWallet);
|
|
237
|
+
if (!customChangeKeys) {
|
|
238
|
+
throw new Error('failed to fetch keychains for custom change wallet');
|
|
239
|
+
}
|
|
240
|
+
if (customChangeKeys.user && customChangeKeys.backup && customChangeKeys.bitgo && customChangeWallet) {
|
|
241
|
+
const customChangeKeychains = [
|
|
242
|
+
customChangeKeys.user,
|
|
243
|
+
customChangeKeys.backup,
|
|
244
|
+
customChangeKeys.bitgo,
|
|
245
|
+
];
|
|
246
|
+
customChange = {
|
|
247
|
+
keys: customChangeKeychains,
|
|
248
|
+
signatures: [
|
|
249
|
+
customChangeKeySignatures.user,
|
|
250
|
+
customChangeKeySignatures.backup,
|
|
251
|
+
customChangeKeySignatures.bitgo,
|
|
252
|
+
],
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Loop through all the outputs and classify each of them as either internal spends
|
|
258
|
+
* or external spends by setting the "external" property to true or false on the output object.
|
|
259
|
+
*/
|
|
260
|
+
const allOutputDetails = await Promise.all(allOutputs.map((currentOutput) => {
|
|
261
|
+
return parseOutput_1.parseOutput({
|
|
262
|
+
currentOutput,
|
|
263
|
+
coin: this,
|
|
264
|
+
txPrebuild,
|
|
265
|
+
verification,
|
|
266
|
+
keychainArray,
|
|
267
|
+
wallet,
|
|
268
|
+
txParams,
|
|
269
|
+
customChange,
|
|
270
|
+
reqId,
|
|
271
|
+
});
|
|
272
|
+
}));
|
|
273
|
+
const needsCustomChangeKeySignatureVerification = allOutputDetails.some((output) => output.needsCustomChangeKeySignatureVerification);
|
|
274
|
+
const changeOutputs = _.filter(allOutputDetails, { external: false });
|
|
275
|
+
// these are all the outputs that were not originally explicitly specified in recipients
|
|
276
|
+
const implicitOutputs = AbstractUtxoCoin.findMissingOutputs(allOutputDetails, expectedOutputs);
|
|
277
|
+
const explicitOutputs = AbstractUtxoCoin.findMissingOutputs(allOutputDetails, implicitOutputs);
|
|
278
|
+
// these are all the non-wallet outputs that had been originally explicitly specified in recipients
|
|
279
|
+
const explicitExternalOutputs = _.filter(explicitOutputs, { external: true });
|
|
280
|
+
// this is the sum of all the originally explicitly specified non-wallet output values
|
|
281
|
+
const explicitExternalSpendAmount = _.sumBy(explicitExternalOutputs, 'amount');
|
|
282
|
+
/**
|
|
283
|
+
* The calculation of the implicit external spend amount pertains to verifying the pay-as-you-go-fee BitGo
|
|
284
|
+
* automatically applies to transactions sending money out of the wallet. The logic is fairly straightforward
|
|
285
|
+
* in that we compare the external spend amount that was specified explicitly by the user to the portion
|
|
286
|
+
* that was specified implicitly. To protect customers from people tampering with the transaction outputs, we
|
|
287
|
+
* define a threshold for the maximum percentage of the implicit external spend in relation to the explicit
|
|
288
|
+
* external spend.
|
|
289
|
+
*/
|
|
290
|
+
// make sure that all the extra addresses are change addresses
|
|
291
|
+
// get all the additional external outputs the server added and calculate their values
|
|
292
|
+
const implicitExternalOutputs = _.filter(implicitOutputs, { external: true });
|
|
293
|
+
const implicitExternalSpendAmount = _.sumBy(implicitExternalOutputs, 'amount');
|
|
294
|
+
return {
|
|
295
|
+
keychains,
|
|
296
|
+
keySignatures,
|
|
297
|
+
outputs: allOutputDetails,
|
|
298
|
+
missingOutputs,
|
|
299
|
+
explicitExternalOutputs,
|
|
300
|
+
implicitExternalOutputs,
|
|
301
|
+
changeOutputs,
|
|
302
|
+
explicitExternalSpendAmount,
|
|
303
|
+
implicitExternalSpendAmount,
|
|
304
|
+
needsCustomChangeKeySignatureVerification,
|
|
305
|
+
customChange,
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Decrypt the wallet's user private key and verify that the claimed public key matches
|
|
310
|
+
* @param {VerifyUserPublicKeyOptions} params
|
|
311
|
+
* @return {boolean}
|
|
312
|
+
* @protected
|
|
313
|
+
*/
|
|
314
|
+
verifyUserPublicKey(params) {
|
|
315
|
+
const { userKeychain, txParams, disableNetworking } = params;
|
|
316
|
+
if (!userKeychain) {
|
|
317
|
+
throw new Error('user keychain is required');
|
|
318
|
+
}
|
|
319
|
+
const userPub = userKeychain.pub;
|
|
320
|
+
// decrypt the user private key so we can verify that the claimed public key is a match
|
|
321
|
+
let userPrv = userKeychain.prv;
|
|
322
|
+
if (_.isEmpty(userPrv)) {
|
|
323
|
+
const encryptedPrv = userKeychain.encryptedPrv;
|
|
324
|
+
if (encryptedPrv && !_.isEmpty(encryptedPrv)) {
|
|
325
|
+
// if the decryption fails, it will throw an error
|
|
326
|
+
userPrv = this.bitgo.decrypt({
|
|
327
|
+
input: encryptedPrv,
|
|
328
|
+
password: txParams.walletPassphrase,
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
if (!userPrv) {
|
|
333
|
+
const errorMessage = 'user private key unavailable for verification';
|
|
334
|
+
if (disableNetworking) {
|
|
335
|
+
console.log(errorMessage);
|
|
336
|
+
return false;
|
|
337
|
+
}
|
|
338
|
+
else {
|
|
339
|
+
throw new Error(errorMessage);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
const userPrivateKey = bip32.fromBase58(userPrv);
|
|
344
|
+
if (userPrivateKey.toBase58() === userPrivateKey.neutered().toBase58()) {
|
|
345
|
+
throw new Error('user private key is only public');
|
|
346
|
+
}
|
|
347
|
+
if (userPrivateKey.neutered().toBase58() !== userPub) {
|
|
348
|
+
throw new Error('user private key does not match public key');
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
return true;
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Verify signatures produced by the user key over the backup and bitgo keys.
|
|
355
|
+
*
|
|
356
|
+
* If set, these signatures ensure that the wallet keys cannot be changed after the wallet has been created.
|
|
357
|
+
* @param {VerifyKeySignaturesOptions} params
|
|
358
|
+
* @return {{backup: boolean, bitgo: boolean}}
|
|
359
|
+
*/
|
|
360
|
+
verifyKeySignature(params) {
|
|
361
|
+
// first, let's verify the integrity of the user key, whose public key is used for subsequent verifications
|
|
362
|
+
const { userKeychain, keychainToVerify, keySignature } = params;
|
|
363
|
+
if (!userKeychain) {
|
|
364
|
+
throw new Error('user keychain is required');
|
|
365
|
+
}
|
|
366
|
+
if (!keychainToVerify) {
|
|
367
|
+
throw new Error('keychain to verify is required');
|
|
368
|
+
}
|
|
369
|
+
if (!keySignature) {
|
|
370
|
+
throw new Error('key signature is required');
|
|
371
|
+
}
|
|
372
|
+
// verify the signature against the user public key
|
|
373
|
+
const publicKey = bip32.fromBase58(userKeychain.pub).publicKey;
|
|
374
|
+
const signingAddress = utxolib.address.toBase58Check(utxolib.crypto.hash160(publicKey), utxolib.networks.bitcoin.pubKeyHash, this.network);
|
|
375
|
+
// BG-5703: use BTC mainnet prefix for all key signature operations
|
|
376
|
+
// (this means do not pass a prefix parameter, and let it use the default prefix instead)
|
|
377
|
+
try {
|
|
378
|
+
return bitcoinMessage.verify(keychainToVerify.pub, signingAddress, Buffer.from(keySignature, 'hex'));
|
|
379
|
+
}
|
|
380
|
+
catch (e) {
|
|
381
|
+
debug('error thrown from bitcoinmessage while verifying key signature', e);
|
|
382
|
+
return false;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Verify signatures against the user private key over the change wallet extended keys
|
|
387
|
+
* @param {ParsedTransaction} tx
|
|
388
|
+
* @param {Keychain} userKeychain
|
|
389
|
+
* @return {boolean}
|
|
390
|
+
* @protected
|
|
391
|
+
*/
|
|
392
|
+
verifyCustomChangeKeySignatures(tx, userKeychain) {
|
|
393
|
+
if (!tx.customChange) {
|
|
394
|
+
throw new Error('parsed transaction is missing required custom change verification data');
|
|
395
|
+
}
|
|
396
|
+
if (!Array.isArray(tx.customChange.keys) || !Array.isArray(tx.customChange.signatures)) {
|
|
397
|
+
throw new Error('customChange property is missing keys or signatures');
|
|
398
|
+
}
|
|
399
|
+
for (const keyIndex of [sdk_core_1.KeyIndices.USER, sdk_core_1.KeyIndices.BACKUP, sdk_core_1.KeyIndices.BITGO]) {
|
|
400
|
+
const keychainToVerify = tx.customChange.keys[keyIndex];
|
|
401
|
+
const keySignature = tx.customChange.signatures[keyIndex];
|
|
402
|
+
if (!keychainToVerify) {
|
|
403
|
+
throw new Error(`missing required custom change ${sdk_core_1.KeyIndices[keyIndex].toLowerCase()} keychain public key`);
|
|
404
|
+
}
|
|
405
|
+
if (!keySignature) {
|
|
406
|
+
throw new Error(`missing required custom change ${sdk_core_1.KeyIndices[keyIndex].toLowerCase()} keychain signature`);
|
|
407
|
+
}
|
|
408
|
+
if (!this.verifyKeySignature({ userKeychain, keychainToVerify, keySignature })) {
|
|
409
|
+
debug('failed to verify custom change %s key signature!', sdk_core_1.KeyIndices[keyIndex].toLowerCase());
|
|
410
|
+
return false;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
return true;
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* Get the maximum percentage limit for pay-as-you-go outputs
|
|
417
|
+
*
|
|
418
|
+
* @protected
|
|
419
|
+
*/
|
|
420
|
+
getPayGoLimit(allowPaygoOutput) {
|
|
421
|
+
// allowing paygo outputs needs to be the default behavior, so only disallow paygo outputs if the
|
|
422
|
+
// relevant verification option is both set and false
|
|
423
|
+
if (!_.isNil(allowPaygoOutput) && !allowPaygoOutput) {
|
|
424
|
+
return 0;
|
|
425
|
+
}
|
|
426
|
+
// 150 basis points is the absolute permitted maximum if paygo outputs are allowed
|
|
427
|
+
return 0.015;
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* Verify that a transaction prebuild complies with the original intention
|
|
431
|
+
*
|
|
432
|
+
* @param params
|
|
433
|
+
* @param params.txParams params object passed to send
|
|
434
|
+
* @param params.txPrebuild prebuild object returned by server
|
|
435
|
+
* @param params.txPrebuild.txHex prebuilt transaction's txHex form
|
|
436
|
+
* @param params.wallet Wallet object to obtain keys to verify against
|
|
437
|
+
* @param params.verification Object specifying some verification parameters
|
|
438
|
+
* @param params.verification.disableNetworking Disallow fetching any data from the internet for verification purposes
|
|
439
|
+
* @param params.verification.keychains Pass keychains manually rather than fetching them by id
|
|
440
|
+
* @param params.verification.addresses Address details to pass in for out-of-band verification
|
|
441
|
+
* @returns {boolean}
|
|
442
|
+
*/
|
|
443
|
+
async verifyTransaction(params) {
|
|
444
|
+
const { txParams, txPrebuild, wallet, verification = { allowPaygoOutput: true }, reqId } = params;
|
|
445
|
+
const disableNetworking = !!verification.disableNetworking;
|
|
446
|
+
const parsedTransaction = await this.parseTransaction({
|
|
447
|
+
txParams,
|
|
448
|
+
txPrebuild,
|
|
449
|
+
wallet,
|
|
450
|
+
verification,
|
|
451
|
+
reqId,
|
|
452
|
+
});
|
|
453
|
+
const keychains = parsedTransaction.keychains;
|
|
454
|
+
// verify that the claimed user public key corresponds to the wallet's user private key
|
|
455
|
+
let userPublicKeyVerified = false;
|
|
456
|
+
try {
|
|
457
|
+
// verify the user public key matches the private key - this will throw if there is no match
|
|
458
|
+
userPublicKeyVerified = this.verifyUserPublicKey({ userKeychain: keychains.user, disableNetworking, txParams });
|
|
459
|
+
}
|
|
460
|
+
catch (e) {
|
|
461
|
+
debug('failed to verify user public key!', e);
|
|
462
|
+
}
|
|
463
|
+
// let's verify these keychains
|
|
464
|
+
const keySignatures = parsedTransaction.keySignatures;
|
|
465
|
+
if (!_.isEmpty(keySignatures)) {
|
|
466
|
+
const verify = (key, pub) => this.verifyKeySignature({ userKeychain: keychains.user, keychainToVerify: key, keySignature: pub });
|
|
467
|
+
const isBackupKeySignatureValid = verify(keychains.backup, keySignatures.backupPub);
|
|
468
|
+
const isBitgoKeySignatureValid = verify(keychains.bitgo, keySignatures.bitgoPub);
|
|
469
|
+
if (!isBackupKeySignatureValid || !isBitgoKeySignatureValid) {
|
|
470
|
+
throw new Error('secondary public key signatures invalid');
|
|
471
|
+
}
|
|
472
|
+
debug('successfully verified backup and bitgo key signatures');
|
|
473
|
+
}
|
|
474
|
+
else if (!disableNetworking) {
|
|
475
|
+
// these keys were obtained online and their signatures were not verified
|
|
476
|
+
// this could be dangerous
|
|
477
|
+
console.log('unsigned keys obtained online are being used for address verification');
|
|
478
|
+
}
|
|
479
|
+
if (parsedTransaction.needsCustomChangeKeySignatureVerification) {
|
|
480
|
+
if (!keychains.user || !userPublicKeyVerified) {
|
|
481
|
+
throw new Error('transaction requires verification of user public key, but it was unable to be verified');
|
|
482
|
+
}
|
|
483
|
+
const customChangeKeySignaturesVerified = this.verifyCustomChangeKeySignatures(parsedTransaction, keychains.user);
|
|
484
|
+
if (!customChangeKeySignaturesVerified) {
|
|
485
|
+
throw new Error('transaction requires verification of custom change key signatures, but they were unable to be verified');
|
|
486
|
+
}
|
|
487
|
+
debug('successfully verified user public key and custom change key signatures');
|
|
488
|
+
}
|
|
489
|
+
const missingOutputs = parsedTransaction.missingOutputs;
|
|
490
|
+
if (missingOutputs.length !== 0) {
|
|
491
|
+
// there are some outputs in the recipients list that have not made it into the actual transaction
|
|
492
|
+
throw new Error('expected outputs missing in transaction prebuild');
|
|
493
|
+
}
|
|
494
|
+
const intendedExternalSpend = parsedTransaction.explicitExternalSpendAmount;
|
|
495
|
+
// this is a limit we impose for the total value that is amended to the transaction beyond what was originally intended
|
|
496
|
+
const payAsYouGoLimit = intendedExternalSpend * this.getPayGoLimit(verification.allowPaygoOutput);
|
|
497
|
+
/*
|
|
498
|
+
Some explanation for why we're doing what we're doing:
|
|
499
|
+
Some customers will have an output to BitGo's PAYGo wallet added to their transaction, and we need to account for
|
|
500
|
+
it here. To protect someone tampering with the output to make it send more than it should to BitGo, we define a
|
|
501
|
+
threshold for the output's value above which we'll throw an error, because the paygo output should never be that
|
|
502
|
+
high.
|
|
503
|
+
*/
|
|
504
|
+
// make sure that all the extra addresses are change addresses
|
|
505
|
+
// get all the additional external outputs the server added and calculate their values
|
|
506
|
+
const nonChangeAmount = parsedTransaction.implicitExternalSpendAmount;
|
|
507
|
+
debug('Intended spend is %s, Non-change amount is %s, paygo limit is %s', intendedExternalSpend, nonChangeAmount, payAsYouGoLimit);
|
|
508
|
+
// the additional external outputs can only be BitGo's pay-as-you-go fee, but we cannot verify the wallet address
|
|
509
|
+
if (nonChangeAmount > payAsYouGoLimit) {
|
|
510
|
+
// there are some addresses that are outside the scope of intended recipients that are not change addresses
|
|
511
|
+
throw new Error('prebuild attempts to spend to unintended external recipients');
|
|
512
|
+
}
|
|
513
|
+
const allOutputs = parsedTransaction.outputs;
|
|
514
|
+
if (!txPrebuild.txHex) {
|
|
515
|
+
throw new Error(`txPrebuild.txHex not set`);
|
|
516
|
+
}
|
|
517
|
+
const transaction = this.createTransactionFromHex(txPrebuild.txHex);
|
|
518
|
+
const transactionCache = {};
|
|
519
|
+
const inputs = await Promise.all(transaction.ins.map(async (currentInput) => {
|
|
520
|
+
var _a, _b;
|
|
521
|
+
const transactionId = Buffer.from(currentInput.hash).reverse().toString('hex');
|
|
522
|
+
const txHex = (_b = (_a = txPrebuild.txInfo) === null || _a === void 0 ? void 0 : _a.txHexes) === null || _b === void 0 ? void 0 : _b[transactionId];
|
|
523
|
+
if (txHex) {
|
|
524
|
+
const localTx = this.createTransactionFromHex(txHex);
|
|
525
|
+
if (localTx.getId() !== transactionId) {
|
|
526
|
+
throw new Error('input transaction hex does not match id');
|
|
527
|
+
}
|
|
528
|
+
const currentOutput = localTx.outs[currentInput.index];
|
|
529
|
+
const address = utxolib.address.fromOutputScript(currentOutput.script, this.network);
|
|
530
|
+
return {
|
|
531
|
+
address,
|
|
532
|
+
value: currentOutput.value,
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
else if (!transactionCache[transactionId]) {
|
|
536
|
+
if (disableNetworking) {
|
|
537
|
+
throw new Error('attempting to retrieve transaction details externally with networking disabled');
|
|
538
|
+
}
|
|
539
|
+
if (reqId) {
|
|
540
|
+
this.bitgo.setRequestTracer(reqId);
|
|
541
|
+
}
|
|
542
|
+
transactionCache[transactionId] = await this.bitgo.get(this.url(`/public/tx/${transactionId}`)).result();
|
|
543
|
+
}
|
|
544
|
+
const transactionDetails = transactionCache[transactionId];
|
|
545
|
+
return transactionDetails.outputs[currentInput.index];
|
|
546
|
+
}));
|
|
547
|
+
const inputAmount = _.sumBy(inputs, 'value');
|
|
548
|
+
const outputAmount = _.sumBy(allOutputs, 'amount');
|
|
549
|
+
const fee = inputAmount - outputAmount;
|
|
550
|
+
if (fee < 0) {
|
|
551
|
+
throw new Error(`attempting to spend ${outputAmount} satoshis, which exceeds the input amount (${inputAmount} satoshis) by ${-fee}`);
|
|
552
|
+
}
|
|
553
|
+
return true;
|
|
554
|
+
}
|
|
555
|
+
/**
|
|
556
|
+
* Make sure an address is valid and throw an error if it's not.
|
|
557
|
+
* @param params.address The address string on the network
|
|
558
|
+
* @param params.addressType
|
|
559
|
+
* @param params.keychains Keychain objects with xpubs
|
|
560
|
+
* @param params.coinSpecific Coin-specific details for the address such as a witness script
|
|
561
|
+
* @param params.chain Derivation chain
|
|
562
|
+
* @param params.index Derivation index
|
|
563
|
+
* @throws {InvalidAddressError}
|
|
564
|
+
* @throws {InvalidAddressDerivationPropertyError}
|
|
565
|
+
* @throws {UnexpectedAddressError}
|
|
566
|
+
*/
|
|
567
|
+
isWalletAddress(params) {
|
|
568
|
+
const { address, addressType, keychains, coinSpecific, chain, index } = params;
|
|
569
|
+
if (!this.isValidAddress(address)) {
|
|
570
|
+
throw new sdk_core_1.InvalidAddressError(`invalid address: ${address}`);
|
|
571
|
+
}
|
|
572
|
+
if ((_.isUndefined(chain) && _.isUndefined(index)) || !(_.isFinite(chain) && _.isFinite(index))) {
|
|
573
|
+
throw new sdk_core_1.InvalidAddressDerivationPropertyError(`address validation failure: invalid chain (${chain}) or index (${index})`);
|
|
574
|
+
}
|
|
575
|
+
if (!_.isObject(coinSpecific)) {
|
|
576
|
+
throw new sdk_core_1.InvalidAddressVerificationObjectPropertyError('address validation failure: coinSpecific field must be an object');
|
|
577
|
+
}
|
|
578
|
+
if (!keychains) {
|
|
579
|
+
throw new Error('missing required param keychains');
|
|
580
|
+
}
|
|
581
|
+
const expectedAddress = this.generateAddress({
|
|
582
|
+
addressType: addressType,
|
|
583
|
+
keychains,
|
|
584
|
+
threshold: 2,
|
|
585
|
+
chain,
|
|
586
|
+
index,
|
|
587
|
+
});
|
|
588
|
+
if (expectedAddress.address !== address) {
|
|
589
|
+
throw new sdk_core_1.UnexpectedAddressError(`address validation failure: expected ${expectedAddress.address} but got ${address}`);
|
|
590
|
+
}
|
|
591
|
+
return true;
|
|
592
|
+
}
|
|
593
|
+
/**
|
|
594
|
+
* Indicates whether coin supports a block target
|
|
595
|
+
* @returns {boolean}
|
|
596
|
+
*/
|
|
597
|
+
supportsBlockTarget() {
|
|
598
|
+
return true;
|
|
599
|
+
}
|
|
600
|
+
/**
|
|
601
|
+
* @param addressType
|
|
602
|
+
* @returns true iff coin supports spending from unspentType
|
|
603
|
+
*/
|
|
604
|
+
supportsAddressType(addressType) {
|
|
605
|
+
return utxolib.bitgo.outputScripts.isSupportedScriptType(this.network, addressType);
|
|
606
|
+
}
|
|
607
|
+
/**
|
|
608
|
+
* @param chain
|
|
609
|
+
* @return true iff coin supports spending from chain
|
|
610
|
+
*/
|
|
611
|
+
supportsAddressChain(chain) {
|
|
612
|
+
return bitgo_1.isChainCode(chain) && this.supportsAddressType(utxolib.bitgo.scriptTypeForChain(chain));
|
|
613
|
+
}
|
|
614
|
+
keyIdsForSigning() {
|
|
615
|
+
return [sdk_core_1.KeyIndices.USER, sdk_core_1.KeyIndices.BACKUP, sdk_core_1.KeyIndices.BITGO];
|
|
616
|
+
}
|
|
617
|
+
/**
|
|
618
|
+
* TODO(BG-11487): Remove addressType, segwit, and bech32 params in SDKv6
|
|
619
|
+
* Generate an address for a wallet based on a set of configurations
|
|
620
|
+
* @param params.addressType {string} Deprecated
|
|
621
|
+
* @param params.keychains {[object]} Array of objects with xpubs
|
|
622
|
+
* @param params.threshold {number} Minimum number of signatures
|
|
623
|
+
* @param params.chain {number} Derivation chain (see https://github.com/BitGo/unspents/blob/master/src/codes.ts for
|
|
624
|
+
* the corresponding address type of a given chain code)
|
|
625
|
+
* @param params.index {number} Derivation index
|
|
626
|
+
* @param params.segwit {boolean} Deprecated
|
|
627
|
+
* @param params.bech32 {boolean} Deprecated
|
|
628
|
+
* @returns {{chain: number, index: number, coin: number, coinSpecific: {outputScript, redeemScript}}}
|
|
629
|
+
*/
|
|
630
|
+
generateAddress(params) {
|
|
631
|
+
const { keychains, threshold, chain, index, segwit = false, bech32 = false } = params;
|
|
632
|
+
let derivationChain = bitgo_1.getExternalChainCode('p2sh');
|
|
633
|
+
if (_.isNumber(chain) && _.isInteger(chain) && bitgo_1.isChainCode(chain)) {
|
|
634
|
+
derivationChain = chain;
|
|
635
|
+
}
|
|
636
|
+
function convertFlagsToAddressType() {
|
|
637
|
+
if (bitgo_1.isChainCode(chain)) {
|
|
638
|
+
return utxolib.bitgo.scriptTypeForChain(chain);
|
|
639
|
+
}
|
|
640
|
+
if (_.isBoolean(segwit) && segwit) {
|
|
641
|
+
return 'p2shP2wsh';
|
|
642
|
+
}
|
|
643
|
+
else if (_.isBoolean(bech32) && bech32) {
|
|
644
|
+
return 'p2wsh';
|
|
645
|
+
}
|
|
646
|
+
else {
|
|
647
|
+
return 'p2sh';
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
const addressType = params.addressType || convertFlagsToAddressType();
|
|
651
|
+
if (addressType !== utxolib.bitgo.scriptTypeForChain(derivationChain)) {
|
|
652
|
+
throw new sdk_core_1.AddressTypeChainMismatchError(addressType, derivationChain);
|
|
653
|
+
}
|
|
654
|
+
if (!this.supportsAddressType(addressType)) {
|
|
655
|
+
switch (addressType) {
|
|
656
|
+
case 'p2sh':
|
|
657
|
+
throw new Error(`internal error: p2sh should always be supported`);
|
|
658
|
+
case 'p2shP2wsh':
|
|
659
|
+
throw new sdk_core_1.P2shP2wshUnsupportedError();
|
|
660
|
+
case 'p2wsh':
|
|
661
|
+
throw new sdk_core_1.P2wshUnsupportedError();
|
|
662
|
+
case 'p2tr':
|
|
663
|
+
throw new sdk_core_1.P2trUnsupportedError();
|
|
664
|
+
default:
|
|
665
|
+
throw new sdk_core_1.UnsupportedAddressTypeError();
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
let signatureThreshold = 2;
|
|
669
|
+
if (_.isInteger(threshold)) {
|
|
670
|
+
signatureThreshold = threshold;
|
|
671
|
+
if (signatureThreshold <= 0) {
|
|
672
|
+
throw new Error('threshold has to be positive');
|
|
673
|
+
}
|
|
674
|
+
if (signatureThreshold > keychains.length) {
|
|
675
|
+
throw new Error('threshold cannot exceed number of keys');
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
let derivationIndex = 0;
|
|
679
|
+
if (_.isInteger(index) && index > 0) {
|
|
680
|
+
derivationIndex = index;
|
|
681
|
+
}
|
|
682
|
+
const path = '0/0/' + derivationChain + '/' + derivationIndex;
|
|
683
|
+
const hdNodes = keychains.map(({ pub }) => bip32.fromBase58(pub));
|
|
684
|
+
const derivedKeys = hdNodes.map((hdNode) => hdNode.derivePath(sdk_core_1.sanitizeLegacyPath(path)).publicKey);
|
|
685
|
+
const { outputScript, redeemScript, witnessScript, address } = this.createMultiSigAddress(addressType, signatureThreshold, derivedKeys);
|
|
686
|
+
return {
|
|
687
|
+
address,
|
|
688
|
+
chain: derivationChain,
|
|
689
|
+
index: derivationIndex,
|
|
690
|
+
coin: this.getChain(),
|
|
691
|
+
coinSpecific: {
|
|
692
|
+
outputScript: outputScript.toString('hex'),
|
|
693
|
+
redeemScript: redeemScript && redeemScript.toString('hex'),
|
|
694
|
+
witnessScript: witnessScript && witnessScript.toString('hex'),
|
|
695
|
+
},
|
|
696
|
+
addressType,
|
|
697
|
+
};
|
|
698
|
+
}
|
|
699
|
+
/**
|
|
700
|
+
* Assemble keychain and half-sign prebuilt transaction
|
|
701
|
+
* @param params - {@see SignTransactionOptions}
|
|
702
|
+
* @returns {Promise<SignedTransaction | HalfSignedUtxoTransaction>}
|
|
703
|
+
*/
|
|
704
|
+
async signTransaction(params) {
|
|
705
|
+
var _a;
|
|
706
|
+
const txPrebuild = params.txPrebuild;
|
|
707
|
+
const userPrv = params.prv;
|
|
708
|
+
if (_.isUndefined(txPrebuild) || !_.isObject(txPrebuild)) {
|
|
709
|
+
if (!_.isUndefined(txPrebuild) && !_.isObject(txPrebuild)) {
|
|
710
|
+
throw new Error(`txPrebuild must be an object, got type ${typeof txPrebuild}`);
|
|
711
|
+
}
|
|
712
|
+
throw new Error('missing txPrebuild parameter');
|
|
713
|
+
}
|
|
714
|
+
const transaction = this.createTransactionFromHex(txPrebuild.txHex);
|
|
715
|
+
if (transaction.ins.length !== txPrebuild.txInfo.unspents.length) {
|
|
716
|
+
throw new Error('length of unspents array should equal to the number of transaction inputs');
|
|
717
|
+
}
|
|
718
|
+
let isLastSignature = false;
|
|
719
|
+
if (_.isBoolean(params.isLastSignature)) {
|
|
720
|
+
// if build is called instead of buildIncomplete, no signature placeholders are left in the sig script
|
|
721
|
+
isLastSignature = params.isLastSignature;
|
|
722
|
+
}
|
|
723
|
+
if (_.isUndefined(userPrv) || !_.isString(userPrv)) {
|
|
724
|
+
if (!_.isUndefined(userPrv)) {
|
|
725
|
+
throw new Error(`prv must be a string, got type ${typeof userPrv}`);
|
|
726
|
+
}
|
|
727
|
+
throw new Error('missing prv parameter to sign transaction');
|
|
728
|
+
}
|
|
729
|
+
if (!params.pubs || params.pubs.length !== 3) {
|
|
730
|
+
throw new Error(`must provide xpub array`);
|
|
731
|
+
}
|
|
732
|
+
const signerKeychain = bip32.fromBase58(userPrv, utxolib.networks.bitcoin);
|
|
733
|
+
if (signerKeychain.isNeutered()) {
|
|
734
|
+
throw new Error('expected user private key but received public key');
|
|
735
|
+
}
|
|
736
|
+
debug(`Here is the public key of the xprv you used to sign: ${signerKeychain.neutered().toBase58()}`);
|
|
737
|
+
const cosignerPub = (_a = params.cosignerPub) !== null && _a !== void 0 ? _a : params.pubs[2];
|
|
738
|
+
const keychains = params.pubs.map((pub) => bip32.fromBase58(pub));
|
|
739
|
+
const cosignerKeychain = bip32.fromBase58(cosignerPub);
|
|
740
|
+
const signedTransaction = sign_1.signAndVerifyWalletTransaction(transaction, txPrebuild.txInfo.unspents, new bitgo_1.WalletUnspentSigner(keychains, signerKeychain, cosignerKeychain), { isLastSignature });
|
|
741
|
+
return {
|
|
742
|
+
txHex: signedTransaction.toBuffer().toString('hex'),
|
|
743
|
+
};
|
|
744
|
+
}
|
|
745
|
+
/**
|
|
746
|
+
* @param unspent
|
|
747
|
+
* @returns {boolean}
|
|
748
|
+
*/
|
|
749
|
+
isBitGoTaintedUnspent(unspent) {
|
|
750
|
+
return replayProtection_1.isReplayProtectionUnspent(unspent, this.network);
|
|
751
|
+
}
|
|
752
|
+
/**
|
|
753
|
+
* @deprecated - use utxolib.bitgo.getDefaultSigHash(network) instead
|
|
754
|
+
* @returns {number}
|
|
755
|
+
*/
|
|
756
|
+
get defaultSigHashType() {
|
|
757
|
+
return utxolib.bitgo.getDefaultSigHash(this.network);
|
|
758
|
+
}
|
|
759
|
+
/**
|
|
760
|
+
* @deprecated - use utxolib.bitcoin.verifySignature() instead
|
|
761
|
+
*/
|
|
762
|
+
verifySignature(transaction, inputIndex, amount, verificationSettings = {}) {
|
|
763
|
+
if (transaction.network !== this.network) {
|
|
764
|
+
throw new Error(`network mismatch`);
|
|
765
|
+
}
|
|
766
|
+
return utxolib.bitgo.verifySignature(transaction, inputIndex, amount, {
|
|
767
|
+
signatureIndex: verificationSettings.signatureIndex,
|
|
768
|
+
publicKey: verificationSettings.publicKey ? Buffer.from(verificationSettings.publicKey, 'hex') : undefined,
|
|
769
|
+
});
|
|
770
|
+
}
|
|
771
|
+
/**
|
|
772
|
+
* Decompose a raw transaction into useful information, such as the total amounts,
|
|
773
|
+
* change amounts, and transaction outputs.
|
|
774
|
+
* @param params
|
|
775
|
+
*/
|
|
776
|
+
async explainTransaction(params) {
|
|
777
|
+
var _a, _b, _c;
|
|
778
|
+
const txHex = _.get(params, 'txHex');
|
|
779
|
+
if (!txHex || !_.isString(txHex) || !txHex.match(/^([a-f0-9]{2})+$/i)) {
|
|
780
|
+
throw new Error('invalid transaction hex, must be a valid hex string');
|
|
781
|
+
}
|
|
782
|
+
let transaction;
|
|
783
|
+
try {
|
|
784
|
+
transaction = this.createTransactionFromHex(txHex);
|
|
785
|
+
}
|
|
786
|
+
catch (e) {
|
|
787
|
+
throw new Error('failed to parse transaction hex');
|
|
788
|
+
}
|
|
789
|
+
const id = transaction.getId();
|
|
790
|
+
let spendAmount = 0;
|
|
791
|
+
let changeAmount = 0;
|
|
792
|
+
const explanation = {
|
|
793
|
+
displayOrder: ['id', 'outputAmount', 'changeAmount', 'outputs', 'changeOutputs'],
|
|
794
|
+
id: id,
|
|
795
|
+
outputs: [],
|
|
796
|
+
changeOutputs: [],
|
|
797
|
+
};
|
|
798
|
+
const { changeAddresses = [], unspents = [] } = (_a = params.txInfo) !== null && _a !== void 0 ? _a : {};
|
|
799
|
+
transaction.outs.forEach((currentOutput) => {
|
|
800
|
+
const currentAddress = utxolib.address.fromOutputScript(currentOutput.script, this.network);
|
|
801
|
+
const currentAmount = currentOutput.value;
|
|
802
|
+
if (changeAddresses.includes(currentAddress)) {
|
|
803
|
+
// this is change
|
|
804
|
+
changeAmount += currentAmount;
|
|
805
|
+
explanation.changeOutputs.push({
|
|
806
|
+
address: currentAddress,
|
|
807
|
+
amount: currentAmount,
|
|
808
|
+
});
|
|
809
|
+
return;
|
|
810
|
+
}
|
|
811
|
+
spendAmount += currentAmount;
|
|
812
|
+
explanation.outputs.push({
|
|
813
|
+
address: currentAddress,
|
|
814
|
+
amount: currentAmount,
|
|
815
|
+
});
|
|
816
|
+
});
|
|
817
|
+
explanation.outputAmount = spendAmount;
|
|
818
|
+
explanation.changeAmount = changeAmount;
|
|
819
|
+
// add fee info if available
|
|
820
|
+
if (params.feeInfo) {
|
|
821
|
+
explanation.displayOrder.push('fee');
|
|
822
|
+
explanation.fee = params.feeInfo;
|
|
823
|
+
}
|
|
824
|
+
if (_.isInteger(transaction.locktime) && transaction.locktime > 0) {
|
|
825
|
+
explanation.locktime = transaction.locktime;
|
|
826
|
+
explanation.displayOrder.push('locktime');
|
|
827
|
+
}
|
|
828
|
+
const prevOutputs = (_b = params.txInfo) === null || _b === void 0 ? void 0 : _b.unspents.map((u) => bitgo_1.toOutput(u, this.network));
|
|
829
|
+
// if keys are provided, prepare the keys for input signature checking
|
|
830
|
+
const keys = (_c = params.pubs) === null || _c === void 0 ? void 0 : _c.map((xpub) => bip32.fromBase58(xpub));
|
|
831
|
+
const walletKeys = keys && keys.length === 3 ? new bitgo_1.RootWalletKeys(keys) : undefined;
|
|
832
|
+
// get the number of signatures per input
|
|
833
|
+
const inputSignatureCounts = transaction.ins.map((input, idx) => {
|
|
834
|
+
if (unspents.length !== transaction.ins.length) {
|
|
835
|
+
return 0;
|
|
836
|
+
}
|
|
837
|
+
if (!prevOutputs) {
|
|
838
|
+
throw new Error(`invalid state`);
|
|
839
|
+
}
|
|
840
|
+
if (!walletKeys) {
|
|
841
|
+
// no pub keys or incorrect number of pub keys
|
|
842
|
+
return 0;
|
|
843
|
+
}
|
|
844
|
+
try {
|
|
845
|
+
return bitgo_1.verifySignatureWithUnspent(transaction, idx, unspents, walletKeys).filter((v) => v).length;
|
|
846
|
+
}
|
|
847
|
+
catch (e) {
|
|
848
|
+
// some other error occurred and we can't validate the signatures
|
|
849
|
+
return 0;
|
|
850
|
+
}
|
|
851
|
+
});
|
|
852
|
+
explanation.inputSignatures = inputSignatureCounts;
|
|
853
|
+
explanation.signatures = _.max(inputSignatureCounts);
|
|
854
|
+
return explanation;
|
|
855
|
+
}
|
|
856
|
+
/**
|
|
857
|
+
* Create a multisig address of a given type from a list of keychains and a signing threshold
|
|
858
|
+
* @param addressType
|
|
859
|
+
* @param signatureThreshold
|
|
860
|
+
* @param keys
|
|
861
|
+
*/
|
|
862
|
+
createMultiSigAddress(addressType, signatureThreshold, keys) {
|
|
863
|
+
const { scriptPubKey: outputScript, redeemScript, witnessScript, } = utxolib.bitgo.outputScripts.createOutputScript2of3(keys, addressType);
|
|
864
|
+
return {
|
|
865
|
+
outputScript,
|
|
866
|
+
redeemScript,
|
|
867
|
+
witnessScript,
|
|
868
|
+
address: utxolib.address.fromOutputScript(outputScript, this.network),
|
|
869
|
+
};
|
|
870
|
+
}
|
|
871
|
+
/**
|
|
872
|
+
* @deprecated - use {@see backupKeyRecovery}
|
|
873
|
+
* Builds a funds recovery transaction without BitGo
|
|
874
|
+
* @param params - {@see backupKeyRecovery}
|
|
875
|
+
*/
|
|
876
|
+
async recover(params) {
|
|
877
|
+
return backupKeyRecovery_1.backupKeyRecovery(this, this.bitgo, params);
|
|
878
|
+
}
|
|
879
|
+
/**
|
|
880
|
+
* Recover coin that was sent to wrong chain
|
|
881
|
+
* @param params
|
|
882
|
+
* @param params.txid The txid of the faulty transaction
|
|
883
|
+
* @param params.recoveryAddress address to send recovered funds to
|
|
884
|
+
* @param params.wallet the wallet that received the funds
|
|
885
|
+
* @param params.recoveryCoin the coin type of the wallet that received the funds
|
|
886
|
+
* @param params.signed return a half-signed transaction (default=true)
|
|
887
|
+
* @param params.walletPassphrase the wallet passphrase
|
|
888
|
+
* @param params.xprv the unencrypted xprv (used instead of wallet passphrase)
|
|
889
|
+
* @returns {*}
|
|
890
|
+
*/
|
|
891
|
+
async recoverFromWrongChain(params) {
|
|
892
|
+
const { txid, recoveryAddress, wallet, walletPassphrase, xprv } = params;
|
|
893
|
+
// params.recoveryCoin used to be params.coin, backwards compatibility
|
|
894
|
+
const recoveryCoin = params.coin || params.recoveryCoin;
|
|
895
|
+
if (!recoveryCoin) {
|
|
896
|
+
throw new Error('missing required object recoveryCoin');
|
|
897
|
+
}
|
|
898
|
+
// signed should default to true, and only be disabled if explicitly set to false (not undefined)
|
|
899
|
+
const signed = params.signed !== false;
|
|
900
|
+
const sourceCoinFamily = this.getFamily();
|
|
901
|
+
const recoveryCoinFamily = recoveryCoin.getFamily();
|
|
902
|
+
const supportedRecoveryCoins = config_1.supportedCrossChainRecoveries[sourceCoinFamily];
|
|
903
|
+
if (_.isUndefined(supportedRecoveryCoins) || !supportedRecoveryCoins.includes(recoveryCoinFamily)) {
|
|
904
|
+
throw new Error(`Recovery of ${sourceCoinFamily} balances from ${recoveryCoinFamily} wallets is not supported.`);
|
|
905
|
+
}
|
|
906
|
+
return await recovery_1.recoverCrossChain(this.bitgo, {
|
|
907
|
+
sourceCoin: this,
|
|
908
|
+
recoveryCoin,
|
|
909
|
+
walletId: wallet,
|
|
910
|
+
txid,
|
|
911
|
+
recoveryAddress,
|
|
912
|
+
walletPassphrase: signed ? walletPassphrase : undefined,
|
|
913
|
+
xprv: signed ? xprv : undefined,
|
|
914
|
+
});
|
|
915
|
+
}
|
|
916
|
+
/**
|
|
917
|
+
* Generate bip32 key pair
|
|
918
|
+
*
|
|
919
|
+
* @param seed
|
|
920
|
+
* @returns {Object} object with generated pub and prv
|
|
921
|
+
*/
|
|
922
|
+
generateKeyPair(seed) {
|
|
923
|
+
if (!seed) {
|
|
924
|
+
// An extended private key has both a normal 256 bit private key and a 256
|
|
925
|
+
// bit chain code, both of which must be random. 512 bits is therefore the
|
|
926
|
+
// maximum entropy and gives us maximum security against cracking.
|
|
927
|
+
seed = crypto_1.randomBytes(512 / 8);
|
|
928
|
+
}
|
|
929
|
+
const extendedKey = bip32.fromSeed(seed);
|
|
930
|
+
return {
|
|
931
|
+
pub: extendedKey.neutered().toBase58(),
|
|
932
|
+
prv: extendedKey.toBase58(),
|
|
933
|
+
};
|
|
934
|
+
}
|
|
935
|
+
async getExtraPrebuildParams(buildParams) {
|
|
936
|
+
return {};
|
|
937
|
+
}
|
|
938
|
+
preCreateBitGo(params) {
|
|
939
|
+
return;
|
|
940
|
+
}
|
|
941
|
+
async presignTransaction(params) {
|
|
942
|
+
return params;
|
|
943
|
+
}
|
|
944
|
+
async supplementGenerateWallet(walletParams, keychains) {
|
|
945
|
+
return walletParams;
|
|
946
|
+
}
|
|
947
|
+
transactionDataAllowed() {
|
|
948
|
+
return false;
|
|
949
|
+
}
|
|
950
|
+
valuelessTransferAllowed() {
|
|
951
|
+
return false;
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
exports.AbstractUtxoCoin = AbstractUtxoCoin;
|
|
955
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWJzdHJhY3RVdHhvQ29pbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9hYnN0cmFjdFV0eG9Db2luLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBOztHQUVHO0FBQ0gsK0JBQStCO0FBQy9CLDJDQUEyQztBQUMzQywwREFVd0M7QUFDeEMsb0RBQW9EO0FBQ3BELG1DQUFxQztBQUNyQyxrQ0FBa0M7QUFDbEMsNEJBQTRCO0FBRTVCLG9FQUFnRjtBQUNoRix5Q0FBcUc7QUFFckcsOENBdUN5QjtBQUN6QiwrQ0FBaUU7QUFFakUsTUFBTSxLQUFLLEdBQUcsUUFBUSxDQUFDLGVBQWUsQ0FBQyxDQUFDO0FBR3hDLHlEQUErRDtBQUMvRCxpQ0FBd0Q7QUFDeEQscUNBQXlEO0FBNkt6RCxNQUFzQixnQkFBaUIsU0FBUSxtQkFBUTtJQUtyRCxZQUFzQixLQUFnQixFQUFFLE9BQXdCO1FBQzlELEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUNiLElBQUksQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxFQUFFO1lBQ3hCLE1BQU0sSUFBSSxLQUFLLENBQUMsMkJBQTJCLENBQUMsQ0FBQztTQUM5QztRQUNELElBQUksQ0FBQyxRQUFRLEdBQUcsT0FBTyxDQUFDO0lBQzFCLENBQUM7SUFFRCxJQUFJLE9BQU87UUFDVCxPQUFPLElBQUksQ0FBQyxRQUFRLENBQUM7SUFDdkIsQ0FBQztJQUVELGlCQUFpQjtRQUNmLE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUVELGtCQUFrQjtJQUNsQixNQUFNLEtBQUssaUJBQWlCO1FBQzFCLE9BQU8sQ0FBQyxHQUFHLHFCQUFhLENBQUMsZUFBZSxDQUFDLENBQUM7SUFDNUMsQ0FBQztJQUVEOzs7T0FHRztJQUNILGFBQWE7UUFDWCxPQUFPLEdBQUcsQ0FBQztJQUNiLENBQUM7SUFFRDs7T0FFRztJQUNILGNBQWM7UUFDWixPQUFPLE9BQU8sQ0FBQztJQUNqQixDQUFDO0lB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RTtZQUN0QyxHQUFHLEVBQUUsV0FBVyxDQUFDLFFBQVEsRUFBRTtTQUM1QixDQUFDO0lBQ0osQ0FBQztJQUVELEtBQUssQ0FBQyxzQkFBc0IsQ0FBQyxXQUF1QztRQUNsRSxPQUFPLEVBQUUsQ0FBQztJQUNaLENBQUM7SUFFRCxjQUFjLENBQUMsTUFBNkI7UUFDMUMsT0FBTztJQUNULENBQUM7SUFFRCxLQUFLLENBQUMsa0JBQWtCLENBQUMsTUFBaUM7UUFDeEQsT0FBTyxNQUFNLENBQUM7SUFDaEIsQ0FBQztJQUVELEtBQUssQ0FBQyx3QkFBd0IsQ0FDNUIsWUFBNkMsRUFDN0MsU0FBMkI7UUFFM0IsT0FBTyxZQUFZLENBQUM7SUFDdEIsQ0FBQztJQUVELHNCQUFzQjtRQUNwQixPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFFRCx3QkFBd0I7UUFDdEIsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0NBQ0Y7QUE1bENELDRDQTRsQ0MiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBwcmV0dGllclxuICovXG5pbXBvcnQgKiBhcyBiaXAzMiBmcm9tICdiaXAzMic7XG5pbXBvcnQgKiBhcyB1dHhvbGliIGZyb20gJ0BiaXRnby91dHhvLWxpYic7XG5pbXBvcnQge1xuICBnZXRFeHRlcm5hbENoYWluQ29kZSxcbiAgaXNDaGFpbkNvZGUsXG4gIFJvb3RXYWxsZXRLZXlzLFxuICBzY3JpcHRUeXBlRm9yQ2hhaW4sXG4gIG91dHB1dFNjcmlwdHMsXG4gIHRvT3V0cHV0LFxuICBVbnNwZW50LFxuICB2ZXJpZnlTaWduYXR1cmVXaXRoVW5zcGVudCxcbiAgV2FsbGV0VW5zcGVudFNpZ25lcixcbn0gZnJvbSAnQGJpdGdvL3V0eG8tbGliL2Rpc3Qvc3JjL2JpdGdvJztcbmltcG9ydCAqIGFzIGJpdGNvaW5NZXNzYWdlIGZyb20gJ2JpdGNvaW5qcy1tZXNzYWdlJztcbmltcG9ydCB7IHJhbmRvbUJ5dGVzIH0gZnJvbSAnY3J5cHRvJztcbmltcG9ydCAqIGFzIGRlYnVnTGliIGZyb20gJ2RlYnVnJztcbmltcG9ydCAqIGFzIF8gZnJvbSAnbG9kYXNoJztcblxuaW1wb3J0IHsgYmFja3VwS2V5UmVjb3ZlcnksIFJlY292ZXJQYXJhbXMgfSBmcm9tICcuL3JlY292ZXJ5L2JhY2t1cEtleVJlY292ZXJ5JztcbmltcG9ydCB7IENyb3NzQ2hhaW5SZWNvdmVyeVNpZ25lZCwgQ3Jvc3NDaGFpblJlY292ZXJ5VW5zaWduZWQsIHJlY292ZXJDcm9zc0NoYWluIH0gZnJvbSAnLi9yZWNvdmVyeSc7XG5cbmltcG9ydCB7XG4gIEFkZHJlc3NDb2luU3BlY2lmaWMsXG4gIEFkZHJlc3NUeXBlQ2hhaW5NaXNtYXRjaEVycm9yLFxuICBCYXNlQ29pbixcbiAgQml0R29CYXNlLFxuICBFeHRyYVByZWJ1aWxkUGFyYW1zT3B0aW9ucyxcbiAgSGFsZlNpZ25lZFV0eG9UcmFuc2FjdGlvbixcbiAgSW52YWxpZEFkZHJlc3NEZXJpdmF0aW9uUHJvcGVydHlFcnJvcixcbiAgSW52YWxpZEFkZHJlc3NFcnJvcixcbiAgSW52YWxpZEFkZHJlc3NWZXJpZmljYXRpb25PYmplY3RQcm9wZXJ0eUVycm9yLFxuICBJUmVxdWVzdFRyYWNlcixcbiAgSVRyYW5zYWN0aW9uRXhwbGFuYXRpb24gYXMgQmFzZVRyYW5zYWN0aW9uRXhwbGFuYXRpb24sXG4gIElXYWxsZXQsXG4gIEtleWNoYWluLFxuICBLZXljaGFpbnNUcmlwbGV0LFxuICBLZXlJbmRpY2VzLFxuICBQMnNoUDJ3c2hVbnN1cHBvcnRlZEVycm9yLFxuICBQMnRyVW5zdXBwb3J0ZWRFcnJvcixcbiAgUDJ3c2hVbnN1cHBvcnRlZEVycm9yLFxuICBQYXJzZWRUcmFuc2FjdGlvbiBhcyBCYXNlUGFyc2VkVHJhbnNhY3Rpb24sXG4gIFBhcnNlVHJhbnNhY3Rpb25PcHRpb25zIGFzIEJhc2VQYXJzZVRyYW5zYWN0aW9uT3B0aW9ucyxcbiAgUHJlY3JlYXRlQml0R29PcHRpb25zLFxuICBQcmVzaWduVHJhbnNhY3Rpb25PcHRpb25zLFxuICBwcm9taXNlUHJvcHMsXG4gIFJlcXVlc3RUcmFjZXIsXG4gIHNhbml0aXplTGVnYWN5UGF0aCxcbiAgU2lnbmVkVHJhbnNhY3Rpb24sXG4gIFNpZ25UcmFuc2FjdGlvbk9wdGlvbnMgYXMgQmFzZVNpZ25UcmFuc2FjdGlvbk9wdGlvbnMsXG4gIFN1cHBsZW1lbnRHZW5lcmF0ZVdhbGxldE9wdGlvbnMsXG4gIFRyYW5zYWN0aW9uUGFyYW1zIGFzIEJhc2VUcmFuc2FjdGlvblBhcmFtcyxcbiAgVHJhbnNhY3Rpb25QcmVidWlsZCBhcyBCYXNlVHJhbnNhY3Rpb25QcmVidWlsZCxcbiAgVHJhbnNhY3Rpb25SZWNpcGllbnQsXG4gIFRyaXBsZSxcbiAgVW5leHBlY3RlZEFkZHJlc3NFcnJvcixcbiAgVW5zdXBwb3J0ZWRBZGRyZXNzVHlwZUVycm9yLFxuICBWZXJpZmljYXRpb25PcHRpb25zLFxuICBWZXJpZnlBZGRyZXNzT3B0aW9ucyBhcyBCYXNlVmVyaWZ5QWRkcmVzc09wdGlvbnMsXG4gIFZlcmlmeVRyYW5zYWN0aW9uT3B0aW9ucyBhcyBCYXNlVmVyaWZ5VHJhbnNhY3Rpb25PcHRpb25zLFxuICBXYWxsZXQsXG59IGZyb20gJ0BiaXRnby9zZGstY29yZSc7XG5pbXBvcnQgeyBDdXN0b21DaGFuZ2VPcHRpb25zLCBwYXJzZU91dHB1dCB9IGZyb20gJy4vcGFyc2VPdXRwdXQnO1xuXG5jb25zdCBkZWJ1ZyA9IGRlYnVnTGliKCdiaXRnbzp2Mjp1dHhvJyk7XG5cbmltcG9ydCBTY3JpcHRUeXBlMk9mMyA9IHV0eG9saWIuYml0Z28ub3V0cHV0U2NyaXB0cy5TY3JpcHRUeXBlMk9mMztcbmltcG9ydCB7IGlzUmVwbGF5UHJvdGVjdGlvblVuc3BlbnQgfSBmcm9tICcuL3JlcGxheVByb3RlY3Rpb24nO1xuaW1wb3J0IHsgc2lnbkFuZFZlcmlmeVdhbGxldFRyYW5zYWN0aW9uIH0gZnJvbSAnLi9zaWduJztcbmltcG9ydCB7IHN1cHBvcnRlZENyb3NzQ2hhaW5SZWNvdmVyaWVzIH0gZnJvbSAnLi9jb25maWcnO1xuZXhwb3J0IGludGVyZmFjZSBWZXJpZnlBZGRyZXNzT3B0aW9ucyBleHRlbmRzIEJhc2VWZXJpZnlBZGRyZXNzT3B0aW9ucyB7XG4gIGNoYWluOiBudW1iZXI7XG4gIGluZGV4OiBudW1iZXI7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgT3V0cHV0IHtcbiAgYWRkcmVzczogc3RyaW5nO1xuICBhbW91bnQ6IHN0cmluZyB8IG51bWJlcjtcbiAgZXh0ZXJuYWw/OiBib29sZWFuO1xuICBuZWVkc0N1c3RvbUNoYW5nZUtleVNpZ25hdHVyZVZlcmlmaWNhdGlvbj86IGJvb2xlYW47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgVHJhbnNhY3Rpb25FeHBsYW5hdGlvbiBleHRlbmRzIEJhc2VUcmFuc2FjdGlvbkV4cGxhbmF0aW9uPHN0cmluZywgbnVtYmVyPiB7XG4gIGxvY2t0aW1lOiBudW1iZXI7XG4gIG91dHB1dHM6IE91dHB1dFtdO1xuICBjaGFuZ2VPdXRwdXRzOiBPdXRwdXRbXTtcblxuICAvKipcbiAgICogTnVtYmVyIG9mIGlucHV0IHNpZ25hdHVyZXMgcGVyIGlucHV0LlxuICAgKi9cbiAgaW5wdXRTaWduYXR1cmVzOiBudW1iZXJbXTtcblxuICAvKipcbiAgICogSGlnaGVzdCBpbnB1dCBzaWduYXR1cmUgY291bnQgZm9yIHRoZSB0cmFuc2FjdGlvblxuICAgKi9cbiAgc2lnbmF0dXJlczogbnVtYmVyO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFRyYW5zYWN0aW9uSW5mbyB7XG4gIC8qKiBNYXBzIHR4aWQgdG8gdHhoZXguIFJlcXVpcmVkIGZvciBvZmZsaW5lIHNpZ25pbmcuICovXG4gIHR4SGV4ZXM/OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+O1xuICBjaGFuZ2VBZGRyZXNzZXM/OiBzdHJpbmdbXTtcbiAgdW5zcGVudHM6IFVuc3BlbnRbXTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBFeHBsYWluVHJhbnNhY3Rpb25PcHRpb25zIHtcbiAgdHhIZXg6IHN0cmluZztcbiAgdHhJbmZvPzogVHJhbnNhY3Rpb25JbmZvO1xuICBmZWVJbmZvPzogc3RyaW5nO1xuICBwdWJzPzogVHJpcGxlPHN0cmluZz47XG59XG5cbmV4cG9ydCB0eXBlIFV0eG9OZXR3b3JrID0gdXR4b2xpYi5OZXR3b3JrO1xuXG5leHBvcnQgaW50ZXJmYWNlIFRyYW5zYWN0aW9uUHJlYnVpbGQgZXh0ZW5kcyBCYXNlVHJhbnNhY3Rpb25QcmVidWlsZCB7XG4gIHR4SW5mbz86IFRyYW5zYWN0aW9uSW5mbztcbiAgYmxvY2tIZWlnaHQ/OiBudW1iZXI7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgVHJhbnNhY3Rpb25QYXJhbXMgZXh0ZW5kcyBCYXNlVHJhbnNhY3Rpb25QYXJhbXMge1xuICB3YWxsZXRQYXNzcGhyYXNlPzogc3RyaW5nO1xuICBjaGFuZ2VBZGRyZXNzPzogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFBhcnNlVHJhbnNhY3Rpb25PcHRpb25zIGV4dGVuZHMgQmFzZVBhcnNlVHJhbnNhY3Rpb25PcHRpb25zIHtcbiAgdHhQYXJhbXM6IFRyYW5zYWN0aW9uUGFyYW1zO1xuICB0eFByZWJ1aWxkOiBUcmFuc2FjdGlvblByZWJ1aWxkO1xuICB3YWxsZXQ6IElXYWxsZXQ7XG4gIHZlcmlmaWNhdGlvbj86IFZlcmlmaWNhdGlvbk9wdGlvbnM7XG4gIHJlcUlkPzogSVJlcXVlc3RUcmFjZXI7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUGFyc2VkVHJhbnNhY3Rpb24gZXh0ZW5kcyBCYXNlUGFyc2VkVHJhbnNhY3Rpb24ge1xuICBrZXljaGFpbnM6IHtcbiAgICB1c2VyPzogS2V5Y2hhaW47XG4gICAgYmFja3VwPzogS2V5Y2hhaW47XG4gICAgYml0Z28/OiBLZXljaGFpbjtcbiAgfTtcbiAga2V5U2lnbmF0dXJlczoge1xuICAgIGJhY2t1cFB1Yj86IHN0cmluZztcbiAgICBiaXRnb1B1Yj86IHN0cmluZztcbiAgfTtcbiAgb3V0cHV0czogT3V0cHV0W107XG4gIG1pc3NpbmdPdXRwdXRzOiBPdXRwdXRbXTtcbiAgZXhwbGljaXRFeHRlcm5hbE91dHB1dHM6IE91dHB1dFtdO1xuICBpbXBsaWNpdEV4dGVybmFsT3V0cHV0czogT3V0cHV0W107XG4gIGNoYW5nZU91dHB1dHM6IE91dHB1dFtdO1xuICBleHBsaWNpdEV4dGVybmFsU3BlbmRBbW91bnQ6IG51bWJlcjtcbiAgaW1wbGljaXRFeHRlcm5hbFNwZW5kQW1vdW50OiBudW1iZXI7XG4gIG5lZWRzQ3VzdG9tQ2hhbmdlS2V5U2lnbmF0dXJlVmVyaWZpY2F0aW9uOiBib29sZWFuO1xuICBjdXN0b21DaGFuZ2U/OiBDdXN0b21DaGFuZ2VPcHRpb25zO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEdlbmVyYXRlQWRkcmVzc09wdGlvbnMge1xuICBhZGRyZXNzVHlwZT86IFNjcmlwdFR5cGUyT2YzO1xuICBrZXljaGFpbnM6IHtcbiAgICBwdWI6IHN0cmluZztcbiAgICBhc3BLZXlJZD86IHN0cmluZztcbiAgfVtdO1xuICB0aHJlc2hvbGQ/OiBudW1iZXI7XG4gIGNoYWluPzogbnVtYmVyO1xuICBpbmRleD86IG51bWJlcjtcbiAgc2Vnd2l0PzogYm9vbGVhbjtcbiAgYmVjaDMyPzogYm9vbGVhbjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBBZGRyZXNzRGV0YWlscyB7XG4gIGFkZHJlc3M6IHN0cmluZztcbiAgY2hhaW46IG51bWJlcjtcbiAgaW5kZXg6IG51bWJlcjtcbiAgY29pbjogc3RyaW5nO1xuICBjb2luU3BlY2lmaWM6IEFkZHJlc3NDb2luU3BlY2lmaWM7XG4gIGFkZHJlc3NUeXBlPzogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFNpZ25UcmFuc2FjdGlvbk9wdGlvbnMgZXh0ZW5kcyBCYXNlU2lnblRyYW5zYWN0aW9uT3B0aW9ucyB7XG4gIC8qKiBUcmFuc2FjdGlvbiBwcmVidWlsZCBmcm9tIGJpdGdvIHNlcnZlciAqL1xuICB0eFByZWJ1aWxkOiB7XG4gICAgdHhIZXg6IHN0cmluZztcbiAgICB0eEluZm86IFRyYW5zYWN0aW9uSW5mbztcbiAgfTtcbiAgLyoqIHhwcnYgb2YgdXNlciBrZXkgb3IgYmFja3VwIGtleSAqL1xuICBwcnY6IHN0cmluZztcbiAgLyoqIHhwdWJzIHRyaXBsZSBmb3Igd2FsbGV0ICh1c2VyLCBiYWNrdXAsIGJpdGdvKSAqL1xuICBwdWJzOiBUcmlwbGU8c3RyaW5nPjtcbiAgLyoqIHhwdWIgZm9yIGNvc2lnbmVyIChkZWZhdWx0cyB0byBiaXRnbykgKi9cbiAgY29zaWduZXJQdWI/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBXaGVuIHRydWUsIGNyZWF0ZXMgZnVsbC1zaWduZWQgdHJhbnNhY3Rpb24gd2l0aG91dCBwbGFjZWhvbGRlciBzaWduYXR1cmVzLlxuICAgKiBXaGVuIGZhbHNlLCBjcmVhdGVzIGhhbGYtc2lnbmVkIHRyYW5zYWN0aW9uIHdpdGggcGxhY2Vob2xkZXIgc2lnbmF0dXJlcy5cbiAgICovXG4gIGlzTGFzdFNpZ25hdHVyZT86IGJvb2xlYW47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgTXVsdGlTaWdBZGRyZXNzIHtcbiAgb3V0cHV0U2NyaXB0OiBCdWZmZXI7XG4gIHJlZGVlbVNjcmlwdD86IEJ1ZmZlcjtcbiAgd2l0bmVzc1NjcmlwdD86IEJ1ZmZlcjtcbiAgYWRkcmVzczogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFJlY292ZXJGcm9tV3JvbmdDaGFpbk9wdGlvbnMge1xuICB0eGlkOiBzdHJpbmc7XG4gIHJlY292ZXJ5QWRkcmVzczogc3RyaW5nO1xuICB3YWxsZXQ6IHN0cmluZztcbiAgd2FsbGV0UGFzc3BocmFzZT86IHN0cmluZztcbiAgeHBydj86IHN0cmluZztcbiAgLyoqIEBkZXByZWNhdGVkICovXG4gIGNvaW4/OiBBYnN0cmFjdFV0eG9Db2luO1xuICByZWNvdmVyeUNvaW4/OiBBYnN0cmFjdFV0eG9Db2luO1xuICBzaWduZWQ/OiBib29sZWFuO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEFkZHJlc3NJbmZvIHtcbiAgdHhDb3VudDogbnVtYmVyO1xuICB0b3RhbEJhbGFuY2U6IG51bWJlcjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBWZXJpZnlLZXlTaWduYXR1cmVzT3B0aW9ucyB7XG4gIHVzZXJLZXljaGFpbj86IEtleWNoYWluO1xuICBrZXljaGFpblRvVmVyaWZ5PzogS2V5Y2hhaW47XG4gIGtleVNpZ25hdHVyZT86IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBWZXJpZnlVc2VyUHVibGljS2V5T3B0aW9ucyB7XG4gIHVzZXJLZXljaGFpbj86IEtleWNoYWluO1xuICBkaXNhYmxlTmV0d29ya2luZzogYm9vbGVhbjtcbiAgdHhQYXJhbXM6IFRyYW5zYWN0aW9uUGFyYW1zO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFZlcmlmeVRyYW5zYWN0aW9uT3B0aW9ucyBleHRlbmRzIEJhc2VWZXJpZnlUcmFuc2FjdGlvbk9wdGlvbnMge1xuICB0eFByZWJ1aWxkOiBUcmFuc2FjdGlvblByZWJ1aWxkO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFVuc3BlbnRQYXJhbXMge1xuICBpZDogc3RyaW5nO1xuICB2YWx1ZTogbnVtYmVyO1xuICB2YWx1ZVN0cmluZzogc3RyaW5nO1xuICBhZGRyZXNzOiBzdHJpbmc7XG4gIGJsb2NrSGVpZ2h0OiBudW1iZXI7XG59XG5cbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBBYnN0cmFjdFV0eG9Db2luIGV4dGVuZHMgQmFzZUNvaW4ge1xuICBwdWJsaWMgYWx0U2NyaXB0SGFzaD86IG51bWJlcjtcbiAgcHVibGljIHN1cHBvcnRBbHRTY3JpcHREZXN0aW5hdGlvbj86IGJvb2xlYW47XG4gIHByaXZhdGUgcmVhZG9ubHkgX25ldHdvcms6IHV0eG9saWIuTmV0d29yaztcblxuICBwcm90ZWN0ZWQgY29uc3RydWN0b3IoYml0Z286IEJpdEdvQmFzZSwgbmV0d29yazogdXR4b2xpYi5OZXR3b3JrKSB7XG4gICAgc3VwZXIoYml0Z28pO1xuICAgIGlmICghXy5pc09iamVjdChuZXR3b3JrKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCduZXR3b3JrIG11c3QgYmUgYW4gb2JqZWN0Jyk7XG4gICAgfVxuICAgIHRoaXMuX25ldHdvcmsgPSBuZXR3b3JrO1xuICB9XG5cbiAgZ2V0IG5ldHdvcmsoKSB7XG4gICAgcmV0dXJuIHRoaXMuX25ldHdvcms7XG4gIH1cblxuICBzd2VlcFdpdGhTZW5kTWFueSgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIC8qKiBAZGVwcmVjYXRlZCAqL1xuICBzdGF0aWMgZ2V0IHZhbGlkQWRkcmVzc1R5cGVzKCk6IFNjcmlwdFR5cGUyT2YzW10ge1xuICAgIHJldHVybiBbLi4ub3V0cHV0U2NyaXB0cy5zY3JpcHRUeXBlczJPZjNdO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIGZhY3RvciBiZXR3ZWVuIHRoZSBiYXNlIHVuaXQgYW5kIGl0cyBzbWFsbGVzdCBzdWJkaXZpc29uXG4gICAqIEByZXR1cm4ge251bWJlcn1cbiAgICovXG4gIGdldEJhc2VGYWN0b3IoKSB7XG4gICAgcmV0dXJuIDFlODtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVwcmVjYXRlZFxuICAgKi9cbiAgZ2V0Q29pbkxpYnJhcnkoKSB7XG4gICAgcmV0dXJuIHV0eG9saWI7XG4gIH1cblxuICAvKipcbiAgICogSGVscGVyIHRvIGdldCB0aGUgdmVyc2lvbiBudW1iZXIgZm9yIGFuIGFkZHJlc3NcbiAgICovXG4gIHByb3RlY3RlZCBnZXRBZGRyZXNzVmVyc2lvbihhZGRyZXNzOiBzdHJpbmcpOiBudW1iZXIgfCB1bmRlZmluZWQge1xuICAgIC8vIHRyeSBkZWNvZGluZyBhcyBiYXNlNTggZmlyc3RcbiAgICB0cnkge1xuICAgICAgY29uc3QgeyB2ZXJzaW9uIH0gPSB1dHhvbGliLmFkZHJlc3MuZnJvbUJhc2U1OENoZWNrKGFkZHJlc3MsIHRoaXMubmV0d29yayk7XG4gICAgICByZXR1cm4gdmVyc2lvbjtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAvLyB0cnkgbmV4dCBmb3JtYXRcbiAgICB9XG5cbiAgICAvLyBpZiBjb2luIGRvZXMgbm90IHN1cHBvcnQgc2NyaXB0IHR5cGVzIHdpdGggYmVjaDMyIGVuY29kaW5nLCBkbyBub3QgYXR0ZW1wdCB0byBwYXJzZVxuICAgIGlmICghdGhpcy5zdXBwb3J0c0FkZHJlc3NUeXBlKCdwMndzaCcpICYmICF0aGlzLnN1cHBvcnRzQWRkcmVzc1R5cGUoJ3AydHInKSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIG90aGVyd2lzZSwgdHJ5IGRlY29kaW5nIGFzIGJlY2gzMlxuICAgIHRyeSB7XG4gICAgICBjb25zdCB7IHZlcnNpb24sIHByZWZpeCB9ID0gdXR4b2xpYi5hZGRyZXNzLmZyb21CZWNoMzIoYWRkcmVzcyk7XG4gICAgICBpZiAoXy5pc1N0cmluZyh0aGlzLm5ldHdvcmsuYmVjaDMyKSAmJiBwcmVmaXggPT09IHRoaXMubmV0d29yay5iZWNoMzIpIHtcbiAgICAgICAgcmV0dXJuIHZlcnNpb247XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgLy8gaWdub3JlIGVycm9ycywganVzdCBmYWxsIHRocm91Z2ggYW5kIHJldHVybiB1bmRlZmluZWRcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogSGVscGVyIHRvIGdldCB0aGUgYmVjaDMyIHByZWZpeCBmb3IgYW4gYWRkcmVzc1xuICAgKi9cbiAgcHJvdGVjdGVkIGdldEFkZHJlc3NQcmVmaXgoYWRkcmVzczogc3RyaW5nKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgICAvLyBvdGhlcndpc2UsIHRyeSBkZWNvZGluZyBhcyBiZWNoMzJcbiAgICB0cnkge1xuICAgICAgY29uc3QgeyBwcmVmaXggfSA9IHV0eG9saWIuYWRkcmVzcy5mcm9tQmVjaDMyKGFkZHJlc3MpO1xuICAgICAgcmV0dXJuIHByZWZpeDtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAvLyBpZ25vcmUgZXJyb3JzLCBqdXN0IGZhbGwgdGhyb3VnaCBhbmQgcmV0dXJuIHVuZGVmaW5lZFxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVjayBpZiBhbiBhZGRyZXNzIGlzIHZhbGlkXG4gICAqIEBwYXJhbSBhZGRyZXNzXG4gICAqIEBwYXJhbSBmb3JjZUFsdFNjcmlwdFN1cHBvcnRcbiAgICovXG4gIGlzVmFsaWRBZGRyZXNzKGFkZHJlc3M6IHN0cmluZywgZm9yY2VBbHRTY3JpcHRTdXBwb3J0ID0gZmFsc2UpOiBib29sZWFuIHtcbiAgICBjb25zdCB2YWxpZFZlcnNpb25zOiBudW1iZXJbXSA9IFt0aGlzLm5ldHdvcmsucHViS2V5SGFzaCwgdGhpcy5uZXR3b3JrLnNjcmlwdEhhc2hdO1xuICAgIGlmICh0aGlzLmFsdFNjcmlwdEhhc2ggJiYgKGZvcmNlQWx0U2NyaXB0U3VwcG9ydCB8fCB0aGlzLnN1cHBvcnRBbHRTY3JpcHREZXN0aW5hdGlvbikpIHtcbiAgICAgIHZhbGlkVmVyc2lvbnMucHVzaCh0aGlzLmFsdFNjcmlwdEhhc2gpO1xuICAgIH1cblxuICAgIGNvbnN0IGFkZHJlc3NWZXJzaW9uID0gdGhpcy5nZXRBZGRyZXNzVmVyc2lvbihhZGRyZXNzKTtcblxuICAgIC8vIHRoZSBhZGRyZXNzIHZlcnNpb24gbmVlZHMgdG8gYmUgYW1vbmcgdGhlIHZhbGlkIG9uZXNcbiAgICBjb25zdCBhZGRyZXNzVmVyc2lvblZhbGlkID0gXy5pc051bWJlcihhZGRyZXNzVmVyc2lvbikgJiYgdmFsaWRWZXJzaW9ucy5pbmNsdWRlcyhhZGRyZXNzVmVyc2lvbik7XG4gICAgY29uc3QgYWRkcmVzc1ByZWZpeCA9IHRoaXMuZ2V0QWRkcmVzc1ByZWZpeChhZGRyZXNzKTtcblxuICAgIGlmICghdGhpcy5zdXBwb3J0c0FkZHJlc3NUeXBlKCdwMndzaCcpIHx8IF8uaXNVbmRlZmluZWQoYWRkcmVzc1ByZWZpeCkpIHtcbiAgICAgIHJldHVybiBhZGRyZXNzVmVyc2lvblZhbGlkO1xuICAgIH1cblxuICAgIC8vIGFkZHJlc3MgaGFzIGEgcG90ZW50aWFsIGJlY2gzMiBwcmVmaXgsIHZhbGlkYXRlIHRoYXRcbiAgICByZXR1cm4gKFxuICAgICAgXy5pc1N0cmluZyh0aGlzLm5ldHdvcmsuYmVjaDMyKSAmJiB0aGlzLm5ldHdvcmsuYmVjaDMyID09PSBhZGRyZXNzUHJlZml4ICYmIGFkZHJlc3MgPT09IGFkZHJlc3MudG9Mb3dlckNhc2UoKVxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJuIGJvb2xlYW4gaW5kaWNhdGluZyB3aGV0aGVyIGlucHV0IGlzIHZhbGlkIHB1YmxpYyBrZXkgZm9yIHRoZSBjb2luLlxuICAgKlxuICAgKiBAcGFyYW0ge1N0cmluZ30gcHViIHRoZSBwdWIgdG8gYmUgY2hlY2tlZFxuICAgKiBAcmV0dXJucyB7Qm9vbGVhbn0gaXMgaXQgdmFsaWQ/XG4gICAqL1xuICBpc1ZhbGlkUHViKHB1Yjogc3RyaW5nKSB7XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiBiaXAzMi5mcm9tQmFzZTU4KHB1YikuaXNOZXV0ZXJlZCgpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRoZSBsYXRlc3QgYmxvY2sgaGVpZ2h0XG4gICAqIEBwYXJhbSByZXFJZFxuICAgKi9cbiAgYXN5bmMgZ2V0TGF0ZXN0QmxvY2tIZWlnaHQocmVxSWQ/OiBSZXF1ZXN0VHJhY2VyKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICBpZiAocmVxSWQpIHtcbiAgICAgIHRoaXMuYml0Z28uc2V0UmVxdWVzdFRyYWNlcihyZXFJZCk7XG4gICAgfVxuICAgIGNvbnN0IGNoYWluaGVhZCA9IGF3YWl0IHRoaXMuYml0Z28uZ2V0KHRoaXMudXJsKCcvcHVibGljL2Jsb2NrL2xhdGVzdCcpKS5yZXN1bHQoKTtcbiAgICByZXR1cm4gKGNoYWluaGVhZCBhcyBhbnkpLmhlaWdodDtcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW4gY3VzdG9tIGNvaW4gbG9naWMgYWZ0ZXIgYSB0cmFuc2FjdGlvbiBwcmVidWlsZCBoYXMgYmVlbiByZWNlaXZlZCBmcm9tIEJpdEdvXG4gICAqIEBwYXJhbSBwcmVidWlsZFxuICAgKi9cbiAgYXN5bmMgcG9zdFByb2Nlc3NQcmVidWlsZChwcmVidWlsZDogVHJhbnNhY3Rpb25QcmVidWlsZCk6IFByb21pc2U8VHJhbnNhY3Rpb25QcmVidWlsZD4ge1xuICAgIGlmIChfLmlzVW5kZWZpbmVkKHByZWJ1aWxkLnR4SGV4KSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdtaXNzaW5nIHJlcXVpcmVkIHR4UHJlYnVpbGQgcHJvcGVydHkgdHhIZXgnKTtcbiAgICB9XG4gICAgY29uc3QgdHJhbnNhY3Rpb24gPSB0aGlzLmNyZWF0ZVRyYW5zYWN0aW9uRnJvbUhleChwcmVidWlsZC50eEhleCk7XG4gICAgaWYgKF8uaXNVbmRlZmluZWQocHJlYnVpbGQuYmxvY2tIZWlnaHQpKSB7XG4gICAgICBwcmVidWlsZC5ibG9ja0hlaWdodCA9IChhd2FpdCB0aGlzLmdldExhdGVzdEJsb2NrSGVpZ2h0KCkpIGFzIG51bWJlcjtcbiAgICB9XG4gICAgLy8gTG9jayB0cmFuc2FjdGlvbiB0byB0aGUgbmV4dCBibG9jayB0byBkaXNjb3VyYWdlIGZlZSBzbmlwaW5nXG4gICAgLy8gU2VlOiBodHRwczovL2dpdGh1Yi5jb20vYml0Y29pbi9iaXRjb2luL2Jsb2IvZmIwYWM0ODJlZWU3NjFlYzE3ZWQyYzExZGYxMWUwNTQzNDdhMDI2ZC9zcmMvd2FsbGV0L3dhbGxldC5jcHAjTDIxMzNcbiAgICB0cmFuc2FjdGlvbi5sb2NrdGltZSA9IHByZWJ1aWxkLmJsb2NrSGVpZ2h0O1xuICAgIHJldHVybiBfLmV4dGVuZCh7fSwgcHJlYnVpbGQsIHsgdHhIZXg6IHRyYW5zYWN0aW9uLnRvSGV4KCkgfSk7XG4gIH1cblxuICAvKipcbiAgICogRmluZCBvdXRwdXRzIHRoYXQgYXJlIHdpdGhpbiBleHBlY3RlZCBvdXRwdXRzIGJ1dCBub3Qgd2l0aGluIGFjdHVhbCBvdXRwdXRzLCBpbmNsdWRpbmcgZHVwbGljYXRlc1xuICAgKiBAcGFyYW0gZXhwZWN0ZWRPdXRwdXRzXG4gICAqIEBwYXJhbSBhY3R1YWxPdXRwdXRzXG4gICAqIEByZXR1cm5zIHtBcnJheX1cbiAgICovXG4gIHByb3RlY3RlZCBzdGF0aWMgZmluZE1pc3NpbmdPdXRwdXRzKGV4cGVjdGVkT3V0cHV0czogT3V0cHV0W10sIGFjdHVhbE91dHB1dHM6IE91dHB1dFtdKTogT3V0cHV0W10ge1xuICAgIGNvbnN0IGtleUZ1bmMgPSAoeyBhZGRyZXNzLCBhbW91bnQgfTogT3V0cHV0KTogc3RyaW5nID0+IGAke2FkZHJlc3N9OiR7TnVtYmVyKGFtb3VudCl9YDtcbiAgICBjb25zdCBncm91cGVkT3V0cHV0cyA9IF8uZ3JvdXBCeShleHBlY3RlZE91dHB1dHMsIGtleUZ1bmMpO1xuXG4gICAgYWN0dWFsT3V0cHV0cy5mb3JFYWNoKChvdXRwdXQpID0+IHtcbiAgICAgIGNvbnN0IGdyb3VwID0gZ3JvdXBlZE91dHB1dHNba2V5RnVuYyhvdXRwdXQpXTtcbiAgICAgIGlmIChncm91cCkge1xuICAgICAgICBncm91cC5wb3AoKTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHJldHVybiBfLmZsYXR0ZW4oXy52YWx1ZXMoZ3JvdXBlZE91dHB1dHMpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZXRlcm1pbmUgYW4gYWRkcmVzcycgdHlwZSBiYXNlZCBvbiBpdHMgd2l0bmVzcyBhbmQgcmVkZWVtIHNjcmlwdCBwcmVzZW5jZVxuICAgKiBAcGFyYW0gYWRkcmVzc0RldGFpbHNcbiAgICovXG4gIHN0YXRpYyBpbmZlckFkZHJlc3NUeXBlKGFkZHJlc3NEZXRhaWxzOiB7IGNoYWluOiBudW1iZXIgfSk6IFNjcmlwdFR5cGUyT2YzIHwgbnVsbCB7XG4gICAgcmV0dXJuIGlzQ2hhaW5Db2RlKGFkZHJlc3NEZXRhaWxzLmNoYWluKSA/IHNjcmlwdFR5cGVGb3JDaGFpbihhZGRyZXNzRGV0YWlscy5jaGFpbikgOiBudWxsO1xuICB9XG5cbiAgY3JlYXRlVHJhbnNhY3Rpb25Gcm9tSGV4KGhleDogc3RyaW5nKSB7XG4gICAgcmV0dXJuIHV0eG9saWIuYml0Z28uY3JlYXRlVHJhbnNhY3Rpb25Gcm9tSGV4KGhleCwgdGhpcy5uZXR3b3JrKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFeHRyYWN0IGFuZCBmaWxsIHRyYW5zYWN0aW9uIGRldGFpbHMgc3VjaCBhcyBpbnRlcm5hbC9jaGFuZ2Ugc3BlbmQsIGV4dGVybmFsIHNwZW5kIChleHBsaWNpdCB2cy4gaW1wbGljaXQpLCBldGMuXG4gICAqIEBwYXJhbSBwYXJhbXNcbiAgICogQHJldHVybnMgeyp9XG4gICAqL1xuICBhc3luYyBwYXJzZVRyYW5zYWN0aW9uKHBhcmFtczogUGFyc2VUcmFuc2FjdGlvbk9wdGlvbnMpOiBQcm9taXNlPFBhcnNlZFRyYW5zYWN0aW9uPiB7XG4gICAgY29uc3QgeyB0eFBhcmFtcywgdHhQcmVidWlsZCwgd2FsbGV0LCB2ZXJpZmljYXRpb24gPSB7fSwgcmVxSWQgfSA9IHBhcmFtcztcblxuICAgIGlmICghXy5pc1VuZGVmaW5lZCh2ZXJpZmljYXRpb24uZGlzYWJsZU5ldHdvcmtpbmcpICYmICFfLmlzQm9vbGVhbih2ZXJpZmljYXRpb24uZGlzYWJsZU5ldHdvcmtpbmcpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ3ZlcmlmaWNhdGlvbi5kaXNhYmxlTmV0d29ya2luZyBtdXN0IGJlIGEgYm9vbGVhbicpO1xuICAgIH1cbiAgICBjb25zdCBkaXNhYmxlTmV0d29ya2luZyA9IHZlcmlmaWNhdGlvbi5kaXNhYmxlTmV0d29ya2luZztcblxuICAgIGNvbnN0IGZldGNoS2V5Y2hhaW5zID0gYXN5bmMgKHdhbGxldDogSVdhbGxldCk6IFByb21pc2U8VmVyaWZpY2F0aW9uT3B0aW9uc1sna2V5Y2hhaW5zJ10+ID0+IHtcbiAgICAgIHJldHVybiBwcm9taXNlUHJvcHMoe1xuICAgICAgICB1c2VyOiB0aGlzLmtleWNoYWlucygpLmdldCh7IGlkOiB3YWxsZXQua2V5SWRzKClbS2V5SW5kaWNlcy5VU0VSXSwgcmVxSWQgfSksXG4gICAgICAgIGJhY2t1cDogdGhpcy5rZXljaGFpbnMoKS5nZXQoeyBpZDogd2FsbGV0LmtleUlkcygpW0tleUluZGljZXMuQkFDS1VQXSwgcmVxSWQgfSksXG4gICAgICAgIGJpdGdvOiB0aGlzLmtleWNoYWlucygpLmdldCh7IGlkOiB3YWxsZXQua2V5SWRzKClbS2V5SW5kaWNlcy5CSVRHT10sIHJlcUlkIH0pLFxuICAgICAgfSk7XG4gICAgfTtcblxuICAgIC8vIG9idGFpbiB0aGUga2V5Y2hhaW5zIGFuZCBrZXkgc2lnbmF0dXJlc1xuICAgIGxldCBrZXljaGFpbnM6IFZlcmlmaWNhdGlvbk9wdGlvbnNbJ2tleWNoYWlucyddIHwgdW5kZWZpbmVkID0gdmVyaWZpY2F0aW9uLmtleWNoYWlucztcbiAgICBpZiAoIWtleWNoYWlucykge1xuICAgICAgaWYgKGRpc2FibGVOZXR3b3JraW5nKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignY2Fubm90IGZldGNoIGtleWNoYWlucyB3aXRob3V0IG5ldHdvcmtpbmcnKTtcbiAgICAgIH1cbiAgICAgIGtleWNoYWlucyA9IGF3YWl0IGZldGNoS2V5Y2hhaW5zKHdhbGxldCk7XG4gICAgfVxuXG4gICAgaWYgKCFrZXljaGFpbnMgfHwgIWtleWNoYWlucy51c2VyIHx8ICFrZXljaGFpbnMuYmFja3VwIHx8ICFrZXljaGFpbnMuYml0Z28pIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcigna2V5Y2hhaW5zIGFyZSByZXF1aXJlZCwgYnV0IGNvdWxkIG5vdCBiZSBmZXRjaGVkJyk7XG4gICAgfVxuXG4gICAgY29uc3Qga2V5Y2hhaW5BcnJheTogVHJpcGxlPEtleWNoYWluPiA9IFtrZXljaGFpbnMudXNlciwga2V5Y2hhaW5zLmJhY2t1cCwga2V5Y2hhaW5zLmJpdGdvXTtcblxuICAgIGNvbnN0IGtleVNpZ25hdHVyZXMgPSBfLmdldCh3YWxsZXQsICdfd2FsbGV0LmtleVNpZ25hdHVyZXMnKTtcblxuICAgIGlmIChfLmlzVW5kZWZpbmVkKHR4UHJlYnVpbGQudHhIZXgpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ21pc3NpbmcgcmVxdWlyZWQgdHhQcmVidWlsZCBwcm9wZXJ0eSB0eEhleCcpO1xuICAgIH1cbiAgICAvLyBvYnRhaW4gYWxsIG91dHB1dHNcbiAgICBjb25zdCBleHBsYW5hdGlvbjogVHJhbnNhY3Rpb25FeHBsYW5hdGlvbiA9IGF3YWl0IHRoaXMuZXhwbGFpblRyYW5zYWN0aW9uKHtcbiAgICAgIHR4SGV4OiB0eFByZWJ1aWxkLnR4SGV4LFxuICAgICAgdHhJbmZvOiB0eFByZWJ1aWxkLnR4SW5mbyxcbiAgICAgIHB1YnM6IGtleWNoYWluQXJyYXkubWFwKChrKSA9PiBrLnB1YikgYXMgVHJpcGxlPHN0cmluZz4sXG4gICAgfSk7XG5cbiAgICBjb25zdCBhbGxPdXRwdXRzID0gWy4uLmV4cGxhbmF0aW9uLm91dHB1dHMsIC4uLmV4cGxhbmF0aW9uLmNoYW5nZU91dHB1dHNdO1xuXG4gICAgLy8gdmVyaWZ5IHRoYXQgZWFjaCByZWNpcGllbnQgZnJvbSB0eFBhcmFtcyBoYXMgdGhlaXIgb3duIG91dHB1dFxuICAgIGNvbnN0IGV4cGVjdGVkT3V0cHV0cyA9IF8uZ2V0KHR4UGFyYW1zLCAncmVjaXBpZW50cycsIFtdIGFzIFRyYW5zYWN0aW9uUmVjaXBpZW50W10pLm1hcCgob3V0cHV0KSA9PiB7XG4gICAgICByZXR1cm4geyAuLi5vdXRwdXQsIGFkZHJlc3M6IHRoaXMuY2Fub25pY2FsQWRkcmVzcyhvdXRwdXQuYWRkcmVzcykgfTtcbiAgICB9KTtcblxuICAgIGNvbnN0IG1pc3NpbmdPdXRwdXRzID0gQWJzdHJhY3RVdHhvQ29pbi5maW5kTWlzc2luZ091dHB1dHMoZXhwZWN0ZWRPdXRwdXRzLCBhbGxPdXRwdXRzKTtcblxuICAgIC8vIGdldCB0aGUga2V5Y2hhaW5zIGZyb20gdGhlIGN1c3RvbSBjaGFuZ2Ugd2FsbGV0IGlmIG5lZWRlZFxuICAgIGxldCBjdXN0b21DaGFuZ2U6IEN1c3RvbUNoYW5nZU9wdGlvbnMgfCB1bmRlZmluZWQ7XG4gICAgY29uc3QgeyBjdXN0b21DaGFuZ2VXYWxsZXRJZCA9IHVuZGVmaW5lZCB9ID0gd2FsbGV0LmNvaW5TcGVjaWZpYygpIHx8IHt9O1xuICAgIGlmIChjdXN0b21DaGFuZ2VXYWxsZXRJZCkge1xuICAgICAgLy8gZmV0Y2gga2V5Y2hhaW5zIGZyb20gY3VzdG9tIGNoYW5nZSB3YWxsZXQgZm9yIGRlcml2aW5nIGFkZHJlc3Nlcy5cbiAgICAgIC8vIFRoZXNlIGtleWNoYWlucyBzaG91bGQgYmUgc2lnbmVkIGFuZCB0aGlzIHNob3VsZCBiZSB2ZXJpZmllZCBpbiB2ZXJpZnlUcmFuc2FjdGlvblxuICAgICAgY29uc3QgY3VzdG9tQ2hhbmdlS2V5U2lnbmF0dXJlcyA9IF8uZ2V0KHdhbGxldCwgJ193YWxsZXQuY3VzdG9tQ2hhbmdlS2V5U2lnbmF0dXJlcycsIHt9KTtcbiAgICAgIGNvbnN0IGN1c3RvbUNoYW5nZVdhbGxldDogV2FsbGV0ID0gYXdhaXQgdGhpcy53YWxsZXRzKCkuZ2V0KHsgaWQ6IGN1c3RvbUNoYW5nZVdhbGxldElkIH0pO1xuICAgICAgY29uc3QgY3VzdG9tQ2hhbmdlS2V5cyA9IGF3YWl0IGZldGNoS2V5Y2hhaW5zKGN1c3RvbUNoYW5nZVdhbGxldCk7XG5cbiAgICAgIGlmICghY3VzdG9tQ2hhbmdlS2V5cykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ2ZhaWxlZCB0byBmZXRjaCBrZXljaGFpbnMgZm9yIGN1c3RvbSBjaGFuZ2Ugd2FsbGV0Jyk7XG4gICAgICB9XG5cbiAgICAgIGlmIChjdXN0b21DaGFuZ2VLZXlzLnVzZXIgJiYgY3VzdG9tQ2hhbmdlS2V5cy5iYWNrdXAgJiYgY3VzdG9tQ2hhbmdlS2V5cy5iaXRnbyAmJiBjdXN0b21DaGFuZ2VXYWxsZXQpIHtcbiAgICAgICAgY29uc3QgY3VzdG9tQ2hhbmdlS2V5Y2hhaW5zOiBbS2V5Y2hhaW4sIEtleWNoYWluLCBLZXljaGFpbl0gPSBbXG4gICAgICAgICAgY3VzdG9tQ2hhbmdlS2V5cy51c2VyLFxuICAgICAgICAgIGN1c3RvbUNoYW5nZUtleXMuYmFja3VwLFxuICAgICAgICAgIGN1c3RvbUNoYW5nZUtleXMuYml0Z28sXG4gICAgICAgIF07XG5cbiAgICAgICAgY3VzdG9tQ2hhbmdlID0ge1xuICAgICAgICAgIGtleXM6IGN1c3RvbUNoYW5nZUtleWNoYWlucyxcbiAgICAgICAgICBzaWduYXR1cmVzOiBbXG4gICAgICAgICAgICBjdXN0b21DaGFuZ2VLZXlTaWduYXR1cmVzLnVzZXIsXG4gICAgICAgICAgICBjdXN0b21DaGFuZ2VLZXlTaWduYXR1cmVzLmJhY2t1cCxcbiAgICAgICAgICAgIGN1c3RvbUNoYW5nZUtleVNpZ25hdHVyZXMuYml0Z28sXG4gICAgICAgICAgXSxcbiAgICAgICAgfTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBMb29wIHRocm91Z2ggYWxsIHRoZSBvdXRwdXRzIGFuZCBjbGFzc2lmeSBlYWNoIG9mIHRoZW0gYXMgZWl0aGVyIGludGVybmFsIHNwZW5kc1xuICAgICAqIG9yIGV4dGVybmFsIHNwZW5kcyBieSBzZXR0aW5nIHRoZSBcImV4dGVybmFsXCIgcHJvcGVydHkgdG8gdHJ1ZSBvciBmYWxzZSBvbiB0aGUgb3V0cHV0IG9iamVjdC5cbiAgICAgKi9cbiAgICBjb25zdCBhbGxPdXRwdXREZXRhaWxzOiBPdXRwdXRbXSA9IGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgYWxsT3V0cHV0cy5tYXAoKGN1cnJlbnRPdXRwdXQpID0+IHtcbiAgICAgICAgcmV0dXJuIHBhcnNlT3V0cHV0KHtcbiAgICAgICAgICBjdXJyZW50T3V0cHV0LFxuICAgICAgICAgIGNvaW46IHRoaXMsXG4gICAgICAgICAgdHhQcmVidWlsZCxcbiAgICAgICAgICB2ZXJpZmljYXRpb24sXG4gICAgICAgICAga2V5Y2hhaW5BcnJheSxcbiAgICAgICAgICB3YWxsZXQsXG4gICAgICAgICAgdHhQYXJhbXMsXG4gICAgICAgICAgY3VzdG9tQ2hhbmdlLFxuICAgICAgICAgIHJlcUlkLFxuICAgICAgICB9KTtcbiAgICAgIH0pXG4gICAgKTtcblxuICAgIGNvbnN0IG5lZWRzQ3VzdG9tQ2hhbmdlS2V5U2lnbmF0dXJlVmVyaWZpY2F0aW9uID0gYWxsT3V0cHV0RGV0YWlscy5zb21lKFxuICAgICAgKG91dHB1dCkgPT4gb3V0cHV0Lm5lZWRzQ3VzdG9tQ2hhbmdlS2V5U2lnbmF0dXJlVmVyaWZpY2F0aW9uXG4gICAgKTtcblxuICAgIGNvbnN0IGNoYW5nZU91dHB1dHMgPSBfLmZpbHRlcihhbGxPdXRwdXREZXRhaWxzLCB7IGV4dGVybmFsOiBmYWxzZSB9KTtcblxuICAgIC8vIHRoZXNlIGFyZSBhbGwgdGhlIG91dHB1dHMgdGhhdCB3ZXJlIG5vdCBvcmlnaW5hbGx5IGV4cGxpY2l0bHkgc3BlY2lmaWVkIGluIHJlY2lwaWVudHNcbiAgICBjb25zdCBpbXBsaWNpdE91dHB1dHMgPSBBYnN0cmFjdFV0eG9Db2luLmZpbmRNaXNzaW5nT3V0cHV0cyhhbGxPdXRwdXREZXRhaWxzLCBleHBlY3RlZE91dHB1dHMpO1xuXG4gICAgY29uc3QgZXhwbGljaXRPdXRwdXRzID0gQWJzdHJhY3RVdHhvQ29pbi5maW5kTWlzc2luZ091dHB1dHMoYWxsT3V0cHV0RGV0YWlscywgaW1wbGljaXRPdXRwdXRzKTtcblxuICAgIC8vIHRoZXNlIGFyZSBhbGwgdGhlIG5vbi13YWxsZXQgb3V0cHV0cyB0aGF0IGhhZCBiZWVuIG9yaWdpbmFsbHkgZXhwbGljaXRseSBzcGVjaWZpZWQgaW4gcmVjaXBpZW50c1xuICAgIGNvbnN0IGV4cGxpY2l0RXh0ZXJuYWxPdXRwdXRzID0gXy5maWx0ZXIoZXhwbGljaXRPdXRwdXRzLCB7IGV4dGVybmFsOiB0cnVlIH0pO1xuXG4gICAgLy8gdGhpcyBpcyB0aGUgc3VtIG9mIGFsbCB0aGUgb3JpZ2luYWxseSBleHBsaWNpdGx5IHNwZWNpZmllZCBub24td2FsbGV0IG91dHB1dCB2YWx1ZXNcbiAgICBjb25zdCBleHBsaWNpdEV4dGVybmFsU3BlbmRBbW91bnQgPSBfLnN1bUJ5KGV4cGxpY2l0RXh0ZXJuYWxPdXRwdXRzLCAnYW1vdW50Jyk7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgY2FsY3VsYXRpb24gb2YgdGhlIGltcGxpY2l0IGV4dGVybmFsIHNwZW5kIGFtb3VudCBwZXJ0YWlucyB0byB2ZXJpZnlpbmcgdGhlIHBheS1hcy15b3UtZ28tZmVlIEJpdEdvXG4gICAgICogYXV0b21hdGljYWxseSBhcHBsaWVzIHRvIHRyYW5zYWN0aW9ucyBzZW5kaW5nIG1vbmV5IG91dCBvZiB0aGUgd2FsbGV0LiBUaGUgbG9naWMgaXMgZmFpcmx5IHN0cmFpZ2h0Zm9yd2FyZFxuICAgICAqIGluIHRoYXQgd2UgY29tcGFyZSB0aGUgZXh0ZXJuYWwgc3BlbmQgYW1vdW50IHRoYXQgd2FzIHNwZWNpZmllZCBleHBsaWNpdGx5IGJ5IHRoZSB1c2VyIHRvIHRoZSBwb3J0aW9uXG4gICAgICogdGhhdCB3YXMgc3BlY2lmaWVkIGltcGxpY2l0bHkuIFRvIHByb3RlY3QgY3VzdG9tZXJzIGZyb20gcGVvcGxlIHRhbXBlcmluZyB3aXRoIHRoZSB0cmFuc2FjdGlvbiBvdXRwdXRzLCB3ZVxuICAgICAqIGRlZmluZSBhIHRocmVzaG9sZCBmb3IgdGhlIG1heGltdW0gcGVyY2VudGFnZSBvZiB0aGUgaW1wbGljaXQgZXh0ZXJuYWwgc3BlbmQgaW4gcmVsYXRpb24gdG8gdGhlIGV4cGxpY2l0XG4gICAgICogZXh0ZXJuYWwgc3BlbmQuXG4gICAgICovXG5cbiAgICAvLyBtYWtlIHN1cmUgdGhhdCBhbGwgdGhlIGV4dHJhIGFkZHJlc3NlcyBhcmUgY2hhbmdlIGFkZHJlc3Nlc1xuICAgIC8vIGdldCBhbGwgdGhlIGFkZGl0aW9uYWwgZXh0ZXJuYWwgb3V0cHV0cyB0aGUgc2VydmVyIGFkZGVkIGFuZCBjYWxjdWxhdGUgdGhlaXIgdmFsdWVzXG4gICAgY29uc3QgaW1wbGljaXRFeHRlcm5hbE91dHB1dHMgPSBfLmZpbHRlcihpbXBsaWNpdE91dHB1dHMsIHsgZXh0ZXJuYWw6IHRydWUgfSk7XG4gICAgY29uc3QgaW1wbGljaXRFeHRlcm5hbFNwZW5kQW1vdW50ID0gXy5zdW1CeShpbXBsaWNpdEV4dGVybmFsT3V0cHV0cywgJ2Ftb3VudCcpO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIGtleWNoYWlucyxcbiAgICAgIGtleVNpZ25hdHVyZXMsXG4gICAgICBvdXRwdXRzOiBhbGxPdXRwdXREZXRhaWxzLFxuICAgICAgbWlzc2luZ091dHB1dHMsXG4gICAgICBleHBsaWNpdEV4dGVybmFsT3V0cHV0cyxcbiAgICAgIGltcGxpY2l0RXh0ZXJuYWxPdXRwdXRzLFxuICAgICAgY2hhbmdlT3V0cHV0cyxcbiAgICAgIGV4cGxpY2l0RXh0ZXJuYWxTcGVuZEFtb3VudCxcbiAgICAgIGltcGxpY2l0RXh0ZXJuYWxTcGVuZEFtb3VudCxcbiAgICAgIG5lZWRzQ3VzdG9tQ2hhbmdlS2V5U2lnbmF0dXJlVmVyaWZpY2F0aW9uLFxuICAgICAgY3VzdG9tQ2hhbmdlLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogRGVjcnlwdCB0aGUgd2FsbGV0J3MgdXNlciBwcml2YXRlIGtleSBhbmQgdmVyaWZ5IHRoYXQgdGhlIGNsYWltZWQgcHVibGljIGtleSBtYXRjaGVzXG4gICAqIEBwYXJhbSB7VmVyaWZ5VXNlclB1YmxpY0tleU9wdGlvbnN9IHBhcmFtc1xuICAgKiBAcmV0dXJuIHtib29sZWFufVxuICAgKiBAcHJvdGVjdGVkXG4gICAqL1xuICBwcm90ZWN0ZWQgdmVyaWZ5VXNlclB1YmxpY0tleShwYXJhbXM6IFZlcmlmeVVzZXJQdWJsaWNLZXlPcHRpb25zKTogYm9vbGVhbiB7XG4gICAgY29uc3QgeyB1c2VyS2V5Y2hhaW4sIHR4UGFyYW1zLCBkaXNhYmxlTmV0d29ya2luZyB9ID0gcGFyYW1zO1xuICAgIGlmICghdXNlcktleWNoYWluKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ3VzZXIga2V5Y2hhaW4gaXMgcmVxdWlyZWQnKTtcbiAgICB9XG5cbiAgICBjb25zdCB1c2VyUHViID0gdXNlcktleWNoYWluLnB1YjtcblxuICAgIC8vIGRlY3J5cHQgdGhlIHVzZXIgcHJpdmF0ZSBrZXkgc28gd2UgY2FuIHZlcmlmeSB0aGF0IHRoZSBjbGFpbWVkIHB1YmxpYyBrZXkgaXMgYSBtYXRjaFxuICAgIGxldCB1c2VyUHJ2ID0gdXNlcktleWNoYWluLnBydjtcbiAgICBpZiAoXy5pc0VtcHR5KHVzZXJQcnYpKSB7XG4gICAgICBjb25zdCBlbmNyeXB0ZWRQcnYgPSB1c2VyS2V5Y2hhaW4uZW5jcnlwdGVkUHJ2O1xuICAgICAgaWYgKGVuY3J5cHRlZFBydiAmJiAhXy5pc0VtcHR5KGVuY3J5cHRlZFBydikpIHtcbiAgICAgICAgLy8gaWYgdGhlIGRlY3J5cHRpb24gZmFpbHMsIGl0IHdpbGwgdGhyb3cgYW4gZXJyb3JcbiAgICAgICAgdXNlclBydiA9IHRoaXMuYml0Z28uZGVjcnlwdCh7XG4gICAgICAgICAgaW5wdXQ6IGVuY3J5cHRlZFBydixcbiAgICAgICAgICBwYXNzd29yZDogdHhQYXJhbXMud2FsbGV0UGFzc3BocmFzZSxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKCF1c2VyUHJ2KSB7XG4gICAgICBjb25zdCBlcnJvck1lc3NhZ2UgPSAndXNlciBwcml2YXRlIGtleSB1bmF2YWlsYWJsZSBmb3IgdmVyaWZpY2F0aW9uJztcbiAgICAgIGlmIChkaXNhYmxlTmV0d29ya2luZykge1xuICAgICAgICBjb25zb2xlLmxvZyhlcnJvck1lc3NhZ2UpO1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoZXJyb3JNZXNzYWdlKTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3QgdXNlclByaXZhdGVLZXkgPSBiaXAzMi5mcm9tQmFzZTU4KHVzZXJQcnYpO1xuICAgICAgaWYgKHVzZXJQcml2YXRlS2V5LnRvQmFzZTU4KCkgPT09IHVzZXJQcml2YXRlS2V5Lm5ldXRlcmVkKCkudG9CYXNlNTgoKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3VzZXIgcHJpdmF0ZSBrZXkgaXMgb25seSBwdWJsaWMnKTtcbiAgICAgIH1cbiAgICAgIGlmICh1c2VyUHJpdmF0ZUtleS5uZXV0ZXJlZCgpLnRvQmFzZTU4KCkgIT09IHVzZXJQdWIpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCd1c2VyIHByaXZhdGUga2V5IGRvZXMgbm90IG1hdGNoIHB1YmxpYyBrZXknKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWZXJpZnkgc2lnbmF0dXJlcyBwcm9kdWNlZCBieSB0aGUgdXNlciBrZXkgb3ZlciB0aGUgYmFja3VwIGFuZCBiaXRnbyBrZXlzLlxuICAgKlxuICAgKiBJZiBzZXQsIHRoZXNlIHNpZ25hdHVyZXMgZW5zdXJlIHRoYXQgdGhlIHdhbGxldCBrZXlzIGNhbm5vdCBiZSBjaGFuZ2VkIGFmdGVyIHRoZSB3YWxsZXQgaGFzIGJlZW4gY3JlYXRlZC5cbiAgICogQHBhcmFtIHtWZXJpZnlLZXlTaWduYXR1cmVzT3B0aW9uc30gcGFyYW1zXG4gICAqIEByZXR1cm4ge3tiYWNrdXA6IGJvb2xlYW4sIGJpdGdvOiBib29sZWFufX1cbiAgICovXG4gIHByb3RlY3RlZCB2ZXJpZnlLZXlTaWduYXR1cmUocGFyYW1zOiBWZXJpZnlLZXlTaWduYXR1cmVzT3B0aW9ucyk6IGJvb2xlYW4ge1xuICAgIC8vIGZpcnN0LCBsZXQncyB2ZXJpZnkgdGhlIGludGVncml0eSBvZiB0aGUgdXNlciBrZXksIHdob3NlIHB1YmxpYyBrZXkgaXMgdXNlZCBmb3Igc3Vic2VxdWVudCB2ZXJpZmljYXRpb25zXG4gICAgY29uc3QgeyB1c2VyS2V5Y2hhaW4sIGtleWNoYWluVG9WZXJpZnksIGtleVNpZ25hdHVyZSB9ID0gcGFyYW1zO1xuICAgIGlmICghdXNlcktleWNoYWluKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ3VzZXIga2V5Y2hhaW4gaXMgcmVxdWlyZWQnKTtcbiAgICB9XG5cbiAgICBpZiAoIWtleWNoYWluVG9WZXJpZnkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcigna2V5Y2hhaW4gdG8gdmVyaWZ5IGlzIHJlcXVpcmVkJyk7XG4gICAgfVxuXG4gICAgaWYgKCFrZXlTaWduYXR1cmUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcigna2V5IHNpZ25hdHVyZSBpcyByZXF1aXJlZCcpO1xuICAgIH1cblxuICAgIC8vIHZlcmlmeSB0aGUgc2lnbmF0dXJlIGFnYWluc3QgdGhlIHVzZXIgcHVibGljIGtleVxuICAgIGNvbnN0IHB1YmxpY0tleSA9IGJpcDMyLmZyb21CYXNlNTgodXNlcktleWNoYWluLnB1YikucHVibGljS2V5O1xuICAgIGNvbnN0IHNpZ25pbmdBZGRyZXNzID0gdXR4b2xpYi5hZGRyZXNzLnRvQmFzZTU4Q2hlY2soXG4gICAgICB1dHhvbGliLmNyeXB0by5oYXNoMTYwKHB1YmxpY0tleSksXG4gICAgICB1dHhvbGliLm5ldHdvcmtzLmJpdGNvaW4ucHViS2V5SGFzaCxcbiAgICAgIHRoaXMubmV0d29ya1xuICAgICk7XG5cbiAgICAvLyBCRy01NzAzOiB1c2UgQlRDIG1haW5uZXQgcHJlZml4IGZvciBhbGwga2V5IHNpZ25hdHVyZSBvcGVyYXRpb25zXG4gICAgLy8gKHRoaXMgbWVhbnMgZG8gbm90IHBhc3MgYSBwcmVmaXggcGFyYW1ldGVyLCBhbmQgbGV0IGl0IHVzZSB0aGUgZGVmYXVsdCBwcmVmaXggaW5zdGVhZClcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIGJpdGNvaW5NZXNzYWdlLnZlcmlmeShrZXljaGFpblRvVmVyaWZ5LnB1Yiwgc2lnbmluZ0FkZHJlc3MsIEJ1ZmZlci5mcm9tKGtleVNpZ25hdHVyZSwgJ2hleCcpKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBkZWJ1ZygnZXJyb3IgdGhyb3duIGZyb20gYml0Y29pbm1lc3NhZ2Ugd2hpbGUgdmVyaWZ5aW5nIGtleSBzaWduYXR1cmUnLCBlKTtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogVmVyaWZ5IHNpZ25hdHVyZXMgYWdhaW5zdCB0aGUgdXNlciBwcml2YXRlIGtleSBvdmVyIHRoZSBjaGFuZ2Ugd2FsbGV0IGV4dGVuZGVkIGtleXNcbiAgICogQHBhcmFtIHtQYXJzZWRUcmFuc2FjdGlvbn0gdHhcbiAgICogQHBhcmFtIHtLZXljaGFpbn0gdXNlcktleWNoYWluXG4gICAqIEByZXR1cm4ge2Jvb2xlYW59XG4gICAqIEBwcm90ZWN0ZWRcbiAgICovXG4gIHByb3RlY3RlZCB2ZXJpZnlDdXN0b21DaGFuZ2VLZXlTaWduYXR1cmVzKHR4OiBQYXJzZWRUcmFuc2FjdGlvbiwgdXNlcktleWNoYWluOiBLZXljaGFpbik6IGJvb2xlYW4ge1xuICAgIGlmICghdHguY3VzdG9tQ2hhbmdlKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ3BhcnNlZCB0cmFuc2FjdGlvbiBpcyBtaXNzaW5nIHJlcXVpcmVkIGN1c3RvbSBjaGFuZ2UgdmVyaWZpY2F0aW9uIGRhdGEnKTtcbiAgICB9XG5cbiAgICBpZiAoIUFycmF5LmlzQXJyYXkodHguY3VzdG9tQ2hhbmdlLmtleXMpIHx8ICFBcnJheS5pc0FycmF5KHR4LmN1c3RvbUNoYW5nZS5zaWduYXR1cmVzKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdjdXN0b21DaGFuZ2UgcHJvcGVydHkgaXMgbWlzc2luZyBrZXlzIG9yIHNpZ25hdHVyZXMnKTtcbiAgICB9XG5cbiAgICBmb3IgKGNvbnN0IGtleUluZGV4IG9mIFtLZXlJbmRpY2VzLlVTRVIsIEtleUluZGljZXMuQkFDS1VQLCBLZXlJbmRpY2VzLkJJVEdPXSkge1xuICAgICAgY29uc3Qga2V5Y2hhaW5Ub1ZlcmlmeSA9IHR4LmN1c3RvbUNoYW5nZS5rZXlzW2tleUluZGV4XTtcbiAgICAgIGNvbnN0IGtleVNpZ25hdHVyZSA9IHR4LmN1c3RvbUNoYW5nZS5zaWduYXR1cmVzW2tleUluZGV4XTtcbiAgICAgIGlmICgha2V5Y2hhaW5Ub1ZlcmlmeSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYG1pc3NpbmcgcmVxdWlyZWQgY3VzdG9tIGNoYW5nZSAke0tleUluZGljZXNba2V5SW5kZXhdLnRvTG93ZXJDYXNlKCl9IGtleWNoYWluIHB1YmxpYyBrZXlgKTtcbiAgICAgIH1cbiAgICAgIGlmICgha2V5U2lnbmF0dXJlKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgbWlzc2luZyByZXF1aXJlZCBjdXN0b20gY2hhbmdlICR7S2V5SW5kaWNlc1trZXlJbmRleF0udG9Mb3dlckNhc2UoKX0ga2V5Y2hhaW4gc2lnbmF0dXJlYCk7XG4gICAgICB9XG4gICAgICBpZiAoIXRoaXMudmVyaWZ5S2V5U2lnbmF0dXJlKHsgdXNlcktleWNoYWluLCBrZXljaGFpblRvVmVyaWZ5LCBrZXlTaWduYXR1cmUgfSkpIHtcbiAgICAgICAgZGVidWcoJ2ZhaWxlZCB0byB2ZXJpZnkgY3VzdG9tIGNoYW5nZSAlcyBrZXkgc2lnbmF0dXJlIScsIEtleUluZGljZXNba2V5SW5kZXhdLnRvTG93ZXJDYXNlKCkpO1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRoZSBtYXhpbXVtIHBlcmNlbnRhZ2UgbGltaXQgZm9yIHBheS1hcy15b3UtZ28gb3V0cHV0c1xuICAgKlxuICAgKiBAcHJvdGVjdGVkXG4gICAqL1xuICBwcm90ZWN0ZWQgZ2V0UGF5R29MaW1pdChhbGxvd1BheWdvT3V0cHV0PzogYm9vbGVhbik6IG51bWJlciB7XG4gICAgLy8gYWxsb3dpbmcgcGF5Z28gb3V0cHV0cyBuZWVkcyB0byBiZSB0aGUgZGVmYXVsdCBiZWhhdmlvciwgc28gb25seSBkaXNhbGxvdyBwYXlnbyBvdXRwdXRzIGlmIHRoZVxuICAgIC8vIHJlbGV2YW50IHZlcmlmaWNhdGlvbiBvcHRpb24gaXMgYm90aCBzZXQgYW5kIGZhbHNlXG4gICAgaWYgKCFfLmlzTmlsKGFsbG93UGF5Z29PdXRwdXQpICYmICFhbGxvd1BheWdvT3V0cHV0KSB7XG4gICAgICByZXR1cm4gMDtcbiAgICB9XG4gICAgLy8gMTUwIGJhc2lzIHBvaW50cyBpcyB0aGUgYWJzb2x1dGUgcGVybWl0dGVkIG1heGltdW0gaWYgcGF5Z28gb3V0cHV0cyBhcmUgYWxsb3dlZFxuICAgIHJldHVybiAwLjAxNTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWZXJpZnkgdGhhdCBhIHRyYW5zYWN0aW9uIHByZWJ1aWxkIGNvbXBsaWVzIHdpdGggdGhlIG9yaWdpbmFsIGludGVudGlvblxuICAgKlxuICAgKiBAcGFyYW0gcGFyYW1zXG4gICAqIEBwYXJhbSBwYXJhbXMudHhQYXJhbXMgcGFyYW1zIG9iamVjdCBwYXNzZWQgdG8gc2VuZFxuICAgKiBAcGFyYW0gcGFyYW1zLnR4UHJlYnVpbGQgcHJlYnVpbGQgb2JqZWN0IHJldHVybmVkIGJ5IHNlcnZlclxuICAgKiBAcGFyYW0gcGFyYW1zLnR4UHJlYnVpbGQudHhIZXggcHJlYnVpbHQgdHJhbnNhY3Rpb24ncyB0eEhleCBmb3JtXG4gICAqIEBwYXJhbSBwYXJhbXMud2FsbGV0IFdhbGxldCBvYmplY3QgdG8gb2J0YWluIGtleXMgdG8gdmVyaWZ5IGFnYWluc3RcbiAgICogQHBhcmFtIHBhcmFtcy52ZXJpZmljYXRpb24gT2JqZWN0IHNwZWNpZnlpbmcgc29tZSB2ZXJpZmljYXRpb24gcGFyYW1ldGVyc1xuICAgKiBAcGFyYW0gcGFyYW1zLnZlcmlmaWNhdGlvbi5kaXNhYmxlTmV0d29ya2luZyBEaXNhbGxvdyBmZXRjaGluZyBhbnkgZGF0YSBmcm9tIHRoZSBpbnRlcm5ldCBmb3IgdmVyaWZpY2F0aW9uIHB1cnBvc2VzXG4gICAqIEBwYXJhbSBwYXJhbXMudmVyaWZpY2F0aW9uLmtleWNoYWlucyBQYXNzIGtleWNoYWlucyBtYW51YWxseSByYXRoZXIgdGhhbiBmZXRjaGluZyB0aGVtIGJ5IGlkXG4gICAqIEBwYXJhbSBwYXJhbXMudmVyaWZpY2F0aW9uLmFkZHJlc3NlcyBBZGRyZXNzIGRldGFpbHMgdG8gcGFzcyBpbiBmb3Igb3V0LW9mLWJhbmQgdmVyaWZpY2F0aW9uXG4gICAqIEByZXR1cm5zIHtib29sZWFufVxuICAgKi9cbiAgYXN5bmMgdmVyaWZ5VHJhbnNhY3Rpb24ocGFyYW1zOiBWZXJpZnlUcmFuc2FjdGlvbk9wdGlvbnMpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICBjb25zdCB7IHR4UGFyYW1zLCB0eFByZWJ1aWxkLCB3YWxsZXQsIHZlcmlmaWNhdGlvbiA9IHsgYWxsb3dQYXlnb091dHB1dDogdHJ1ZSB9LCByZXFJZCB9ID0gcGFyYW1zO1xuICAgIGNvbnN0IGRpc2FibGVOZXR3b3JraW5nID0gISF2ZXJpZmljYXRpb24uZGlzYWJsZU5ldHdvcmtpbmc7XG4gICAgY29uc3QgcGFyc2VkVHJhbnNhY3Rpb246IFBhcnNlZFRyYW5zYWN0aW9uID0gYXdhaXQgdGhpcy5wYXJzZVRyYW5zYWN0aW9uKHtcbiAgICAgIHR4UGFyYW1zLFxuICAgICAgdHhQcmVidWlsZCxcbiAgICAgIHdhbGxldCxcbiAgICAgIHZlcmlmaWNhdGlvbixcbiAgICAgIHJlcUlkLFxuICAgIH0pO1xuXG4gICAgY29uc3Qga2V5Y2hhaW5zID0gcGFyc2VkVHJhbnNhY3Rpb24ua2V5Y2hhaW5zO1xuXG4gICAgLy8gdmVyaWZ5IHRoYXQgdGhlIGNsYWltZWQgdXNlciBwdWJsaWMga2V5IGNvcnJlc3BvbmRzIHRvIHRoZSB3YWxsZXQncyB1c2VyIHByaXZhdGUga2V5XG4gICAgbGV0IHVzZXJQdWJsaWNLZXlWZXJpZmllZCA9IGZhbHNlO1xuICAgIHRyeSB7XG4gICAgICAvLyB2ZXJpZnkgdGhlIHVzZXIgcHVibGljIGtleSBtYXRjaGVzIHRoZSBwcml2YXRlIGtleSAtIHRoaXMgd2lsbCB0aHJvdyBpZiB0aGVyZSBpcyBubyBtYXRjaFxuICAgICAgdXNlclB1YmxpY0tleVZlcmlmaWVkID0gdGhpcy52ZXJpZnlVc2VyUHVibGljS2V5KHsgdXNlcktleWNoYWluOiBrZXljaGFpbnMudXNlciwgZGlzYWJsZU5ldHdvcmtpbmcsIHR4UGFyYW1zIH0pO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIGRlYnVnKCdmYWlsZWQgdG8gdmVyaWZ5IHVzZXIgcHVibGljIGtleSEnLCBlKTtcbiAgICB9XG5cbiAgICAvLyBsZXQncyB2ZXJpZnkgdGhlc2Uga2V5Y2hhaW5zXG4gICAgY29uc3Qga2V5U2lnbmF0dXJlcyA9IHBhcnNlZFRyYW5zYWN0aW9uLmtleVNpZ25hdHVyZXM7XG4gICAgaWYgKCFfLmlzRW1wdHkoa2V5U2lnbmF0dXJlcykpIHtcbiAgICAgIGNvbnN0IHZlcmlmeSA9IChrZXksIHB1YikgPT5cbiAgICAgICAgdGhpcy52ZXJpZnlLZXlTaWduYXR1cmUoeyB1c2VyS2V5Y2hhaW46IGtleWNoYWlucy51c2VyLCBrZXljaGFpblRvVmVyaWZ5OiBrZXksIGtleVNpZ25hdHVyZTogcHViIH0pO1xuICAgICAgY29uc3QgaXNCYWNrdXBLZXlTaWduYXR1cmVWYWxpZCA9IHZlcmlmeShrZXljaGFpbnMuYmFja3VwLCBrZXlTaWduYXR1cmVzLmJhY2t1cFB1Yik7XG4gICAgICBjb25zdCBpc0JpdGdvS2V5U2lnbmF0dXJlVmFsaWQgPSB2ZXJpZnkoa2V5Y2hhaW5zLmJpdGdvLCBrZXlTaWduYXR1cmVzLmJpdGdvUHViKTtcbiAgICAgIGlmICghaXNCYWNrdXBLZXlTaWduYXR1cmVWYWxpZCB8fCAhaXNCaXRnb0tleVNpZ25hdHVyZVZhbGlkKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignc2Vjb25kYXJ5IHB1YmxpYyBrZXkgc2lnbmF0dXJlcyBpbnZhbGlkJyk7XG4gICAgICB9XG4gICAgICBkZWJ1Zygnc3VjY2Vzc2Z1bGx5IHZlcmlmaWVkIGJhY2t1cCBhbmQgYml0Z28ga2V5IHNpZ25hdHVyZXMnKTtcbiAgICB9IGVsc2UgaWYgKCFkaXNhYmxlTmV0d29ya2luZykge1xuICAgICAgLy8gdGhlc2Uga2V5cyB3ZXJlIG9idGFpbmVkIG9ubGluZSBhbmQgdGhlaXIgc2lnbmF0dXJlcyB3ZXJlIG5vdCB2ZXJpZmllZFxuICAgICAgLy8gdGhpcyBjb3VsZCBiZSBkYW5nZXJvdXNcbiAgICAgIGNvbnNvbGUubG9nKCd1bnNpZ25lZCBrZXlzIG9idGFpbmVkIG9ubGluZSBhcmUgYmVpbmcgdXNlZCBmb3IgYWRkcmVzcyB2ZXJpZmljYXRpb24nKTtcbiAgICB9XG5cbiAgICBpZiAocGFyc2VkVHJhbnNhY3Rpb24ubmVlZHNDdXN0b21DaGFuZ2VLZXlTaWduYXR1cmVWZXJpZmljYXRpb24pIHtcbiAgICAgIGlmICgha2V5Y2hhaW5zLnVzZXIgfHwgIXVzZXJQdWJsaWNLZXlWZXJpZmllZCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3RyYW5zYWN0aW9uIHJlcXVpcmVzIHZlcmlmaWNhdGlvbiBvZiB1c2VyIHB1YmxpYyBrZXksIGJ1dCBpdCB3YXMgdW5hYmxlIHRvIGJlIHZlcmlmaWVkJyk7XG4gICAgICB9XG4gICAgICBjb25zdCBjdXN0b21DaGFuZ2VLZXlTaWduYXR1cmVzVmVyaWZpZWQgPSB0aGlzLnZlcmlmeUN1c3RvbUNoYW5nZUtleVNpZ25hdHVyZXMocGFyc2VkVHJhbnNhY3Rpb24sIGtleWNoYWlucy51c2VyKTtcbiAgICAgIGlmICghY3VzdG9tQ2hhbmdlS2V5U2lnbmF0dXJlc1ZlcmlmaWVkKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAndHJhbnNhY3Rpb24gcmVxdWlyZXMgdmVyaWZpY2F0aW9uIG9mIGN1c3RvbSBjaGFuZ2Uga2V5IHNpZ25hdHVyZXMsIGJ1dCB0aGV5IHdlcmUgdW5hYmxlIHRvIGJlIHZlcmlmaWVkJ1xuICAgICAgICApO1xuICAgICAgfVxuICAgICAgZGVidWcoJ3N1Y2Nlc3NmdWxseSB2ZXJpZmllZCB1c2VyIHB1YmxpYyBrZXkgYW5kIGN1c3RvbSBjaGFuZ2Uga2V5IHNpZ25hdHVyZXMnKTtcbiAgICB9XG5cbiAgICBjb25zdCBtaXNzaW5nT3V0cHV0cyA9IHBhcnNlZFRyYW5zYWN0aW9uLm1pc3NpbmdPdXRwdXRzO1xuICAgIGlmIChtaXNzaW5nT3V0cHV0cy5sZW5ndGggIT09IDApIHtcbiAgICAgIC8vIHRoZXJlIGFyZSBzb21lIG91dHB1dHMgaW4gdGhlIHJlY2lwaWVudHMgbGlzdCB0aGF0IGhhdmUgbm90IG1hZGUgaXQgaW50byB0aGUgYWN0dWFsIHRyYW5zYWN0aW9uXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2V4cGVjdGVkIG91dHB1dHMgbWlzc2luZyBpbiB0cmFuc2FjdGlvbiBwcmVidWlsZCcpO1xuICAgIH1cblxuICAgIGNvbnN0IGludGVuZGVkRXh0ZXJuYWxTcGVuZCA9IHBhcnNlZFRyYW5zYWN0aW9uLmV4cGxpY2l0RXh0ZXJuYWxTcGVuZEFtb3VudDtcblxuICAgIC8vIHRoaXMgaXMgYSBsaW1pdCB3ZSBpbXBvc2UgZm9yIHRoZSB0b3RhbCB2YWx1ZSB0aGF0IGlzIGFtZW5kZWQgdG8gdGhlIHRyYW5zYWN0aW9uIGJleW9uZCB3aGF0IHdhcyBvcmlnaW5hbGx5IGludGVuZGVkXG4gICAgY29uc3QgcGF5QXNZb3VHb0xpbWl0ID0gaW50ZW5kZWRFeHRlcm5hbFNwZW5kICogdGhpcy5nZXRQYXlHb0xpbWl0KHZlcmlmaWNhdGlvbi5hbGxvd1BheWdvT3V0cHV0KTtcblxuICAgIC8qXG4gICAgU29tZSBleHBsYW5hdGlvbiBmb3Igd2h5IHdlJ3JlIGRvaW5nIHdoYXQgd2UncmUgZG9pbmc6XG4gICAgU29tZSBjdXN0b21lcnMgd2lsbCBoYXZlIGFuIG91dHB1dCB0byBCaXRHbydzIFBBWUdvIHdhbGxldCBhZGRlZCB0byB0aGVpciB0cmFuc2FjdGlvbiwgYW5kIHdlIG5lZWQgdG8gYWNjb3VudCBmb3JcbiAgICBpdCBoZXJlLiBUbyBwcm90ZWN0IHNvbWVvbmUgdGFtcGVyaW5nIHdpdGggdGhlIG91dHB1dCB0byBtYWtlIGl0IHNlbmQgbW9yZSB0aGFuIGl0IHNob3VsZCB0byBCaXRHbywgd2UgZGVmaW5lIGFcbiAgICB0aHJlc2hvbGQgZm9yIHRoZSBvdXRwdXQncyB2YWx1ZSBhYm92ZSB3aGljaCB3ZSdsbCB0aHJvdyBhbiBlcnJvciwgYmVjYXVzZSB0aGUgcGF5Z28gb3V0cHV0IHNob3VsZCBuZXZlciBiZSB0aGF0XG4gICAgaGlnaC5cbiAgICAgKi9cblxuICAgIC8vIG1ha2Ugc3VyZSB0aGF0IGFsbCB0aGUgZXh0cmEgYWRkcmVzc2VzIGFyZSBjaGFuZ2UgYWRkcmVzc2VzXG4gICAgLy8gZ2V0IGFsbCB0aGUgYWRkaXRpb25hbCBleHRlcm5hbCBvdXRwdXRzIHRoZSBzZXJ2ZXIgYWRkZWQgYW5kIGNhbGN1bGF0ZSB0aGVpciB2YWx1ZXNcbiAgICBjb25zdCBub25DaGFuZ2VBbW91bnQgPSBwYXJzZWRUcmFuc2FjdGlvbi5pbXBsaWNpdEV4dGVybmFsU3BlbmRBbW91bnQ7XG5cbiAgICBkZWJ1ZyhcbiAgICAgICdJbnRlbmRlZCBzcGVuZCBpcyAlcywgTm9uLWNoYW5nZSBhbW91bnQgaXMgJXMsIHBheWdvIGxpbWl0IGlzICVzJyxcbiAgICAgIGludGVuZGVkRXh0ZXJuYWxTcGVuZCxcbiAgICAgIG5vbkNoYW5nZUFtb3VudCxcbiAgICAgIHBheUFzWW91R29MaW1pdFxuICAgICk7XG5cbiAgICAvLyB0aGUgYWRkaXRpb25hbCBleHRlcm5hbCBvdXRwdXRzIGNhbiBvbmx5IGJlIEJpdEdvJ3MgcGF5LWFzLXlvdS1nbyBmZWUsIGJ1dCB3ZSBjYW5ub3QgdmVyaWZ5IHRoZSB3YWxsZXQgYWRkcmVzc1xuICAgIGlmIChub25DaGFuZ2VBbW91bnQgPiBwYXlBc1lvdUdvTGltaXQpIHtcbiAgICAgIC8vIHRoZXJlIGFyZSBzb21lIGFkZHJlc3NlcyB0aGF0IGFyZSBvdXRzaWRlIHRoZSBzY29wZSBvZiBpbnRlbmRlZCByZWNpcGllbnRzIHRoYXQgYXJlIG5vdCBjaGFuZ2UgYWRkcmVzc2VzXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ3ByZWJ1aWxkIGF0dGVtcHRzIHRvIHNwZW5kIHRvIHVuaW50ZW5kZWQgZXh0ZXJuYWwgcmVjaXBpZW50cycpO1xuICAgIH1cblxuICAgIGNvbnN0IGFsbE91dHB1dHMgPSBwYXJzZWRUcmFuc2FjdGlvbi5vdXRwdXRzO1xuICAgIGlmICghdHhQcmVidWlsZC50eEhleCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGB0eFByZWJ1aWxkLnR4SGV4IG5vdCBzZXRgKTtcbiAgICB9XG4gICAgY29uc3QgdHJhbnNhY3Rpb24gPSB0aGlzLmNyZWF0ZVRyYW5zYWN0aW9uRnJvbUhleCh0eFByZWJ1aWxkLnR4SGV4KTtcbiAgICBjb25zdCB0cmFuc2FjdGlvbkNhY2hlID0ge307XG4gICAgY29uc3QgaW5wdXRzID0gYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICB0cmFuc2FjdGlvbi5pbnMubWFwKGFzeW5jIChjdXJyZW50SW5wdXQpID0+IHtcbiAgICAgICAgY29uc3QgdHJhbnNhY3Rpb25JZCA9IChCdWZmZXIuZnJvbShjdXJyZW50SW5wdXQuaGFzaCkucmV2ZXJzZSgpIGFzIEJ1ZmZlcikudG9TdHJpbmcoJ2hleCcpO1xuICAgICAgICBjb25zdCB0eEhleCA9IHR4UHJlYnVpbGQudHhJbmZvPy50eEhleGVzPy5bdHJhbnNhY3Rpb25JZF07XG4gICAgICAgIGlmICh0eEhleCkge1xuICAgICAgICAgIGNvbnN0IGxvY2FsVHggPSB0aGlzLmNyZWF0ZVRyYW5zYWN0aW9uRnJvbUhleCh0eEhleCk7XG4gICAgICAgICAgaWYgKGxvY2FsVHguZ2V0SWQoKSAhPT0gdHJhbnNhY3Rpb25JZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdpbnB1dCB0cmFuc2FjdGlvbiBoZXggZG9lcyBub3QgbWF0Y2ggaWQnKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgY29uc3QgY3VycmVudE91dHB1dCA9IGxvY2FsVHgub3V0c1tjdXJyZW50SW5wdXQuaW5kZXhdO1xuICAgICAgICAgIGNvbnN0IGFkZHJlc3MgPSB1dHhvbGliLmFkZHJlc3MuZnJvbU91dHB1dFNjcmlwdChjdXJyZW50T3V0cHV0LnNjcmlwdCwgdGhpcy5uZXR3b3JrKTtcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgYWRkcmVzcyxcbiAgICAgICAgICAgIHZhbHVlOiBjdXJyZW50T3V0cHV0LnZhbHVlLFxuICAgICAgICAgIH07XG4gICAgICAgIH0gZWxzZSBpZiAoIXRyYW5zYWN0aW9uQ2FjaGVbdHJhbnNhY3Rpb25JZF0pIHtcbiAgICAgICAgICBpZiAoZGlzYWJsZU5ldHdvcmtpbmcpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignYXR0ZW1wdGluZyB0byByZXRyaWV2ZSB0cmFuc2FjdGlvbiBkZXRhaWxzIGV4dGVybmFsbHkgd2l0aCBuZXR3b3JraW5nIGRpc2FibGVkJyk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmIChyZXFJZCkge1xuICAgICAgICAgICAgdGhpcy5iaXRnby5zZXRSZXF1ZXN0VHJhY2VyKHJlcUlkKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgdHJhbnNhY3Rpb25DYWNoZVt0cmFuc2FjdGlvbklkXSA9IGF3YWl0IHRoaXMuYml0Z28uZ2V0KHRoaXMudXJsKGAvcHVibGljL3R4LyR7dHJhbnNhY3Rpb25JZH1gKSkucmVzdWx0KCk7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgdHJhbnNhY3Rpb25EZXRhaWxzID0gdHJhbnNhY3Rpb25DYWNoZVt0cmFuc2FjdGlvbklkXTtcbiAgICAgICAgcmV0dXJuIHRyYW5zYWN0aW9uRGV0YWlscy5vdXRwdXRzW2N1cnJlbnRJbnB1dC5pbmRleF07XG4gICAgICB9KVxuICAgICk7XG5cbiAgICBjb25zdCBpbnB1dEFtb3VudCA9IF8uc3VtQnkoaW5wdXRzLCAndmFsdWUnKTtcbiAgICBjb25zdCBvdXRwdXRBbW91bnQgPSBfLnN1bUJ5KGFsbE91dHB1dHMsICdhbW91bnQnKTtcbiAgICBjb25zdCBmZWUgPSBpbnB1dEFtb3VudCAtIG91dHB1dEFtb3VudDtcblxuICAgIGlmIChmZWUgPCAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBhdHRlbXB0aW5nIHRvIHNwZW5kICR7b3V0cHV0QW1vdW50fSBzYXRvc2hpcywgd2hpY2ggZXhjZWVkcyB0aGUgaW5wdXQgYW1vdW50ICgke2lucHV0QW1vdW50fSBzYXRvc2hpcykgYnkgJHstZmVlfWBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICAvKipcbiAgICogTWFrZSBzdXJlIGFuIGFkZHJlc3MgaXMgdmFsaWQgYW5kIHRocm93IGFuIGVycm9yIGlmIGl0J3Mgbm90LlxuICAgKiBAcGFyYW0gcGFyYW1zLmFkZHJlc3MgVGhlIGFkZHJlc3Mgc3RyaW5nIG9uIHRoZSBuZXR3b3JrXG4gICAqIEBwYXJhbSBwYXJhbXMuYWRkcmVzc1R5cGVcbiAgICogQHBhcmFtIHBhcmFtcy5rZXljaGFpbnMgS2V5Y2hhaW4gb2JqZWN0cyB3aXRoIHhwdWJzXG4gICAqIEBwYXJhbSBwYXJhbXMuY29pblNwZWNpZmljIENvaW4tc3BlY2lmaWMgZGV0YWlscyBmb3IgdGhlIGFkZHJlc3Mgc3VjaCBhcyBhIHdpdG5lc3Mgc2NyaXB0XG4gICAqIEBwYXJhbSBwYXJhbXMuY2hhaW4gRGVyaXZhdGlvbiBjaGFpblxuICAgKiBAcGFyYW0gcGFyYW1zLmluZGV4IERlcml2YXRpb24gaW5kZXhcbiAgICogQHRocm93cyB7SW52YWxpZEFkZHJlc3NFcnJvcn1cbiAgICogQHRocm93cyB7SW52YWxpZEFkZHJlc3NEZXJpdmF0aW9uUHJvcGVydHlFcnJvcn1cbiAgICogQHRocm93cyB7VW5leHBlY3RlZEFkZHJlc3NFcnJvcn1cbiAgICovXG4gIGlzV2FsbGV0QWRkcmVzcyhwYXJhbXM6IFZlcmlmeUFkZHJlc3NPcHRpb25zKTogYm9vbGVhbiB7XG4gICAgY29uc3QgeyBhZGRyZXNzLCBhZGRyZXNzVHlwZSwga2V5Y2hhaW5zLCBjb2luU3BlY2lmaWMsIGNoYWluLCBpbmRleCB9ID0gcGFyYW1zO1xuXG4gICAgaWYgKCF0aGlzLmlzVmFsaWRBZGRyZXNzKGFkZHJlc3MpKSB7XG4gICAgICB0aHJvdyBuZXcgSW52YWxpZEFkZHJlc3NFcnJvcihgaW52YWxpZCBhZGRyZXNzOiAke2FkZHJlc3N9YCk7XG4gICAgfVxuXG4gICAgaWYgKChfLmlzVW5kZWZpbmVkKGNoYWluKSAmJiBfLmlzVW5kZWZpbmVkKGluZGV4KSkgfHwgIShfLmlzRmluaXRlKGNoYWluKSAmJiBfLmlzRmluaXRlKGluZGV4KSkpIHtcbiAgICAgIHRocm93IG5ldyBJbnZhbGlkQWRkcmVzc0Rlcml2YXRpb25Qcm9wZXJ0eUVycm9yKFxuICAgICAgICBgYWRkcmVzcyB2YWxpZGF0aW9uIGZhaWx1cmU6IGludmFsaWQgY2hhaW4gKCR7Y2hhaW59KSBvciBpbmRleCAoJHtpbmRleH0pYFxuICAgICAgKTtcbiAgICB9XG5cbiAgICBpZiAoIV8uaXNPYmplY3QoY29pblNwZWNpZmljKSkge1xuICAgICAgdGhyb3cgbmV3IEludmFsaWRBZGRyZXNzVmVyaWZpY2F0aW9uT2JqZWN0UHJvcGVydHlFcnJvcihcbiAgICAgICAgJ2FkZHJlc3MgdmFsaWRhdGlvbiBmYWlsdXJlOiBjb2luU3BlY2lmaWMgZmllbGQgbXVzdCBiZSBhbiBvYmplY3QnXG4gICAgICApO1xuICAgIH1cblxuICAgIGlmICgha2V5Y2hhaW5zKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ21pc3NpbmcgcmVxdWlyZWQgcGFyYW0ga2V5Y2hhaW5zJyk7XG4gICAgfVxuXG4gICAgY29uc3QgZXhwZWN0ZWRBZGRyZXNzID0gdGhpcy5nZW5lcmF0ZUFkZHJlc3Moe1xuICAgICAgYWRkcmVzc1R5cGU6IGFkZHJlc3NUeXBlIGFzIFNjcmlwdFR5cGUyT2YzLFxuICAgICAga2V5Y2hhaW5zLFxuICAgICAgdGhyZXNob2xkOiAyLFxuICAgICAgY2hhaW4sXG4gICAgICBpbmRleCxcbiAgICB9KTtcblxuICAgIGlmIChleHBlY3RlZEFkZHJlc3MuYWRkcmVzcyAhPT0gYWRkcmVzcykge1xuICAgICAgdGhyb3cgbmV3IFVuZXhwZWN0ZWRBZGRyZXNzRXJyb3IoXG4gICAgICAgIGBhZGRyZXNzIHZhbGlkYXRpb24gZmFpbHVyZTogZXhwZWN0ZWQgJHtleHBlY3RlZEFkZHJlc3MuYWRkcmVzc30gYnV0IGdvdCAke2FkZHJlc3N9YFxuICAgICAgKTtcbiAgICB9XG5cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJbmRpY2F0ZXMgd2hldGhlciBjb2luIHN1cHBvcnRzIGEgYmxvY2sgdGFyZ2V0XG4gICAqIEByZXR1cm5zIHtib29sZWFufVxuICAgKi9cbiAgc3VwcG9ydHNCbG9ja1RhcmdldCgpIHtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAcGFyYW0gYWRkcmVzc1R5cGVcbiAgICogQHJldHVybnMgdHJ1ZSBpZmYgY29pbiBzdXBwb3J0cyBzcGVuZGluZyBmcm9tIHVuc3BlbnRUeXBlXG4gICAqL1xuICBzdXBwb3J0c0FkZHJlc3NUeXBlKGFkZHJlc3NUeXBlOiBTY3JpcHRUeXBlMk9mMyk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB1dHhvbGliLmJpdGdvLm91dHB1dFNjcmlwdHMuaXNTdXBwb3J0ZWRTY3JpcHRUeXBlKHRoaXMubmV0d29yaywgYWRkcmVzc1R5cGUpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBwYXJhbSBjaGFpblxuICAgKiBAcmV0dXJuIHRydWUgaWZmIGNvaW4gc3VwcG9ydHMgc3BlbmRpbmcgZnJvbSBjaGFpblxuICAgKi9cbiAgc3VwcG9ydHNBZGRyZXNzQ2hhaW4oY2hhaW46IG51bWJlcik6IGJvb2xlYW4ge1xuICAgIHJldHVybiBpc0NoYWluQ29kZShjaGFpbikgJiYgdGhpcy5zdXBwb3J0c0FkZHJlc3NUeXBlKHV0eG9saWIuYml0Z28uc2NyaXB0VHlwZUZvckNoYWluKGNoYWluKSk7XG4gIH1cblxuICBrZXlJZHNGb3JTaWduaW5nKCk6IG51bWJlcltdIHtcbiAgICByZXR1cm4gW0tleUluZGljZXMuVVNFUiwgS2V5SW5kaWNlcy5CQUNLVVAsIEtleUluZGljZXMuQklUR09dO1xuICB9XG5cbiAgLyoqXG4gICAqIFRPRE8oQkctMTE0ODcpOiBSZW1vdmUgYWRkcmVzc1R5cGUsIHNlZ3dpdCwgYW5kIGJlY2gzMiBwYXJhbXMgaW4gU0RLdjZcbiAgICogR2VuZXJhdGUgYW4gYWRkcmVzcyBmb3IgYSB3YWxsZXQgYmFzZWQgb24gYSBzZXQgb2YgY29uZmlndXJhdGlvbnNcbiAgICogQHBhcmFtIHBhcmFtcy5hZGRyZXNzVHlwZSB7c3RyaW5nfSAgIERlcHJlY2F0ZWRcbiAgICogQHBhcmFtIHBhcmFtcy5rZXljaGFpbnMgICB7W29iamVjdF19IEFycmF5IG9mIG9iamVjdHMgd2l0aCB4cHVic1xuICAgKiBAcGFyYW0gcGFyYW1zLnRocmVzaG9sZCAgIHtudW1iZXJ9ICAgTWluaW11bSBudW1iZXIgb2Ygc2lnbmF0dXJlc1xuICAgKiBAcGFyYW0gcGFyYW1zLmNoYWluICAgICAgIHtudW1iZXJ9ICAgRGVyaXZhdGlvbiBjaGFpbiAoc2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9CaXRHby91bnNwZW50cy9ibG9iL21hc3Rlci9zcmMvY29kZXMudHMgZm9yXG4gICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZSBjb3JyZXNwb25kaW5nIGFkZHJlc3MgdHlwZSBvZiBhIGdpdmVuIGNoYWluIGNvZGUpXG4gICAqIEBwYXJhbSBwYXJhbXMuaW5kZXggICAgICAge251bWJlcn0gICBEZXJpdmF0aW9uIGluZGV4XG4gICAqIEBwYXJhbSBwYXJhbXMuc2Vnd2l0ICAgICAge2Jvb2xlYW59ICBEZXByZWNhdGVkXG4gICAqIEBwYXJhbSBwYXJhbXMuYmVjaDMyICAgICAge2Jvb2xlYW59ICBEZXByZWNhdGVkXG4gICAqIEByZXR1cm5zIHt7Y2hhaW46IG51bWJlciwgaW5kZXg6IG51bWJlciwgY29pbjogbnVtYmVyLCBjb2luU3BlY2lmaWM6IHtvdXRwdXRTY3JpcHQsIHJlZGVlbVNjcmlwdH19fVxuICAgKi9cbiAgZ2VuZXJhdGVBZGRyZXNzKHBhcmFtczogR2VuZXJhdGVBZGRyZXNzT3B0aW9ucyk6IEFkZHJlc3NEZXRhaWxzIHtcbiAgICBjb25zdCB7IGtleWNoYWlucywgdGhyZXNob2xkLCBjaGFpbiwgaW5kZXgsIHNlZ3dpdCA9IGZhbHNlLCBiZWNoMzIgPSBmYWxzZSB9ID0gcGFyYW1zO1xuICAgIGxldCBkZXJpdmF0aW9uQ2hhaW4gPSBnZXRFeHRlcm5hbENoYWluQ29kZSgncDJzaCcpO1xuICAgIGlmIChfLmlzTnVtYmVyKGNoYWluKSAmJiBfLmlzSW50ZWdlcihjaGFpbikgJiYgaXNDaGFpbkNvZGUoY2hhaW4pKSB7XG4gICAgICBkZXJpdmF0aW9uQ2hhaW4gPSBjaGFpbjtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBjb252ZXJ0RmxhZ3NUb0FkZHJlc3NUeXBlKCk6IFNjcmlwdFR5cGUyT2YzIHtcbiAgICAgIGlmIChpc0NoYWluQ29kZShjaGFpbikpIHtcbiAgICAgICAgcmV0dXJuIHV0eG9saWIuYml0Z28uc2NyaXB0VHlwZUZvckNoYWluKGNoYWluKTtcbiAgICAgIH1cbiAgICAgIGlmIChfLmlzQm9vbGVhbihzZWd3aXQpICYmIHNlZ3dpdCkge1xuICAgICAgICByZXR1cm4gJ3Ayc2hQMndzaCc7XG4gICAgICB9IGVsc2UgaWYgKF8uaXNCb29sZWFuKGJlY2gzMikgJiYgYmVjaDMyKSB7XG4gICAgICAgIHJldHVybiAncDJ3c2gnO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuICdwMnNoJztcbiAgICAgIH1cbiAgICB9XG5cbiAgICBjb25zdCBhZGRyZXNzVHlwZSA9IHBhcmFtcy5hZGRyZXNzVHlwZSB8fCBjb252ZXJ0RmxhZ3NUb0FkZHJlc3NUeXBlKCk7XG5cbiAgICBpZiAoYWRkcmVzc1R5cGUgIT09IHV0eG9saWIuYml0Z28uc2NyaXB0VHlwZUZvckNoYWluKGRlcml2YXRpb25DaGFpbikpIHtcbiAgICAgIHRocm93IG5ldyBBZGRyZXNzVHlwZUNoYWluTWlzbWF0Y2hFcnJvcihhZGRyZXNzVHlwZSwgZGVyaXZhdGlvbkNoYWluKTtcbiAgICB9XG5cbiAgICBpZiAoIXRoaXMuc3VwcG9ydHNBZGRyZXNzVHlwZShhZGRyZXNzVHlwZSkpIHtcbiAgICAgIHN3aXRjaCAoYWRkcmVzc1R5cGUpIHtcbiAgICAgICAgY2FzZSAncDJzaCc6XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBpbnRlcm5hbCBlcnJvcjogcDJzaCBzaG91bGQgYWx3YXlzIGJlIHN1cHBvcnRlZGApO1xuICAgICAgICBjYXNlICdwMnNoUDJ3c2gnOlxuICAgICAgICAgIHRocm93IG5ldyBQMnNoUDJ3c2hVbnN1cHBvcnRlZEVycm9yKCk7XG4gICAgICAgIGNhc2UgJ3Ayd3NoJzpcbiAgICAgICAgICB0aHJvdyBuZXcgUDJ3c2hVbnN1cHBvcnRlZEVycm9yKCk7XG4gICAgICAgIGNhc2UgJ3AydHInOlxuICAgICAgICAgIHRocm93IG5ldyBQMnRyVW5zdXBwb3J0ZWRFcnJvcigpO1xuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgIHRocm93IG5ldyBVbnN1cHBvcnRlZEFkZHJlc3NUeXBlRXJyb3IoKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBsZXQgc2lnbmF0dXJlVGhyZXNob2xkID0gMjtcbiAgICBpZiAoXy5pc0ludGVnZXIodGhyZXNob2xkKSkge1xuICAgICAgc2lnbmF0dXJlVGhyZXNob2xkID0gdGhyZXNob2xkIGFzIG51bWJlcjtcbiAgICAgIGlmIChzaWduYXR1cmVUaHJlc2hvbGQgPD0gMCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3RocmVzaG9sZCBoYXMgdG8gYmUgcG9zaXRpdmUnKTtcbiAgICAgIH1cbiAgICAgIGlmIChzaWduYXR1cmVUaHJlc2hvbGQgPiBrZXljaGFpbnMubGVuZ3RoKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcigndGhyZXNob2xkIGNhbm5vdCBleGNlZWQgbnVtYmVyIG9mIGtleXMnKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBsZXQgZGVyaXZhdGlvbkluZGV4ID0gMDtcbiAgICBpZiAoXy5pc0ludGVnZXIoaW5kZXgpICYmIChpbmRleCBhcyBudW1iZXIpID4gMCkge1xuICAgICAgZGVyaXZhdGlvbkluZGV4ID0gaW5kZXggYXMgbnVtYmVyO1xuICAgIH1cblxuICAgIGNvbnN0IHBhdGggPSAnMC8wLycgKyBkZXJpdmF0aW9uQ2hhaW4gKyAnLycgKyBkZXJpdmF0aW9uSW5kZXg7XG4gICAgY29uc3QgaGROb2RlcyA9IGtleWNoYWlucy5tYXAoKHsgcHViIH0pID0+IGJpcDMyLmZyb21CYXNlNTgocHViKSk7XG4gICAgY29uc3QgZGVyaXZlZEtleXMgPSBoZE5vZGVzLm1hcCgoaGROb2RlKSA9PiBoZE5vZGUuZGVyaXZlUGF0aChzYW5pdGl6ZUxlZ2FjeVBhdGgocGF0aCkpLnB1YmxpY0tleSk7XG5cbiAgICBjb25zdCB7IG91dHB1dFNjcmlwdCwgcmVkZWVtU2NyaXB0LCB3aXRuZXNzU2NyaXB0LCBhZGRyZXNzIH0gPSB0aGlzLmNyZWF0ZU11bHRpU2lnQWRkcmVzcyhcbiAgICAgIGFkZHJlc3NUeXBlLFxuICAgICAgc2lnbmF0dXJlVGhyZXNob2xkLFxuICAgICAgZGVyaXZlZEtleXNcbiAgICApO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIGFkZHJlc3MsXG4gICAgICBjaGFpbjogZGVyaXZhdGlvbkNoYWluLFxuICAgICAgaW5kZXg6IGRlcml2YXRpb25JbmRleCxcbiAgICAgIGNvaW46IHRoaXMuZ2V0Q2hhaW4oKSxcbiAgICAgIGNvaW5TcGVjaWZpYzoge1xuICAgICAgICBvdXRwdXRTY3JpcHQ6IG91dHB1dFNjcmlwdC50b1N0cmluZygnaGV4JyksXG4gICAgICAgIHJlZGVlbVNjcmlwdDogcmVkZWVtU2NyaXB0ICYmIHJlZGVlbVNjcmlwdC50b1N0cmluZygnaGV4JyksXG4gICAgICAgIHdpdG5lc3NTY3JpcHQ6IHdpdG5lc3NTY3JpcHQgJiYgd2l0bmVzc1NjcmlwdC50b1N0cmluZygnaGV4JyksXG4gICAgICB9LFxuICAgICAgYWRkcmVzc1R5cGUsXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBc3NlbWJsZSBrZXljaGFpbiBhbmQgaGFsZi1zaWduIHByZWJ1aWx0IHRyYW5zYWN0aW9uXG4gICAqIEBwYXJhbSBwYXJhbXMgLSB7QHNlZSBTaWduVHJhbnNhY3Rpb25PcHRpb25zfVxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxTaWduZWRUcmFuc2FjdGlvbiB8IEhhbGZTaWduZWRVdHhvVHJhbnNhY3Rpb24+fVxuICAgKi9cbiAgYXN5bmMgc2lnblRyYW5zYWN0aW9uKHBhcmFtczogU2lnblRyYW5zYWN0aW9uT3B0aW9ucyk6IFByb21pc2U8U2lnbmVkVHJhbnNhY3Rpb24gfCBIYWxmU2lnbmVkVXR4b1RyYW5zYWN0aW9uPiB7XG4gICAgY29uc3QgdHhQcmVidWlsZCA9IHBhcmFtcy50eFByZWJ1aWxkO1xuICAgIGNvbnN0IHVzZXJQcnYgPSBwYXJhbXMucHJ2O1xuXG4gICAgaWYgKF8uaXNVbmRlZmluZWQodHhQcmVidWlsZCkgfHwgIV8uaXNPYmplY3QodHhQcmVidWlsZCkpIHtcbiAgICAgIGlmICghXy5pc1VuZGVmaW5lZCh0eFByZWJ1aWxkKSAmJiAhXy5pc09iamVjdCh0eFByZWJ1aWxkKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYHR4UHJlYnVpbGQgbXVzdCBiZSBhbiBvYmplY3QsIGdvdCB0eXBlICR7dHlwZW9mIHR4UHJlYnVpbGR9YCk7XG4gICAgICB9XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ21pc3NpbmcgdHhQcmVidWlsZCBwYXJhbWV0ZXInKTtcbiAgICB9XG4gICAgY29uc3QgdHJhbnNhY3Rpb24gPSB0aGlzLmNyZWF0ZVRyYW5zYWN0aW9uRnJvbUhleCh0eFByZWJ1aWxkLnR4SGV4KTtcblxuICAgIGlmICh0cmFuc2FjdGlvbi5pbnMubGVuZ3RoICE9PSB0eFByZWJ1aWxkLnR4SW5mby51bnNwZW50cy5sZW5ndGgpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignbGVuZ3RoIG9mIHVuc3BlbnRzIGFycmF5IHNob3VsZCBlcXVhbCB0byB0aGUgbnVtYmVyIG9mIHRyYW5zYWN0aW9uIGlucHV0cycpO1xuICAgIH1cblxuICAgIGxldCBpc0xhc3RTaWduYXR1cmUgPSBmYWxzZTtcbiAgICBpZiAoXy5pc0Jvb2xlYW4ocGFyYW1zLmlzTGFzdFNpZ25hdHVyZSkpIHtcbiAgICAgIC8vIGlmIGJ1aWxkIGlzIGNhbGxlZCBpbnN0ZWFkIG9mIGJ1aWxkSW5jb21wbGV0ZSwgbm8gc2lnbmF0dXJlIHBsYWNlaG9sZGVycyBhcmUgbGVmdCBpbiB0aGUgc2lnIHNjcmlwdFxuICAgICAgaXNMYXN0U2lnbmF0dXJlID0gcGFyYW1zLmlzTGFzdFNpZ25hdHVyZTtcbiAgICB9XG5cbiAgICBpZiAoXy5pc1VuZGVmaW5lZCh1c2VyUHJ2KSB8fCAhXy5pc1N0cmluZyh1c2VyUHJ2KSkge1xuICAgICAgaWYgKCFfLmlzVW5kZWZpbmVkKHVzZXJQcnYpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgcHJ2IG11c3QgYmUgYSBzdHJpbmcsIGdvdCB0eXBlICR7dHlwZW9mIHVzZXJQcnZ9YCk7XG4gICAgICB9XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ21pc3NpbmcgcHJ2IHBhcmFtZXRlciB0byBzaWduIHRyYW5zYWN0aW9uJyk7XG4gICAgfVxuXG4gICAgaWYgKCFwYXJhbXMucHVicyB8fCBwYXJhbXMucHVicy5sZW5ndGggIT09IDMpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgbXVzdCBwcm92aWRlIHhwdWIgYXJyYXlgKTtcbiAgICB9XG5cbiAgICBjb25zdCBzaWduZXJLZXljaGFpbiA9IGJpcDMyLmZyb21CYXNlNTgodXNlclBydiwgdXR4b2xpYi5uZXR3b3Jrcy5iaXRjb2luKTtcbiAgICBpZiAoc2lnbmVyS2V5Y2hhaW4uaXNOZXV0ZXJlZCgpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2V4cGVjdGVkIHVzZXIgcHJpdmF0ZSBrZXkgYnV0IHJlY2VpdmVkIHB1YmxpYyBrZXknKTtcbiAgICB9XG4gICAgZGVidWcoYEhlcmUgaXMgdGhlIHB1YmxpYyBrZXkgb2YgdGhlIHhwcnYgeW91IHVzZWQgdG8gc2lnbjogJHtzaWduZXJLZXljaGFpbi5uZXV0ZXJlZCgpLnRvQmFzZTU4KCl9YCk7XG5cbiAgICBjb25zdCBjb3NpZ25lclB1YiA9IHBhcmFtcy5jb3NpZ25lclB1YiA/PyBwYXJhbXMucHVic1syXTtcbiAgICBjb25zdCBrZXljaGFpbnMgPSBwYXJhbXMucHVicy5tYXAoKHB1YikgPT4gYmlwMzIuZnJvbUJhc2U1OChwdWIpKSBhcyBUcmlwbGU8YmlwMzIuQklQMzJJbnRlcmZhY2U+O1xuICAgIGNvbnN0IGNvc2lnbmVyS2V5Y2hhaW4gPSBiaXAzMi5mcm9tQmFzZTU4KGNvc2lnbmVyUHViKTtcblxuICAgIGNvbnN0IHNpZ25lZFRyYW5zYWN0aW9uID0gc2lnbkFuZFZlcmlmeVdhbGxldFRyYW5zYWN0aW9uKFxuICAgICAgdHJhbnNhY3Rpb24sXG4gICAgICB0eFByZWJ1aWxkLnR4SW5mby51bnNwZW50cyxcbiAgICAgIG5ldyBXYWxsZXRVbnNwZW50U2lnbmVyPFJvb3RXYWxsZXRLZXlzPihrZXljaGFpbnMsIHNpZ25lcktleWNoYWluLCBjb3NpZ25lcktleWNoYWluKSxcbiAgICAgIHsgaXNMYXN0U2lnbmF0dXJlIH1cbiAgICApO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIHR4SGV4OiBzaWduZWRUcmFuc2FjdGlvbi50b0J1ZmZlcigpLnRvU3RyaW5nKCdoZXgnKSxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEBwYXJhbSB1bnNwZW50XG4gICAqIEByZXR1cm5zIHtib29sZWFufVxuICAgKi9cbiAgaXNCaXRHb1RhaW50ZWRVbnNwZW50KHVuc3BlbnQ6IFVuc3BlbnQpOiBib29sZWFuIHtcbiAgICByZXR1cm4gaXNSZXBsYXlQcm90ZWN0aW9uVW5zcGVudCh1bnNwZW50LCB0aGlzLm5ldHdvcmspO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXByZWNhdGVkIC0gdXNlIHV0eG9saWIuYml0Z28uZ2V0RGVmYXVsdFNpZ0hhc2gobmV0d29yaykgaW5zdGVhZFxuICAgKiBAcmV0dXJucyB7bnVtYmVyfVxuICAgKi9cbiAgZ2V0IGRlZmF1bHRTaWdIYXNoVHlwZSgpOiBudW1iZXIge1xuICAgIHJldHVybiB1dHhvbGliLmJpdGdvLmdldERlZmF1bHRTaWdIYXNoKHRoaXMubmV0d29yayk7XG4gIH1cblxuICAvKipcbiAgICogQGRlcHJlY2F0ZWQgLSB1c2UgdXR4b2xpYi5iaXRjb2luLnZlcmlmeVNpZ25hdHVyZSgpIGluc3RlYWRcbiAgICovXG4gIHZlcmlmeVNpZ25hdHVyZShcbiAgICB0cmFuc2FjdGlvbjogYW55LFxuICAgIGlucHV0SW5kZXg6IG51bWJlcixcbiAgICBhbW91bnQ6IG51bWJlcixcbiAgICB2ZXJpZmljYXRpb25TZXR0aW5nczoge1xuICAgICAgc2lnbmF0dXJlSW5kZXg/OiBudW1iZXI7XG4gICAgICBwdWJsaWNLZXk/OiBzdHJpbmc7XG4gICAgfSA9IHt9XG4gICk6IGJvb2xlYW4ge1xuICAgIGlmICh0cmFuc2FjdGlvbi5uZXR3b3JrICE9PSB0aGlzLm5ldHdvcmspIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgbmV0d29yayBtaXNtYXRjaGApO1xuICAgIH1cbiAgICByZXR1cm4gdXR4b2xpYi5iaXRnby52ZXJpZnlTaWduYXR1cmUodHJhbnNhY3Rpb24sIGlucHV0SW5kZXgsIGFtb3VudCwge1xuICAgICAgc2lnbmF0dXJlSW5kZXg6IHZlcmlmaWNhdGlvblNldHRpbmdzLnNpZ25hdHVyZUluZGV4LFxuICAgICAgcHVibGljS2V5OiB2ZXJpZmljYXRpb25TZXR0aW5ncy5wdWJsaWNLZXkgPyBCdWZmZXIuZnJvbSh2ZXJpZmljYXRpb25TZXR0aW5ncy5wdWJsaWNLZXksICdoZXgnKSA6IHVuZGVmaW5lZCxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZWNvbXBvc2UgYSByYXcgdHJhbnNhY3Rpb24gaW50byB1c2VmdWwgaW5mb3JtYXRpb24sIHN1Y2ggYXMgdGhlIHRvdGFsIGFtb3VudHMsXG4gICAqIGNoYW5nZSBhbW91bnRzLCBhbmQgdHJhbnNhY3Rpb24gb3V0cHV0cy5cbiAgICogQHBhcmFtIHBhcmFtc1xuICAgKi9cbiAgYXN5bmMgZXhwbGFpblRyYW5zYWN0aW9uKHBhcmFtczogRXhwbGFpblRyYW5zYWN0aW9uT3B0aW9ucyk6IFByb21pc2U8VHJhbnNhY3Rpb25FeHBsYW5hdGlvbj4ge1xuICAgIGNvbnN0IHR4SGV4ID0gXy5nZXQocGFyYW1zLCAndHhIZXgnKTtcbiAgICBpZiAoIXR4SGV4IHx8ICFfLmlzU3RyaW5nKHR4SGV4KSB8fCAhdHhIZXgubWF0Y2goL14oW2EtZjAtOV17Mn0pKyQvaSkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignaW52YWxpZCB0cmFuc2FjdGlvbiBoZXgsIG11c3QgYmUgYSB2YWxpZCBoZXggc3RyaW5nJyk7XG4gICAgfVxuXG4gICAgbGV0IHRyYW5zYWN0aW9uO1xuICAgIHRyeSB7XG4gICAgICB0cmFuc2FjdGlvbiA9IHRoaXMuY3JlYXRlVHJhbnNhY3Rpb25Gcm9tSGV4KHR4SGV4KTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2ZhaWxlZCB0byBwYXJzZSB0cmFuc2FjdGlvbiBoZXgnKTtcbiAgICB9XG5cbiAgICBjb25zdCBpZCA9IHRyYW5zYWN0aW9uLmdldElkKCk7XG4gICAgbGV0IHNwZW5kQW1vdW50ID0gMDtcbiAgICBsZXQgY2hhbmdlQW1vdW50ID0gMDtcbiAgICBjb25zdCBleHBsYW5hdGlvbiA9IHtcbiAgICAgIGRpc3BsYXlPcmRlcjogWydpZCcsICdvdXRwdXRBbW91bnQnLCAnY2hhbmdlQW1vdW50JywgJ291dHB1dHMnLCAnY2hhbmdlT3V0cHV0cyddLFxuICAgICAgaWQ6IGlkLFxuICAgICAgb3V0cHV0czogW10gYXMgT3V0cHV0W10sXG4gICAgICBjaGFuZ2VPdXRwdXRzOiBbXSBhcyBPdXRwdXRbXSxcbiAgICB9IGFzIFRyYW5zYWN0aW9uRXhwbGFuYXRpb247XG5cbiAgICBjb25zdCB7IGNoYW5nZUFkZHJlc3NlcyA9IFtdLCB1bnNwZW50cyA9IFtdIH0gPSBwYXJhbXMudHhJbmZvID8/IHt9O1xuXG4gICAgdHJhbnNhY3Rpb24ub3V0cy5mb3JFYWNoKChjdXJyZW50T3V0cHV0KSA9PiB7XG4gICAgICBjb25zdCBjdXJyZW50QWRkcmVzcyA9IHV0eG9saWIuYWRkcmVzcy5mcm9tT3V0cHV0U2NyaXB0KGN1cnJlbnRPdXRwdXQuc2NyaXB0LCB0aGlzLm5ldHdvcmspO1xuICAgICAgY29uc3QgY3VycmVudEFtb3VudCA9IGN1cnJlbnRPdXRwdXQudmFsdWU7XG5cbiAgICAgIGlmIChjaGFuZ2VBZGRyZXNzZXMuaW5jbHVkZXMoY3VycmVudEFkZHJlc3MpKSB7XG4gICAgICAgIC8vIHRoaXMgaXMgY2hhbmdlXG4gICAgICAgIGNoYW5nZUFtb3VudCArPSBjdXJyZW50QW1vdW50O1xuICAgICAgICBleHBsYW5hdGlvbi5jaGFuZ2VPdXRwdXRzLnB1c2goe1xuICAgICAgICAgIGFkZHJlc3M6IGN1cnJlbnRBZGRyZXNzLFxuICAgICAgICAgIGFtb3VudDogY3VycmVudEFtb3VudCxcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgc3BlbmRBbW91bnQgKz0gY3VycmVudEFtb3VudDtcbiAgICAgIGV4cGxhbmF0aW9uLm91dHB1dHMucHVzaCh7XG4gICAgICAgIGFkZHJlc3M6IGN1cnJlbnRBZGRyZXNzLFxuICAgICAgICBhbW91bnQ6IGN1cnJlbnRBbW91bnQsXG4gICAgICB9KTtcbiAgICB9KTtcbiAgICBleHBsYW5hdGlvbi5vdXRwdXRBbW91bnQgPSBzcGVuZEFtb3VudDtcbiAgICBleHBsYW5hdGlvbi5jaGFuZ2VBbW91bnQgPSBjaGFuZ2VBbW91bnQ7XG5cbiAgICAvLyBhZGQgZmVlIGluZm8gaWYgYXZhaWxhYmxlXG4gICAgaWYgKHBhcmFtcy5mZWVJbmZvKSB7XG4gICAgICBleHBsYW5hdGlvbi5kaXNwbGF5T3JkZXIucHVzaCgnZmVlJyk7XG4gICAgICBleHBsYW5hdGlvbi5mZWUgPSBwYXJhbXMuZmVlSW5mbztcbiAgICB9XG5cbiAgICBpZiAoXy5pc0ludGVnZXIodHJhbnNhY3Rpb24ubG9ja3RpbWUpICYmIHRyYW5zYWN0aW9uLmxvY2t0aW1lID4gMCkge1xuICAgICAgZXhwbGFuYXRpb24ubG9ja3RpbWUgPSB0cmFuc2FjdGlvbi5sb2NrdGltZTtcbiAgICAgIGV4cGxhbmF0aW9uLmRpc3BsYXlPcmRlci5wdXNoKCdsb2NrdGltZScpO1xuICAgIH1cblxuICAgIGNvbnN0IHByZXZPdXRwdXRzID0gcGFyYW1zLnR4SW5mbz8udW5zcGVudHMubWFwKCh1KSA9PiB0b091dHB1dCh1LCB0aGlzLm5ldHdvcmspKTtcblxuICAgIC8vIGlmIGtleXMgYXJlIHByb3ZpZGVkLCBwcmVwYXJlIHRoZSBrZXlzIGZvciBpbnB1dCBzaWduYXR1cmUgY2hlY2tpbmdcbiAgICBjb25zdCBrZXlzID0gcGFyYW1zLnB1YnM/Lm1hcCgoeHB1YikgPT4gYmlwMzIuZnJvbUJhc2U1OCh4cHViKSk7XG4gICAgY29uc3Qgd2FsbGV0S2V5cyA9IGtleXMgJiYga2V5cy5sZW5ndGggPT09IDMgPyBuZXcgUm9vdFdhbGxldEtleXMoa2V5cyBhcyBUcmlwbGU8YmlwMzIuQklQMzJJbnRlcmZhY2U+KSA6IHVuZGVmaW5lZDtcblxuICAgIC8vIGdldCB0aGUgbnVtYmVyIG9mIHNpZ25hdHVyZXMgcGVyIGlucHV0XG4gICAgY29uc3QgaW5wdXRTaWduYXR1cmVDb3VudHMgPSB0cmFuc2FjdGlvbi5pbnMubWFwKChpbnB1dCwgaWR4KTogbnVtYmVyID0+IHtcbiAgICAgIGlmICh1bnNwZW50cy5sZW5ndGggIT09IHRyYW5zYWN0aW9uLmlucy5sZW5ndGgpIHtcbiAgICAgICAgcmV0dXJuIDA7XG4gICAgICB9XG5cbiAgICAgIGlmICghcHJldk91dHB1dHMpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBpbnZhbGlkIHN0YXRlYCk7XG4gICAgICB9XG5cbiAgICAgIGlmICghd2FsbGV0S2V5cykge1xuICAgICAgICAvLyBubyBwdWIga2V5cyBvciBpbmNvcnJlY3QgbnVtYmVyIG9mIHB1YiBrZXlzXG4gICAgICAgIHJldHVybiAwO1xuICAgICAgfVxuXG4gICAgICB0cnkge1xuICAgICAgICByZXR1cm4gdmVyaWZ5U2lnbmF0dXJlV2l0aFVuc3BlbnQodHJhbnNhY3Rpb24sIGlkeCwgdW5zcGVudHMsIHdhbGxldEtleXMpLmZpbHRlcigodikgPT4gdikubGVuZ3RoO1xuICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAvLyBzb21lIG90aGVyIGVycm9yIG9jY3VycmVkIGFuZCB3ZSBjYW4ndCB2YWxpZGF0ZSB0aGUgc2lnbmF0dXJlc1xuICAgICAgICByZXR1cm4gMDtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIGV4cGxhbmF0aW9uLmlucHV0U2lnbmF0dXJlcyA9IGlucHV0U2lnbmF0dXJlQ291bnRzO1xuICAgIGV4cGxhbmF0aW9uLnNpZ25hdHVyZXMgPSBfLm1heChpbnB1dFNpZ25hdHVyZUNvdW50cykgYXMgbnVtYmVyO1xuICAgIHJldHVybiBleHBsYW5hdGlvbjtcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGUgYSBtdWx0aXNpZyBhZGRyZXNzIG9mIGEgZ2l2ZW4gdHlwZSBmcm9tIGEgbGlzdCBvZiBrZXljaGFpbnMgYW5kIGEgc2lnbmluZyB0aHJlc2hvbGRcbiAgICogQHBhcmFtIGFkZHJlc3NUeXBlXG4gICAqIEBwYXJhbSBzaWduYXR1cmVUaHJlc2hvbGRcbiAgICogQHBhcmFtIGtleXNcbiAgICovXG4gIGNyZWF0ZU11bHRpU2lnQWRkcmVzcyhhZGRyZXNzVHlwZTogU2NyaXB0VHlwZTJPZjMsIHNpZ25hdHVyZVRocmVzaG9sZDogbnVtYmVyLCBrZXlzOiBCdWZmZXJbXSk6IE11bHRpU2lnQWRkcmVzcyB7XG4gICAgY29uc3Qge1xuICAgICAgc2NyaXB0UHViS2V5OiBvdXRwdXRTY3JpcHQsXG4gICAgICByZWRlZW1TY3JpcHQsXG4gICAgICB3aXRuZXNzU2NyaXB0LFxuICAgIH0gPSB1dHhvbGliLmJpdGdvLm91dHB1dFNjcmlwdHMuY3JlYXRlT3V0cHV0U2NyaXB0Mm9mMyhrZXlzLCBhZGRyZXNzVHlwZSk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgb3V0cHV0U2NyaXB0LFxuICAgICAgcmVkZWVtU2NyaXB0LFxuICAgICAgd2l0bmVzc1NjcmlwdCxcbiAgICAgIGFkZHJlc3M6IHV0eG9saWIuYWRkcmVzcy5mcm9tT3V0cHV0U2NyaXB0KG91dHB1dFNjcmlwdCwgdGhpcy5uZXR3b3JrKSxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXByZWNhdGVkIC0gdXNlIHtAc2VlIGJhY2t1cEtleVJlY292ZXJ5fVxuICAgKiBCdWlsZHMgYSBmdW5kcyByZWNvdmVyeSB0cmFuc2FjdGlvbiB3aXRob3V0IEJpdEdvXG4gICAqIEBwYXJhbSBwYXJhbXMgLSB7QHNlZSBiYWNrdXBLZXlSZWNvdmVyeX1cbiAgICovXG4gIGFzeW5jIHJlY292ZXIocGFyYW1zOiBSZWNvdmVyUGFyYW1zKTogUmV0dXJuVHlwZTx0eXBlb2YgYmFja3VwS2V5UmVjb3Zlcnk+IHtcbiAgICByZXR1cm4gYmFja3VwS2V5UmVjb3ZlcnkodGhpcywgdGhpcy5iaXRnbywgcGFyYW1zKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZWNvdmVyIGNvaW4gdGhhdCB3YXMgc2VudCB0byB3cm9uZyBjaGFpblxuICAgKiBAcGFyYW0gcGFyYW1zXG4gICAqIEBwYXJhbSBwYXJhbXMudHhpZCBUaGUgdHhpZCBvZiB0aGUgZmF1bHR5IHRyYW5zYWN0aW9uXG4gICAqIEBwYXJhbSBwYXJhbXMucmVjb3ZlcnlBZGRyZXNzIGFkZHJlc3MgdG8gc2VuZCByZWNvdmVyZWQgZnVuZHMgdG9cbiAgICogQHBhcmFtIHBhcmFtcy53YWxsZXQgdGhlIHdhbGxldCB0aGF0IHJlY2VpdmVkIHRoZSBmdW5kc1xuICAgKiBAcGFyYW0gcGFyYW1zLnJlY292ZXJ5Q29pbiB0aGUgY29pbiB0eXBlIG9mIHRoZSB3YWxsZXQgdGhhdCByZWNlaXZlZCB0aGUgZnVuZHNcbiAgICogQHBhcmFtIHBhcmFtcy5zaWduZWQgcmV0dXJuIGEgaGFsZi1zaWduZWQgdHJhbnNhY3Rpb24gKGRlZmF1bHQ9dHJ1ZSlcbiAgICogQHBhcmFtIHBhcmFtcy53YWxsZXRQYXNzcGhyYXNlIHRoZSB3YWxsZXQgcGFzc3BocmFzZVxuICAgKiBAcGFyYW0gcGFyYW1zLnhwcnYgdGhlIHVuZW5jcnlwdGVkIHhwcnYgKHVzZWQgaW5zdGVhZCBvZiB3YWxsZXQgcGFzc3BocmFzZSlcbiAgICogQHJldHVybnMgeyp9XG4gICAqL1xuICBhc3luYyByZWNvdmVyRnJvbVdyb25nQ2hhaW4oXG4gICAgcGFyYW1zOiBSZWNvdmVyRnJvbVdyb25nQ2hhaW5PcHRpb25zXG4gICk6IFByb21pc2U8Q3Jvc3NDaGFpblJlY292ZXJ5U2lnbmVkIHwgQ3Jvc3NDaGFpblJlY292ZXJ5VW5zaWduZWQ+IHtcbiAgICBjb25zdCB7IHR4aWQsIHJlY292ZXJ5QWRkcmVzcywgd2FsbGV0LCB3YWxsZXRQYXNzcGhyYXNlLCB4cHJ2IH0gPSBwYXJhbXM7XG5cbiAgICAvLyBwYXJhbXMucmVjb3ZlcnlDb2luIHVzZWQgdG8gYmUgcGFyYW1zLmNvaW4sIGJhY2t3YXJkcyBjb21wYXRpYmlsaXR5XG4gICAgY29uc3QgcmVjb3ZlcnlDb2luID0gcGFyYW1zLmNvaW4gfHwgcGFyYW1zLnJlY292ZXJ5Q29pbjtcbiAgICBpZiAoIXJlY292ZXJ5Q29pbikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdtaXNzaW5nIHJlcXVpcmVkIG9iamVjdCByZWNvdmVyeUNvaW4nKTtcbiAgICB9XG4gICAgLy8gc2lnbmVkIHNob3VsZCBkZWZhdWx0IHRvIHRydWUsIGFuZCBvbmx5IGJlIGRpc2FibGVkIGlmIGV4cGxpY2l0bHkgc2V0IHRvIGZhbHNlIChub3QgdW5kZWZpbmVkKVxuICAgIGNvbnN0IHNpZ25lZCA9IHBhcmFtcy5zaWduZWQgIT09IGZhbHNlO1xuXG4gICAgY29uc3Qgc291cmNlQ29pbkZhbWlseSA9IHRoaXMuZ2V0RmFtaWx5KCk7XG4gICAgY29uc3QgcmVjb3ZlcnlDb2luRmFtaWx5ID0gcmVjb3ZlcnlDb2luLmdldEZhbWlseSgpO1xuICAgIGNvbnN0IHN1cHBvcnRlZFJlY292ZXJ5Q29pbnMgPSBzdXBwb3J0ZWRDcm9zc0NoYWluUmVjb3Zlcmllc1tzb3VyY2VDb2luRmFtaWx5XTtcblxuICAgIGlmIChfLmlzVW5kZWZpbmVkKHN1cHBvcnRlZFJlY292ZXJ5Q29pbnMpIHx8ICFzdXBwb3J0ZWRSZWNvdmVyeUNvaW5zLmluY2x1ZGVzKHJlY292ZXJ5Q29pbkZhbWlseSkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgUmVjb3Zlcnkgb2YgJHtzb3VyY2VDb2luRmFtaWx5fSBiYWxhbmNlcyBmcm9tICR7cmVjb3ZlcnlDb2luRmFtaWx5fSB3YWxsZXRzIGlzIG5vdCBzdXBwb3J0ZWQuYCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGF3YWl0IHJlY292ZXJDcm9zc0NoYWluKHRoaXMuYml0Z28sIHtcbiAgICAgIHNvdXJjZUNvaW46IHRoaXMsXG4gICAgICByZWNvdmVyeUNvaW4sXG4gICAgICB3YWxsZXRJZDogd2FsbGV0LFxuICAgICAgdHhpZCxcbiAgICAgIHJlY292ZXJ5QWRkcmVzcyxcbiAgICAgIHdhbGxldFBhc3NwaHJhc2U6IHNpZ25lZCA/IHdhbGxldFBhc3NwaHJhc2UgOiB1bmRlZmluZWQsXG4gICAgICB4cHJ2OiBzaWduZWQgPyB4cHJ2IDogdW5kZWZpbmVkLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEdlbmVyYXRlIGJpcDMyIGtleSBwYWlyXG4gICAqXG4gICAqIEBwYXJhbSBzZWVkXG4gICAqIEByZXR1cm5zIHtPYmplY3R9IG9iamVjdCB3aXRoIGdlbmVyYXRlZCBwdWIgYW5kIHBydlxuICAgKi9cbiAgZ2VuZXJhdGVLZXlQYWlyKHNlZWQ6IEJ1ZmZlcik6IHsgcHViOiBzdHJpbmc7IHBydjogc3RyaW5nIH0ge1xuICAgIGlmICghc2VlZCkge1xuICAgICAgLy8gQW4gZXh0ZW5kZWQgcHJpdmF0ZSBrZXkgaGFzIGJvdGggYSBub3JtYWwgMjU2IGJpdCBwcml2YXRlIGtleSBhbmQgYSAyNTZcbiAgICAgIC8vIGJpdCBjaGFpbiBjb2RlLCBib3RoIG9mIHdoaWNoIG11c3QgYmUgcmFuZG9tLiA1MTIgYml0cyBpcyB0aGVyZWZvcmUgdGhlXG4gICAgICAvLyBtYXhpbXVtIGVudHJvcHkgYW5kIGdpdmVzIHVzIG1heGltdW0gc2VjdXJpdHkgYWdhaW5zdCBjcmFja2luZy5cbiAgICAgIHNlZWQgPSByYW5kb21CeXRlcyg1MTIgLyA4KTtcbiAgICB9XG4gICAgY29uc3QgZXh0ZW5kZWRLZXkgPSBiaXAzMi5mcm9tU2VlZChzZWVkKTtcbiAgICByZXR1cm4ge1xuICAgICAgcHViOiBleHRlbmRlZEtleS5uZXV0ZXJlZCgpLnRvQmFzZTU4KCksXG4gICAgICBwcnY6IGV4dGVuZGVkS2V5LnRvQmFzZTU4KCksXG4gICAgfTtcbiAgfVxuXG4gIGFzeW5jIGdldEV4dHJhUHJlYnVpbGRQYXJhbXMoYnVpbGRQYXJhbXM6IEV4dHJhUHJlYnVpbGRQYXJhbXNPcHRpb25zKTogUHJvbWlzZTxhbnk+IHtcbiAgICByZXR1cm4ge307XG4gIH1cblxuICBwcmVDcmVhdGVCaXRHbyhwYXJhbXM6IFByZWNyZWF0ZUJpdEdvT3B0aW9ucyk6IHZvaWQge1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGFzeW5jIHByZXNpZ25UcmFuc2FjdGlvbihwYXJhbXM6IFByZXNpZ25UcmFuc2FjdGlvbk9wdGlvbnMpOiBQcm9taXNlPGFueT4ge1xuICAgIHJldHVybiBwYXJhbXM7XG4gIH1cblxuICBhc3luYyBzdXBwbGVtZW50R2VuZXJhdGVXYWxsZXQoXG4gICAgd2FsbGV0UGFyYW1zOiBTdXBwbGVtZW50R2VuZXJhdGVXYWxsZXRPcHRpb25zLFxuICAgIGtleWNoYWluczogS2V5Y2hhaW5zVHJpcGxldFxuICApOiBQcm9taXNlPGFueT4ge1xuICAgIHJldHVybiB3YWxsZXRQYXJhbXM7XG4gIH1cblxuICB0cmFuc2FjdGlvbkRhdGFBbGxvd2VkKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIHZhbHVlbGVzc1RyYW5zZmVyQWxsb3dlZCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbn1cbiJdfQ==
|