UNPKG

bitcore-wallet-client

Version:

Client for bitcore-wallet-service

435 lines 21.8 kB
'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 (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { if (kind === "m") throw new TypeError("Private method is not writable"); if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; }; var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); }; var _Key_xPrivKey, _Key_xPrivKeyEncrypted, _Key_version, _Key_mnemonic, _Key_mnemonicEncrypted, _Key_mnemonicHasPassphrase; Object.defineProperty(exports, "__esModule", { value: true }); exports.Key = void 0; var $ = require('preconditions').singleton(); const crypto_wallet_core_1 = require("crypto-wallet-core"); const _ = __importStar(require("lodash")); require("source-map-support/register"); const common_1 = require("./common"); const credentials_1 = require("./credentials"); var Bitcore = crypto_wallet_core_1.BitcoreLib; var Mnemonic = require('bitcore-mnemonic'); var sjcl = require('sjcl'); var log = require('./log'); const async = require('async'); const Uuid = require('uuid'); var Errors = require('./errors'); const wordsForLang = { en: Mnemonic.Words.ENGLISH, es: Mnemonic.Words.SPANISH, ja: Mnemonic.Words.JAPANESE, zh: Mnemonic.Words.CHINESE, fr: Mnemonic.Words.FRENCH, it: Mnemonic.Words.ITALIAN }; const NETWORK = 'livenet'; class Key { constructor(opts = { seedType: 'new' }) { _Key_xPrivKey.set(this, void 0); _Key_xPrivKeyEncrypted.set(this, void 0); _Key_version.set(this, void 0); _Key_mnemonic.set(this, void 0); _Key_mnemonicEncrypted.set(this, void 0); _Key_mnemonicHasPassphrase.set(this, void 0); this.toObj = function () { const ret = { xPrivKey: __classPrivateFieldGet(this, _Key_xPrivKey, "f"), xPrivKeyEncrypted: __classPrivateFieldGet(this, _Key_xPrivKeyEncrypted, "f"), mnemonic: __classPrivateFieldGet(this, _Key_mnemonic, "f"), mnemonicEncrypted: __classPrivateFieldGet(this, _Key_mnemonicEncrypted, "f"), version: __classPrivateFieldGet(this, _Key_version, "f"), mnemonicHasPassphrase: __classPrivateFieldGet(this, _Key_mnemonicHasPassphrase, "f"), fingerPrint: this.fingerPrint, compliantDerivation: this.compliantDerivation, BIP45: this.BIP45, use0forBCH: this.use0forBCH, use44forMultisig: this.use44forMultisig, id: this.id }; return _.clone(ret); }; this.isPrivKeyEncrypted = function () { return !!__classPrivateFieldGet(this, _Key_xPrivKeyEncrypted, "f") && !__classPrivateFieldGet(this, _Key_xPrivKey, "f"); }; this.checkPassword = function (password) { if (this.isPrivKeyEncrypted()) { try { sjcl.decrypt(password, __classPrivateFieldGet(this, _Key_xPrivKeyEncrypted, "f")); } catch (ex) { return false; } return true; } return null; }; this.get = function (password) { let keys = {}; let fingerPrintUpdated = false; if (this.isPrivKeyEncrypted()) { $.checkArgument(password, 'Private keys are encrypted, a password is needed'); try { keys.xPrivKey = sjcl.decrypt(password, __classPrivateFieldGet(this, _Key_xPrivKeyEncrypted, "f")); if (!this.fingerPrint) { let xpriv = new Bitcore.HDPrivateKey(keys.xPrivKey); this.fingerPrint = xpriv.fingerPrint.toString('hex'); fingerPrintUpdated = true; } if (__classPrivateFieldGet(this, _Key_mnemonicEncrypted, "f")) { keys.mnemonic = sjcl.decrypt(password, __classPrivateFieldGet(this, _Key_mnemonicEncrypted, "f")); } } catch (ex) { throw new Error('Could not decrypt'); } } else { keys.xPrivKey = __classPrivateFieldGet(this, _Key_xPrivKey, "f"); keys.mnemonic = __classPrivateFieldGet(this, _Key_mnemonic, "f"); if (fingerPrintUpdated) { keys.fingerPrintUpdated = true; } } keys.mnemonicHasPassphrase = __classPrivateFieldGet(this, _Key_mnemonicHasPassphrase, "f") || false; return keys; }; this.encrypt = function (password, opts) { if (__classPrivateFieldGet(this, _Key_xPrivKeyEncrypted, "f")) throw new Error('Private key already encrypted'); if (!__classPrivateFieldGet(this, _Key_xPrivKey, "f")) throw new Error('No private key to encrypt'); __classPrivateFieldSet(this, _Key_xPrivKeyEncrypted, sjcl.encrypt(password, __classPrivateFieldGet(this, _Key_xPrivKey, "f"), opts), "f"); if (!__classPrivateFieldGet(this, _Key_xPrivKeyEncrypted, "f")) throw new Error('Could not encrypt'); if (__classPrivateFieldGet(this, _Key_mnemonic, "f")) __classPrivateFieldSet(this, _Key_mnemonicEncrypted, sjcl.encrypt(password, __classPrivateFieldGet(this, _Key_mnemonic, "f"), opts), "f"); __classPrivateFieldSet(this, _Key_xPrivKey, null, "f"); __classPrivateFieldSet(this, _Key_mnemonic, null, "f"); }; this.decrypt = function (password) { if (!__classPrivateFieldGet(this, _Key_xPrivKeyEncrypted, "f")) throw new Error('Private key is not encrypted'); try { __classPrivateFieldSet(this, _Key_xPrivKey, sjcl.decrypt(password, __classPrivateFieldGet(this, _Key_xPrivKeyEncrypted, "f")), "f"); if (__classPrivateFieldGet(this, _Key_mnemonicEncrypted, "f")) { __classPrivateFieldSet(this, _Key_mnemonic, sjcl.decrypt(password, __classPrivateFieldGet(this, _Key_mnemonicEncrypted, "f")), "f"); } __classPrivateFieldSet(this, _Key_xPrivKeyEncrypted, null, "f"); __classPrivateFieldSet(this, _Key_mnemonicEncrypted, null, "f"); } catch (ex) { log.error('error decrypting:', ex); throw new Error('Could not decrypt'); } }; this.derive = function (password, path) { $.checkArgument(path, 'no path at derive()'); var xPrivKey = new Bitcore.HDPrivateKey(this.get(password).xPrivKey, NETWORK); var deriveFn = this.compliantDerivation ? _.bind(xPrivKey.deriveChild, xPrivKey) : _.bind(xPrivKey.deriveNonCompliantChild, xPrivKey); return deriveFn(path); }; this._checkChain = function (chain) { if (!_.includes(common_1.Constants.CHAINS, chain)) throw new Error('Invalid chain'); }; this._checkNetwork = function (network) { if (!_.includes(['livenet', 'testnet', 'regtest'], network)) throw new Error('Invalid network ' + network); }; this.getBaseAddressDerivationPath = function (opts) { $.checkArgument(opts, 'Need to provide options'); $.checkArgument(opts.n >= 1, 'n need to be >=1'); const chain = opts.chain || common_1.Utils.getChain(opts.coin); let purpose = opts.n == 1 || this.use44forMultisig ? '44' : '48'; let coinCode = '0'; if (['testnet', 'regtest]'].includes(opts.network) && common_1.Constants.UTXO_CHAINS.includes(chain)) { coinCode = '1'; } else if (chain == 'bch') { if (this.use0forBCH || opts.use0forBCH) { coinCode = '0'; } else { coinCode = '145'; } } else if (chain == 'btc') { coinCode = '0'; } else if (chain == 'eth') { coinCode = '60'; } else if (chain == 'matic') { coinCode = '60'; } else if (chain == 'arb') { coinCode = '60'; } else if (chain == 'op') { coinCode = '60'; } else if (chain == 'base') { coinCode = '60'; } else if (chain == 'xrp') { coinCode = '144'; } else if (chain == 'doge') { coinCode = '3'; } else if (chain == 'ltc') { coinCode = '2'; } else { throw new Error('unknown chain: ' + chain); } return 'm/' + purpose + "'/" + coinCode + "'/" + opts.account + "'"; }; this.createCredentials = function (password, opts) { var _a; opts = opts || {}; opts.chain = opts.chain || common_1.Utils.getChain(opts.coin); if (password) $.shouldBeString(password, 'provide password'); this._checkNetwork(opts.network); $.shouldBeNumber(opts.account, 'Invalid account'); $.shouldBeNumber(opts.n, 'Invalid n'); $.shouldBeUndefined(opts.useLegacyCoinType); $.shouldBeUndefined(opts.useLegacyPurpose); let path = this.getBaseAddressDerivationPath(opts); let xPrivKey = this.derive(password, path); let requestPrivKey = this.derive(password, common_1.Constants.PATHS.REQUEST_KEY).privateKey.toString(); if (['testnet', 'regtest'].includes(opts.network)) { let x = xPrivKey.toObject(); x.network = opts.network; delete x.xprivkey; delete x.checksum; x.privateKey = _.padStart(x.privateKey, 64, '0'); xPrivKey = new Bitcore.HDPrivateKey(x); } return credentials_1.Credentials.fromDerivedKey({ xPubKey: xPrivKey.hdPublicKey.toString(), coin: opts.coin, chain: ((_a = opts.chain) === null || _a === void 0 ? void 0 : _a.toLowerCase()) || common_1.Utils.getChain(opts.coin), network: opts.network, account: opts.account, n: opts.n, rootPath: path, keyId: this.id, requestPrivKey, addressType: opts.addressType, walletPrivKey: opts.walletPrivKey }); }; this.createAccess = function (password, opts) { opts = opts || {}; $.shouldBeString(opts.path); var requestPrivKey = new Bitcore.PrivateKey(opts.requestPrivKey || null); var requestPubKey = requestPrivKey.toPublicKey().toString(); var xPriv = this.derive(password, opts.path); var signature = common_1.Utils.signRequestPubKey(requestPubKey, xPriv); requestPrivKey = requestPrivKey.toString(); return { signature, requestPrivKey }; }; this.sign = function (rootPath, txp, password, cb) { var _a; $.shouldBeString(rootPath); if (this.isPrivKeyEncrypted() && !password) { return cb(new Errors.ENCRYPTED_PRIVATE_KEY()); } var privs = []; var derived = {}; var derived = this.derive(password, rootPath); var xpriv = new Bitcore.HDPrivateKey(derived); var t = common_1.Utils.buildTx(txp); var chain = ((_a = txp.chain) === null || _a === void 0 ? void 0 : _a.toLowerCase()) || common_1.Utils.getChain(txp.coin); if (common_1.Constants.UTXO_CHAINS.includes(chain)) { for (const i of txp.inputs) { $.checkState(i.path, 'Input derivation path not available (signing transaction)'); if (!derived[i.path]) { derived[i.path] = xpriv.deriveChild(i.path).privateKey; privs.push(derived[i.path]); } } ; var signatures = privs.map(function (priv, i) { return t.getSignatures(priv, undefined, txp.signingMethod); }); signatures = signatures.flat().sort((a, b) => a.inputIndex - b.inputIndex); signatures = signatures.map(sig => sig.signature.toDER().toString('hex')); return signatures; } else { let tx = t.uncheckedSerialize(); tx = typeof tx === 'string' ? [tx] : tx; const txArray = _.isArray(tx) ? tx : [tx]; const isChange = false; const addressIndex = 0; const { privKey, pubKey } = crypto_wallet_core_1.Deriver.derivePrivateKey(chain.toUpperCase(), txp.network, derived, addressIndex, isChange); let signatures = []; for (const rawTx of txArray) { const signed = crypto_wallet_core_1.Transactions.getSignature({ chain: chain.toUpperCase(), tx: rawTx, key: { privKey, pubKey } }); signatures.push(signed); } return signatures; } }; __classPrivateFieldSet(this, _Key_version, 1, "f"); this.id = opts.id || Uuid.v4(); this.use0forBCH = opts.useLegacyCoinType; this.use44forMultisig = opts.useLegacyPurpose; this.compliantDerivation = !opts.nonCompliantDerivation; let x = opts.seedData; switch (opts.seedType) { case 'new': if (opts.language && !wordsForLang[opts.language]) throw new Error('Unsupported language'); let m = new Mnemonic(wordsForLang[opts.language]); while (!Mnemonic.isValid(m.toString())) { m = new Mnemonic(wordsForLang[opts.language]); } this.setFromMnemonic(m, opts); break; case 'mnemonic': $.checkArgument(x, 'Need to provide opts.seedData'); $.checkArgument(_.isString(x), 'sourceData need to be a string'); this.setFromMnemonic(new Mnemonic(x), opts); break; case 'extendedPrivateKey': $.checkArgument(x, 'Need to provide opts.seedData'); let xpriv; try { xpriv = new Bitcore.HDPrivateKey(x); } catch (e) { throw new Error('Invalid argument'); } this.fingerPrint = xpriv.fingerPrint.toString('hex'); if (opts.password) { __classPrivateFieldSet(this, _Key_xPrivKeyEncrypted, sjcl.encrypt(opts.password, xpriv.toString(), opts), "f"); if (!__classPrivateFieldGet(this, _Key_xPrivKeyEncrypted, "f")) throw new Error('Could not encrypt'); } else { __classPrivateFieldSet(this, _Key_xPrivKey, xpriv.toString(), "f"); } __classPrivateFieldSet(this, _Key_mnemonic, null, "f"); __classPrivateFieldSet(this, _Key_mnemonicHasPassphrase, null, "f"); break; case 'object': $.shouldBeObject(x, 'Need to provide an object at opts.seedData'); $.shouldBeUndefined(opts.password, 'opts.password not allowed when source is object'); if (__classPrivateFieldGet(this, _Key_version, "f") != x.version) { throw new Error('Bad Key version'); } __classPrivateFieldSet(this, _Key_xPrivKey, x.xPrivKey, "f"); __classPrivateFieldSet(this, _Key_xPrivKeyEncrypted, x.xPrivKeyEncrypted, "f"); __classPrivateFieldSet(this, _Key_mnemonic, x.mnemonic, "f"); __classPrivateFieldSet(this, _Key_mnemonicEncrypted, x.mnemonicEncrypted, "f"); __classPrivateFieldSet(this, _Key_mnemonicHasPassphrase, x.mnemonicHasPassphrase, "f"); __classPrivateFieldSet(this, _Key_version, x.version, "f"); this.fingerPrint = x.fingerPrint; this.compliantDerivation = x.compliantDerivation; this.BIP45 = x.BIP45; this.id = x.id; this.use0forBCH = x.use0forBCH; this.use44forMultisig = x.use44forMultisig; $.checkState(__classPrivateFieldGet(this, _Key_xPrivKey, "f") || __classPrivateFieldGet(this, _Key_xPrivKeyEncrypted, "f"), 'Failed state: #xPrivKey || #xPrivKeyEncrypted at Key constructor'); break; case 'objectV1': this.use0forBCH = false; this.use44forMultisig = false; this.compliantDerivation = true; this.id = Uuid.v4(); if (!_.isUndefined(x.compliantDerivation)) this.compliantDerivation = x.compliantDerivation; if (!_.isUndefined(x.id)) this.id = x.id; __classPrivateFieldSet(this, _Key_xPrivKey, x.xPrivKey, "f"); __classPrivateFieldSet(this, _Key_xPrivKeyEncrypted, x.xPrivKeyEncrypted, "f"); __classPrivateFieldSet(this, _Key_mnemonic, x.mnemonic, "f"); __classPrivateFieldSet(this, _Key_mnemonicEncrypted, x.mnemonicEncrypted, "f"); __classPrivateFieldSet(this, _Key_mnemonicHasPassphrase, x.mnemonicHasPassphrase, "f"); __classPrivateFieldSet(this, _Key_version, x.version || 1, "f"); this.fingerPrint = x.fingerPrint; this.use44forMultisig = x.n > 1 ? true : false; this.use0forBCH = x.use145forBCH ? false : x.coin == 'bch' ? true : false; this.BIP45 = x.derivationStrategy == 'BIP45'; break; default: throw new Error('Unknown seed source: ' + opts.seedType); } } static match(a, b) { return a.id == b.id || a.fingerPrint == b.fingerPrint; } setFromMnemonic(m, opts) { const xpriv = m.toHDPrivateKey(opts.passphrase, NETWORK); this.fingerPrint = xpriv.fingerPrint.toString('hex'); if (opts.password) { __classPrivateFieldSet(this, _Key_xPrivKeyEncrypted, sjcl.encrypt(opts.password, xpriv.toString(), opts.sjclOpts), "f"); if (!__classPrivateFieldGet(this, _Key_xPrivKeyEncrypted, "f")) throw new Error('Could not encrypt'); __classPrivateFieldSet(this, _Key_mnemonicEncrypted, sjcl.encrypt(opts.password, m.phrase, opts.sjclOpts), "f"); if (!__classPrivateFieldGet(this, _Key_mnemonicEncrypted, "f")) throw new Error('Could not encrypt'); } else { __classPrivateFieldSet(this, _Key_xPrivKey, xpriv.toString(), "f"); __classPrivateFieldSet(this, _Key_mnemonic, m.phrase, "f"); __classPrivateFieldSet(this, _Key_mnemonicHasPassphrase, !!opts.passphrase, "f"); } } } exports.Key = Key; _Key_xPrivKey = new WeakMap(), _Key_xPrivKeyEncrypted = new WeakMap(), _Key_version = new WeakMap(), _Key_mnemonic = new WeakMap(), _Key_mnemonicEncrypted = new WeakMap(), _Key_mnemonicHasPassphrase = new WeakMap(); //# sourceMappingURL=key.js.map