bitcore-wallet-client
Version:
Client for bitcore-wallet-service
435 lines • 21.8 kB
JavaScript
'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