diff --git a/angular-bitcore-wallet-client.js b/angular-bitcore-wallet-client.js index c41654f..d252a6a 100644 --- a/angular-bitcore-wallet-client.js +++ b/angular-bitcore-wallet-client.js @@ -2,59 +2,53 @@ var bwcModule = angular.module('bwcModule', []); var Client = require('bitcore-wallet-client'); -bwcModule.constant('MODULE_VERSION', '1.1.7'); +bwcModule.constant('MODULE_VERSION', '5.1.2'); bwcModule.provider("bwcService", function() { var provider = {}; var config = { - baseUrl: 'http://localhost:3001/bws/api', + baseUrl: 'https://bws.bitpay.com/bws/api', verbose: null, - transports: null - }; - - provider.setBaseUrl = function(url) { - config.baseUrl = url; - }; - - provider.setVerbose = function(v) { - config.verbose = v ? true : false; + timeout: 100000, + transports: ['polling'] }; provider.$get = function() { var service = {}; - service.setBaseUrl = function(url) { - config.baseUrl = url; - }; - - service.setTransports = function(transports) { - config.transports = transports; - }; - service.getBitcore = function() { return Client.Bitcore; }; + service.getErrors = function() { + return Client.errors; + }; + service.getSJCL = function() { return Client.sjcl; }; service.buildTx = Client.buildTx; service.parseSecret = Client.parseSecret; + service.Client = Client; service.getUtils = function() { return Client.Utils; }; - service.getClient = function(walletData) { + service.getClient = function(walletData, opts) { + opts = opts || {}; + + //note opts use `bwsurl` all lowercase; var bwc = new Client({ - baseUrl: config.baseUrl, - verbose: config.verbose, - transports: config.transports + baseUrl: opts.bwsurl || config.baseUrl, + verbose: opts.verbose || config.verbose, + timeout: config.timeout, + transports: config.transport }); if (walletData) - bwc.import(walletData); + bwc.import(walletData, opts); return bwc; }; return service; @@ -63,100253 +57,79645 @@ bwcModule.provider("bwcService", function() { return provider; }); -},{"bitcore-wallet-client":2}],2:[function(require,module,exports){ -var Client = require('./lib'); -module.exports = Client; - -},{"./lib":11}],3:[function(require,module,exports){ -(function (process,Buffer){ -/** @namespace Client.API */ -'use strict'; - -var _ = require('lodash'); -var $ = require('preconditions').singleton(); -var util = require('util'); -var async = require('async'); -var events = require('events'); -var Bitcore = require('bitcore-lib'); -var sjcl = require('sjcl'); -var url = require('url'); -var querystring = require('querystring'); -var Stringify = require('json-stable-stringify'); +},{"bitcore-wallet-client":126}],2:[function(require,module,exports){ +;(function () { -var request; -if (process && !process.browser) { - request = require('request'); -} else { - request = require('browser-request'); -} + var object = typeof exports != 'undefined' ? exports : this; // #8: web workers + var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; -var Common = require('./common'); -var Constants = Common.Constants; -var Defaults = Common.Defaults; -var Utils = Common.Utils; + function InvalidCharacterError(message) { + this.message = message; + } + InvalidCharacterError.prototype = new Error; + InvalidCharacterError.prototype.name = 'InvalidCharacterError'; -var PayPro = require('./paypro'); -var log = require('./log'); -var Credentials = require('./credentials'); -var Verifier = require('./verifier'); -var Package = require('../package.json'); -var ClientError = require('./errors/clienterror'); -var Errors = require('./errors/errordefinitions'); + // encoder + // [https://gist.github.com/999166] by [https://github.com/nignag] + object.btoa || ( + object.btoa = function (input) { + for ( + // initialize result and counter + var block, charCode, idx = 0, map = chars, output = ''; + // if the next input index does not exist: + // change the mapping table to "=" + // check if d has no fractional digits + input.charAt(idx | 0) || (map = '=', idx % 1); + // "8 - idx % 1 * 8" generates the sequence 2, 4, 6, 8 + output += map.charAt(63 & block >> 8 - idx % 1 * 8) + ) { + charCode = input.charCodeAt(idx += 3/4); + if (charCode > 0xFF) { + throw new InvalidCharacterError("'btoa' failed: The string to be encoded contains characters outside of the Latin1 range."); + } + block = block << 8 | charCode; + } + return output; + }); + // decoder + // [https://gist.github.com/1020396] by [https://github.com/atk] + object.atob || ( + object.atob = function (input) { + input = input.replace(/=+$/, ''); + if (input.length % 4 == 1) { + throw new InvalidCharacterError("'atob' failed: The string to be decoded is not correctly encoded."); + } + for ( + // initialize result and counters + var bc = 0, bs, buffer, idx = 0, output = ''; + // get next character + buffer = input.charAt(idx++); + // character found in table? initialize bit storage and add its ascii value; + ~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer, + // and if not first of each 4 characters, + // convert the first 8 bits to one ascii character + bc++ % 4) ? output += String.fromCharCode(255 & bs >> (-2 * bc & 6)) : 0 + ) { + // try to find character in table (0-63, not found => -1) + buffer = chars.indexOf(buffer); + } + return output; + }); +}()); -var BASE_URL = 'http://localhost:3232/bws/api'; +},{}],3:[function(require,module,exports){ +var asn1 = exports; -/** - * @desc ClientAPI constructor. - * - * @param {Object} opts - * @constructor - */ -function API(opts) { - opts = opts || {}; +asn1.bignum = require('bn.js'); - this.verbose = !!opts.verbose; - this.request = opts.request || request; - this.baseUrl = opts.baseUrl || BASE_URL; - var parsedUrl = url.parse(this.baseUrl); - this.basePath = parsedUrl.path; - this.baseHost = parsedUrl.protocol + '//' + parsedUrl.host; - this.payProHttp = null; // Only for testing - this.doNotVerifyPayPro = opts.doNotVerifyPayPro; +asn1.define = require('./asn1/api').define; +asn1.base = require('./asn1/base'); +asn1.constants = require('./asn1/constants'); +asn1.decoders = require('./asn1/decoders'); +asn1.encoders = require('./asn1/encoders'); - this.timeout = opts.timeout || 50000; +},{"./asn1/api":4,"./asn1/base":6,"./asn1/constants":10,"./asn1/decoders":12,"./asn1/encoders":15,"bn.js":143}],4:[function(require,module,exports){ +var asn1 = require('../asn1'); +var inherits = require('inherits'); +var api = exports; - if (this.verbose) { - log.setLevel('debug'); - } else { - log.setLevel('info'); - } +api.define = function define(name, body) { + return new Entity(name, body); }; -util.inherits(API, events.EventEmitter); -API.privateKeyEncryptionOpts = { - iter: 10000 -}; +function Entity(name, body) { + this.name = name; + this.body = body; -API.prototype.initNotifications = function(cb) { - log.warn('DEPRECATED: use initialize() instead.'); - this.initialize({}, cb); + this.decoders = {}; + this.encoders = {}; }; -API.prototype.initialize = function(opts, cb) { - $.checkState(this.credentials); +Entity.prototype._createNamed = function createNamed(base) { + var named; + try { + named = require('vm').runInThisContext( + '(function ' + this.name + '(entity) {\n' + + ' this._initNamed(entity);\n' + + '})' + ); + } catch (e) { + named = function (entity) { + this._initNamed(entity); + }; + } + inherits(named, base); + named.prototype._initNamed = function initnamed(entity) { + base.call(this, entity); + }; - var self = this; + return new named(this); +}; - self._initNotifications(opts); - return cb(); +Entity.prototype._getDecoder = function _getDecoder(enc) { + enc = enc || 'der'; + // Lazily create decoder + if (!this.decoders.hasOwnProperty(enc)) + this.decoders[enc] = this._createNamed(asn1.decoders[enc]); + return this.decoders[enc]; }; -API.prototype.dispose = function(cb) { - var self = this; - self._disposeNotifications(); - return cb(); +Entity.prototype.decode = function decode(data, enc, options) { + return this._getDecoder(enc).decode(data, options); }; -API.prototype._fetchLatestNotifications = function(interval, cb) { - var self = this; +Entity.prototype._getEncoder = function _getEncoder(enc) { + enc = enc || 'der'; + // Lazily create encoder + if (!this.encoders.hasOwnProperty(enc)) + this.encoders[enc] = this._createNamed(asn1.encoders[enc]); + return this.encoders[enc]; +}; - cb = cb || function() {}; +Entity.prototype.encode = function encode(data, enc, /* internal */ reporter) { + return this._getEncoder(enc).encode(data, reporter); +}; - var opts = { - lastNotificationId: self.lastNotificationId, - }; +},{"../asn1":3,"inherits":233,"vm":304}],5:[function(require,module,exports){ +var inherits = require('inherits'); +var Reporter = require('../base').Reporter; +var Buffer = require('buffer').Buffer; - if (!self.lastNotificationId) { - opts.timeSpan = interval; +function DecoderBuffer(base, options) { + Reporter.call(this, options); + if (!Buffer.isBuffer(base)) { + this.error('Input not Buffer'); + return; } - self.getNotifications(opts, function(err, notifications) { - if (err) { - log.warn('Error receiving notifications.'); - log.debug(err); - return cb(err); - } - if (notifications.length > 0) { - self.lastNotificationId = _.last(notifications).id; - } + this.base = base; + this.offset = 0; + this.length = base.length; +} +inherits(DecoderBuffer, Reporter); +exports.DecoderBuffer = DecoderBuffer; - _.each(notifications, function(notification) { - self.emit('notification', notification); - }); - return cb(); - }); +DecoderBuffer.prototype.save = function save() { + return { offset: this.offset, reporter: Reporter.prototype.save.call(this) }; }; -API.prototype._initNotifications = function(opts) { - var self = this; +DecoderBuffer.prototype.restore = function restore(save) { + // Return skipped data + var res = new DecoderBuffer(this.base); + res.offset = save.offset; + res.length = this.offset; - opts = opts || {}; + this.offset = save.offset; + Reporter.prototype.restore.call(this, save.reporter); - var interval = opts.notificationIntervalSeconds || 5; - self.notificationsIntervalId = setInterval(function() { - self._fetchLatestNotifications(interval, function(err) { - if (err) { - if (err.code == 'NOT_FOUND' || err.code == 'NOT_AUTHORIZED') { - self._disposeNotifications(); - } - } - }); - }, interval * 1000); + return res; }; -API.prototype._disposeNotifications = function() { - var self = this; - - if (self.notificationsIntervalId) { - clearInterval(self.notificationsIntervalId); - self.notificationsIntervalId = null; - } +DecoderBuffer.prototype.isEmpty = function isEmpty() { + return this.offset === this.length; }; +DecoderBuffer.prototype.readUInt8 = function readUInt8(fail) { + if (this.offset + 1 <= this.length) + return this.base.readUInt8(this.offset++, true); + else + return this.error(fail || 'DecoderBuffer overrun'); +} -/** - * Reset notification polling with new interval - * @memberof Client.API - * @param {Numeric} notificationIntervalSeconds - use 0 to pause notifications - */ -API.prototype.setNotificationsInterval = function(notificationIntervalSeconds) { - var self = this; - self._disposeNotifications(); - if (notificationIntervalSeconds > 0) { - self._initNotifications({ - notificationIntervalSeconds: notificationIntervalSeconds - }); - } -}; +DecoderBuffer.prototype.skip = function skip(bytes, fail) { + if (!(this.offset + bytes <= this.length)) + return this.error(fail || 'DecoderBuffer overrun'); + var res = new DecoderBuffer(this.base); -/** - * Encrypt a message - * @private - * @static - * @memberof Client.API - * @param {String} message - * @param {String} encryptingKey - */ -API._encryptMessage = function(message, encryptingKey) { - if (!message) return null; - return Utils.encryptMessage(message, encryptingKey); -}; + // Share reporter state + res._reporterState = this._reporterState; -/** - * Decrypt a message - * @private - * @static - * @memberof Client.API - * @param {String} message - * @param {String} encryptingKey - */ -API._decryptMessage = function(message, encryptingKey) { - if (!message) return ''; - try { - return Utils.decryptMessage(message, encryptingKey); - } catch (ex) { - return ''; + res.offset = this.offset; + res.length = this.offset + bytes; + this.offset += bytes; + return res; +} + +DecoderBuffer.prototype.raw = function raw(save) { + return this.base.slice(save ? save.offset : this.offset, this.length); +} + +function EncoderBuffer(value, reporter) { + if (Array.isArray(value)) { + this.length = 0; + this.value = value.map(function(item) { + if (!(item instanceof EncoderBuffer)) + item = new EncoderBuffer(item, reporter); + this.length += item.length; + return item; + }, this); + } else if (typeof value === 'number') { + if (!(0 <= value && value <= 0xff)) + return reporter.error('non-byte EncoderBuffer value'); + this.value = value; + this.length = 1; + } else if (typeof value === 'string') { + this.value = value; + this.length = Buffer.byteLength(value); + } else if (Buffer.isBuffer(value)) { + this.value = value; + this.length = value.length; + } else { + return reporter.error('Unsupported type: ' + typeof value); } -}; +} +exports.EncoderBuffer = EncoderBuffer; -/** - * Decrypt text fields in transaction proposals - * @private - * @static - * @memberof Client.API - * @param {Array} txps - * @param {String} encryptingKey - */ -API.prototype._processTxps = function(txps) { - var self = this; - if (!txps) return; +EncoderBuffer.prototype.join = function join(out, offset) { + if (!out) + out = new Buffer(this.length); + if (!offset) + offset = 0; - var encryptingKey = self.credentials.sharedEncryptingKey; - _.each([].concat(txps), function(txp) { - txp.encryptedMessage = txp.message; - txp.message = API._decryptMessage(txp.message, encryptingKey) || null; + if (this.length === 0) + return out; - _.each(txp.actions, function(action) { - action.comment = API._decryptMessage(action.comment, encryptingKey); - // TODO get copayerName from Credentials -> copayerId to copayerName - // action.copayerName = null; - }); - _.each(txp.outputs, function(output) { - output.encryptedMessage = output.message; - output.message = API._decryptMessage(output.message, encryptingKey) || null; - }); - txp.hasUnconfirmedInputs = _.any(txp.inputs, function(input) { - return input.confirmations == 0; + if (Array.isArray(this.value)) { + this.value.forEach(function(item) { + item.join(out, offset); + offset += item.length; }); - }); -}; - -/** - * Parse errors - * @private - * @static - * @memberof Client.API - * @param {Object} body - */ -API._parseError = function(body) { - if (_.isString(body)) { - try { - body = JSON.parse(body); - } catch (e) { - body = { - error: body - }; - } - } - var ret; - if (body && body.code) { - ret = new ClientError(body.code, body.message); } else { - ret = { - code: 'ERROR', - error: body ? body.error : 'There was an unknown error processing the request', - }; + if (typeof this.value === 'number') + out[offset] = this.value; + else if (typeof this.value === 'string') + out.write(this.value, offset); + else if (Buffer.isBuffer(this.value)) + this.value.copy(out, offset); + offset += this.length; } - log.error(ret); - return ret; -}; -/** - * Sign an HTTP request - * @private - * @static - * @memberof Client.API - * @param {String} method - The HTTP method - * @param {String} url - The URL for the request - * @param {Object} args - The arguments in case this is a POST/PUT request - * @param {String} privKey - Private key to sign the request - */ -API._signRequest = function(method, url, args, privKey) { - var message = [method.toLowerCase(), url, JSON.stringify(args)].join('|'); - return Utils.signMessage(message, privKey); + return out; }; +},{"../base":6,"buffer":174,"inherits":233}],6:[function(require,module,exports){ +var base = exports; -/** - * Seed from random - * - * @param {Object} opts - * @param {String} opts.network - default 'livenet' - */ -API.prototype.seedFromRandom = function(opts) { - $.checkArgument(arguments.length <= 1, 'DEPRECATED: only 1 argument accepted.'); - $.checkArgument(_.isUndefined(opts) || _.isObject(opts), 'DEPRECATED: argument should be an options object.'); +base.Reporter = require('./reporter').Reporter; +base.DecoderBuffer = require('./buffer').DecoderBuffer; +base.EncoderBuffer = require('./buffer').EncoderBuffer; +base.Node = require('./node'); - opts = opts || {}; - this.credentials = Credentials.create(opts.network || 'livenet'); -}; +},{"./buffer":5,"./node":7,"./reporter":8}],7:[function(require,module,exports){ +var Reporter = require('../base').Reporter; +var EncoderBuffer = require('../base').EncoderBuffer; +var DecoderBuffer = require('../base').DecoderBuffer; +var assert = require('minimalistic-assert'); -/** - * Seed from random with mnemonic - * - * @param {Object} opts - * @param {String} opts.network - default 'livenet' - * @param {String} opts.passphrase - * @param {Number} opts.language - default 'en' - * @param {Number} opts.account - default 0 - */ -API.prototype.seedFromRandomWithMnemonic = function(opts) { - $.checkArgument(arguments.length <= 1, 'DEPRECATED: only 1 argument accepted.'); - $.checkArgument(_.isUndefined(opts) || _.isObject(opts), 'DEPRECATED: argument should be an options object.'); +// Supported tags +var tags = [ + 'seq', 'seqof', 'set', 'setof', 'objid', 'bool', + 'gentime', 'utctime', 'null_', 'enum', 'int', 'objDesc', + 'bitstr', 'bmpstr', 'charstr', 'genstr', 'graphstr', 'ia5str', 'iso646str', + 'numstr', 'octstr', 'printstr', 't61str', 'unistr', 'utf8str', 'videostr' +]; - opts = opts || {}; - this.credentials = Credentials.createWithMnemonic(opts.network || 'livenet', opts.passphrase, opts.language || 'en', opts.account || 0); -}; +// Public methods list +var methods = [ + 'key', 'obj', 'use', 'optional', 'explicit', 'implicit', 'def', 'choice', + 'any', 'contains' +].concat(tags); -API.prototype.getMnemonic = function() { - return this.credentials.getMnemonic(); -}; +// Overrided methods list +var overrided = [ + '_peekTag', '_decodeTag', '_use', + '_decodeStr', '_decodeObjid', '_decodeTime', + '_decodeNull', '_decodeInt', '_decodeBool', '_decodeList', -API.prototype.mnemonicHasPassphrase = function() { - return this.credentials.mnemonicHasPassphrase; -}; + '_encodeComposite', '_encodeStr', '_encodeObjid', '_encodeTime', + '_encodeNull', '_encodeInt', '_encodeBool' +]; +function Node(enc, parent) { + var state = {}; + this._baseState = state; + state.enc = enc; -API.prototype.clearMnemonic = function() { - return this.credentials.clearMnemonic(); -}; + state.parent = parent || null; + state.children = null; + // State + state.tag = null; + state.args = null; + state.reverseArgs = null; + state.choice = null; + state.optional = false; + state.any = false; + state.obj = false; + state.use = null; + state.useDecoder = null; + state.key = null; + state['default'] = null; + state.explicit = null; + state.implicit = null; + state.contains = null; -/** - * Seed from extended private key - * - * @param {String} xPrivKey - */ -API.prototype.seedFromExtendedPrivateKey = function(xPrivKey) { - this.credentials = Credentials.fromExtendedPrivateKey(xPrivKey); -}; + // Should create new instance on each method + if (!state.parent) { + state.children = []; + this._wrap(); + } +} +module.exports = Node; +var stateProps = [ + 'enc', 'parent', 'children', 'tag', 'args', 'reverseArgs', 'choice', + 'optional', 'any', 'obj', 'use', 'alteredUse', 'key', 'default', 'explicit', + 'implicit', 'contains' +]; -/** - * Seed from Mnemonics (language autodetected) - * Can throw an error if mnemonic is invalid - * - * @param {String} BIP39 words - * @param {Object} opts - * @param {String} opts.network - default 'livenet' - * @param {String} opts.passphrase - * @param {Number} opts.account - default 0 - * @param {String} opts.derivationStrategy - default 'BIP44' - */ -API.prototype.seedFromMnemonic = function(words, opts) { - $.checkArgument(_.isUndefined(opts) || _.isObject(opts), 'DEPRECATED: second argument should be an options object.'); +Node.prototype.clone = function clone() { + var state = this._baseState; + var cstate = {}; + stateProps.forEach(function(prop) { + cstate[prop] = state[prop]; + }); + var res = new this.constructor(cstate.parent); + res._baseState = cstate; + return res; +}; - opts = opts || {}; - this.credentials = Credentials.fromMnemonic(opts.network || 'livenet', words, opts.passphrase, opts.account || 0, opts.derivationStrategy || Constants.DERIVATION_STRATEGIES.BIP44); +Node.prototype._wrap = function wrap() { + var state = this._baseState; + methods.forEach(function(method) { + this[method] = function _wrappedMethod() { + var clone = new this.constructor(this); + state.children.push(clone); + return clone[method].apply(clone, arguments); + }; + }, this); }; -/** - * Seed from external wallet public key - * - * @param {String} xPubKey - * @param {String} source - A name identifying the source of the xPrivKey (e.g. ledger, TREZOR, ...) - * @param {String} entropySourceHex - A HEX string containing pseudo-random data, that can be deterministically derived from the xPrivKey, and should not be derived from xPubKey. - * @param {Object} opts - * @param {Number} opts.account - default 0 - * @param {String} opts.derivationStrategy - default 'BIP44' - */ -API.prototype.seedFromExtendedPublicKey = function(xPubKey, source, entropySourceHex, opts) { - $.checkArgument(_.isUndefined(opts) || _.isObject(opts)); +Node.prototype._init = function init(body) { + var state = this._baseState; - opts = opts || {}; - this.credentials = Credentials.fromExtendedPublicKey(xPubKey, source, entropySourceHex, opts.account || 0, opts.derivationStrategy || Constants.DERIVATION_STRATEGIES.BIP44); -}; + assert(state.parent === null); + body.call(this); + // Filter children + state.children = state.children.filter(function(child) { + return child._baseState.parent === this; + }, this); + assert.equal(state.children.length, 1, 'Root node can have only one child'); +}; -/** - * Export wallet - * - * @param {Object} opts - * @param {Boolean} opts.noSign - */ -API.prototype.export = function(opts) { - $.checkState(this.credentials); +Node.prototype._useArgs = function useArgs(args) { + var state = this._baseState; - opts = opts || {}; + // Filter children and args + var children = args.filter(function(arg) { + return arg instanceof this.constructor; + }, this); + args = args.filter(function(arg) { + return !(arg instanceof this.constructor); + }, this); - var output; + if (children.length !== 0) { + assert(state.children === null); + state.children = children; - var c = Credentials.fromObj(this.credentials); + // Replace parent to maintain backward link + children.forEach(function(child) { + child._baseState.parent = this; + }, this); + } + if (args.length !== 0) { + assert(state.args === null); + state.args = args; + state.reverseArgs = args.map(function(arg) { + if (typeof arg !== 'object' || arg.constructor !== Object) + return arg; - if (opts.noSign) { - c.setNoSign(); + var res = {}; + Object.keys(arg).forEach(function(key) { + if (key == (key | 0)) + key |= 0; + var value = arg[key]; + res[value] = key; + }); + return res; + }); } +}; - output = JSON.stringify(c.toObj()); +// +// Overrided methods +// - return output; -} +overrided.forEach(function(method) { + Node.prototype[method] = function _overrided() { + var state = this._baseState; + throw new Error(method + ' not implemented for encoding: ' + state.enc); + }; +}); +// +// Public methods +// -/** - * Import wallet - * - * @param {Object} str - * @param {Object} opts - * @param {String} opts.password If the source has the private key encrypted, the password - * will be needed for derive credentials fields. - */ -API.prototype.import = function(str, opts) { - opts = opts || {}; - try { - var credentials = Credentials.fromObj(JSON.parse(str)); - this.credentials = credentials; - } catch (ex) { - throw Errors.INVALID_BACKUP; - } -}; +tags.forEach(function(tag) { + Node.prototype[tag] = function _tagMethod() { + var state = this._baseState; + var args = Array.prototype.slice.call(arguments); -API.prototype._import = function(cb) { - $.checkState(this.credentials); + assert(state.tag === null); + state.tag = tag; - var self = this; + this._useArgs(args); - // First option, grab wallet info from BWS. - self.openWallet(function(err, ret) { + return this; + }; +}); - // it worked? - if (!err) return cb(null, ret); +Node.prototype.use = function use(item) { + assert(item); + var state = this._baseState; - // Is the error other than "copayer was not found"? || or no priv key. - if (err.code != 'NOT_AUTHORIZED' || self.isPrivKeyExternal()) - return cb(err); + assert(state.use === null); + state.use = item; - //Second option, lets try to add an access - log.info('Copayer not found, trying to add access'); - self.addAccess({}, function(err) { + return this; +}; - // it worked? - if (!err) self.openWallet(cb); +Node.prototype.optional = function optional() { + var state = this._baseState; - return cb(Errors.WALLET_DOES_NOT_EXIST) - }); - }); + state.optional = true; + + return this; }; -/** - * Import from Mnemonics (language autodetected) - * Can throw an error if mnemonic is invalid - * - * @param {String} BIP39 words - * @param {Object} opts - * @param {String} opts.network - default 'livenet' - * @param {String} opts.passphrase - * @param {Number} opts.account - default 0 - * @param {String} opts.derivationStrategy - default 'BIP44' - */ -API.prototype.importFromMnemonic = function(words, opts, cb) { - log.debug('Importing from 12 Words'); +Node.prototype.def = function def(val) { + var state = this._baseState; - opts = opts || {}; - try { - this.credentials = Credentials.fromMnemonic(opts.network || 'livenet', words, opts.passphrase, opts.account || 0, opts.derivationStrategy || Constants.DERIVATION_STRATEGIES.BIP44); - } catch (e) { - log.info('Mnemonic error:', e); - return cb(Errors.INVALID_BACKUP); - }; + assert(state['default'] === null); + state['default'] = val; + state.optional = true; - this._import(cb); + return this; }; -API.prototype.importFromExtendedPrivateKey = function(xPrivKey, cb) { - log.debug('Importing from Extended Private Key'); - try { - this.credentials = Credentials.fromExtendedPrivateKey(xPrivKey); - } catch (e) { - log.info('xPriv error:', e); - return cb(Errors.INVALID_BACKUP); - }; +Node.prototype.explicit = function explicit(num) { + var state = this._baseState; - this._import(cb); + assert(state.explicit === null && state.implicit === null); + state.explicit = num; + + return this; }; -/** - * Import from Extended Public Key - * - * @param {String} xPubKey - * @param {String} source - A name identifying the source of the xPrivKey - * @param {String} entropySourceHex - A HEX string containing pseudo-random data, that can be deterministically derived from the xPrivKey, and should not be derived from xPubKey. - * @param {Object} opts - * @param {Number} opts.account - default 0 - * @param {String} opts.derivationStrategy - default 'BIP44' - */ -API.prototype.importFromExtendedPublicKey = function(xPubKey, source, entropySourceHex, opts, cb) { - $.checkArgument(arguments.length == 5, "DEPRECATED: should receive 5 arguments"); - $.checkArgument(_.isUndefined(opts) || _.isObject(opts)); - $.shouldBeFunction(cb); +Node.prototype.implicit = function implicit(num) { + var state = this._baseState; - opts = opts || {}; - log.debug('Importing from Extended Private Key'); - try { - this.credentials = Credentials.fromExtendedPublicKey(xPubKey, source, entropySourceHex, opts.account || 0, opts.derivationStrategy || Constants.DERIVATION_STRATEGIES.BIP44); - } catch (e) { - log.info('xPriv error:', e); - return cb(Errors.INVALID_BACKUP); - }; + assert(state.explicit === null && state.implicit === null); + state.implicit = num; - this._import(cb); + return this; }; -API.prototype.decryptBIP38PrivateKey = function(encryptedPrivateKeyBase58, passphrase, opts, cb) { - var Bip38 = require('bip38'); - var bip38 = new Bip38(); - - var privateKeyWif; - try { - privateKeyWif = bip38.decrypt(encryptedPrivateKeyBase58, passphrase); - } catch (ex) { - return cb(new Error('Could not decrypt BIP38 private key', ex)); - } +Node.prototype.obj = function obj() { + var state = this._baseState; + var args = Array.prototype.slice.call(arguments); - var privateKey = new Bitcore.PrivateKey(privateKeyWif); - var address = privateKey.publicKey.toAddress().toString(); - var addrBuff = new Buffer(address, 'ascii'); - var actualChecksum = Bitcore.crypto.Hash.sha256sha256(addrBuff).toString('hex').substring(0, 8); - var expectedChecksum = Bitcore.encoding.Base58Check.decode(encryptedPrivateKeyBase58).toString('hex').substring(6, 14); + state.obj = true; - if (actualChecksum != expectedChecksum) - return cb(new Error('Incorrect passphrase')); + if (args.length !== 0) + this._useArgs(args); - return cb(null, privateKeyWif); + return this; }; -API.prototype.getBalanceFromPrivateKey = function(privateKey, cb) { - var self = this; +Node.prototype.key = function key(newKey) { + var state = this._baseState; - var privateKey = new Bitcore.PrivateKey(privateKey); - var address = privateKey.publicKey.toAddress(); - self.getUtxos({ - addresses: address.toString(), - }, function(err, utxos) { - if (err) return cb(err); - return cb(null, _.sum(utxos, 'satoshis')); - }); -}; + assert(state.key === null); + state.key = newKey; -API.prototype.buildTxFromPrivateKey = function(privateKey, destinationAddress, opts, cb) { - var self = this; + return this; +}; - opts = opts || {}; +Node.prototype.any = function any() { + var state = this._baseState; - var privateKey = new Bitcore.PrivateKey(privateKey); - var address = privateKey.publicKey.toAddress(); + state.any = true; - async.waterfall([ + return this; +}; - function(next) { - self.getUtxos({ - addresses: address.toString(), - }, function(err, utxos) { - return next(err, utxos); - }); - }, - function(utxos, next) { - if (!_.isArray(utxos) || utxos.length == 0) return next(new Error('No utxos found')); +Node.prototype.choice = function choice(obj) { + var state = this._baseState; - var fee = opts.fee || 10000; - var amount = _.sum(utxos, 'satoshis') - fee; - if (amount <= 0) return next(Errors.INSUFFICIENT_FUNDS); + assert(state.choice === null); + state.choice = obj; + this._useArgs(Object.keys(obj).map(function(key) { + return obj[key]; + })); - var tx; - try { - var toAddress = Bitcore.Address.fromString(destinationAddress); + return this; +}; - tx = new Bitcore.Transaction() - .from(utxos) - .to(toAddress, amount) - .fee(fee) - .sign(privateKey); +Node.prototype.contains = function contains(item) { + var state = this._baseState; - // Make sure the tx can be serialized - tx.serialize(); + assert(state.use === null); + state.contains = item; - } catch (ex) { - log.error('Could not build transaction from private key', ex); - return next(Errors.COULD_NOT_BUILD_TRANSACTION); - } - return next(null, tx); - } - ], cb); + return this; }; -/** - * Open a wallet and try to complete the public key ring. - * - * @param {Callback} cb - The callback that handles the response. It returns a flag indicating that the wallet is complete. - * @fires API#walletCompleted - */ -API.prototype.openWallet = function(cb) { - $.checkState(this.credentials); - var self = this; - if (self.credentials.isComplete() && self.credentials.hasWalletInfo()) - return cb(null, true); +// +// Decoding +// - self._doGetRequest('/v2/wallets/?includeExtendedInfo=1', function(err, ret) { - if (err) return cb(err); - var wallet = ret.wallet; +Node.prototype._decode = function decode(input, options) { + var state = this._baseState; - if (wallet.status != 'complete') - return cb(); + // Decode root node + if (state.parent === null) + return input.wrapResult(state.children[0]._decode(input, options)); - if (self.credentials.walletPrivKey) { - if (!Verifier.checkCopayers(self.credentials, wallet.copayers)) { - return cb(Errors.SERVER_COMPROMISED); + var result = state['default']; + var present = true; + + var prevKey = null; + if (state.key !== null) + prevKey = input.enterKey(state.key); + + // Check if tag is there + if (state.optional) { + var tag = null; + if (state.explicit !== null) + tag = state.explicit; + else if (state.implicit !== null) + tag = state.implicit; + else if (state.tag !== null) + tag = state.tag; + + if (tag === null && !state.any) { + // Trial and Error + var save = input.save(); + try { + if (state.choice === null) + this._decodeGeneric(state.tag, input, options); + else + this._decodeChoice(input, options); + present = true; + } catch (e) { + present = false; } + input.restore(save); } else { - // this should only happends in AIR-GAPPED flows - log.warn('Could not verify copayers key (missing wallet Private Key)'); - } - - // Wallet was not complete. We are completing it. - self.credentials.addPublicKeyRing(API._extractPublicKeyRing(wallet.copayers)); + present = this._peekTag(input, tag, state.any); - if (!self.credentials.hasWalletInfo()) { - var me = _.find(wallet.copayers, { - id: self.credentials.copayerId - }); - self.credentials.addWalletInfo(wallet.id, wallet.name, wallet.m, wallet.n, null, me.name); + if (input.isError(present)) + return present; } - self.emit('walletCompleted', wallet); + } - self._processTxps(ret.pendingTxps); - self._processCustomData(ret); + // Push object on stack + var prevObj; + if (state.obj && present) + prevObj = input.enterObject(); - return cb(null, ret); - }); -}; + if (present) { + // Unwrap explicit values + if (state.explicit !== null) { + var explicit = this._decodeTag(input, state.explicit); + if (input.isError(explicit)) + return explicit; + input = explicit; + } + var start = input.offset; + // Unwrap implicit and normal values + if (state.use === null && state.choice === null) { + if (state.any) + var save = input.save(); + var body = this._decodeTag( + input, + state.implicit !== null ? state.implicit : state.tag, + state.any + ); + if (input.isError(body)) + return body; -/** - * Do an HTTP request - * @private - * - * @param {Object} method - * @param {String} url - * @param {Object} args - * @param {Callback} cb - */ -API.prototype._doRequest = function(method, url, args, cb) { - $.checkState(this.credentials); + if (state.any) + result = input.raw(save); + else + input = body; + } - var reqSignature; + if (options && options.track && state.tag !== null) + options.track(input.path(), start, input.length, 'tagged'); - var key = args._requestPrivKey || this.credentials.requestPrivKey; - if (key) { - delete args['_requestPrivKey']; - reqSignature = API._signRequest(method, url, args, key); - } + if (options && options.track && state.tag !== null) + options.track(input.path(), input.offset, input.length, 'content'); - var absUrl = this.baseUrl + url; - var args = { - // relUrl: only for testing with `supertest` - relUrl: this.basePath + url, - headers: { - 'x-identity': this.credentials.copayerId, - 'x-signature': reqSignature, - 'x-client-version': 'bwc-' + Package.version, - }, - method: method, - url: absUrl, - body: args, - json: true, - withCredentials: false, - timeout: this.timeout, - }; + // Select proper method for tag + if (state.any) + result = result; + else if (state.choice === null) + result = this._decodeGeneric(state.tag, input, options); + else + result = this._decodeChoice(input, options); - log.debug('Request Args', util.inspect(args, { - depth: 10 - })); + if (input.isError(result)) + return result; - this.request(args, function(err, res, body) { - log.debug(util.inspect(body, { - depth: 10 - })); - if (!res) { - return cb({ - code: 'CONNECTION_ERROR', + // Decode children + if (!state.any && state.choice === null && state.children !== null) { + state.children.forEach(function decodeChildren(child) { + // NOTE: We are ignoring errors here, to let parser continue with other + // parts of encoded data + child._decode(input, options); }); } - if (res.statusCode != 200) { - if (res.statusCode == 404) - return cb({ - code: 'NOT_FOUND' - }); - - if (!res.statusCode) - return cb({ - code: 'CONNECTION_ERROR', - }); - - return cb(API._parseError(body)); + // Decode contained/encoded by schema, only in bit or octet strings + if (state.contains && (state.tag === 'octstr' || state.tag === 'bitstr')) { + var data = new DecoderBuffer(result); + result = this._getUse(state.contains, input._reporterState.obj) + ._decode(data, options); } + } - if (body === '{"error":"read ECONNRESET"}') - return cb(JSON.parse(body)); - - return cb(null, body, res.header); - }); -}; + // Pop object + if (state.obj && present) + result = input.leaveObject(prevObj); -/** - * Do a POST request - * @private - * - * @param {String} url - * @param {Object} args - * @param {Callback} cb - */ -API.prototype._doPostRequest = function(url, args, cb) { - return this._doRequest('post', url, args, cb); -}; + // Set key + if (state.key !== null && (result !== null || present === true)) + input.leaveKey(prevKey, state.key, result); + else if (prevKey !== null) + input.exitKey(prevKey); -API.prototype._doPutRequest = function(url, args, cb) { - return this._doRequest('put', url, args, cb); + return result; }; -/** - * Do a GET request - * @private - * - * @param {String} url - * @param {Callback} cb - */ -API.prototype._doGetRequest = function(url, cb) { - url += url.indexOf('?') > 0 ? '&' : '?'; - url += 'r=' + _.random(10000, 99999); - return this._doRequest('get', url, {}, cb); -}; +Node.prototype._decodeGeneric = function decodeGeneric(tag, input, options) { + var state = this._baseState; -/** - * Do a DELETE request - * @private - * - * @param {String} url - * @param {Callback} cb - */ -API.prototype._doDeleteRequest = function(url, cb) { - return this._doRequest('delete', url, {}, cb); -}; + if (tag === 'seq' || tag === 'set') + return null; + if (tag === 'seqof' || tag === 'setof') + return this._decodeList(input, tag, state.args[0], options); + else if (/str$/.test(tag)) + return this._decodeStr(input, tag, options); + else if (tag === 'objid' && state.args) + return this._decodeObjid(input, state.args[0], state.args[1], options); + else if (tag === 'objid') + return this._decodeObjid(input, null, null, options); + else if (tag === 'gentime' || tag === 'utctime') + return this._decodeTime(input, tag, options); + else if (tag === 'null_') + return this._decodeNull(input, options); + else if (tag === 'bool') + return this._decodeBool(input, options); + else if (tag === 'objDesc') + return this._decodeStr(input, tag, options); + else if (tag === 'int' || tag === 'enum') + return this._decodeInt(input, state.args && state.args[0], options); -API._buildSecret = function(walletId, walletPrivKey, network) { - if (_.isString(walletPrivKey)) { - walletPrivKey = Bitcore.PrivateKey.fromString(walletPrivKey); + if (state.use !== null) { + return this._getUse(state.use, input._reporterState.obj) + ._decode(input, options); + } else { + return input.error('unknown tag: ' + tag); } - var widHex = new Buffer(walletId.replace(/-/g, ''), 'hex'); - var widBase58 = new Bitcore.encoding.Base58(widHex).toString(); - return _.padRight(widBase58, 22, '0') + walletPrivKey.toWIF() + (network == 'testnet' ? 'T' : 'L'); }; -API.parseSecret = function(secret) { - $.checkArgument(secret); +Node.prototype._getUse = function _getUse(entity, obj) { - function split(str, indexes) { - var parts = []; - indexes.push(str.length); - var i = 0; - while (i < indexes.length) { - parts.push(str.substring(i == 0 ? 0 : indexes[i - 1], indexes[i])); - i++; - }; - return parts; - }; - - try { - var secretSplit = split(secret, [22, 74]); - var widBase58 = secretSplit[0].replace(/0/g, ''); - var widHex = Bitcore.encoding.Base58.decode(widBase58).toString('hex'); - var walletId = split(widHex, [8, 12, 16, 20]).join('-'); - - var walletPrivKey = Bitcore.PrivateKey.fromString(secretSplit[1]); - var networkChar = secretSplit[2]; - - return { - walletId: walletId, - walletPrivKey: walletPrivKey, - network: networkChar == 'T' ? 'testnet' : 'livenet', - }; - } catch (ex) { - throw new Error('Invalid secret'); + var state = this._baseState; + // Create altered use decoder if implicit is set + state.useDecoder = this._use(entity, obj); + assert(state.useDecoder._baseState.parent === null); + state.useDecoder = state.useDecoder._baseState.children[0]; + if (state.implicit !== state.useDecoder._baseState.implicit) { + state.useDecoder = state.useDecoder.clone(); + state.useDecoder._baseState.implicit = state.implicit; } + return state.useDecoder; }; -API.buildTx = function(txp) { - var t = new Bitcore.Transaction(); +Node.prototype._decodeChoice = function decodeChoice(input, options) { + var state = this._baseState; + var result = null; + var match = false; - $.checkState(_.contains(_.values(Constants.SCRIPT_TYPES), txp.addressType)); + Object.keys(state.choice).some(function(key) { + var save = input.save(); + var node = state.choice[key]; + try { + var value = node._decode(input, options); + if (input.isError(value)) + return false; - switch (txp.addressType) { - case Constants.SCRIPT_TYPES.P2SH: - _.each(txp.inputs, function(i) { - t.from(i, i.publicKeys, txp.requiredSignatures); - }); - break; - case Constants.SCRIPT_TYPES.P2PKH: - t.from(txp.inputs); - break; - } + result = { type: key, value: value }; + match = true; + } catch (e) { + input.restore(save); + return false; + } + return true; + }, this); - if (txp.toAddress && txp.amount && !txp.outputs) { - t.to(txp.toAddress, txp.amount); - } else if (txp.outputs) { - _.each(txp.outputs, function(o) { - $.checkState(!o.script != !o.toAddress, 'Output should have either toAddress or script specified'); - if (o.script) { - t.addOutput(new Bitcore.Transaction.Output({ - script: o.script, - satoshis: o.amount - })); - } else { - t.to(o.toAddress, o.amount); - } - }); - } + if (!match) + return input.error('Choice not matched'); - if (_.startsWith(txp.version, '1.')) { - Bitcore.Transaction.FEE_SECURITY_MARGIN = 1; - t.feePerKb(txp.feePerKb); - } else { - t.fee(txp.fee); - } + return result; +}; - t.change(txp.changeAddress.address); +// +// Encoding +// - // Shuffle outputs for improved privacy - if (t.outputs.length > 1) { - $.checkState(t.outputs.length == txp.outputOrder.length); - t.sortOutputs(function(outputs) { - return _.map(txp.outputOrder, function(i) { - return outputs[i]; - }); - }); - } +Node.prototype._createEncoderBuffer = function createEncoderBuffer(data) { + return new EncoderBuffer(data, this.reporter); +}; - // Validate inputs vs outputs independently of Bitcore - var totalInputs = _.reduce(txp.inputs, function(memo, i) { - return +i.satoshis + memo; - }, 0); - var totalOutputs = _.reduce(t.outputs, function(memo, o) { - return +o.satoshis + memo; - }, 0); +Node.prototype._encode = function encode(data, reporter, parent) { + var state = this._baseState; + if (state['default'] !== null && state['default'] === data) + return; - $.checkState(totalInputs - totalOutputs <= Defaults.MAX_TX_FEE); + var result = this._encodeValue(data, reporter, parent); + if (result === undefined) + return; - return t; + if (this._skipDefault(result, reporter, parent)) + return; + + return result; }; -API.prototype._signTxp = function(txp) { - var self = this; +Node.prototype._encodeValue = function encode(data, reporter, parent) { + var state = this._baseState; - $.checkArgument(txp); + // Decode root node + if (state.parent === null) + return state.children[0]._encode(data, reporter || new Reporter()); - //Derive proper key to sign, for each input - var privs = []; - var derived = {}; + var result = null; - var xpriv = self.credentials.getDerivedXPrivKey(); + // Set reporter to share it with a child class + this.reporter = reporter; - _.each(txp.inputs, function(i) { - if (!derived[i.path]) { - derived[i.path] = xpriv.derive(i.path).privateKey; - privs.push(derived[i.path]); - } - }); + // Check if data is there + if (state.optional && data === undefined) { + if (state['default'] !== null) + data = state['default'] + else + return; + } - var t = API.buildTx(txp); + // Encode children first + var content = null; + var primitive = false; + if (state.any) { + // Anything that was given is translated to buffer + result = this._createEncoderBuffer(data); + } else if (state.choice) { + result = this._encodeChoice(data, reporter); + } else if (state.contains) { + content = this._getUse(state.contains, parent)._encode(data, reporter); + primitive = true; + } else if (state.children) { + content = state.children.map(function(child) { + if (child._baseState.tag === 'null_') + return child._encode(null, reporter, data); - var signatures = _.map(privs, function(priv, i) { - return t.getSignatures(priv); - }); + if (child._baseState.key === null) + return reporter.error('Child should have a key'); + var prevKey = reporter.enterKey(child._baseState.key); - signatures = _.map(_.sortBy(_.flatten(signatures), 'inputIndex'), function(s) { - return s.signature.toDER().toString('hex'); - }); + if (typeof data !== 'object') + return reporter.error('Child expected, but input is not object'); - return signatures; -}; + var res = child._encode(data[child._baseState.key], reporter, data); + reporter.leaveKey(prevKey); -/** - * Join - * @private - * - * @param {String} walletId - * @param {String} walletPrivKey - * @param {String} xPubKey - * @param {String} requestPubKey - * @param {String} copayerName - * @param {Object} Optional args - * @param {String} opts.customData - * @param {Callback} cb - */ -API.prototype._doJoinWallet = function(walletId, walletPrivKey, xPubKey, requestPubKey, copayerName, opts, cb) { - $.shouldBeFunction(cb); - opts = opts || {}; + return res; + }, this).filter(function(child) { + return child; + }); + content = this._createEncoderBuffer(content); + } else { + if (state.tag === 'seqof' || state.tag === 'setof') { + // TODO(indutny): this should be thrown on DSL level + if (!(state.args && state.args.length === 1)) + return reporter.error('Too many args for : ' + state.tag); - // Adds encrypted walletPrivateKey to CustomData - opts.customData = opts.customData || {}; - opts.customData.walletPrivKey = walletPrivKey.toString();; - var encCustomData = Utils.encryptMessage(JSON.stringify(opts.customData), - this.credentials.personalEncryptingKey); + if (!Array.isArray(data)) + return reporter.error('seqof/setof, but data is not Array'); - var args = { - walletId: walletId, - name: copayerName, - xPubKey: xPubKey, - requestPubKey: requestPubKey, - customData: encCustomData, - }; - if (opts.dryRun) args.dryRun = true; + var child = this.clone(); + child._baseState.implicit = null; + content = this._createEncoderBuffer(data.map(function(item) { + var state = this._baseState; - if (_.isBoolean(opts.supportBIP44AndP2PKH)) - args.supportBIP44AndP2PKH = opts.supportBIP44AndP2PKH; + return this._getUse(state.args[0], data)._encode(item, reporter); + }, child)); + } else if (state.use !== null) { + result = this._getUse(state.use, parent)._encode(data, reporter); + } else { + content = this._encodePrimitive(state.tag, data); + primitive = true; + } + } - var hash = Utils.getCopayerHash(args.name, args.xPubKey, args.requestPubKey); - args.copayerSignature = Utils.signMessage(hash, walletPrivKey); + // Encode data itself + var result; + if (!state.any && state.choice === null) { + var tag = state.implicit !== null ? state.implicit : state.tag; + var cls = state.implicit === null ? 'universal' : 'context'; - var url = '/v2/wallets/' + walletId + '/copayers'; - this._doPostRequest(url, args, function(err, body) { - if (err) return cb(err); - return cb(null, body.wallet); - }); -}; + if (tag === null) { + if (state.use === null) + reporter.error('Tag could be ommited only for .use()'); + } else { + if (state.use === null) + result = this._encodeComposite(tag, primitive, cls, content); + } + } -/** - * Return if wallet is complete - */ -API.prototype.isComplete = function() { - return this.credentials && this.credentials.isComplete(); -}; + // Wrap in explicit + if (state.explicit !== null) + result = this._encodeComposite(state.explicit, false, 'context', result); -/** - * Is private key currently encrypted? (ie, locked) - * - * @return {Boolean} - */ -API.prototype.isPrivKeyEncrypted = function() { - return this.credentials && this.credentials.isPrivKeyEncrypted(); + return result; }; -/** - * Is private key encryption setup? - * - * @return {Boolean} - */ -API.prototype.hasPrivKeyEncrypted = function() { - return this.credentials && this.credentials.hasPrivKeyEncrypted(); -}; +Node.prototype._encodeChoice = function encodeChoice(data, reporter) { + var state = this._baseState; -/** - * Is private key external? - * - * @return {Boolean} - */ -API.prototype.isPrivKeyExternal = function() { - return this.credentials && this.credentials.hasExternalSource(); + var node = state.choice[data.type]; + if (!node) { + assert( + false, + data.type + ' not found in ' + + JSON.stringify(Object.keys(state.choice))); + } + return node._encode(data.value, reporter); }; -/** - * Get external wallet source name - * - * @return {String} - */ -API.prototype.getPrivKeyExternalSourceName = function() { - return this.credentials ? this.credentials.getExternalSourceName() : null; +Node.prototype._encodePrimitive = function encodePrimitive(tag, data) { + var state = this._baseState; + + if (/str$/.test(tag)) + return this._encodeStr(data, tag); + else if (tag === 'objid' && state.args) + return this._encodeObjid(data, state.reverseArgs[0], state.args[1]); + else if (tag === 'objid') + return this._encodeObjid(data, null, null); + else if (tag === 'gentime' || tag === 'utctime') + return this._encodeTime(data, tag); + else if (tag === 'null_') + return this._encodeNull(); + else if (tag === 'int' || tag === 'enum') + return this._encodeInt(data, state.args && state.reverseArgs[0]); + else if (tag === 'bool') + return this._encodeBool(data); + else if (tag === 'objDesc') + return this._encodeStr(data, tag); + else + throw new Error('Unsupported tag: ' + tag); }; -/** - * unlocks the private key. `lock` need to be called explicity - * later to remove the unencrypted private key. - * - * @param password - */ -API.prototype.unlock = function(password) { - try { - this.credentials.unlock(password); - } catch (e) { - throw new Error('Could not unlock:' + e); - } +Node.prototype._isNumstr = function isNumstr(str) { + return /^[0-9 ]*$/.test(str); }; -/** - * Can this credentials sign a transaction? - * (Only returns fail on a 'proxy' setup for airgapped operation) - * - * @return {undefined} - */ -API.prototype.canSign = function() { - return this.credentials && this.credentials.canSign(); +Node.prototype._isPrintstr = function isPrintstr(str) { + return /^[A-Za-z0-9 '\(\)\+,\-\.\/:=\?]*$/.test(str); }; +},{"../base":6,"minimalistic-assert":242}],8:[function(require,module,exports){ +var inherits = require('inherits'); -API._extractPublicKeyRing = function(copayers) { - return _.map(copayers, function(copayer) { - var pkr = _.pick(copayer, ['xPubKey', 'requestPubKey']); - pkr.copayerName = copayer.name; - return pkr; - }); +function Reporter(options) { + this._reporterState = { + obj: null, + path: [], + options: options || {}, + errors: [] + }; +} +exports.Reporter = Reporter; + +Reporter.prototype.isError = function isError(obj) { + return obj instanceof ReporterError; }; -/** - * sets up encryption for the extended private key - * - * @param {String} password Password used to encrypt - * @param {Object} opts optional: SJCL options to encrypt (.iter, .salt, etc). - * @return {undefined} - */ -API.prototype.setPrivateKeyEncryption = function(password, opts) { - this.credentials.setPrivateKeyEncryption(password, opts || API.privateKeyEncryptionOpts); +Reporter.prototype.save = function save() { + var state = this._reporterState; + + return { obj: state.obj, pathLen: state.path.length }; }; -/** - * disables encryption for private key. - * wallet must be unlocked - * - */ -API.prototype.disablePrivateKeyEncryption = function(password, opts) { - return this.credentials.disablePrivateKeyEncryption(); +Reporter.prototype.restore = function restore(data) { + var state = this._reporterState; + + state.obj = data.obj; + state.path = state.path.slice(0, data.pathLen); }; -/** - * Locks private key (removes the unencrypted version and keep only the encrypted) - * - * @return {undefined} - */ -API.prototype.lock = function() { - this.credentials.lock(); +Reporter.prototype.enterKey = function enterKey(key) { + return this._reporterState.path.push(key); }; +Reporter.prototype.exitKey = function exitKey(index) { + var state = this._reporterState; -/** - * Get current fee levels for the specified network - * - * @param {string} network - 'livenet' (default) or 'testnet' - * @param {Callback} cb - * @returns {Callback} cb - Returns error or an object with status information - */ -API.prototype.getFeeLevels = function(network, cb) { - var self = this; + state.path = state.path.slice(0, index - 1); +}; - $.checkArgument(network || _.contains(['livenet', 'testnet'], network)); +Reporter.prototype.leaveKey = function leaveKey(index, key, value) { + var state = this._reporterState; - self._doGetRequest('/v1/feelevels/?network=' + (network || 'livenet'), function(err, result) { - if (err) return cb(err); - return cb(err, result); - }); + this.exitKey(index); + if (state.obj !== null) + state.obj[key] = value; }; -/** - * Get service version - * - * @param {Callback} cb - */ -API.prototype.getVersion = function(cb) { - this._doGetRequest('/v1/version/', cb); +Reporter.prototype.path = function path() { + return this._reporterState.path.join('/'); }; -/** - * - * Create a wallet. - * @param {String} walletName - * @param {String} copayerName - * @param {Number} m - * @param {Number} n - * @param {object} opts (optional: advanced options) - * @param {string} opts.network - 'livenet' or 'testnet' - * @param {String} opts.walletPrivKey - set a walletPrivKey (instead of random) - * @param {String} opts.id - set a id for wallet (instead of server given) - * @param {String} opts.withMnemonics - generate credentials - * @param cb - * @return {undefined} - */ -API.prototype.createWallet = function(walletName, copayerName, m, n, opts, cb) { - var self = this; - if (opts) $.shouldBeObject(opts); - opts = opts || {}; +Reporter.prototype.enterObject = function enterObject() { + var state = this._reporterState; - var network = opts.network || 'livenet'; - if (!_.contains(['testnet', 'livenet'], network)) return cb(new Error('Invalid network')); + var prev = state.obj; + state.obj = {}; + return prev; +}; - if (!self.credentials) { - log.info('Generating new keys'); - self.seedFromRandom({ - network: network - }); - } else { - log.info('Using existing keys'); - } +Reporter.prototype.leaveObject = function leaveObject(prev) { + var state = this._reporterState; - if (network != self.credentials.network) { - return cb(new Error('Existing keys were created for a different network')); + var now = state.obj; + state.obj = prev; + return now; +}; + +Reporter.prototype.error = function error(msg) { + var err; + var state = this._reporterState; + + var inherited = msg instanceof ReporterError; + if (inherited) { + err = msg; + } else { + err = new ReporterError(state.path.map(function(elem) { + return '[' + JSON.stringify(elem) + ']'; + }).join(''), msg.message || msg, msg.stack); } - var walletPrivKey = opts.walletPrivKey || new Bitcore.PrivateKey(); - var args = { - name: walletName, - m: m, - n: n, - pubKey: (new Bitcore.PrivateKey(walletPrivKey)).toPublicKey().toString(), - network: network, - id: opts.id, - }; - self._doPostRequest('/v2/wallets/', args, function(err, body) { - if (err) return cb(err); + if (!state.options.partial) + throw err; - var walletId = body.walletId; - self.credentials.addWalletInfo(walletId, walletName, m, n, walletPrivKey.toString(), copayerName); - var c = self.credentials; - var secret = API._buildSecret(c.walletId, c.walletPrivKey, c.network); + if (!inherited) + state.errors.push(err); - self._doJoinWallet(walletId, walletPrivKey, self.credentials.xPubKey, self.credentials.requestPubKey, copayerName, {}, - function(err, wallet) { - if (err) return cb(err); - return cb(null, n > 1 ? secret : null); - }); - }); + return err; }; -/** - * Join an existent wallet - * - * @param {String} secret - * @param {String} copayerName - * @param {Object} opts - * @param {Boolean} opts.dryRun[=false] - Simulate wallet join - * @param {Callback} cb - * @returns {Callback} cb - Returns the wallet - */ -API.prototype.joinWallet = function(secret, copayerName, opts, cb) { - var self = this; +Reporter.prototype.wrapResult = function wrapResult(result) { + var state = this._reporterState; + if (!state.options.partial) + return result; - if (!cb) { - cb = opts; - opts = {}; - log.warn('DEPRECATED WARN: joinWallet should receive 4 parameters.') - } + return { + result: this.isError(result) ? null : result, + errors: state.errors + }; +}; - opts = opts || {}; +function ReporterError(path, msg) { + this.path = path; + this.rethrow(msg); +}; +inherits(ReporterError, Error); - try { - var secretData = API.parseSecret(secret); - } catch (ex) { - return cb(ex); - } +ReporterError.prototype.rethrow = function rethrow(msg) { + this.message = msg + ' at: ' + (this.path || '(shallow)'); + if (Error.captureStackTrace) + Error.captureStackTrace(this, ReporterError); - if (!self.credentials) { - self.seedFromRandom({ - network: secretData.network - }); + if (!this.stack) { + try { + // IE only adds stack when thrown + throw new Error(this.message); + } catch (e) { + this.stack = e.stack; + } } + return this; +}; - self._doJoinWallet(secretData.walletId, secretData.walletPrivKey, self.credentials.xPubKey, self.credentials.requestPubKey, copayerName, { - dryRun: !!opts.dryRun, - }, function(err, wallet) { - if (err) return cb(err); - if (!opts.dryRun) { - self.credentials.addWalletInfo(wallet.id, wallet.name, wallet.m, wallet.n, secretData.walletPrivKey.toString(), copayerName); - } - return cb(null, wallet); - }); -}; - -/** - * Recreates a wallet, given credentials (with wallet id) - * - * @returns {Callback} cb - Returns the wallet - */ -API.prototype.recreateWallet = function(cb) { - $.checkState(this.credentials); - $.checkState(this.credentials.isComplete()); - $.checkState(this.credentials.walletPrivKey); - //$.checkState(this.credentials.hasWalletInfo()); - var self = this; +},{"inherits":233}],9:[function(require,module,exports){ +var constants = require('../constants'); - // First: Try to get the wallet with current credentials - this.getStatus({ - includeExtendedInfo: true - }, function(err) { - // No error? -> Wallet is ready. - if (!err) { - log.info('Wallet is already created'); - return cb(); - }; - var walletPrivKey = Bitcore.PrivateKey.fromString(self.credentials.walletPrivKey); - var walletId = self.credentials.walletId; - var supportBIP44AndP2PKH = self.credentials.derivationStrategy != Constants.DERIVATION_STRATEGIES.BIP45; +exports.tagClass = { + 0: 'universal', + 1: 'application', + 2: 'context', + 3: 'private' +}; +exports.tagClassByName = constants._reverse(exports.tagClass); - var args = { - name: self.credentials.walletName || 'recovered wallet', - m: self.credentials.m, - n: self.credentials.n, - pubKey: walletPrivKey.toPublicKey().toString(), - network: self.credentials.network, - id: walletId, - supportBIP44AndP2PKH: supportBIP44AndP2PKH, - }; +exports.tag = { + 0x00: 'end', + 0x01: 'bool', + 0x02: 'int', + 0x03: 'bitstr', + 0x04: 'octstr', + 0x05: 'null_', + 0x06: 'objid', + 0x07: 'objDesc', + 0x08: 'external', + 0x09: 'real', + 0x0a: 'enum', + 0x0b: 'embed', + 0x0c: 'utf8str', + 0x0d: 'relativeOid', + 0x10: 'seq', + 0x11: 'set', + 0x12: 'numstr', + 0x13: 'printstr', + 0x14: 't61str', + 0x15: 'videostr', + 0x16: 'ia5str', + 0x17: 'utctime', + 0x18: 'gentime', + 0x19: 'graphstr', + 0x1a: 'iso646str', + 0x1b: 'genstr', + 0x1c: 'unistr', + 0x1d: 'charstr', + 0x1e: 'bmpstr' +}; +exports.tagByName = constants._reverse(exports.tag); - self._doPostRequest('/v2/wallets/', args, function(err, body) { - if (err) { - if (err.code != 'WALLET_ALREADY_EXISTS') - return cb(err); +},{"../constants":10}],10:[function(require,module,exports){ +var constants = exports; - return self.addAccess({}, function(err) { - if (err) return cb(err); - self.openWallet(function(err) { - return cb(err); - }); - }); - } +// Helper +constants._reverse = function reverse(map) { + var res = {}; - if (!walletId) { - walletId = body.walletId; - } + Object.keys(map).forEach(function(key) { + // Convert key to integer if it is stringified + if ((key | 0) == key) + key = key | 0; - var i = 1; - async.each(self.credentials.publicKeyRing, function(item, next) { - var name = item.copayerName || ('copayer ' + i++); - self._doJoinWallet(walletId, walletPrivKey, item.xPubKey, item.requestPubKey, name, { - supportBIP44AndP2PKH: supportBIP44AndP2PKH, - }, function(err) { - //Ignore error is copayer already in wallet - if (err && err.code == 'COPAYER_IN_WALLET') return next(); - return next(err); - }); - }, cb); - }); + var value = map[key]; + res[value] = key; }); -}; - -API.prototype._processCustomData = function(result) { - var copayers = result.wallet.copayers; - if (!copayers) return; + return res; +}; - var me = _.find(copayers, { - 'id': this.credentials.copayerId - }); - if (!me || !me.customData) return; +constants.der = require('./der'); - var customData; - try { - customData = JSON.parse(Utils.decryptMessage(me.customData, this.credentials.personalEncryptingKey)); - } catch (e) { - log.warn('Could not decrypt customData:', me.customData); - } - if (!customData) return; +},{"./der":9}],11:[function(require,module,exports){ +var inherits = require('inherits'); - // Add it to result - result.customData = customData; +var asn1 = require('../../asn1'); +var base = asn1.base; +var bignum = asn1.bignum; - // Update walletPrivateKey - if (!this.credentials.walletPrivKey && customData.walletPrivKey) - this.credentials.addWalletPrivateKey(customData.walletPrivKey) -} +// Import DER constants +var der = asn1.constants.der; -/** - * Get latest notifications - * - * @param {object} opts - * @param {String} lastNotificationId (optional) - The ID of the last received notification - * @param {String} timeSpan (optional) - A time window on which to look for notifications (in seconds) - * @returns {Callback} cb - Returns error or an array of notifications - */ -API.prototype.getNotifications = function(opts, cb) { - $.checkState(this.credentials); +function DERDecoder(entity) { + this.enc = 'der'; + this.name = entity.name; + this.entity = entity; - var self = this; - opts = opts || {}; + // Construct base tree + this.tree = new DERNode(); + this.tree._init(entity.body); +}; +module.exports = DERDecoder; - var url = '/v1/notifications/'; - if (opts.lastNotificationId) { - url += '?notificationId=' + opts.lastNotificationId; - } else if (opts.timeSpan) { - url += '?timeSpan=' + opts.timeSpan; - } +DERDecoder.prototype.decode = function decode(data, options) { + if (!(data instanceof base.DecoderBuffer)) + data = new base.DecoderBuffer(data, options); - self._doGetRequest(url, function(err, result) { - if (err) return cb(err); - var notifications = _.filter(result, function(notification) { - return (notification.creatorId != self.credentials.copayerId); - }); - return cb(null, notifications); - }); + return this.tree._decode(data, options); }; -/** - * Get status of the wallet - * - * @param {object} opts.includeExtendedInfo (optional: query extended status) - * @returns {Callback} cb - Returns error or an object with status information - */ -API.prototype.getStatus = function(opts, cb) { - $.checkState(this.credentials); +// Tree methods - if (!cb) { - cb = opts; - opts = {}; - log.warn('DEPRECATED WARN: getStatus should receive 2 parameters.') - } +function DERNode(parent) { + base.Node.call(this, 'der', parent); +} +inherits(DERNode, base.Node); - var self = this; - opts = opts || {}; +DERNode.prototype._peekTag = function peekTag(buffer, tag, any) { + if (buffer.isEmpty()) + return false; - self._doGetRequest('/v2/wallets/?includeExtendedInfo=' + (opts.includeExtendedInfo ? '1' : '0'), function(err, result) { - if (err) return cb(err); - if (result.wallet.status == 'pending') { - var c = self.credentials; - result.wallet.secret = API._buildSecret(c.walletId, c.walletPrivKey, c.network); - } - self._processTxps(result.pendingTxps); - self._processCustomData(result); - return cb(err, result); - }); -}; + var state = buffer.save(); + var decodedTag = derDecodeTag(buffer, 'Failed to peek tag: "' + tag + '"'); + if (buffer.isError(decodedTag)) + return decodedTag; -/** - * Get copayer preferences - * - * @param {Callback} cb - * @return {Callback} cb - Return error or object - */ -API.prototype.getPreferences = function(cb) { - $.checkState(this.credentials && this.credentials.isComplete()); - $.checkArgument(cb); + buffer.restore(state); - var self = this; - self._doGetRequest('/v1/preferences/', function(err, preferences) { - if (err) return cb(err); - return cb(null, preferences); - }); + return decodedTag.tag === tag || decodedTag.tagStr === tag || + (decodedTag.tagStr + 'of') === tag || any; }; -/** - * Save copayer preferences - * - * @param {Object} preferences - * @param {Callback} cb - * @return {Callback} cb - Return error or object - */ -API.prototype.savePreferences = function(preferences, cb) { - $.checkState(this.credentials && this.credentials.isComplete()); - $.checkArgument(cb); +DERNode.prototype._decodeTag = function decodeTag(buffer, tag, any) { + var decodedTag = derDecodeTag(buffer, + 'Failed to decode tag of "' + tag + '"'); + if (buffer.isError(decodedTag)) + return decodedTag; - var self = this; - self._doPutRequest('/v1/preferences/', preferences, cb); -}; + var len = derDecodeLen(buffer, + decodedTag.primitive, + 'Failed to get length of "' + tag + '"'); + // Failure + if (buffer.isError(len)) + return len; -API.prototype._computeProposalSignature = function(args) { - var hash; - if (args.outputs) { - $.shouldBeArray(args.outputs); - // should match bws server createTx - var proposalHeader = { - outputs: _.map(args.outputs, function(output) { - $.shouldBeNumber(output.amount); - return _.pick(output, ['toAddress', 'amount', 'message']); - }), - message: args.message || null, - payProUrl: args.payProUrl || null, - }; - hash = Utils.getProposalHash(proposalHeader); - } else { - $.shouldBeNumber(args.amount); - hash = Utils.getProposalHash(args.toAddress, args.amount, args.message || null, args.payProUrl || null); + if (!any && + decodedTag.tag !== tag && + decodedTag.tagStr !== tag && + decodedTag.tagStr + 'of' !== tag) { + return buffer.error('Failed to match tag: "' + tag + '"'); } - return Utils.signMessage(hash, this.credentials.requestPrivKey); -} -/** - * fetchPayPro - * - * @param opts.payProUrl URL for paypro request - * @returns {Callback} cb - Return error or the parsed payment protocol request - * Returns (err,paypro) - * paypro.amount - * paypro.toAddress - * paypro.memo - */ -API.prototype.fetchPayPro = function(opts, cb) { - $.checkArgument(opts) - .checkArgument(opts.payProUrl); + if (decodedTag.primitive || len !== null) + return buffer.skip(len, 'Failed to match body of: "' + tag + '"'); - PayPro.get({ - url: opts.payProUrl, - http: this.payProHttp, - }, function(err, paypro) { - if (err) - return cb(err || 'Could not fetch PayPro request'); + // Indefinite length... find END tag + var state = buffer.save(); + var res = this._skipUntilEnd( + buffer, + 'Failed to skip indefinite length body: "' + this.tag + '"'); + if (buffer.isError(res)) + return res; - return cb(null, paypro); - }); + len = buffer.offset - state.offset; + buffer.restore(state); + return buffer.skip(len, 'Failed to match body of: "' + tag + '"'); }; -/** - * Gets list of utxos - * - * @param {Function} cb - * @param {Object} opts - * @param {Array} opts.addresses (optional) - List of addresses from where to fetch UTXOs. - * @returns {Callback} cb - Return error or the list of utxos - */ -API.prototype.getUtxos = function(opts, cb) { - $.checkState(this.credentials && this.credentials.isComplete()); - opts = opts || {}; - var url = '/v1/utxos/'; - if (opts.addresses) { - url += '?' + querystring.stringify({ - addresses: [].concat(opts.addresses).join(',') - }); - } - this._doGetRequest(url, cb); -}; +DERNode.prototype._skipUntilEnd = function skipUntilEnd(buffer, fail) { + while (true) { + var tag = derDecodeTag(buffer, fail); + if (buffer.isError(tag)) + return tag; + var len = derDecodeLen(buffer, tag.primitive, fail); + if (buffer.isError(len)) + return len; -/** - * Send a transaction proposal - * - * @param {Object} opts - * @param {String} opts.toAddress | opts.outputs[].toAddress - * @param {Number} opts.amount | opts.outputs[].amount - * @param {String} opts.message | opts.outputs[].message - * @param {string} opts.feePerKb - Optional: Use an alternative fee per KB for this TX - * @param {String} opts.payProUrl - Optional: Tx is from a payment protocol URL - * @param {string} opts.excludeUnconfirmedUtxos - Optional: Do not use UTXOs of unconfirmed transactions as inputs - * @returns {Callback} cb - Return error or the transaction proposal - */ -API.prototype.sendTxProposal = function(opts, cb) { - $.checkState(this.credentials && this.credentials.isComplete()); - $.checkArgument(!opts.message || this.credentials.sharedEncryptingKey, 'Cannot create transaction with message without shared Encrypting key'); - $.checkArgument(opts); + var res; + if (tag.primitive || len !== null) + res = buffer.skip(len) + else + res = this._skipUntilEnd(buffer, fail); - var self = this; + // Failure + if (buffer.isError(res)) + return res; - var args = { - toAddress: opts.toAddress, - amount: opts.amount, - message: API._encryptMessage(opts.message, this.credentials.sharedEncryptingKey) || null, - feePerKb: opts.feePerKb, - payProUrl: opts.payProUrl || null, - excludeUnconfirmedUtxos: !!opts.excludeUnconfirmedUtxos, - type: opts.type, - outputs: _.cloneDeep(opts.outputs), - customData: opts.customData - }; - if (args.outputs) { - _.each(args.outputs, function(o) { - o.message = API._encryptMessage(o.message, self.credentials.sharedEncryptingKey) || null; - }); + if (tag.tagStr === 'end') + break; } - log.debug('Generating & signing tx proposal:', JSON.stringify(args)); - args.proposalSignature = this._computeProposalSignature(args); - - this._doPostRequest('/v1/txproposals/', args, function(err, txp) { - if (err) return cb(err); - return cb(null, txp); - }); }; -/** - * Create a new address - * - * @param {Callback} cb - * @returns {Callback} cb - Return error or the address - */ -API.prototype.createAddress = function(cb) { - $.checkState(this.credentials && this.credentials.isComplete()); +DERNode.prototype._decodeList = function decodeList(buffer, tag, decoder, + options) { + var result = []; + while (!buffer.isEmpty()) { + var possibleEnd = this._peekTag(buffer, 'end'); + if (buffer.isError(possibleEnd)) + return possibleEnd; - var self = this; + var res = decoder.decode(buffer, 'der', options); + if (buffer.isError(res) && possibleEnd) + break; + result.push(res); + } + return result; +}; - self._doPostRequest('/v2/addresses/', {}, function(err, address) { - if (err) return cb(err); +DERNode.prototype._decodeStr = function decodeStr(buffer, tag) { + if (tag === 'bitstr') { + var unused = buffer.readUInt8(); + if (buffer.isError(unused)) + return unused; + return { unused: unused, data: buffer.raw() }; + } else if (tag === 'bmpstr') { + var raw = buffer.raw(); + if (raw.length % 2 === 1) + return buffer.error('Decoding of string type: bmpstr length mismatch'); - if (!Verifier.checkAddress(self.credentials, address)) { - return cb(Errors.SERVER_COMPROMISED); + var str = ''; + for (var i = 0; i < raw.length / 2; i++) { + str += String.fromCharCode(raw.readUInt16BE(i * 2)); } - - return cb(null, address); - }); + return str; + } else if (tag === 'numstr') { + var numstr = buffer.raw().toString('ascii'); + if (!this._isNumstr(numstr)) { + return buffer.error('Decoding of string type: ' + + 'numstr unsupported characters'); + } + return numstr; + } else if (tag === 'octstr') { + return buffer.raw(); + } else if (tag === 'objDesc') { + return buffer.raw(); + } else if (tag === 'printstr') { + var printstr = buffer.raw().toString('ascii'); + if (!this._isPrintstr(printstr)) { + return buffer.error('Decoding of string type: ' + + 'printstr unsupported characters'); + } + return printstr; + } else if (/str$/.test(tag)) { + return buffer.raw().toString(); + } else { + return buffer.error('Decoding of string type: ' + tag + ' unsupported'); + } }; -/** - * Get your main addresses - * - * @param {Object} opts - * @param {Boolean} opts.doNotVerify - * @param {Numeric} opts.limit (optional) - Limit the resultset. Return all addresses by default. - * @param {Boolean} [opts.reverse=false] (optional) - Reverse the order of returned addresses. - * @param {Callback} cb - * @returns {Callback} cb - Return error or the array of addresses - */ -API.prototype.getMainAddresses = function(opts, cb) { - $.checkState(this.credentials && this.credentials.isComplete()); +DERNode.prototype._decodeObjid = function decodeObjid(buffer, values, relative) { + var result; + var identifiers = []; + var ident = 0; + while (!buffer.isEmpty()) { + var subident = buffer.readUInt8(); + ident <<= 7; + ident |= subident & 0x7f; + if ((subident & 0x80) === 0) { + identifiers.push(ident); + ident = 0; + } + } + if (subident & 0x80) + identifiers.push(ident); - var self = this; + var first = (identifiers[0] / 40) | 0; + var second = identifiers[0] % 40; - opts = opts || {}; + if (relative) + result = identifiers; + else + result = [first, second].concat(identifiers.slice(1)); - var args = []; - if (opts.limit) args.push('limit=' + opts.limit); - if (opts.reverse) args.push('reverse=1'); - var qs = ''; - if (args.length > 0) { - qs = '?' + args.join('&'); + if (values) { + var tmp = values[result.join(' ')]; + if (tmp === undefined) + tmp = values[result.join('.')]; + if (tmp !== undefined) + result = tmp; } - var url = '/v1/addresses/' + qs; - self._doGetRequest(url, function(err, addresses) { - if (err) return cb(err); - - if (!opts.doNotVerify) { - var fake = _.any(addresses, function(address) { - return !Verifier.checkAddress(self.credentials, address); - }); - if (fake) - return cb(Errors.SERVER_COMPROMISED); - } - return cb(null, addresses); - }); + return result; }; -/** - * Update wallet balance - * - * @param {Callback} cb - */ -API.prototype.getBalance = function(cb) { - $.checkState(this.credentials && this.credentials.isComplete()); - this._doGetRequest('/v1/balance/', cb); -}; +DERNode.prototype._decodeTime = function decodeTime(buffer, tag) { + var str = buffer.raw().toString(); + if (tag === 'gentime') { + var year = str.slice(0, 4) | 0; + var mon = str.slice(4, 6) | 0; + var day = str.slice(6, 8) | 0; + var hour = str.slice(8, 10) | 0; + var min = str.slice(10, 12) | 0; + var sec = str.slice(12, 14) | 0; + } else if (tag === 'utctime') { + var year = str.slice(0, 2) | 0; + var mon = str.slice(2, 4) | 0; + var day = str.slice(4, 6) | 0; + var hour = str.slice(6, 8) | 0; + var min = str.slice(8, 10) | 0; + var sec = str.slice(10, 12) | 0; + if (year < 70) + year = 2000 + year; + else + year = 1900 + year; + } else { + return buffer.error('Decoding ' + tag + ' time is not supported yet'); + } -/** - * Get list of transactions proposals - * - * @param {Object} opts - * @param {Boolean} opts.doNotVerify - * @param {Boolean} opts.forAirGapped - * @return {Callback} cb - Return error or array of transactions proposals - */ -API.prototype.getTxProposals = function(opts, cb) { - $.checkState(this.credentials && this.credentials.isComplete()); + return Date.UTC(year, mon - 1, day, hour, min, sec, 0); +}; - var self = this; +DERNode.prototype._decodeNull = function decodeNull(buffer) { + return null; +}; - self._doGetRequest('/v1/txproposals/', function(err, txps) { - if (err) return cb(err); +DERNode.prototype._decodeBool = function decodeBool(buffer) { + var res = buffer.readUInt8(); + if (buffer.isError(res)) + return res; + else + return res !== 0; +}; - self._processTxps(txps); - async.every(txps, - function(txp, acb) { - if (opts.doNotVerify) return acb(true); - self.getPayPro(txp, function(err, paypro) { +DERNode.prototype._decodeInt = function decodeInt(buffer, values) { + // Bigint, return as it is (assume big endian) + var raw = buffer.raw(); + var res = new bignum(raw); - var isLegit = Verifier.checkTxProposal(self.credentials, txp, { - paypro: paypro, - }); + if (values) + res = values[res.toString(10)] || res; - return acb(isLegit); - }); - }, - function(isLegit) { - if (!isLegit) - return cb(Errors.SERVER_COMPROMISED); + return res; +}; - var result; - if (opts.forAirGapped) { - result = { - txps: JSON.parse(JSON.stringify(txps)), - encryptedPkr: Utils.encryptMessage(JSON.stringify(self.credentials.publicKeyRing), self.credentials.personalEncryptingKey), - m: self.credentials.m, - n: self.credentials.n, - }; - } else { - result = txps; - } - return cb(null, result); - }); - }); +DERNode.prototype._use = function use(entity, obj) { + if (typeof entity === 'function') + entity = entity(obj); + return entity._getDecoder('der').tree; }; -API.prototype.getPayPro = function(txp, cb) { - var self = this; - if (!txp.payProUrl || this.doNotVerifyPayPro) - return cb(); +// Utility methods - PayPro.get({ - url: txp.payProUrl, - http: self.payProHttp, - }, function(err, paypro) { - if (err) return cb(new Error('Cannot check transaction now:' + err)); - return cb(null, paypro); - }); -}; - - -/** - * Sign a transaction proposal - * - * @param {Object} txp - * @param {Callback} cb - * @return {Callback} cb - Return error or object - */ -API.prototype.signTxProposal = function(txp, cb) { - $.checkState(this.credentials && this.credentials.isComplete()); - $.checkArgument(txp.creatorId); +function derDecodeTag(buf, fail) { + var tag = buf.readUInt8(fail); + if (buf.isError(tag)) + return tag; - var self = this; + var cls = der.tagClass[tag >> 6]; + var primitive = (tag & 0x20) === 0; - if (!self.canSign() && !txp.signatures) - return cb(new Error('You do not have the required keys to sign transactions')); + // Multi-octet tag - load + if ((tag & 0x1f) === 0x1f) { + var oct = tag; + tag = 0; + while ((oct & 0x80) === 0x80) { + oct = buf.readUInt8(fail); + if (buf.isError(oct)) + return oct; - if (self.isPrivKeyEncrypted()) - return cb(new Error('Private Key is encrypted, cannot sign')); + tag <<= 7; + tag |= oct & 0x7f; + } + } else { + tag &= 0x1f; + } + var tagStr = der.tag[tag]; - self.getPayPro(txp, function(err, paypro) { - if (err) return cb(err); + return { + cls: cls, + primitive: primitive, + tag: tag, + tagStr: tagStr + }; +} - var isLegit = Verifier.checkTxProposal(self.credentials, txp, { - paypro: paypro, - }); +function derDecodeLen(buf, primitive, fail) { + var len = buf.readUInt8(fail); + if (buf.isError(len)) + return len; - if (!isLegit) - return cb(Errors.SERVER_COMPROMISED); + // Indefinite form + if (!primitive && len === 0x80) + return null; - var signatures = txp.signatures || self._signTxp(txp); + // Definite form + if ((len & 0x80) === 0) { + // Short form + return len; + } - var url = '/v1/txproposals/' + txp.id + '/signatures/'; - var args = { - signatures: signatures - }; + // Long form + var num = len & 0x7f; + if (num > 4) + return buf.error('length octect is too long'); - self._doPostRequest(url, args, function(err, txp) { - if (err) return cb(err); - self._processTxps([txp]); - return cb(null, txp); - }); - }) -}; + len = 0; + for (var i = 0; i < num; i++) { + len <<= 8; + var j = buf.readUInt8(fail); + if (buf.isError(j)) + return j; + len |= j; + } -/** - * Sign transaction proposal from AirGapped - * - * @param {Object} txp - * @param {String} encryptedPkr - * @param {Number} m - * @param {Number} n - * @return {Object} txp - Return transaction - */ -API.prototype.signTxProposalFromAirGapped = function(txp, encryptedPkr, m, n) { - $.checkState(this.credentials); + return len; +} - var self = this; +},{"../../asn1":3,"inherits":233}],12:[function(require,module,exports){ +var decoders = exports; - if (!self.canSign()) - throw Errors.MISSING_PRIVATE_KEY; +decoders.der = require('./der'); +decoders.pem = require('./pem'); - if (self.isPrivKeyEncrypted()) - throw Errors.ENCRYPTED_PRIVATE_KEY; +},{"./der":11,"./pem":13}],13:[function(require,module,exports){ +var inherits = require('inherits'); +var Buffer = require('buffer').Buffer; - var publicKeyRing; - try { - publicKeyRing = JSON.parse(Utils.decryptMessage(encryptedPkr, self.credentials.personalEncryptingKey)); - } catch (ex) { - throw new Error('Could not decrypt public key ring'); - } +var DERDecoder = require('./der'); - if (!_.isArray(publicKeyRing) || publicKeyRing.length != n) { - throw new Error('Invalid public key ring'); - } +function PEMDecoder(entity) { + DERDecoder.call(this, entity); + this.enc = 'pem'; +}; +inherits(PEMDecoder, DERDecoder); +module.exports = PEMDecoder; - self.credentials.m = m; - self.credentials.n = n; - self.credentials.addressType = txp.addressType; - self.credentials.addPublicKeyRing(publicKeyRing); +PEMDecoder.prototype.decode = function decode(data, options) { + var lines = data.toString().split(/[\r\n]+/g); - if (!Verifier.checkTxProposalBody(self.credentials, txp)) - throw new Error('Fake transaction proposal'); + var label = options.label.toUpperCase(); - return self._signTxp(txp); -}; + var re = /^-----(BEGIN|END) ([^-]+)-----$/; + var start = -1; + var end = -1; + for (var i = 0; i < lines.length; i++) { + var match = lines[i].match(re); + if (match === null) + continue; + if (match[2] !== label) + continue; -/** - * Reject a transaction proposal - * - * @param {Object} txp - * @param {String} reason - * @param {Callback} cb - * @return {Callback} cb - Return error or object - */ -API.prototype.rejectTxProposal = function(txp, reason, cb) { - $.checkState(this.credentials && this.credentials.isComplete()); - $.checkArgument(cb); + if (start === -1) { + if (match[1] !== 'BEGIN') + break; + start = i; + } else { + if (match[1] !== 'END') + break; + end = i; + break; + } + } + if (start === -1 || end === -1) + throw new Error('PEM section not found for: ' + label); - var self = this; + var base64 = lines.slice(start + 1, end).join(''); + // Remove excessive symbols + base64.replace(/[^a-z0-9\+\/=]+/gi, ''); - var url = '/v1/txproposals/' + txp.id + '/rejections/'; - var args = { - reason: API._encryptMessage(reason, self.credentials.sharedEncryptingKey) || '', - }; - self._doPostRequest(url, args, function(err, txp) { - if (err) return cb(err); - self._processTxps([txp]); - return cb(null, txp); - }); + var input = new Buffer(base64, 'base64'); + return DERDecoder.prototype.decode.call(this, input, options); }; -/** - * Broadcast raw transaction - * - * @param {Object} opts - * @param {String} opts.network - * @param {String} opts.rawTx - * @param {Callback} cb - * @return {Callback} cb - Return error or txid - */ -API.prototype.broadcastRawTx = function(opts, cb) { - $.checkState(this.credentials); - $.checkArgument(cb); +},{"./der":11,"buffer":174,"inherits":233}],14:[function(require,module,exports){ +var inherits = require('inherits'); +var Buffer = require('buffer').Buffer; - var self = this; +var asn1 = require('../../asn1'); +var base = asn1.base; - opts = opts || {}; +// Import DER constants +var der = asn1.constants.der; - var url = '/v1/broadcast_raw/'; - self._doPostRequest(url, opts, function(err, txid) { - if (err) return cb(err); - return cb(null, txid); - }); +function DEREncoder(entity) { + this.enc = 'der'; + this.name = entity.name; + this.entity = entity; + + // Construct base tree + this.tree = new DERNode(); + this.tree._init(entity.body); }; +module.exports = DEREncoder; -API.prototype._doBroadcast = function(txp, cb) { - var self = this; - var url = '/v1/txproposals/' + txp.id + '/broadcast/'; - self._doPostRequest(url, {}, function(err, txp) { - if (err) return cb(err); - return cb(null, txp); - }); +DEREncoder.prototype.encode = function encode(data, reporter) { + return this.tree._encode(data, reporter).join(); }; +// Tree methods -/** - * Broadcast a transaction proposal - * - * @param {Object} txp - * @param {Callback} cb - * @return {Callback} cb - Return error or object - */ -API.prototype.broadcastTxProposal = function(txp, cb) { - $.checkState(this.credentials && this.credentials.isComplete()); +function DERNode(parent) { + base.Node.call(this, 'der', parent); +} +inherits(DERNode, base.Node); - var self = this; +DERNode.prototype._encodeComposite = function encodeComposite(tag, + primitive, + cls, + content) { + var encodedTag = encodeTag(tag, primitive, cls, this.reporter); - self.getPayPro(txp, function(err, paypro) { + // Short form + if (content.length < 0x80) { + var header = new Buffer(2); + header[0] = encodedTag; + header[1] = content.length; + return this._createEncoderBuffer([ header, content ]); + } - if (paypro) { + // Long form + // Count octets required to store length + var lenOctets = 1; + for (var i = content.length; i >= 0x100; i >>= 8) + lenOctets++; - var t = API.buildTx(txp); - self.createAddress(function(err, addr) { - if (err) return cb(err); + var header = new Buffer(1 + 1 + lenOctets); + header[0] = encodedTag; + header[1] = 0x80 | lenOctets; - PayPro.send({ - http: self.payProHttp, - url: txp.payProUrl, - amountSat: txp.amount, - refundAddr: addr.address, - merchant_data: paypro.merchant_data, - rawTx: t.uncheckedSerialize(), - }, function(err, ack, memo) { - if (err) return cb(err); - self._doBroadcast(txp, function(err, txp) { - return cb(err, txp, memo); - }); - }); - }); - } else { - self._doBroadcast(txp, cb); - } - }); + for (var i = 1 + lenOctets, j = content.length; j > 0; i--, j >>= 8) + header[i] = j & 0xff; + + return this._createEncoderBuffer([ header, content ]); }; -/** - * Remove a transaction proposal - * - * @param {Object} txp - * @param {Callback} cb - * @return {Callback} cb - Return error or empty - */ -API.prototype.removeTxProposal = function(txp, cb) { - $.checkState(this.credentials && this.credentials.isComplete()); +DERNode.prototype._encodeStr = function encodeStr(str, tag) { + if (tag === 'bitstr') { + return this._createEncoderBuffer([ str.unused | 0, str.data ]); + } else if (tag === 'bmpstr') { + var buf = new Buffer(str.length * 2); + for (var i = 0; i < str.length; i++) { + buf.writeUInt16BE(str.charCodeAt(i), i * 2); + } + return this._createEncoderBuffer(buf); + } else if (tag === 'numstr') { + if (!this._isNumstr(str)) { + return this.reporter.error('Encoding of string type: numstr supports ' + + 'only digits and space'); + } + return this._createEncoderBuffer(str); + } else if (tag === 'printstr') { + if (!this._isPrintstr(str)) { + return this.reporter.error('Encoding of string type: printstr supports ' + + 'only latin upper and lower case letters, ' + + 'digits, space, apostrophe, left and rigth ' + + 'parenthesis, plus sign, comma, hyphen, ' + + 'dot, slash, colon, equal sign, ' + + 'question mark'); + } + return this._createEncoderBuffer(str); + } else if (/str$/.test(tag)) { + return this._createEncoderBuffer(str); + } else if (tag === 'objDesc') { + return this._createEncoderBuffer(str); + } else { + return this.reporter.error('Encoding of string type: ' + tag + + ' unsupported'); + } +}; - var self = this; +DERNode.prototype._encodeObjid = function encodeObjid(id, values, relative) { + if (typeof id === 'string') { + if (!values) + return this.reporter.error('string objid given, but no values map found'); + if (!values.hasOwnProperty(id)) + return this.reporter.error('objid not found in values map'); + id = values[id].split(/[\s\.]+/g); + for (var i = 0; i < id.length; i++) + id[i] |= 0; + } else if (Array.isArray(id)) { + id = id.slice(); + for (var i = 0; i < id.length; i++) + id[i] |= 0; + } - var url = '/v1/txproposals/' + txp.id; - self._doDeleteRequest(url, function(err) { - return cb(err); - }); -}; + if (!Array.isArray(id)) { + return this.reporter.error('objid() should be either array or string, ' + + 'got: ' + JSON.stringify(id)); + } -/** - * Get transaction history - * - * @param {Object} opts - * @param {Number} opts.skip (defaults to 0) - * @param {Number} opts.limit - * @param {Callback} cb - * @return {Callback} cb - Return error or array of transactions - */ -API.prototype.getTxHistory = function(opts, cb) { - $.checkState(this.credentials && this.credentials.isComplete()); + if (!relative) { + if (id[1] >= 40) + return this.reporter.error('Second objid identifier OOB'); + id.splice(0, 2, id[0] * 40 + id[1]); + } - var self = this; - var args = []; - if (opts) { - if (opts.skip) args.push('skip=' + opts.skip); - if (opts.limit) args.push('limit=' + opts.limit); + // Count number of octets + var size = 0; + for (var i = 0; i < id.length; i++) { + var ident = id[i]; + for (size++; ident >= 0x80; ident >>= 7) + size++; } - var qs = ''; - if (args.length > 0) { - qs = '?' + args.join('&'); + + var objid = new Buffer(size); + var offset = objid.length - 1; + for (var i = id.length - 1; i >= 0; i--) { + var ident = id[i]; + objid[offset--] = ident & 0x7f; + while ((ident >>= 7) > 0) + objid[offset--] = 0x80 | (ident & 0x7f); } - var url = '/v1/txhistory/' + qs; - self._doGetRequest(url, function(err, txs) { - if (err) return cb(err); - self._processTxps(txs); - return cb(null, txs); - }); + return this._createEncoderBuffer(objid); }; -/** - * getTx - * - * @param {String} TransactionId - * @return {Callback} cb - Return error or transaction - */ -API.prototype.getTx = function(id, cb) { - $.checkState(this.credentials && this.credentials.isComplete()); +function two(num) { + if (num < 10) + return '0' + num; + else + return num; +} - var self = this; - var url = '/v1/txproposals/' + id; - this._doGetRequest(url, function(err, tx) { - if (err) return cb(err); +DERNode.prototype._encodeTime = function encodeTime(time, tag) { + var str; + var date = new Date(time); - self._processTxps([tx]); - return cb(null, tx); - }); + if (tag === 'gentime') { + str = [ + two(date.getFullYear()), + two(date.getUTCMonth() + 1), + two(date.getUTCDate()), + two(date.getUTCHours()), + two(date.getUTCMinutes()), + two(date.getUTCSeconds()), + 'Z' + ].join(''); + } else if (tag === 'utctime') { + str = [ + two(date.getFullYear() % 100), + two(date.getUTCMonth() + 1), + two(date.getUTCDate()), + two(date.getUTCHours()), + two(date.getUTCMinutes()), + two(date.getUTCSeconds()), + 'Z' + ].join(''); + } else { + this.reporter.error('Encoding ' + tag + ' time is not supported yet'); + } + + return this._encodeStr(str, 'octstr'); }; +DERNode.prototype._encodeNull = function encodeNull() { + return this._createEncoderBuffer(''); +}; -/** - * Start an address scanning process. - * When finished, the scanning process will send a notification 'ScanFinished' to all copayers. - * - * @param {Object} opts - * @param {Boolean} opts.includeCopayerBranches (defaults to false) - * @param {Callback} cb - */ -API.prototype.startScan = function(opts, cb) { - $.checkState(this.credentials && this.credentials.isComplete()); +DERNode.prototype._encodeInt = function encodeInt(num, values) { + if (typeof num === 'string') { + if (!values) + return this.reporter.error('String int or enum given, but no values map'); + if (!values.hasOwnProperty(num)) { + return this.reporter.error('Values map doesn\'t contain: ' + + JSON.stringify(num)); + } + num = values[num]; + } - var self = this; + // Bignum, assume big endian + if (typeof num !== 'number' && !Buffer.isBuffer(num)) { + var numArray = num.toArray(); + if (!num.sign && numArray[0] & 0x80) { + numArray.unshift(0); + } + num = new Buffer(numArray); + } - var args = { - includeCopayerBranches: opts.includeCopayerBranches, - }; + if (Buffer.isBuffer(num)) { + var size = num.length; + if (num.length === 0) + size++; - self._doPostRequest('/v1/addresses/scan', args, function(err) { - return cb(err); - }); -}; + var out = new Buffer(size); + num.copy(out); + if (num.length === 0) + out[0] = 0 + return this._createEncoderBuffer(out); + } -/* - * - * Compatibility Functions - * - */ + if (num < 0x80) + return this._createEncoderBuffer(num); -API.prototype._oldCopayDecrypt = function(username, password, blob) { - var SEP1 = '@#$'; - var SEP2 = '%^#@'; + if (num < 0x100) + return this._createEncoderBuffer([0, num]); - var decrypted; - try { - var passphrase = username + SEP1 + password; - decrypted = sjcl.decrypt(passphrase, blob); - } catch (e) { - passphrase = username + SEP2 + password; - try { - decrypted = sjcl.decrypt(passphrase, blob); - } catch (e) { - log.debug(e); - }; - } + var size = 1; + for (var i = num; i >= 0x100; i >>= 8) + size++; - if (!decrypted) - return null; + var out = new Array(size); + for (var i = out.length - 1; i >= 0; i--) { + out[i] = num & 0xff; + num >>= 8; + } + if(out[0] & 0x80) { + out.unshift(0); + } - var ret; - try { - ret = JSON.parse(decrypted); - } catch (e) {}; - return ret; + return this._createEncoderBuffer(new Buffer(out)); }; +DERNode.prototype._encodeBool = function encodeBool(value) { + return this._createEncoderBuffer(value ? 0xff : 0); +}; -API.prototype.getWalletIdsFromOldCopay = function(username, password, blob) { - var p = this._oldCopayDecrypt(username, password, blob); - if (!p) return null; - var ids = p.walletIds.concat(_.keys(p.focusedTimestamps)); - return _.uniq(ids); +DERNode.prototype._use = function use(entity, obj) { + if (typeof entity === 'function') + entity = entity(obj); + return entity._getEncoder('der').tree; }; +DERNode.prototype._skipDefault = function skipDefault(dataBuffer, reporter, parent) { + var state = this._baseState; + var i; + if (state['default'] === null) + return false; -/** - * createWalletFromOldCopay - * - * @param username - * @param password - * @param blob - * @param cb - * @return {undefined} - */ -API.prototype.createWalletFromOldCopay = function(username, password, blob, cb) { - var self = this; - var w = this._oldCopayDecrypt(username, password, blob); - if (!w) return cb('Could not decrypt'); + var data = dataBuffer.join(); + if (state.defaultBuffer === undefined) + state.defaultBuffer = this._encodeValue(state['default'], reporter, parent).join(); - if (w.publicKeyRing.copayersExtPubKeys.length != w.opts.totalCopayers) - return cb('Wallet is incomplete, cannot be imported'); + if (data.length !== state.defaultBuffer.length) + return false; - this.credentials = Credentials.fromOldCopayWallet(w); - this.recreateWallet(cb); + for (i=0; i < data.length; i++) + if (data[i] !== state.defaultBuffer[i]) + return false; + + return true; }; -/* - Adds access to the current copayer - * @param {Object} opts - * @param {bool} opts.generateNewKey Optional: generate a new key for the new access - * @param {string} opts.restrictions - * - cannotProposeTXs - * - cannotXXX TODO - * @param {string} opts.name (name for the new access) - * - * return the accesses Wallet and the requestPrivateKey - */ -API.prototype.addAccess = function(opts, cb) { - $.checkState(this.credentials && this.credentials.canSign()); +// Utility methods - var reqPrivKey = new Bitcore.PrivateKey(opts.generateNewKey ? null : this.credentials.requestPrivKey); - var requestPubKey = reqPrivKey.toPublicKey().toString(); +function encodeTag(tag, primitive, cls, reporter) { + var res; - var xPriv = new Bitcore.HDPrivateKey(this.credentials.xPrivKey) - .derive(this.credentials.getBaseAddressDerivationPath()); - var sig = Utils.signRequestPubKey(requestPubKey, xPriv); - var copayerId = this.credentials.copayerId; + if (tag === 'seqof') + tag = 'seq'; + else if (tag === 'setof') + tag = 'set'; - var opts = { - copayerId: copayerId, - requestPubKey: requestPubKey, - signature: sig, - name: opts.name, - restrictions: opts.restrictions, - }; + if (der.tagByName.hasOwnProperty(tag)) + res = der.tagByName[tag]; + else if (typeof tag === 'number' && (tag | 0) === tag) + res = tag; + else + return reporter.error('Unknown tag: ' + tag); - this._doPutRequest('/v1/copayers/' + copayerId + '/', opts, function(err, res) { - if (err) return cb(err); - return cb(null, res.wallet, reqPrivKey); - }); -}; + if (res >= 0x1f) + return reporter.error('Multi-octet tag encoding unsupported'); + if (!primitive) + res |= 0x20; -module.exports = API; + res |= (der.tagClassByName[cls || 'universal'] << 6); -}).call(this,require('_process'),require("buffer").Buffer) -},{"../package.json":282,"./common":6,"./credentials":8,"./errors/clienterror":9,"./errors/errordefinitions":10,"./log":12,"./paypro":13,"./verifier":14,"_process":499,"async":15,"bip38":16,"bitcore-lib":65,"browser-request":176,"buffer":299,"events":489,"json-stable-stringify":177,"lodash":181,"preconditions":182,"querystring":503,"request":187,"sjcl":281,"url":517,"util":519}],4:[function(require,module,exports){ -'use strict'; + return res; +} -var Constants = {}; +},{"../../asn1":3,"buffer":174,"inherits":233}],15:[function(require,module,exports){ +var encoders = exports; -Constants.SCRIPT_TYPES = { - P2SH: 'P2SH', - P2PKH: 'P2PKH', -}; -Constants.DERIVATION_STRATEGIES = { - BIP44: 'BIP44', - BIP45: 'BIP45', - BIP48: 'BIP48', -}; +encoders.der = require('./der'); +encoders.pem = require('./pem'); -Constants.PATHS = { - REQUEST_KEY: "m/1'/0", - TXPROPOSAL_KEY: "m/1'/1", - REQUEST_KEY_AUTH: "m/2", // relative to BASE +},{"./der":14,"./pem":16}],16:[function(require,module,exports){ +var inherits = require('inherits'); + +var DEREncoder = require('./der'); + +function PEMEncoder(entity) { + DEREncoder.call(this, entity); + this.enc = 'pem'; }; +inherits(PEMEncoder, DEREncoder); +module.exports = PEMEncoder; -Constants.BIP45_SHARED_INDEX = 0x80000000 - 1; +PEMEncoder.prototype.encode = function encode(data, options) { + var buf = DEREncoder.prototype.encode.call(this, data); -Constants.UNITS = { - btc: { - toSatoshis: 100000000, - maxDecimals: 6, - minDecimals: 2, - }, - bit: { - toSatoshis: 100, - maxDecimals: 0, - minDecimals: 0, - }, + var p = buf.toString('base64'); + var out = [ '-----BEGIN ' + options.label + '-----' ]; + for (var i = 0; i < p.length; i += 64) + out.push(p.slice(i, i + 64)); + out.push('-----END ' + options.label + '-----'); + return out.join('\n'); }; -module.exports = Constants; +},{"./der":14,"inherits":233}],17:[function(require,module,exports){ +// http://wiki.commonjs.org/wiki/Unit_Testing/1.0 +// +// THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8! +// +// Originally from narwhal.js (http://narwhaljs.org) +// Copyright (c) 2009 Thomas Robinson <280north.com> +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the 'Software'), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -},{}],5:[function(require,module,exports){ -'use strict'; +// when used in node, this will actually load the util module we depend on +// versus loading the builtin util module as happens otherwise +// this is a bug in node module loading as far as I am concerned +var util = require('util/'); -var Defaults = {}; +var pSlice = Array.prototype.slice; +var hasOwn = Object.prototype.hasOwnProperty; -Defaults.DEFAULT_FEE_PER_KB = 10000; -Defaults.MIN_FEE_PER_KB = 0; -Defaults.MAX_FEE_PER_KB = 1000000; -Defaults.MAX_TX_FEE = 1 * 1e8; +// 1. The assert module provides functions that throw +// AssertionError's when particular conditions are not met. The +// assert module must conform to the following interface. -module.exports = Defaults; +var assert = module.exports = ok; -},{}],6:[function(require,module,exports){ -var Common = {}; +// 2. The AssertionError is defined in assert. +// new assert.AssertionError({ message: message, +// actual: actual, +// expected: expected }) -Common.Constants = require('./constants'); -Common.Defaults = require('./defaults'); -Common.Utils = require('./utils'); +assert.AssertionError = function AssertionError(options) { + this.name = 'AssertionError'; + this.actual = options.actual; + this.expected = options.expected; + this.operator = options.operator; + if (options.message) { + this.message = options.message; + this.generatedMessage = false; + } else { + this.message = getMessage(this); + this.generatedMessage = true; + } + var stackStartFunction = options.stackStartFunction || fail; -module.exports = Common; + if (Error.captureStackTrace) { + Error.captureStackTrace(this, stackStartFunction); + } + else { + // non v8 browsers so we can have a stacktrace + var err = new Error(); + if (err.stack) { + var out = err.stack; -},{"./constants":4,"./defaults":5,"./utils":7}],7:[function(require,module,exports){ -(function (Buffer){ -'use strict'; + // try to strip useless frames + var fn_name = stackStartFunction.name; + var idx = out.indexOf('\n' + fn_name); + if (idx >= 0) { + // once we have located the function frame + // we need to strip out everything before it (and its line) + var next_line = out.indexOf('\n', idx + 1); + out = out.substring(next_line + 1); + } -var _ = require('lodash'); -var $ = require('preconditions').singleton(); -var sjcl = require('sjcl'); -var Stringify = require('json-stable-stringify'); + this.stack = out; + } + } +}; -var Bitcore = require('bitcore-lib'); -var Address = Bitcore.Address; -var PrivateKey = Bitcore.PrivateKey; -var PublicKey = Bitcore.PublicKey; -var crypto = Bitcore.crypto; -var encoding = Bitcore.encoding; +// assert.AssertionError instanceof Error +util.inherits(assert.AssertionError, Error); -var Constants = require('./constants'); +function replacer(key, value) { + if (util.isUndefined(value)) { + return '' + value; + } + if (util.isNumber(value) && !isFinite(value)) { + return value.toString(); + } + if (util.isFunction(value) || util.isRegExp(value)) { + return value.toString(); + } + return value; +} -function Utils() {}; +function truncate(s, n) { + if (util.isString(s)) { + return s.length < n ? s : s.slice(0, n); + } else { + return s; + } +} -Utils.encryptMessage = function(message, encryptingKey) { - var key = sjcl.codec.base64.toBits(encryptingKey); - return sjcl.encrypt(key, message, { - ks: 128, - iter: 1, - }); -}; +function getMessage(self) { + return truncate(JSON.stringify(self.actual, replacer), 128) + ' ' + + self.operator + ' ' + + truncate(JSON.stringify(self.expected, replacer), 128); +} -Utils.decryptMessage = function(cyphertextJson, encryptingKey) { - var key = sjcl.codec.base64.toBits(encryptingKey); - return sjcl.decrypt(key, cyphertextJson); -}; +// At present only the three keys mentioned above are used and +// understood by the spec. Implementations or sub modules can pass +// other keys to the AssertionError's constructor - they will be +// ignored. -/* TODO: It would be nice to be compatible with bitcoind signmessage. How - * the hash is calculated there? */ -Utils.hashMessage = function(text) { - $.checkArgument(text); - var buf = new Buffer(text); - var ret = crypto.Hash.sha256sha256(buf); - ret = new Bitcore.encoding.BufferReader(ret).readReverse(); - return ret; -}; +// 3. All of the following functions must throw an AssertionError +// when a corresponding condition is not met, with a message that +// may be undefined if not provided. All assertion methods provide +// both the actual and expected values to the assertion error for +// display purposes. + +function fail(actual, expected, message, operator, stackStartFunction) { + throw new assert.AssertionError({ + message: message, + actual: actual, + expected: expected, + operator: operator, + stackStartFunction: stackStartFunction + }); +} +// EXTENSION! allows for well behaved errors defined elsewhere. +assert.fail = fail; -Utils.signMessage = function(text, privKey) { - $.checkArgument(text); - var priv = new PrivateKey(privKey); - var hash = Utils.hashMessage(text); - return crypto.ECDSA.sign(hash, priv, 'little').toString(); -}; +// 4. Pure assertion tests whether a value is truthy, as determined +// by !!guard. +// assert.ok(guard, message_opt); +// This statement is equivalent to assert.equal(true, !!guard, +// message_opt);. To test strictly for the value true, use +// assert.strictEqual(true, guard, message_opt);. +function ok(value, message) { + if (!value) fail(value, true, message, '==', assert.ok); +} +assert.ok = ok; -Utils.verifyMessage = function(text, signature, pubKey) { - $.checkArgument(text); - $.checkArgument(pubKey); +// 5. The equality assertion tests shallow, coercive equality with +// ==. +// assert.equal(actual, expected, message_opt); - if (!signature) - return false; +assert.equal = function equal(actual, expected, message) { + if (actual != expected) fail(actual, expected, message, '==', assert.equal); +}; - var pub = new PublicKey(pubKey); - var hash = Utils.hashMessage(text); +// 6. The non-equality assertion tests for whether two objects are not equal +// with != assert.notEqual(actual, expected, message_opt); - try { - var sig = new crypto.Signature.fromString(signature); - return crypto.ECDSA.verify(hash, sig, pub, 'little'); - } catch (e) { - return false; +assert.notEqual = function notEqual(actual, expected, message) { + if (actual == expected) { + fail(actual, expected, message, '!=', assert.notEqual); } }; -Utils.privateKeyToAESKey = function(privKey) { - $.checkArgument(privKey && _.isString(privKey)); - $.checkArgument(Bitcore.PrivateKey.isValid(privKey), 'The private key received is invalid'); - var pk = Bitcore.PrivateKey.fromString(privKey); - return Bitcore.crypto.Hash.sha256(pk.toBuffer()).slice(0, 16).toString('base64'); -}; +// 7. The equivalence assertion tests a deep equality relation. +// assert.deepEqual(actual, expected, message_opt); -Utils.getCopayerHash = function(name, xPubKey, requestPubKey) { - return [name, xPubKey, requestPubKey].join('|'); +assert.deepEqual = function deepEqual(actual, expected, message) { + if (!_deepEqual(actual, expected)) { + fail(actual, expected, message, 'deepEqual', assert.deepEqual); + } }; -Utils.getProposalHash = function(proposalHeader) { - function getOldHash(toAddress, amount, message, payProUrl) { - return [toAddress, amount, (message || ''), (payProUrl || '')].join('|'); - }; +function _deepEqual(actual, expected) { + // 7.1. All identical values are equivalent, as determined by ===. + if (actual === expected) { + return true; - // For backwards compatibility - if (arguments.length > 1) { - return getOldHash.apply(this, arguments); - } + } else if (util.isBuffer(actual) && util.isBuffer(expected)) { + if (actual.length != expected.length) return false; - return Stringify(proposalHeader); -}; + for (var i = 0; i < actual.length; i++) { + if (actual[i] !== expected[i]) return false; + } -Utils.deriveAddress = function(scriptType, publicKeyRing, path, m, network) { - $.checkArgument(_.contains(_.values(Constants.SCRIPT_TYPES), scriptType)); + return true; - var publicKeys = _.map(publicKeyRing, function(item) { - var xpub = new Bitcore.HDPublicKey(item.xPubKey); - return xpub.derive(path).publicKey; - }); + // 7.2. If the expected value is a Date object, the actual value is + // equivalent if it is also a Date object that refers to the same time. + } else if (util.isDate(actual) && util.isDate(expected)) { + return actual.getTime() === expected.getTime(); - var bitcoreAddress; - switch (scriptType) { - case Constants.SCRIPT_TYPES.P2SH: - bitcoreAddress = Address.createMultisig(publicKeys, m, network); - break; - case Constants.SCRIPT_TYPES.P2PKH: - $.checkState(_.isArray(publicKeys) && publicKeys.length == 1); - bitcoreAddress = Address.fromPublicKey(publicKeys[0], network); - break; - } + // 7.3 If the expected value is a RegExp object, the actual value is + // equivalent if it is also a RegExp object with the same source and + // properties (`global`, `multiline`, `lastIndex`, `ignoreCase`). + } else if (util.isRegExp(actual) && util.isRegExp(expected)) { + return actual.source === expected.source && + actual.global === expected.global && + actual.multiline === expected.multiline && + actual.lastIndex === expected.lastIndex && + actual.ignoreCase === expected.ignoreCase; - return { - address: bitcoreAddress.toString(), - path: path, - publicKeys: _.invoke(publicKeys, 'toString'), - }; -}; + // 7.4. Other pairs that do not both pass typeof value == 'object', + // equivalence is determined by ==. + } else if (!util.isObject(actual) && !util.isObject(expected)) { + return actual == expected; -Utils.xPubToCopayerId = function(xpub) { - var hash = sjcl.hash.sha256.hash(xpub); - return sjcl.codec.hex.fromBits(hash); -}; + // 7.5 For all other Object pairs, including Array objects, equivalence is + // determined by having the same number of owned properties (as verified + // with Object.prototype.hasOwnProperty.call), the same set of keys + // (although not necessarily the same order), equivalent values for every + // corresponding key, and an identical 'prototype' property. Note: this + // accounts for both named and indexed properties on Arrays. + } else { + return objEquiv(actual, expected); + } +} -Utils.signRequestPubKey = function(requestPubKey, xPrivKey) { - var priv = new Bitcore.HDPrivateKey(xPrivKey).derive(Constants.PATHS.REQUEST_KEY_AUTH).privateKey; - return Utils.signMessage(requestPubKey, priv); -}; +function isArguments(object) { + return Object.prototype.toString.call(object) == '[object Arguments]'; +} -Utils.verifyRequestPubKey = function(requestPubKey, signature, xPubKey) { - var pub = (new Bitcore.HDPublicKey(xPubKey)).derive(Constants.PATHS.REQUEST_KEY_AUTH).publicKey; - return Utils.verifyMessage(requestPubKey, signature, pub.toString()); -}; +function objEquiv(a, b) { + if (util.isNullOrUndefined(a) || util.isNullOrUndefined(b)) + return false; + // an identical 'prototype' property. + if (a.prototype !== b.prototype) return false; + // if one is a primitive, the other must be same + if (util.isPrimitive(a) || util.isPrimitive(b)) { + return a === b; + } + var aIsArgs = isArguments(a), + bIsArgs = isArguments(b); + if ((aIsArgs && !bIsArgs) || (!aIsArgs && bIsArgs)) + return false; + if (aIsArgs) { + a = pSlice.call(a); + b = pSlice.call(b); + return _deepEqual(a, b); + } + var ka = objectKeys(a), + kb = objectKeys(b), + key, i; + // having the same number of owned properties (keys incorporates + // hasOwnProperty) + if (ka.length != kb.length) + return false; + //the same set of keys (although not necessarily the same order), + ka.sort(); + kb.sort(); + //~~~cheap key test + for (i = ka.length - 1; i >= 0; i--) { + if (ka[i] != kb[i]) + return false; + } + //equivalent values for every corresponding key, and + //~~~possibly expensive deep test + for (i = ka.length - 1; i >= 0; i--) { + key = ka[i]; + if (!_deepEqual(a[key], b[key])) return false; + } + return true; +} -Utils.formatAmount = function(satoshis, unit, opts) { - $.shouldBeNumber(satoshis); - $.checkArgument(_.contains(_.keys(Constants.UNITS), unit)); +// 8. The non-equivalence assertion tests for any deep inequality. +// assert.notDeepEqual(actual, expected, message_opt); - function addSeparators(nStr, thousands, decimal, minDecimals) { - nStr = nStr.replace('.', decimal); - var x = nStr.split(decimal); - var x0 = x[0]; - var x1 = x[1]; +assert.notDeepEqual = function notDeepEqual(actual, expected, message) { + if (_deepEqual(actual, expected)) { + fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual); + } +}; - x1 = _.dropRightWhile(x1, function(n, i) { - return n == '0' && i >= minDecimals; - }).join(''); - var x2 = x.length > 1 ? decimal + x1 : ''; +// 9. The strict equality assertion tests strict equality, as determined by ===. +// assert.strictEqual(actual, expected, message_opt); - x0 = x0.replace(/\B(?=(\d{3})+(?!\d))/g, thousands); - return x0 + x2; +assert.strictEqual = function strictEqual(actual, expected, message) { + if (actual !== expected) { + fail(actual, expected, message, '===', assert.strictEqual); } +}; - opts = opts || {}; +// 10. The strict non-equality assertion tests for strict inequality, as +// determined by !==. assert.notStrictEqual(actual, expected, message_opt); - var u = Constants.UNITS[unit]; - var amount = (satoshis / u.toSatoshis).toFixed(u.maxDecimals); - return addSeparators(amount, opts.thousandsSeparator || ',', opts.decimalSeparator || '.', u.minDecimals); +assert.notStrictEqual = function notStrictEqual(actual, expected, message) { + if (actual === expected) { + fail(actual, expected, message, '!==', assert.notStrictEqual); + } }; -module.exports = Utils; +function expectedException(actual, expected) { + if (!actual || !expected) { + return false; + } -}).call(this,require("buffer").Buffer) -},{"./constants":4,"bitcore-lib":65,"buffer":299,"json-stable-stringify":177,"lodash":181,"preconditions":182,"sjcl":281}],8:[function(require,module,exports){ -(function (Buffer){ -'use strict'; + if (Object.prototype.toString.call(expected) == '[object RegExp]') { + return expected.test(actual); + } else if (actual instanceof expected) { + return true; + } else if (expected.call({}, actual) === true) { + return true; + } -var $ = require('preconditions').singleton(); -var _ = require('lodash'); + return false; +} -var Bitcore = require('bitcore-lib'); -var Mnemonic = require('bitcore-mnemonic'); -var sjcl = require('sjcl'); +function _throws(shouldThrow, block, expected, message) { + var actual; -var Common = require('./common'); -var Constants = Common.Constants; -var Utils = Common.Utils; - -var FIELDS = [ - 'network', - 'xPrivKey', - 'xPrivKeyEncrypted', - 'xPubKey', - 'requestPrivKey', - 'requestPubKey', - 'copayerId', - 'publicKeyRing', - 'walletId', - 'walletName', - 'm', - 'n', - 'walletPrivKey', - 'personalEncryptingKey', - 'sharedEncryptingKey', - 'copayerName', - 'externalSource', - 'mnemonic', - 'mnemonicEncrypted', - 'entropySource', - 'mnemonicHasPassphrase', - 'derivationStrategy', - 'account', - 'addressType', -]; - -function Credentials() { - this.version = '1.0.0'; - this.derivationStrategy = Constants.DERIVATION_STRATEGIES.BIP44; - this.account = 0; -}; - -function _checkNetwork(network) { - if (!_.contains(['livenet', 'testnet'], network)) throw new Error('Invalid network'); -}; - -Credentials.create = function(network) { - _checkNetwork(network); + if (util.isString(expected)) { + message = expected; + expected = null; + } - var x = new Credentials(); + try { + block(); + } catch (e) { + actual = e; + } - x.network = network; - x.xPrivKey = (new Bitcore.HDPrivateKey(network)).toString(); - x._expand(); - return x; -}; + message = (expected && expected.name ? ' (' + expected.name + ').' : '.') + + (message ? ' ' + message : '.'); -var wordsForLang = { - 'en': Mnemonic.Words.ENGLISH, - 'es': Mnemonic.Words.SPANISH, - 'ja': Mnemonic.Words.JAPANESE, - 'zh': Mnemonic.Words.CHINESE, - 'fr': Mnemonic.Words.FRENCH, -}; + if (shouldThrow && !actual) { + fail(actual, expected, 'Missing expected exception' + message); + } -Credentials.createWithMnemonic = function(network, passphrase, language, account) { - _checkNetwork(network); - if (!wordsForLang[language]) throw new Error('Unsupported language'); - $.shouldBeNumber(account); + if (!shouldThrow && expectedException(actual, expected)) { + fail(actual, expected, 'Got unwanted exception' + message); + } - var m = new Mnemonic(wordsForLang[language]); - while (!Mnemonic.isValid(m.toString())) { - m = new Mnemonic(wordsForLang[language]) - }; - var x = new Credentials(); + if ((shouldThrow && actual && expected && + !expectedException(actual, expected)) || (!shouldThrow && actual)) { + throw actual; + } +} - x.network = network; - x.account = account; - x.xPrivKey = m.toHDPrivateKey(passphrase, network).toString(); - x._expand(); - x.mnemonic = m.phrase; - x.mnemonicHasPassphrase = !!passphrase; +// 11. Expected to throw an error: +// assert.throws(block, Error_opt, message_opt); - return x; +assert.throws = function(block, /*optional*/error, /*optional*/message) { + _throws.apply(this, [true].concat(pSlice.call(arguments))); }; -Credentials.fromExtendedPrivateKey = function(xPrivKey) { - var x = new Credentials(); - x.xPrivKey = xPrivKey; - x._expand(); - return x; +// EXTENSION! This is annoying to write outside this module. +assert.doesNotThrow = function(block, /*optional*/message) { + _throws.apply(this, [false].concat(pSlice.call(arguments))); }; -// note that mnemonic / passphrase is NOT stored -Credentials.fromMnemonic = function(network, words, passphrase, account, derivationStrategy) { - _checkNetwork(network); - $.shouldBeNumber(account); - $.checkArgument(_.contains(_.values(Constants.DERIVATION_STRATEGIES), derivationStrategy)); +assert.ifError = function(err) { if (err) {throw err;}}; - var m = new Mnemonic(words); - var x = new Credentials(); - x.xPrivKey = m.toHDPrivateKey(passphrase, network).toString(); - x.mnemonicHasPassphrase = !!passphrase; - x.account = account; - x.derivationStrategy = derivationStrategy; - x._expand(); - return x; +var objectKeys = Object.keys || function (obj) { + var keys = []; + for (var key in obj) { + if (hasOwn.call(obj, key)) keys.push(key); + } + return keys; }; -/* - * BWC uses - * xPrivKey -> m/44'/network'/account' -> Base Address Key - * so, xPubKey is PublicKeyHD(xPrivKey.derive("m/44'/network'/account'"). - * - * For external sources, this derivation should be done before - * call fromExtendedPublicKey - * - * entropySource should be a HEX string containing pseudo-random data, that can - * be deterministically derived from the xPrivKey, and should not be derived from xPubKey - */ -Credentials.fromExtendedPublicKey = function(xPubKey, source, entropySourceHex, account, derivationStrategy) { - $.checkArgument(entropySourceHex); - $.shouldBeNumber(account); - $.checkArgument(_.contains(_.values(Constants.DERIVATION_STRATEGIES), derivationStrategy)); - - var entropyBuffer = new Buffer(entropySourceHex, 'hex'); - //require at least 112 bits of entropy - $.checkArgument(entropyBuffer.length >= 14, 'At least 112 bits of entropy are needed') +},{"util/":303}],18:[function(require,module,exports){ +var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; - var x = new Credentials(); - x.xPubKey = xPubKey; - x.entropySource = Bitcore.crypto.Hash.sha256sha256(entropyBuffer).toString('hex'); - x.account = account; - x.derivationStrategy = derivationStrategy; - x.externalSource = source; - x._expand(); - return x; -}; +;(function (exports) { + 'use strict'; -// Get network from extended private key or extended public key -Credentials._getNetworkFromExtendedKey = function(xKey) { - $.checkArgument(xKey && _.isString(xKey)); - return xKey.charAt(0) == 't' ? 'testnet' : 'livenet'; -}; + var Arr = (typeof Uint8Array !== 'undefined') + ? Uint8Array + : Array -Credentials._xPubToCopayerId = function(xpub) { - var hash = sjcl.hash.sha256.hash(xpub); - return sjcl.codec.hex.fromBits(hash); -}; + var PLUS = '+'.charCodeAt(0) + var SLASH = '/'.charCodeAt(0) + var NUMBER = '0'.charCodeAt(0) + var LOWER = 'a'.charCodeAt(0) + var UPPER = 'A'.charCodeAt(0) + var PLUS_URL_SAFE = '-'.charCodeAt(0) + var SLASH_URL_SAFE = '_'.charCodeAt(0) -Credentials.prototype._hashFromEntropy = function(prefix, length) { - $.checkState(prefix); - var b = new Buffer(this.entropySource, 'hex'); - var b2 = Bitcore.crypto.Hash.sha256hmac(b, new Buffer(prefix)); - return b2.slice(0, length); -}; + function decode (elt) { + var code = elt.charCodeAt(0) + if (code === PLUS || + code === PLUS_URL_SAFE) + return 62 // '+' + if (code === SLASH || + code === SLASH_URL_SAFE) + return 63 // '/' + if (code < NUMBER) + return -1 //no match + if (code < NUMBER + 10) + return code - NUMBER + 26 + 26 + if (code < UPPER + 26) + return code - UPPER + if (code < LOWER + 26) + return code - LOWER + 26 + } + function b64ToByteArray (b64) { + var i, j, l, tmp, placeHolders, arr -Credentials.prototype._expand = function() { - $.checkState(this.xPrivKey || (this.xPubKey && this.entropySource)); + if (b64.length % 4 > 0) { + throw new Error('Invalid string. Length must be a multiple of 4') + } - var network = Credentials._getNetworkFromExtendedKey(this.xPrivKey || this.xPubKey); - if (this.network) { - $.checkState(this.network == network); - } else { - this.network = network; - } + // the number of equal signs (place holders) + // if there are two placeholders, than the two characters before it + // represent one byte + // if there is only one, then the three characters before it represent 2 bytes + // this is just a cheap hack to not do indexOf twice + var len = b64.length + placeHolders = '=' === b64.charAt(len - 2) ? 2 : '=' === b64.charAt(len - 1) ? 1 : 0 - if (this.xPrivKey) { - var xPrivKey = new Bitcore.HDPrivateKey.fromString(this.xPrivKey); + // base64 is 4/3 + up to two characters of the original data + arr = new Arr(b64.length * 3 / 4 - placeHolders) - // this extra derivation is not to share a non hardened xPubKey to the server. - var addressDerivation = xPrivKey.derive(this.getBaseAddressDerivationPath()); - this.xPubKey = (new Bitcore.HDPublicKey(addressDerivation)).toString(); + // if there are placeholders, only get up to the last complete 4 chars + l = placeHolders > 0 ? b64.length - 4 : b64.length - var requestDerivation = xPrivKey.derive(Constants.PATHS.REQUEST_KEY); - this.requestPrivKey = requestDerivation.privateKey.toString(); + var L = 0 - var pubKey = requestDerivation.publicKey; - this.requestPubKey = pubKey.toString(); + function push (v) { + arr[L++] = v + } - this.entropySource = Bitcore.crypto.Hash.sha256(requestDerivation.privateKey.toBuffer()).toString('hex'); - } else { - var seed = this._hashFromEntropy('reqPrivKey', 32); - var privKey = new Bitcore.PrivateKey(seed.toString('hex'), network); - this.requestPrivKey = privKey.toString(); - this.requestPubKey = privKey.toPublicKey().toString(); - } + for (i = 0, j = 0; i < l; i += 4, j += 3) { + tmp = (decode(b64.charAt(i)) << 18) | (decode(b64.charAt(i + 1)) << 12) | (decode(b64.charAt(i + 2)) << 6) | decode(b64.charAt(i + 3)) + push((tmp & 0xFF0000) >> 16) + push((tmp & 0xFF00) >> 8) + push(tmp & 0xFF) + } - this.personalEncryptingKey = this._hashFromEntropy('personalKey', 16).toString('base64'); + if (placeHolders === 2) { + tmp = (decode(b64.charAt(i)) << 2) | (decode(b64.charAt(i + 1)) >> 4) + push(tmp & 0xFF) + } else if (placeHolders === 1) { + tmp = (decode(b64.charAt(i)) << 10) | (decode(b64.charAt(i + 1)) << 4) | (decode(b64.charAt(i + 2)) >> 2) + push((tmp >> 8) & 0xFF) + push(tmp & 0xFF) + } + return arr + } - this.copayerId = Credentials._xPubToCopayerId(this.xPubKey); - this.publicKeyRing = [{ - xPubKey: this.xPubKey, - requestPubKey: this.requestPubKey, - }]; -}; + function uint8ToBase64 (uint8) { + var i, + extraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes + output = "", + temp, length -Credentials.fromObj = function(obj) { - var x = new Credentials(); + function encode (num) { + return lookup.charAt(num) + } - _.each(FIELDS, function(k) { - x[k] = obj[k]; - }); + function tripletToBase64 (num) { + return encode(num >> 18 & 0x3F) + encode(num >> 12 & 0x3F) + encode(num >> 6 & 0x3F) + encode(num & 0x3F) + } - x.derivationStrategy = x.derivationStrategy || Constants.DERIVATION_STRATEGIES.BIP45; - x.addressType = x.addressType || Constants.SCRIPT_TYPES.P2SH; - x.account = x.account || 0; + // go through the array every three bytes, we'll deal with trailing stuff later + for (i = 0, length = uint8.length - extraBytes; i < length; i += 3) { + temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]) + output += tripletToBase64(temp) + } - $.checkState(x.xPrivKey || x.xPubKey || x.xPrivKeyEncrypted, "invalid input"); - return x; -}; + // pad the end with zeros, but make sure to not forget the extra bytes + switch (extraBytes) { + case 1: + temp = uint8[uint8.length - 1] + output += encode(temp >> 2) + output += encode((temp << 4) & 0x3F) + output += '==' + break + case 2: + temp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1]) + output += encode(temp >> 10) + output += encode((temp >> 4) & 0x3F) + output += encode((temp << 2) & 0x3F) + output += '=' + break + } -Credentials.prototype.toObj = function() { - var self = this; + return output + } - if (self.hasPrivKeyEncrypted()) - self.lock(); + exports.toByteArray = b64ToByteArray + exports.fromByteArray = uint8ToBase64 +}(typeof exports === 'undefined' ? (this.base64js = {}) : exports)) - var x = {}; - _.each(FIELDS, function(k) { - x[k] = self[k]; - }); - return x; -}; +},{}],19:[function(require,module,exports){ +// (public) Constructor +function BigInteger(a, b, c) { + if (!(this instanceof BigInteger)) + return new BigInteger(a, b, c) -Credentials.prototype.getBaseAddressDerivationPath = function() { - var purpose; - switch (this.derivationStrategy) { - case Constants.DERIVATION_STRATEGIES.BIP45: - return "m/45'"; - case Constants.DERIVATION_STRATEGIES.BIP44: - purpose = '44'; - break; - case Constants.DERIVATION_STRATEGIES.BIP48: - purpose = '48'; - break; + if (a != null) { + if ("number" == typeof a) this.fromNumber(a, b, c) + else if (b == null && "string" != typeof a) this.fromString(a, 256) + else this.fromString(a, b) } +} - var coin = (this.network == 'livenet' ? "0" : "1"); - return "m/" + purpose + "'/" + coin + "'/" + this.account + "'"; -}; - -Credentials.prototype.getDerivedXPrivKey = function() { - var path = this.getBaseAddressDerivationPath(); - return new Bitcore.HDPrivateKey(this.xPrivKey, this.network).derive(path); -}; - -Credentials.prototype.addWalletPrivateKey = function(walletPrivKey) { - this.walletPrivKey = walletPrivKey; - this.sharedEncryptingKey = Utils.privateKeyToAESKey(walletPrivKey); -}; - -Credentials.prototype.addWalletInfo = function(walletId, walletName, m, n, walletPrivKey, copayerName) { - this.walletId = walletId; - this.walletName = walletName; - this.m = m; - this.n = n; +var proto = BigInteger.prototype - if (walletPrivKey) - this.addWalletPrivateKey(walletPrivKey); +// duck-typed isBigInteger +proto.__bigi = require('../package.json').version +BigInteger.isBigInteger = function (obj, check_ver) { + return obj && obj.__bigi && (!check_ver || obj.__bigi === proto.__bigi) +} - if (copayerName) - this.copayerName = copayerName; +// Bits per digit +var dbits - this.addressType = (n == 1) ? Constants.SCRIPT_TYPES.P2PKH : Constants.SCRIPT_TYPES.P2SH; +// am: Compute w_j += (x*this_i), propagate carries, +// c is initial carry, returns final carry. +// c < 3*dvalue, x < 2*dvalue, this_i < dvalue +// We need to select the fastest one that works in this environment. - // Use m/48' for multisig hardware wallets - if (!this.xPrivKey && this.externalSource && n > 1) { - this.derivationStrategy = Constants.DERIVATION_STRATEGIES.BIP48; +// am1: use a single mult and divide to get the high bits, +// max digit bits should be 26 because +// max internal value = 2*dvalue^2-2*dvalue (< 2^53) +function am1(i, x, w, j, c, n) { + while (--n >= 0) { + var v = x * this[i++] + w[j] + c + c = Math.floor(v / 0x4000000) + w[j++] = v & 0x3ffffff } - - if (n == 1) { - this.addPublicKeyRing([{ - xPubKey: this.xPubKey, - requestPubKey: this.requestPubKey, - }]); + return c +} +// am2 avoids a big mult-and-extract completely. +// Max digit bits should be <= 30 because we do bitwise ops +// on values up to 2*hdvalue^2-hdvalue-1 (< 2^31) +function am2(i, x, w, j, c, n) { + var xl = x & 0x7fff, + xh = x >> 15 + while (--n >= 0) { + var l = this[i] & 0x7fff + var h = this[i++] >> 15 + var m = xh * l + h * xl + l = xl * l + ((m & 0x7fff) << 15) + w[j] + (c & 0x3fffffff) + c = (l >>> 30) + (m >>> 15) + xh * h + (c >>> 30) + w[j++] = l & 0x3fffffff } -}; - -Credentials.prototype.hasWalletInfo = function() { - return !!this.walletId; -}; - -Credentials.prototype.isPrivKeyEncrypted = function() { - return (!!this.xPrivKeyEncrypted) && !this.xPrivKey; -}; - -Credentials.prototype.hasPrivKeyEncrypted = function() { - return (!!this.xPrivKeyEncrypted); -}; - -Credentials.prototype.setPrivateKeyEncryption = function(password, opts) { - if (this.xPrivKeyEncrypted) - throw new Error('Encrypted Privkey Already exists'); - - if (!this.xPrivKey) - throw new Error('No private key to encrypt'); - + return c +} +// Alternately, set max digit bits to 28 since some +// browsers slow down when dealing with 32-bit numbers. +function am3(i, x, w, j, c, n) { + var xl = x & 0x3fff, + xh = x >> 14 + while (--n >= 0) { + var l = this[i] & 0x3fff + var h = this[i++] >> 14 + var m = xh * l + h * xl + l = xl * l + ((m & 0x3fff) << 14) + w[j] + c + c = (l >> 28) + (m >> 14) + xh * h + w[j++] = l & 0xfffffff + } + return c +} - this.xPrivKeyEncrypted = sjcl.encrypt(password, this.xPrivKey, opts); - if (!this.xPrivKeyEncrypted) - throw new Error('Could not encrypt'); +// wtf? +BigInteger.prototype.am = am1 +dbits = 26 - if (this.mnemonic) - this.mnemonicEncrypted = sjcl.encrypt(password, this.mnemonic, opts); -}; +BigInteger.prototype.DB = dbits +BigInteger.prototype.DM = ((1 << dbits) - 1) +var DV = BigInteger.prototype.DV = (1 << dbits) +var BI_FP = 52 +BigInteger.prototype.FV = Math.pow(2, BI_FP) +BigInteger.prototype.F1 = BI_FP - dbits +BigInteger.prototype.F2 = 2 * dbits - BI_FP -Credentials.prototype.disablePrivateKeyEncryption = function() { - if (!this.xPrivKeyEncrypted) - throw new Error('Private Key is not encrypted'); +// Digit conversions +var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz" +var BI_RC = new Array() +var rr, vv +rr = "0".charCodeAt(0) +for (vv = 0; vv <= 9; ++vv) BI_RC[rr++] = vv +rr = "a".charCodeAt(0) +for (vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv +rr = "A".charCodeAt(0) +for (vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv - if (!this.xPrivKey) - throw new Error('Wallet is locked, cannot disable encryption'); +function int2char(n) { + return BI_RM.charAt(n) +} - this.xPrivKeyEncrypted = null; - this.mnemonicEncrypted = null; -}; +function intAt(s, i) { + var c = BI_RC[s.charCodeAt(i)] + return (c == null) ? -1 : c +} +// (protected) copy this to r +function bnpCopyTo(r) { + for (var i = this.t - 1; i >= 0; --i) r[i] = this[i] + r.t = this.t + r.s = this.s +} -Credentials.prototype.lock = function() { - if (!this.xPrivKeyEncrypted) - throw new Error('Could not lock, no encrypted private key'); +// (protected) set from integer value x, -DV <= x < DV +function bnpFromInt(x) { + this.t = 1 + this.s = (x < 0) ? -1 : 0 + if (x > 0) this[0] = x + else if (x < -1) this[0] = x + DV + else this.t = 0 +} - delete this.xPrivKey; - delete this.mnemonic; -}; +// return bigint initialized to value +function nbv(i) { + var r = new BigInteger() + r.fromInt(i) + return r +} -Credentials.prototype.unlock = function(password) { - $.checkArgument(password); +// (protected) set from string and radix +function bnpFromString(s, b) { + var self = this - if (this.xPrivKeyEncrypted) { - this.xPrivKey = sjcl.decrypt(password, this.xPrivKeyEncrypted); - if (this.mnemonicEncrypted) { - this.mnemonic = sjcl.decrypt(password, this.mnemonicEncrypted); - } + var k + if (b == 16) k = 4 + else if (b == 8) k = 3 + else if (b == 256) k = 8; // byte array + else if (b == 2) k = 1 + else if (b == 32) k = 5 + else if (b == 4) k = 2 + else { + self.fromRadix(s, b) + return } -}; - -Credentials.prototype.addPublicKeyRing = function(publicKeyRing) { - this.publicKeyRing = _.clone(publicKeyRing); -}; - -Credentials.prototype.canSign = function() { - return (!!this.xPrivKey || !!this.xPrivKeyEncrypted); -}; - -Credentials.prototype.setNoSign = function() { - delete this.xPrivKey; - delete this.xPrivKeyEncrypted; - delete this.mnemonic; - delete this.mnemonicEncrypted; -}; + self.t = 0 + self.s = 0 + var i = s.length, + mi = false, + sh = 0 + while (--i >= 0) { + var x = (k == 8) ? s[i] & 0xff : intAt(s, i) + if (x < 0) { + if (s.charAt(i) == "-") mi = true + continue + } + mi = false + if (sh == 0) + self[self.t++] = x + else if (sh + k > self.DB) { + self[self.t - 1] |= (x & ((1 << (self.DB - sh)) - 1)) << sh + self[self.t++] = (x >> (self.DB - sh)) + } else + self[self.t - 1] |= x << sh + sh += k + if (sh >= self.DB) sh -= self.DB + } + if (k == 8 && (s[0] & 0x80) != 0) { + self.s = -1 + if (sh > 0) self[self.t - 1] |= ((1 << (self.DB - sh)) - 1) << sh + } + self.clamp() + if (mi) BigInteger.ZERO.subTo(self, self) +} -Credentials.prototype.isComplete = function() { - if (!this.m || !this.n) return false; - if (!this.publicKeyRing || this.publicKeyRing.length != this.n) return false; - return true; -}; +// (protected) clamp off excess high words +function bnpClamp() { + var c = this.s & this.DM + while (this.t > 0 && this[this.t - 1] == c)--this.t +} -Credentials.prototype.hasExternalSource = function() { - return (typeof this.externalSource == "string"); -}; +// (public) return string representation in given radix +function bnToString(b) { + var self = this + if (self.s < 0) return "-" + self.negate() + .toString(b) + var k + if (b == 16) k = 4 + else if (b == 8) k = 3 + else if (b == 2) k = 1 + else if (b == 32) k = 5 + else if (b == 4) k = 2 + else return self.toRadix(b) + var km = (1 << k) - 1, + d, m = false, + r = "", + i = self.t + var p = self.DB - (i * self.DB) % k + if (i-- > 0) { + if (p < self.DB && (d = self[i] >> p) > 0) { + m = true + r = int2char(d) + } + while (i >= 0) { + if (p < k) { + d = (self[i] & ((1 << p) - 1)) << (k - p) + d |= self[--i] >> (p += self.DB - k) + } else { + d = (self[i] >> (p -= k)) & km + if (p <= 0) { + p += self.DB + --i + } + } + if (d > 0) m = true + if (m) r += int2char(d) + } + } + return m ? r : "0" +} -Credentials.prototype.getExternalSourceName = function() { - return this.externalSource; -}; +// (public) -this +function bnNegate() { + var r = new BigInteger() + BigInteger.ZERO.subTo(this, r) + return r +} -Credentials.prototype.getMnemonic = function() { - if (this.mnemonicEncrypted && !this.mnemonic) { - throw new Error('Credentials are encrypted'); +// (public) |this| +function bnAbs() { + return (this.s < 0) ? this.negate() : this +} + +// (public) return + if this > a, - if this < a, 0 if equal +function bnCompareTo(a) { + var r = this.s - a.s + if (r != 0) return r + var i = this.t + r = i - a.t + if (r != 0) return (this.s < 0) ? -r : r + while (--i >= 0) + if ((r = this[i] - a[i]) != 0) return r + return 0 +} + +// returns bit length of the integer x +function nbits(x) { + var r = 1, + t + if ((t = x >>> 16) != 0) { + x = t + r += 16 + } + if ((t = x >> 8) != 0) { + x = t + r += 8 + } + if ((t = x >> 4) != 0) { + x = t + r += 4 + } + if ((t = x >> 2) != 0) { + x = t + r += 2 + } + if ((t = x >> 1) != 0) { + x = t + r += 1 } + return r +} - return this.mnemonic; -}; +// (public) return the number of bits in "this" +function bnBitLength() { + if (this.t <= 0) return 0 + return this.DB * (this.t - 1) + nbits(this[this.t - 1] ^ (this.s & this.DM)) +} +// (public) return the number of bytes in "this" +function bnByteLength() { + return this.bitLength() >> 3 +} -Credentials.prototype.clearMnemonic = function() { - delete this.mnemonic; - delete this.mnemonicEncrypted; -}; +// (protected) r = this << n*DB +function bnpDLShiftTo(n, r) { + var i + for (i = this.t - 1; i >= 0; --i) r[i + n] = this[i] + for (i = n - 1; i >= 0; --i) r[i] = 0 + r.t = this.t + n + r.s = this.s +} -Credentials.fromOldCopayWallet = function(w) { - function walletPrivKeyFromOldCopayWallet(w) { - // IN BWS, the master Pub Keys are not sent to the server, - // so it is safe to use them as seed for wallet's shared secret. - var seed = w.publicKeyRing.copayersExtPubKeys.sort().join(''); - var seedBuf = new Buffer(seed); - var privKey = new Bitcore.PrivateKey.fromBuffer(Bitcore.crypto.Hash.sha256(seedBuf)); - return privKey.toString(); - }; +// (protected) r = this >> n*DB +function bnpDRShiftTo(n, r) { + for (var i = n; i < this.t; ++i) r[i - n] = this[i] + r.t = Math.max(this.t - n, 0) + r.s = this.s +} - var credentials = new Credentials(); - credentials.derivationStrategy = Constants.DERIVATION_STRATEGIES.BIP45; - credentials.xPrivKey = w.privateKey.extendedPrivateKeyString; - credentials._expand(); +// (protected) r = this << n +function bnpLShiftTo(n, r) { + var self = this + var bs = n % self.DB + var cbs = self.DB - bs + var bm = (1 << cbs) - 1 + var ds = Math.floor(n / self.DB), + c = (self.s << bs) & self.DM, + i + for (i = self.t - 1; i >= 0; --i) { + r[i + ds + 1] = (self[i] >> cbs) | c + c = (self[i] & bm) << bs + } + for (i = ds - 1; i >= 0; --i) r[i] = 0 + r[ds] = c + r.t = self.t + ds + 1 + r.s = self.s + r.clamp() +} - credentials.addWalletInfo(w.opts.id, w.opts.name, w.opts.requiredCopayers, w.opts.totalCopayers, walletPrivKeyFromOldCopayWallet(w)) +// (protected) r = this >> n +function bnpRShiftTo(n, r) { + var self = this + r.s = self.s + var ds = Math.floor(n / self.DB) + if (ds >= self.t) { + r.t = 0 + return + } + var bs = n % self.DB + var cbs = self.DB - bs + var bm = (1 << bs) - 1 + r[0] = self[ds] >> bs + for (var i = ds + 1; i < self.t; ++i) { + r[i - ds - 1] |= (self[i] & bm) << cbs + r[i - ds] = self[i] >> bs + } + if (bs > 0) r[self.t - ds - 1] |= (self.s & bm) << cbs + r.t = self.t - ds + r.clamp() +} - var pkr = _.map(w.publicKeyRing.copayersExtPubKeys, function(xPubStr) { +// (protected) r = this - a +function bnpSubTo(a, r) { + var self = this + var i = 0, + c = 0, + m = Math.min(a.t, self.t) + while (i < m) { + c += self[i] - a[i] + r[i++] = c & self.DM + c >>= self.DB + } + if (a.t < self.t) { + c -= a.s + while (i < self.t) { + c += self[i] + r[i++] = c & self.DM + c >>= self.DB + } + c += self.s + } else { + c += self.s + while (i < a.t) { + c -= a[i] + r[i++] = c & self.DM + c >>= self.DB + } + c -= a.s + } + r.s = (c < 0) ? -1 : 0 + if (c < -1) r[i++] = self.DV + c + else if (c > 0) r[i++] = c + r.t = i + r.clamp() +} - var isMe = xPubStr === credentials.xPubKey; - var requestDerivation; +// (protected) r = this * a, r != this,a (HAC 14.12) +// "this" should be the larger one if appropriate. +function bnpMultiplyTo(a, r) { + var x = this.abs(), + y = a.abs() + var i = x.t + r.t = i + y.t + while (--i >= 0) r[i] = 0 + for (i = 0; i < y.t; ++i) r[i + x.t] = x.am(0, y[i], r, i, 0, x.t) + r.s = 0 + r.clamp() + if (this.s != a.s) BigInteger.ZERO.subTo(r, r) +} - if (isMe) { - var path = Constants.PATHS.REQUEST_KEY; - requestDerivation = (new Bitcore.HDPrivateKey(credentials.xPrivKey)) - .derive(path).hdPublicKey; - } else { - // this - var path = Constants.PATHS.REQUEST_KEY_AUTH; - requestDerivation = (new Bitcore.HDPublicKey(xPubStr)).derive(path); +// (protected) r = this^2, r != this (HAC 14.16) +function bnpSquareTo(r) { + var x = this.abs() + var i = r.t = 2 * x.t + while (--i >= 0) r[i] = 0 + for (i = 0; i < x.t - 1; ++i) { + var c = x.am(i, x[i], r, 2 * i, 0, 1) + if ((r[i + x.t] += x.am(i + 1, 2 * x[i], r, 2 * i + 1, c, x.t - i - 1)) >= x.DV) { + r[i + x.t] -= x.DV + r[i + x.t + 1] = 1 } + } + if (r.t > 0) r[r.t - 1] += x.am(i, x[i], r, 2 * i, 0, 1) + r.s = 0 + r.clamp() +} - // Grab Copayer Name - var hd = new Bitcore.HDPublicKey(xPubStr).derive('m/2147483646/0/0'); - var pubKey = hd.publicKey.toString('hex'); - var copayerName = w.publicKeyRing.nicknameFor[pubKey]; - if (isMe) { - credentials.copayerName = copayerName; +// (protected) divide this by m, quotient and remainder to q, r (HAC 14.20) +// r != q, this != m. q or r may be null. +function bnpDivRemTo(m, q, r) { + var self = this + var pm = m.abs() + if (pm.t <= 0) return + var pt = self.abs() + if (pt.t < pm.t) { + if (q != null) q.fromInt(0) + if (r != null) self.copyTo(r) + return + } + if (r == null) r = new BigInteger() + var y = new BigInteger(), + ts = self.s, + ms = m.s + var nsh = self.DB - nbits(pm[pm.t - 1]); // normalize modulus + if (nsh > 0) { + pm.lShiftTo(nsh, y) + pt.lShiftTo(nsh, r) + } else { + pm.copyTo(y) + pt.copyTo(r) + } + var ys = y.t + var y0 = y[ys - 1] + if (y0 == 0) return + var yt = y0 * (1 << self.F1) + ((ys > 1) ? y[ys - 2] >> self.F2 : 0) + var d1 = self.FV / yt, + d2 = (1 << self.F1) / yt, + e = 1 << self.F2 + var i = r.t, + j = i - ys, + t = (q == null) ? new BigInteger() : q + y.dlShiftTo(j, t) + if (r.compareTo(t) >= 0) { + r[r.t++] = 1 + r.subTo(t, r) + } + BigInteger.ONE.dlShiftTo(ys, t) + t.subTo(y, y); // "negative" y so we can replace sub with am later + while (y.t < ys) y[y.t++] = 0 + while (--j >= 0) { + // Estimate quotient digit + var qd = (r[--i] == y0) ? self.DM : Math.floor(r[i] * d1 + (r[i - 1] + e) * d2) + if ((r[i] += y.am(0, qd, r, j, 0, ys)) < qd) { // Try it out + y.dlShiftTo(j, t) + r.subTo(t, r) + while (r[i] < --qd) r.subTo(t, r) } + } + if (q != null) { + r.drShiftTo(ys, q) + if (ts != ms) BigInteger.ZERO.subTo(q, q) + } + r.t = ys + r.clamp() + if (nsh > 0) r.rShiftTo(nsh, r); // Denormalize remainder + if (ts < 0) BigInteger.ZERO.subTo(r, r) +} - return { - xPubKey: xPubStr, - requestPubKey: requestDerivation.publicKey.toString(), - copayerName: copayerName, - }; - }); - credentials.addPublicKeyRing(pkr); - return credentials; -}; +// (public) this mod a +function bnMod(a) { + var r = new BigInteger() + this.abs() + .divRemTo(a, null, r) + if (this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r, r) + return r +} -module.exports = Credentials; +// Modular reduction using "classic" algorithm +function Classic(m) { + this.m = m +} -}).call(this,require("buffer").Buffer) -},{"./common":6,"bitcore-lib":65,"bitcore-mnemonic":142,"buffer":299,"lodash":181,"preconditions":182,"sjcl":281}],9:[function(require,module,exports){ -'use strict'; +function cConvert(x) { + if (x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m) + else return x +} -function ClientError(code, message) { - this.code = code; - this.message = message; -}; +function cRevert(x) { + return x +} -ClientError.prototype.toString = function() { - return ''; -}; +function cReduce(x) { + x.divRemTo(this.m, null, x) +} -module.exports = ClientError; +function cMulTo(x, y, r) { + x.multiplyTo(y, r) + this.reduce(r) +} -},{}],10:[function(require,module,exports){ -'use strict'; +function cSqrTo(x, r) { + x.squareTo(r) + this.reduce(r) +} -var _ = require('lodash'); +Classic.prototype.convert = cConvert +Classic.prototype.revert = cRevert +Classic.prototype.reduce = cReduce +Classic.prototype.mulTo = cMulTo +Classic.prototype.sqrTo = cSqrTo -var ClientError = require('./clienterror'); +// (protected) return "-1/this % 2^DB"; useful for Mont. reduction +// justification: +// xy == 1 (mod m) +// xy = 1+km +// xy(2-xy) = (1+km)(1-km) +// x[y(2-xy)] = 1-k^2m^2 +// x[y(2-xy)] == 1 (mod m^2) +// if y is 1/x mod m, then y(2-xy) is 1/x mod m^2 +// should reduce x and y(2-xy) by m^2 at each step to keep size bounded. +// JS multiply "overflows" differently from C/C++, so care is needed here. +function bnpInvDigit() { + if (this.t < 1) return 0 + var x = this[0] + if ((x & 1) == 0) return 0 + var y = x & 3; // y == 1/x mod 2^2 + y = (y * (2 - (x & 0xf) * y)) & 0xf; // y == 1/x mod 2^4 + y = (y * (2 - (x & 0xff) * y)) & 0xff; // y == 1/x mod 2^8 + y = (y * (2 - (((x & 0xffff) * y) & 0xffff))) & 0xffff; // y == 1/x mod 2^16 + // last step - calculate inverse mod DV directly + // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints + y = (y * (2 - x * y % this.DV)) % this.DV; // y == 1/x mod 2^dbits + // we really want the negative inverse, and -DV < y < DV + return (y > 0) ? this.DV - y : -y +} -var errors = { - INVALID_BACKUP: 'Invalid Backup', - WALLET_DOES_NOT_EXIST: 'Wallet does not exist. Need to recreate', - MISSING_PRIVATE_KEY: 'Missing private keys to sign', - ENCRYPTED_PRIVATE_KEY: 'Private key is encrypted, cannot sign', - SERVER_COMPROMISED: 'Server response could not be verified', - COULD_NOT_BUILD_TRANSACTION: 'Could not build transaction', - INSUFFICIENT_FUNDS: 'Insufficient funds', -}; +// Montgomery reduction +function Montgomery(m) { + this.m = m + this.mp = m.invDigit() + this.mpl = this.mp & 0x7fff + this.mph = this.mp >> 15 + this.um = (1 << (m.DB - 15)) - 1 + this.mt2 = 2 * m.t +} -var errorObjects = _.zipObject(_.map(errors, function(msg, code) { - return [code, new ClientError(code, msg)]; -})); +// xR mod m +function montConvert(x) { + var r = new BigInteger() + x.abs() + .dlShiftTo(this.m.t, r) + r.divRemTo(this.m, null, r) + if (x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r, r) + return r +} -errorObjects.codes = _.mapValues(errors, function(v, k) { - return k; -}); +// x/R mod m +function montRevert(x) { + var r = new BigInteger() + x.copyTo(r) + this.reduce(r) + return r +} -module.exports = errorObjects; +// x = x/R mod m (HAC 14.32) +function montReduce(x) { + while (x.t <= this.mt2) // pad x so am has enough room later + x[x.t++] = 0 + for (var i = 0; i < this.m.t; ++i) { + // faster way of calculating u0 = x[i]*mp mod DV + var j = x[i] & 0x7fff + var u0 = (j * this.mpl + (((j * this.mph + (x[i] >> 15) * this.mpl) & this.um) << 15)) & x.DM + // use am to combine the multiply-shift-add into one call + j = i + this.m.t + x[j] += this.m.am(0, u0, x, i, 0, this.m.t) + // propagate carry + while (x[j] >= x.DV) { + x[j] -= x.DV + x[++j]++ + } + } + x.clamp() + x.drShiftTo(this.m.t, x) + if (x.compareTo(this.m) >= 0) x.subTo(this.m, x) +} -},{"./clienterror":9,"lodash":181}],11:[function(require,module,exports){ -/** - * The official client library for bitcore-wallet-service. - * @module Client - */ +// r = "x^2/R mod m"; x != r +function montSqrTo(x, r) { + x.squareTo(r) + this.reduce(r) +} -/** - * Client API. - * @alias module:Client.API - */ -var client = module.exports = require('./api'); +// r = "xy/R mod m"; x,y != r +function montMulTo(x, y, r) { + x.multiplyTo(y, r) + this.reduce(r) +} -/** - * Verifier module. - * @alias module:Client.Verifier - */ -client.Verifier = require('./verifier'); -client.Utils = require('./common/utils'); -client.sjcl = require('sjcl'); +Montgomery.prototype.convert = montConvert +Montgomery.prototype.revert = montRevert +Montgomery.prototype.reduce = montReduce +Montgomery.prototype.mulTo = montMulTo +Montgomery.prototype.sqrTo = montSqrTo -// Expose bitcore -client.Bitcore = require('bitcore-lib'); +// (protected) true iff this is even +function bnpIsEven() { + return ((this.t > 0) ? (this[0] & 1) : this.s) == 0 +} -},{"./api":3,"./common/utils":7,"./verifier":14,"bitcore-lib":65,"sjcl":281}],12:[function(require,module,exports){ -var _ = require('lodash'); -/** - * @desc - * A simple logger that wraps the console.log methods when available. - * - * Usage: - *
- *   log = new Logger('copay');
- *   log.setLevel('info');
- *   log.debug('Message!'); // won't show
- *   log.setLevel('debug');
- *   log.debug('Message!', 1); // will show '[debug] copay: Message!, 1'
- * 
- * - * @param {string} name - a name for the logger. This will show up on every log call - * @constructor - */ -var Logger = function(name) { - this.name = name || 'log'; - this.level = 2; -}; +// (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79) +function bnpExp(e, z) { + if (e > 0xffffffff || e < 1) return BigInteger.ONE + var r = new BigInteger(), + r2 = new BigInteger(), + g = z.convert(this), + i = nbits(e) - 1 + g.copyTo(r) + while (--i >= 0) { + z.sqrTo(r, r2) + if ((e & (1 << i)) > 0) z.mulTo(r2, g, r) + else { + var t = r + r = r2 + r2 = t + } + } + return z.revert(r) +} -Logger.prototype.getLevels = function() { - return levels; -}; +// (public) this^e % m, 0 <= e < 2^32 +function bnModPowInt(e, m) { + var z + if (e < 256 || m.isEven()) z = new Classic(m) + else z = new Montgomery(m) + return this.exp(e, z) +} + +// protected +proto.copyTo = bnpCopyTo +proto.fromInt = bnpFromInt +proto.fromString = bnpFromString +proto.clamp = bnpClamp +proto.dlShiftTo = bnpDLShiftTo +proto.drShiftTo = bnpDRShiftTo +proto.lShiftTo = bnpLShiftTo +proto.rShiftTo = bnpRShiftTo +proto.subTo = bnpSubTo +proto.multiplyTo = bnpMultiplyTo +proto.squareTo = bnpSquareTo +proto.divRemTo = bnpDivRemTo +proto.invDigit = bnpInvDigit +proto.isEven = bnpIsEven +proto.exp = bnpExp +// public +proto.toString = bnToString +proto.negate = bnNegate +proto.abs = bnAbs +proto.compareTo = bnCompareTo +proto.bitLength = bnBitLength +proto.byteLength = bnByteLength +proto.mod = bnMod +proto.modPowInt = bnModPowInt -var levels = { - 'debug': 0, - 'info': 1, - 'log': 2, - 'warn': 3, - 'error': 4, - 'fatal': 5 -}; +// (public) +function bnClone() { + var r = new BigInteger() + this.copyTo(r) + return r +} -_.each(levels, function(level, levelName) { - Logger.prototype[levelName] = function() { - if (level >= levels[this.level]) { +// (public) return value as integer +function bnIntValue() { + if (this.s < 0) { + if (this.t == 1) return this[0] - this.DV + else if (this.t == 0) return -1 + } else if (this.t == 1) return this[0] + else if (this.t == 0) return 0 + // assumes 16 < DB < 32 + return ((this[1] & ((1 << (32 - this.DB)) - 1)) << this.DB) | this[0] +} - if (Error.stackTraceLimit && this.level == 'debug') { - var old = Error.stackTraceLimit; - Error.stackTraceLimit = 2; - var stack; +// (public) return value as byte +function bnByteValue() { + return (this.t == 0) ? this.s : (this[0] << 24) >> 24 +} - // this hack is to be compatible with IE11 - try { - anerror(); - } catch (e) { - stack = e.stack; - } - var lines = stack.split('\n'); - var caller = lines[2]; - caller = ':' + caller.substr(6); - Error.stackTraceLimit = old; +// (public) return value as short (assumes DB>=16) +function bnShortValue() { + return (this.t == 0) ? this.s : (this[0] << 16) >> 16 +} + +// (protected) return x s.t. r^x < DV +function bnpChunkSize(r) { + return Math.floor(Math.LN2 * this.DB / Math.log(r)) +} + +// (public) 0 if this == 0, 1 if this > 0 +function bnSigNum() { + if (this.s < 0) return -1 + else if (this.t <= 0 || (this.t == 1 && this[0] <= 0)) return 0 + else return 1 +} + +// (protected) convert to radix string +function bnpToRadix(b) { + if (b == null) b = 10 + if (this.signum() == 0 || b < 2 || b > 36) return "0" + var cs = this.chunkSize(b) + var a = Math.pow(b, cs) + var d = nbv(a), + y = new BigInteger(), + z = new BigInteger(), + r = "" + this.divRemTo(d, y, z) + while (y.signum() > 0) { + r = (a + z.intValue()) + .toString(b) + .substr(1) + r + y.divRemTo(d, y, z) + } + return z.intValue() + .toString(b) + r +} + +// (protected) convert from radix string +function bnpFromRadix(s, b) { + var self = this + self.fromInt(0) + if (b == null) b = 10 + var cs = self.chunkSize(b) + var d = Math.pow(b, cs), + mi = false, + j = 0, + w = 0 + for (var i = 0; i < s.length; ++i) { + var x = intAt(s, i) + if (x < 0) { + if (s.charAt(i) == "-" && self.signum() == 0) mi = true + continue + } + w = b * w + x + if (++j >= cs) { + self.dMultiply(d) + self.dAddOffset(w, 0) + j = 0 + w = 0 + } + } + if (j > 0) { + self.dMultiply(Math.pow(b, j)) + self.dAddOffset(w, 0) + } + if (mi) BigInteger.ZERO.subTo(self, self) +} + +// (protected) alternate constructor +function bnpFromNumber(a, b, c) { + var self = this + if ("number" == typeof b) { + // new BigInteger(int,int,RNG) + if (a < 2) self.fromInt(1) + else { + self.fromNumber(a, c) + if (!self.testBit(a - 1)) // force MSB set + self.bitwiseTo(BigInteger.ONE.shiftLeft(a - 1), op_or, self) + if (self.isEven()) self.dAddOffset(1, 0); // force odd + while (!self.isProbablePrime(b)) { + self.dAddOffset(2, 0) + if (self.bitLength() > a) self.subTo(BigInteger.ONE.shiftLeft(a - 1), self) } + } + } else { + // new BigInteger(int,RNG) + var x = new Array(), + t = a & 7 + x.length = (a >> 3) + 1 + b.nextBytes(x) + if (t > 0) x[0] &= ((1 << t) - 1) + else x[0] = 0 + self.fromString(x, 256) + } +} - var str = '[' + levelName + (caller || '') + '] ' + arguments[0], - extraArgs, - extraArgs = [].slice.call(arguments, 1); - if (console[levelName]) { - extraArgs.unshift(str); - console[levelName].apply(console, extraArgs); +// (public) convert to bigendian byte array +function bnToByteArray() { + var self = this + var i = self.t, + r = new Array() + r[0] = self.s + var p = self.DB - (i * self.DB) % 8, + d, k = 0 + if (i-- > 0) { + if (p < self.DB && (d = self[i] >> p) != (self.s & self.DM) >> p) + r[k++] = d | (self.s << (self.DB - p)) + while (i >= 0) { + if (p < 8) { + d = (self[i] & ((1 << p) - 1)) << (8 - p) + d |= self[--i] >> (p += self.DB - 8) } else { - if (extraArgs.length) { - str += JSON.stringify(extraArgs); + d = (self[i] >> (p -= 8)) & 0xff + if (p <= 0) { + p += self.DB + --i } - console.log(str); } + if ((d & 0x80) != 0) d |= -256 + if (k === 0 && (self.s & 0x80) != (d & 0x80))++k + if (k > 0 || d != self.s) r[k++] = d } - }; -}); + } + return r +} -/** - * @desc - * Sets the level of a logger. A level can be any bewteen: 'debug', 'info', 'log', - * 'warn', 'error', and 'fatal'. That order matters: if a logger's level is set to - * 'warn', calling level.debug won't have any effect. - * - * @param {number} level - the name of the logging level - */ -Logger.prototype.setLevel = function(level) { - this.level = level; -}; +function bnEquals(a) { + return (this.compareTo(a) == 0) +} -/** - * @class Logger - * @method debug - * @desc Log messages at the debug level. - * @param {*} args - the arguments to be logged. - */ -/** - * @class Logger - * @method info - * @desc Log messages at the info level. - * @param {*} args - the arguments to be logged. - */ -/** - * @class Logger - * @method log - * @desc Log messages at an intermediary level called 'log'. - * @param {*} args - the arguments to be logged. - */ -/** - * @class Logger - * @method warn - * @desc Log messages at the warn level. - * @param {*} args - the arguments to be logged. - */ -/** - * @class Logger - * @method error - * @desc Log messages at the error level. - * @param {*} args - the arguments to be logged. - */ -/** - * @class Logger - * @method fatal - * @desc Log messages at the fatal level. - * @param {*} args - the arguments to be logged. - */ +function bnMin(a) { + return (this.compareTo(a) < 0) ? this : a +} -var logger = new Logger('copay'); -var error = new Error(); -logger.setLevel('info'); -module.exports = logger; +function bnMax(a) { + return (this.compareTo(a) > 0) ? this : a +} -},{"lodash":181}],13:[function(require,module,exports){ -(function (process,Buffer){ -var $ = require('preconditions').singleton(); +// (protected) r = this op a (bitwise) +function bnpBitwiseTo(a, op, r) { + var self = this + var i, f, m = Math.min(a.t, self.t) + for (i = 0; i < m; ++i) r[i] = op(self[i], a[i]) + if (a.t < self.t) { + f = a.s & self.DM + for (i = m; i < self.t; ++i) r[i] = op(self[i], f) + r.t = self.t + } else { + f = self.s & self.DM + for (i = m; i < a.t; ++i) r[i] = op(f, a[i]) + r.t = a.t + } + r.s = op(self.s, a.s) + r.clamp() +} -var Bitcore = require('bitcore-lib'); -var BitcorePayPro = require('bitcore-payment-protocol'); -var PayPro = {}; +// (public) this & a +function op_and(x, y) { + return x & y +} -PayPro._nodeRequest = function(opts, cb) { - opts.agent = false; - var http = opts.httpNode || (opts.proto === 'http' ? require("http") : require("https")); +function bnAnd(a) { + var r = new BigInteger() + this.bitwiseTo(a, op_and, r) + return r +} - var fn = opts.method == 'POST' ? 'post' : 'get'; +// (public) this | a +function op_or(x, y) { + return x | y +} - http[fn](opts, function(res) { - if (res.statusCode != 200) - return cb('HTTP Request Error'); +function bnOr(a) { + var r = new BigInteger() + this.bitwiseTo(a, op_or, r) + return r +} - var data = []; // List of Buffer objects - res.on("data", function(chunk) { - data.push(chunk); // Append Buffer object - }); - res.on("end", function() { - data = Buffer.concat(data); // Make one large Buffer of it - return cb(null, data); - }); - }); -}; +// (public) this ^ a +function op_xor(x, y) { + return x ^ y +} -PayPro._browserRequest = function(opts, cb) { - var method = (opts.method || 'GET').toUpperCase(); - var url = opts.url; - var req = opts; +function bnXor(a) { + var r = new BigInteger() + this.bitwiseTo(a, op_xor, r) + return r +} - req.headers = req.headers || {}; - req.body = req.body || req.data || ''; +// (public) this & ~a +function op_andnot(x, y) { + return x & ~y +} - var xhr = opts.xhr || new XMLHttpRequest(); - xhr.open(method, url, true); +function bnAndNot(a) { + var r = new BigInteger() + this.bitwiseTo(a, op_andnot, r) + return r +} - Object.keys(req.headers).forEach(function(key) { - var val = req.headers[key]; - if (key === 'Content-Length') return; - if (key === 'Content-Transfer-Encoding') return; - xhr.setRequestHeader(key, val); - }); - xhr.responseType = 'arraybuffer'; +// (public) ~this +function bnNot() { + var r = new BigInteger() + for (var i = 0; i < this.t; ++i) r[i] = this.DM & ~this[i] + r.t = this.t + r.s = ~this.s + return r +} - xhr.onload = function(event) { - var response = xhr.response; - return cb(null, new Uint8Array(response)); - }; +// (public) this << n +function bnShiftLeft(n) { + var r = new BigInteger() + if (n < 0) this.rShiftTo(-n, r) + else this.lShiftTo(n, r) + return r +} - xhr.onerror = function(event) { - var status; - if (xhr.status === 0 || !xhr.statusText) { - status = 'HTTP Request Error'; - } else { - status = xhr.statusText; - } - return cb(status); - }; +// (public) this >> n +function bnShiftRight(n) { + var r = new BigInteger() + if (n < 0) this.lShiftTo(-n, r) + else this.rShiftTo(n, r) + return r +} - if (req.body) { - xhr.send(req.body); - } else { - xhr.send(null); +// return index of lowest 1-bit in x, x < 2^31 +function lbit(x) { + if (x == 0) return -1 + var r = 0 + if ((x & 0xffff) == 0) { + x >>= 16 + r += 16 } -}; + if ((x & 0xff) == 0) { + x >>= 8 + r += 8 + } + if ((x & 0xf) == 0) { + x >>= 4 + r += 4 + } + if ((x & 3) == 0) { + x >>= 2 + r += 2 + } + if ((x & 1) == 0)++r + return r +} -var getHttp = function(opts) { - var match = opts.url.match(/^((http[s]?):\/)?\/?([^:\/\s]+)((\/\w+)*\/)([\w\-\.]+[^#?\s]+)(.*)?(#[\w\-]+)?$/); +// (public) returns index of lowest 1-bit (or -1 if none) +function bnGetLowestSetBit() { + for (var i = 0; i < this.t; ++i) + if (this[i] != 0) return i * this.DB + lbit(this[i]) + if (this.s < 0) return this.t * this.DB + return -1 +} - opts.proto = RegExp.$2; - opts.host = RegExp.$3; - opts.path = RegExp.$4 + RegExp.$6; - if (opts.http) return opts.http; +// return number of 1 bits in x +function cbit(x) { + var r = 0 + while (x != 0) { + x &= x - 1 + ++r + } + return r +} - var env = opts.env; - if (!env) - env = (process && !process.browser) ? 'node' : 'browser'; +// (public) return number of set bits +function bnBitCount() { + var r = 0, + x = this.s & this.DM + for (var i = 0; i < this.t; ++i) r += cbit(this[i] ^ x) + return r +} - return (env == "node") ? PayPro._nodeRequest : http = PayPro._browserRequest;; -}; +// (public) true iff nth bit is set +function bnTestBit(n) { + var j = Math.floor(n / this.DB) + if (j >= this.t) return (this.s != 0) + return ((this[j] & (1 << (n % this.DB))) != 0) +} -PayPro.get = function(opts, cb) { - $.checkArgument(opts && opts.url); +// (protected) this op (1< 1) - return cb(new Error('Payment Protocol Error: Requests with more that one output are not supported')) - - var output = outputs[0]; - - var amount = output.get('amount').toNumber(); - var network = pd.get('network') == 'test' ? 'testnet' : 'livenet'; +// (public) this | (1<>= self.DB + } + if (a.t < self.t) { + c += a.s + while (i < self.t) { + c += self[i] + r[i++] = c & self.DM + c >>= self.DB } - - var ok = verified.verified; - var caName; - - if (verified.isChain) { - ok = ok && verified.chainVerified; + c += self.s + } else { + c += self.s + while (i < a.t) { + c += a[i] + r[i++] = c & self.DM + c >>= self.DB } + c += a.s + } + r.s = (c < 0) ? -1 : 0 + if (c > 0) r[i++] = c + else if (c < -1) r[i++] = self.DV + c + r.t = i + r.clamp() +} - return cb(null, { - verified: ok, - caTrusted: verified.caTrusted, - caName: verified.caName, - selfSigned: verified.selfSigned, - expires: pd.get('expires'), - memo: pd.get('memo'), - time: pd.get('time'), - merchant_data: md, - toAddress: addr.toString(), - amount: amount, - network: network, - domain: opts.host, - url: opts.url, - }); - }); -}; +// (public) this + a +function bnAdd(a) { + var r = new BigInteger() + this.addTo(a, r) + return r +} +// (public) this - a +function bnSubtract(a) { + var r = new BigInteger() + this.subTo(a, r) + return r +} -PayPro._getPayProRefundOutputs = function(addrStr, amount) { - amount = amount.toString(10); +// (public) this * a +function bnMultiply(a) { + var r = new BigInteger() + this.multiplyTo(a, r) + return r +} - var output = new BitcorePayPro.Output(); - var addr = new Bitcore.Address(addrStr); - var hash = addr.toObject().hash; +// (public) this^2 +function bnSquare() { + var r = new BigInteger() + this.squareTo(r) + return r +} - var s = new Bitcore.Script(); - s.add(Bitcore.Opcode.OP_HASH160) - .add(new Buffer(hash, 'hex')) - .add(Bitcore.Opcode.OP_EQUAL); +// (public) this / a +function bnDivide(a) { + var r = new BigInteger() + this.divRemTo(a, r, null) + return r +} - // console.log('PayPro refund address set to:', addrStr,s); - output.set('script', s.toBuffer()); - output.set('amount', amount); - return [output]; -}; +// (public) this % a +function bnRemainder(a) { + var r = new BigInteger() + this.divRemTo(a, null, r) + return r +} +// (public) [this/a,this%a] +function bnDivideAndRemainder(a) { + var q = new BigInteger(), + r = new BigInteger() + this.divRemTo(a, q, r) + return new Array(q, r) +} -PayPro._createPayment = function(merchant_data, rawTx, refundAddr, amountSat) { - var pay = new BitcorePayPro(); - pay = pay.makePayment(); +// (protected) this *= n, this >= 0, 1 < n < DV +function bnpDMultiply(n) { + this[this.t] = this.am(0, n - 1, this, 0, 0, this.t) + ++this.t + this.clamp() +} - if (merchant_data) { - merchant_data = new Buffer(merchant_data); - pay.set('merchant_data', merchant_data); +// (protected) this += n << w words, this >= 0 +function bnpDAddOffset(n, w) { + if (n == 0) return + while (this.t <= w) this[this.t++] = 0 + this[w] += n + while (this[w] >= this.DV) { + this[w] -= this.DV + if (++w >= this.t) this[this.t++] = 0 + ++this[w] } +} - var txBuf = new Buffer(rawTx, 'hex'); - pay.set('transactions', [txBuf]); - - var refund_outputs = this._getPayProRefundOutputs(refundAddr, amountSat); - if (refund_outputs) - pay.set('refund_to', refund_outputs); - - // Unused for now - // options.memo = ''; - // pay.set('memo', options.memo); - - pay = pay.serialize(); - var buf = new ArrayBuffer(pay.length); - var view = new Uint8Array(buf); - for (var i = 0; i < pay.length; i++) { - view[i] = pay[i]; - } +// A "null" reducer +function NullExp() {} - return view; -}; +function nNop(x) { + return x +} -PayPro.send = function(opts, cb) { - $.checkArgument(opts.merchant_data) - .checkArgument(opts.url) - .checkArgument(opts.rawTx) - .checkArgument(opts.refundAddr) - .checkArgument(opts.amountSat); +function nMulTo(x, y, r) { + x.multiplyTo(y, r) +} - var payment = PayPro._createPayment(opts.merchant_data, opts.rawTx, opts.refundAddr, opts.amountSat); +function nSqrTo(x, r) { + x.squareTo(r) +} - var http = getHttp(opts); - opts.method = 'POST'; - opts.headers = opts.headers || { - 'Accept': BitcorePayPro.PAYMENT_ACK_CONTENT_TYPE, - 'Content-Type': BitcorePayPro.PAYMENT_CONTENT_TYPE, - // 'Content-Type': 'application/octet-stream', - }; - opts.body = payment; +NullExp.prototype.convert = nNop +NullExp.prototype.revert = nNop +NullExp.prototype.mulTo = nMulTo +NullExp.prototype.sqrTo = nSqrTo - http(opts, function(err, rawData) { - if (err) return cb(err); - var memo; - if (rawData) { - try { - var data = BitcorePayPro.PaymentACK.decode(rawData); - var pp = new BitcorePayPro(); - var ack = pp.makePaymentACK(data); - memo = ack.get('memo'); - } catch (e) {}; - } - return cb(null, rawData, memo); - }); -}; +// (public) this^e +function bnPow(e) { + return this.exp(e, new NullExp()) +} -module.exports = PayPro; +// (protected) r = lower n words of "this * a", a.t <= n +// "this" should be the larger one if appropriate. +function bnpMultiplyLowerTo(a, n, r) { + var i = Math.min(this.t + a.t, n) + r.s = 0; // assumes a,this >= 0 + r.t = i + while (i > 0) r[--i] = 0 + var j + for (j = r.t - this.t; i < j; ++i) r[i + this.t] = this.am(0, a[i], r, i, 0, this.t) + for (j = Math.min(a.t, n); i < j; ++i) this.am(0, a[i], r, i, 0, n - i) + r.clamp() +} -}).call(this,require('_process'),require("buffer").Buffer) -},{"_process":499,"bitcore-lib":65,"bitcore-payment-protocol":153,"buffer":299,"http":490,"https":494,"preconditions":182}],14:[function(require,module,exports){ -/** @namespace Verifier */ +// (protected) r = "this * a" without lower n words, n > 0 +// "this" should be the larger one if appropriate. +function bnpMultiplyUpperTo(a, n, r) { + --n + var i = r.t = this.t + a.t - n + r.s = 0; // assumes a,this >= 0 + while (--i >= 0) r[i] = 0 + for (i = Math.max(n - this.t, 0); i < a.t; ++i) + r[this.t + i - n] = this.am(n - i, a[i], r, 0, 0, this.t + i - n) + r.clamp() + r.drShiftTo(1, r) +} -var $ = require('preconditions').singleton(); -var _ = require('lodash'); +// Barrett modular reduction +function Barrett(m) { + // setup Barrett + this.r2 = new BigInteger() + this.q3 = new BigInteger() + BigInteger.ONE.dlShiftTo(2 * m.t, this.r2) + this.mu = this.r2.divide(m) + this.m = m +} -var Bitcore = require('bitcore-lib'); +function barrettConvert(x) { + if (x.s < 0 || x.t > 2 * this.m.t) return x.mod(this.m) + else if (x.compareTo(this.m) < 0) return x + else { + var r = new BigInteger() + x.copyTo(r) + this.reduce(r) + return r + } +} -var Common = require('./common'); -var Utils = Common.Utils; +function barrettRevert(x) { + return x +} -var log = require('./log'); +// x = x mod m (HAC 14.42) +function barrettReduce(x) { + var self = this + x.drShiftTo(self.m.t - 1, self.r2) + if (x.t > self.m.t + 1) { + x.t = self.m.t + 1 + x.clamp() + } + self.mu.multiplyUpperTo(self.r2, self.m.t + 1, self.q3) + self.m.multiplyLowerTo(self.q3, self.m.t + 1, self.r2) + while (x.compareTo(self.r2) < 0) x.dAddOffset(1, self.m.t + 1) + x.subTo(self.r2, x) + while (x.compareTo(self.m) >= 0) x.subTo(self.m, x) +} -/** - * @desc Verifier constructor. Checks data given by the server - * - * @constructor - */ -function Verifier(opts) {}; +// r = x^2 mod m; x != r +function barrettSqrTo(x, r) { + x.squareTo(r) + this.reduce(r) +} -/** - * Check address - * - * @param {Function} credentials - * @param {String} address - * @returns {Boolean} true or false - */ -Verifier.checkAddress = function(credentials, address) { - $.checkState(credentials.isComplete()); +// r = x*y mod m; x,y != r +function barrettMulTo(x, y, r) { + x.multiplyTo(y, r) + this.reduce(r) +} - var local = Utils.deriveAddress(address.type || credentials.addressType, credentials.publicKeyRing, address.path, credentials.m, credentials.network); - return (local.address == address.address && - _.difference(local.publicKeys, address.publicKeys).length === 0); -}; +Barrett.prototype.convert = barrettConvert +Barrett.prototype.revert = barrettRevert +Barrett.prototype.reduce = barrettReduce +Barrett.prototype.mulTo = barrettMulTo +Barrett.prototype.sqrTo = barrettSqrTo -/** - * Check copayers - * - * @param {Function} credentials - * @param {Array} copayers - * @returns {Boolean} true or false - */ -Verifier.checkCopayers = function(credentials, copayers) { - $.checkState(credentials.walletPrivKey); - var walletPubKey = Bitcore.PrivateKey.fromString(credentials.walletPrivKey).toPublicKey().toString(); +// (public) this^e % m (HAC 14.85) +function bnModPow(e, m) { + var i = e.bitLength(), + k, r = nbv(1), + z + if (i <= 0) return r + else if (i < 18) k = 1 + else if (i < 48) k = 3 + else if (i < 144) k = 4 + else if (i < 768) k = 5 + else k = 6 + if (i < 8) + z = new Classic(m) + else if (m.isEven()) + z = new Barrett(m) + else + z = new Montgomery(m) - if (copayers.length != credentials.n) { - log.error('Missing public keys in server response'); - return false; + // precomputation + var g = new Array(), + n = 3, + k1 = k - 1, + km = (1 << k) - 1 + g[1] = z.convert(this) + if (k > 1) { + var g2 = new BigInteger() + z.sqrTo(g[1], g2) + while (n <= km) { + g[n] = new BigInteger() + z.mulTo(g2, g[n - 2], g[n]) + n += 2 + } } - // Repeated xpub kes? - var uniq = []; - var error; - _.each(copayers, function(copayer) { - if (error) return; - - if (uniq[copayers.xPubKey]++) { - log.error('Repeated public keys in server response'); - error = true; + var j = e.t - 1, + w, is1 = true, + r2 = new BigInteger(), + t + i = nbits(e[j]) - 1 + while (j >= 0) { + if (i >= k1) w = (e[j] >> (i - k1)) & km + else { + w = (e[j] & ((1 << (i + 1)) - 1)) << (k1 - i) + if (j > 0) w |= e[j - 1] >> (this.DB + i - k1) } - // Not signed pub keys - if (!copayer.name || !copayer.xPubKey || !copayer.requestPubKey || !copayer.signature) { - log.error('Missing copayer fields in server response'); - error = true; + n = k + while ((w & 1) == 0) { + w >>= 1 + --n + } + if ((i -= n) < 0) { + i += this.DB + --j + } + if (is1) { // ret == 1, don't bother squaring or multiplying it + g[w].copyTo(r) + is1 = false } else { - var hash = Utils.getCopayerHash(copayer.name, copayer.xPubKey, copayer.requestPubKey); - if (!Utils.verifyMessage(hash, copayer.signature, walletPubKey)) { - log.error('Invalid signatures in server response'); - error = true; + while (n > 1) { + z.sqrTo(r, r2) + z.sqrTo(r2, r) + n -= 2 + } + if (n > 0) z.sqrTo(r, r2) + else { + t = r + r = r2 + r2 = t } + z.mulTo(r2, g[w], r) } - }); - - if (error) return false; - if (!_.contains(_.pluck(copayers, 'xPubKey'), credentials.xPubKey)) { - log.error('Server response does not contains our public keys') - return false; + while (j >= 0 && (e[j] & (1 << i)) == 0) { + z.sqrTo(r, r2) + t = r + r = r2 + r2 = t + if (--i < 0) { + i = this.DB - 1 + --j + } + } } - return true; -}; - -Verifier.checkTxProposalBody = function(credentials, txp) { - $.checkArgument(txp.creatorId); - $.checkState(credentials.isComplete()); - - var creatorKeys = _.find(credentials.publicKeyRing, function(item) { - if (Utils.xPubToCopayerId(item.xPubKey) === txp.creatorId) return true; - }); - - if (!creatorKeys) return false; - var creatorSigningPubKey; - - // If the txp using a selfsigned pub key? - if (txp.proposalSignaturePubKey) { - - // Verify it... - if (!Utils.verifyRequestPubKey(txp.proposalSignaturePubKey, txp.proposalSignaturePubKeySig, creatorKeys.xPubKey)) - return false; + return z.revert(r) +} - creatorSigningPubKey = txp.proposalSignaturePubKey; - } else { - creatorSigningPubKey = creatorKeys.requestPubKey; +// (public) gcd(this,a) (HAC 14.54) +function bnGCD(a) { + var x = (this.s < 0) ? this.negate() : this.clone() + var y = (a.s < 0) ? a.negate() : a.clone() + if (x.compareTo(y) < 0) { + var t = x + x = y + y = t } - if (!creatorSigningPubKey) return false; - - var hash; - if (txp.outputs) { - var outputs = _.map(txp.outputs, function(o) { - return { - toAddress: o.toAddress, - amount: o.amount, - message: o.encryptedMessage || o.message || null - }; - }); - var proposalHeader = { - outputs: outputs, - message: txp.encryptedMessage || txp.message || null, - payProUrl: txp.payProUrl || null, - }; - hash = Utils.getProposalHash(proposalHeader); - } else { - hash = Utils.getProposalHash(txp.toAddress, txp.amount, txp.encryptedMessage || txp.message || null, txp.payProUrl || null); + var i = x.getLowestSetBit(), + g = y.getLowestSetBit() + if (g < 0) return x + if (i < g) g = i + if (g > 0) { + x.rShiftTo(g, x) + y.rShiftTo(g, y) } - log.debug('Regenerating & verifying tx proposal hash -> Hash: ', hash, ' Signature: ', txp.proposalSignature); - - if (!Utils.verifyMessage(hash, txp.proposalSignature, creatorSigningPubKey)) - return false; - - if (!Verifier.checkAddress(credentials, txp.changeAddress)) - return false; - - return true; -}; - - - -/** - * Check transaction proposal - * - * @param {Function} credentials - * @param {Object} txp - * @param {Object} Optional: paypro - * @param {Boolean} isLegit - */ -Verifier.checkTxProposal = function(credentials, txp, opts) { - opts = opts || {}; - - if (!this.checkTxProposalBody(credentials, txp)) - return false; - - if (opts.paypro) { - if (txp.toAddress != opts.paypro.toAddress || txp.amount != opts.paypro.amount) - return false; + while (x.signum() > 0) { + if ((i = x.getLowestSetBit()) > 0) x.rShiftTo(i, x) + if ((i = y.getLowestSetBit()) > 0) y.rShiftTo(i, y) + if (x.compareTo(y) >= 0) { + x.subTo(y, x) + x.rShiftTo(1, x) + } else { + y.subTo(x, y) + y.rShiftTo(1, y) + } } + if (g > 0) y.lShiftTo(g, y) + return y +} - return true; -}; +// (protected) this % n, n < 2^26 +function bnpModInt(n) { + if (n <= 0) return 0 + var d = this.DV % n, + r = (this.s < 0) ? n - 1 : 0 + if (this.t > 0) + if (d == 0) r = this[0] % n + else + for (var i = this.t - 1; i >= 0; --i) r = (d * r + this[i]) % n + return r +} -module.exports = Verifier; +// (public) 1/this % m (HAC 14.61) +function bnModInverse(m) { + var ac = m.isEven() + if (this.signum() === 0) throw new Error('division by zero') + if ((this.isEven() && ac) || m.signum() == 0) return BigInteger.ZERO + var u = m.clone(), + v = this.clone() + var a = nbv(1), + b = nbv(0), + c = nbv(0), + d = nbv(1) + while (u.signum() != 0) { + while (u.isEven()) { + u.rShiftTo(1, u) + if (ac) { + if (!a.isEven() || !b.isEven()) { + a.addTo(this, a) + b.subTo(m, b) + } + a.rShiftTo(1, a) + } else if (!b.isEven()) b.subTo(m, b) + b.rShiftTo(1, b) + } + while (v.isEven()) { + v.rShiftTo(1, v) + if (ac) { + if (!c.isEven() || !d.isEven()) { + c.addTo(this, c) + d.subTo(m, d) + } + c.rShiftTo(1, c) + } else if (!d.isEven()) d.subTo(m, d) + d.rShiftTo(1, d) + } + if (u.compareTo(v) >= 0) { + u.subTo(v, u) + if (ac) a.subTo(c, a) + b.subTo(d, b) + } else { + v.subTo(u, v) + if (ac) c.subTo(a, c) + d.subTo(b, d) + } + } + if (v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO + while (d.compareTo(m) >= 0) d.subTo(m, d) + while (d.signum() < 0) d.addTo(m, d) + return d +} -},{"./common":6,"./log":12,"bitcore-lib":65,"lodash":181,"preconditions":182}],15:[function(require,module,exports){ -(function (process){ -/*! - * async - * https://github.com/caolan/async - * - * Copyright 2010-2014 Caolan McMahon - * Released under the MIT license - */ -/*jshint onevar: false, indent:4 */ -/*global setImmediate: false, setTimeout: false, console: false */ -(function () { +var lowprimes = [ + 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, + 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, + 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, + 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, + 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, + 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, + 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, + 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, + 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, + 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, + 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997 +] - var async = {}; +var lplim = (1 << 26) / lowprimes[lowprimes.length - 1] - // global on the server, window in the browser - var root, previous_async; +// (public) test primality with certainty >= 1-.5^t +function bnIsProbablePrime(t) { + var i, x = this.abs() + if (x.t == 1 && x[0] <= lowprimes[lowprimes.length - 1]) { + for (i = 0; i < lowprimes.length; ++i) + if (x[0] == lowprimes[i]) return true + return false + } + if (x.isEven()) return false + i = 1 + while (i < lowprimes.length) { + var m = lowprimes[i], + j = i + 1 + while (j < lowprimes.length && m < lplim) m *= lowprimes[j++] + m = x.modInt(m) + while (i < j) if (m % lowprimes[i++] == 0) return false + } + return x.millerRabin(t) +} - root = this; - if (root != null) { - previous_async = root.async; +// (protected) true if probably prime (HAC 4.24, Miller-Rabin) +function bnpMillerRabin(t) { + var n1 = this.subtract(BigInteger.ONE) + var k = n1.getLowestSetBit() + if (k <= 0) return false + var r = n1.shiftRight(k) + t = (t + 1) >> 1 + if (t > lowprimes.length) t = lowprimes.length + var a = new BigInteger(null) + var j, bases = [] + for (var i = 0; i < t; ++i) { + for (;;) { + j = lowprimes[Math.floor(Math.random() * lowprimes.length)] + if (bases.indexOf(j) == -1) break + } + bases.push(j) + a.fromInt(j) + var y = a.modPow(r, this) + if (y.compareTo(BigInteger.ONE) != 0 && y.compareTo(n1) != 0) { + var j = 1 + while (j++ < k && y.compareTo(n1) != 0) { + y = y.modPowInt(2, this) + if (y.compareTo(BigInteger.ONE) == 0) return false + } + if (y.compareTo(n1) != 0) return false } + } + return true +} - async.noConflict = function () { - root.async = previous_async; - return async; - }; +// protected +proto.chunkSize = bnpChunkSize +proto.toRadix = bnpToRadix +proto.fromRadix = bnpFromRadix +proto.fromNumber = bnpFromNumber +proto.bitwiseTo = bnpBitwiseTo +proto.changeBit = bnpChangeBit +proto.addTo = bnpAddTo +proto.dMultiply = bnpDMultiply +proto.dAddOffset = bnpDAddOffset +proto.multiplyLowerTo = bnpMultiplyLowerTo +proto.multiplyUpperTo = bnpMultiplyUpperTo +proto.modInt = bnpModInt +proto.millerRabin = bnpMillerRabin - function only_once(fn) { - var called = false; - return function() { - if (called) throw new Error("Callback was already called."); - called = true; - fn.apply(root, arguments); - } - } +// public +proto.clone = bnClone +proto.intValue = bnIntValue +proto.byteValue = bnByteValue +proto.shortValue = bnShortValue +proto.signum = bnSigNum +proto.toByteArray = bnToByteArray +proto.equals = bnEquals +proto.min = bnMin +proto.max = bnMax +proto.and = bnAnd +proto.or = bnOr +proto.xor = bnXor +proto.andNot = bnAndNot +proto.not = bnNot +proto.shiftLeft = bnShiftLeft +proto.shiftRight = bnShiftRight +proto.getLowestSetBit = bnGetLowestSetBit +proto.bitCount = bnBitCount +proto.testBit = bnTestBit +proto.setBit = bnSetBit +proto.clearBit = bnClearBit +proto.flipBit = bnFlipBit +proto.add = bnAdd +proto.subtract = bnSubtract +proto.multiply = bnMultiply +proto.divide = bnDivide +proto.remainder = bnRemainder +proto.divideAndRemainder = bnDivideAndRemainder +proto.modPow = bnModPow +proto.modInverse = bnModInverse +proto.pow = bnPow +proto.gcd = bnGCD +proto.isProbablePrime = bnIsProbablePrime - //// cross-browser compatiblity functions //// +// JSBN-specific extension +proto.square = bnSquare - var _toString = Object.prototype.toString; +// constants +BigInteger.ZERO = nbv(0) +BigInteger.ONE = nbv(1) +BigInteger.valueOf = nbv - var _isArray = Array.isArray || function (obj) { - return _toString.call(obj) === '[object Array]'; - }; +module.exports = BigInteger - var _each = function (arr, iterator) { - for (var i = 0; i < arr.length; i += 1) { - iterator(arr[i], i, arr); - } - }; +},{"../package.json":22}],20:[function(require,module,exports){ +(function (Buffer){ +// FIXME: Kind of a weird way to throw exceptions, consider removing +var assert = require('assert') +var BigInteger = require('./bigi') - var _map = function (arr, iterator) { - if (arr.map) { - return arr.map(iterator); - } - var results = []; - _each(arr, function (x, i, a) { - results.push(iterator(x, i, a)); - }); - return results; - }; +/** + * Turns a byte array into a big integer. + * + * This function will interpret a byte array as a big integer in big + * endian notation. + */ +BigInteger.fromByteArrayUnsigned = function(byteArray) { + // BigInteger expects a DER integer conformant byte array + if (byteArray[0] & 0x80) { + return new BigInteger([0].concat(byteArray)) + } - var _reduce = function (arr, iterator, memo) { - if (arr.reduce) { - return arr.reduce(iterator, memo); - } - _each(arr, function (x, i, a) { - memo = iterator(memo, x, i, a); - }); - return memo; - }; + return new BigInteger(byteArray) +} - var _keys = function (obj) { - if (Object.keys) { - return Object.keys(obj); - } - var keys = []; - for (var k in obj) { - if (obj.hasOwnProperty(k)) { - keys.push(k); - } - } - return keys; - }; +/** + * Returns a byte array representation of the big integer. + * + * This returns the absolute of the contained value in big endian + * form. A value of zero results in an empty array. + */ +BigInteger.prototype.toByteArrayUnsigned = function() { + var byteArray = this.toByteArray() + return byteArray[0] === 0 ? byteArray.slice(1) : byteArray +} - //// exported async module functions //// +BigInteger.fromDERInteger = function(byteArray) { + return new BigInteger(byteArray) +} - //// nextTick implementation with browser-compatible fallback //// - if (typeof process === 'undefined' || !(process.nextTick)) { - if (typeof setImmediate === 'function') { - async.nextTick = function (fn) { - // not a direct alias for IE10 compatibility - setImmediate(fn); - }; - async.setImmediate = async.nextTick; - } - else { - async.nextTick = function (fn) { - setTimeout(fn, 0); - }; - async.setImmediate = async.nextTick; - } - } - else { - async.nextTick = process.nextTick; - if (typeof setImmediate !== 'undefined') { - async.setImmediate = function (fn) { - // not a direct alias for IE10 compatibility - setImmediate(fn); - }; - } - else { - async.setImmediate = async.nextTick; - } - } +/* + * Converts BigInteger to a DER integer representation. + * + * The format for this value uses the most significant bit as a sign + * bit. If the most significant bit is already set and the integer is + * positive, a 0x00 is prepended. + * + * Examples: + * + * 0 => 0x00 + * 1 => 0x01 + * -1 => 0xff + * 127 => 0x7f + * -127 => 0x81 + * 128 => 0x0080 + * -128 => 0x80 + * 255 => 0x00ff + * -255 => 0xff01 + * 16300 => 0x3fac + * -16300 => 0xc054 + * 62300 => 0x00f35c + * -62300 => 0xff0ca4 +*/ +BigInteger.prototype.toDERInteger = BigInteger.prototype.toByteArray - async.each = function (arr, iterator, callback) { - callback = callback || function () {}; - if (!arr.length) { - return callback(); - } - var completed = 0; - _each(arr, function (x) { - iterator(x, only_once(done) ); - }); - function done(err) { - if (err) { - callback(err); - callback = function () {}; - } - else { - completed += 1; - if (completed >= arr.length) { - callback(); - } - } - } - }; - async.forEach = async.each; +BigInteger.fromBuffer = function(buffer) { + // BigInteger expects a DER integer conformant byte array + if (buffer[0] & 0x80) { + var byteArray = Array.prototype.slice.call(buffer) - async.eachSeries = function (arr, iterator, callback) { - callback = callback || function () {}; - if (!arr.length) { - return callback(); - } - var completed = 0; - var iterate = function () { - iterator(arr[completed], function (err) { - if (err) { - callback(err); - callback = function () {}; - } - else { - completed += 1; - if (completed >= arr.length) { - callback(); - } - else { - iterate(); - } - } - }); - }; - iterate(); - }; - async.forEachSeries = async.eachSeries; + return new BigInteger([0].concat(byteArray)) + } - async.eachLimit = function (arr, limit, iterator, callback) { - var fn = _eachLimit(limit); - fn.apply(null, [arr, iterator, callback]); - }; - async.forEachLimit = async.eachLimit; + return new BigInteger(buffer) +} - var _eachLimit = function (limit) { +BigInteger.fromHex = function(hex) { + if (hex === '') return BigInteger.ZERO - return function (arr, iterator, callback) { - callback = callback || function () {}; - if (!arr.length || limit <= 0) { - return callback(); - } - var completed = 0; - var started = 0; - var running = 0; + assert.equal(hex, hex.match(/^[A-Fa-f0-9]+/), 'Invalid hex string') + assert.equal(hex.length % 2, 0, 'Incomplete hex') + return new BigInteger(hex, 16) +} - (function replenish () { - if (completed >= arr.length) { - return callback(); - } +BigInteger.prototype.toBuffer = function(size) { + var byteArray = this.toByteArrayUnsigned() + var zeros = [] - while (running < limit && started < arr.length) { - started += 1; - running += 1; - iterator(arr[started - 1], function (err) { - if (err) { - callback(err); - callback = function () {}; - } - else { - completed += 1; - running -= 1; - if (completed >= arr.length) { - callback(); - } - else { - replenish(); - } - } - }); - } - })(); - }; - }; + var padding = size - byteArray.length + while (zeros.length < padding) zeros.push(0) + return new Buffer(zeros.concat(byteArray)) +} - var doParallel = function (fn) { - return function () { - var args = Array.prototype.slice.call(arguments); - return fn.apply(null, [async.each].concat(args)); - }; - }; - var doParallelLimit = function(limit, fn) { - return function () { - var args = Array.prototype.slice.call(arguments); - return fn.apply(null, [_eachLimit(limit)].concat(args)); - }; - }; - var doSeries = function (fn) { - return function () { - var args = Array.prototype.slice.call(arguments); - return fn.apply(null, [async.eachSeries].concat(args)); - }; - }; +BigInteger.prototype.toHex = function(size) { + return this.toBuffer(size).toString('hex') +} +}).call(this,require("buffer").Buffer) +},{"./bigi":19,"assert":17,"buffer":174}],21:[function(require,module,exports){ +var BigInteger = require('./bigi') - var _asyncMap = function (eachfn, arr, iterator, callback) { - arr = _map(arr, function (x, i) { - return {index: i, value: x}; - }); - if (!callback) { - eachfn(arr, function (x, callback) { - iterator(x.value, function (err) { - callback(err); - }); - }); - } else { - var results = []; - eachfn(arr, function (x, callback) { - iterator(x.value, function (err, v) { - results[x.index] = v; - callback(err); - }); - }, function (err) { - callback(err, results); - }); - } - }; - async.map = doParallel(_asyncMap); - async.mapSeries = doSeries(_asyncMap); - async.mapLimit = function (arr, limit, iterator, callback) { - return _mapLimit(limit)(arr, iterator, callback); - }; +//addons +require('./convert') - var _mapLimit = function(limit) { - return doParallelLimit(limit, _asyncMap); - }; +module.exports = BigInteger +},{"./bigi":19,"./convert":20}],22:[function(require,module,exports){ +module.exports={ + "_args": [ + [ + { + "raw": "bigi@^1.2.0", + "scope": null, + "escapedName": "bigi", + "name": "bigi", + "rawSpec": "^1.2.0", + "spec": ">=1.2.0 <2.0.0", + "type": "range" + }, + "/Volumes/Backup/Github/angular-bitcore-wallet-client/node_modules/bip38" + ] + ], + "_from": "bigi@>=1.2.0 <2.0.0", + "_id": "bigi@1.4.2", + "_inCache": true, + "_installable": true, + "_location": "/bigi", + "_nodeVersion": "6.1.0", + "_npmOperationalInternal": { + "host": "packages-12-west.internal.npmjs.com", + "tmp": "tmp/bigi-1.4.2.tgz_1469584192413_0.6801238611806184" + }, + "_npmUser": { + "name": "jprichardson", + "email": "jprichardson@gmail.com" + }, + "_npmVersion": "3.8.6", + "_phantomChildren": {}, + "_requested": { + "raw": "bigi@^1.2.0", + "scope": null, + "escapedName": "bigi", + "name": "bigi", + "rawSpec": "^1.2.0", + "spec": ">=1.2.0 <2.0.0", + "type": "range" + }, + "_requiredBy": [ + "/bip38", + "/ecurve" + ], + "_resolved": "https://registry.npmjs.org/bigi/-/bigi-1.4.2.tgz", + "_shasum": "9c665a95f88b8b08fc05cfd731f561859d725825", + "_shrinkwrap": null, + "_spec": "bigi@^1.2.0", + "_where": "/Volumes/Backup/Github/angular-bitcore-wallet-client/node_modules/bip38", + "bugs": { + "url": "https://github.com/cryptocoinjs/bigi/issues" + }, + "dependencies": {}, + "description": "Big integers.", + "devDependencies": { + "coveralls": "^2.11.2", + "istanbul": "^0.3.5", + "jshint": "^2.5.1", + "mocha": "^2.1.0", + "mochify": "^2.1.0" + }, + "directories": {}, + "dist": { + "shasum": "9c665a95f88b8b08fc05cfd731f561859d725825", + "tarball": "https://registry.npmjs.org/bigi/-/bigi-1.4.2.tgz" + }, + "gitHead": "c25308081c896ff84702303722bf5ecd8b3f78e3", + "homepage": "https://github.com/cryptocoinjs/bigi#readme", + "keywords": [ + "cryptography", + "math", + "bitcoin", + "arbitrary", + "precision", + "arithmetic", + "big", + "integer", + "int", + "number", + "biginteger", + "bigint", + "bignumber", + "decimal", + "float" + ], + "main": "./lib/index.js", + "maintainers": [ + { + "name": "midnightlightning", + "email": "boydb@midnightdesign.ws" + }, + { + "name": "sidazhang", + "email": "sidazhang89@gmail.com" + }, + { + "name": "nadav", + "email": "npm@shesek.info" + }, + { + "name": "jprichardson", + "email": "jprichardson@gmail.com" + } + ], + "name": "bigi", + "optionalDependencies": {}, + "readme": "ERROR: No README data found!", + "repository": { + "url": "git+https://github.com/cryptocoinjs/bigi.git", + "type": "git" + }, + "scripts": { + "browser-test": "mochify --wd -R spec", + "coverage": "istanbul cover ./node_modules/.bin/_mocha -- --reporter list test/*.js", + "coveralls": "npm run-script coverage && node ./node_modules/.bin/coveralls < coverage/lcov.info", + "jshint": "jshint --config jshint.json lib/*.js ; true", + "test": "_mocha -- test/*.js", + "unit": "mocha" + }, + "testling": { + "files": "test/*.js", + "harness": "mocha", + "browsers": [ + "ie/9..latest", + "firefox/latest", + "chrome/latest", + "safari/6.0..latest", + "iphone/6.0..latest", + "android-browser/4.2..latest" + ] + }, + "version": "1.4.2" +} - // reduce only has a series version, as doing reduce in parallel won't - // work in many situations. - async.reduce = function (arr, memo, iterator, callback) { - async.eachSeries(arr, function (x, callback) { - iterator(memo, x, function (err, v) { - memo = v; - callback(err); - }); - }, function (err) { - callback(err, memo); - }); - }; - // inject alias - async.inject = async.reduce; - // foldl alias - async.foldl = async.reduce; +},{}],23:[function(require,module,exports){ +(function (Buffer){ +var aes = require('browserify-aes') +var assert = require('assert') +var createHash = require('create-hash') +var cs = require('coinstring') +var scrypt = require('scryptsy') +var xor = require('buffer-xor') - async.reduceRight = function (arr, memo, iterator, callback) { - var reversed = _map(arr, function (x) { - return x; - }).reverse(); - async.reduce(reversed, memo, iterator, callback); - }; - // foldr alias - async.foldr = async.reduceRight; +var ecurve = require('ecurve') +var curve = ecurve.getCurveByName('secp256k1') - var _filter = function (eachfn, arr, iterator, callback) { - var results = []; - arr = _map(arr, function (x, i) { - return {index: i, value: x}; - }); - eachfn(arr, function (x, callback) { - iterator(x.value, function (v) { - if (v) { - results.push(x); - } - callback(); - }); - }, function (err) { - callback(_map(results.sort(function (a, b) { - return a.index - b.index; - }), function (x) { - return x.value; - })); - }); - }; - async.filter = doParallel(_filter); - async.filterSeries = doSeries(_filter); - // select alias - async.select = async.filter; - async.selectSeries = async.filterSeries; +var BigInteger = require('bigi') - var _reject = function (eachfn, arr, iterator, callback) { - var results = []; - arr = _map(arr, function (x, i) { - return {index: i, value: x}; - }); - eachfn(arr, function (x, callback) { - iterator(x.value, function (v) { - if (!v) { - results.push(x); - } - callback(); - }); - }, function (err) { - callback(_map(results.sort(function (a, b) { - return a.index - b.index; - }), function (x) { - return x.value; - })); - }); - }; - async.reject = doParallel(_reject); - async.rejectSeries = doSeries(_reject); +// SHA256(SHA256(buffer)) +function sha256x2 (buffer) { + buffer = createHash('sha256').update(buffer).digest() + return createHash('sha256').update(buffer).digest() +} - var _detect = function (eachfn, arr, iterator, main_callback) { - eachfn(arr, function (x, callback) { - iterator(x, function (result) { - if (result) { - main_callback(x); - main_callback = function () {}; - } - else { - callback(); - } - }); - }, function (err) { - main_callback(); - }); - }; - async.detect = doParallel(_detect); - async.detectSeries = doSeries(_detect); +function Bip38 (versions) { + if (!(this instanceof Bip38)) return new Bip38() - async.some = function (arr, iterator, main_callback) { - async.each(arr, function (x, callback) { - iterator(x, function (v) { - if (v) { - main_callback(true); - main_callback = function () {}; - } - callback(); - }); - }, function (err) { - main_callback(false); - }); - }; - // any alias - async.any = async.some; + // default to Bitcoin WIF versions + this.versions = versions || { private: 0x80 } - async.every = function (arr, iterator, main_callback) { - async.each(arr, function (x, callback) { - iterator(x, function (v) { - if (!v) { - main_callback(false); - main_callback = function () {}; - } - callback(); - }); - }, function (err) { - main_callback(true); - }); - }; - // all alias - async.all = async.every; + // BIP38 recommended + this.scryptParams = { + N: 16384, + r: 8, + p: 8 + } +} - async.sortBy = function (arr, iterator, callback) { - async.map(arr, function (x, callback) { - iterator(x, function (err, criteria) { - if (err) { - callback(err); - } - else { - callback(null, {value: x, criteria: criteria}); - } - }); - }, function (err, results) { - if (err) { - return callback(err); - } - else { - var fn = function (left, right) { - var a = left.criteria, b = right.criteria; - return a < b ? -1 : a > b ? 1 : 0; - }; - callback(null, _map(results.sort(fn), function (x) { - return x.value; - })); - } - }); - }; +Bip38.prototype.encryptRaw = function (buffer, compressed, passphrase, saltAddress, progressCallback) { + assert.equal(buffer.length, 32, 'Invalid private key length') - async.auto = function (tasks, callback) { - callback = callback || function () {}; - var keys = _keys(tasks); - var remainingTasks = keys.length - if (!remainingTasks) { - return callback(); - } + var secret = new Buffer(passphrase, 'utf8') + var salt = sha256x2(saltAddress).slice(0, 4) - var results = {}; + var N = this.scryptParams.N + var r = this.scryptParams.r + var p = this.scryptParams.p - var listeners = []; - var addListener = function (fn) { - listeners.unshift(fn); - }; - var removeListener = function (fn) { - for (var i = 0; i < listeners.length; i += 1) { - if (listeners[i] === fn) { - listeners.splice(i, 1); - return; - } - } - }; - var taskComplete = function () { - remainingTasks-- - _each(listeners.slice(0), function (fn) { - fn(); - }); - }; + var scryptBuf = scrypt(secret, salt, N, r, p, 64, progressCallback) + var derivedHalf1 = scryptBuf.slice(0, 32) + var derivedHalf2 = scryptBuf.slice(32, 64) - addListener(function () { - if (!remainingTasks) { - var theCallback = callback; - // prevent final callback from calling itself if it errors - callback = function () {}; + var xorBuf = xor(buffer, derivedHalf1) + var cipher = aes.createCipheriv('aes-256-ecb', derivedHalf2, new Buffer(0)) + cipher.setAutoPadding(false) + cipher.end(xorBuf) - theCallback(null, results); - } - }); + var cipherText = cipher.read() - _each(keys, function (k) { - var task = _isArray(tasks[k]) ? tasks[k]: [tasks[k]]; - var taskCallback = function (err) { - var args = Array.prototype.slice.call(arguments, 1); - if (args.length <= 1) { - args = args[0]; - } - if (err) { - var safeResults = {}; - _each(_keys(results), function(rkey) { - safeResults[rkey] = results[rkey]; - }); - safeResults[k] = args; - callback(err, safeResults); - // stop subsequent errors hitting callback multiple times - callback = function () {}; - } - else { - results[k] = args; - async.setImmediate(taskComplete); - } - }; - var requires = task.slice(0, Math.abs(task.length - 1)) || []; - var ready = function () { - return _reduce(requires, function (a, x) { - return (a && results.hasOwnProperty(x)); - }, true) && !results.hasOwnProperty(k); - }; - if (ready()) { - task[task.length - 1](taskCallback, results); - } - else { - var listener = function () { - if (ready()) { - removeListener(listener); - task[task.length - 1](taskCallback, results); - } - }; - addListener(listener); - } - }); - }; + // 0x01 + 0x42 + flagByte + salt + cipherText + var flagByte = compressed ? 0xe0 : 0xc0 + var prefix = new Buffer(3) + prefix.writeUInt8(0x01, 0) + prefix.writeUInt8(0x42, 1) + prefix.writeUInt8(flagByte, 2) - async.retry = function(times, task, callback) { - var DEFAULT_TIMES = 5; - var attempts = []; - // Use defaults if times not passed - if (typeof times === 'function') { - callback = task; - task = times; - times = DEFAULT_TIMES; - } - // Make sure times is a number - times = parseInt(times, 10) || DEFAULT_TIMES; - var wrappedTask = function(wrappedCallback, wrappedResults) { - var retryAttempt = function(task, finalAttempt) { - return function(seriesCallback) { - task(function(err, result){ - seriesCallback(!err || finalAttempt, {err: err, result: result}); - }, wrappedResults); - }; - }; - while (times) { - attempts.push(retryAttempt(task, !(times-=1))); - } - async.series(attempts, function(done, data){ - data = data[data.length - 1]; - (wrappedCallback || callback)(data.err, data.result); - }); - } - // If a callback is passed, run this as a controll flow - return callback ? wrappedTask() : wrappedTask - }; + return Buffer.concat([prefix, salt, cipherText]) +} - async.waterfall = function (tasks, callback) { - callback = callback || function () {}; - if (!_isArray(tasks)) { - var err = new Error('First argument to waterfall must be an array of functions'); - return callback(err); - } - if (!tasks.length) { - return callback(); - } - var wrapIterator = function (iterator) { - return function (err) { - if (err) { - callback.apply(null, arguments); - callback = function () {}; - } - else { - var args = Array.prototype.slice.call(arguments, 1); - var next = iterator.next(); - if (next) { - args.push(wrapIterator(next)); - } - else { - args.push(callback); - } - async.setImmediate(function () { - iterator.apply(null, args); - }); - } - }; - }; - wrapIterator(async.iterator(tasks))(); - }; +Bip38.prototype.encrypt = function (wif, passphrase, saltAddress, progressCallback) { + var d = cs.decode(wif).slice(1) + var compressed = (d.length === 33) && (d[32] === 0x01) - var _parallel = function(eachfn, tasks, callback) { - callback = callback || function () {}; - if (_isArray(tasks)) { - eachfn.map(tasks, function (fn, callback) { - if (fn) { - fn(function (err) { - var args = Array.prototype.slice.call(arguments, 1); - if (args.length <= 1) { - args = args[0]; - } - callback.call(null, err, args); - }); - } - }, callback); - } - else { - var results = {}; - eachfn.each(_keys(tasks), function (k, callback) { - tasks[k](function (err) { - var args = Array.prototype.slice.call(arguments, 1); - if (args.length <= 1) { - args = args[0]; - } - results[k] = args; - callback(err); - }); - }, function (err) { - callback(err, results); - }); - } - }; + // truncate the compression flag + if (compressed) { + d = d.slice(0, -1) + } - async.parallel = function (tasks, callback) { - _parallel({ map: async.map, each: async.each }, tasks, callback); - }; + return cs.encode(this.encryptRaw(d, compressed, passphrase, saltAddress, progressCallback)) +} - async.parallelLimit = function(tasks, limit, callback) { - _parallel({ map: _mapLimit(limit), each: _eachLimit(limit) }, tasks, callback); - }; +// some of the techniques borrowed from: https://github.com/pointbiz/bitaddress.org +// todo: (optimization) init buffer in advance, and use copy instead of concat +Bip38.prototype.decryptRaw = function (encData, passphrase, progressCallback) { + // 39 bytes: 2 bytes prefix, 37 bytes payload + assert.equal(encData.length, 39, 'Invalid BIP38 data length') - async.series = function (tasks, callback) { - callback = callback || function () {}; - if (_isArray(tasks)) { - async.mapSeries(tasks, function (fn, callback) { - if (fn) { - fn(function (err) { - var args = Array.prototype.slice.call(arguments, 1); - if (args.length <= 1) { - args = args[0]; - } - callback.call(null, err, args); - }); - } - }, callback); - } - else { - var results = {}; - async.eachSeries(_keys(tasks), function (k, callback) { - tasks[k](function (err) { - var args = Array.prototype.slice.call(arguments, 1); - if (args.length <= 1) { - args = args[0]; - } - results[k] = args; - callback(err); - }); - }, function (err) { - callback(err, results); - }); - } - }; + // first byte is always 0x01 + assert.equal(encData.readUInt8(0), 0x01, 'Invalid BIP38 prefix') - async.iterator = function (tasks) { - var makeCallback = function (index) { - var fn = function () { - if (tasks.length) { - tasks[index].apply(null, arguments); - } - return fn.next(); - }; - fn.next = function () { - return (index < tasks.length - 1) ? makeCallback(index + 1): null; - }; - return fn; - }; - return makeCallback(0); - }; + // check if BIP38 EC multiply + var type = encData.readUInt8(1) + if (type === 0x43) { + return this.decryptECMult(encData, passphrase, progressCallback) + } - async.apply = function (fn) { - var args = Array.prototype.slice.call(arguments, 1); - return function () { - return fn.apply( - null, args.concat(Array.prototype.slice.call(arguments)) - ); - }; - }; + passphrase = new Buffer(passphrase, 'utf8') - var _concat = function (eachfn, arr, fn, callback) { - var r = []; - eachfn(arr, function (x, cb) { - fn(x, function (err, y) { - r = r.concat(y || []); - cb(err); - }); - }, function (err) { - callback(err, r); - }); - }; - async.concat = doParallel(_concat); - async.concatSeries = doSeries(_concat); + assert.equal(type, 0x42, 'Invalid BIP38 type') + var flagByte = encData.readUInt8(2) + var compressed = flagByte === 0xe0 - async.whilst = function (test, iterator, callback) { - if (test()) { - iterator(function (err) { - if (err) { - return callback(err); - } - async.whilst(test, iterator, callback); - }); - } - else { - callback(); - } - }; + if (!compressed) { + assert.equal(flagByte, 0xc0, 'Invalid BIP38 compression flag') + } - async.doWhilst = function (iterator, test, callback) { - iterator(function (err) { - if (err) { - return callback(err); - } - var args = Array.prototype.slice.call(arguments, 1); - if (test.apply(null, args)) { - async.doWhilst(iterator, test, callback); - } - else { - callback(); - } - }); - }; + var N = this.scryptParams.N + var r = this.scryptParams.r + var p = this.scryptParams.p - async.until = function (test, iterator, callback) { - if (!test()) { - iterator(function (err) { - if (err) { - return callback(err); - } - async.until(test, iterator, callback); - }); - } - else { - callback(); - } - }; + var addresshash = encData.slice(3, 7) + var scryptBuf = scrypt(passphrase, addresshash, N, r, p, 64, progressCallback) + var derivedHalf1 = scryptBuf.slice(0, 32) + var derivedHalf2 = scryptBuf.slice(32, 64) - async.doUntil = function (iterator, test, callback) { - iterator(function (err) { - if (err) { - return callback(err); - } - var args = Array.prototype.slice.call(arguments, 1); - if (!test.apply(null, args)) { - async.doUntil(iterator, test, callback); - } - else { - callback(); - } - }); - }; + var privKeyBuf = encData.slice(7, 7 + 32) + var decipher = aes.createDecipheriv('aes-256-ecb', derivedHalf2, new Buffer(0)) + decipher.setAutoPadding(false) + decipher.end(privKeyBuf) - async.queue = function (worker, concurrency) { - if (concurrency === undefined) { - concurrency = 1; - } - function _insert(q, data, pos, callback) { - if (!q.started){ - q.started = true; - } - if (!_isArray(data)) { - data = [data]; - } - if(data.length == 0) { - // call drain immediately if there are no tasks - return async.setImmediate(function() { - if (q.drain) { - q.drain(); - } - }); - } - _each(data, function(task) { - var item = { - data: task, - callback: typeof callback === 'function' ? callback : null - }; + var plainText = decipher.read() + var privateKey = xor(plainText, derivedHalf1) - if (pos) { - q.tasks.unshift(item); - } else { - q.tasks.push(item); - } + return { + privateKey: privateKey, + compressed: compressed + } +} - if (q.saturated && q.tasks.length === q.concurrency) { - q.saturated(); - } - async.setImmediate(q.process); - }); - } +Bip38.prototype.decrypt = function (encryptedBase58, passphrase, progressCallback) { + var encBuffer = cs.decode(encryptedBase58) + var decrypt = this.decryptRaw(encBuffer, passphrase, progressCallback) - var workers = 0; - var q = { - tasks: [], - concurrency: concurrency, - saturated: null, - empty: null, - drain: null, - started: false, - paused: false, - push: function (data, callback) { - _insert(q, data, false, callback); - }, - kill: function () { - q.drain = null; - q.tasks = []; - }, - unshift: function (data, callback) { - _insert(q, data, true, callback); - }, - process: function () { - if (!q.paused && workers < q.concurrency && q.tasks.length) { - var task = q.tasks.shift(); - if (q.empty && q.tasks.length === 0) { - q.empty(); - } - workers += 1; - var next = function () { - workers -= 1; - if (task.callback) { - task.callback.apply(task, arguments); - } - if (q.drain && q.tasks.length + workers === 0) { - q.drain(); - } - q.process(); - }; - var cb = only_once(next); - worker(task.data, cb); - } - }, - length: function () { - return q.tasks.length; - }, - running: function () { - return workers; - }, - idle: function() { - return q.tasks.length + workers === 0; - }, - pause: function () { - if (q.paused === true) { return; } - q.paused = true; - }, - resume: function () { - if (q.paused === false) { return; } - q.paused = false; - // Need to call q.process once per concurrent - // worker to preserve full concurrency after pause - for (var w = 1; w <= q.concurrency; w++) { - async.setImmediate(q.process); - } - } - }; - return q; - }; + // Convert to WIF + var bufferLen = decrypt.compressed ? 34 : 33 + var buffer = new Buffer(bufferLen) - async.priorityQueue = function (worker, concurrency) { + buffer.writeUInt8(this.versions.private, 0) + decrypt.privateKey.copy(buffer, 1) - function _compareTasks(a, b){ - return a.priority - b.priority; - }; + if (decrypt.compressed) { + buffer.writeUInt8(0x01, 33) + } - function _binarySearch(sequence, item, compare) { - var beg = -1, - end = sequence.length - 1; - while (beg < end) { - var mid = beg + ((end - beg + 1) >>> 1); - if (compare(item, sequence[mid]) >= 0) { - beg = mid; - } else { - end = mid - 1; - } - } - return beg; - } + return cs.encode(buffer) +} - function _insert(q, data, priority, callback) { - if (!q.started){ - q.started = true; - } - if (!_isArray(data)) { - data = [data]; - } - if(data.length == 0) { - // call drain immediately if there are no tasks - return async.setImmediate(function() { - if (q.drain) { - q.drain(); - } - }); - } - _each(data, function(task) { - var item = { - data: task, - priority: priority, - callback: typeof callback === 'function' ? callback : null - }; +Bip38.prototype.decryptECMult = function (encData, passphrase, progressCallback) { + passphrase = new Buffer(passphrase, 'utf8') + encData = encData.slice(1) // FIXME: we can avoid this - q.tasks.splice(_binarySearch(q.tasks, item, _compareTasks) + 1, 0, item); + var compressed = (encData[1] & 0x20) !== 0 + var hasLotSeq = (encData[1] & 0x04) !== 0 - if (q.saturated && q.tasks.length === q.concurrency) { - q.saturated(); - } - async.setImmediate(q.process); - }); - } + assert.equal((encData[1] & 0x24), encData[1], 'Invalid private key.') - // Start with a normal queue - var q = async.queue(worker, concurrency); + var addresshash = encData.slice(2, 6) + var ownerEntropy = encData.slice(6, 14) + var ownerSalt - // Override push to accept second parameter representing priority - q.push = function (data, priority, callback) { - _insert(q, data, priority, callback); - }; + // 4 bytes ownerSalt if 4 bytes lot/sequence + if (hasLotSeq) { + ownerSalt = ownerEntropy.slice(0, 4) - // Remove unshift function - delete q.unshift; + // else, 8 bytes ownerSalt + } else { + ownerSalt = ownerEntropy + } - return q; - }; + var encryptedPart1 = encData.slice(14, 22) // First 8 bytes + var encryptedPart2 = encData.slice(22, 38) // 16 bytes - async.cargo = function (worker, payload) { - var working = false, - tasks = []; + var N = this.scryptParams.N + var r = this.scryptParams.r + var p = this.scryptParams.p + var preFactor = scrypt(passphrase, ownerSalt, N, r, p, 32, progressCallback) - var cargo = { - tasks: tasks, - payload: payload, - saturated: null, - empty: null, - drain: null, - drained: true, - push: function (data, callback) { - if (!_isArray(data)) { - data = [data]; - } - _each(data, function(task) { - tasks.push({ - data: task, - callback: typeof callback === 'function' ? callback : null - }); - cargo.drained = false; - if (cargo.saturated && tasks.length === payload) { - cargo.saturated(); - } - }); - async.setImmediate(cargo.process); - }, - process: function process() { - if (working) return; - if (tasks.length === 0) { - if(cargo.drain && !cargo.drained) cargo.drain(); - cargo.drained = true; - return; - } + var passFactor + if (hasLotSeq) { + var hashTarget = Buffer.concat([preFactor, ownerEntropy]) + passFactor = sha256x2(hashTarget) + } else { + passFactor = preFactor + } - var ts = typeof payload === 'number' - ? tasks.splice(0, payload) - : tasks.splice(0, tasks.length); + var passInt = BigInteger.fromBuffer(passFactor) + var passPoint = curve.G.multiply(passInt).getEncoded(true) - var ds = _map(ts, function (task) { - return task.data; - }); + var seedBPass = scrypt(passPoint, Buffer.concat([addresshash, ownerEntropy]), 1024, 1, 1, 64) + var derivedHalf1 = seedBPass.slice(0, 32) + var derivedHalf2 = seedBPass.slice(32, 64) - if(cargo.empty) cargo.empty(); - working = true; - worker(ds, function () { - working = false; + var decipher = aes.createDecipheriv('aes-256-ecb', derivedHalf2, new Buffer(0)) + decipher.setAutoPadding(false) + decipher.end(encryptedPart2) - var args = arguments; - _each(ts, function (data) { - if (data.callback) { - data.callback.apply(null, args); - } - }); + var decryptedPart2 = decipher.read() + var tmp = xor(decryptedPart2, derivedHalf1.slice(16, 32)) + var seedBPart2 = tmp.slice(8, 16) - process(); - }); - }, - length: function () { - return tasks.length; - }, - running: function () { - return working; - } - }; - return cargo; - }; + var decipher2 = aes.createDecipheriv('aes-256-ecb', derivedHalf2, new Buffer(0)) + decipher2.setAutoPadding(false) + decipher2.write(encryptedPart1) // first 8 bytes + decipher2.end(tmp.slice(0, 8)) // last 8 bytes - var _console_fn = function (name) { - return function (fn) { - var args = Array.prototype.slice.call(arguments, 1); - fn.apply(null, args.concat([function (err) { - var args = Array.prototype.slice.call(arguments, 1); - if (typeof console !== 'undefined') { - if (err) { - if (console.error) { - console.error(err); - } - } - else if (console[name]) { - _each(args, function (x) { - console[name](x); - }); - } - } - }])); - }; - }; - async.log = _console_fn('log'); - async.dir = _console_fn('dir'); - /*async.info = _console_fn('info'); - async.warn = _console_fn('warn'); - async.error = _console_fn('error');*/ + var seedBPart1 = xor(decipher2.read(), derivedHalf1.slice(0, 16)) + var seedB = Buffer.concat([seedBPart1, seedBPart2], 24) + var factorB = sha256x2(seedB) - async.memoize = function (fn, hasher) { - var memo = {}; - var queues = {}; - hasher = hasher || function (x) { - return x; - }; - var memoized = function () { - var args = Array.prototype.slice.call(arguments); - var callback = args.pop(); - var key = hasher.apply(null, args); - if (key in memo) { - async.nextTick(function () { - callback.apply(null, memo[key]); - }); - } - else if (key in queues) { - queues[key].push(callback); - } - else { - queues[key] = [callback]; - fn.apply(null, args.concat([function () { - memo[key] = arguments; - var q = queues[key]; - delete queues[key]; - for (var i = 0, l = q.length; i < l; i++) { - q[i].apply(null, arguments); - } - }])); - } - }; - memoized.memo = memo; - memoized.unmemoized = fn; - return memoized; - }; + // d = passFactor * factorB (mod n) + var d = passInt.multiply(BigInteger.fromBuffer(factorB)).mod(curve.n) - async.unmemoize = function (fn) { - return function () { - return (fn.unmemoized || fn).apply(null, arguments); - }; - }; + return { + privateKey: d.toBuffer(32), + compressed: compressed + } +} - async.times = function (count, iterator, callback) { - var counter = []; - for (var i = 0; i < count; i++) { - counter.push(i); - } - return async.map(counter, iterator, callback); - }; +Bip38.prototype.verify = function (encryptedBase58) { + var decoded + try { + decoded = cs.decode(encryptedBase58) + } catch (e) { + return false + } - async.timesSeries = function (count, iterator, callback) { - var counter = []; - for (var i = 0; i < count; i++) { - counter.push(i); - } - return async.mapSeries(counter, iterator, callback); - }; + if (decoded.length !== 39) return false + if (decoded.readUInt8(0) !== 0x01) return false - async.seq = function (/* functions... */) { - var fns = arguments; - return function () { - var that = this; - var args = Array.prototype.slice.call(arguments); - var callback = args.pop(); - async.reduce(fns, args, function (newargs, fn, cb) { - fn.apply(that, newargs.concat([function () { - var err = arguments[0]; - var nextargs = Array.prototype.slice.call(arguments, 1); - cb(err, nextargs); - }])) - }, - function (err, results) { - callback.apply(that, [err].concat(results)); - }); - }; - }; - - async.compose = function (/* functions... */) { - return async.seq.apply(null, Array.prototype.reverse.call(arguments)); - }; - - var _applyEach = function (eachfn, fns /*args...*/) { - var go = function () { - var that = this; - var args = Array.prototype.slice.call(arguments); - var callback = args.pop(); - return eachfn(fns, function (fn, cb) { - fn.apply(that, args.concat([cb])); - }, - callback); - }; - if (arguments.length > 2) { - var args = Array.prototype.slice.call(arguments, 2); - return go.apply(this, args); - } - else { - return go; - } - }; - async.applyEach = doParallel(_applyEach); - async.applyEachSeries = doSeries(_applyEach); - - async.forever = function (fn, callback) { - function next(err) { - if (err) { - if (callback) { - return callback(err); - } - throw err; - } - fn(next); - } - next(); - }; - - // Node.js - if (typeof module !== 'undefined' && module.exports) { - module.exports = async; - } - // AMD / RequireJS - else if (typeof define !== 'undefined' && define.amd) { - define([], function () { - return async; - }); - } - // included directly via