@bitgo-beta/utxo-lib
Version:
Client-side Bitcoin JavaScript library
467 lines • 70.5 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.signInput2Of3 = exports.signInputP2shP2pk = exports.verifySignatureWithPublicKey = exports.verifySignatureWithPublicKeys = exports.verifySignature = exports.getSignatureVerifications = exports.parseSignatureScript2Of3 = exports.parseSignatureScript = exports.getDefaultSigHash = exports.isPlaceholderSignature = void 0;
const opcodes = require("bitcoin-ops");
const bitcoinjs_lib_1 = require("bitcoinjs-lib");
const UtxoTransaction_1 = require("./UtxoTransaction");
const outputScripts_1 = require("./outputScripts");
const types_1 = require("./types");
const __1 = require("../");
const networks_1 = require("../networks");
const noble_ecc_1 = require("../noble_ecc");
const inputTypes = [
'multisig',
'nonstandard',
'nulldata',
'pubkey',
'pubkeyhash',
'scripthash',
'witnesspubkeyhash',
'witnessscripthash',
'taproot',
'taprootnofn',
'witnesscommitment',
];
function isPlaceholderSignature(v) {
if (Buffer.isBuffer(v)) {
return v.length === 0;
}
return v === 0;
}
exports.isPlaceholderSignature = isPlaceholderSignature;
function getDefaultSigHash(network, scriptType) {
switch (networks_1.getMainnet(network)) {
case networks_1.networks.bitcoincash:
case networks_1.networks.bitcoinsv:
case networks_1.networks.bitcoingold:
return bitcoinjs_lib_1.Transaction.SIGHASH_ALL | UtxoTransaction_1.UtxoTransaction.SIGHASH_FORKID;
default:
return scriptType === 'p2tr' ? bitcoinjs_lib_1.Transaction.SIGHASH_DEFAULT : bitcoinjs_lib_1.Transaction.SIGHASH_ALL;
}
}
exports.getDefaultSigHash = getDefaultSigHash;
/**
* Parse a transaction's signature script to obtain public keys, signatures, the sig script,
* and other properties.
*
* Only supports script types used in BitGo transactions.
*
* @param input
* @returns ParsedSignatureScript
*/
function parseSignatureScript(input) {
const isSegwitInput = input.witness.length > 0;
const isNativeSegwitInput = input.script.length === 0;
let decompiledSigScript;
let inputClassification;
if (isSegwitInput) {
// The decompiledSigScript is the script containing the signatures, public keys, and the script that was committed
// to (pubScript). If this is a segwit input the decompiledSigScript is in the witness, regardless of whether it
// is native or not. The inputClassification is determined based on whether or not the input is native to give an
// accurate classification. Note that p2shP2wsh inputs will be classified as p2sh and not p2wsh.
decompiledSigScript = input.witness;
if (isNativeSegwitInput) {
inputClassification = __1.classify.witness(decompiledSigScript, true);
}
else {
inputClassification = __1.classify.input(input.script, true);
}
}
else {
inputClassification = __1.classify.input(input.script, true);
decompiledSigScript = bitcoinjs_lib_1.script.decompile(input.script);
}
if (!decompiledSigScript) {
return { scriptType: undefined, isSegwitInput, inputClassification };
}
if (inputClassification === 'pubkeyhash') {
/* istanbul ignore next */
if (!decompiledSigScript || decompiledSigScript.length !== 2) {
throw new Error('unexpected signature for p2pkh');
}
const [signature, publicKey] = decompiledSigScript;
/* istanbul ignore next */
if (!Buffer.isBuffer(signature) || !Buffer.isBuffer(publicKey)) {
throw new Error('unexpected signature for p2pkh');
}
const publicKeys = [publicKey];
const signatures = [signature];
const pubScript = bitcoinjs_lib_1.payments.p2pkh({ pubkey: publicKey }).output;
return {
scriptType: 'p2pkh',
isSegwitInput,
inputClassification,
signatures,
publicKeys,
pubScript,
};
}
if (inputClassification === 'taproot') {
// assumes no annex
if (input.witness.length !== 4) {
throw new Error(`unrecognized taproot input`);
}
const [sig1, sig2, tapscript, controlBlock] = input.witness;
const tapscriptClassification = __1.classify.output(tapscript);
if (tapscriptClassification !== 'taprootnofn') {
throw new Error(`tapscript must be n of n multisig`);
}
const publicKeys = bitcoinjs_lib_1.payments.p2tr_ns({ output: tapscript }, { eccLib: noble_ecc_1.ecc }).pubkeys;
if (!publicKeys || publicKeys.length !== 2) {
throw new Error('expected 2 pubkeys');
}
const signatures = [sig1, sig2].map((b) => {
if (Buffer.isBuffer(b)) {
return b;
}
throw new Error(`unexpected signature element ${b}`);
});
const scriptPathLevel = controlBlock.length === 65 ? 1 : controlBlock.length === 97 ? 2 : undefined;
/* istanbul ignore next */
if (scriptPathLevel === undefined) {
throw new Error(`unexpected control block length ${controlBlock.length}`);
}
return {
scriptType: 'p2tr',
isSegwitInput,
inputClassification,
publicKeys: publicKeys,
signatures,
pubScript: tapscript,
controlBlock,
scriptPathLevel,
};
}
// Note the assumption here that if we have a p2sh or p2wsh input it will be multisig (appropriate because the
// BitGo platform only supports multisig within these types of inputs, with the exception of replay protection inputs,
// which are single signature p2sh). Signatures are all but the last entry in the decompiledSigScript.
// The redeemScript/witnessScript (depending on which type of input this is) is the last entry in
// the decompiledSigScript (denoted here as the pubScript). The public keys are the second through
// antepenultimate entries in the decompiledPubScript. See below for a visual representation of the typical 2-of-3
// multisig setup:
//
// decompiledSigScript = 0 <sig1> <sig2> [<sig3>] <pubScript>
// decompiledPubScript = 2 <pub1> <pub2> <pub3> 3 OP_CHECKMULTISIG
//
// Transactions built with `.build()` only have two signatures `<sig1>` and `<sig2>` in _decompiledSigScript_.
// Transactions built with `.buildIncomplete()` have three signatures, where missing signatures are substituted with `OP_0`.
if (inputClassification !== 'scripthash' && inputClassification !== 'witnessscripthash') {
return { scriptType: undefined, isSegwitInput, inputClassification };
}
const pubScript = decompiledSigScript[decompiledSigScript.length - 1];
/* istanbul ignore next */
if (!Buffer.isBuffer(pubScript)) {
throw new Error(`invalid pubScript`);
}
const p2shOutputClassification = __1.classify.output(pubScript);
if (inputClassification === 'scripthash' && p2shOutputClassification === 'pubkey') {
return {
scriptType: 'p2shP2pk',
isSegwitInput,
inputClassification,
p2shOutputClassification,
};
}
if (p2shOutputClassification !== 'multisig') {
return {
scriptType: undefined,
isSegwitInput,
inputClassification,
p2shOutputClassification,
};
}
const decompiledPubScript = bitcoinjs_lib_1.script.decompile(pubScript);
if (decompiledPubScript === null) {
/* istanbul ignore next */
throw new Error(`could not decompile pubScript`);
}
const expectedScriptLength =
// complete transactions with 2 signatures
decompiledSigScript.length === 4 ||
// incomplete transaction with 3 signatures or signature placeholders
decompiledSigScript.length === 5;
if (!expectedScriptLength) {
return { scriptType: undefined, isSegwitInput, inputClassification };
}
if (isSegwitInput) {
/* istanbul ignore next */
if (!Buffer.isBuffer(decompiledSigScript[0])) {
throw new Error(`expected decompiledSigScript[0] to be a buffer for segwit inputs`);
}
/* istanbul ignore next */
if (decompiledSigScript[0].length !== 0) {
throw new Error(`witness stack expected to start with empty buffer`);
}
}
else if (decompiledSigScript[0] !== opcodes.OP_0) {
throw new Error(`sigScript expected to start with OP_0`);
}
const signatures = decompiledSigScript.slice(1 /* ignore leading OP_0 */, -1 /* ignore trailing pubScript */);
/* istanbul ignore next */
if (signatures.length !== 2 && signatures.length !== 3) {
throw new Error(`expected 2 or 3 signatures, got ${signatures.length}`);
}
/* istanbul ignore next */
if (decompiledPubScript.length !== 6) {
throw new Error(`unexpected decompiledPubScript length`);
}
const publicKeys = decompiledPubScript.slice(1, -2);
publicKeys.forEach((b) => {
/* istanbul ignore next */
if (!Buffer.isBuffer(b)) {
throw new Error();
}
});
if (!types_1.isTriple(publicKeys)) {
/* istanbul ignore next */
throw new Error(`expected 3 public keys, got ${publicKeys.length}`);
}
// Op codes 81 through 96 represent numbers 1 through 16 (see https://en.bitcoin.it/wiki/Script#Opcodes), which is
// why we subtract by 80 to get the number of signatures (n) and the number of public keys (m) in an n-of-m setup.
const len = decompiledPubScript.length;
const signatureThreshold = decompiledPubScript[0] - 80;
/* istanbul ignore next */
if (signatureThreshold !== 2) {
throw new Error(`expected signatureThreshold 2, got ${signatureThreshold}`);
}
const nPubKeys = decompiledPubScript[len - 2] - 80;
/* istanbul ignore next */
if (nPubKeys !== 3) {
throw new Error(`expected nPubKeys 3, got ${nPubKeys}`);
}
const lastOpCode = decompiledPubScript[len - 1];
/* istanbul ignore next */
if (lastOpCode !== opcodes.OP_CHECKMULTISIG) {
throw new Error(`expected opcode #${opcodes.OP_CHECKMULTISIG}, got opcode #${lastOpCode}`);
}
const scriptType = input.witness.length
? input.script.length
? 'p2shP2wsh'
: 'p2wsh'
: input.script.length
? 'p2sh'
: undefined;
if (scriptType === undefined) {
throw new Error('illegal state');
}
return {
scriptType,
isSegwitInput,
inputClassification,
p2shOutputClassification,
signatures: signatures.map((b) => {
if (Buffer.isBuffer(b) || b === 0) {
return b;
}
throw new Error(`unexpected signature element ${b}`);
}),
publicKeys,
pubScript,
};
}
exports.parseSignatureScript = parseSignatureScript;
function parseSignatureScript2Of3(input) {
const result = parseSignatureScript(input);
if (![__1.classify.types.P2WSH, __1.classify.types.P2SH, __1.classify.types.P2PKH, __1.classify.types.P2TR].includes(result.inputClassification)) {
throw new Error(`unexpected inputClassification ${result.inputClassification}`);
}
if (!result.signatures) {
throw new Error(`missing signatures`);
}
if (result.publicKeys.length !== 3 &&
(result.publicKeys.length !== 2 || result.inputClassification !== __1.classify.types.P2TR)) {
throw new Error(`unexpected pubkey count`);
}
if (!result.pubScript || result.pubScript.length === 0) {
throw new Error(`pubScript missing or empty`);
}
return result;
}
exports.parseSignatureScript2Of3 = parseSignatureScript2Of3;
/**
* @deprecated - use {@see verifySignaturesWithPublicKeys} instead
* Get signature verifications for multsig transaction
* @param transaction
* @param inputIndex
* @param amount - must be set for segwit transactions and BIP143 transactions
* @param verificationSettings
* @param prevOutputs - must be set for p2tr transactions
* @returns SignatureVerification[] - in order of parsed non-empty signatures
*/
function getSignatureVerifications(transaction, inputIndex, amount, verificationSettings = {}, prevOutputs) {
/* istanbul ignore next */
if (!transaction.ins) {
throw new Error(`invalid transaction`);
}
const input = transaction.ins[inputIndex];
/* istanbul ignore next */
if (!input) {
throw new Error(`no input at index ${inputIndex}`);
}
if ((!input.script || input.script.length === 0) && input.witness.length === 0) {
// Unsigned input: no signatures.
return [];
}
const parsedScript = parseSignatureScript2Of3(input);
const signatures = parsedScript.signatures
.filter((s) => s && s.length)
.filter((s, i) => verificationSettings.signatureIndex === undefined || verificationSettings.signatureIndex === i);
const publicKeys = parsedScript.publicKeys.filter((buf) => verificationSettings.publicKey === undefined ||
verificationSettings.publicKey.equals(buf) ||
verificationSettings.publicKey.slice(1).equals(buf));
return signatures.map((signatureBuffer) => {
if (signatureBuffer === 0 || signatureBuffer.length === 0) {
return { signedBy: undefined };
}
let hashType = bitcoinjs_lib_1.Transaction.SIGHASH_DEFAULT;
if (signatureBuffer.length === 65) {
hashType = signatureBuffer[signatureBuffer.length - 1];
signatureBuffer = signatureBuffer.slice(0, -1);
}
if (parsedScript.inputClassification === __1.classify.types.P2TR) {
if (verificationSettings.signatureIndex !== undefined) {
throw new Error(`signatureIndex parameter not supported for p2tr`);
}
if (!prevOutputs) {
throw new Error(`prevOutputs not set`);
}
if (prevOutputs.length !== transaction.ins.length) {
throw new Error(`prevOutputs length ${prevOutputs.length}, expected ${transaction.ins.length}`);
}
const { controlBlock, pubScript } = parsedScript;
if (!controlBlock) {
throw new Error('expected controlBlock');
}
const leafHash = bitcoinjs_lib_1.taproot.getTapleafHash(noble_ecc_1.ecc, controlBlock, pubScript);
const signatureHash = transaction.hashForWitnessV1(inputIndex, prevOutputs.map(({ script }) => script), prevOutputs.map(({ value }) => value), hashType, leafHash);
const signedBy = publicKeys.filter((k) => Buffer.isBuffer(signatureBuffer) && noble_ecc_1.ecc.verifySchnorr(signatureHash, k, signatureBuffer));
if (signedBy.length === 0) {
return { signedBy: undefined };
}
if (signedBy.length === 1) {
return { signedBy: signedBy[0] };
}
throw new Error(`illegal state: signed by multiple public keys`);
}
else {
// slice the last byte from the signature hash input because it's the hash type
const { signature, hashType } = bitcoinjs_lib_1.ScriptSignature.decode(signatureBuffer);
const transactionHash = parsedScript.isSegwitInput
? transaction.hashForWitnessV0(inputIndex, parsedScript.pubScript, amount, hashType)
: transaction.hashForSignatureByNetwork(inputIndex, parsedScript.pubScript, amount, hashType);
const signedBy = publicKeys.filter((publicKey) => noble_ecc_1.ecc.verify(transactionHash, publicKey, signature,
/*
Strict verification (require lower-S value), as required by BIP-0146
https://github.com/bitcoin/bips/blob/master/bip-0146.mediawiki
https://github.com/bitcoin-core/secp256k1/blob/ac83be33/include/secp256k1.h#L478-L508
https://github.com/bitcoinjs/tiny-secp256k1/blob/v1.1.6/js.js#L231-L233
*/
true));
if (signedBy.length === 0) {
return { signedBy: undefined };
}
if (signedBy.length === 1) {
return { signedBy: signedBy[0] };
}
throw new Error(`illegal state: signed by multiple public keys`);
}
});
}
exports.getSignatureVerifications = getSignatureVerifications;
/**
* @deprecated use {@see verifySignatureWithPublicKeys} instead
* @param transaction
* @param inputIndex
* @param amount
* @param verificationSettings - if publicKey is specified, returns true iff any signature is signed by publicKey.
* @param prevOutputs - must be set for p2tr transactions
*/
function verifySignature(transaction, inputIndex, amount, verificationSettings = {}, prevOutputs) {
const signatureVerifications = getSignatureVerifications(transaction, inputIndex, amount, verificationSettings, prevOutputs).filter((v) =>
// If no publicKey is set in verificationSettings, all signatures must be valid.
// Otherwise, a single valid signature by the specified pubkey is sufficient.
verificationSettings.publicKey === undefined ||
(v.signedBy !== undefined &&
(verificationSettings.publicKey.equals(v.signedBy) ||
verificationSettings.publicKey.slice(1).equals(v.signedBy))));
return signatureVerifications.length > 0 && signatureVerifications.every((v) => v.signedBy !== undefined);
}
exports.verifySignature = verifySignature;
/**
* @param v
* @param publicKey
* @return true iff signature is by publicKey (or xonly variant of publicKey)
*/
function isSignatureByPublicKey(v, publicKey) {
return (!!v.signedBy &&
(v.signedBy.equals(publicKey) ||
/* for p2tr signatures, we pass the pubkey in 33-byte format recover it from the signature in 32-byte format */
(publicKey.length === 33 && isSignatureByPublicKey(v, publicKey.slice(1)))));
}
/**
* @param transaction
* @param inputIndex
* @param prevOutputs - transaction outputs for inputs
* @param publicKeys - public keys to check signatures for
* @return array of booleans indicating a valid signature for every pubkey in _publicKeys_
*/
function verifySignatureWithPublicKeys(transaction, inputIndex, prevOutputs, publicKeys) {
if (transaction.ins.length !== prevOutputs.length) {
throw new Error(`input length must match prevOutputs length`);
}
const signatureVerifications = getSignatureVerifications(transaction, inputIndex, prevOutputs[inputIndex].value, {}, prevOutputs);
return publicKeys.map((publicKey) => !!signatureVerifications.find((v) => isSignatureByPublicKey(v, publicKey)));
}
exports.verifySignatureWithPublicKeys = verifySignatureWithPublicKeys;
/**
* Wrapper for {@see verifySignatureWithPublicKeys} for single pubkey
* @param transaction
* @param inputIndex
* @param prevOutputs
* @param publicKey
* @return true iff signature is valid
*/
function verifySignatureWithPublicKey(transaction, inputIndex, prevOutputs, publicKey) {
return verifySignatureWithPublicKeys(transaction, inputIndex, prevOutputs, [publicKey])[0];
}
exports.verifySignatureWithPublicKey = verifySignatureWithPublicKey;
function signInputP2shP2pk(txBuilder, vin, keyPair) {
const prevOutScriptType = 'p2sh-p2pk';
const { redeemScript, witnessScript } = outputScripts_1.createOutputScriptP2shP2pk(keyPair.publicKey);
keyPair.network = txBuilder.network;
txBuilder.sign({
vin,
prevOutScriptType,
keyPair,
hashType: getDefaultSigHash(txBuilder.network),
redeemScript,
witnessScript,
witnessValue: undefined,
});
}
exports.signInputP2shP2pk = signInputP2shP2pk;
function signInput2Of3(txBuilder, vin, scriptType, pubkeys, keyPair, cosigner, amount) {
let controlBlock;
let redeemScript;
let witnessScript;
const prevOutScriptType = outputScripts_1.scriptType2Of3AsPrevOutType(scriptType);
if (scriptType === 'p2tr') {
({ witnessScript, controlBlock } = outputScripts_1.createSpendScriptP2tr(pubkeys, [keyPair.publicKey, cosigner]));
}
else {
({ redeemScript, witnessScript } = outputScripts_1.createOutputScript2of3(pubkeys, scriptType));
}
keyPair.network = txBuilder.network;
txBuilder.sign({
vin,
prevOutScriptType,
keyPair,
hashType: getDefaultSigHash(txBuilder.network, scriptType),
redeemScript,
witnessScript,
witnessValue: amount,
controlBlock,
});
}
exports.signInput2Of3 = signInput2Of3;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2lnbmF0dXJlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2JpdGdvL3NpZ25hdHVyZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSx1Q0FBdUM7QUFHdkMsaURBQTJHO0FBRTNHLHVEQUFvRDtBQUVwRCxtREFPeUI7QUFDekIsbUNBQTJDO0FBQzNDLDJCQUErQjtBQUMvQiwwQ0FBNEQ7QUFDNUQsNENBQTZDO0FBRTdDLE1BQU0sVUFBVSxHQUFHO0lBQ2pCLFVBQVU7SUFDVixhQUFhO0lBQ2IsVUFBVTtJQUNWLFFBQVE7SUFDUixZQUFZO0lBQ1osWUFBWTtJQUNaLG1CQUFtQjtJQUNuQixtQkFBbUI7SUFDbkIsU0FBUztJQUNULGFBQWE7SUFDYixtQkFBbUI7Q0FDWCxDQUFDO0FBSVgsU0FBZ0Isc0JBQXNCLENBQUMsQ0FBa0I7SUFDdkQsSUFBSSxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxFQUFFO1FBQ3RCLE9BQU8sQ0FBQyxDQUFDLE1BQU0sS0FBSyxDQUFDLENBQUM7S0FDdkI7SUFDRCxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUM7QUFDakIsQ0FBQztBQUxELHdEQUtDO0FBcURELFNBQWdCLGlCQUFpQixDQUFDLE9BQWdCLEVBQUUsVUFBMkI7SUFDN0UsUUFBUSxxQkFBVSxDQUFDLE9BQU8sQ0FBQyxFQUFFO1FBQzNCLEtBQUssbUJBQVEsQ0FBQyxXQUFXLENBQUM7UUFDMUIsS0FBSyxtQkFBUSxDQUFDLFNBQVMsQ0FBQztRQUN4QixLQUFLLG1CQUFRLENBQUMsV0FBVztZQUN2QixPQUFPLDJCQUFXLENBQUMsV0FBVyxHQUFHLGlDQUFlLENBQUMsY0FBYyxDQUFDO1FBQ2xFO1lBQ0UsT0FBTyxVQUFVLEtBQUssTUFBTSxDQUFDLENBQUMsQ0FBQywyQkFBVyxDQUFDLGVBQWUsQ0FBQyxDQUFDLENBQUMsMkJBQVcsQ0FBQyxXQUFXLENBQUM7S0FDeEY7QUFDSCxDQUFDO0FBVEQsOENBU0M7QUFF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Q0FBc0IsQ0FBQyxPQUFPLEVBQUUsVUFBVSxDQUFDLENBQUMsQ0FBQztLQUNqRjtJQUVELE9BQU8sQ0FBQyxPQUFPLEdBQUcsU0FBUyxDQUFDLE9BQU8sQ0FBQztJQUVwQyxTQUFTLENBQUMsSUFBSSxDQUFDO1FBQ2IsR0FBRztRQUNILGlCQUFpQjtRQUNqQixPQUFPO1FBQ1AsUUFBUSxFQUFFLGlCQUFpQixDQUFDLFNBQVMsQ0FBQyxPQUFrQixFQUFFLFVBQVUsQ0FBQztRQUNyRSxZQUFZO1FBQ1osYUFBYTtRQUNiLFlBQVksRUFBRSxNQUFNO1FBQ3BCLFlBQVk7S0FDYixDQUFDLENBQUM7QUFDTCxDQUFDO0FBaENELHNDQWdDQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIG9wY29kZXMgZnJvbSAnYml0Y29pbi1vcHMnO1xuaW1wb3J0IHsgQklQMzJJbnRlcmZhY2UgfSBmcm9tICdiaXAzMic7XG5cbmltcG9ydCB7IHBheW1lbnRzLCBzY3JpcHQsIFRyYW5zYWN0aW9uLCBUeElucHV0LCB0YXByb290LCBUeE91dHB1dCwgU2NyaXB0U2lnbmF0dXJlIH0gZnJvbSAnYml0Y29pbmpzLWxpYic7XG5cbmltcG9ydCB7IFV0eG9UcmFuc2FjdGlvbiB9IGZyb20gJy4vVXR4b1RyYW5zYWN0aW9uJztcbmltcG9ydCB7IFV0eG9UcmFuc2FjdGlvbkJ1aWxkZXIgfSBmcm9tICcuL1V0eG9UcmFuc2FjdGlvbkJ1aWxkZXInO1xuaW1wb3J0IHtcbiAgY3JlYXRlT3V0cHV0U2NyaXB0Mm9mMyxcbiAgY3JlYXRlT3V0cHV0U2NyaXB0UDJzaFAycGssXG4gIGNyZWF0ZVNwZW5kU2NyaXB0UDJ0cixcbiAgU2NyaXB0VHlwZSxcbiAgU2NyaXB0VHlwZTJPZjMsXG4gIHNjcmlwdFR5cGUyT2YzQXNQcmV2T3V0VHlwZSxcbn0gZnJvbSAnLi9vdXRwdXRTY3JpcHRzJztcbmltcG9ydCB7IGlzVHJpcGxlLCBUcmlwbGUgfSBmcm9tICcuL3R5cGVzJztcbmltcG9ydCB7IGNsYXNzaWZ5IH0gZnJvbSAnLi4vJztcbmltcG9ydCB7IGdldE1haW5uZXQsIE5ldHdvcmssIG5ldHdvcmtzIH0gZnJvbSAnLi4vbmV0d29ya3MnO1xuaW1wb3J0IHsgZWNjIGFzIGVjY0xpYiB9IGZyb20gJy4uL25vYmxlX2VjYyc7XG5cbmNvbnN0IGlucHV0VHlwZXMgPSBbXG4gICdtdWx0aXNpZycsXG4gICdub25zdGFuZGFyZCcsXG4gICdudWxsZGF0YScsXG4gICdwdWJrZXknLFxuICAncHVia2V5aGFzaCcsXG4gICdzY3JpcHRoYXNoJyxcbiAgJ3dpdG5lc3NwdWJrZXloYXNoJyxcbiAgJ3dpdG5lc3NzY3JpcHRoYXNoJyxcbiAgJ3RhcHJvb3QnLFxuICAndGFwcm9vdG5vZm4nLFxuICAnd2l0bmVzc2NvbW1pdG1lbnQnLFxuXSBhcyBjb25zdDtcblxudHlwZSBJbnB1dFR5cGUgPSB0eXBlb2YgaW5wdXRUeXBlc1tudW1iZXJdO1xuXG5leHBvcnQgZnVuY3Rpb24gaXNQbGFjZWhvbGRlclNpZ25hdHVyZSh2OiBudW1iZXIgfCBCdWZmZXIpOiBib29sZWFuIHtcbiAgaWYgKEJ1ZmZlci5pc0J1ZmZlcih2KSkge1xuICAgIHJldHVybiB2Lmxlbmd0aCA9PT0gMDtcbiAgfVxuICByZXR1cm4gdiA9PT0gMDtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBQYXJzZWRTaWduYXR1cmVTY3JpcHQge1xuICBzY3JpcHRUeXBlOiBTY3JpcHRUeXBlIHwgJ3AycGtoJyB8IHVuZGVmaW5lZDtcbiAgaXNTZWd3aXRJbnB1dDogYm9vbGVhbjtcbiAgaW5wdXRDbGFzc2lmaWNhdGlvbjogSW5wdXRUeXBlO1xuICBwMnNoT3V0cHV0Q2xhc3NpZmljYXRpb24/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUGFyc2VkU2lnbmF0dXJlU2NyaXB0VW5rbm93biBleHRlbmRzIFBhcnNlZFNpZ25hdHVyZVNjcmlwdCB7XG4gIHNjcmlwdFR5cGU6IHVuZGVmaW5lZDtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBQYXJzZWRTaWduYXR1cmVTY3JpcHRQMlBLIGV4dGVuZHMgUGFyc2VkU2lnbmF0dXJlU2NyaXB0IHtcbiAgc2NyaXB0VHlwZTogJ3Ayc2hQMnBrJztcbiAgaW5wdXRDbGFzc2lmaWNhdGlvbjogJ3NjcmlwdGhhc2gnO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFBhcnNlZFNpZ25hdHVyZVNjcmlwdFAyUEtIIGV4dGVuZHMgUGFyc2VkU2lnbmF0dXJlU2NyaXB0IHtcbiAgc2NyaXB0VHlwZTogJ3AycGtoJztcbiAgaW5wdXRDbGFzc2lmaWNhdGlvbjogJ3B1YmtleWhhc2gnO1xuICBzaWduYXR1cmVzOiBbQnVmZmVyXTtcbiAgcHVibGljS2V5czogW0J1ZmZlcl07XG4gIHB1YlNjcmlwdD86IEJ1ZmZlcjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBQYXJzZWRTaWduYXR1cmVTY3JpcHQyT2YzIGV4dGVuZHMgUGFyc2VkU2lnbmF0dXJlU2NyaXB0IHtcbiAgc2NyaXB0VHlwZTogJ3Ayc2gnIHwgJ3Ayc2hQMndzaCcgfCAncDJ3c2gnO1xuICBpbnB1dENsYXNzaWZpY2F0aW9uOiAnc2NyaXB0aGFzaCcgfCAnd2l0bmVzc3NjcmlwdGhhc2gnO1xuICBwdWJsaWNLZXlzOiBbQnVmZmVyLCBCdWZmZXIsIEJ1ZmZlcl07XG4gIHNpZ25hdHVyZXM6XG4gICAgfCBbQnVmZmVyLCBCdWZmZXJdIC8vIGZ1bGx5LXNpZ25lZCB0cmFuc2FjdGlvbnMgd2l0aCBzaWduYXR1cmVzXG4gICAgLyogUGFydGlhbGx5IHNpZ25lZCB0cmFuc2FjdGlvbnMgd2l0aCBwbGFjZWhvbGRlciBzaWduYXR1cmVzLlxuICAgICAgIEZvciBwMnNoLCB0aGUgcGxhY2Vob2xkZXIgaXMgT1BfMCAobnVtYmVyIDApICovXG4gICAgfCBbQnVmZmVyIHwgMCwgQnVmZmVyIHwgMCwgQnVmZmVyIHwgMF07XG4gIHB1YlNjcmlwdDogQnVmZmVyO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFBhcnNlZFNpZ25hdHVyZVNjcmlwdFRhcHJvb3QgZXh0ZW5kcyBQYXJzZWRTaWduYXR1cmVTY3JpcHQge1xuICBzY3JpcHRUeXBlOiAncDJ0cic7XG4gIGlucHV0Q2xhc3NpZmljYXRpb246ICd0YXByb290JztcbiAgLy8gUDJUUiB0YXBzY3JpcHQgc3BlbmRzIGFyZSBmb3Iga2V5cGF0aCBzcGVuZHMgb3IgMi1vZi0yIG11bHRpc2lnIHNjcmlwdHNcbiAgLy8gQSBzaW5nbGUgc2lnbmF0dXJlIGluZGljYXRlcyBhIGtleXBhdGggc3BlbmQuXG4gIC8vIFR3byBzaWduYXR1cmVzIGluZGljYXRlIGEgc2NyaXB0UGF0aCBzcGVuZC5cbiAgcHVibGljS2V5czogW0J1ZmZlcl0gfCBbQnVmZmVyLCBCdWZmZXJdO1xuICBzaWduYXR1cmVzOiBbQnVmZmVyXSB8IFtCdWZmZXIsIEJ1ZmZlcl07XG4gIC8vIEZvciBzY3JpcHRwYXRoIHNpZ25hdHVyZXMsIHRoaXMgY29udGFpbnMgdGhlIGNvbnRyb2wgYmxvY2sgZGF0YS4gRm9yIGtleXBhdGggc2lnbmF0dXJlcyB0aGlzIGlzIHVuZGVmaW5lZC5cbiAgY29udHJvbEJsb2NrOiBCdWZmZXIgfCB1bmRlZmluZWQ7XG4gIC8vIEZvciBzY3JpcHRwYXRoIHNpZ25hdHVyZXMsIHRoaXMgaW5kaWNhdGVzIHRoZSBsZXZlbCBpbnNpZGUgdGhlIHRhcHRyZWUuIEZvciBrZXlwYXRoIHNpZ25hdHVyZXMgdGhpcyBpcyB1bmRlZmluZWQuXG4gIHNjcmlwdFBhdGhMZXZlbDogbnVtYmVyIHwgdW5kZWZpbmVkO1xuICBwdWJTY3JpcHQ6IEJ1ZmZlcjtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldERlZmF1bHRTaWdIYXNoKG5ldHdvcms6IE5ldHdvcmssIHNjcmlwdFR5cGU/OiBTY3JpcHRUeXBlMk9mMyk6IG51bWJlciB7XG4gIHN3aXRjaCAoZ2V0TWFpbm5ldChuZXR3b3JrKSkge1xuICAgIGNhc2UgbmV0d29ya3MuYml0Y29pbmNhc2g6XG4gICAgY2FzZSBuZXR3b3Jrcy5iaXRjb2luc3Y6XG4gICAgY2FzZSBuZXR3b3Jrcy5iaXRjb2luZ29sZDpcbiAgICAgIHJldHVybiBUcmFuc2FjdGlvbi5TSUdIQVNIX0FMTCB8IFV0eG9UcmFuc2FjdGlvbi5TSUdIQVNIX0ZPUktJRDtcbiAgICBkZWZhdWx0OlxuICAgICAgcmV0dXJuIHNjcmlwdFR5cGUgPT09ICdwMnRyJyA/IFRyYW5zYWN0aW9uLlNJR0hBU0hfREVGQVVMVCA6IFRyYW5zYWN0aW9uLlNJR0hBU0hfQUxMO1xuICB9XG59XG5cbi8qKlxuICogUGFyc2UgYSB0cmFuc2FjdGlvbidzIHNpZ25hdHVyZSBzY3JpcHQgdG8gb2J0YWluIHB1YmxpYyBrZXlzLCBzaWduYXR1cmVzLCB0aGUgc2lnIHNjcmlwdCxcbiAqIGFuZCBvdGhlciBwcm9wZXJ0aWVzLlxuICpcbiAqIE9ubHkgc3VwcG9ydHMgc2NyaXB0IHR5cGVzIHVzZWQgaW4gQml0R28gdHJhbnNhY3Rpb25zLlxuICpcbiAqIEBwYXJhbSBpbnB1dFxuICogQHJldHVybnMgUGFyc2VkU2lnbmF0dXJlU2NyaXB0XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwYXJzZVNpZ25hdHVyZVNjcmlwdChcbiAgaW5wdXQ6IFR4SW5wdXRcbik6XG4gIHwgUGFyc2VkU2lnbmF0dXJlU2NyaXB0VW5rbm93blxuICB8IFBhcnNlZFNpZ25hdHVyZVNjcmlwdFAyUEtcbiAgfCBQYXJzZWRTaWduYXR1cmVTY3JpcHRQMlBLSFxuICB8IFBhcnNlZFNpZ25hdHVyZVNjcmlwdDJPZjNcbiAgfCBQYXJzZWRTaWduYXR1cmVTY3JpcHRUYXByb290IHtcbiAgY29uc3QgaXNTZWd3aXRJbnB1dCA9IGlucHV0LndpdG5lc3MubGVuZ3RoID4gMDtcbiAgY29uc3QgaXNOYXRpdmVTZWd3aXRJbnB1dCA9IGlucHV0LnNjcmlwdC5sZW5ndGggPT09IDA7XG4gIGxldCBkZWNvbXBpbGVkU2lnU2NyaXB0OiBBcnJheTxCdWZmZXIgfCBudW1iZXI+IHwgbnVsbDtcbiAgbGV0IGlucHV0Q2xhc3NpZmljYXRpb246IElucHV0VHlwZTtcbiAgaWYgKGlzU2Vnd2l0SW5wdXQpIHtcbiAgICAvLyBUaGUgZGVjb21waWxlZFNpZ1NjcmlwdCBpcyB0aGUgc2NyaXB0IGNvbnRhaW5pbmcgdGhlIHNpZ25hdHVyZXMsIHB1YmxpYyBrZXlzLCBhbmQgdGhlIHNjcmlwdCB0aGF0IHdhcyBjb21taXR0ZWRcbiAgICAvLyB0byAocHViU2NyaXB0KS4gSWYgdGhpcyBpcyBhIHNlZ3dpdCBpbnB1dCB0aGUgZGVjb21waWxlZFNpZ1NjcmlwdCBpcyBpbiB0aGUgd2l0bmVzcywgcmVnYXJkbGVzcyBvZiB3aGV0aGVyIGl0XG4gICAgLy8gaXMgbmF0aXZlIG9yIG5vdC4gVGhlIGlucHV0Q2xhc3NpZmljYXRpb24gaXMgZGV0ZXJtaW5lZCBiYXNlZCBvbiB3aGV0aGVyIG9yIG5vdCB0aGUgaW5wdXQgaXMgbmF0aXZlIHRvIGdpdmUgYW5cbiAgICAvLyBhY2N1cmF0ZSBjbGFzc2lmaWNhdGlvbi4gTm90ZSB0aGF0IHAyc2hQMndzaCBpbnB1dHMgd2lsbCBiZSBjbGFzc2lmaWVkIGFzIHAyc2ggYW5kIG5vdCBwMndzaC5cbiAgICBkZWNvbXBpbGVkU2lnU2NyaXB0ID0gaW5wdXQud2l0bmVzcztcbiAgICBpZiAoaXNOYXRpdmVTZWd3aXRJbnB1dCkge1xuICAgICAgaW5wdXRDbGFzc2lmaWNhdGlvbiA9IGNsYXNzaWZ5LndpdG5lc3MoZGVjb21waWxlZFNpZ1NjcmlwdCBhcyBCdWZmZXJbXSwgdHJ1ZSkgYXMgSW5wdXRUeXBlO1xuICAgIH0gZWxzZSB7XG4gICAgICBpbnB1dENsYXNzaWZpY2F0aW9uID0gY2xhc3NpZnkuaW5wdXQoaW5wdXQuc2NyaXB0LCB0cnVlKSBhcyBJbnB1dFR5cGU7XG4gICAgfVxuICB9IGVsc2Uge1xuICAgIGlucHV0Q2xhc3NpZmljYXRpb24gPSBjbGFzc2lmeS5pbnB1dChpbnB1dC5zY3JpcHQsIHRydWUpIGFzIElucHV0VHlwZTtcbiAgICBkZWNvbXBpbGVkU2lnU2NyaXB0ID0gc2NyaXB0LmRlY29tcGlsZShpbnB1dC5zY3JpcHQpO1xuICB9XG5cbiAgaWYgKCFkZWNvbXBpbGVkU2lnU2NyaXB0KSB7XG4gICAgcmV0dXJuIHsgc2NyaXB0VHlwZTogdW5kZWZpbmVkLCBpc1NlZ3dpdElucHV0LCBpbnB1dENsYXNzaWZpY2F0aW9uIH07XG4gIH1cblxuICBpZiAoaW5wdXRDbGFzc2lmaWNhdGlvbiA9PT0gJ3B1YmtleWhhc2gnKSB7XG4gICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQgKi9cbiAgICBpZiAoIWRlY29tcGlsZWRTaWdTY3JpcHQgfHwgZGVjb21waWxlZFNpZ1NjcmlwdC5sZW5ndGggIT09IDIpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcigndW5leHBlY3RlZCBzaWduYXR1cmUgZm9yIHAycGtoJyk7XG4gICAgfVxuICAgIGNvbnN0IFtzaWduYXR1cmUsIHB1YmxpY0tleV0gPSBkZWNvbXBpbGVkU2lnU2NyaXB0O1xuICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovXG4gICAgaWYgKCFCdWZmZXIuaXNCdWZmZXIoc2lnbmF0dXJlKSB8fCAhQnVmZmVyLmlzQnVmZmVyKHB1YmxpY0tleSkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcigndW5leHBlY3RlZCBzaWduYXR1cmUgZm9yIHAycGtoJyk7XG4gICAgfVxuICAgIGNvbnN0IHB1YmxpY0tleXM6IFtCdWZmZXJdID0gW3B1YmxpY0tleV07XG4gICAgY29uc3Qgc2lnbmF0dXJlczogW0J1ZmZlcl0gPSBbc2lnbmF0dXJlXTtcbiAgICBjb25zdCBwdWJTY3JpcHQgPSBwYXltZW50cy5wMnBraCh7IHB1YmtleTogcHVibGljS2V5IH0pLm91dHB1dDtcblxuICAgIHJldHVybiB7XG4gICAgICBzY3JpcHRUeXBlOiAncDJwa2gnLFxuICAgICAgaXNTZWd3aXRJbnB1dCxcbiAgICAgIGlucHV0Q2xhc3NpZmljYXRpb24sXG4gICAgICBzaWduYXR1cmVzLFxuICAgICAgcHVibGljS2V5cyxcbiAgICAgIHB1YlNjcmlwdCxcbiAgICB9O1xuICB9XG5cbiAgaWYgKGlucHV0Q2xhc3NpZmljYXRpb24gPT09ICd0YXByb290Jykge1xuICAgIC8vIGFzc3VtZXMgbm8gYW5uZXhcbiAgICBpZiAoaW5wdXQud2l0bmVzcy5sZW5ndGggIT09IDQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgdW5yZWNvZ25pemVkIHRhcHJvb3QgaW5wdXRgKTtcbiAgICB9XG4gICAgY29uc3QgW3NpZzEsIHNpZzIsIHRhcHNjcmlwdCwgY29udHJvbEJsb2NrXSA9IGlucHV0LndpdG5lc3M7XG4gICAgY29uc3QgdGFwc2NyaXB0Q2xhc3NpZmljYXRpb24gPSBjbGFzc2lmeS5vdXRwdXQodGFwc2NyaXB0KTtcbiAgICBpZiAodGFwc2NyaXB0Q2xhc3NpZmljYXRpb24gIT09ICd0YXByb290bm9mbicpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgdGFwc2NyaXB0IG11c3QgYmUgbiBvZiBuIG11bHRpc2lnYCk7XG4gICAgfVxuXG4gICAgY29uc3QgcHVibGljS2V5cyA9IHBheW1lbnRzLnAydHJfbnMoeyBvdXRwdXQ6IHRhcHNjcmlwdCB9LCB7IGVjY0xpYiB9KS5wdWJrZXlzO1xuICAgIGlmICghcHVibGljS2V5cyB8fCBwdWJsaWNLZXlzLmxlbmd0aCAhPT0gMikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdleHBlY3RlZCAyIHB1YmtleXMnKTtcbiAgICB9XG5cbiAgICBjb25zdCBzaWduYXR1cmVzID0gW3NpZzEsIHNpZzJdLm1hcCgoYikgPT4ge1xuICAgICAgaWYgKEJ1ZmZlci5pc0J1ZmZlcihiKSkge1xuICAgICAgICByZXR1cm4gYjtcbiAgICAgIH1cbiAgICAgIHRocm93IG5ldyBFcnJvcihgdW5leHBlY3RlZCBzaWduYXR1cmUgZWxlbWVudCAke2J9YCk7XG4gICAgfSkgYXMgW0J1ZmZlciwgQnVmZmVyXTtcblxuICAgIGNvbnN0IHNjcmlwdFBhdGhMZXZlbCA9IGNvbnRyb2xCbG9jay5sZW5ndGggPT09IDY1ID8gMSA6IGNvbnRyb2xCbG9jay5sZW5ndGggPT09IDk3ID8gMiA6IHVuZGVmaW5lZDtcblxuICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovXG4gICAgaWYgKHNjcmlwdFBhdGhMZXZlbCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYHVuZXhwZWN0ZWQgY29udHJvbCBibG9jayBsZW5ndGggJHtjb250cm9sQmxvY2subGVuZ3RofWApO1xuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICBzY3JpcHRUeXBlOiAncDJ0cicsXG4gICAgICBpc1NlZ3dpdElucHV0LFxuICAgICAgaW5wdXRDbGFzc2lmaWNhdGlvbixcbiAgICAgIHB1YmxpY0tleXM6IHB1YmxpY0tleXMgYXMgW0J1ZmZlciwgQnVmZmVyXSxcbiAgICAgIHNpZ25hdHVyZXMsXG4gICAgICBwdWJTY3JpcHQ6IHRhcHNjcmlwdCxcbiAgICAgIGNvbnRyb2xCbG9jayxcbiAgICAgIHNjcmlwdFBhdGhMZXZlbCxcbiAgICB9O1xuICB9XG5cbiAgLy8gTm90ZSB0aGUgYXNzdW1wdGlvbiBoZXJlIHRoYXQgaWYgd2UgaGF2ZSBhIHAyc2ggb3IgcDJ3c2ggaW5wdXQgaXQgd2lsbCBiZSBtdWx0aXNpZyAoYXBwcm9wcmlhdGUgYmVjYXVzZSB0aGVcbiAgLy8gQml0R28gcGxhdGZvcm0gb25seSBzdXBwb3J0cyBtdWx0aXNpZyB3aXRoaW4gdGhlc2UgdHlwZXMgb2YgaW5wdXRzLCB3aXRoIHRoZSBleGNlcHRpb24gb2YgcmVwbGF5IHByb3RlY3Rpb24gaW5wdXRzLFxuICAvLyB3aGljaCBhcmUgc2luZ2xlIHNpZ25hdHVyZSBwMnNoKS4gU2lnbmF0dXJlcyBhcmUgYWxsIGJ1dCB0aGUgbGFzdCBlbnRyeSBpbiB0aGUgZGVjb21waWxlZFNpZ1NjcmlwdC5cbiAgLy8gVGhlIHJlZGVlbVNjcmlwdC93aXRuZXNzU2NyaXB0IChkZXBlbmRpbmcgb24gd2hpY2ggdHlwZSBvZiBpbnB1dCB0aGlzIGlzKSBpcyB0aGUgbGFzdCBlbnRyeSBpblxuICAvLyB0aGUgZGVjb21waWxlZFNpZ1NjcmlwdCAoZGVub3RlZCBoZXJlIGFzIHRoZSBwdWJTY3JpcHQpLiBUaGUgcHVibGljIGtleXMgYXJlIHRoZSBzZWNvbmQgdGhyb3VnaFxuICAvLyBhbnRlcGVudWx0aW1hdGUgZW50cmllcyBpbiB0aGUgZGVjb21waWxlZFB1YlNjcmlwdC4gU2VlIGJlbG93IGZvciBhIHZpc3VhbCByZXByZXNlbnRhdGlvbiBvZiB0aGUgdHlwaWNhbCAyLW9mLTNcbiAgLy8gbXVsdGlzaWcgc2V0dXA6XG4gIC8vXG4gIC8vICAgZGVjb21waWxlZFNpZ1NjcmlwdCA9IDAgPHNpZzE+IDxzaWcyPiBbPHNpZzM+XSA8cHViU2NyaXB0PlxuICAvLyAgIGRlY29tcGlsZWRQd