PHP WebShell
Текущая директория: /opt/BitGoJS/modules/utxo-staking/dist/src/babylon
Просмотр файла: delegationMessage.js
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getSignedPsbt = getSignedPsbt;
exports.forceFinalizePsbt = forceFinalizePsbt;
exports.getBtcProviderForECKey = getBtcProviderForECKey;
exports.toStakerInfo = toStakerInfo;
exports.createStaking = createStaking;
exports.toStakingTransaction = toStakingTransaction;
exports.createDelegationMessageWithTransaction = createDelegationMessageWithTransaction;
exports.createUnsignedPreStakeRegistrationBabylonTransactionWithBtcProvider = createUnsignedPreStakeRegistrationBabylonTransactionWithBtcProvider;
/**
* https://github.com/babylonlabs-io/babylon/blob/v1.99.0-snapshot.250211/x/btcstaking/types/validate_parsed_message.go
*/
const assert_1 = __importDefault(require("assert"));
const bip322_js_1 = require("bip322-js");
const vendor = __importStar(require("@bitgo/babylonlabs-io-btc-staking-ts"));
const bitcoinjslib = __importStar(require("bitcoinjs-lib"));
const utxolib = __importStar(require("@bitgo/utxo-lib"));
const utxo_core_1 = require("@bitgo/utxo-core");
const descriptor_1 = require("@bitgo/utxo-core/descriptor");
const stakingManager_1 = require("./stakingManager");
const stakingParams_1 = require("./stakingParams");
const network_1 = require("./network");
/**
* Decode a hex or base64 encoded string and check if the length is valid.
* @param v
* @param encoding
*/
function decodeCheck(v, encoding) {
const result = Buffer.from(v, encoding);
if (result.toString(encoding).length !== v.length) {
throw new Error(`Invalid ${encoding} encoding`);
}
return result;
}
/**
* Convert a Buffer or string to a base64 encoded string.
* @param v
*/
function toBase64(v) {
if (typeof v === 'string') {
for (const encoding of ['base64', 'hex']) {
try {
return toBase64(decodeCheck(v, encoding));
}
catch (e) {
// try next
}
}
throw new Error(`Invalid base64 or hex encoding: ${v}`);
}
return v.toString('base64');
}
function getSignedPsbt(psbt, descriptor, signers, { finalize = false }) {
const wrappedPsbt = (0, descriptor_1.toWrappedPsbt)(psbt.toBuffer());
const signedInputs = psbt.data.inputs.flatMap((input, i) => {
(0, assert_1.default)(input.witnessUtxo);
if (Buffer.from(descriptor.scriptPubkey()).equals(input.witnessUtxo.script)) {
wrappedPsbt.updateInputWithDescriptor(i, descriptor);
const signResults = signers.map((signer) => {
(0, assert_1.default)(signer.privateKey);
return wrappedPsbt.signWithPrv(signer.privateKey);
});
return [[i, signResults]];
}
return [];
});
(0, assert_1.default)(signedInputs.length > 0);
if (finalize) {
wrappedPsbt.finalize();
}
return bitcoinjslib.Psbt.fromBuffer(Buffer.from(wrappedPsbt.serialize()));
}
/**
* Utility method to work around a bug in btc-staking-ts
* https://github.com/babylonlabs-io/btc-staking-ts/issues/71
* @param v
* @param network
*/
function forceFinalizePsbt(v, network) {
if (v instanceof utxolib.Psbt) {
v = v.toBuffer();
}
if (v instanceof bitcoinjslib.Psbt) {
v = v.toBuffer();
}
const psbt = bitcoinjslib.Psbt.fromBuffer(v, { network: (0, network_1.toBitcoinJsNetwork)(network) });
// this only works with certain bitcoinjslib versions
psbt.finalizeAllInputs();
return psbt;
}
function getBtcProviderForECKey(descriptorBuilder, stakerKey) {
function signWithDescriptor(psbt, descriptor, key) {
psbt = getSignedPsbt(psbt, descriptor, [key], { finalize: false });
// BUG: we need to blindly finalize here even though we have not fully signed
psbt.finalizeAllInputs();
return psbt;
}
function signBip322Simple(message) {
// Get the script public key from the staking descriptor
const scriptPubKey = Buffer.from(descriptorBuilder.getStakingDescriptor().scriptPubkey());
const toSpendTx = bip322_js_1.BIP322.buildToSpendTx(message, scriptPubKey);
// Get the to_spend txid
const toSpendTxId = toSpendTx.getId();
// Create PSBT object for constructing the transaction
const toSignPsbt = new bitcoinjslib.Psbt();
toSignPsbt.setVersion(2); // nVersion = 0
toSignPsbt.setLocktime(0); // nLockTime = 0
toSignPsbt.addInput({
hash: toSpendTxId,
index: 0,
sequence: descriptorBuilder.stakingTimeLock,
witnessUtxo: {
script: scriptPubKey,
value: 0,
},
});
// Sign the PSBT with the staker key
const wrappedPsbt = (0, descriptor_1.toWrappedPsbt)(toSignPsbt.toBuffer());
wrappedPsbt.updateInputWithDescriptor(0, descriptorBuilder.getStakingDescriptor());
(0, descriptor_1.signWithKey)(wrappedPsbt, stakerKey);
wrappedPsbt.finalize();
// Encode the witness data and return
return bip322_js_1.BIP322.encodeWitness(bitcoinjslib.Psbt.fromBuffer(Buffer.from(wrappedPsbt.serialize())));
}
return {
/**
* @param signingStep
* @param message
* @param type
* @returns Base64 encoded string
*/
async signMessage(signingStep, message, type) {
(0, assert_1.default)(signingStep === 'proof-of-possession');
switch (type) {
case 'ecdsa':
return toBase64(stakerKey.sign(Buffer.from(message, 'hex')));
case 'bip322-simple':
return toBase64(signBip322Simple(message));
default:
throw new Error(`unexpected signing step: ${signingStep}`);
}
},
async signPsbt(signingStep, psbtHex) {
const psbt = bitcoinjslib.Psbt.fromHex(psbtHex);
switch (signingStep) {
case 'staking-slashing':
return signWithDescriptor(psbt, descriptorBuilder.getStakingDescriptor(), stakerKey).toHex();
case 'unbonding-slashing':
return signWithDescriptor(psbt, descriptorBuilder.getUnbondingDescriptor(), stakerKey).toHex();
default:
throw new Error(`unexpected signing step: ${signingStep}`);
}
},
};
}
/**
* @param stakingKey - this is the single-sig key that is used for co-signing the staking output
* @param changeAddress - this is unrelated to the staking key and is used for the change output
*/
function toStakerInfo(stakingKey, changeAddress) {
if (typeof stakingKey === 'object' && 'publicKey' in stakingKey) {
stakingKey = stakingKey.publicKey;
}
if (typeof stakingKey === 'string') {
stakingKey = Buffer.from(stakingKey, 'hex');
}
return {
publicKeyNoCoordHex: (0, utxo_core_1.toXOnlyPublicKey)(stakingKey).toString('hex'),
address: changeAddress,
};
}
function createStaking(network, blockHeight, stakerBtcInfo, stakingInput, versionedParams = (0, stakingParams_1.getStakingParams)(network)) {
if (blockHeight === 0) {
throw new Error('Babylon BTC tip height cannot be 0');
}
// Get the Babylon params based on the BTC tip height from Babylon chain
const params = vendor.getBabylonParamByBtcHeight(blockHeight, versionedParams);
return new vendor.Staking((0, network_1.toBitcoinJsNetwork)(network), stakerBtcInfo, params, stakingInput.finalityProviderPkNoCoordHex, stakingInput.stakingTimelock);
}
function toStakingTransactionFromPsbt(psbt) {
if (!(psbt instanceof utxolib.bitgo.UtxoPsbt)) {
psbt = utxolib.bitgo.createPsbtFromBuffer(psbt.toBuffer(), utxolib.networks.bitcoin);
}
if (psbt instanceof utxolib.bitgo.UtxoPsbt) {
// only utxolib.bitgo.UtxoPsbt has the getUnsignedTx method
return bitcoinjslib.Transaction.fromHex(psbt.getUnsignedTx().toHex());
}
throw new Error('illegal state');
}
function toStakingTransaction(tx) {
if (tx instanceof bitcoinjslib.Psbt || tx instanceof utxolib.Psbt) {
return toStakingTransactionFromPsbt(tx);
}
return bitcoinjslib.Transaction.fromHex(tx.toHex());
}
/*
* This is mostly lifted from
* https://github.com/babylonlabs-io/btc-staking-ts/blob/v0.4.0-rc.2/src/staking/manager.ts#L100-L172
*
* The difference is that here we are returning an _unsigned_ delegation message.
*/
async function createDelegationMessageWithTransaction(manager, staking, stakingAmountSat, transaction, babylonAddress) {
if (!vendor.isValidBabylonAddress(babylonAddress)) {
throw new Error('Invalid Babylon address');
}
// Create delegation message without including inclusion proof
return manager.createBtcDelegationMsg(staking, {
stakingTimelock: staking.stakingTimelock,
finalityProviderPkNoCoordHex: staking.finalityProviderPkNoCoordHex,
stakingAmountSat,
}, toStakingTransaction(transaction), babylonAddress, staking.stakerInfo, staking.params);
}
async function createUnsignedPreStakeRegistrationBabylonTransactionWithBtcProvider(btcProvider, network, stakerBtcInfo, stakingInput, babylonBtcTipHeight, inputUTXOs, feeRateSatB, babylonAddress, stakingParams = (0, stakingParams_1.getStakingParams)(network)) {
if (inputUTXOs.length === 0) {
throw new Error('No input UTXOs provided');
}
const manager = (0, stakingManager_1.createStakingManager)(network, btcProvider, stakingParams);
const staking = createStaking(network, babylonBtcTipHeight, stakerBtcInfo, stakingInput, stakingParams);
// Create unsigned staking transaction
const { transaction } = staking.createStakingTransaction(stakingInput.stakingAmountSat, inputUTXOs, feeRateSatB);
const unsignedDelegationMsg = await createDelegationMessageWithTransaction(manager, staking, stakingInput.stakingAmountSat, transaction, babylonAddress);
return { unsignedDelegationMsg, stakingTx: transaction };
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVsZWdhdGlvbk1lc3NhZ2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvYmFieWxvbi9kZWxlZ2F0aW9uTWVzc2FnZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQXFEQSxzQ0F3QkM7QUFRRCw4Q0FjQztBQUVELHdEQWtGQztBQVVELG9DQWNDO0FBRUQsc0NBcUJDO0FBdUJELG9EQUtDO0FBUUQsd0ZBdUJDO0FBRUQsa0pBMEJDO0FBN1REOztHQUVHO0FBQ0gsb0RBQTRCO0FBRTVCLHlDQUFtQztBQUNuQyw2RUFBK0Q7QUFFL0QsNERBQThDO0FBQzlDLHlEQUEyQztBQUUzQyxnREFBb0Q7QUFDcEQsNERBQXlFO0FBR3pFLHFEQUF3RDtBQUN4RCxtREFBbUQ7QUFDbkQsdUNBQW1FO0FBSW5FOzs7O0dBSUc7QUFDSCxTQUFTLFdBQVcsQ0FBQyxDQUFTLEVBQUUsUUFBMEI7SUFDeEQsTUFBTSxNQUFNLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLEVBQUUsUUFBUSxDQUFDLENBQUM7SUFDeEMsSUFBSSxNQUFNLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxDQUFDLE1BQU0sS0FBSyxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUM7UUFDbEQsTUFBTSxJQUFJLEtBQUssQ0FBQyxXQUFXLFFBQVEsV0FBVyxDQUFDLENBQUM7SUFDbEQsQ0FBQztJQUNELE9BQU8sTUFBTSxDQUFDO0FBQ2hCLENBQUM7QUFFRDs7O0dBR0c7QUFDSCxTQUFTLFFBQVEsQ0FBQyxDQUFrQjtJQUNsQyxJQUFJLE9BQU8sQ0FBQyxLQUFLLFFBQVEsRUFBRSxDQUFDO1FBQzFCLEtBQUssTUFBTSxRQUFRLElBQUksQ0FBQyxRQUFRLEVBQUUsS0FBSyxDQUFVLEVBQUUsQ0FBQztZQUNsRCxJQUFJLENBQUM7Z0JBQ0gsT0FBTyxRQUFRLENBQUMsV0FBVyxDQUFDLENBQUMsRUFBRSxR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LEVBQ1gsY0FBYyxDQUNmLENBQUM7SUFDRixPQUFPLEVBQUUscUJBQXFCLEVBQUUsU0FBUyxFQUFFLFdBQVcsRUFBRSxDQUFDO0FBQzNELENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIGh0dHBzOi8vZ2l0aHViLmNvbS9iYWJ5bG9ubGFicy1pby9iYWJ5bG9uL2Jsb2IvdjEuOTkuMC1zbmFwc2hvdC4yNTAyMTEveC9idGNzdGFraW5nL3R5cGVzL3ZhbGlkYXRlX3BhcnNlZF9tZXNzYWdlLmdvXG4gKi9cbmltcG9ydCBhc3NlcnQgZnJvbSAnYXNzZXJ0JztcblxuaW1wb3J0IHsgQklQMzIyIH0gZnJvbSAnYmlwMzIyLWpzJztcbmltcG9ydCAqIGFzIHZlbmRvciBmcm9tICdAYml0Z28vYmFieWxvbmxhYnMtaW8tYnRjLXN0YWtpbmctdHMnO1xuaW1wb3J0ICogYXMgYmFieWxvblByb3RvYnVmIGZyb20gJ0BiYWJ5bG9ubGFicy1pby9iYWJ5bG9uLXByb3RvLXRzJztcbmltcG9ydCAqIGFzIGJpdGNvaW5qc2xpYiBmcm9tICdiaXRjb2luanMtbGliJztcbmltcG9ydCAqIGFzIHV0eG9saWIgZnJvbSAnQGJpdGdvL3V0eG8tbGliJztcbmltcG9ydCB7IERlc2NyaXB0b3IgfSBmcm9tICdAYml0Z28vd2FzbS1taW5pc2NyaXB0JztcbmltcG9ydCB7IHRvWE9ubHlQdWJsaWNLZXkgfSBmcm9tICdAYml0Z28vdXR4by1jb3JlJztcbmltcG9ydCB7IHNpZ25XaXRoS2V5LCB0b1dyYXBwZWRQc2J0IH0gZnJvbSAnQGJpdGdvL3V0eG8tY29yZS9kZXNjcmlwdG9yJztcblxuaW1wb3J0IHsgQmFieWxvbkRlc2NyaXB0b3JCdWlsZGVyIH0gZnJvbSAnLi9kZXNjcmlwdG9yJztcbmltcG9ydCB7IGNyZWF0ZVN0YWtpbmdNYW5hZ2VyIH0gZnJvbSAnLi9zdGFraW5nTWFuYWdlcic7XG5pbXBvcnQgeyBnZXRTdGFraW5nUGFyYW1zIH0gZnJvbSAnLi9zdGFraW5nUGFyYW1zJztcbmltcG9ydCB7IEJhYnlsb25OZXR3b3JrTGlrZSwgdG9CaXRjb2luSnNOZXR3b3JrIH0gZnJvbSAnLi9uZXR3b3JrJztcblxuZXhwb3J0IHR5cGUgVmFsdWVXaXRoVHlwZVVybDxUPiA9IHsgdHlwZVVybDogc3RyaW5nOyB2YWx1ZTogVCB9O1xuXG4vKipcbiAqIERlY29kZSBhIGhleCBvciBiYXNlNjQgZW5jb2RlZCBzdHJpbmcgYW5kIGNoZWNrIGlmIHRoZSBsZW5ndGggaXMgdmFsaWQuXG4gKiBAcGFyYW0gdlxuICogQHBhcmFtIGVuY29kaW5nXG4gKi9cbmZ1bmN0aW9uIGRlY29kZUNoZWNrKHY6IHN0cmluZywgZW5jb2Rpbmc6ICdoZXgnIHwgJ2Jhc2U2NCcpIHtcbiAgY29uc3QgcmVzdWx0ID0gQnVmZmVyLmZyb20odiwgZW5jb2RpbmcpO1xuICBpZiAocmVzdWx0LnRvU3RyaW5nKGVuY29kaW5nKS5sZW5ndGggIT09IHYubGVuZ3RoKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkICR7ZW5jb2Rpbmd9IGVuY29kaW5nYCk7XG4gIH1cbiAgcmV0dXJuIHJlc3VsdDtcbn1cblxuLyoqXG4gKiBDb252ZXJ0IGEgQnVmZmVyIG9yIHN0cmluZyB0byBhIGJhc2U2NCBlbmNvZGVkIHN0cmluZy5cbiAqIEBwYXJhbSB2XG4gKi9cbmZ1bmN0aW9uIHRvQmFzZTY0KHY6IEJ1ZmZlciB8IHN0cmluZykge1xuICBpZiAodHlwZW9mIHYgPT09ICdzdHJpbmcnKSB7XG4gICAgZm9yIChjb25zdCBlbmNvZGluZyBvZiBbJ2Jhc2U2NCcsICdoZXgnXSBhcyBjb25zdCkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgcmV0dXJuIHRvQmFzZTY0KGRlY29kZUNoZWNrKHYsIGVuY29kaW5nKSk7XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIC8vIHRyeSBuZXh0XG4gICAgICB9XG4gICAgfVxuICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCBiYXNlNjQgb3IgaGV4IGVuY29kaW5nOiAke3Z9YCk7XG4gIH1cblxuICByZXR1cm4gdi50b1N0cmluZygnYmFzZTY0Jyk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRTaWduZWRQc2J0KFxuICBwc2J0OiBiaXRjb2luanNsaWIuUHNidCxcbiAgZGVzY3JpcHRvcjogRGVzY3JpcHRvcixcbiAgc2lnbmVyczogdXR4b2xpYi5FQ1BhaXJJbnRlcmZhY2VbXSxcbiAgeyBmaW5hbGl6ZSA9IGZhbHNlIH1cbik6IGJpdGNvaW5qc2xpYi5Qc2J0IHtcbiAgY29uc3Qgd3JhcHBlZFBzYnQgPSB0b1dyYXBwZWRQc2J0KHBzYnQudG9CdWZmZXIoKSk7XG4gIGNvbnN0IHNpZ25lZElucHV0cyA9IHBzYnQuZGF0YS5pbnB1dHMuZmxhdE1hcCgoaW5wdXQsIGkpID0+IHtcbiAgICBhc3NlcnQoaW5wdXQud2l0bmVzc1V0eG8pO1xuICAgIGlmIChCdWZmZXIuZnJvbShkZXNjcmlwdG9yLnNjcmlwdFB1YmtleSgpKS5lcXVhbHMoaW5wdXQud2l0bmVzc1V0eG8uc2NyaXB0KSkge1xuICAgICAgd3JhcHBlZFBzYnQudXBkYXRlSW5wdXRXaXRoRGVzY3JpcHRvcihpLCBkZXNjcmlwdG9yKTtcbiAgICAgIGNvbnN0IHNpZ25SZXN1bHRzID0gc2lnbmVycy5tYXAoKHNpZ25lcikgPT4ge1xuICAgICAgICBhc3NlcnQoc2lnbmVyLnByaXZhdGVLZXkpO1xuICAgICAgICByZXR1cm4gd3JhcHBlZFBzYnQuc2lnbldpdGhQcnYoc2lnbmVyLnByaXZhdGVLZXkpO1xuICAgICAgfSk7XG4gICAgICByZXR1cm4gW1tpLCBzaWduUmVzdWx0c11dO1xuICAgIH1cbiAgICByZXR1cm4gW107XG4gIH0pO1xuICBhc3NlcnQoc2lnbmVkSW5wdXRzLmxlbmd0aCA+IDApO1xuICBpZiAoZmluYWxpemUpIHtcbiAgICB3cmFwcGVkUHNidC5maW5hbGl6ZSgpO1xuICB9XG4gIHJldHVybiBiaXRjb2luanNsaWIuUHNidC5mcm9tQnVmZmVyKEJ1ZmZlci5mcm9tKHdyYXBwZWRQc2J0LnNlcmlhbGl6ZSgpKSk7XG59XG5cbi8qKlxuICogVXRpbGl0eSBtZXRob2QgdG8gd29yayBhcm91bmQgYSBidWcgaW4gYnRjLXN0YWtpbmctdHNcbiAqIGh0dHBzOi8vZ2l0aHViLmNvbS9iYWJ5bG9ubGFicy1pby9idGMtc3Rha2luZy10cy9pc3N1ZXMvNzFcbiAqIEBwYXJhbSB2XG4gKiBAcGFyYW0gbmV0d29ya1xuICovXG5leHBvcnQgZnVuY3Rpb24gZm9yY2VGaW5hbGl6ZVBzYnQoXG4gIHY6IEJ1ZmZlciB8IHV0eG9saWIuUHNidCB8IGJpdGNvaW5qc2xpYi5Qc2J0LFxuICBuZXR3b3JrOiBCYWJ5bG9uTmV0d29ya0xpa2Vcbik6IGJpdGNvaW5qc2xpYi5Qc2J0IHtcbiAgaWYgKHYgaW5zdGFuY2VvZiB1dHhvbGliLlBzYnQpIHtcbiAgICB2ID0gdi50b0J1ZmZlcigpO1xuICB9XG4gIGlmICh2IGluc3RhbmNlb2YgYml0Y29pbmpzbGliLlBzYnQpIHtcbiAgICB2ID0gdi50b0J1ZmZlcigpO1xuICB9XG4gIGNvbnN0IHBzYnQgPSBiaXRjb2luanNsaWIuUHNidC5mcm9tQnVmZmVyKHYsIHsgbmV0d29yazogdG9CaXRjb2luSnNOZXR3b3JrKG5ldHdvcmspIH0pO1xuICAvLyB0aGlzIG9ubHkgd29ya3Mgd2l0aCBjZXJ0YWluIGJpdGNvaW5qc2xpYiB2ZXJzaW9uc1xuICBwc2J0LmZpbmFsaXplQWxsSW5wdXRzKCk7XG4gIHJldHVybiBwc2J0O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0QnRjUHJvdmlkZXJGb3JFQ0tleShcbiAgZGVzY3JpcHRvckJ1aWxkZXI6IEJhYnlsb25EZXNjcmlwdG9yQnVpbGRlcixcbiAgc3Rha2VyS2V5OiB1dHhvbGliLkVDUGFpckludGVyZmFjZVxuKTogdmVuZG9yLkJ0Y1Byb3ZpZGVyIHtcbiAgZnVuY3Rpb24gc2lnbldpdGhEZXNjcmlwdG9yKFxuICAgIHBzYnQ6IGJpdGNvaW5qc2xpYi5Qc2J0LFxuICAgIGRlc2NyaXB0b3I6IERlc2NyaXB0b3IsXG4gICAga2V5OiB1dHhvbGliLkVDUGFpckludGVyZmFjZVxuICApOiBiaXRjb2luanNsaWIuUHNidCB7XG4gICAgcHNidCA9IGdldFNpZ25lZFBzYnQocHNidCwgZGVzY3JpcHRvciwgW2tleV0sIHsgZmluYWxpemU6IGZhbHNlIH0pO1xuICAgIC8vIEJVRzogd2UgbmVlZCB0byBibGluZGx5IGZpbmFsaXplIGhlcmUgZXZlbiB0aG91Z2ggd2UgaGF2ZSBub3QgZnVsbHkgc2lnbmVkXG4gICAgcHNidC5maW5hbGl6ZUFsbElucHV0cygpO1xuICAgIHJldHVybiBwc2J0O1xuICB9XG5cbiAgZnVuY3Rpb24gc2lnbkJpcDMyMlNpbXBsZShtZXNzYWdlOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIC8vIEdldCB0aGUgc2NyaXB0IHB1YmxpYyBrZXkgZnJvbSB0aGUgc3Rha2luZyBkZXNjcmlwdG9yXG4gICAgY29uc3Qgc2NyaXB0UHViS2V5ID0gQnVmZmVyLmZyb20oZGVzY3JpcHRvckJ1aWxkZXIuZ2V0U3Rha2luZ0Rlc2NyaXB0b3IoKS5zY3JpcHRQdWJrZXkoKSk7XG4gICAgY29uc3QgdG9TcGVuZFR4ID0gQklQMzIyLmJ1aWxkVG9TcGVuZFR4KG1lc3NhZ2UsIHNjcmlwdFB1YktleSk7XG5cbiAgICAvLyBHZXQgdGhlIHRvX3NwZW5kIHR4aWRcbiAgICBjb25zdCB0b1NwZW5kVHhJZCA9IHRvU3BlbmRUeC5nZXRJZCgpO1xuXG4gICAgLy8gQ3JlYXRlIFBTQlQgb2JqZWN0IGZvciBjb25zdHJ1Y3RpbmcgdGhlIHRyYW5zYWN0aW9uXG4gICAgY29uc3QgdG9TaWduUHNidCA9IG5ldyBiaXRjb2luanNsaWIuUHNidCgpO1xuICAgIHRvU2lnblBzYnQuc2V0VmVyc2lvbigyKTsgLy8gblZlcnNpb24gPSAwXG4gICAgdG9TaWduUHNidC5zZXRMb2NrdGltZSgwKTsgLy8gbkxvY2tUaW1lID0gMFxuICAgIHRvU2lnblBzYnQuYWRkSW5wdXQoe1xuICAgICAgaGFzaDogdG9TcGVuZFR4SWQsXG4gICAgICBpbmRleDogMCxcbiAgICAgIHNlcXVlbmNlOiBkZXNjcmlwdG9yQnVpbGRlci5zdGFraW5nVGltZUxvY2ssXG4gICAgICB3aXRuZXNzVXR4bzoge1xuICAgICAgICBzY3JpcHQ6IHNjcmlwdFB1YktleSxcbiAgICAgICAgdmFsdWU6IDAsXG4gICAgICB9LFxuICAgIH0pO1xuXG4gICAgLy8gU2lnbiB0aGUgUFNCVCB3aXRoIHRoZSBzdGFrZXIga2V5XG4gICAgY29uc3Qgd3JhcHBlZFBzYnQgPSB0b1dyYXBwZWRQc2J0KHRvU2lnblBzYnQudG9CdWZmZXIoKSk7XG4gICAgd3JhcHBlZFBzYnQudXBkYXRlSW5wdXRXaXRoRGVzY3JpcHRvcigwLCBkZXNjcmlwdG9yQnVpbGRlci5nZXRTdGFraW5nRGVzY3JpcHRvcigpKTtcbiAgICBzaWduV2l0aEtleSh3cmFwcGVkUHNidCwgc3Rha2VyS2V5KTtcbiAgICB3cmFwcGVkUHNidC5maW5hbGl6ZSgpO1xuXG4gICAgLy8gRW5jb2RlIHRoZSB3aXRuZXNzIGRhdGEgYW5kIHJldHVyblxuICAgIHJldHVybiBCSVAzMjIuZW5jb2RlV2l0bmVzcyhiaXRjb2luanNsaWIuUHNidC5mcm9tQnVmZmVyKEJ1ZmZlci5mcm9tKHdyYXBwZWRQc2J0LnNlcmlhbGl6ZSgpKSkpO1xuICB9XG5cbiAgcmV0dXJuIHtcbiAgICAvKipcbiAgICAgKiBAcGFyYW0gc2lnbmluZ1N0ZXBcbiAgICAgKiBAcGFyYW0gbWVzc2FnZVxuICAgICAqIEBwYXJhbSB0eXBlXG4gICAgICogQHJldHVybnMgQmFzZTY0IGVuY29kZWQgc3RyaW5nXG4gICAgICovXG4gICAgYXN5bmMgc2lnbk1lc3NhZ2UoXG4gICAgICBzaWduaW5nU3RlcDogdmVuZG9yLlNpZ25pbmdTdGVwLFxuICAgICAgbWVzc2FnZTogc3RyaW5nLFxuICAgICAgdHlwZTogJ2VjZHNhJyB8ICdiaXAzMjItc2ltcGxlJ1xuICAgICk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgICBhc3NlcnQoc2lnbmluZ1N0ZXAgPT09ICdwcm9vZi1vZi1wb3NzZXNzaW9uJyk7XG4gICAgICBzd2l0Y2ggKHR5cGUpIHtcbiAgICAgICAgY2FzZSAnZWNkc2EnOlxuICAgICAgICAgIHJldHVybiB0b0Jhc2U2NChzdGFrZXJLZXkuc2lnbihCdWZmZXIuZnJvbShtZXNzYWdlLCAnaGV4JykpKTtcbiAgICAgICAgY2FzZSAnYmlwMzIyLXNpbXBsZSc6XG4gICAgICAgICAgcmV0dXJuIHRvQmFzZTY0KHNpZ25CaXAzMjJTaW1wbGUobWVzc2FnZSkpO1xuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgdW5leHBlY3RlZCBzaWduaW5nIHN0ZXA6ICR7c2lnbmluZ1N0ZXB9YCk7XG4gICAgICB9XG4gICAgfSxcblxuICAgIGFzeW5jIHNpZ25Qc2J0KHNpZ25pbmdTdGVwOiB2ZW5kb3IuU2lnbmluZ1N0ZXAsIHBzYnRIZXg6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgICBjb25zdCBwc2J0ID0gYml0Y29pbmpzbGliLlBzYnQuZnJvbUhleChwc2J0SGV4KTtcbiAgICAgIHN3aXRjaCAoc2lnbmluZ1N0ZXApIHtcbiAgICAgICAgY2FzZSAnc3Rha2luZy1zbGFzaGluZyc6XG4gICAgICAgICAgcmV0dXJuIHNpZ25XaXRoRGVzY3JpcHRvcihwc2J0LCBkZXNjcmlwdG9yQnVpbGRlci5nZXRTdGFraW5nRGVzY3JpcHRvcigpLCBzdGFrZXJLZXkpLnRvSGV4KCk7XG4gICAgICAgIGNhc2UgJ3VuYm9uZGluZy1zbGFzaGluZyc6XG4gICAgICAgICAgcmV0dXJuIHNpZ25XaXRoRGVzY3JpcHRvcihwc2J0LCBkZXNjcmlwdG9yQnVpbGRlci5nZXRVbmJvbmRpbmdEZXNjcmlwdG9yKCksIHN0YWtlcktleSkudG9IZXgoKTtcbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYHVuZXhwZWN0ZWQgc2lnbmluZyBzdGVwOiAke3NpZ25pbmdTdGVwfWApO1xuICAgICAgfVxuICAgIH0sXG4gIH07XG59XG50eXBlIFJlc3VsdCA9IHtcbiAgdW5zaWduZWREZWxlZ2F0aW9uTXNnOiBWYWx1ZVdpdGhUeXBlVXJsPGJhYnlsb25Qcm90b2J1Zi5idGNzdGFraW5ndHguTXNnQ3JlYXRlQlRDRGVsZWdhdGlvbj47XG4gIHN0YWtpbmdUeDogYml0Y29pbmpzbGliLlRyYW5zYWN0aW9uO1xufTtcblxuLyoqXG4gKiBAcGFyYW0gc3Rha2luZ0tleSAtIHRoaXMgaXMgdGhlIHNpbmdsZS1zaWcga2V5IHRoYXQgaXMgdXNlZCBmb3IgY28tc2lnbmluZyB0aGUgc3Rha2luZyBvdXRwdXRcbiAqIEBwYXJhbSBjaGFuZ2VBZGRyZXNzIC0gdGhpcyBpcyB1bnJlbGF0ZWQgdG8gdGhlIHN0YWtpbmcga2V5IGFuZCBpcyB1c2VkIGZvciB0aGUgY2hhbmdlIG91dHB1dFxuICovXG5leHBvcnQgZnVuY3Rpb24gdG9TdGFrZXJJbmZvKFxuICBzdGFraW5nS2V5OiB1dHhvbGliLkVDUGFpckludGVyZmFjZSB8IEJ1ZmZlciB8IHN0cmluZyxcbiAgY2hhbmdlQWRkcmVzczogc3RyaW5nXG4pOiB2ZW5kb3IuU3Rha2VySW5mbyB7XG4gIGlmICh0eXBlb2Ygc3Rha2luZ0tleSA9PT0gJ29iamVjdCcgJiYgJ3B1YmxpY0tleScgaW4gc3Rha2luZ0tleSkge1xuICAgIHN0YWtpbmdLZXkgPSBzdGFraW5nS2V5LnB1YmxpY0tleTtcbiAgfVxuICBpZiAodHlwZW9mIHN0YWtpbmdLZXkgPT09ICdzdHJpbmcnKSB7XG4gICAgc3Rha2luZ0tleSA9IEJ1ZmZlci5mcm9tKHN0YWtpbmdLZXksICdoZXgnKTtcbiAgfVxuICByZXR1cm4ge1xuICAgIHB1YmxpY0tleU5vQ29vcmRIZXg6IHRvWE9ubHlQdWJsaWNLZXkoc3Rha2luZ0tleSkudG9TdHJpbmcoJ2hleCcpLFxuICAgIGFkZHJlc3M6IGNoYW5nZUFkZHJlc3MsXG4gIH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVTdGFraW5nKFxuICBuZXR3b3JrOiBCYWJ5bG9uTmV0d29ya0xpa2UsXG4gIGJsb2NrSGVpZ2h0OiBudW1iZXIsXG4gIHN0YWtlckJ0Y0luZm86IHZlbmRvci5TdGFrZXJJbmZvLFxuICBzdGFraW5nSW5wdXQ6IHZlbmRvci5TdGFraW5nSW5wdXRzLFxuICB2ZXJzaW9uZWRQYXJhbXM6IHZlbmRvci5WZXJzaW9uZWRTdGFraW5nUGFyYW1zW10gPSBnZXRTdGFraW5nUGFyYW1zKG5ldHdvcmspXG4pOiB2ZW5kb3IuU3Rha2luZyB7XG4gIGlmIChibG9ja0hlaWdodCA9PT0gMCkge1xuICAgIHRocm93IG5ldyBFcnJvcignQmFieWxvbiBCVEMgdGlwIGhlaWdodCBjYW5ub3QgYmUgMCcpO1xuICB9XG5cbiAgLy8gR2V0IHRoZSBCYWJ5bG9uIHBhcmFtcyBiYXNlZCBvbiB0aGUgQlRDIHRpcCBoZWlnaHQgZnJvbSBCYWJ5bG9uIGNoYWluXG4gIGNvbnN0IHBhcmFtcyA9IHZlbmRvci5nZXRCYWJ5bG9uUGFyYW1CeUJ0Y0hlaWdodChibG9ja0hlaWdodCwgdmVyc2lvbmVkUGFyYW1zKTtcblxuICByZXR1cm4gbmV3IHZlbmRvci5TdGFraW5nKFxuICAgIHRvQml0Y29pbkpzTmV0d29yayhuZXR3b3JrKSxcbiAgICBzdGFrZXJCdGNJbmZvLFxuICAgIHBhcmFtcyxcbiAgICBzdGFraW5nSW5wdXQuZmluYWxpdHlQcm92aWRlclBrTm9Db29yZEhleCxcbiAgICBzdGFraW5nSW5wdXQuc3Rha2luZ1RpbWVsb2NrXG4gICk7XG59XG5cbnR5cGUgVHJhbnNhY3Rpb25MaWtlID1cbiAgfCBiaXRjb2luanNsaWIuUHNidFxuICB8IGJpdGNvaW5qc2xpYi5UcmFuc2FjdGlvblxuICB8IHV0eG9saWIuVHJhbnNhY3Rpb25cbiAgfCB1dHhvbGliLmJpdGdvLlV0eG9UcmFuc2FjdGlvbjxiaWdpbnQgfCBudW1iZXI+XG4gIHwgdXR4b2xpYi5Qc2J0XG4gIHwgdXR4b2xpYi5iaXRnby5VdHhvUHNidDtcblxuZnVuY3Rpb24gdG9TdGFraW5nVHJhbnNhY3Rpb25Gcm9tUHNidChcbiAgcHNidDogYml0Y29pbmpzbGliLlBzYnQgfCB1dHhvbGliLlBzYnQgfCB1dHhvbGliLmJpdGdvLlV0eG9Qc2J0XG4pOiBiaXRjb2luanNsaWIuVHJhbnNhY3Rpb24ge1xuICBpZiAoIShwc2J0IGluc3RhbmNlb2YgdXR4b2xpYi5iaXRnby5VdHhvUHNidCkpIHtcbiAgICBwc2J0ID0gdXR4b2xpYi5iaXRnby5jcmVhdGVQc2J0RnJvbUJ1ZmZlcihwc2J0LnRvQnVmZmVyKCksIHV0eG9saWIubmV0d29ya3MuYml0Y29pbik7XG4gIH1cbiAgaWYgKHBzYnQgaW5zdGFuY2VvZiB1dHhvbGliLmJpdGdvLlV0eG9Qc2J0KSB7XG4gICAgLy8gb25seSB1dHhvbGliLmJpdGdvLlV0eG9Qc2J0IGhhcyB0aGUgZ2V0VW5zaWduZWRUeCBtZXRob2RcbiAgICByZXR1cm4gYml0Y29pbmpzbGliLlRyYW5zYWN0aW9uLmZyb21IZXgocHNidC5nZXRVbnNpZ25lZFR4KCkudG9IZXgoKSk7XG4gIH1cbiAgdGhyb3cgbmV3IEVycm9yKCdpbGxlZ2FsIHN0YXRlJyk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiB0b1N0YWtpbmdUcmFuc2FjdGlvbih0eDogVHJhbnNhY3Rpb25MaWtlKTogYml0Y29pbmpzbGliLlRyYW5zYWN0aW9uIHtcbiAgaWYgKHR4IGluc3RhbmNlb2YgYml0Y29pbmpzbGliLlBzYnQgfHwgdHggaW5zdGFuY2VvZiB1dHhvbGliLlBzYnQpIHtcbiAgICByZXR1cm4gdG9TdGFraW5nVHJhbnNhY3Rpb25Gcm9tUHNidCh0eCk7XG4gIH1cbiAgcmV0dXJuIGJpdGNvaW5qc2xpYi5UcmFuc2FjdGlvbi5mcm9tSGV4KHR4LnRvSGV4KCkpO1xufVxuXG4vKlxuICogVGhpcyBpcyBtb3N0bHkgbGlmdGVkIGZyb21cbiAqIGh0dHBzOi8vZ2l0aHViLmNvbS9iYWJ5bG9ubGFicy1pby9idGMtc3Rha2luZy10cy9ibG9iL3YwLjQuMC1yYy4yL3NyYy9zdGFraW5nL21hbmFnZXIudHMjTDEwMC1MMTcyXG4gKlxuICogVGhlIGRpZmZlcmVuY2UgaXMgdGhhdCBoZXJlIHdlIGFyZSByZXR1cm5pbmcgYW4gX3Vuc2lnbmVkXyBkZWxlZ2F0aW9uIG1lc3NhZ2UuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjcmVhdGVEZWxlZ2F0aW9uTWVzc2FnZVdpdGhUcmFuc2FjdGlvbihcbiAgbWFuYWdlcjogdmVuZG9yLkJhYnlsb25CdGNTdGFraW5nTWFuYWdlcixcbiAgc3Rha2luZzogdmVuZG9yLlN0YWtpbmcsXG4gIHN0YWtpbmdBbW91bnRTYXQ6IG51bWJlcixcbiAgdHJhbnNhY3Rpb246IFRyYW5zYWN0aW9uTGlrZSxcbiAgYmFieWxvbkFkZHJlc3M6IHN0cmluZ1xuKTogUHJvbWlzZTxWYWx1ZVdpdGhUeXBlVXJsPGJhYnlsb25Qcm90b2J1Zi5idGNzdGFraW5ndHguTXNnQ3JlYXRlQlRDRGVsZWdhdGlvbj4+IHtcbiAgaWYgKCF2ZW5kb3IuaXNWYWxpZEJhYnlsb25BZGRyZXNzKGJhYnlsb25BZGRyZXNzKSkge1xuICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBCYWJ5bG9uIGFkZHJlc3MnKTtcbiAgfVxuICAvLyBDcmVhdGUgZGVsZWdhdGlvbiBtZXNzYWdlIHdpdGhvdXQgaW5jbHVkaW5nIGluY2x1c2lvbiBwcm9vZlxuICByZXR1cm4gbWFuYWdlci5jcmVhdGVCdGNEZWxlZ2F0aW9uTXNnKFxuICAgIHN0YWtpbmcsXG4gICAge1xuICAgICAgc3Rha2luZ1RpbWVsb2NrOiBzdGFraW5nLnN0YWtpbmdUaW1lbG9jayxcbiAgICAgIGZpbmFsaXR5UHJvdmlkZXJQa05vQ29vcmRIZXg6IHN0YWtpbmcuZmluYWxpdHlQcm92aWRlclBrTm9Db29yZEhleCxcbiAgICAgIHN0YWtpbmdBbW91bnRTYXQsXG4gICAgfSxcbiAgICB0b1N0YWtpbmdUcmFuc2FjdGlvbih0cmFuc2FjdGlvbiksXG4gICAgYmFieWxvbkFkZHJlc3MsXG4gICAgc3Rha2luZy5zdGFrZXJJbmZvLFxuICAgIHN0YWtpbmcucGFyYW1zXG4gICk7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjcmVhdGVVbnNpZ25lZFByZVN0YWtlUmVnaXN0cmF0aW9uQmFieWxvblRyYW5zYWN0aW9uV2l0aEJ0Y1Byb3ZpZGVyKFxuICBidGNQcm92aWRlcjogdmVuZG9yLkJ0Y1Byb3ZpZGVyLFxuICBuZXR3b3JrOiBiaXRjb2luanNsaWIuTmV0d29yayxcbiAgc3Rha2VyQnRjSW5mbzogdmVuZG9yLlN0YWtlckluZm8sXG4gIHN0YWtpbmdJbnB1dDogdmVuZG9yLlN0YWtpbmdJbnB1dHMsXG4gIGJhYnlsb25CdGNUaXBIZWlnaHQ6IG51bWJlcixcbiAgaW5wdXRVVFhPczogdmVuZG9yLlVUWE9bXSxcbiAgZmVlUmF0ZVNhdEI6IG51bWJlcixcbiAgYmFieWxvbkFkZHJlc3M6IHN0cmluZyxcbiAgc3Rha2luZ1BhcmFtczogdmVuZG9yLlZlcnNpb25lZFN0YWtpbmdQYXJhbXNbXSA9IGdldFN0YWtpbmdQYXJhbXMobmV0d29yaylcbik6IFByb21pc2U8UmVzdWx0PiB7XG4gIGlmIChpbnB1dFVUWE9zLmxlbmd0aCA9PT0gMCkge1xuICAgIHRocm93IG5ldyBFcnJvcignTm8gaW5wdXQgVVRYT3MgcHJvdmlkZWQnKTtcbiAgfVxuICBjb25zdCBtYW5hZ2VyID0gY3JlYXRlU3Rha2luZ01hbmFnZXIobmV0d29yaywgYnRjUHJvdmlkZXIsIHN0YWtpbmdQYXJhbXMpO1xuICBjb25zdCBzdGFraW5nID0gY3JlYXRlU3Rha2luZyhuZXR3b3JrLCBiYWJ5bG9uQnRjVGlwSGVpZ2h0LCBzdGFrZXJCdGNJbmZvLCBzdGFraW5nSW5wdXQsIHN0YWtpbmdQYXJhbXMpO1xuICAvLyBDcmVhdGUgdW5zaWduZWQgc3Rha2luZyB0cmFuc2FjdGlvblxuICBjb25zdCB7IHRyYW5zYWN0aW9uIH0gPSBzdGFraW5nLmNyZWF0ZVN0YWtpbmdUcmFuc2FjdGlvbihzdGFraW5nSW5wdXQuc3Rha2luZ0Ftb3VudFNhdCwgaW5wdXRVVFhPcywgZmVlUmF0ZVNhdEIpO1xuICBjb25zdCB1bnNpZ25lZERlbGVnYXRpb25Nc2cgPSBhd2FpdCBjcmVhdGVEZWxlZ2F0aW9uTWVzc2FnZVdpdGhUcmFuc2FjdGlvbihcbiAgICBtYW5hZ2VyLFxuICAgIHN0YWtpbmcsXG4gICAgc3Rha2luZ0lucHV0LnN0YWtpbmdBbW91bnRTYXQsXG4gICAgdHJhbnNhY3Rpb24sXG4gICAgYmFieWxvbkFkZHJlc3NcbiAgKTtcbiAgcmV0dXJuIHsgdW5zaWduZWREZWxlZ2F0aW9uTXNnLCBzdGFraW5nVHg6IHRyYW5zYWN0aW9uIH07XG59XG4iXX0=Выполнить команду
Для локальной разработки. Не используйте в интернете!