├── .circleci └── config.yml ├── .coveralls.yml ├── .editorconfig ├── .gitignore ├── Gruntfile.js ├── LICENSE ├── Makefile ├── README.header.md ├── README.md ├── bitcore-wallet-client.min.js ├── bower.json ├── index.js ├── lib ├── api.js ├── common │ ├── constants.js │ ├── defaults.js │ ├── index.js │ └── utils.js ├── credentials.js ├── errors │ ├── index.js │ └── spec.js ├── index.js ├── log.js ├── paypro.js └── verifier.js ├── package-lock.json ├── package.json └── test ├── client.js ├── credentials.js ├── legacyImportData.js ├── log.js ├── paypro.js ├── test-config.js ├── testdata.js └── utils.js /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | # Javascript Node CircleCI 2.0 configuration file 2 | # Check https://circleci.com/docs/2.0/language-javascript/ for more details 3 | version: 2 4 | jobs: 5 | copay: 6 | docker: 7 | - image: circleci/node:8.12.0 8 | - image: circleci/mongo:4.0.4 9 | 10 | working_directory: ~/bws 11 | steps: 12 | - checkout 13 | # Download and cache dependencies 14 | - restore_cache: 15 | keys: 16 | - v1-dependencies-{{ checksum "package.json" }} 17 | # fallback to using the latest cache if no exact match is found 18 | - v1-dependencies- 19 | - run: npm ci 20 | - save_cache: 21 | paths: 22 | - node_modules 23 | key: v1-dependencies-{{ checksum "package.json" }} 24 | - run: npm test 25 | - run: npx codecov 26 | - store_artifacts: 27 | path: ./test 28 | - store_test_results: 29 | path: ./test 30 | 31 | workflows: 32 | version: 2 33 | build_and_test: 34 | jobs: 35 | - copay 36 | -------------------------------------------------------------------------------- /.coveralls.yml: -------------------------------------------------------------------------------- 1 | repo_token: JrJM1SMeS0mtVEmRlgijo9LiovuFjVlLX 2 | 3 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | ; .editorconfig 2 | 3 | root = true 4 | 5 | [**.js] 6 | indent_style = space 7 | indent_size = 2 8 | 9 | [**.css] 10 | indent_style = space 11 | indent_size = 2 12 | 13 | [**.html] 14 | indent_style = space 15 | indent_size = 2 16 | max_char = 78 17 | brace_style = expand 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | *.sw* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 18 | .grunt 19 | 20 | # Compiled binary addons (http://nodejs.org/api/addons.html) 21 | build/Release 22 | 23 | # Dependency directory 24 | # Commenting this out is preferred by some people, see 25 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 26 | node_modules 27 | 28 | # Users Environment Variables 29 | .lock-wscript 30 | 31 | *.swp 32 | out/ 33 | db/* 34 | 35 | docs 36 | 37 | # VIM ignore 38 | [._]*.s[a-w][a-z] 39 | [._]s[a-w][a-z] 40 | *.un~ 41 | Session.vim 42 | .netrwhist 43 | *~ 44 | 45 | # OSX 46 | .DS_Store 47 | .AppleDouble 48 | .LSOverride 49 | 50 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | // Project configuration. 4 | grunt.initConfig({ 5 | pkg: grunt.file.readJSON('package.json') 6 | }); 7 | 8 | // Default task(s). 9 | grunt.registerTask('default', []); 10 | }; 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2015 BitPay 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: cover 2 | 3 | BIN_PATH:=node_modules/.bin/ 4 | 5 | all: bitcore-wallet-client.js 6 | 7 | clean: 8 | rm bitcore-wallet-client.js 9 | 10 | bitcore-wallet-client.js: index.js lib/*.js 11 | ${BIN_PATH}browserify $< > $@ 12 | 13 | cover: 14 | ./node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha -- --reporter spec test 15 | -------------------------------------------------------------------------------- /README.header.md: -------------------------------------------------------------------------------- 1 | # bitcore-wallet-client 2 | 3 | [![NPM Package](https://img.shields.io/npm/v/bitcore-wallet-client.svg?style=flat-square)](https://www.npmjs.org/package/bitcore-wallet-client) 4 | [![Build Status](https://img.shields.io/travis/bitpay/bitcore-wallet-client.svg?branch=master&style=flat-square)](https://travis-ci.org/bitpay/bitcore-wallet-client) 5 | [![Coverage Status](https://coveralls.io/repos/bitpay/bitcore-wallet-client/badge.svg)](https://coveralls.io/r/bitpay/bitcore-wallet-client) 6 | 7 | The *official* client library for [bitcore-wallet-service] (https://github.com/bitpay/bitcore-wallet-service). 8 | 9 | ## Description 10 | 11 | This package communicates with BWS [Bitcore wallet service](https://github.com/bitpay/bitcore-wallet-service) using the REST API. All REST endpoints are wrapped as simple async methods. All relevant responses from BWS are checked independently by the peers, thus the importance of using this library when talking to a third party BWS instance. 12 | 13 | See [Bitcore-wallet] (https://github.com/bitpay/bitcore-wallet) for a simple CLI wallet implementation that relays on BWS and uses bitcore-wallet-client. 14 | 15 | ## Get Started 16 | 17 | You can start using bitcore-wallet-client in any of these two ways: 18 | 19 | * via [Bower](http://bower.io/): by running `bower install bitcore-wallet-client` from your console 20 | * or via [NPM](https://www.npmjs.com/package/bitcore-wallet-client): by running `npm install bitcore-wallet-client` from your console. 21 | 22 | ## Example 23 | 24 | Start your own local [Bitcore wallet service](https://github.com/bitpay/bitcore-wallet-service) instance. In this example we assume you have `bitcore-wallet-service` running on your `localhost:3232`. 25 | 26 | Then create two files `irene.js` and `tomas.js` with the content below: 27 | 28 | **irene.js** 29 | 30 | ``` javascript 31 | var Client = require('bitcore-wallet-client'); 32 | 33 | 34 | var fs = require('fs'); 35 | var BWS_INSTANCE_URL = 'https://bws.bitpay.com/bws/api' 36 | 37 | var client = new Client({ 38 | baseUrl: BWS_INSTANCE_URL, 39 | verbose: false, 40 | }); 41 | 42 | client.createWallet("My Wallet", "Irene", 2, 2, {network: 'testnet'}, function(err, secret) { 43 | if (err) { 44 | console.log('error: ',err); 45 | return 46 | }; 47 | // Handle err 48 | console.log('Wallet Created. Share this secret with your copayers: ' + secret); 49 | fs.writeFileSync('irene.dat', client.export()); 50 | }); 51 | ``` 52 | 53 | **tomas.js** 54 | 55 | ``` javascript 56 | 57 | var Client = require('bitcore-wallet-client'); 58 | 59 | 60 | var fs = require('fs'); 61 | var BWS_INSTANCE_URL = 'https://bws.bitpay.com/bws/api' 62 | 63 | var secret = process.argv[2]; 64 | if (!secret) { 65 | console.log('./tomas.js ') 66 | 67 | process.exit(0); 68 | } 69 | 70 | var client = new Client({ 71 | baseUrl: BWS_INSTANCE_URL, 72 | verbose: false, 73 | }); 74 | 75 | client.joinWallet(secret, "Tomas", {}, function(err, wallet) { 76 | if (err) { 77 | console.log('error: ', err); 78 | return 79 | }; 80 | 81 | console.log('Joined ' + wallet.name + '!'); 82 | fs.writeFileSync('tomas.dat', client.export()); 83 | 84 | 85 | client.openWallet(function(err, ret) { 86 | if (err) { 87 | console.log('error: ', err); 88 | return 89 | }; 90 | console.log('\n\n** Wallet Info', ret); //TODO 91 | 92 | console.log('\n\nCreating first address:', ret); //TODO 93 | if (ret.wallet.status == 'complete') { 94 | client.createAddress({}, function(err,addr){ 95 | if (err) { 96 | console.log('error: ', err); 97 | return; 98 | }; 99 | 100 | console.log('\nReturn:', addr) 101 | }); 102 | } 103 | }); 104 | }); 105 | ``` 106 | 107 | Install `bitcore-wallet-client` before start: 108 | 109 | ``` 110 | npm i bitcore-wallet-client 111 | ``` 112 | 113 | Create a new wallet with the first script: 114 | 115 | ``` 116 | $ node irene.js 117 | info Generating new keys 118 | Wallet Created. Share this secret with your copayers: JbTDjtUkvWS4c3mgAtJf4zKyRGzdQzZacfx2S7gRqPLcbeAWaSDEnazFJF6mKbzBvY1ZRwZCbvT 119 | ``` 120 | 121 | Join to this wallet with generated secret: 122 | 123 | ``` 124 | $ node tomas.js JbTDjtUkvWS4c3mgAtJf4zKyRGzdQzZacfx2S7gRqPLcbeAWaSDEnazFJF6mKbzBvY1ZRwZCbvT 125 | Joined My Wallet! 126 | 127 | Wallet Info: [...] 128 | 129 | Creating first address: 130 | 131 | Return: [...] 132 | 133 | ``` 134 | 135 | Note that the scripts created two files named `irene.dat` and `tomas.dat`. With these files you can get status, generate addresses, create proposals, sign transactions, etc. 136 | 137 | 138 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # bitcore-wallet-client 2 | 3 | 4 | THIS REPO HAVE BEEN MOVED TO BITCORE's MONO REPO. Check: 5 | https://github.com/bitpay/bitcore/tree/master/packages/bitcore-wallet-client 6 | -------------------------------------------------------------------------------- /bitcore-wallet-client.min.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitpay/bitcore-wallet-client/6953ef5f43dd45610d732dea5c026e0b5ff4e79e/bitcore-wallet-client.min.js -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bitcore-wallet-client", 3 | "main": "index.js", 4 | "version": "2.1.1", 5 | "homepage": "https://github.com/bitpay/bitcore-wallet-client", 6 | "authors": ["BitPay Inc"], 7 | "description": "Client for bitcore-wallet-service", 8 | "keywords": [ 9 | "bitcoin", 10 | "copay", 11 | "multisig", 12 | "wallet", 13 | "client", 14 | "bitcore" 15 | ], 16 | "ignore": [ 17 | "**/.*", 18 | "lib", 19 | "node_modules", 20 | "Gruntfile.js", 21 | "Makefile", 22 | "index.js", 23 | "test", 24 | "Makefile" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var Client = require('./lib'); 2 | module.exports = Client; 3 | 4 | // Errors thrown by the library 5 | Client.errors = require('./lib/errors'); 6 | -------------------------------------------------------------------------------- /lib/common/constants.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Constants = {}; 4 | 5 | Constants.SCRIPT_TYPES = { 6 | P2SH: 'P2SH', 7 | P2PKH: 'P2PKH', 8 | }; 9 | Constants.DERIVATION_STRATEGIES = { 10 | BIP44: 'BIP44', 11 | BIP45: 'BIP45', 12 | BIP48: 'BIP48', 13 | }; 14 | 15 | Constants.PATHS = { 16 | REQUEST_KEY: "m/1'/0", 17 | TXPROPOSAL_KEY: "m/1'/1", 18 | REQUEST_KEY_AUTH: "m/2", // relative to BASE 19 | }; 20 | 21 | Constants.BIP45_SHARED_INDEX = 0x80000000 - 1; 22 | 23 | Constants.UNITS = { 24 | btc: { 25 | toSatoshis: 100000000, 26 | full: { 27 | maxDecimals: 8, 28 | minDecimals: 8, 29 | }, 30 | short: { 31 | maxDecimals: 6, 32 | minDecimals: 2, 33 | } 34 | }, 35 | bit: { 36 | toSatoshis: 100, 37 | full: { 38 | maxDecimals: 2, 39 | minDecimals: 2, 40 | }, 41 | short: { 42 | maxDecimals: 0, 43 | minDecimals: 0, 44 | } 45 | }, 46 | }; 47 | 48 | module.exports = Constants; 49 | -------------------------------------------------------------------------------- /lib/common/defaults.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Defaults = {}; 4 | 5 | Defaults.DEFAULT_FEE_PER_KB = 10000; 6 | Defaults.MIN_FEE_PER_KB = 0; 7 | Defaults.MAX_FEE_PER_KB = 1000000; 8 | Defaults.MAX_TX_FEE = 1 * 1e8; 9 | 10 | module.exports = Defaults; 11 | -------------------------------------------------------------------------------- /lib/common/index.js: -------------------------------------------------------------------------------- 1 | var Common = {}; 2 | 3 | Common.Constants = require('./constants'); 4 | Common.Defaults = require('./defaults'); 5 | Common.Utils = require('./utils'); 6 | 7 | module.exports = Common; 8 | -------------------------------------------------------------------------------- /lib/common/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _ = require('lodash'); 4 | var $ = require('preconditions').singleton(); 5 | var sjcl = require('sjcl'); 6 | var Stringify = require('json-stable-stringify'); 7 | 8 | var Bitcore = require('bitcore-lib'); 9 | var Bitcore_ = { 10 | btc: Bitcore, 11 | bch: require('bitcore-lib-cash'), 12 | }; 13 | var PrivateKey = Bitcore.PrivateKey; 14 | var PublicKey = Bitcore.PublicKey; 15 | var crypto = Bitcore.crypto; 16 | var encoding = Bitcore.encoding; 17 | 18 | var Constants = require('./constants'); 19 | var Defaults = require('./defaults'); 20 | 21 | function Utils() {}; 22 | 23 | Utils.SJCL = {}; 24 | 25 | Utils.encryptMessage = function(message, encryptingKey) { 26 | var key = sjcl.codec.base64.toBits(encryptingKey); 27 | return sjcl.encrypt(key, message, _.defaults({ 28 | ks: 128, 29 | iter: 1, 30 | }, Utils.SJCL)); 31 | }; 32 | 33 | // Will throw if it can't decrypt 34 | Utils.decryptMessage = function(cyphertextJson, encryptingKey) { 35 | if (!cyphertextJson) return; 36 | 37 | if (!encryptingKey) 38 | throw 'No key'; 39 | 40 | var key = sjcl.codec.base64.toBits(encryptingKey); 41 | return sjcl.decrypt(key, cyphertextJson); 42 | }; 43 | 44 | 45 | Utils.decryptMessageNoThrow = function(cyphertextJson, encryptingKey) { 46 | function isJsonString(str) { 47 | var r; 48 | try { 49 | r=JSON.parse(str); 50 | } catch (e) { 51 | return false; 52 | } 53 | return r; 54 | } 55 | 56 | if (!encryptingKey) 57 | return ''; 58 | 59 | if (!cyphertextJson) 60 | return ''; 61 | 62 | // no sjcl encrypted json 63 | var r= isJsonString(cyphertextJson); 64 | if (!r|| !r.iv || !r.ct) { 65 | return cyphertextJson; 66 | } 67 | 68 | try { 69 | return Utils.decryptMessage(cyphertextJson, encryptingKey); 70 | } catch (e) { 71 | return ''; 72 | } 73 | }; 74 | 75 | 76 | /* TODO: It would be nice to be compatible with bitcoind signmessage. How 77 | * the hash is calculated there? */ 78 | Utils.hashMessage = function(text) { 79 | $.checkArgument(text); 80 | var buf = new Buffer(text); 81 | var ret = crypto.Hash.sha256sha256(buf); 82 | ret = new Bitcore.encoding.BufferReader(ret).readReverse(); 83 | return ret; 84 | }; 85 | 86 | 87 | Utils.signMessage = function(text, privKey) { 88 | $.checkArgument(text); 89 | var priv = new PrivateKey(privKey); 90 | var hash = Utils.hashMessage(text); 91 | return crypto.ECDSA.sign(hash, priv, 'little').toString(); 92 | }; 93 | 94 | 95 | Utils.verifyMessage = function(text, signature, pubKey) { 96 | $.checkArgument(text); 97 | $.checkArgument(pubKey); 98 | 99 | if (!signature) 100 | return false; 101 | 102 | var pub = new PublicKey(pubKey); 103 | var hash = Utils.hashMessage(text); 104 | 105 | try { 106 | var sig = new crypto.Signature.fromString(signature); 107 | return crypto.ECDSA.verify(hash, sig, pub, 'little'); 108 | } catch (e) { 109 | return false; 110 | } 111 | }; 112 | 113 | Utils.privateKeyToAESKey = function(privKey) { 114 | $.checkArgument(privKey && _.isString(privKey)); 115 | $.checkArgument(Bitcore.PrivateKey.isValid(privKey), 'The private key received is invalid'); 116 | var pk = Bitcore.PrivateKey.fromString(privKey); 117 | return Bitcore.crypto.Hash.sha256(pk.toBuffer()).slice(0, 16).toString('base64'); 118 | }; 119 | 120 | Utils.getCopayerHash = function(name, xPubKey, requestPubKey) { 121 | return [name, xPubKey, requestPubKey].join('|'); 122 | }; 123 | 124 | Utils.getProposalHash = function(proposalHeader) { 125 | function getOldHash(toAddress, amount, message, payProUrl) { 126 | return [toAddress, amount, (message || ''), (payProUrl || '')].join('|'); 127 | }; 128 | 129 | // For backwards compatibility 130 | if (arguments.length > 1) { 131 | return getOldHash.apply(this, arguments); 132 | } 133 | 134 | return Stringify(proposalHeader); 135 | }; 136 | 137 | Utils.deriveAddress = function(scriptType, publicKeyRing, path, m, network, coin) { 138 | $.checkArgument(_.includes(_.values(Constants.SCRIPT_TYPES), scriptType)); 139 | 140 | coin = coin || 'btc'; 141 | var bitcore = Bitcore_[coin]; 142 | var publicKeys = _.map(publicKeyRing, function(item) { 143 | var xpub = new bitcore.HDPublicKey(item.xPubKey); 144 | return xpub.deriveChild(path).publicKey; 145 | }); 146 | 147 | var bitcoreAddress; 148 | switch (scriptType) { 149 | case Constants.SCRIPT_TYPES.P2SH: 150 | bitcoreAddress = bitcore.Address.createMultisig(publicKeys, m, network); 151 | break; 152 | case Constants.SCRIPT_TYPES.P2PKH: 153 | $.checkState(_.isArray(publicKeys) && publicKeys.length == 1); 154 | bitcoreAddress = bitcore.Address.fromPublicKey(publicKeys[0], network); 155 | break; 156 | } 157 | 158 | return { 159 | address: coin == 'bch' ? bitcoreAddress.toLegacyAddress() : bitcoreAddress.toString(), 160 | path: path, 161 | publicKeys: _.invokeMap(publicKeys, 'toString'), 162 | }; 163 | }; 164 | 165 | Utils.xPubToCopayerId = function(coin, xpub) { 166 | var str = coin == 'btc' ? xpub : coin + xpub; 167 | var hash = sjcl.hash.sha256.hash(str); 168 | return sjcl.codec.hex.fromBits(hash); 169 | }; 170 | 171 | Utils.signRequestPubKey = function(requestPubKey, xPrivKey) { 172 | var priv = new Bitcore.HDPrivateKey(xPrivKey).deriveChild(Constants.PATHS.REQUEST_KEY_AUTH).privateKey; 173 | return Utils.signMessage(requestPubKey, priv); 174 | }; 175 | 176 | Utils.verifyRequestPubKey = function(requestPubKey, signature, xPubKey) { 177 | var pub = (new Bitcore.HDPublicKey(xPubKey)).deriveChild(Constants.PATHS.REQUEST_KEY_AUTH).publicKey; 178 | return Utils.verifyMessage(requestPubKey, signature, pub.toString()); 179 | }; 180 | 181 | Utils.formatAmount = function(satoshis, unit, opts) { 182 | $.shouldBeNumber(satoshis); 183 | $.checkArgument(_.includes(_.keys(Constants.UNITS), unit)); 184 | 185 | function clipDecimals(number, decimals) { 186 | var x = number.toString().split('.'); 187 | var d = (x[1] || '0').substring(0, decimals); 188 | return parseFloat(x[0] + '.' + d); 189 | }; 190 | 191 | function addSeparators(nStr, thousands, decimal, minDecimals) { 192 | nStr = nStr.replace('.', decimal); 193 | var x = nStr.split(decimal); 194 | var x0 = x[0]; 195 | var x1 = x[1]; 196 | 197 | x1 = _.dropRightWhile(x1, function(n, i) { 198 | return n == '0' && i >= minDecimals; 199 | }).join(''); 200 | var x2 = x.length > 1 ? decimal + x1 : ''; 201 | 202 | x0 = x0.replace(/\B(?=(\d{3})+(?!\d))/g, thousands); 203 | return x0 + x2; 204 | }; 205 | 206 | opts = opts || {}; 207 | 208 | var u = Constants.UNITS[unit]; 209 | var precision = opts.fullPrecision ? 'full' : 'short'; 210 | var amount = clipDecimals((satoshis / u.toSatoshis), u[precision].maxDecimals).toFixed(u[precision].maxDecimals); 211 | return addSeparators(amount, opts.thousandsSeparator || ',', opts.decimalSeparator || '.', u[precision].minDecimals); 212 | }; 213 | 214 | Utils.buildTx = function(txp) { 215 | var coin = txp.coin || 'btc'; 216 | 217 | var bitcore = Bitcore_[coin]; 218 | 219 | var t = new bitcore.Transaction(); 220 | 221 | $.checkState(_.includes(_.values(Constants.SCRIPT_TYPES), txp.addressType)); 222 | 223 | switch (txp.addressType) { 224 | case Constants.SCRIPT_TYPES.P2SH: 225 | _.each(txp.inputs, function(i) { 226 | t.from(i, i.publicKeys, txp.requiredSignatures); 227 | }); 228 | break; 229 | case Constants.SCRIPT_TYPES.P2PKH: 230 | t.from(txp.inputs); 231 | break; 232 | } 233 | 234 | if (txp.toAddress && txp.amount && !txp.outputs) { 235 | t.to(txp.toAddress, txp.amount); 236 | } else if (txp.outputs) { 237 | _.each(txp.outputs, function(o) { 238 | $.checkState(o.script || o.toAddress, 'Output should have either toAddress or script specified'); 239 | if (o.script) { 240 | t.addOutput(new bitcore.Transaction.Output({ 241 | script: o.script, 242 | satoshis: o.amount 243 | })); 244 | } else { 245 | t.to(o.toAddress, o.amount); 246 | } 247 | }); 248 | } 249 | 250 | t.fee(txp.fee); 251 | t.change(txp.changeAddress.address); 252 | 253 | // Shuffle outputs for improved privacy 254 | if (t.outputs.length > 1) { 255 | var outputOrder = _.reject(txp.outputOrder, function(order) { 256 | return order >= t.outputs.length; 257 | }); 258 | $.checkState(t.outputs.length == outputOrder.length); 259 | t.sortOutputs(function(outputs) { 260 | return _.map(outputOrder, function(i) { 261 | return outputs[i]; 262 | }); 263 | }); 264 | } 265 | 266 | // Validate inputs vs outputs independently of Bitcore 267 | var totalInputs = _.reduce(txp.inputs, function(memo, i) { 268 | return +i.satoshis + memo; 269 | }, 0); 270 | var totalOutputs = _.reduce(t.outputs, function(memo, o) { 271 | return +o.satoshis + memo; 272 | }, 0); 273 | 274 | $.checkState(totalInputs - totalOutputs >= 0); 275 | $.checkState(totalInputs - totalOutputs <= Defaults.MAX_TX_FEE); 276 | 277 | return t; 278 | }; 279 | 280 | 281 | module.exports = Utils; 282 | -------------------------------------------------------------------------------- /lib/credentials.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var $ = require('preconditions').singleton(); 4 | var _ = require('lodash'); 5 | 6 | var Bitcore = require('bitcore-lib'); 7 | var Mnemonic = require('bitcore-mnemonic'); 8 | var sjcl = require('sjcl'); 9 | 10 | var Common = require('./common'); 11 | var Constants = Common.Constants; 12 | var Utils = Common.Utils; 13 | 14 | var FIELDS = [ 15 | 'coin', 16 | 'network', 17 | 'xPrivKey', 18 | 'xPrivKeyEncrypted', 19 | 'xPubKey', 20 | 'requestPrivKey', 21 | 'requestPubKey', 22 | 'copayerId', 23 | 'publicKeyRing', 24 | 'walletId', 25 | 'walletName', 26 | 'm', 27 | 'n', 28 | 'walletPrivKey', 29 | 'personalEncryptingKey', 30 | 'sharedEncryptingKey', 31 | 'copayerName', 32 | 'externalSource', 33 | 'mnemonic', 34 | 'mnemonicEncrypted', 35 | 'entropySource', 36 | 'mnemonicHasPassphrase', 37 | 'derivationStrategy', 38 | 'account', 39 | 'compliantDerivation', 40 | 'addressType', 41 | 'hwInfo', 42 | 'entropySourcePath', 43 | ]; 44 | 45 | function Credentials() { 46 | this.version = '1.0.0'; 47 | this.derivationStrategy = Constants.DERIVATION_STRATEGIES.BIP44; 48 | this.account = 0; 49 | }; 50 | 51 | function _checkCoin(coin) { 52 | if (!_.includes(['btc', 'bch'], coin)) throw new Error('Invalid coin'); 53 | }; 54 | 55 | function _checkNetwork(network) { 56 | if (!_.includes(['livenet', 'testnet'], network)) throw new Error('Invalid network'); 57 | }; 58 | 59 | Credentials.create = function(coin, network) { 60 | _checkCoin(coin); 61 | _checkNetwork(network); 62 | 63 | var x = new Credentials(); 64 | 65 | x.coin = coin; 66 | x.network = network; 67 | x.xPrivKey = (new Bitcore.HDPrivateKey(network)).toString(); 68 | x.compliantDerivation = true; 69 | x._expand(); 70 | return x; 71 | }; 72 | 73 | var wordsForLang = { 74 | 'en': Mnemonic.Words.ENGLISH, 75 | 'es': Mnemonic.Words.SPANISH, 76 | 'ja': Mnemonic.Words.JAPANESE, 77 | 'zh': Mnemonic.Words.CHINESE, 78 | 'fr': Mnemonic.Words.FRENCH, 79 | 'it': Mnemonic.Words.ITALIAN, 80 | }; 81 | 82 | Credentials.createWithMnemonic = function(coin, network, passphrase, language, account, opts) { 83 | _checkCoin(coin); 84 | _checkNetwork(network); 85 | if (!wordsForLang[language]) throw new Error('Unsupported language'); 86 | $.shouldBeNumber(account); 87 | 88 | opts = opts || {}; 89 | 90 | var m = new Mnemonic(wordsForLang[language]); 91 | while (!Mnemonic.isValid(m.toString())) { 92 | m = new Mnemonic(wordsForLang[language]) 93 | }; 94 | var x = new Credentials(); 95 | 96 | x.coin = coin; 97 | x.network = network; 98 | x.account = account; 99 | x.xPrivKey = m.toHDPrivateKey(passphrase, network).toString(); 100 | x.compliantDerivation = true; 101 | x._expand(); 102 | x.mnemonic = m.phrase; 103 | x.mnemonicHasPassphrase = !!passphrase; 104 | 105 | return x; 106 | }; 107 | 108 | Credentials.fromExtendedPrivateKey = function(coin, xPrivKey, account, derivationStrategy, opts) { 109 | _checkCoin(coin); 110 | $.shouldBeNumber(account); 111 | $.checkArgument(_.includes(_.values(Constants.DERIVATION_STRATEGIES), derivationStrategy)); 112 | 113 | opts = opts || {}; 114 | 115 | var x = new Credentials(); 116 | x.coin = coin; 117 | x.xPrivKey = xPrivKey; 118 | x.account = account; 119 | x.derivationStrategy = derivationStrategy; 120 | x.compliantDerivation = !opts.nonCompliantDerivation; 121 | 122 | if (opts.walletPrivKey) { 123 | x.addWalletPrivateKey(opts.walletPrivKey); 124 | } 125 | 126 | x._expand(); 127 | return x; 128 | }; 129 | 130 | // note that mnemonic / passphrase is NOT stored 131 | Credentials.fromMnemonic = function(coin, network, words, passphrase, account, derivationStrategy, opts) { 132 | _checkCoin(coin); 133 | _checkNetwork(network); 134 | $.shouldBeNumber(account); 135 | $.checkArgument(_.includes(_.values(Constants.DERIVATION_STRATEGIES), derivationStrategy)); 136 | 137 | opts = opts || {}; 138 | 139 | var m = new Mnemonic(words); 140 | var x = new Credentials(); 141 | x.coin = coin; 142 | x.xPrivKey = m.toHDPrivateKey(passphrase, network).toString(); 143 | x.mnemonic = words; 144 | x.mnemonicHasPassphrase = !!passphrase; 145 | x.account = account; 146 | x.derivationStrategy = derivationStrategy; 147 | x.compliantDerivation = !opts.nonCompliantDerivation; 148 | x.entropySourcePath = opts.entropySourcePath; 149 | 150 | if (opts.walletPrivKey) { 151 | x.addWalletPrivateKey(opts.walletPrivKey); 152 | } 153 | 154 | x._expand(); 155 | return x; 156 | }; 157 | 158 | /* 159 | * BWC uses 160 | * xPrivKey -> m/44'/network'/account' -> Base Address Key 161 | * so, xPubKey is PublicKeyHD(xPrivKey.deriveChild("m/44'/network'/account'"). 162 | * 163 | * For external sources, this derivation should be done before 164 | * call fromExtendedPublicKey 165 | * 166 | * entropySource should be a HEX string containing pseudo-random data, that can 167 | * be deterministically derived from the xPrivKey, and should not be derived from xPubKey 168 | */ 169 | Credentials.fromExtendedPublicKey = function(coin, xPubKey, source, entropySourceHex, account, derivationStrategy, opts) { 170 | _checkCoin(coin); 171 | $.checkArgument(entropySourceHex); 172 | $.shouldBeNumber(account); 173 | $.checkArgument(_.includes(_.values(Constants.DERIVATION_STRATEGIES), derivationStrategy)); 174 | 175 | opts = opts || {}; 176 | 177 | var entropyBuffer = new Buffer(entropySourceHex, 'hex'); 178 | //require at least 112 bits of entropy 179 | $.checkArgument(entropyBuffer.length >= 14, 'At least 112 bits of entropy are needed') 180 | 181 | var x = new Credentials(); 182 | x.coin = coin; 183 | x.xPubKey = xPubKey; 184 | x.entropySource = Bitcore.crypto.Hash.sha256sha256(entropyBuffer).toString('hex'); 185 | x.account = account; 186 | x.derivationStrategy = derivationStrategy; 187 | x.externalSource = source; 188 | x.compliantDerivation = true; 189 | x._expand(); 190 | return x; 191 | }; 192 | 193 | // Get network from extended private key or extended public key 194 | Credentials._getNetworkFromExtendedKey = function(xKey) { 195 | $.checkArgument(xKey && _.isString(xKey)); 196 | return xKey.charAt(0) == 't' ? 'testnet' : 'livenet'; 197 | }; 198 | 199 | Credentials.prototype._hashFromEntropy = function(prefix, length) { 200 | $.checkState(prefix); 201 | var b = new Buffer(this.entropySource, 'hex'); 202 | var b2 = Bitcore.crypto.Hash.sha256hmac(b, new Buffer(prefix)); 203 | return b2.slice(0, length); 204 | }; 205 | 206 | 207 | Credentials.prototype._expand = function() { 208 | $.checkState(this.xPrivKey || (this.xPubKey && this.entropySource)); 209 | 210 | 211 | var network = Credentials._getNetworkFromExtendedKey(this.xPrivKey || this.xPubKey); 212 | if (this.network) { 213 | $.checkState(this.network == network); 214 | } else { 215 | this.network = network; 216 | } 217 | 218 | if (this.xPrivKey) { 219 | var xPrivKey = new Bitcore.HDPrivateKey.fromString(this.xPrivKey); 220 | 221 | var deriveFn = this.compliantDerivation ? _.bind(xPrivKey.deriveChild, xPrivKey) : _.bind(xPrivKey.deriveNonCompliantChild, xPrivKey); 222 | 223 | var derivedXPrivKey = deriveFn(this.getBaseAddressDerivationPath()); 224 | 225 | // this is the xPubKey shared with the server. 226 | this.xPubKey = derivedXPrivKey.hdPublicKey.toString(); 227 | } 228 | 229 | // requests keys from mnemonics, but using a xPubkey 230 | // This is only used when importing mnemonics FROM 231 | // an hwwallet, in which xPriv was not available when 232 | // the wallet was created. 233 | if (this.entropySourcePath) { 234 | var seed = deriveFn(this.entropySourcePath).publicKey.toBuffer(); 235 | this.entropySource = Bitcore.crypto.Hash.sha256sha256(seed).toString('hex'); 236 | } 237 | 238 | if (this.entropySource) { 239 | // request keys from entropy (hw wallets) 240 | var seed = this._hashFromEntropy('reqPrivKey', 32); 241 | var privKey = new Bitcore.PrivateKey(seed.toString('hex'), network); 242 | this.requestPrivKey = privKey.toString(); 243 | this.requestPubKey = privKey.toPublicKey().toString(); 244 | } else { 245 | // request keys derived from xPriv 246 | var requestDerivation = deriveFn(Constants.PATHS.REQUEST_KEY); 247 | this.requestPrivKey = requestDerivation.privateKey.toString(); 248 | 249 | var pubKey = requestDerivation.publicKey; 250 | this.requestPubKey = pubKey.toString(); 251 | 252 | this.entropySource = Bitcore.crypto.Hash.sha256(requestDerivation.privateKey.toBuffer()).toString('hex'); 253 | } 254 | 255 | this.personalEncryptingKey = this._hashFromEntropy('personalKey', 16).toString('base64'); 256 | 257 | $.checkState(this.coin); 258 | 259 | this.copayerId = Utils.xPubToCopayerId(this.coin, this.xPubKey); 260 | this.publicKeyRing = [{ 261 | xPubKey: this.xPubKey, 262 | requestPubKey: this.requestPubKey, 263 | }]; 264 | }; 265 | 266 | Credentials.fromObj = function(obj) { 267 | var x = new Credentials(); 268 | 269 | _.each(FIELDS, function(k) { 270 | x[k] = obj[k]; 271 | }); 272 | 273 | x.coin = x.coin || 'btc'; 274 | x.derivationStrategy = x.derivationStrategy || Constants.DERIVATION_STRATEGIES.BIP45; 275 | x.addressType = x.addressType || Constants.SCRIPT_TYPES.P2SH; 276 | x.account = x.account || 0; 277 | 278 | $.checkState(x.xPrivKey || x.xPubKey || x.xPrivKeyEncrypted, "invalid input"); 279 | return x; 280 | }; 281 | 282 | Credentials.prototype.toObj = function() { 283 | var self = this; 284 | 285 | var x = {}; 286 | _.each(FIELDS, function(k) { 287 | x[k] = self[k]; 288 | }); 289 | return x; 290 | }; 291 | 292 | Credentials.prototype.getBaseAddressDerivationPath = function() { 293 | var purpose; 294 | switch (this.derivationStrategy) { 295 | case Constants.DERIVATION_STRATEGIES.BIP45: 296 | return "m/45'"; 297 | case Constants.DERIVATION_STRATEGIES.BIP44: 298 | purpose = '44'; 299 | break; 300 | case Constants.DERIVATION_STRATEGIES.BIP48: 301 | purpose = '48'; 302 | break; 303 | } 304 | 305 | var coin = (this.network == 'livenet' ? "0" : "1"); 306 | return "m/" + purpose + "'/" + coin + "'/" + this.account + "'"; 307 | }; 308 | 309 | Credentials.prototype.getDerivedXPrivKey = function(password) { 310 | var path = this.getBaseAddressDerivationPath(); 311 | var xPrivKey = new Bitcore.HDPrivateKey(this.getKeys(password).xPrivKey, this.network); 312 | var deriveFn = !!this.compliantDerivation ? _.bind(xPrivKey.deriveChild, xPrivKey) : _.bind(xPrivKey.deriveNonCompliantChild, xPrivKey); 313 | return deriveFn(path); 314 | }; 315 | 316 | Credentials.prototype.addWalletPrivateKey = function(walletPrivKey) { 317 | this.walletPrivKey = walletPrivKey; 318 | this.sharedEncryptingKey = Utils.privateKeyToAESKey(walletPrivKey); 319 | }; 320 | 321 | Credentials.prototype.addWalletInfo = function(walletId, walletName, m, n, copayerName) { 322 | this.walletId = walletId; 323 | this.walletName = walletName; 324 | this.m = m; 325 | this.n = n; 326 | 327 | if (copayerName) 328 | this.copayerName = copayerName; 329 | 330 | if (this.derivationStrategy == 'BIP44' && n == 1) 331 | this.addressType = Constants.SCRIPT_TYPES.P2PKH; 332 | else 333 | this.addressType = Constants.SCRIPT_TYPES.P2SH; 334 | 335 | // Use m/48' for multisig hardware wallets 336 | if (!this.xPrivKey && this.externalSource && n > 1) { 337 | this.derivationStrategy = Constants.DERIVATION_STRATEGIES.BIP48; 338 | } 339 | 340 | if (n == 1) { 341 | this.addPublicKeyRing([{ 342 | xPubKey: this.xPubKey, 343 | requestPubKey: this.requestPubKey, 344 | }]); 345 | } 346 | }; 347 | 348 | Credentials.prototype.hasWalletInfo = function() { 349 | return !!this.walletId; 350 | }; 351 | 352 | Credentials.prototype.isPrivKeyEncrypted = function() { 353 | return (!!this.xPrivKeyEncrypted) && !this.xPrivKey; 354 | }; 355 | 356 | Credentials.prototype.encryptPrivateKey = function(password, opts) { 357 | if (this.xPrivKeyEncrypted) 358 | throw new Error('Private key already encrypted'); 359 | 360 | if (!this.xPrivKey) 361 | throw new Error('No private key to encrypt'); 362 | 363 | 364 | this.xPrivKeyEncrypted = sjcl.encrypt(password, this.xPrivKey, opts); 365 | if (!this.xPrivKeyEncrypted) 366 | throw new Error('Could not encrypt'); 367 | 368 | if (this.mnemonic) 369 | this.mnemonicEncrypted = sjcl.encrypt(password, this.mnemonic, opts); 370 | 371 | delete this.xPrivKey; 372 | delete this.mnemonic; 373 | }; 374 | 375 | Credentials.prototype.decryptPrivateKey = function(password) { 376 | if (!this.xPrivKeyEncrypted) 377 | throw new Error('Private key is not encrypted'); 378 | 379 | try { 380 | this.xPrivKey = sjcl.decrypt(password, this.xPrivKeyEncrypted); 381 | 382 | if (this.mnemonicEncrypted) { 383 | this.mnemonic = sjcl.decrypt(password, this.mnemonicEncrypted); 384 | } 385 | delete this.xPrivKeyEncrypted; 386 | delete this.mnemonicEncrypted; 387 | } catch (ex) { 388 | throw new Error('Could not decrypt'); 389 | } 390 | }; 391 | 392 | Credentials.prototype.getKeys = function(password) { 393 | var keys = {}; 394 | 395 | if (this.isPrivKeyEncrypted()) { 396 | $.checkArgument(password, 'Private keys are encrypted, a password is needed'); 397 | try { 398 | keys.xPrivKey = sjcl.decrypt(password, this.xPrivKeyEncrypted); 399 | 400 | if (this.mnemonicEncrypted) { 401 | keys.mnemonic = sjcl.decrypt(password, this.mnemonicEncrypted); 402 | } 403 | } catch (ex) { 404 | throw new Error('Could not decrypt'); 405 | } 406 | } else { 407 | keys.xPrivKey = this.xPrivKey; 408 | keys.mnemonic = this.mnemonic; 409 | } 410 | return keys; 411 | }; 412 | 413 | Credentials.prototype.addPublicKeyRing = function(publicKeyRing) { 414 | this.publicKeyRing = _.clone(publicKeyRing); 415 | }; 416 | 417 | Credentials.prototype.canSign = function() { 418 | return (!!this.xPrivKey || !!this.xPrivKeyEncrypted); 419 | }; 420 | 421 | Credentials.prototype.setNoSign = function() { 422 | delete this.xPrivKey; 423 | delete this.xPrivKeyEncrypted; 424 | delete this.mnemonic; 425 | delete this.mnemonicEncrypted; 426 | }; 427 | 428 | Credentials.prototype.isComplete = function() { 429 | if (!this.m || !this.n) return false; 430 | if (!this.publicKeyRing || this.publicKeyRing.length != this.n) return false; 431 | return true; 432 | }; 433 | 434 | Credentials.prototype.hasExternalSource = function() { 435 | return (typeof this.externalSource == "string"); 436 | }; 437 | 438 | Credentials.prototype.getExternalSourceName = function() { 439 | return this.externalSource; 440 | }; 441 | 442 | Credentials.prototype.getMnemonic = function() { 443 | if (this.mnemonicEncrypted && !this.mnemonic) { 444 | throw new Error('Credentials are encrypted'); 445 | } 446 | 447 | return this.mnemonic; 448 | }; 449 | 450 | Credentials.prototype.clearMnemonic = function() { 451 | delete this.mnemonic; 452 | delete this.mnemonicEncrypted; 453 | }; 454 | 455 | 456 | Credentials.fromOldCopayWallet = function(w) { 457 | function walletPrivKeyFromOldCopayWallet(w) { 458 | // IN BWS, the master Pub Keys are not sent to the server, 459 | // so it is safe to use them as seed for wallet's shared secret. 460 | var seed = w.publicKeyRing.copayersExtPubKeys.sort().join(''); 461 | var seedBuf = new Buffer(seed); 462 | var privKey = new Bitcore.PrivateKey.fromBuffer(Bitcore.crypto.Hash.sha256(seedBuf)); 463 | return privKey.toString(); 464 | }; 465 | 466 | var credentials = new Credentials(); 467 | credentials.coin = 'btc'; 468 | credentials.derivationStrategy = Constants.DERIVATION_STRATEGIES.BIP45; 469 | credentials.xPrivKey = w.privateKey.extendedPrivateKeyString; 470 | credentials._expand(); 471 | 472 | credentials.addWalletPrivateKey(walletPrivKeyFromOldCopayWallet(w)); 473 | credentials.addWalletInfo(w.opts.id, w.opts.name, w.opts.requiredCopayers, w.opts.totalCopayers) 474 | 475 | var pkr = _.map(w.publicKeyRing.copayersExtPubKeys, function(xPubStr) { 476 | 477 | var isMe = xPubStr === credentials.xPubKey; 478 | var requestDerivation; 479 | 480 | if (isMe) { 481 | var path = Constants.PATHS.REQUEST_KEY; 482 | requestDerivation = (new Bitcore.HDPrivateKey(credentials.xPrivKey)) 483 | .deriveChild(path).hdPublicKey; 484 | } else { 485 | // this 486 | var path = Constants.PATHS.REQUEST_KEY_AUTH; 487 | requestDerivation = (new Bitcore.HDPublicKey(xPubStr)).deriveChild(path); 488 | } 489 | 490 | // Grab Copayer Name 491 | var hd = new Bitcore.HDPublicKey(xPubStr).deriveChild('m/2147483646/0/0'); 492 | var pubKey = hd.publicKey.toString('hex'); 493 | var copayerName = w.publicKeyRing.nicknameFor[pubKey]; 494 | if (isMe) { 495 | credentials.copayerName = copayerName; 496 | } 497 | 498 | return { 499 | xPubKey: xPubStr, 500 | requestPubKey: requestDerivation.publicKey.toString(), 501 | copayerName: copayerName, 502 | }; 503 | }); 504 | credentials.addPublicKeyRing(pkr); 505 | return credentials; 506 | }; 507 | 508 | 509 | module.exports = Credentials; 510 | -------------------------------------------------------------------------------- /lib/errors/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _ = require('lodash'); 4 | 5 | function format(message, args) { 6 | return message 7 | .replace('{0}', args[0]) 8 | .replace('{1}', args[1]) 9 | .replace('{2}', args[2]); 10 | } 11 | var traverseNode = function(parent, errorDefinition) { 12 | var NodeError = function() { 13 | if (_.isString(errorDefinition.message)) { 14 | this.message = format(errorDefinition.message, arguments); 15 | } else if (_.isFunction(errorDefinition.message)) { 16 | this.message = errorDefinition.message.apply(null, arguments); 17 | } else { 18 | throw new Error('Invalid error definition for ' + errorDefinition.name); 19 | } 20 | this.stack = this.message + '\n' + (new Error()).stack; 21 | }; 22 | NodeError.prototype = Object.create(parent.prototype); 23 | NodeError.prototype.name = parent.prototype.name + errorDefinition.name; 24 | parent[errorDefinition.name] = NodeError; 25 | if (errorDefinition.errors) { 26 | childDefinitions(NodeError, errorDefinition.errors); 27 | } 28 | return NodeError; 29 | }; 30 | 31 | /* jshint latedef: false */ 32 | var childDefinitions = function(parent, childDefinitions) { 33 | _.each(childDefinitions, function(childDefinition) { 34 | traverseNode(parent, childDefinition); 35 | }); 36 | }; 37 | /* jshint latedef: true */ 38 | 39 | var traverseRoot = function(parent, errorsDefinition) { 40 | childDefinitions(parent, errorsDefinition); 41 | return parent; 42 | }; 43 | 44 | 45 | var bwc = {}; 46 | bwc.Error = function() { 47 | this.message = 'Internal error'; 48 | this.stack = this.message + '\n' + (new Error()).stack; 49 | }; 50 | bwc.Error.prototype = Object.create(Error.prototype); 51 | bwc.Error.prototype.name = 'bwc.Error'; 52 | 53 | 54 | var data = require('./spec'); 55 | traverseRoot(bwc.Error, data); 56 | 57 | module.exports = bwc.Error; 58 | 59 | module.exports.extend = function(spec) { 60 | return traverseNode(bwc.Error, spec); 61 | }; 62 | -------------------------------------------------------------------------------- /lib/errors/spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var errorSpec = [{ 4 | name: 'INVALID_BACKUP', 5 | message: 'Invalid Backup.' 6 | }, { 7 | name: 'WALLET_DOES_NOT_EXIST', 8 | message: 'Wallet does not exist.' 9 | }, { 10 | name: 'MISSING_PRIVATE_KEY', 11 | message: 'Missing private keys to sign.' 12 | }, { 13 | name: 'ENCRYPTED_PRIVATE_KEY', 14 | message: 'Private key is encrypted, cannot sign transaction.' 15 | }, { 16 | name: 'SERVER_COMPROMISED', 17 | message: 'Server response could not be verified.' 18 | }, { 19 | name: 'COULD_NOT_BUILD_TRANSACTION', 20 | message: 'Could not build the transaction.' 21 | }, { 22 | name: 'INSUFFICIENT_FUNDS', 23 | message: 'Insufficient funds.' 24 | }, { 25 | name: 'CONNECTION_ERROR', 26 | message: 'Wallet service connection error.' 27 | }, { 28 | name: 'NOT_FOUND', 29 | message: 'Wallet service not found.' 30 | }, { 31 | name: 'ECONNRESET_ERROR', 32 | message: 'ECONNRESET, body: {0}' 33 | }, { 34 | name: 'WALLET_ALREADY_EXISTS', 35 | message: 'Wallet already exists.' 36 | }, { 37 | name: 'COPAYER_IN_WALLET', 38 | message: 'Copayer in wallet.' 39 | }, { 40 | name: 'WALLET_FULL', 41 | message: 'Wallet is full.' 42 | }, { 43 | name: 'WALLET_NOT_FOUND', 44 | message: 'Wallet not found.' 45 | }, { 46 | name: 'INSUFFICIENT_FUNDS_FOR_FEE', 47 | message: 'Insufficient funds for fee.' 48 | }, { 49 | name: 'LOCKED_FUNDS', 50 | message: 'Locked funds.' 51 | }, { 52 | name: 'DUST_AMOUNT', 53 | message: 'Amount below dust threshold.' 54 | }, { 55 | name: 'COPAYER_VOTED', 56 | message: 'Copayer already voted on this transaction proposal.' 57 | }, { 58 | name: 'NOT_AUTHORIZED', 59 | message: 'Not authorized.' 60 | }, { 61 | name: 'UNAVAILABLE_UTXOS', 62 | message: 'Unavailable unspent outputs.' 63 | }, { 64 | name: 'TX_NOT_FOUND', 65 | message: 'Transaction proposal not found.' 66 | }, { 67 | name: 'MAIN_ADDRESS_GAP_REACHED', 68 | message: 'Maximum number of consecutive addresses without activity reached.' 69 | }, { 70 | name: 'COPAYER_REGISTERED', 71 | message: 'Copayer already register on server.' 72 | } 73 | ]; 74 | 75 | module.exports = errorSpec; 76 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The official client library for bitcore-wallet-service. 3 | * @module Client 4 | */ 5 | 6 | /** 7 | * Client API. 8 | * @alias module:Client.API 9 | */ 10 | var client = module.exports = require('./api'); 11 | 12 | /** 13 | * Verifier module. 14 | * @alias module:Client.Verifier 15 | */ 16 | client.Verifier = require('./verifier'); 17 | client.Utils = require('./common/utils'); 18 | client.sjcl = require('sjcl'); 19 | 20 | // Expose bitcore 21 | client.Bitcore = require('bitcore-lib'); 22 | client.BitcoreCash = require('bitcore-lib-cash'); 23 | -------------------------------------------------------------------------------- /lib/log.js: -------------------------------------------------------------------------------- 1 | var _ = require('lodash'); 2 | 3 | var DEFAULT_LOG_LEVEL = 'silent'; 4 | 5 | /** 6 | * @desc 7 | * A simple logger that wraps the console.log methods when available. 8 | * 9 | * Usage: 10 | *
 11 |  *   log = new Logger('copay');
 12 |  *   log.setLevel('info');
 13 |  *   log.debug('Message!'); // won't show
 14 |  *   log.setLevel('debug');
 15 |  *   log.debug('Message!', 1); // will show '[debug] copay: Message!, 1'
 16 |  * 
17 | * 18 | * @param {string} name - a name for the logger. This will show up on every log call 19 | * @constructor 20 | */ 21 | var Logger = function(name) { 22 | this.name = name || 'log'; 23 | this.level = DEFAULT_LOG_LEVEL; 24 | }; 25 | 26 | Logger.prototype.getLevels = function() { 27 | return levels; 28 | }; 29 | 30 | 31 | var levels = { 32 | 'silent': -1, 33 | 'debug': 0, 34 | 'info': 1, 35 | 'log': 2, 36 | 'warn': 3, 37 | 'error': 4, 38 | 'fatal': 5 39 | }; 40 | 41 | _.each(levels, function(level, levelName) { 42 | if (levelName === 'silent') { // dont create a log.silent() method 43 | return; 44 | } 45 | Logger.prototype[levelName] = function() { 46 | if (this.level === 'silent') { 47 | return; 48 | } 49 | 50 | if (level >= levels[this.level]) { 51 | 52 | if (Error.stackTraceLimit && this.level == 'debug') { 53 | var old = Error.stackTraceLimit; 54 | Error.stackTraceLimit = 2; 55 | var stack; 56 | 57 | // this hack is to be compatible with IE11 58 | try { 59 | anerror(); 60 | } catch (e) { 61 | stack = e.stack; 62 | } 63 | var lines = stack.split('\n'); 64 | var caller = lines[2]; 65 | caller = ':' + caller.substr(6); 66 | Error.stackTraceLimit = old; 67 | } 68 | 69 | var str = '[' + levelName + (caller || '') + '] ' + arguments[0], 70 | extraArgs, 71 | extraArgs = [].slice.call(arguments, 1); 72 | if (console[levelName]) { 73 | extraArgs.unshift(str); 74 | console[levelName].apply(console, extraArgs); 75 | } else { 76 | if (extraArgs.length) { 77 | str += JSON.stringify(extraArgs); 78 | } 79 | console.log(str); 80 | } 81 | } 82 | }; 83 | }); 84 | 85 | /** 86 | * @desc 87 | * Sets the level of a logger. A level can be any bewteen: 'debug', 'info', 'log', 88 | * 'warn', 'error', and 'fatal'. That order matters: if a logger's level is set to 89 | * 'warn', calling level.debug won't have any effect. 90 | * 91 | * @param {string} level - the name of the logging level 92 | */ 93 | Logger.prototype.setLevel = function(level) { 94 | this.level = level; 95 | }; 96 | 97 | /** 98 | * @class Logger 99 | * @method debug 100 | * @desc Log messages at the debug level. 101 | * @param {*} args - the arguments to be logged. 102 | */ 103 | /** 104 | * @class Logger 105 | * @method info 106 | * @desc Log messages at the info level. 107 | * @param {*} args - the arguments to be logged. 108 | */ 109 | /** 110 | * @class Logger 111 | * @method log 112 | * @desc Log messages at an intermediary level called 'log'. 113 | * @param {*} args - the arguments to be logged. 114 | */ 115 | /** 116 | * @class Logger 117 | * @method warn 118 | * @desc Log messages at the warn level. 119 | * @param {*} args - the arguments to be logged. 120 | */ 121 | /** 122 | * @class Logger 123 | * @method error 124 | * @desc Log messages at the error level. 125 | * @param {*} args - the arguments to be logged. 126 | */ 127 | /** 128 | * @class Logger 129 | * @method fatal 130 | * @desc Log messages at the fatal level. 131 | * @param {*} args - the arguments to be logged. 132 | */ 133 | 134 | var logger = new Logger('copay'); 135 | module.exports = logger; 136 | -------------------------------------------------------------------------------- /lib/paypro.js: -------------------------------------------------------------------------------- 1 | var $ = require('preconditions').singleton(); 2 | var Bitcore = require('bitcore-lib'); 3 | var Bitcore_ = { 4 | btc: Bitcore, 5 | bch: require('bitcore-lib-cash'), 6 | }; 7 | 8 | var BitcorePayPro = require('bitcore-payment-protocol'); 9 | var PayPro = {}; 10 | 11 | PayPro._nodeRequest = function(opts, cb) { 12 | opts.agent = false; 13 | var http = opts.httpNode || (opts.proto === 'http' ? require("http") : require("https")); 14 | 15 | var fn = opts.method == 'POST' ? 'post' : 'get'; 16 | 17 | http[fn](opts, function(res) { 18 | var data = []; // List of Buffer objects 19 | 20 | 21 | if (res.statusCode != 200) 22 | return cb(new Error('HTTP Request Error: ' + res.statusCode + ' ' + res.statusMessage + ' ' + ( data ? data : '' ) )); 23 | 24 | res.on("data", function(chunk) { 25 | data.push(chunk); // Append Buffer object 26 | }); 27 | res.on("end", function() { 28 | data = Buffer.concat(data); // Make one large Buffer of it 29 | return cb(null, data); 30 | }); 31 | }); 32 | }; 33 | 34 | PayPro._browserRequest = function(opts, cb) { 35 | var method = (opts.method || 'GET').toUpperCase(); 36 | var url = opts.url; 37 | var req = opts; 38 | 39 | req.headers = req.headers || {}; 40 | req.body = req.body || req.data || ''; 41 | 42 | var xhr = opts.xhr || new XMLHttpRequest(); 43 | xhr.open(method, url, true); 44 | 45 | Object.keys(req.headers).forEach(function(key) { 46 | var val = req.headers[key]; 47 | if (key === 'Content-Length') return; 48 | if (key === 'Content-Transfer-Encoding') return; 49 | xhr.setRequestHeader(key, val); 50 | }); 51 | xhr.responseType = 'arraybuffer'; 52 | 53 | xhr.onload = function(event) { 54 | var response = xhr.response; 55 | if (xhr.status == 200) { 56 | return cb(null, new Uint8Array(response)); 57 | } else { 58 | return cb('HTTP Request Error: ' + xhr.status + ' ' + xhr.statusText + ' ' + response ? response : ''); 59 | } 60 | }; 61 | 62 | xhr.onerror = function(event) { 63 | var status; 64 | if (xhr.status === 0 || !xhr.statusText) { 65 | status = 'HTTP Request Error'; 66 | } else { 67 | status = xhr.statusText; 68 | } 69 | return cb(new Error(status)); 70 | }; 71 | 72 | if (req.body) { 73 | xhr.send(req.body); 74 | } else { 75 | xhr.send(null); 76 | } 77 | }; 78 | 79 | var getHttp = function(opts) { 80 | var match = opts.url.match(/^((http[s]?):\/)?\/?([^:\/\s]+)((\/\w+)*\/)([\w\-\.]+[^#?\s]+)(.*)?(#[\w\-]+)?$/); 81 | 82 | opts.proto = RegExp.$2; 83 | opts.host = RegExp.$3; 84 | opts.path = RegExp.$4 + RegExp.$6; 85 | if (opts.http) return opts.http; 86 | 87 | var env = opts.env; 88 | if (!env) 89 | env = (process && !process.browser) ? 'node' : 'browser'; 90 | 91 | return (env == "node") ? PayPro._nodeRequest : http = PayPro._browserRequest;; 92 | }; 93 | 94 | PayPro.get = function(opts, cb) { 95 | $.checkArgument(opts && opts.url); 96 | 97 | var http = getHttp(opts); 98 | var coin = opts.coin || 'btc'; 99 | var bitcore = Bitcore_[coin]; 100 | 101 | var COIN = coin.toUpperCase(); 102 | var PP = new BitcorePayPro(COIN); 103 | 104 | opts.headers = opts.headers || { 105 | 'Accept': BitcorePayPro.LEGACY_PAYMENT[COIN].REQUEST_CONTENT_TYPE, 106 | 'Content-Type': 'application/octet-stream', 107 | }; 108 | 109 | http(opts, function(err, dataBuffer) { 110 | if (err) return cb(err); 111 | var request, verified, signature, serializedDetails; 112 | try { 113 | var body = BitcorePayPro.PaymentRequest.decode(dataBuffer); 114 | request = PP.makePaymentRequest(body); 115 | signature = request.get('signature'); 116 | serializedDetails = request.get('serialized_payment_details'); 117 | // Verify the signature 118 | verified = request.verify(true); 119 | } catch (e) { 120 | return cb(new Error('Could not parse payment protocol' + e)); 121 | } 122 | 123 | // Get the payment details 124 | var decodedDetails = BitcorePayPro.PaymentDetails.decode(serializedDetails); 125 | var pd = new BitcorePayPro(); 126 | pd = pd.makePaymentDetails(decodedDetails); 127 | 128 | var outputs = pd.get('outputs'); 129 | if (outputs.length > 1) 130 | return cb(new Error('Payment Protocol Error: Requests with more that one output are not supported')) 131 | 132 | var output = outputs[0]; 133 | 134 | var amount = output.get('amount').toNumber(); 135 | var network = pd.get('network') == 'test' ? 'testnet' : 'livenet'; 136 | 137 | // We love payment protocol 138 | var offset = output.get('script').offset; 139 | var limit = output.get('script').limit; 140 | 141 | // NOTE: For some reason output.script.buffer 142 | // is only an ArrayBuffer 143 | var buffer = new Buffer(new Uint8Array(output.get('script').buffer)); 144 | var scriptBuf = buffer.slice(offset, limit); 145 | var addr = new bitcore.Address.fromScript(new bitcore.Script(scriptBuf), network); 146 | 147 | var md = pd.get('merchant_data'); 148 | 149 | if (md) { 150 | md = md.toString(); 151 | } 152 | 153 | var ok = verified.verified; 154 | var caName; 155 | 156 | if (verified.isChain) { 157 | ok = ok && verified.chainVerified; 158 | } 159 | 160 | var ret = { 161 | verified: ok, 162 | caTrusted: verified.caTrusted, 163 | caName: verified.caName, 164 | selfSigned: verified.selfSigned, 165 | expires: pd.get('expires'), 166 | memo: pd.get('memo'), 167 | time: pd.get('time'), 168 | merchant_data: md, 169 | toAddress: coin == 'bch' ? addr.toLegacyAddress() : addr.toString(), 170 | amount: amount, 171 | network: network, 172 | domain: opts.host, 173 | url: opts.url, 174 | }; 175 | 176 | var requiredFeeRate = pd.get('required_fee_rate'); 177 | if (requiredFeeRate) 178 | ret.requiredFeeRate = requiredFeeRate; 179 | 180 | return cb(null, ret); 181 | }); 182 | }; 183 | 184 | 185 | PayPro._getPayProRefundOutputs = function(addrStr, amount, coin) { 186 | amount = amount.toString(10); 187 | 188 | var bitcore = Bitcore_[coin]; 189 | var output = new BitcorePayPro.Output(); 190 | var addr = new bitcore.Address(addrStr); 191 | 192 | var s; 193 | if (addr.isPayToPublicKeyHash()) { 194 | s = bitcore.Script.buildPublicKeyHashOut(addr); 195 | } else if (addr.isPayToScriptHash()) { 196 | s = bitcore.Script.buildScriptHashOut(addr); 197 | } else { 198 | throw new Error('Unrecognized address type ' + addr.type); 199 | } 200 | 201 | // console.log('PayPro refund address set to:', addrStr,s); 202 | output.set('script', s.toBuffer()); 203 | output.set('amount', amount); 204 | return [output]; 205 | }; 206 | 207 | 208 | PayPro._createPayment = function(merchant_data, rawTx, refundAddr, amountSat, coin) { 209 | var pay = new BitcorePayPro(); 210 | pay = pay.makePayment(); 211 | 212 | if (merchant_data) { 213 | merchant_data = new Buffer(merchant_data); 214 | pay.set('merchant_data', merchant_data); 215 | } 216 | 217 | var txBuf = new Buffer(rawTx, 'hex'); 218 | pay.set('transactions', [txBuf]); 219 | 220 | var refund_outputs = this._getPayProRefundOutputs(refundAddr, amountSat, coin); 221 | if (refund_outputs) 222 | pay.set('refund_to', refund_outputs); 223 | 224 | // Unused for now 225 | // options.memo = ''; 226 | // pay.set('memo', options.memo); 227 | 228 | pay = pay.serialize(); 229 | var buf = new ArrayBuffer(pay.length); 230 | var view = new Uint8Array(buf); 231 | for (var i = 0; i < pay.length; i++) { 232 | view[i] = pay[i]; 233 | } 234 | 235 | return view; 236 | }; 237 | 238 | PayPro.send = function(opts, cb) { 239 | $.checkArgument(opts.merchant_data) 240 | .checkArgument(opts.url) 241 | .checkArgument(opts.rawTx) 242 | .checkArgument(opts.refundAddr) 243 | .checkArgument(opts.amountSat); 244 | 245 | 246 | var coin = opts.coin || 'btc'; 247 | var COIN = coin.toUpperCase(); 248 | 249 | var payment = PayPro._createPayment(opts.merchant_data, opts.rawTx, opts.refundAddr, opts.amountSat, coin); 250 | 251 | var http = getHttp(opts); 252 | opts.method = 'POST'; 253 | opts.headers = opts.headers || { 254 | 'Accept': BitcorePayPro.LEGACY_PAYMENT[COIN].ACK_CONTENT_TYPE, 255 | 'Content-Type': BitcorePayPro.LEGACY_PAYMENT[COIN].CONTENT_TYPE, 256 | // 'Content-Type': 'application/octet-stream', 257 | }; 258 | opts.body = payment; 259 | 260 | http(opts, function(err, rawData) { 261 | if (err) return cb(err); 262 | var memo; 263 | if (rawData) { 264 | try { 265 | var data = BitcorePayPro.PaymentACK.decode(rawData); 266 | var pp = new BitcorePayPro(COIN); 267 | var ack = pp.makePaymentACK(data); 268 | memo = ack.get('memo'); 269 | } catch (e) { 270 | console.log('Could not decode paymentACK'); 271 | }; 272 | } 273 | return cb(null, rawData, memo); 274 | }); 275 | }; 276 | 277 | module.exports = PayPro; 278 | -------------------------------------------------------------------------------- /lib/verifier.js: -------------------------------------------------------------------------------- 1 | var $ = require('preconditions').singleton(); 2 | var _ = require('lodash'); 3 | 4 | var Bitcore = require('bitcore-lib'); 5 | 6 | var Common = require('./common'); 7 | var Utils = Common.Utils; 8 | 9 | var log = require('./log'); 10 | 11 | /** 12 | * @desc Verifier constructor. Checks data given by the server 13 | * 14 | * @constructor 15 | */ 16 | function Verifier(opts) {}; 17 | 18 | /** 19 | * Check address 20 | * 21 | * @param {Function} credentials 22 | * @param {String} address 23 | * @returns {Boolean} true or false 24 | */ 25 | Verifier.checkAddress = function(credentials, address) { 26 | $.checkState(credentials.isComplete()); 27 | 28 | var local = Utils.deriveAddress(address.type || credentials.addressType, credentials.publicKeyRing, address.path, credentials.m, credentials.network, credentials.coin); 29 | return (local.address == address.address && 30 | _.difference(local.publicKeys, address.publicKeys).length === 0); 31 | }; 32 | 33 | /** 34 | * Check copayers 35 | * 36 | * @param {Function} credentials 37 | * @param {Array} copayers 38 | * @returns {Boolean} true or false 39 | */ 40 | Verifier.checkCopayers = function(credentials, copayers) { 41 | $.checkState(credentials.walletPrivKey); 42 | var walletPubKey = Bitcore.PrivateKey.fromString(credentials.walletPrivKey).toPublicKey().toString(); 43 | 44 | if (copayers.length != credentials.n) { 45 | log.error('Missing public keys in server response'); 46 | return false; 47 | } 48 | 49 | // Repeated xpub kes? 50 | var uniq = []; 51 | var error; 52 | _.each(copayers, function(copayer) { 53 | if (error) return; 54 | 55 | if (uniq[copayers.xPubKey]++) { 56 | log.error('Repeated public keys in server response'); 57 | error = true; 58 | } 59 | 60 | // Not signed pub keys 61 | if (!(copayer.encryptedName || copayer.name) || !copayer.xPubKey || !copayer.requestPubKey || !copayer.signature) { 62 | log.error('Missing copayer fields in server response'); 63 | error = true; 64 | } else { 65 | var hash = Utils.getCopayerHash(copayer.encryptedName || copayer.name, copayer.xPubKey, copayer.requestPubKey); 66 | if (!Utils.verifyMessage(hash, copayer.signature, walletPubKey)) { 67 | log.error('Invalid signatures in server response'); 68 | error = true; 69 | } 70 | } 71 | }); 72 | 73 | if (error) return false; 74 | 75 | if (!_.includes(_.map(copayers, 'xPubKey'), credentials.xPubKey)) { 76 | log.error('Server response does not contains our public keys') 77 | return false; 78 | } 79 | return true; 80 | }; 81 | 82 | Verifier.checkProposalCreation = function(args, txp, encryptingKey) { 83 | function strEqual(str1, str2) { 84 | return ((!str1 && !str2) || (str1 === str2)); 85 | } 86 | 87 | if (txp.outputs.length != args.outputs.length) return false; 88 | 89 | for (var i = 0; i < txp.outputs.length; i++) { 90 | var o1 = txp.outputs[i]; 91 | var o2 = args.outputs[i]; 92 | if (!strEqual(o1.toAddress, o2.toAddress)) return false; 93 | if (!strEqual(o1.script, o2.script)) return false; 94 | if (o1.amount != o2.amount) return false; 95 | var decryptedMessage = null; 96 | try { 97 | decryptedMessage = Utils.decryptMessage(o2.message, encryptingKey); 98 | } catch (e) { 99 | return false; 100 | } 101 | if (!strEqual(o1.message, decryptedMessage)) return false; 102 | } 103 | 104 | var changeAddress; 105 | if (txp.changeAddress) { 106 | changeAddress = txp.changeAddress.address; 107 | } 108 | 109 | if (args.changeAddress && !strEqual(changeAddress, args.changeAddress)) return false; 110 | if (_.isNumber(args.feePerKb) && (txp.feePerKb != args.feePerKb)) return false; 111 | if (!strEqual(txp.payProUrl, args.payProUrl)) return false; 112 | 113 | var decryptedMessage = null; 114 | try { 115 | decryptedMessage = Utils.decryptMessage(args.message, encryptingKey); 116 | } catch (e) { 117 | return false; 118 | } 119 | if (!strEqual(txp.message, decryptedMessage)) return false; 120 | if ((args.customData || txp.customData) && !_.isEqual(txp.customData, args.customData)) return false; 121 | 122 | return true; 123 | }; 124 | 125 | Verifier.checkTxProposalSignature = function(credentials, txp) { 126 | $.checkArgument(txp.creatorId); 127 | $.checkState(credentials.isComplete()); 128 | 129 | var creatorKeys = _.find(credentials.publicKeyRing, function(item) { 130 | if (Utils.xPubToCopayerId(txp.coin || 'btc', item.xPubKey) === txp.creatorId) return true; 131 | }); 132 | 133 | if (!creatorKeys) return false; 134 | var creatorSigningPubKey; 135 | 136 | // If the txp using a selfsigned pub key? 137 | if (txp.proposalSignaturePubKey) { 138 | 139 | // Verify it... 140 | if (!Utils.verifyRequestPubKey(txp.proposalSignaturePubKey, txp.proposalSignaturePubKeySig, creatorKeys.xPubKey)) 141 | return false; 142 | 143 | creatorSigningPubKey = txp.proposalSignaturePubKey; 144 | } else { 145 | creatorSigningPubKey = creatorKeys.requestPubKey; 146 | } 147 | if (!creatorSigningPubKey) return false; 148 | 149 | 150 | var hash; 151 | if (parseInt(txp.version) >= 3) { 152 | var t = Utils.buildTx(txp); 153 | hash = t.uncheckedSerialize(); 154 | } else { 155 | throw new Error('Transaction proposal not supported'); 156 | } 157 | 158 | log.debug('Regenerating & verifying tx proposal hash -> Hash: ', hash, ' Signature: ', txp.proposalSignature); 159 | if (!Utils.verifyMessage(hash, txp.proposalSignature, creatorSigningPubKey)) 160 | return false; 161 | 162 | if (!Verifier.checkAddress(credentials, txp.changeAddress)) 163 | return false; 164 | 165 | return true; 166 | }; 167 | 168 | 169 | Verifier.checkPaypro = function(txp, payproOpts) { 170 | var toAddress, amount, feeRate; 171 | 172 | if (parseInt(txp.version) >= 3) { 173 | toAddress = txp.outputs[0].toAddress; 174 | amount = txp.amount; 175 | if (txp.feePerKb) { 176 | feeRate = txp.feePerKb / 1024; 177 | } 178 | } else { 179 | toAddress = txp.toAddress; 180 | amount = txp.amount; 181 | } 182 | 183 | // if (feeRate && payproOpts.requiredFeeRate && 184 | // feeRate < payproOpts.requiredFeeRate) 185 | // return false; 186 | 187 | return toAddress == payproOpts.toAddress && amount == payproOpts.amount; 188 | }; 189 | 190 | 191 | /** 192 | * Check transaction proposal 193 | * 194 | * @param {Function} credentials 195 | * @param {Object} txp 196 | * @param {Object} Optional: paypro 197 | * @param {Boolean} isLegit 198 | */ 199 | Verifier.checkTxProposal = function(credentials, txp, opts) { 200 | opts = opts || {}; 201 | 202 | if (!this.checkTxProposalSignature(credentials, txp)) 203 | return false; 204 | 205 | if (opts.paypro && !this.checkPaypro(txp, opts.paypro)) 206 | return false; 207 | 208 | return true; 209 | }; 210 | 211 | module.exports = Verifier; 212 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bitcore-wallet-client", 3 | "description": "Client for bitcore-wallet-service", 4 | "author": "BitPay Inc", 5 | "version": "6.8.1", 6 | "license": "MIT", 7 | "keywords": [ 8 | "bitcoin", 9 | "copay", 10 | "multisig", 11 | "wallet", 12 | "client", 13 | "bitcore", 14 | "BWS", 15 | "BWC" 16 | ], 17 | "engine": "node >= 8.0.0", 18 | "main": "index.js", 19 | "repository": { 20 | "url": "git@github.com:bitpay/bitcore-wallet-client.git", 21 | "type": "git" 22 | }, 23 | "bugs": { 24 | "url": "https://github.com/bitpay/bitcore-wallet-client/issues" 25 | }, 26 | "dependencies": { 27 | "async": "^0.9.0", 28 | "bip38": "^1.3.0", 29 | "bitcore-lib": "=0.16.0", 30 | "bitcore-lib-cash": "=0.19.0", 31 | "bitcore-mnemonic": "^1.3.0", 32 | "bitcore-payment-protocol": "^1.7.0", 33 | "json-stable-stringify": "^1.0.0", 34 | "lodash": "^4.17.11", 35 | "preconditions": "^2.2.1", 36 | "sjcl": "1.0.3", 37 | "superagent": "^3.4.1" 38 | }, 39 | "devDependencies": { 40 | "bitcore-wallet-service": "2.5.1", 41 | "browserify": "^13.1.0", 42 | "chai": "^1.9.1", 43 | "coveralls": "^3.0.2", 44 | "istanbul": "*", 45 | "mocha": "^5.2.0", 46 | "mongodb": "^2.0.27", 47 | "sinon": "^7.1.1", 48 | "supertest": "^3.0.0", 49 | "uuid": "^2.0.1" 50 | }, 51 | "scripts": { 52 | "start": "node app.js", 53 | "coverage": "./node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha -- --reporter spec test", 54 | "test": "./node_modules/.bin/mocha --exit", 55 | "coveralls": "./node_modules/.bin/istanbul cover ./node_modules/mocha/bin/_mocha --report lcovonly -- -R spec && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage", 56 | "docs": "./node_modules/.bin/jsdox lib/* lib/common lib/errors -o docs && cat README.header.md docs/*.md LICENSE > README.md" 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /test/credentials.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _ = require('lodash'); 4 | var chai = chai || require('chai'); 5 | var sinon = sinon || require('sinon'); 6 | var should = chai.should(); 7 | 8 | var Constants = require('../lib/common/constants'); 9 | var Credentials = require('../lib/credentials'); 10 | var TestData = require('./testdata'); 11 | 12 | describe('Credentials', function() { 13 | 14 | describe('#create', function() { 15 | it('Should create', function() { 16 | var c = Credentials.create('btc', 'livenet'); 17 | should.exist(c.xPrivKey); 18 | should.exist(c.copayerId); 19 | }); 20 | 21 | it('Should create random credentials', function() { 22 | var all = {}; 23 | for (var i = 0; i < 10; i++) { 24 | var c = Credentials.create('btc', 'livenet'); 25 | var exist = all[c.xPrivKey]; 26 | should.not.exist(exist); 27 | all[c.xPrivKey] = 1; 28 | } 29 | }); 30 | }); 31 | 32 | describe('#getBaseAddressDerivationPath', function() { 33 | it('should return path for livenet', function() { 34 | var c = Credentials.create('btc', 'livenet'); 35 | var path = c.getBaseAddressDerivationPath(); 36 | path.should.equal("m/44'/0'/0'"); 37 | }); 38 | it('should return path for testnet account 2', function() { 39 | var c = Credentials.create('btc', 'testnet'); 40 | c.account = 2; 41 | var path = c.getBaseAddressDerivationPath(); 42 | path.should.equal("m/44'/1'/2'"); 43 | }); 44 | it('should return path for BIP45', function() { 45 | var c = Credentials.create('btc', 'livenet'); 46 | c.derivationStrategy = Constants.DERIVATION_STRATEGIES.BIP45; 47 | var path = c.getBaseAddressDerivationPath(); 48 | path.should.equal("m/45'"); 49 | }); 50 | }); 51 | 52 | describe('#getDerivedXPrivKey', function() { 53 | it('should derive extended private key from master livenet', function() { 54 | var c = Credentials.fromExtendedPrivateKey('btc', 'xprv9s21ZrQH143K3zLpjtB4J4yrRfDTEfbrMa9vLZaTAv5BzASwBmA16mdBmZKpMLssw1AzTnm31HAD2pk2bsnZ9dccxaLD48mRdhtw82XoiBi', 0, 'BIP44'); 55 | var xpk = c.getDerivedXPrivKey().toString(); 56 | xpk.should.equal('xprv9xud2WztGSSBPDPDL9RQ3rG3vucRA4BmEnfAdP76bTqtkGCK8VzWjevLw9LsdqwH1PEWiwcjymf1T2FLp12XjwjuCRvcSBJvxDgv1BDTbWY'); 57 | }); 58 | it('should derive extended private key from master testnet', function() { 59 | var c = Credentials.fromExtendedPrivateKey('btc', 'tprv8ZgxMBicQKsPfPX8avSJXY1tZYJJESNg8vR88i8rJFkQJm6HgPPtDEmD36NLVSJWV5ieejVCK62NdggXmfMEHog598PxvXuLEsWgE6tKdwz', 0, 'BIP44'); 60 | var xpk = c.getDerivedXPrivKey().toString(); 61 | xpk.should.equal('tprv8gBu8N7JbHZs7MsW4kgE8LAYMhGJES9JP6DHsj2gw9Tc5PrF5Grr9ynAZkH1LyWsxjaAyCuEMFKTKhzdSaykpqzUnmEhpLsxfujWHA66N93'); 62 | }); 63 | it('should derive extended private key from master BIP48 livenet', function() { 64 | var c = Credentials.fromExtendedPrivateKey('btc', 'xprv9s21ZrQH143K3zLpjtB4J4yrRfDTEfbrMa9vLZaTAv5BzASwBmA16mdBmZKpMLssw1AzTnm31HAD2pk2bsnZ9dccxaLD48mRdhtw82XoiBi', 0, 'BIP48'); 65 | var xpk = c.getDerivedXPrivKey().toString(); 66 | xpk.should.equal('xprv9yaGCLKPS2ovEGw987MZr4DCkfZHGh518ndVk3Jb6eiUdPwCQu7nYru59WoNkTEQvmhnv5sPbYxeuee5k8QASWRnGV2iFX4RmKXEQse8KnQ'); 67 | }); 68 | it('should derive extended private key from master livenet (BIP45)', function() { 69 | var c = Credentials.fromExtendedPrivateKey('btc', 'xprv9s21ZrQH143K3zLpjtB4J4yrRfDTEfbrMa9vLZaTAv5BzASwBmA16mdBmZKpMLssw1AzTnm31HAD2pk2bsnZ9dccxaLD48mRdhtw82XoiBi', 0, 'BIP45'); 70 | var xpk = c.getDerivedXPrivKey().toString(); 71 | xpk.should.equal('xprv9vDaAbbvT8LHKr8v5A2JeFJrnbQk6ZrMDGWuiv2vZgSyugeV4RE7Z9QjBNYsdafdhwEGb6Y48DRrXFVKvYRAub9ExzcmJHt6Js6ybJCSssm'); 72 | }); 73 | it('should set addressType & BIP45', function() { 74 | var c = Credentials.fromExtendedPrivateKey('btc', 'xprv9s21ZrQH143K3zLpjtB4J4yrRfDTEfbrMa9vLZaTAv5BzASwBmA16mdBmZKpMLssw1AzTnm31HAD2pk2bsnZ9dccxaLD48mRdhtw82XoiBi', 8, 'BIP45'); 75 | c.addWalletInfo(1, 'name', 1, 1, 'juan'); 76 | c.account.should.equal(8); 77 | }); 78 | it('should derive compliant child', function() { 79 | var c = Credentials.fromExtendedPrivateKey('btc', 'tprv8ZgxMBicQKsPd8U9aBBJ5J2v8XMwKwZvf8qcu2gLK5FRrsrPeSgkEcNHqKx4zwv6cP536m68q2UD7wVM24zdSCpaJRmpowaeJTeVMXL5v5k', 0, 'BIP44'); 80 | c.compliantDerivation.should.be.true; 81 | var xpk = c.getDerivedXPrivKey().toString(); 82 | xpk.should.equal('tprv8gXvQvjGt7oYCTRD3d4oeQr9B7JLuC2B6S854F4XWCQ4pr9NcjokH9kouWMAp1MJKy4Y8QLBgbmPtk3i7RegVzaWhWsnVPi4ZmykJXt4HeV'); 83 | }); 84 | it('should derive non-compliant child', function() { 85 | var c = Credentials.fromExtendedPrivateKey('btc', 'tprv8ZgxMBicQKsPd8U9aBBJ5J2v8XMwKwZvf8qcu2gLK5FRrsrPeSgkEcNHqKx4zwv6cP536m68q2UD7wVM24zdSCpaJRmpowaeJTeVMXL5v5k', 0, 'BIP44', { 86 | nonCompliantDerivation: true 87 | }); 88 | c.compliantDerivation.should.be.false; 89 | var xpk = c.getDerivedXPrivKey().toString(); 90 | xpk.should.equal('tprv8gSy16H5hQ1MKNHzZDzsktr4aaGQSHg4XYVEbfsEiGSBcgw4J8dEm8uf19FH4L9h6W47VBKtc3bbYyjb6HAm6QdyRLpB6fsA7bW19RZnby2'); 91 | }); 92 | }); 93 | 94 | describe('#fromExtendedPrivateKey', function() { 95 | it('Should create credentials from seed', function() { 96 | var xPriv = 'xprv9s21ZrQH143K2TjT3rF4m5AJcMvCetfQbVjFEx1Rped8qzcMJwbqxv21k3ftL69z7n3gqvvHthkdzbW14gxEFDYQdrRQMub3XdkJyt3GGGc'; 97 | var c = Credentials.fromExtendedPrivateKey('btc', xPriv, 0, 'BIP44'); 98 | 99 | c.xPrivKey.should.equal('xprv9s21ZrQH143K2TjT3rF4m5AJcMvCetfQbVjFEx1Rped8qzcMJwbqxv21k3ftL69z7n3gqvvHthkdzbW14gxEFDYQdrRQMub3XdkJyt3GGGc'); 100 | c.xPubKey.should.equal('xpub6DUean44k773kxbUq8QpSmAPFaNCpk5AzrxbFRAMsNCZBGD15XQVnRJCgNd8GtJVmDyDZh89NPZz1XPQeX5w6bAdLGfSTUuPDEQwBgKxfh1'); 101 | c.copayerId.should.equal('bad66ef88ad8dec08e36d576c29b4f091d30197f04e166871e64bf969d08a958'); 102 | c.network.should.equal('livenet'); 103 | c.personalEncryptingKey.should.equal('M4MTmfRZaTtX6izAAxTpJg=='); 104 | should.not.exist(c.walletPrivKey); 105 | }); 106 | 107 | it('Should create credentials from seed and walletPrivateKey', function() { 108 | var xPriv = 'xprv9s21ZrQH143K2TjT3rF4m5AJcMvCetfQbVjFEx1Rped8qzcMJwbqxv21k3ftL69z7n3gqvvHthkdzbW14gxEFDYQdrRQMub3XdkJyt3GGGc'; 109 | 110 | var wKey = 'a28840e18650b1de8cb83bcd2213672a728be38a63e70680b0c2be9c452e2d4d'; 111 | var c = Credentials.fromExtendedPrivateKey('btc', xPriv, 0, 'BIP44', { walletPrivKey: 'a28840e18650b1de8cb83bcd2213672a728be38a63e70680b0c2be9c452e2d4d'}); 112 | 113 | c.xPrivKey.should.equal('xprv9s21ZrQH143K2TjT3rF4m5AJcMvCetfQbVjFEx1Rped8qzcMJwbqxv21k3ftL69z7n3gqvvHthkdzbW14gxEFDYQdrRQMub3XdkJyt3GGGc'); 114 | c.walletPrivKey.should.equal(wKey); 115 | }); 116 | 117 | 118 | 119 | 120 | describe('Compliant derivation', function() { 121 | it('Should create compliant base address derivation key', function() { 122 | var xPriv = 'xprv9s21ZrQH143K4HHBKb6APEoa5i58fxeFWP1x5AGMfr6zXB3A6Hjt7f9LrPXp9P7CiTCA3Hk66cS4g8enUHWpYHpNhtufxSrSpcbaQyVX163'; 123 | var c = Credentials.fromExtendedPrivateKey('btc', xPriv, 0, 'BIP44'); 124 | c.xPubKey.should.equal('xpub6CUtFEwZKBEyX6xF4ECdJdfRBBo69ufVgmRpy7oqzWJBSadSZ3vaqvCPNFsarga4UWcgTuoDQL7ZnpgWkUVUAX3oc7ej8qfLEuhMALGvFwX'); 125 | }); 126 | 127 | it('Should create compliant request key', function() { 128 | var xPriv = 'xprv9s21ZrQH143K3xMCR1BNaUrTuh1XJnsj8KjEL5VpQty3NY8ufgbR8SjZS8B4offHq6Jj5WhgFpM2dcYxeqLLCuj1wgMnSfmZuPUtGk8rWT7'; 129 | var c = Credentials.fromExtendedPrivateKey('btc', xPriv, 0, 'BIP44'); 130 | c.requestPrivKey.should.equal('559371263eb0b2fd9cd2aa773ca5fea69ed1f9d9bdb8a094db321f02e9d53cec'); 131 | }); 132 | 133 | it('should accept non-compliant derivation as a parameter when importing', function() { 134 | var c = Credentials.fromExtendedPrivateKey('btc', 'tprv8ZgxMBicQKsPd8U9aBBJ5J2v8XMwKwZvf8qcu2gLK5FRrsrPeSgkEcNHqKx4zwv6cP536m68q2UD7wVM24zdSCpaJRmpowaeJTeVMXL5v5k', 0, 'BIP44', { 135 | nonCompliantDerivation: true 136 | }); 137 | c.xPrivKey.should.equal('tprv8ZgxMBicQKsPd8U9aBBJ5J2v8XMwKwZvf8qcu2gLK5FRrsrPeSgkEcNHqKx4zwv6cP536m68q2UD7wVM24zdSCpaJRmpowaeJTeVMXL5v5k'); 138 | c.compliantDerivation.should.be.false; 139 | c.xPubKey.should.equal('tpubDD919WKKqmh2CqKnSsfUAJWB9bnLbcry6r61tBuY8YEaTBBpvXSpwdXXBGAB1n4JRFDC7ebo7if3psUAMpvQJUBe3LcjuMNA6Y4nP8U9SNg'); 140 | c.getDerivedXPrivKey().toString().should.equal("tprv8gSy16H5hQ1MKNHzZDzsktr4aaGQSHg4XYVEbfsEiGSBcgw4J8dEm8uf19FH4L9h6W47VBKtc3bbYyjb6HAm6QdyRLpB6fsA7bW19RZnby2"); 141 | }); 142 | }); 143 | }); 144 | 145 | describe('#fromMnemonic', function() { 146 | it('Should create credentials from mnemonic BIP44', function() { 147 | var words = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"; 148 | var c = Credentials.fromMnemonic('btc', 'livenet', words, '', 0, 'BIP44'); 149 | c.xPrivKey.should.equal('xprv9s21ZrQH143K3GJpoapnV8SFfukcVBSfeCficPSGfubmSFDxo1kuHnLisriDvSnRRuL2Qrg5ggqHKNVpxR86QEC8w35uxmGoggxtQTPvfUu'); 150 | c.network.should.equal('livenet'); 151 | c.account.should.equal(0); 152 | c.derivationStrategy.should.equal('BIP44'); 153 | c.xPubKey.should.equal('xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj'); 154 | c.getBaseAddressDerivationPath().should.equal("m/44'/0'/0'"); 155 | }); 156 | 157 | it('Should create credentials from mnemonic BIP48', function() { 158 | var words = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"; 159 | var c = Credentials.fromMnemonic('btc', 'livenet', words, '', 0, 'BIP48'); 160 | c.xPrivKey.should.equal('xprv9s21ZrQH143K3GJpoapnV8SFfukcVBSfeCficPSGfubmSFDxo1kuHnLisriDvSnRRuL2Qrg5ggqHKNVpxR86QEC8w35uxmGoggxtQTPvfUu'); 161 | c.network.should.equal('livenet'); 162 | c.account.should.equal(0); 163 | c.derivationStrategy.should.equal('BIP48'); 164 | c.xPubKey.should.equal('xpub6CKZtUaK1YHpQbg6CLaGRmsMKLQB1iKzsvmxtyHD6X7gzLqCB2VNZYd1XCxrccQnE8hhDxtYbR1Sakkvisy2J4CcTxWeeGjmkasCoNS9vZm'); 165 | c.getBaseAddressDerivationPath().should.equal("m/48'/0'/0'"); 166 | }); 167 | 168 | it('Should create credentials from mnemonic account 1', function() { 169 | var words = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"; 170 | var c = Credentials.fromMnemonic('btc', 'livenet', words, '', 1, 'BIP44'); 171 | c.xPrivKey.should.equal('xprv9s21ZrQH143K3GJpoapnV8SFfukcVBSfeCficPSGfubmSFDxo1kuHnLisriDvSnRRuL2Qrg5ggqHKNVpxR86QEC8w35uxmGoggxtQTPvfUu'); 172 | c.account.should.equal(1); 173 | c.xPubKey.should.equal('xpub6BosfCnifzxcJJ1wYuntGJfF2zPJkDeG9ELNHcKNjezuea4tumswN9sH1psMdSVqCMoJC21Bv8usSeqSP4Sp1tLzW7aY59fGn9GCYzx5UTo'); 174 | c.getBaseAddressDerivationPath().should.equal("m/44'/0'/1'"); 175 | }); 176 | 177 | it('Should create credentials from mnemonic with undefined/null passphrase', function() { 178 | var words = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"; 179 | var c = Credentials.fromMnemonic('btc', 'livenet', words, undefined, 0, 'BIP44'); 180 | c.xPrivKey.should.equal('xprv9s21ZrQH143K3GJpoapnV8SFfukcVBSfeCficPSGfubmSFDxo1kuHnLisriDvSnRRuL2Qrg5ggqHKNVpxR86QEC8w35uxmGoggxtQTPvfUu'); 181 | c = Credentials.fromMnemonic('btc', 'livenet', words, null, 0, 'BIP44'); 182 | c.xPrivKey.should.equal('xprv9s21ZrQH143K3GJpoapnV8SFfukcVBSfeCficPSGfubmSFDxo1kuHnLisriDvSnRRuL2Qrg5ggqHKNVpxR86QEC8w35uxmGoggxtQTPvfUu'); 183 | }); 184 | 185 | it('Should create credentials from mnemonic and passphrase', function() { 186 | var words = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"; 187 | var c = Credentials.fromMnemonic('btc', 'livenet', words, 'húngaro', 0, 'BIP44'); 188 | c.xPrivKey.should.equal('xprv9s21ZrQH143K2LkGEPHqW8w5vMJ3giizin94rFpSM5Ys5KhDaP7Hde3rEuzC7VpZDtNX643bJdvhHnkbhKMNmLx3Yi6H8WEsHBBox3qbpqq'); 189 | }); 190 | 191 | it('Should create credentials from mnemonic and passphrase for testnet account 2', function() { 192 | var words = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"; 193 | var c = Credentials.fromMnemonic('btc', 'testnet', words, 'húngaro', 2, 'BIP44'); 194 | c.xPrivKey.should.equal('tprv8ZgxMBicQKsPd9yntx9LfnZ5EUiFvEm14L4BigEtq43LrvSJZkT39PRJA69r7sCsbKuJ69fMTzWVkeJLpXhKaQDe5MJanrxvCGwEPnNxN85'); 195 | c.network.should.equal('testnet'); 196 | c.xPubKey.should.equal('tpubDCoAP4Ut9MXK5CakPFPudKAP4yCw6Xr7uzV2129v2LTa3eBoPoUGMqi2y3kmh83oRGX93m7EehB6LWan5GTSVD8yUnV5Jc7Kjzfa3Zsf8nE'); 197 | c.getBaseAddressDerivationPath().should.equal("m/44'/1'/2'"); 198 | }); 199 | 200 | it('Should create credentials from mnemonic (ES)', function() { 201 | var words = 'afirmar diseño hielo fideo etapa ogro cambio fideo toalla pomelo número buscar'; 202 | var c = Credentials.fromMnemonic('btc', 'livenet', words, '', 0, 'BIP44'); 203 | c.xPrivKey.should.equal('xprv9s21ZrQH143K3H3WtXCn9nHtpi7Fz1ZE9VJErWErhrGL4hV1cApFVo3t4aANoPF7ufcLLWqN168izu3xGQdLaGxXG2qYZF8wWQGNWnuSSon'); 204 | c.network.should.equal('livenet'); 205 | }); 206 | 207 | describe('Compliant derivation', function() { 208 | it('Should create compliant base address derivation key from mnemonic', function() { 209 | var words = "shoulder sphere pull seven top much black copy labor dress depth unit"; 210 | var c = Credentials.fromMnemonic('btc', 'livenet', words, '', 0, 'BIP44'); 211 | c.xPrivKey.should.equal('xprv9s21ZrQH143K3WoNK8dVjQJpcXhqfwyuBTpuZdc1ZVa9yWW2i7TmM4TLyfPrSKXctQuLgbg3U1WJmodK9yWM26JWeuh2vhT6bmsPPie688n'); 212 | c.xPubKey.should.equal('xpub6DVMaW3r1CcZcsUazSHspjRfZZJzZG3N7GRL4DciY54Z8M4KmRSDrq2hd75VzxKZDXPu4EKiAwCGwiXMxec2pq6oVgtZYxQHSrgtxksWehx'); 213 | }); 214 | 215 | it('Should create compliant request key from mnemonic', function() { 216 | var words = "pool stomach bridge series powder mammal betray slogan pass roast neglect reunion"; 217 | var c = Credentials.fromMnemonic('btc', 'livenet', words, '', 0, 'BIP44'); 218 | c.xPrivKey.should.equal('xprv9s21ZrQH143K3ZMudFRXpEwftifDuJkjLKnCtk26pXhxQuK8bCnytJuUTGkfvaibnCxPQQ9xToUtDAZkJqjm3W62GBXXr7JwhiAz1XWgTUJ'); 219 | c.requestPrivKey.should.equal('7582efa9b71aefa831823592d753704cba9648b810b14b77ee078dfe8b730157'); 220 | }); 221 | it('should accept non-compliant derivation as a parameter when importing', function() { 222 | var c = Credentials.fromMnemonic('btc', 'testnet', 'level unusual burger hole call main basic flee drama diary argue legal', '', 0, 'BIP44', { 223 | nonCompliantDerivation: true 224 | }); 225 | c.xPrivKey.should.equal('tprv8ZgxMBicQKsPd8U9aBBJ5J2v8XMwKwZvf8qcu2gLK5FRrsrPeSgkEcNHqKx4zwv6cP536m68q2UD7wVM24zdSCpaJRmpowaeJTeVMXL5v5k'); 226 | c.compliantDerivation.should.be.false; 227 | c.xPubKey.should.equal('tpubDD919WKKqmh2CqKnSsfUAJWB9bnLbcry6r61tBuY8YEaTBBpvXSpwdXXBGAB1n4JRFDC7ebo7if3psUAMpvQJUBe3LcjuMNA6Y4nP8U9SNg'); 228 | c.getDerivedXPrivKey().toString().should.equal("tprv8gSy16H5hQ1MKNHzZDzsktr4aaGQSHg4XYVEbfsEiGSBcgw4J8dEm8uf19FH4L9h6W47VBKtc3bbYyjb6HAm6QdyRLpB6fsA7bW19RZnby2"); 229 | }); 230 | }); 231 | }); 232 | 233 | describe('#createWithMnemonic', function() { 234 | it('Should create credentials with mnemonic', function() { 235 | var c = Credentials.createWithMnemonic('btc', 'livenet', '', 'en', 0); 236 | should.exist(c.mnemonic); 237 | c.mnemonic.split(' ').length.should.equal(12); 238 | c.network.should.equal('livenet'); 239 | c.account.should.equal(0); 240 | }); 241 | 242 | it('should assume derivation compliance on new credentials', function() { 243 | var c = Credentials.createWithMnemonic('btc', 'livenet', '', 'en', 0); 244 | c.compliantDerivation.should.be.true; 245 | var xPrivKey = c.getDerivedXPrivKey(); 246 | should.exist(xPrivKey); 247 | }); 248 | 249 | it('Should create credentials with mnemonic (testnet)', function() { 250 | var c = Credentials.createWithMnemonic('btc', 'testnet', '', 'en', 0); 251 | should.exist(c.mnemonic); 252 | c.mnemonic.split(' ').length.should.equal(12); 253 | c.network.should.equal('testnet'); 254 | }); 255 | 256 | it('Should return and clear mnemonic', function() { 257 | var c = Credentials.createWithMnemonic('btc', 'testnet', '', 'en', 0); 258 | should.exist(c.mnemonic); 259 | c.getMnemonic().split(' ').length.should.equal(12); 260 | c.clearMnemonic(); 261 | should.not.exist(c.getMnemonic()); 262 | }); 263 | }); 264 | 265 | describe('#createWithMnemonic #fromMnemonic roundtrip', function() { 266 | _.each(['en', 'es', 'ja', 'zh', 'fr'], function(lang) { 267 | it('Should verify roundtrip create/from with ' + lang + '/passphrase', function() { 268 | var c = Credentials.createWithMnemonic('btc', 'testnet', 'holamundo', lang, 0); 269 | should.exist(c.mnemonic); 270 | var words = c.mnemonic; 271 | var xPriv = c.xPrivKey; 272 | var path = c.getBaseAddressDerivationPath(); 273 | 274 | var c2 = Credentials.fromMnemonic('btc', 'testnet', words, 'holamundo', 0, 'BIP44'); 275 | should.exist(c2.mnemonic); 276 | words.should.be.equal(c2.mnemonic); 277 | c2.xPrivKey.should.equal(c.xPrivKey); 278 | c2.network.should.equal(c.network); 279 | c2.getBaseAddressDerivationPath().should.equal(path); 280 | }); 281 | }); 282 | 283 | it('Should fail roundtrip create/from with ES/passphrase with wrong passphrase', function() { 284 | var c = Credentials.createWithMnemonic('btc', 'testnet', 'holamundo', 'es', 0); 285 | should.exist(c.mnemonic); 286 | var words = c.mnemonic; 287 | var xPriv = c.xPrivKey; 288 | var path = c.getBaseAddressDerivationPath(); 289 | 290 | var c2 = Credentials.fromMnemonic('btc', 'testnet', words, 'chaumundo', 0, 'BIP44'); 291 | c2.network.should.equal(c.network); 292 | c2.getBaseAddressDerivationPath().should.equal(path); 293 | c2.xPrivKey.should.not.equal(c.xPrivKey); 294 | }); 295 | }); 296 | 297 | describe('Private key encryption', function() { 298 | describe('#encryptPrivateKey', function() { 299 | it('should encrypt private key and remove cleartext', function() { 300 | var c = Credentials.createWithMnemonic('btc', 'livenet', '', 'en', 0); 301 | c.encryptPrivateKey('password'); 302 | c.isPrivKeyEncrypted().should.be.true; 303 | should.exist(c.xPrivKeyEncrypted); 304 | should.exist(c.mnemonicEncrypted); 305 | should.not.exist(c.xPrivKey); 306 | should.not.exist(c.mnemonic); 307 | }); 308 | it('should fail to encrypt private key if already encrypted', function() { 309 | var c = Credentials.create('btc', 'livenet'); 310 | c.encryptPrivateKey('password'); 311 | var err; 312 | try { 313 | c.encryptPrivateKey('password'); 314 | } catch (ex) { 315 | err = ex; 316 | } 317 | should.exist(err); 318 | }); 319 | }); 320 | describe('#decryptPrivateKey', function() { 321 | it('should decrypt private key', function() { 322 | var c = Credentials.createWithMnemonic('btc', 'livenet', '', 'en', 0); 323 | c.encryptPrivateKey('password'); 324 | c.isPrivKeyEncrypted().should.be.true; 325 | c.decryptPrivateKey('password'); 326 | c.isPrivKeyEncrypted().should.be.false; 327 | should.exist(c.xPrivKey); 328 | should.exist(c.mnemonic); 329 | should.not.exist(c.xPrivKeyEncrypted); 330 | should.not.exist(c.mnemonicEncrypted); 331 | }); 332 | it('should fail to decrypt private key with wrong password', function() { 333 | var c = Credentials.createWithMnemonic('btc', 'livenet', '', 'en', 0); 334 | c.encryptPrivateKey('password'); 335 | 336 | var err; 337 | try { 338 | c.decryptPrivateKey('wrong'); 339 | } catch (ex) { 340 | err = ex; 341 | } 342 | should.exist(err); 343 | c.isPrivKeyEncrypted().should.be.true; 344 | should.exist(c.mnemonicEncrypted); 345 | should.not.exist(c.mnemonic); 346 | }); 347 | it('should fail to decrypt private key when not encrypted', function() { 348 | var c = Credentials.create('btc', 'livenet'); 349 | 350 | var err; 351 | try { 352 | c.decryptPrivateKey('password'); 353 | } catch (ex) { 354 | err = ex; 355 | } 356 | should.exist(err); 357 | c.isPrivKeyEncrypted().should.be.false; 358 | }); 359 | }); 360 | describe('#getKeys', function() { 361 | it('should get keys regardless of encryption', function() { 362 | var c = Credentials.createWithMnemonic('btc', 'livenet', '', 'en', 0); 363 | var keys = c.getKeys(); 364 | should.exist(keys); 365 | should.exist(keys.xPrivKey); 366 | should.exist(keys.mnemonic); 367 | keys.xPrivKey.should.equal(c.xPrivKey); 368 | keys.mnemonic.should.equal(c.mnemonic); 369 | 370 | c.encryptPrivateKey('password'); 371 | c.isPrivKeyEncrypted().should.be.true; 372 | var keys2 = c.getKeys('password'); 373 | should.exist(keys2); 374 | keys2.should.deep.equal(keys); 375 | 376 | c.decryptPrivateKey('password'); 377 | c.isPrivKeyEncrypted().should.be.false; 378 | var keys3 = c.getKeys(); 379 | should.exist(keys3); 380 | keys3.should.deep.equal(keys); 381 | }); 382 | it('should get derived keys regardless of encryption', function() { 383 | var c = Credentials.createWithMnemonic('btc', 'livenet', '', 'en', 0); 384 | var xPrivKey = c.getDerivedXPrivKey(); 385 | should.exist(xPrivKey); 386 | 387 | c.encryptPrivateKey('password'); 388 | c.isPrivKeyEncrypted().should.be.true; 389 | var xPrivKey2 = c.getDerivedXPrivKey('password'); 390 | should.exist(xPrivKey2); 391 | 392 | xPrivKey2.toString('hex').should.equal(xPrivKey.toString('hex')); 393 | 394 | c.decryptPrivateKey('password'); 395 | c.isPrivKeyEncrypted().should.be.false; 396 | var xPrivKey3 = c.getDerivedXPrivKey(); 397 | should.exist(xPrivKey3); 398 | xPrivKey3.toString('hex').should.equal(xPrivKey.toString('hex')); 399 | }); 400 | }); 401 | }); 402 | }); 403 | -------------------------------------------------------------------------------- /test/legacyImportData.js: -------------------------------------------------------------------------------- 1 | var copayers = [{ 2 | username: '123', 3 | password: '123qweasdZXC.', 4 | ls: { 5 | 'profile::4872dd8b2ceaa54f922e8e6ba6a8eaa77b488721': '{"iv":"b1Nsi+8CC9y8yuyMDo8ptw==","v":1,"iter":5000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"mjuBtGybi/4=","ct":"cxWEUayLM5gKDjxdIeYwc1WFfm8CQn606QAof41LkW9fy1w+VwuN2QyQ8WKSk7HFnCVGsKqMlW3bzUUlzTAcB9uz/6V1y/HLyY8v7zjVFk67QFLHt5gDxnwUZTMPVsLjVd4ORhCBstekd5b6OL4jN/YPzCo4U2zjt2UdciKzARWUWjnPUj03qaKnvOnabtGcSDDdlsMi+qHNfsttJxjKhtu+Vw2S9Sl48BaGzE5dtn6uxABXYR0LVyfW9o0LSE4HlXzE+Pxs3CXc0hJfKsth5QLvh8XsvqHwIlp0kMsuRUcZ86jQ+b1+kdBkv911ppbdV2eFB2IPw2p9OY+GC/s3zCzaJ0ov/qarvJ4rq2yFfg05akptBcC7BE0+SpKRoQuwNpKUJRhdcjqzMW/8bEbhrZ/5Ucy1/9ijhedWHplKQvdbVd+TXtqhCqMjx/CvaGP33l+EMyQcDKpUFglQpw=="}', 6 | 'wallet::4d32f0737a05f072': '{"iv":"zooCmnqINutmJ2HAOj4SqQ==","v":1,"iter":5000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"mjuBtGybi/4=","ct":"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"}', 7 | 'wallet::7065a73486c8cb5d': '{"iv":"T3mXsRTEfMmDO7yvooHuSQ==","v":1,"iter":5000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"mjuBtGybi/4=","ct":"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"}', 8 | 'wallet::8f197244e661f4d0': '{"iv":"ey0b5/szn+jBexTsZokzMQ==","v":1,"iter":5000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"mjuBtGybi/4=","ct":"9Rn+6r8b4DwdA/jFGNmfI6GVCwTlAMCa5YTa+fWZuO2M2gSkA1MNCEGPvy65d74xEGX7aybF3E9KPL4rNxUoAV5hCkndkbA20Cwp06k/5HS9oPdnCMNPdzH8skrPvXZLCTzcXsJZsA8F4TVYiOLGycBEdGA63Ki2CVjbG+xZZvvAI3WCQY3PErZetISX8ciU8AuzUiiYkfn9w+bKu2XP4T8JzVP+yf74JwZY8OJAeEIgPCbBR/HN6JNDpUBi5bC9dFmGNI+oreUBTUle0g6WYBfgd9YAMPf9IySRhIaTuj3vJU+ROTleFiMtoa40BxMhtJgIItCvqahiszGcIg+a+mFDvZEd9FP2ZhhGSzMmsScL4tsqES1CvnmLl0Vg+SHAZkbdyajpE6MTjEI8SV2NWqrpbziZhNJdIGaS/GzpzzKEwejrCmUK6jww+UT5it51ltI7+OEmhLUzgz7eLZ7yrRL+c6F9V8ndwkenOe7plXew4NKQT1s655FltVwr/UNjemwSPmx133lqajilL6emafMTbO5njrFmvaE4LCS54nXqCRuCXzQKnpulDWxWkXr61qzeAhsKTaChO/WTBtoV7V3g8wyEuWTKJJg/DeRN4JUjM6RxU+lcVa5WamOYCmWIWIAwKihsKK9xxbiQsDDI1uw/tdzIXwBhs0SYjK4J+HvpSznT0mbaCKv7ldDkngNlMxjAOYlzMbnwtAa7/HzkfW5Q20NO1jUuv3zJO9fjnDT71OLRMI193RXHYNdCOXj017Kduq2bFhJNnC9kID7cyU7SVpT6lUZEeq+mtMokHy+tzcF7kIkhavs6pyF5D89O7HUX3JF+1kL6Wp9J9U/wmCZCSuFvspgG2aRH3ZbGwQ4F+qNXyfDsHDgEf9Z88vWSeYRhZb3rHkrPp+WasSQRqi8wZmxyHKtzeKSL7bM05MVRdWZfnIFu9gn+vo6QbmvJNlFHnY3hWGuCYfj949iwprW4df1fzW9z1dPwil9E7UP5tdkUZb6wKAeQvgBBNw29eRrMw4pv1ngwQxOUGgUQAEKANu+SFVbHqRwWu1CI3b+n5lnJWmGNw44o9PRRqzgBmiV4G+unbmUsYh9JwYI3MJhqev0i9fNtEKdoeGetBlMVUmDanil0Uo9ealPJfzKt4YyWgw3gB+vTXzLGipXchG84sH4OrJH/oZ67xLCffzsmK2PiaPAnVYWIOOj/MUYeAPJB+SqPzz+FOoc9WlF+xOGIHYwr62I4A3KPROENQdt3QdZo3ckzvAxXRnvg08WQZ5KCdV24Rnz8v4/V5RgLYbhJDKmAwwv8hSnOwThdoYCuxzhCkH+bO/+BuwEdPd0asHxtoVTtRMMGkgNZOmcb76/R8MoV4uNjX4RQC3NFXrVaqDug3dpL+81muc28oVU7Cq7bcwZo2gXgtU2myaikfXrxFpv4art5Qi/Pc8P2G76xD5r8o+jdriRAZhf792eOb2uluUOZfvsgZrhjg0vGo7u2bV/kCi1PZFOAbdbqWfm+L9WMw9qraW+TJqzLPyl5+2bxP/tIzxanhXYsNR/mzV2PYp/XEiEUC7TFC4gWFEKJif3kFdoPWt8YL2BBeirl8du3OwqMNdn8+aRXF9qHyiEasOVUDYjo5rhxur53Wafl/jGfjuLU7AZojD0AfLodaeQgYWwDbmZWZFKl9uyxpiuhgr7bGCoSy8C5ie4O5ss9KsvdGGAx+IVYWzCVk89bBtlU/4uxNKAkDdMMSkRr7SJORjrtIB1b77DNLD8n2KHoPsDDTj5LMsUhy0s54Ror84wYLnNkmXtNDD0jM3iyGMY45/RgWGbWVaU9ZIDN"}', 9 | 'wallet::e2c2d72024979ded': '{"iv":"SE2jsjnmAd27S8dyvM+/AA==","v":1,"iter":5000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"mjuBtGybi/4=","ct":"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"}', 10 | }, 11 | 12 | }, { 13 | username: '234', 14 | password: '123qweasdZXC.', 15 | ls: { 16 | 'profile::19510bad7f0638eb36548f9ad54f76fdfe2254f8': '{"iv":"ldPQwfVgrbBbxqyD0t/fCw==","v":1,"iter":5000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"mjuBtGybi/4=","ct":"XYUELIWyxxAmuRrot6wXAG7f9ccAaatuI4Cuy6eVIjyYXCuR7F52DlG/cr2OdkiR+t63jLeGexOmyD/eq2cU8AYAK8giA8D3O+ogZrciyHGio1JQt+3iaJ8rj+4g/YlXC9Zx2gWPD8cToy+W3aMjBD1QCTsw27B6Lr6cp3/21Ireu3c60YVYRUH3cUF55tlH2ky50BftqANgCUjPUyb0LUoMaw99du0rgzat7RDbEWVUeQFvSN5UIUssVxOyO437bdsXWE7Ba9SQPsTHGToP+6MRh42m319SVzblZjCHyLwo6NAfDypRl5mVcAmCv2RLTYeQS+Ro4Ie57HRt3Ngh2DNBAm0TOGoLLr6rhMl1Ac1A1BGRMFDq3LEEJARzq0+dsz5WcX8t4lQ/"}', 17 | 'wallet::4d32f0737a05f072': '{"iv":"JyZc5viMPjPPz11HcchsGg==","v":1,"iter":5000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"mjuBtGybi/4=","ct":"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"}', 18 | 'wallet::7065a73486c8cb5d': '{"iv":"7j5Z78zSgRk6+5nxkVtq0Q==","v":1,"iter":5000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"mjuBtGybi/4=","ct":"dCifjzWmsHqBx0y2NKYxvWbp5QuwhxZgnsWLUoJezcdaqY6RWfIXpRDxaggETwS8KtnAywV9bL8SDzkowQnKzs/xdkvqInjRTgvdDF2lxwoUhUbmT8AhFio+XMssQxXRcc82NMI3+YlPTuO/HmDUeniLmp5iHLc48o5VT1SeWV557Wh+MyIg86+Zvw0/BZTYl7JrTZtur425j62jY9zVkaB8mdQR1QYdTqJ3Utwozute8NROIs4p4aZAU/rSkr4knylSZKOwX0//pCw0Y4glPQeRKm7EFwfG+UZIQH248pNG9lmzRbUAxN020cgHHiQ0PJYUd8WfjpLrM8Vuyfqrr/ZY+ZteQXnsVOODPcwXXGEeHrLcfKWxsy5n/nrmMjN/auLmMPJY4furl3UG7fcCV4W+RbuJrA6I7Ld3XtSMLLwVwxSq0tGRELhuuzM01ZLV7KJA6McgJPPetNTLE6LBt9LUtUCUE+tc5OmqSKsxG7UWbDdh59kP5om2g3wn9lZh8z8+KGjKOWkeaYxVNNHSmR1oE6/4qouLqjhlaF0gERRGu0GwHUG2ytgil6tTYzWjpFQpa3RsR7TnJqHMkS66h4Kw5ausWHYECoNntujyriNzgn4w4vtTC1Wm4OjQwN136ywbXJ6GMbfbYNX9XERv3VKLngzAPTbJpPbbbVs9AECx+kZiSp3FU58DLXqQyg41KeGfqFjPjrB3g1HTi7Fj326UR7ofAGyXkiygnT/13zNVoX++wrAEcImJvBcH7zwnuA+xNwFrKJLKeTEptYcnMLHqYp8kges57CaAkICD/0Lp+RclFe3xKsDtqXRLPKE3ALlBSIDhLDA2V5fDN8vR1f4Ks9EHRh3FBrfoSI2UqTnDeA0uASIk28DtaDPLeHZreGNmAaF4oV8k/UJd1fLQLaogzRU9L2HTQSe9zowLbqZ2grpvqm6dDIVPNzkGTJgWeduilA/lVKitUoGm3unSG8PcJb6MnqVhAkvrQvizM6GpkxlMpRW8ZKUVbVY+3MUZSvmDTCilPmOm70rfToacxDC/RvbKMiqyKMCJQNEyTMm/eUw+fYQyb7WouGzC4CrahaH/kEyYPmUSubVw+kGoXbX/mjyPOGGDjvn8qspKpSqJ/okqRMrISrKZ5G0UAjkaMa4tWUzJXMx3dtF6tPuNzJ17s4Irr0SNtkJJL+fMn4MCARfhPJmzU6XPzFkb3B0eOrPtMnRoko9NdVJwsOSibSs2Fj/1/ryCF0SCQDQAaWfGhIDey1xh8QlQGchXOxkQa0RSKPOtRk803b8WfZTOGYjRr0P1ZdkQxSl2m6E+mdQ+dlKGhoGVu7COJ1+7mO9I02m8VHh0ZUnW8HOKts0JKaVV+u+NbYHEXXWegcCnVB7lkbVZHCmptl9j+Z8aVwHjn0/wUt3qRo/2FNUZhq83J5wEKjqUr5o/A2wkwquKY8FMHp/6vM8NO7/HAT/9N1ggecRR8GGIYEnsJXFqsqGuROzRWLruX43cWO7tZ90wlbWNHeTeJfKckMVd8jEZexlfJEipN5PUPbZCShUsnK6RAxPgU0U+bNks4YaalpeLsbeDtnbyIXskyOH4gc4U02g9pC6xL3SvuJbDhfSoMffzPWePHVAACQYYhvf8LMdR5oTiOsq7xXKDFHnep6C5DrugYm63ppOeCPd0H5cJUhSTDEXXta8Ba0nksQYP0lkGZ4+eP5qPpZddQrLFWzHBzb+cguAGH6keeL3F4x8n5xVOhEGRGcfzcC8FJrcQ0tKQ9NRByFNcSM8uHwj7osCXahv+lIdKZnCgxrwvWyB+Ku+UyrJrK3ZSk5kCRXpB6ErgCJeRFy5liEyPvaa6H38i0Z1mjEwzdAVdMPDzFwgZilW+r8wdUXpe9/DQ0E6WQCslh5FUoS0nhUkQcxCObuDq/HFabLhtiVQRiYwZz2moLst2AZUnZQkuND/fh8Hjv2932huGJai5v5WFwUlyfCD4RqXREGuOaKjqjuui0xcM6GOdqIzhMERU18vyF7J700IlcdRHkpxbDYTYf0x7uDRh7+Ws7ovMxbsEIGdbBjVe52QidSfpGWBE7i4g4+wzbBl/U2NcxhudHTsUVvdT/bkUNbYApfcF+lrj32JVaubaM53UNQrLPUViJZuWvENgbd/94Zuz67szhiiDNLYcASvSaILET+CSkn4WYinafhMvRFzIpapX08Qa45UZ3WYMoPGaCkV4ymRTXRxn3OedJY69Q6R/yqmNNJgUQ2FM2dpvnpwmGZzOLszLyhzXTfbdwpogB+bm2DN027qMJVBqsNOtBoOQrZbKHhrZBwJyE6AOj1UQlVRFTKHu8yqYcFKnHV+n5gZ4OERPLifXMkoYysnTNnWdYaSJgKbsk4hw0mhjs5xGzeZbeoKH55O8VYozyWiRTUF/bIajpGy6ZM5+YGFL+1v/sHKCRixNOxPMXr8coGlvFuyC12CWV/Ab9EvAT5DIcDQFmbBFX/3qo1eEBToUbGDzJOCp41+iQ69RosoNwKkrfoktAPZ0zG9OSLpBgkdNv62jIwL7eth1tN5lQHbTnsKjFlS1jDW2HbL74ynYImEOWXM1nwkPHHaE/BnY9dODK0b7xugAXmGbiw3enmZ5r4hLqd5pGv87GZqonpoi1kvpsr2PnEOq2v4Y/rfxekXxPva9iyCDxIGx7z6OBbuVkNfIU0Vs10Llx5PWQ7Pn21Tf1TlZE21zG3r4qQraL62X6g1KTza3S9rkWCDO3EvF34hlFRpuG/exO4Pa9lLIOPxpU0nEJxDw10imV95UVuI94U87yvySU06OA3HbktUoPv39v4GyT8z7iq1qZ5qoqdsGT3Adn7eNsIVPAPmtJ6cqx6JQPfMZir5SAabD40EQZTyG4Mz1XTJ7Ltz/IB0GPXRLqD2t7NO0J3JA8f9isa7Yt+UL5TB96tYI9waxhNV131K/VqtiPrsJ4YwS07bMwXEyuMEeL/7zJB3msfR1u0ZOaCL0yogdh/Zx/k9Xg5JbywrfbACoPX0PRxzcPe0csUlMLfQffYeX4+W4UhdUyJ4+d5F2aHaK+Iihk+Nbdgryqi4BDbgNtS/sOr7skqV+YUBbJ+WcFuUJ7Zp3kSh+SDSObWkLazfS+7xogvOI1O9p2pg2BLxRWPmOcOCoAvRCDb3TQOg/RhCGw9w7coCVq7WEkE1iQwZk3hwNpTbP6jX2rHM2okjIw8KW8oxyQYoy03MdQthSMNtoqyg0VpjsCg7zvlBKNPg4vdNtEii0Q6rOyKC8L/8yWwituzrc/5K90hlk8V5G+197/av5oYdZjzsi+kLk3QjAUEMREkmL7sXjAT3f2iMcnexOz6cgIiNQ7YsLwXhPosopUCLdPXyUV+y4mW1rp0AD3unTzM9I8/kfYZprIYt0qXZVsnT0xYfxqWQo5Xtl+EOUUtVedIYqFTJa5NkT2kE6NDKMeKTA7lCqXoE7+Ft26JpKkYBGIgr9PpIifQF5DC+j4IrZMOdQIQj8VOX7OAO8Fo2mNNe4tJbt+NHrKuz2LJF9Ptd0O3lLsuZ++Gvp/cLsGXk7aJf2j4LYTiwJPXz0dwrqF953o1ynAk7UdyQcI9Bc4MbVraHgLjEnxUFGABZfNMPuH4Gxqah6h+HPHlTP41SMiCoXFyjvikenpbQxQySyWscfKt7Ekp4S8IHbflQ7XcHYR4DgoqCUu6yTnDNZ3tQOl7UvUOpU++zYNmrCIgw6WGGretq/RkrcdgaYO0xrfUeXKXn9VZ7DE9OzJ3wWrZh+oWMPnwSPcMJwsO6c/Ca+IBNz5Cgro9uYxbA2f7Im3Wj8gfx+tJUhwdQ5v+AYaXwJw4BNfwe7Kg9mLU5y5M474Ae+1rlFSE+bx1gT5yiKexLS8qYFGMxA+x2NvWrBHxHL1L8AvvMfxy0k45bL7ELGwIkg8YOO1deSDoY76KpMt4LYdYmDIHdIVyoVcPtRRD5xHbjU1xfB6Y23Xj1MkUFNxauYk3fbSsL9oUwXFU/zM6Ygac29GNmVxs/dhHpdUH7tIRMIzDkawxP9W8fwP5ahWGfK0FCXa4L5zKu02XJqTi97bOjNZ/zTkWI9seKmmChp2p0WAnpnU/8ngbygkVQBBaWpcPKZB8R7pf0OvOxyNI0FTbLHr+o1fDeFgC13og46aINhy/mo/xFbvGloQMFFMxd+X39JL9RprMIQJJUSgrpXv+oisvD/xAYEA2l9pTBsMzu3ud1q446jpmRmSGbTVoHc+0fYO0XS7Np3mX0g9j24JHaKHjTd9WhZO+G2ChX1kdHJjji9DGrBUqvxCRyDzzu3CCUzozxZPa2rBYZDwoySEek+mnnu/5zdJfYk8yRrnqzebb6Alpw5r8y3LiDh824UacOQVcBMToXGgJ7qHZQGZN4pEpnpXElB0YojHGV1lgcubQ/uRTq7r47ngOJgLU6NH84NqmYquJmpi5wZhXBV4ospJZrAQ1jQed+5uMZtf3iFPOG7gdul1FvmguUQfbuAApmenEMBJjPiitZHiMQaLx2sNizIVk6inwEOKf9YTcZL2am49s330WvNji0qX9Ux3XLyJXzlVHlNEHc7UrQteIrWIApetz9CJzuDrg1WrrU3rF/k537XEeF2y1S3uIKmKqbbO5x/7GZllMVAlt+yVEZCBP6Pm6NdRligwz+qXrBPWtKxxTOk22GN6uwmOvTd0ocTMRZgqOu1Jx8nZf871LB99SqbZ/3ZnzjWLxzKWk3T84CZ24f0g0GwBRRpWHqnL6ivO9qeze/eLmEnOavrt+oh1dOuaBdP89NTnN97ix7BnSppWVl5XfYloy5A36nRSGgLykbtSrK4i30MO6ifpiXrsyArBB+FzylUaKp+cSy5jjCe72y5tPxbMN/dhTkQZCNcq4vjGbNM5vu5J97hiCzFM6naiBvPEdd2nwSfHRFpQhNB+A44EYOFubSDFi/auUz920m+Ff6ZmY1hEq6EOLR+LKnycfIEJ2iTa9EWAI4p0fpzQwOUH0ziSMnWIulJ0yosIYolt//8Usj55d/G9KFiJErfCmI+YL0rXLjqxgj9ecWIr3c9qCYBw4erUTQA5UFjgvIBMUSIV0q4ZiARYZBLGJwdT0+O8wHCPLhw0koCO2Bxsk1cmyY8eSdBQNRa+R9jR4LoV2ORxNdTGvSFVmuOvOkuEGYXowkJi+7n4ZWXtmQEx/C4f6JMYt0HoXnbShZW6/GmLtgsAVbLRjmPYljQj7QsdxsV60659KdqhHNZp5tmaz7emFq/ROFTBLqTXinHM828HJFcb9aSwAkKCGnpQwF0qRnR1oOoLmJgILpaRrOTEqIHyiytxrFyJ07794lWBpsruki/GSaAOLGaRZfHZFTHRSmt/XdXkY/8cgiwFIM8e3Tg2aPu2yMpLZ9dV/eqOjEG6FASvals6S8dR1EUHhp58PX3JQ9BqS0KlhN1oraUcF6XpgVNRPWkfCwpE2HPhh77vEB7NrOhdUiQvOIjIu4/+WrL66KpaiRxZqbCQhMhlWXUBIfobEI7wdboIuiTM4Ny8eStq37yj5ZdOY1dnl5E47xPxNr1tidD21F4H2QA6GCDHWHdh7/u2iANnBj5sB8ZgiH3pSbb0VmjcR10gnMrG4P7t38AwRBZXBmZRWSbkoHxIv9ldEMHNhLcGk0GfdlFtCLG8p8TwVAf4PyooChru/6M9jMwnLm7mnOfHsWYTsxLKqBiK4zNzX6qag4EwyKtm3cju7ViP11gRd/WwFf8F42Lf14q83cKkW0ZU95bzOh5mGw/rk8+iPRV3T0YgpGGlvtaliGk+GqZxExwb7UYMYA2WzynufAyIcTJflxfvfA7z1AoZaoS8qtQz809eDKIOr63W4Wk3yA6NXw9wjtaO/ng7q47tgLQ3zr6YCfYIsHC6yk3+A/cFK1Vgd1fIr7asiRHeafVpReSRy0nkg2W/9K34ApZTt/mCEKnwVi7DKLp6CqRbb0B1iL18zSfJ7VmJ2rt1mMzHz0EUATRvuS8Fb6cpplVVwRhcOV7E+fiM2YypwSgzzeil4wL5wuArCPg4OH8gPtmofw5CgEabwfqB8eDvksE+1ENBwVvHFo4BB4A09m9PLxoyviVMSdxe31i2ZGGbF1U1v8iBT219YQpVJtKMMoK47lV9F326cALt8GY1s5urlk//KJqNZ58hfR9E/xA4EK4orsWyFgOlQ+Cg2jsOtUSseRC9BL03+hixkeAbizwBjVsBOm8/T7aSCa9Uub1oQLFmGkta+1fWQdJSMdBUFIHr+QaIMEQSORzCNoEg/OWLOiYt4lybTM48CihYWSFd1XlMRw09tMefPZdCn8fHEzLylyqxfeyLhvTk7i6vjvsZDQEUaqXoVzPp5loNyUYXJ1cKd8pzDpeqqobePleBmdhyEJr3Qf8LSHtVnX+oc6XRiQQ9qOqPeS2uXMAUot/wJgV45k5USZMMwBAfuwZEB/ePMJP5Wy51B+EyR8OgrK0g2w4qkLdrGSU/HWrQuLjnHWY80BrNjeDzmWdUVnN4FvN3epaW8nLovoRCOab/RtwCcBzX+dZYjmlsRmLtIbC7F5Ttjs2qzvuXi74H8z5sfdv72Av47o1ttSttH/H5gPcbxAYkgcPIcNd6v3oc7vq3Nn+gLisoH1fgIrg6dkWN203S83Vnod0RwA1SxMBIk8sAjDiDWuGX8qsEdqlNNNOTrbMkLKcJTDMd0SdJ46s/U7wldsIh5Zo0rcU+kpUXfuvaR7NWPUbEWwcdG2DbInHjJ9CNRNDbEduD6YQbfRciCwda6MqHnB4UYSn00wFXWZa6PmoTrWMTvFonSp5bccuh/vqhIiYipqiVv6NqYzYsHzLXYG3DBLBn7GAccKjS6IChIHbI5899c7yvQ78Bgq/eSBg3EO+V4SJopz310478bjt/QEuN2Nh/8E+XHGUtx6tjccQixuRmwQHA4qKObHQ1RZ+onPV93EMHvALUjwATbWq5bAmQzDhUPsW5oH6PRUMjjOZDotp/vshjCY1IeTWgi08NvMiRp5tyWXmUFMz2/dexC0NQPCG6t+cLEpO9zNTmeW7DwbLXlmBWx+HnNlPvUKV/4UPdXW0j9NEykVzq5wfVXektbdBS8ipOqx+nAlfNW04CXlj8U8C3l8aJ4P4Uxy9hI7WnnyPyC+OqTEZD5VmAPMlyuLbWMnEcTfv4jQxZM6WOxv83XTBIDuzB9arMWwdSPv7qyAsO3OOVpnxVcvjNJJHZ1SRLIaV9IG5oSIPSfjaoZFI+ohTDxTUT7E1+FVQ3zJrXFrOtIyUsb/7nRi0RUue7DE+0Lgfl/t+MS2Wlpgp8t3yc16ogkobXZf0EmeYQiQ8J+awWKZcaC6RDxo4/rEaKQCNd3ae46Np/579wQxdmm6bFUU1Vpuw5cY5TutNAznttryOP7/6/cz6jsqMwXV9nzVKJyKPexxfIKdNXlcxB2PqslMsLj7PMYCc+8TjGMeyyXLDz7NvRsI2CwrWOAd44RniGvvQ41y3cSwVVaLqL168b6wMtUAjk4Z7ix+LiIJqKVnvBQwHvyPELvuWDu8ypbGhv4KV1mo0B82tXbMh0E8Wer+QGdd419AT9kDlGf7dv886jiy9x8nYPWeSj5/Fw4Eqh8aHOKoBrjUTxVN51rQN6NfK23LNxMk9F8KvSz40wpjF6pyY3iy/7OjSi0yP+NreioO2fc0wkA8hPQHl//zf/GuLnm8m0Uq7xgECD3YxL0n/PBtg1rtowGr/KyXyOqm9qCQoYsJyPvjBnN63yMob1E65ig2xGD/F/kYqbgdoAcRc4/MmY7LWhBtRQScMjfsL0rDlD2cUWCX4K/QsQsuiOfTQ+FssGnzk23R3OC3U20+TVGyndRp5cOmRGLfdT1MoOF2aM6QvVYrUKvQ7By76hdBouoQazOM2TXXPY5mIuFJueKNwvVfzXd5UvKBpQ15qpLrOW57p3QSj0Kb1Hm6CoxaoLxAFuF9xd0Ci3uw8p+X4nJgWnstx2qALmc4blsDzJd3pYesip96uS7kv/T9n8kEK6IaJ6L26iWTqIszGBmqrgYcyOcUgHPZ4+upaJd8JpeFq5+SFzI/ScBpSeS0PpVGEYBFZ9iSPiCi6WYoQsl7RIigXI783TbOjTyVzugBYRGdC/UyFn24SfnGvWQn6dWAx0zaeOwpBDPRZDCh4nYqeocpCd62qbSHq8kQrYfbhI+BAfdIdpCJyCQYTrCtL3FpJhXzWZtwzxsEFkFVCT/2rR62x6dIpkzfWmqtZ18hUMQ0viXztbBG27AaIwfBXFkynfSWihMzrOrs8X17yFYoi9zDwmS6QXLuGsyVsDvJdim9O/Jk+9von2YG8cr/WE9N7orHmC+ywlMLnnLGKk4ozmigW3Q31jR5qeF+UdyKO5Ter+zpMtWYJQQH8lqS+wvIE00/zRhg51ALMs4sMVI538+ABn+pT7rjyRr/7Er5tppvu28NZpYmhMUXiEoH+/JIRWONqNzjEeM0NhwxKSYFoUXjGytfouuAk8q+akJ5S544SJLBubPd7KL52MxrbOKeIjFlvng1YfniEYWDE9DfBS7AznsJFsO1bEP9XHVxMqLTm9xzFD7e+URFCtcBH0HO6vVcXwBI55BR0q+PxnfOJxeORGc/ljIi91+RPjz9W+7T83nlqbuhQoemo/srnpxZqfiqEdorMQTuhuViAkoM0lrz7sKiDpUErUs4QCu6SMSlIQCClTqPGUR1pHaiF6hFE8erjy+948f0sVkmu2Jw+eyU/skJIDcRYaqkq+cBJINebCJUKVYZl7oywAv/FYnru5WWssw2bc1l5YFpYENNkHQndX+tTviOaADWGsZgY+b5/odHDjKL6uy4JwSD5mlBJOg5OgW98YlX9eVKNmg4SYnyzS/FOjzFEe6TPicvjip0eKqy8OImgrkoJI5nyeljOKfpQx1p/sc75k1Yl98yXRH12m0ZympSPgt93H1wTtv5BSFKPXtoGkPh+VnkU8pAeGBHUgz30QUT/QnKY5iYkcAgm0/1eneCt9y4c9LboTOV7lUlTaUG4FA7ysJjMHbNmbG6f0uiT0xgP+w2nuEgr+2FY0qMZt8EX7RSlynY1ZNCzArdyVYzpRGa8ILaf9videPY4EveQVUnNysaU1oCCfST5Z+gF3lyRKs5BqhrjaJmbSApL0kNrRU+LG40FRR4aH0/0JiiqJvUd6JC3Vhmh8jpWwwK5ikzaiA9j3nZyHBXMhXXSNFET38tYfOB4GUAVxTIqP1q+fLqk8fv8LgYZ+LIWegjop3v9QmgDfxEM/1BDvMeL2P3VxkrzwAraIMzOGXp7O2LHZ9ElvGK6QIqY4yXe18tnTT2WdkftyxnbF8NOOubyDa9CGUbIdtn0JLyjdYRklGDufSy2EbjVHJUl+MUecJe+XFxcl5YBFfLBxnAlbFyZn6VsfjwLJ3+JCYI6py7o5NCVgU9Hhava2BP7ZwnmM9h1H/46vbeGi2N+69H4bX8Nxf2BmI2dzyeWeF4Tsrr5v7m85fU34xN7ujCn8QC8EZZh+eJBENVxViDc/ZISzqqTFhKvbw8/8zMhlS960KyCZQWGeqFHF4Bq4BPk0Ig1BgxKX0TfGdF7x6GXVE1bEsvtMRBM1Uo1e4Rd96VtNYZ1booUg+/MXzFjFviDGN0QgZ/8lOChJ5FlRvMP5ax7BlFtVeq18lf0TaNxa5Oyz7ae59CHEfHmh1h4Jh+693tC45ANtqsUMAS1vFludrxpKFAOijkKupvELj0MqmmFKke1gk8WOYCpSN/4Rd7L1smAPRch4VwkyRMqPy3NrpnTq0GVRhBi+B2YewwhiwEYA5tKO/3v4n3uSiM0XGIACq0d9KcRiRwRd9JZECEOi4yYMPbrsw7Zt9t53Wlv9NFfrWutK2eedhsRn036XCd+Sb26VjZsvmeR1a6p/kQoK4XZHoXHXTGAgnGmkIqnhu1AF6pSHw9d7+7b+4d/x4PHPIqWd0s56BI0a06iZwrciGOUwbY6/buso231i6WWSccE7Plvfyzi45TxLUymcAO0TSB6fzjPDQdWAsg82I6NZWIF2Rrr/q7wyF4bjueaTxbj4s72swMuL3howPt6Q3XAuIz374ho0BFKi9g56Wa110E/wbe53zh416yvhPQ+56fQ0Ficbb8kSy0AUZ3lod4TVf7xZEpzZqmFybfLDBn+HUXn64Q39XjmZTxtwhH/v9jaXYUHLwGERJm9YrskkqQLpH4HInozUIspmQVLms96fUt1kQaeQnL6az5NCH3JxavtuSkB94K89N9d7WOahsn/IS3DRE5N8n2hBHgVst+VTXcLfc3K2EMFtNvibDIAm/UnQ+jPFnbgINBDaPMN2psQiKiZ45mGLu+8tp7zdWCVymEIolZflbKTcfHX7PJ/Yw/EryBj5P3Ghyltc1tpNS1whUwLum3qfwVmu87R4E4Vm2dHHm3F68BlRLQe2Mx831IYUUAKiTgkvN/Fo3zj1PqTrH6+IENOZYppzgFWAP5w7sOZbZmZSkRjqqNkmaGuZYkIYVohkdxUysMJsnjQPAVaXHjd82f1WcKY8M/n"}', 19 | 'wallet::871b9de859991023': '{"iv":"E6C+AsQMfwtTv/31l7Yxrw==","v":1,"iter":5000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"mjuBtGybi/4=","ct":"mmFYrdsJ6J4BV6fpRkR7JwQ4xTp/pkiMRt4Q+yxIw3m5soQmIEAt4NkIl+cEtNZZ+J8tMkYYhobHkOeT+jMJjS/QQfxpEqmYEWz2Tq8I1zIg76KuaUcKEXq78pONcPFctCkUZgA5p5QtuGlt0vzJTcTI4Mo0jJixgHis9EEhXa43ay6E0LZYdjQZEoNn14ZH+o0hr/pK4X8Muf6JQaXAXZ6ialyisf54fiYWb+TOuGaCjw1k/a3sSdUVxKdLLt8mOjlTlRqlI7+1VuyxlSRCUuwqb/rboEC7qLfxU/Dy2tYOzUJGDwD0k/CHF14DiZxHOW2qAKbL35y69K2s44clRGV7JtapfRlO7h6fssFh9qbOYoRO6ode6h8mD7PqnmAct77vP57vvC2az5v3vMmydy1+Hwc6zknvLJF55AXhg1yZzT3fa8DGC+ISmyOxvbGX4bxKObKaeoZAy6dMFwzKywGvtvN5cV1epFVTJs9+pNHazba40HiwNIV45jC2QeeJErWcH7ODJqvx0ckGdijfQ41VUZ5kNC3uroEPFazHeIL7NgK6i9LGCVMQB6jFhTD7kr5Wc3m7H9MVCg+s5eW3bbJ7elFuzdluCrgt9ntijhTzRtxVzDoYLKbq0bkaXQQtXwiDpENIYWRJ/Nttlz98KC+aHcfSrq3B/ZvtbsVw4ua84sXMPvCM6LQF61nhDxbBo7SVxWRA/TGpZ+GYX/O8ABkRP/L1ed2EXdTkGjKyEDy5sbMPEiIxYZCrfJ0DMvp7/kS00cLxxRi5gWzZ9rtAqrXDZTeTvDs/PjJNnsOH5qWSkrvIxJerBF5fOexv175jl3sYSl1Sym0IHPd+T4CT7h3N0UHuqp7QugeOS7I8HhFOWgHHjGmUmGm/IOE0MRRPdMrwLy+WPxzkcZH3Ywy7OuVcRWEaV1QApAz0jLZN129EZN7QAbP7r5M2+6wKcZvlJjdk9MIOBZQqkFTaNvnkNAyvzlbq6VpQnClyhZ+NAH3kzJedZdmqjrUSDErATSEaPjeWNzygy1+YDA0O78yyCpAMe7xf2/HnY3jKzVioahJ7VBJnrEsiGO7Q5FUpr4qbDx/xL4HkQ5G2XedIHvOdhzHvMFAgKzDZpAkspH0MmIBnjbZ2xnOYB8rTRtOaZ5f4aUU487qeQ0jKaP/saAx+f/ox88zplhSsAyzaH9OI03/k593LhSsMoZit4XqjtoD/Z0oyYukj8SzYbTl8yJrCEePIIYkyB07qbPYPDGbZCauSlILL0aYcxkFDd6cP07gKVcZcKRWaPBXF0gQEq16sgyuAxoOyBpHx+VMeNq0qGyrEBQ9bQBVBM9tcrirWf6Yh9+TzqnclG99Mk0poQ3PcqDZ7KBN8WTCNRYiVuQRssGIdLHS3bVl4eCaxJu+GLRqJbCC+SS4zTbVkTxExnx8AXUEX7SrrmLwLp+tzYfx7hg9Tgc8S3kMVCvmxiepdFPUfG+24hj+mnz8f3TjYZnlDacyhi6F5hhamItct37DLmhX+An6lkKrqjw3yqCiUlr+2P/mH88eK3tG8wxyJ8qGEtIumK6xW5bbeFmipi7w5N/qvNi+vij2uTuDTTK3Ys7G/Npit3/9gF9qkwdH72EwJSgwpil1P"}', 20 | } 21 | }, { 22 | username: '345', 23 | password: '123qweasdZXC.', 24 | ls: { 25 | 'profile::2cf943e7720652c2924a0737761377ccc679ab57': '{"iv":"zY72H76ShUA8cajds69DMQ==","v":1,"iter":5000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"mjuBtGybi/4=","ct":"iaDWQDC6KM7VJZImT2jSRtbjnlYuUXUNofCMb4LkYmocwXWK9TpD4XC2/tSsZcXpBFzeK063xB+fk1OuPDrm1lX+VkO2RvxaOz0a5mv5526PQkCwYzddF1uZxVJY7dDeuwoxsqukx48FP9/zF//62rgdbv2QuaudUonbLb0XUcqn+dheH+E4US46dhJE+iJGUBiVbop0xV2uZWwAUeRzsaWFrw99WBw//zNx/HsPz277ZvtOfo0KkyIIoGFLuNJ30XB2Vh43+6rrsO9v2vnAtA+PIcMNRuUJ+Xsu+EtMYMxhszMyeg=="}', 26 | 'wallet::7065a73486c8cb5d':'{"iv":"6Ut9/VXCezlzBX/zZSD15A==","v":1,"iter":5000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"mjuBtGybi/4=","ct":"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"}', 27 | }, 28 | }, ]; 29 | module.exports.copayers = copayers; 30 | -------------------------------------------------------------------------------- /test/log.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _ = require('lodash'); 4 | var chai = chai || require('chai'); 5 | var sinon = sinon || require('sinon'); 6 | var should = chai.should(); 7 | var log = require('../lib/log'); 8 | 9 | describe('log utils', function() { 10 | afterEach(function() { 11 | log.setLevel('info'); 12 | }); 13 | 14 | it('should log .warn', function() { 15 | if (console.warn.restore) 16 | console.warn.restore(); 17 | 18 | sinon.stub(console, 'warn'); 19 | 20 | log.setLevel('debug'); 21 | log.warn('hola'); 22 | 23 | var arg = console.warn.getCall(0).args[0]; 24 | //arg.should.contain('util.log.js'); /* Firefox does not include the stack track */ 25 | arg.should.contain('hola'); 26 | console.warn.restore(); 27 | }); 28 | 29 | 30 | it('should log .fatal', function() { 31 | if (console.log.restore) 32 | console.log.restore(); 33 | 34 | sinon.stub(console, 'log'); 35 | 36 | log.setLevel('debug'); 37 | log.fatal('hola', "que", 'tal'); 38 | 39 | var arg = console.log.getCall(0).args[0]; 40 | //arg.should.contain('util.log.js'); /* Firefox does not include the stack track */ 41 | arg.should.contain('que'); 42 | console.log.restore(); 43 | }); 44 | 45 | 46 | it('should not log debug', function() { 47 | sinon.stub(console, 'log'); 48 | log.setLevel('info'); 49 | log.debug('hola'); 50 | console.log.called.should.equal(false); 51 | console.log.restore(); 52 | }); 53 | 54 | it('should log debug', function() { 55 | log.getLevels().debug.should.equal(0); 56 | log.getLevels().fatal.should.equal(5); 57 | }); 58 | 59 | it('should log nothing if logLevel is set to silent', function() { 60 | var sandbox = sinon.sandbox.create(); 61 | var cl = sandbox.stub(console, 'log'); 62 | 63 | log.setLevel('silent'); 64 | log.debug('foo'); 65 | log.info('foo'); 66 | log.log('foo'); 67 | log.warn('foo'); 68 | log.error('foo'); 69 | log.fatal('foo'); 70 | 71 | cl.callCount.should.equal(0); 72 | sandbox.restore(); 73 | }); 74 | 75 | it('should not create a log.silent() method', function() { 76 | should.not.exist(log.silent); 77 | }); 78 | 79 | }); 80 | -------------------------------------------------------------------------------- /test/paypro.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _ = require('lodash'); 4 | var chai = chai || require('chai'); 5 | var sinon = sinon || require('sinon'); 6 | var should = chai.should(); 7 | var PayPro = require('../lib/paypro'); 8 | var TestData = require('./testdata'); 9 | 10 | var TestDataBCH = _.clone(TestData.payProData); 11 | 12 | //paypro is using C/H address for now 13 | //TestDataBCH.toAddress = 'bchtest:qqkcn2tjp59v4xl24ercn99qdvdtz7qcvuvmw9knqf'; 14 | 15 | 16 | describe('paypro', function() { 17 | var xhr, httpNode, clock, headers; 18 | before(function() { 19 | // Stub time before cert expiration at Mar 27 2016 20 | clock = sinon.useFakeTimers(1459105693843); 21 | 22 | xhr = {}; 23 | headers = {}; 24 | xhr.onCreate = function(req) {}; 25 | xhr.open = function(method, url) {}; 26 | xhr.setRequestHeader = function(k, v) { 27 | //console.log('[paypro.js.21]', k,v); //TODO 28 | headers[k]=v; 29 | }; 30 | xhr.getAllResponseHeaders = function() { 31 | 32 | return 'content-type: test'; 33 | }; 34 | xhr.send = function() { 35 | xhr.response = TestData.payProBuf; 36 | xhr.onload(); 37 | }; 38 | 39 | httpNode = {}; 40 | httpNode.get = function(opts, cb) { 41 | var res = {}; 42 | res.statusCode = httpNode.error || 200; 43 | if (httpNode.error == 404) 44 | res.statusMessage = 'Not Found'; 45 | res.on = function(e, cb) { 46 | if (e == 'data') 47 | return cb(TestData.payProBuf); 48 | if (e == 'end') 49 | return cb(); 50 | }; 51 | return cb(res); 52 | }; 53 | httpNode.post = function(opts, cb) { 54 | var res = {}; 55 | res.statusCode = httpNode.error || 200; 56 | res.on = function(e, cb) { 57 | if (e == 'data') 58 | return cb(new Buffer('id')); 59 | if (e == 'end') 60 | return cb(); 61 | }; 62 | 63 | return cb(res); 64 | }; 65 | }); 66 | after(function() { 67 | clock.restore(); 68 | }); 69 | 70 | it('Make a PP request with browser', function(done) { 71 | xhr.status=200; 72 | PayPro.get({ 73 | url: 'http://an.url.com/paypro', 74 | xhr: xhr, 75 | env: 'browser', 76 | }, function(err, res) { 77 | headers['Accept'].should.equal('application/bitcoin-paymentrequest'); 78 | should.not.exist(err); 79 | res.should.deep.equal(TestData.payProData); 80 | done(); 81 | }); 82 | }); 83 | 84 | 85 | it('Should handle a failed request from the browser', function(done) { 86 | xhr.status=404; 87 | PayPro.get({ 88 | url: 'http://an.url.com/paypro', 89 | xhr: xhr, 90 | env: 'browser', 91 | }, function(err, res) { 92 | headers['Accept'].should.equal('application/bitcoin-paymentrequest'); 93 | should.exist(err); 94 | done(); 95 | }); 96 | }); 97 | 98 | 99 | 100 | it('Make a PP request with browser BCH', function(done) { 101 | xhr.status=200; 102 | PayPro.get({ 103 | url: 'http://an.url.com/paypro', 104 | xhr: xhr, 105 | env: 'browser', 106 | coin: 'bch', 107 | }, function(err, res) { 108 | should.not.exist(err); 109 | headers['Accept'].should.equal('application/bitcoincash-paymentrequest'); 110 | res.should.deep.equal(TestDataBCH); 111 | done(); 112 | }); 113 | }); 114 | 115 | it('Make a PP request with browser with headers', function(done) { 116 | PayPro.get({ 117 | url: 'http://an.url.com/paypro', 118 | xhr: xhr, 119 | env: 'browser', 120 | headers: { 121 | 'Accept': 'xx/xxx', 122 | 'Content-Type': 'application/octet-stream', 123 | 'Content-Length': 0, 124 | 'Content-Transfer-Encoding': 'xxx', 125 | } 126 | 127 | }, function(err, res) { 128 | should.not.exist(err); 129 | res.should.deep.equal(TestData.payProData); 130 | done(); 131 | }); 132 | }); 133 | 134 | 135 | 136 | it('make a pp request with browser, with http error', function(done) { 137 | xhr.send = function() { 138 | xhr.onerror(); 139 | }; 140 | PayPro.get({ 141 | url: 'http://an.url.com/paypro', 142 | xhr: xhr, 143 | env: 'browser', 144 | }, function(err, res) { 145 | err.should.be.an.instanceOf(Error); 146 | err.message.should.equal('HTTP Request Error'); 147 | done(); 148 | }); 149 | }); 150 | 151 | it('Make a PP request with browser, with http given error', function(done) { 152 | xhr.send = function() { 153 | xhr.onerror(); 154 | }; 155 | xhr.statusText = 'myerror'; 156 | PayPro.get({ 157 | url: 'http://an.url.com/paypro', 158 | xhr: xhr, 159 | env: 'browser', 160 | }, function(err, res) { 161 | err.should.be.an.instanceOf(Error); 162 | err.message.should.equal('myerror'); 163 | done(); 164 | }); 165 | }); 166 | 167 | it('Make a PP request with node', function(done) { 168 | xhr.send = function() { 169 | xhr.response = 'id'; 170 | xhr.onload(); 171 | }; 172 | 173 | 174 | xhr.statusText = null; 175 | PayPro.get({ 176 | url: 'http://an.url.com/paypro', 177 | httpNode: httpNode, 178 | env: 'node', 179 | }, function(err, res) { 180 | should.not.exist(err); 181 | res.should.deep.equal(TestData.payProData); 182 | done(); 183 | }); 184 | }); 185 | 186 | 187 | it('Make a PP request with node with HTTP error', function(done) { 188 | httpNode.error = 404; 189 | PayPro.get({ 190 | url: 'http://an.url.com/paypro', 191 | httpNode: httpNode, 192 | env: 'node', 193 | }, function(err, res) { 194 | err.should.be.an.instanceOf(Error); 195 | err.message.should.equal('HTTP Request Error: 404 Not Found '); 196 | done(); 197 | }); 198 | }); 199 | 200 | it('Create a PP payment', function() { 201 | var data = TestData.payProData; 202 | var payment = PayPro._createPayment(data.merchant_data, '12ab1234', 'mwRGmB4NE3bG4EbXJKTHf8uvodoUtMCRhZ', 100, 'btc'); 203 | var s = ''; 204 | for (var i = 0; i < payment.length; i++) { 205 | s += payment[i].toString(16); 206 | } 207 | s.should.equal('a4c7b22696e766f6963654964223a22436962454a4a74473174394837374b6d4d3631453274222c226d65726368616e744964223a22444766754344656f66556e576a446d5537454c634568227d12412ab12341a1d864121976a914ae6eeec7e05624db748f9c16cce6fb53696ab3988ac'); 208 | }); 209 | 210 | it('Send a PP payment (browser, BTC)', function(done) { 211 | var data = TestData.payProData; 212 | var opts = { 213 | merchant_data: data.merchant_data, 214 | rawTx: '12ab1234', 215 | refundAddr: 'mwRGmB4NE3bG4EbXJKTHf8uvodoUtMCRhZ', 216 | amountSat: 100, 217 | url: 'http://an.url.com/paypro', 218 | xhr: xhr, 219 | env: 'browser', 220 | }; 221 | var payment = PayPro.send(opts, function(err, data) { 222 | headers['Accept'].should.equal('application/bitcoin-paymentack'); 223 | headers['Content-Type'].should.equal('application/bitcoin-payment'); 224 | should.not.exist(err); 225 | done(); 226 | }); 227 | }); 228 | 229 | it('Send a PP payment (browser, BCH)', function(done) { 230 | var data = TestData.payProData; 231 | var opts = { 232 | merchant_data: data.merchant_data, 233 | rawTx: '12ab1234', 234 | refundAddr: 'mwRGmB4NE3bG4EbXJKTHf8uvodoUtMCRhZ', 235 | amountSat: 100, 236 | url: 'http://an.url.com/paypro', 237 | xhr: xhr, 238 | env: 'browser', 239 | coin: 'bch', 240 | }; 241 | var payment = PayPro.send(opts, function(err, data) { 242 | headers['Accept'].should.equal('application/bitcoincash-paymentack'); 243 | headers['Content-Type'].should.equal('application/bitcoincash-payment'); 244 | should.not.exist(err); 245 | done(); 246 | }); 247 | }); 248 | 249 | 250 | 251 | it('Send a PP payment (node)', function(done) { 252 | httpNode.error = null; 253 | var data = TestData.payProData; 254 | var opts = { 255 | merchant_data: data.merchant_data, 256 | rawTx: '12ab1234', 257 | refundAddr: 'mwRGmB4NE3bG4EbXJKTHf8uvodoUtMCRhZ', 258 | amountSat: 100, 259 | httpNode: httpNode, 260 | url: 'http://an.url.com/paypro', 261 | env: 'node', 262 | }; 263 | var payment = PayPro.send(opts, function(err, data) { 264 | should.not.exist(err); 265 | done(); 266 | }); 267 | }); 268 | 269 | }); 270 | -------------------------------------------------------------------------------- /test/test-config.js: -------------------------------------------------------------------------------- 1 | var config = { 2 | mongoDb: { 3 | uri: 'mongodb://localhost:27017/bwc_test', 4 | }, 5 | }; 6 | 7 | module.exports = config; 8 | -------------------------------------------------------------------------------- /test/testdata.js: -------------------------------------------------------------------------------- 1 | var history = [{ 2 | txid: "0279ef7b21630f859deb723e28beac9e7011660bd1346c2da40321d2f7e34f04", 3 | vin: [{ 4 | txid: "c8e221141e8bb60977896561b77fa59d6dacfcc10db82bf6f5f923048b11c70d", 5 | vout: 0, 6 | n: 0, 7 | addr: "2N6Zutg26LEC4iYVxi7SHhopVLP1iZPU1rZ", 8 | valueSat: 485645, 9 | value: 0.00485645, 10 | }, { 11 | txid: "6e599eea3e2898b91087eb87e041c5d8dec5362447a8efba185ed593f6dc64c0", 12 | vout: 1, 13 | n: 1, 14 | addr: "2MyqmcWjmVxW8i39wdk1CVPdEqKyFSY9H1S", 15 | valueSat: 885590, 16 | value: 0.0088559, 17 | }], 18 | vout: [{ 19 | value: "0.00045753", 20 | n: 0, 21 | scriptPubKey: { 22 | addresses: [ 23 | "2NAVFnsHqy5JvqDJydbHPx393LFqFFBQ89V" 24 | ] 25 | }, 26 | }, { 27 | value: "0.01300000", 28 | n: 1, 29 | scriptPubKey: { 30 | addresses: [ 31 | "mq4D3Va5mYHohMEHrgHNGzCjKhBKvuEhPE" 32 | ] 33 | } 34 | }], 35 | confirmations: 2, 36 | time: 1424471041, 37 | blocktime: 20, 38 | valueOut: 0.01345753, 39 | valueIn: 0.01371235, 40 | fees: 0.00025482 41 | }, { 42 | txid: "fad88682ccd2ff34cac6f7355fe9ecd8addd9ef167e3788455972010e0d9d0de", 43 | vin: [{ 44 | txid: "0279ef7b21630f859deb723e28beac9e7011660bd1346c2da40321d2f7e34f04", 45 | vout: 0, 46 | n: 0, 47 | addr: "2NAVFnsHqy5JvqDJydbHPx393LFqFFBQ89V", 48 | valueSat: 45753, 49 | value: 0.00045753, 50 | }], 51 | vout: [{ 52 | value: "0.00011454", 53 | n: 0, 54 | scriptPubKey: { 55 | addresses: [ 56 | "2N7GT7XaN637eBFMmeczton2aZz5rfRdZso" 57 | ] 58 | } 59 | }, { 60 | value: "0.00020000", 61 | n: 1, 62 | scriptPubKey: { 63 | addresses: [ 64 | "mq4D3Va5mYHohMEHrgHNGzCjKhBKvuEhPE" 65 | ] 66 | } 67 | }], 68 | confirmations: 1, 69 | firstSeenTs: 1424472242, 70 | blocktime: 10, 71 | valueOut: 0.00031454, 72 | valueIn: 0.00045753, 73 | fees: 0.00014299 74 | }]; 75 | 76 | var payproHex = '0801120b783530392b7368613235361a89250aa40a3082052030820408a003020102020727a49d05046d62300d06092a864886f70d01010b05003081b4310b30090603550406130255533110300e060355040813074172697a6f6e61311330110603550407130a53636f74747364616c65311a3018060355040a1311476f44616464792e636f6d2c20496e632e312d302b060355040b1324687474703a2f2f63657274732e676f64616464792e636f6d2f7265706f7369746f72792f313330310603550403132a476f2044616464792053656375726520436572746966696361746520417574686f72697479202d204732301e170d3134303432363132333532365a170d3136303432363132333532365a303a3121301f060355040b1318446f6d61696e20436f6e74726f6c2056616c6964617465643115301306035504030c0c2a2e6269747061792e636f6d30820122300d06092a864886f70d01010105000382010f003082010a0282010100e2a5dd4aea959c1d0fb016e6e05bb7011e741cdc61918c61f9625a2f682f485f0e862ea63db61cc9161753127504de800604df36b10f46cb17ab6cb99dba8aa45a36adfb901a2fc380c89e234bce18de6639b883e9339801673efaee1f2df77eeb82f7c39c96a2f8ef4572b634c203d9be8fd1e0036d32fb38b6b9b5ecd5a0684345c7e9ffc5d26bc6fd69aa6619f77badaa4bfb989478fb2f41aa92782e40b34ba9ac4549a4e6fda76b5fc4a581853bd0de5fb5a2c6dfdc12cdfadb54e9636a6d1223705924b8be566b81ac7921078cf590a146ae397a84908ef4fc83ff5715a44ab59e9258674d90113bb607b8d81eb268e4c6ce849497c76521795b0873950203010001a38201ae308201aa300f0603551d130101ff04053003010100301d0603551d250416301406082b0601050507030106082b06010505070302300e0603551d0f0101ff0404030205a030360603551d1f042f302d302ba029a0278625687474703a2f2f63726c2e676f64616464792e636f6d2f676469673273312d34392e63726c30530603551d20044c304a3048060b6086480186fd6d010717013039303706082b06010505070201162b687474703a2f2f6365727469666963617465732e676f64616464792e636f6d2f7265706f7369746f72792f307606082b06010505070101046a3068302406082b060105050730018618687474703a2f2f6f6373702e676f64616464792e636f6d2f304006082b060105050730028634687474703a2f2f6365727469666963617465732e676f64616464792e636f6d2f7265706f7369746f72792f67646967322e637274301f0603551d2304183016801440c2bd278ecc348330a233d7fb6cb3f0b42c80ce30230603551d11041c301a820c2a2e6269747061792e636f6d820a6269747061792e636f6d301d0603551d0e0416041485454e3b4072e2f58e377438988b5229387e967a300d06092a864886f70d01010b050003820101002d0a7ef97f988905ebbbad4e9ffb690352535211d6792516119838b55f24ff9fa4e93b6187b8517cbb0477457d3378078ef66057abe41bcafeb142ec52443a94b88114fa069f725c6198581d97af16352727f4f35e7f2110faa41a0511bcfdf8e3f4a3a310278c150b10f32a962c81e8f3d5374d9cb56d893027ff4fa4e3c3e6384c1f1557ceea6fca9cbc0c110748c08b82d8f0ed9a579637ee43a2d8fec3b5b04d1f3c8f1a3e2088da2274b6bc60948bbe744a7f8b942b41f0ae9b4afaeefbb7e0f04a0587b52efb6ebfa2d970b9de56a068575e4bf0cf824618dc17bbeaa2cdd25d65970a9f1a06fc9fffb466a10c9568cd651795bc2c7996975027bdbaba0ad409308204d0308203b8a003020102020107300d06092a864886f70d01010b0500308183310b30090603550406130255533110300e060355040813074172697a6f6e61311330110603550407130a53636f74747364616c65311a3018060355040a1311476f44616464792e636f6d2c20496e632e3131302f06035504031328476f20446164647920526f6f7420436572746966696361746520417574686f72697479202d204732301e170d3131303530333037303030305a170d3331303530333037303030305a3081b4310b30090603550406130255533110300e060355040813074172697a6f6e61311330110603550407130a53636f74747364616c65311a3018060355040a1311476f44616464792e636f6d2c20496e632e312d302b060355040b1324687474703a2f2f63657274732e676f64616464792e636f6d2f7265706f7369746f72792f313330310603550403132a476f2044616464792053656375726520436572746966696361746520417574686f72697479202d20473230820122300d06092a864886f70d01010105000382010f003082010a0282010100b9e0cb10d4af76bdd49362eb3064b881086cc304d962178e2fff3e65cf8fce62e63c521cda16454b55ab786b63836290ce0f696c99c81a148b4ccc4533ea88dc9ea3af2bfe80619d7957c4cf2ef43f303c5d47fc9a16bcc3379641518e114b54f828bed08cbef030381ef3b026f86647636dde7126478f384753d1461db4e3dc00ea45acbdbc71d9aa6f00dbdbcd303a794f5f4c47f81def5bc2c49d603bb1b24391d8a4334eeab3d6274fad258aa5c6f4d5d0a6ae7405645788b54455d42d2a3a3ef8b8bde9320a029464c4163a50f14aaee77933af0c20077fe8df0439c269026c6352fa77c11bc87487c8b993185054354b694ebc3bd3492e1fdcc1d252fb0203010001a382011a30820116300f0603551d130101ff040530030101ff300e0603551d0f0101ff040403020106301d0603551d0e0416041440c2bd278ecc348330a233d7fb6cb3f0b42c80ce301f0603551d230418301680143a9a8507106728b6eff6bd05416e20c194da0fde303406082b0601050507010104283026302406082b060105050730018618687474703a2f2f6f6373702e676f64616464792e636f6d2f30350603551d1f042e302c302aa028a0268624687474703a2f2f63726c2e676f64616464792e636f6d2f6764726f6f742d67322e63726c30460603551d20043f303d303b0604551d20003033303106082b06010505070201162568747470733a2f2f63657274732e676f64616464792e636f6d2f7265706f7369746f72792f300d06092a864886f70d01010b05000382010100087e6c9310c838b896a9904bffa15f4f04ef6c3e9c8806c9508fa673f757311bbebce42fdbf8bad35be0b4e7e679620e0ca2d76a637331b5f5a848a43b082da25d90d7b47c254f115630c4b6449d7b2c9de55ee6ef0c61aabfe42a1bee849eb8837dc143ce44a713700d911ff4c813ad8360d9d872a873241eb5ac220eca17896258441bab892501000fcdc41b62db51b4d30f512a9bf4bc73fc76ce36a4cdd9d82ceaae9bf52ab290d14d75188a3f8a4190237d5b4bfea403589b46b2c3606083f87d5041cec2a190c3bbef022fd21554ee4415d90aaea78a33edb12d763626dc04eb9ff7611f15dc876fee469628ada1267d0a09a72e04a38dbcf8bc0430010a81093082047d30820365a00302010202031be715300d06092a864886f70d01010b05003063310b30090603550406130255533121301f060355040a131854686520476f2044616464792047726f75702c20496e632e3131302f060355040b1328476f20446164647920436c61737320322043657274696669636174696f6e20417574686f72697479301e170d3134303130313037303030305a170d3331303533303037303030305a308183310b30090603550406130255533110300e060355040813074172697a6f6e61311330110603550407130a53636f74747364616c65311a3018060355040a1311476f44616464792e636f6d2c20496e632e3131302f06035504031328476f20446164647920526f6f7420436572746966696361746520417574686f72697479202d20473230820122300d06092a864886f70d01010105000382010f003082010a0282010100bf716208f1fa5934f71bc918a3f7804958e9228313a6c52043013b84f1e685499f27eaf6841b4ea0b4db7098c73201b1053e074eeef4fa4f2f593022e7ab19566be28007fcf316758039517be5f935b6744ea98d8213e4b63fa90383faa2be8a156a7fde0bc3b6191405caeac3a804943b467c320df3006622c88d696d368c1118b7d3b21c60b438fa028cced3dd4607de0a3eeb5d7cc87cfbb02b53a4926269512505611a44818c2ca9439623dfac3a819a0e29c51ca9e95d1eb69e9e300a39cef18880fb4b5dcc32ec85624325340256270191b43b702a3f6eb1e89c88017d9fd4f9db536d609dbf2ce758abb85f46fccec41b033c09eb49315c6946b3e0470203010001a382011730820113300f0603551d130101ff040530030101ff300e0603551d0f0101ff040403020106301d0603551d0e041604143a9a8507106728b6eff6bd05416e20c194da0fde301f0603551d23041830168014d2c4b0d291d44c1171b361cb3da1fedda86ad4e3303406082b0601050507010104283026302406082b060105050730018618687474703a2f2f6f6373702e676f64616464792e636f6d2f30320603551d1f042b30293027a025a0238621687474703a2f2f63726c2e676f64616464792e636f6d2f6764726f6f742e63726c30460603551d20043f303d303b0604551d20003033303106082b06010505070201162568747470733a2f2f63657274732e676f64616464792e636f6d2f7265706f7369746f72792f300d06092a864886f70d01010b05000382010100590b53bd928611a7247bed5b31cf1d1f6c70c5b86ebe4ebbf6be9750e1307fba285c6294c2e37e33f7fb427685db951c8c225875090c886567390a1609c5a03897a4c523933fb418a601064491e3a76927b45a257f3ab732cddd84ff2a382933a4dd67b285fea188201c5089c8dc2af64203374ce688dfd5af24f2b1c3dfccb5ece0995eb74954203c94180cc71c521849a46de1b3580bc9d8ecd9ae1c328e28700de2fea6179e840fbd5770b35ae91fa08653bbef7cff690be048c3b7930bc80a54c4ac5d1467376ccaa52f310837aa6e6f8cbc9be2575d2481af97979c84ad6cac374c66f361911120e4be309f7aa42909b0e1345f6477184051df8c30a6af0a840830820400308202e8a003020102020100300d06092a864886f70d01010505003063310b30090603550406130255533121301f060355040a131854686520476f2044616464792047726f75702c20496e632e3131302f060355040b1328476f20446164647920436c61737320322043657274696669636174696f6e20417574686f72697479301e170d3034303632393137303632305a170d3334303632393137303632305a3063310b30090603550406130255533121301f060355040a131854686520476f2044616464792047726f75702c20496e632e3131302f060355040b1328476f20446164647920436c61737320322043657274696669636174696f6e20417574686f7269747930820120300d06092a864886f70d01010105000382010d00308201080282010100de9dd7ea571849a15bebd75f4886eabeddffe4ef671cf46568b35771a05e77bbed9b49e970803d561863086fdaf2ccd03f7f0254225410d8b281d4c0753d4b7fc777c33e78ab1a03b5206b2f6a2bb1c5887ec4bb1eb0c1d845276faa3758f78726d7d82df6a917b71f72364ea6173f659892db2a6e5da2fe88e00bde7fe58d15e1ebcb3ad5e212a2132dd88eaf5f123da0080508b65ca565380445991ea3606074c541a572621b62c51f6f5f1a42be025165a8ae23186afc7803a94d7f80c3faab5afca140a4ca1916feb2c8ef5e730dee77bd9af67998bcb10767a2150ddda058c6447b0a3e62285fba41075358cf117e3874c5f8ffb569908f8474ea971baf020103a381c03081bd301d0603551d0e04160414d2c4b0d291d44c1171b361cb3da1fedda86ad4e330818d0603551d230481853081828014d2c4b0d291d44c1171b361cb3da1fedda86ad4e3a167a4653063310b30090603550406130255533121301f060355040a131854686520476f2044616464792047726f75702c20496e632e3131302f060355040b1328476f20446164647920436c61737320322043657274696669636174696f6e20417574686f72697479820100300c0603551d13040530030101ff300d06092a864886f70d01010505000382010100324bf3b2ca3e91fc12c6a1078c8e77a03306145c901e18f708a63d0a19f98780116e69e4961730ff3491637238eecc1c01a31d9428a431f67ac454d7f6e5315803a2ccce62db944573b5bf45c924b5d58202ad2379698db8b64dcecf4cca3323e81c88aa9d8b416e16c920e5899ecd3bda70f77e992620145425ab6e7385e69b219d0a6c820ea8f8c20cfa101e6c96ef870dc40f618badee832b95f88e92847239eb20ea83ed83cd976e08bceb4e26b6732be4d3f64cfe2671e26111744aff571a870f75482ecf516917a002126195d5d140b2104ceec4ac1043a6a59e0ad595629a0dcf8882c5320ce42b9f45e60d9f289cb1b92a5a57ad370faf1d7fdbbd9f2285020a0474657374121f0894d818121976a9142d89a9720d0aca9beaae478994a06b1ab178186788ac18f3f2caa80520f7f9caa8052a505061796d656e74207265717565737420666f722042697450617920696e766f69636520436962454a4a74473174394837374b6d4d363145327420666f72206d65726368616e742074657374436f706179323068747470733a2f2f746573742e6269747061792e636f6d2f692f436962454a4a74473174394837374b6d4d36314532743a4c7b22696e766f6963654964223a22436962454a4a74473174394837374b6d4d3631453274222c226d65726368616e744964223a22444766754344656f66556e576a446d5537454c634568227d2a8002c7146109dfd2584b905627f13e79fe96cc390de6d9729f1263be9ded44f907cc185a1968b71d1b99f073671e288ff51be93493dc2b0cbd7a9de761692bbb143c117aa24961c64e3add6a35b67b48da73c6c740024665494c28cd80d6bbf99ab98d9cee87a6bf826666990d51791d87978cbefd132679851c19962c0ba364913786ec6c9706989c0b4e257d1313cd635822569babff5e58e41f4f94add69efc5ed2850fc1c87cac0487ef3678d02b92459e04666f0e2d3e530502c0623768cd741262fcdf696817ffecb93917152a16a701d21f0a257302d2596f3c86b3fa296450662a11fdd857c40e6bb50cfad4e65cf647eb65541a617661c69da903c54bf6'; 77 | 78 | var payProData = { 79 | verified: true, 80 | caName: 'Go Daddy Class 2 CA', 81 | caTrusted: true, 82 | selfSigned: 0, 83 | expires: 1427291383, 84 | memo: 'Payment request for BitPay invoice CibEJJtG1t9H77KmM61E2t for merchant testCopay', 85 | time: 1427290483, 86 | toAddress: 'mjfjcbuYwBUdEyq2m7AezjCAR4etUBqyiE', 87 | amount: 404500, 88 | network: 'testnet', 89 | domain: 'an.url.com', 90 | url: 'http://an.url.com/paypro', 91 | merchant_data: '{"invoiceId":"CibEJJtG1t9H77KmM61E2t","merchantId":"DGfuCDeofUnWjDmU7ELcEh"}', 92 | }; 93 | 94 | var payAck = [10, 0, 18, 95, 84, 114, 97, 110, 115, 97, 99, 116, 105, 111, 110, 32, 114, 101, 99, 101, 105, 118, 101, 100, 32, 98, 121, 32, 66, 105, 116, 80, 97, 121, 46, 32, 73, 110, 118, 111, 105, 99, 101, 32, 119, 105, 108, 108, 32, 98, 101, 32, 109, 97, 114, 107, 101, 100, 32, 97, 115, 32, 112, 97, 105, 100, 32, 105, 102, 32, 116, 104, 101, 32, 116, 114, 97, 110, 115, 97, 99, 116, 105, 111, 110, 32, 105, 115, 32, 99, 111, 110, 102, 105, 114, 109, 101, 100, 46]; 95 | 96 | 97 | var payProBufBCH = [ 98 | 8,1,18,11,120,53,48,57,43,115,104,97,50,53,54,26,145,33,10,179,14,48,130,7,47,48,130,6,23,160,3,2,1,2,2,9,0,132,145,79,189,177,108,195,183,48,13,6,9,42,134,72,134,247,13,1,1,11,5,0,48,129,180,49,11,48,9,6,3,85,4,6,19,2,85,83,49,16,48,14,6,3,85,4,8,19,7,65,114,105,122,111,110,97,49,19,48,17,6,3,85,4,7,19,10,83,99,111,116,116,115,100,97,108,101,49,26,48,24,6,3,85,4,10,19,17,71,111,68,97,100,100,121,46,99,111,109,44,32,73,110,99,46,49,45,48,43,6,3,85,4,11,19,36,104,116,116,112,58,47,47,99,101,114,116,115,46,103,111,100,97,100,100,121,46,99,111,109,47,114,101,112,111,115,105,116,111,114,121,47,49,51,48,49,6,3,85,4,3,19,42,71,111,32,68,97,100,100,121,32,83,101,99,117,114,101,32,67,101,114,116,105,102,105,99,97,116,101,32,65,117,116,104,111,114,105,116,121,32,45,32,71,50,48,30,23,13,49,55,48,51,50,51,49,56,50,50,48,48,90,23,13,49,57,48,52,50,53,49,57,49,49,48,48,90,48,129,190,49,19,48,17,6,11,43,6,1,4,1,130,55,60,2,1,3,19,2,85,83,49,25,48,23,6,11,43,6,1,4,1,130,55,60,2,1,2,19,8,68,101,108,97,119,97,114,101,49,29,48,27,6,3,85,4,15,19,20,80,114,105,118,97,116,101,32,79,114,103,97,110,105,122,97,116,105,111,110,49,16,48,14,6,3,85,4,5,19,7,53,49,54,51,57,54,54,49,11,48,9,6,3,85,4,6,19,2,85,83,49,16,48,14,6,3,85,4,8,19,7,71,101,111,114,103,105,97,49,16,48,14,6,3,85,4,7,19,7,65,116,108,97,110,116,97,49,21,48,19,6,3,85,4,10,19,12,66,105,116,80,97,121,44,32,73,110,99,46,49,19,48,17,6,3,85,4,3,19,10,98,105,116,112,97,121,46,99,111,109,48,130,1,34,48,13,6,9,42,134,72,134,247,13,1,1,1,5,0,3,130,1,15,0,48,130,1,10,2,130,1,1,0,228,32,37,54,154,128,60,27,68,35,74,39,157,18,59,97,14,193,23,132,82,252,124,87,242,87,100,146,225,18,49,102,190,213,238,193,29,18,168,184,36,144,79,119,170,97,102,206,110,17,21,56,32,65,33,6,155,94,207,248,31,209,171,39,177,185,71,92,73,215,104,14,245,244,6,245,122,24,113,183,115,146,167,181,196,55,15,80,75,161,117,97,127,120,254,36,201,237,118,21,75,70,170,103,124,246,70,58,32,41,9,113,27,52,206,236,190,14,231,185,118,108,253,112,24,136,107,103,229,24,241,172,57,163,113,81,82,214,46,89,84,127,52,212,64,237,61,250,1,169,42,66,237,11,34,28,9,49,68,237,99,248,108,35,0,184,207,25,43,117,146,151,50,175,99,196,21,38,228,253,105,115,95,0,98,198,28,45,188,181,111,100,57,255,155,190,98,80,125,165,39,82,193,217,159,36,175,187,58,107,92,152,152,157,33,150,251,107,217,204,131,165,171,33,240,96,233,85,231,244,90,1,201,239,231,130,241,92,212,138,184,36,214,39,45,178,183,28,137,136,208,32,113,232,5,223,2,3,1,0,1,163,130,3,54,48,130,3,50,48,12,6,3,85,29,19,1,1,255,4,2,48,0,48,29,6,3,85,29,37,4,22,48,20,6,8,43,6,1,5,5,7,3,1,6,8,43,6,1,5,5,7,3,2,48,14,6,3,85,29,15,1,1,255,4,4,3,2,5,160,48,53,6,3,85,29,31,4,46,48,44,48,42,160,40,160,38,134,36,104,116,116,112,58,47,47,99,114,108,46,103,111,100,97,100,100,121,46,99,111,109,47,103,100,105,103,50,115,51,45,55,46,99,114,108,48,92,6,3,85,29,32,4,85,48,83,48,72,6,11,96,134,72,1,134,253,109,1,7,23,3,48,57,48,55,6,8,43,6,1,5,5,7,2,1,22,43,104,116,116,112,58,47,47,99,101,114,116,105,102,105,99,97,116,101,115,46,103,111,100,97,100,100,121,46,99,111,109,47,114,101,112,111,115,105,116,111,114,121,47,48,7,6,5,103,129,12,1,1,48,118,6,8,43,6,1,5,5,7,1,1,4,106,48,104,48,36,6,8,43,6,1,5,5,7,48,1,134,24,104,116,116,112,58,47,47,111,99,115,112,46,103,111,100,97,100,100,121,46,99,111,109,47,48,64,6,8,43,6,1,5,5,7,48,2,134,52,104,116,116,112,58,47,47,99,101,114,116,105,102,105,99,97,116,101,115,46,103,111,100,97,100,100,121,46,99,111,109,47,114,101,112,111,115,105,116,111,114,121,47,103,100,105,103,50,46,99,114,116,48,31,6,3,85,29,35,4,24,48,22,128,20,64,194,189,39,142,204,52,131,48,162,51,215,251,108,179,240,180,44,128,206,48,37,6,3,85,29,17,4,30,48,28,130,10,98,105,116,112,97,121,46,99,111,109,130,14,119,119,119,46,98,105,116,112,97,121,46,99,111,109,48,29,6,3,85,29,14,4,22,4,20,165,105,138,112,218,161,64,93,188,221,26,2,233,93,184,165,26,170,221,127,48,130,1,125,6,10,43,6,1,4,1,214,121,2,4,2,4,130,1,109,4,130,1,105,1,103,0,118,0,86,20,6,154,47,215,194,236,211,245,225,189,68,178,62,199,70,118,185,188,153,17,92,192,239,148,152,85,214,137,208,221,0,0,1,90,252,104,175,199,0,0,4,3,0,71,48,69,2,33,0,235,151,195,31,196,176,22,241,181,150,113,177,184,185,126,129,244,193,62,243,11,183,85,160,220,123,250,104,239,131,22,21,2,32,121,107,28,254,2,126,232,38,149,125,242,22,115,6,156,58,112,223,33,221,134,139,248,252,197,33,187,102,96,100,109,86,0,117,0,238,75,189,183,117,206,96,186,225,66,105,31,171,225,158,102,163,15,126,95,176,114,216,131,0,196,123,137,122,168,253,203,0,0,1,90,252,104,180,42,0,0,4,3,0,70,48,68,2,32,18,70,1,35,114,116,214,52,45,28,249,10,80,72,78,252,87,139,79,8,151,183,192,123,193,49,238,27,132,95,130,132,2,32,118,114,255,79,171,189,66,175,212,250,248,91,33,148,81,223,15,136,235,107,60,66,75,214,242,105,6,200,240,214,11,84,0,118,0,164,185,9,144,180,24,88,20,135,187,19,162,204,103,112,10,60,53,152,4,249,27,223,184,227,119,205,14,200,13,220,16,0,0,1,90,252,104,180,224,0,0,4,3,0,71,48,69,2,33,0,185,8,32,27,186,160,33,80,70,30,105,97,216,179,117,162,48,101,220,103,88,178,35,86,135,143,42,176,134,78,137,26,2,32,104,75,86,208,190,225,209,65,241,125,209,80,170,181,60,118,232,73,241,247,26,87,186,102,5,95,78,120,83,254,48,225,48,13,6,9,42,134,72,134,247,13,1,1,11,5,0,3,130,1,1,0,32,16,146,183,128,136,147,128,107,160,143,171,254,235,215,108,218,18,150,13,84,146,29,185,15,222,34,109,9,111,117,80,151,130,47,78,76,91,192,255,76,183,160,211,251,171,0,254,18,99,198,0,27,80,110,210,207,158,116,141,5,138,212,2,116,145,0,9,141,135,108,25,5,170,131,79,186,255,163,96,170,100,167,84,63,209,27,221,92,179,44,11,122,185,49,171,17,202,109,182,58,187,180,137,228,107,23,91,174,126,204,145,77,174,162,179,137,139,245,205,152,2,34,161,176,203,155,250,194,184,214,144,91,99,136,29,204,216,67,32,227,193,171,115,37,146,226,109,120,156,215,115,220,128,231,128,57,129,190,179,225,99,196,90,158,58,54,89,213,221,176,52,62,248,141,241,86,207,229,64,186,155,182,99,169,243,14,218,126,23,158,107,139,106,95,14,168,135,67,84,63,52,14,80,238,84,140,158,26,72,54,67,104,144,250,21,215,198,36,84,113,128,73,252,39,36,26,174,132,250,214,138,204,43,123,38,140,33,53,6,176,203,74,45,111,217,84,65,191,157,240,177,115,145,142,199,10,212,9,48,130,4,208,48,130,3,184,160,3,2,1,2,2,1,7,48,13,6,9,42,134,72,134,247,13,1,1,11,5,0,48,129,131,49,11,48,9,6,3,85,4,6,19,2,85,83,49,16,48,14,6,3,85,4,8,19,7,65,114,105,122,111,110,97,49,19,48,17,6,3,85,4,7,19,10,83,99,111,116,116,115,100,97,108,101,49,26,48,24,6,3,85,4,10,19,17,71,111,68,97,100,100,121,46,99,111,109,44,32,73,110,99,46,49,49,48,47,6,3,85,4,3,19,40,71,111,32,68,97,100,100,121,32,82,111,111,116,32,67,101,114,116,105,102,105,99,97,116,101,32,65,117,116,104,111,114,105,116,121,32,45,32,71,50,48,30,23,13,49,49,48,53,48,51,48,55,48,48,48,48,90,23,13,51,49,48,53,48,51,48,55,48,48,48,48,90,48,129,180,49,11,48,9,6,3,85,4,6,19,2,85,83,49,16,48,14,6,3,85,4,8,19,7,65,114,105,122,111,110,97,49,19,48,17,6,3,85,4,7,19,10,83,99,111,116,116,115,100,97,108,101,49,26,48,24,6,3,85,4,10,19,17,71,111,68,97,100,100,121,46,99,111,109,44,32,73,110,99,46,49,45,48,43,6,3,85,4,11,19,36,104,116,116,112,58,47,47,99,101,114,116,115,46,103,111,100,97,100,100,121,46,99,111,109,47,114,101,112,111,115,105,116,111,114,121,47,49,51,48,49,6,3,85,4,3,19,42,71,111,32,68,97,100,100,121,32,83,101,99,117,114,101,32,67,101,114,116,105,102,105,99,97,116,101,32,65,117,116,104,111,114,105,116,121,32,45,32,71,50,48,130,1,34,48,13,6,9,42,134,72,134,247,13,1,1,1,5,0,3,130,1,15,0,48,130,1,10,2,130,1,1,0,185,224,203,16,212,175,118,189,212,147,98,235,48,100,184,129,8,108,195,4,217,98,23,142,47,255,62,101,207,143,206,98,230,60,82,28,218,22,69,75,85,171,120,107,99,131,98,144,206,15,105,108,153,200,26,20,139,76,204,69,51,234,136,220,158,163,175,43,254,128,97,157,121,87,196,207,46,244,63,48,60,93,71,252,154,22,188,195,55,150,65,81,142,17,75,84,248,40,190,208,140,190,240,48,56,30,243,176,38,248,102,71,99,109,222,113,38,71,143,56,71,83,209,70,29,180,227,220,0,234,69,172,189,188,113,217,170,111,0,219,219,205,48,58,121,79,95,76,71,248,29,239,91,194,196,157,96,59,177,178,67,145,216,164,51,78,234,179,214,39,79,173,37,138,165,198,244,213,208,166,174,116,5,100,87,136,181,68,85,212,45,42,58,62,248,184,189,233,50,10,2,148,100,196,22,58,80,241,74,174,231,121,51,175,12,32,7,127,232,223,4,57,194,105,2,108,99,82,250,119,193,27,200,116,135,200,185,147,24,80,84,53,75,105,78,188,59,211,73,46,31,220,193,210,82,251,2,3,1,0,1,163,130,1,26,48,130,1,22,48,15,6,3,85,29,19,1,1,255,4,5,48,3,1,1,255,48,14,6,3,85,29,15,1,1,255,4,4,3,2,1,6,48,29,6,3,85,29,14,4,22,4,20,64,194,189,39,142,204,52,131,48,162,51,215,251,108,179,240,180,44,128,206,48,31,6,3,85,29,35,4,24,48,22,128,20,58,154,133,7,16,103,40,182,239,246,189,5,65,110,32,193,148,218,15,222,48,52,6,8,43,6,1,5,5,7,1,1,4,40,48,38,48,36,6,8,43,6,1,5,5,7,48,1,134,24,104,116,116,112,58,47,47,111,99,115,112,46,103,111,100,97,100,100,121,46,99,111,109,47,48,53,6,3,85,29,31,4,46,48,44,48,42,160,40,160,38,134,36,104,116,116,112,58,47,47,99,114,108,46,103,111,100,97,100,100,121,46,99,111,109,47,103,100,114,111,111,116,45,103,50,46,99,114,108,48,70,6,3,85,29,32,4,63,48,61,48,59,6,4,85,29,32,0,48,51,48,49,6,8,43,6,1,5,5,7,2,1,22,37,104,116,116,112,115,58,47,47,99,101,114,116,115,46,103,111,100,97,100,100,121,46,99,111,109,47,114,101,112,111,115,105,116,111,114,121,47,48,13,6,9,42,134,72,134,247,13,1,1,11,5,0,3,130,1,1,0,8,126,108,147,16,200,56,184,150,169,144,75,255,161,95,79,4,239,108,62,156,136,6,201,80,143,166,115,247,87,49,27,190,188,228,47,219,248,186,211,91,224,180,231,230,121,98,14,12,162,215,106,99,115,49,181,245,168,72,164,59,8,45,162,93,144,215,180,124,37,79,17,86,48,196,182,68,157,123,44,157,229,94,230,239,12,97,170,191,228,42,27,238,132,158,184,131,125,193,67,206,68,167,19,112,13,145,31,244,200,19,173,131,96,217,216,114,168,115,36,30,181,172,34,14,202,23,137,98,88,68,27,171,137,37,1,0,15,205,196,27,98,219,81,180,211,15,81,42,155,244,188,115,252,118,206,54,164,205,217,216,44,234,174,155,245,42,178,144,209,77,117,24,138,63,138,65,144,35,125,91,75,254,164,3,88,155,70,178,195,96,96,131,248,125,80,65,206,194,161,144,195,187,239,2,47,210,21,84,238,68,21,217,10,174,167,138,51,237,177,45,118,54,38,220,4,235,159,247,97,31,21,220,135,111,238,70,150,40,173,161,38,125,10,9,167,46,4,163,141,188,248,188,4,48,1,10,129,9,48,130,4,125,48,130,3,101,160,3,2,1,2,2,3,27,231,21,48,13,6,9,42,134,72,134,247,13,1,1,11,5,0,48,99,49,11,48,9,6,3,85,4,6,19,2,85,83,49,33,48,31,6,3,85,4,10,19,24,84,104,101,32,71,111,32,68,97,100,100,121,32,71,114,111,117,112,44,32,73,110,99,46,49,49,48,47,6,3,85,4,11,19,40,71,111,32,68,97,100,100,121,32,67,108,97,115,115,32,50,32,67,101,114,116,105,102,105,99,97,116,105,111,110,32,65,117,116,104,111,114,105,116,121,48,30,23,13,49,52,48,49,48,49,48,55,48,48,48,48,90,23,13,51,49,48,53,51,48,48,55,48,48,48,48,90,48,129,131,49,11,48,9,6,3,85,4,6,19,2,85,83,49,16,48,14,6,3,85,4,8,19,7,65,114,105,122,111,110,97,49,19,48,17,6,3,85,4,7,19,10,83,99,111,116,116,115,100,97,108,101,49,26,48,24,6,3,85,4,10,19,17,71,111,68,97,100,100,121,46,99,111,109,44,32,73,110,99,46,49,49,48,47,6,3,85,4,3,19,40,71,111,32,68,97,100,100,121,32,82,111,111,116,32,67,101,114,116,105,102,105,99,97,116,101,32,65,117,116,104,111,114,105,116,121,32,45,32,71,50,48,130,1,34,48,13,6,9,42,134,72,134,247,13,1,1,1,5,0,3,130,1,15,0,48,130,1,10,2,130,1,1,0,191,113,98,8,241,250,89,52,247,27,201,24,163,247,128,73,88,233,34,131,19,166,197,32,67,1,59,132,241,230,133,73,159,39,234,246,132,27,78,160,180,219,112,152,199,50,1,177,5,62,7,78,238,244,250,79,47,89,48,34,231,171,25,86,107,226,128,7,252,243,22,117,128,57,81,123,229,249,53,182,116,78,169,141,130,19,228,182,63,169,3,131,250,162,190,138,21,106,127,222,11,195,182,25,20,5,202,234,195,168,4,148,59,70,124,50,13,243,0,102,34,200,141,105,109,54,140,17,24,183,211,178,28,96,180,56,250,2,140,206,211,221,70,7,222,10,62,235,93,124,200,124,251,176,43,83,164,146,98,105,81,37,5,97,26,68,129,140,44,169,67,150,35,223,172,58,129,154,14,41,197,28,169,233,93,30,182,158,158,48,10,57,206,241,136,128,251,75,93,204,50,236,133,98,67,37,52,2,86,39,1,145,180,59,112,42,63,110,177,232,156,136,1,125,159,212,249,219,83,109,96,157,191,44,231,88,171,184,95,70,252,206,196,27,3,60,9,235,73,49,92,105,70,179,224,71,2,3,1,0,1,163,130,1,23,48,130,1,19,48,15,6,3,85,29,19,1,1,255,4,5,48,3,1,1,255,48,14,6,3,85,29,15,1,1,255,4,4,3,2,1,6,48,29,6,3,85,29,14,4,22,4,20,58,154,133,7,16,103,40,182,239,246,189,5,65,110,32,193,148,218,15,222,48,31,6,3,85,29,35,4,24,48,22,128,20,210,196,176,210,145,212,76,17,113,179,97,203,61,161,254,221,168,106,212,227,48,52,6,8,43,6,1,5,5,7,1,1,4,40,48,38,48,36,6,8,43,6,1,5,5,7,48,1,134,24,104,116,116,112,58,47,47,111,99,115,112,46,103,111,100,97,100,100,121,46,99,111,109,47,48,50,6,3,85,29,31,4,43,48,41,48,39,160,37,160,35,134,33,104,116,116,112,58,47,47,99,114,108,46,103,111,100,97,100,100,121,46,99,111,109,47,103,100,114,111,111,116,46,99,114,108,48,70,6,3,85,29,32,4,63,48,61,48,59,6,4,85,29,32,0,48,51,48,49,6,8,43,6,1,5,5,7,2,1,22,37,104,116,116,112,115,58,47,47,99,101,114,116,115,46,103,111,100,97,100,100,121,46,99,111,109,47,114,101,112,111,115,105,116,111,114,121,47,48,13,6,9,42,134,72,134,247,13,1,1,11,5,0,3,130,1,1,0,89,11,83,189,146,134,17,167,36,123,237,91,49,207,29,31,108,112,197,184,110,190,78,187,246,190,151,80,225,48,127,186,40,92,98,148,194,227,126,51,247,251,66,118,133,219,149,28,140,34,88,117,9,12,136,101,103,57,10,22,9,197,160,56,151,164,197,35,147,63,180,24,166,1,6,68,145,227,167,105,39,180,90,37,127,58,183,50,205,221,132,255,42,56,41,51,164,221,103,178,133,254,161,136,32,28,80,137,200,220,42,246,66,3,55,76,230,136,223,213,175,36,242,177,195,223,204,181,236,224,153,94,183,73,84,32,60,148,24,12,199,28,82,24,73,164,109,225,179,88,11,201,216,236,217,174,28,50,142,40,112,13,226,254,166,23,158,132,15,189,87,112,179,90,233,31,160,134,83,187,239,124,255,105,11,224,72,195,183,147,11,200,10,84,196,172,93,20,103,55,108,202,165,47,49,8,55,170,110,111,140,188,155,226,87,93,36,129,175,151,151,156,132,173,108,172,55,76,102,243,97,145,17,32,228,190,48,159,122,164,41,9,176,225,52,95,100,119,24,64,81,223,140,48,166,175,34,147,2,10,4,109,97,105,110,18,31,8,136,217,50,18,25,118,169,20,61,123,48,115,88,170,118,23,109,249,2,118,169,160,185,179,88,139,203,208,136,172,24,181,249,186,212,5,32,185,128,187,212,5,42,99,80,97,121,109,101,110,116,32,114,101,113,117,101,115,116,32,102,111,114,32,66,105,116,80,97,121,32,105,110,118,111,105,99,101,32,53,107,88,85,84,118,88,109,97,54,119,53,70,54,76,49,68,84,68,103,90,86,32,102,111,114,32,109,101,114,99,104,97,110,116,32,66,105,116,80,97,121,32,86,105,115,97,194,174,32,76,111,97,100,32,40,85,83,68,45,85,83,65,41,50,43,104,116,116,112,115,58,47,47,98,105,116,112,97,121,46,99,111,109,47,105,47,53,107,88,85,84,118,88,109,97,54,119,53,70,54,76,49,68,84,68,103,90,86,58,76,123,34,105,110,118,111,105,99,101,73,100,34,58,34,53,107,88,85,84,118,88,109,97,54,119,53,70,54,76,49,68,84,68,103,90,86,34,44,34,109,101,114,99,104,97,110,116,73,100,34,58,34,75,87,122,122,66,82,122,103,115,89,89,112,76,55,102,69,99,80,88,65,74,70,34,125,42,128,2,152,8,184,8,195,9,60,196,244,10,57,69,173,210,197,15,250,159,63,207,251,113,197,140,82,128,181,14,108,56,67,3,237,226,111,227,152,52,148,143,31,1,245,9,26,52,14,178,160,126,17,171,144,59,204,243,147,88,197,71,135,73,241,136,68,127,170,185,53,71,244,135,165,17,18,156,21,224,102,42,122,203,47,128,20,52,90,76,221,100,201,153,155,44,239,109,19,251,2,199,85,242,228,131,182,94,94,104,223,167,247,214,7,172,50,170,220,145,66,129,158,100,246,219,40,157,149,55,137,74,232,16,30,186,127,233,208,47,136,28,210,169,65,21,124,58,206,183,27,93,235,181,105,238,46,43,208,88,88,114,33,29,246,55,243,102,30,118,215,205,147,79,167,118,221,4,145,86,166,71,44,48,166,205,244,189,220,193,120,124,118,138,173,37,233,153,92,130,125,125,10,99,8,126,27,235,93,92,193,0,181,243,105,91,243,188,130,36,229,207,57,35,95,51,63,245,125,240,61,77,34,100,78,199,118,38,2,83,57,97,0,27,89,193,246,207,119,216,15,20,64,86,179,130,220,226 99 | ]; 100 | 101 | 102 | var payProRequestedFeeBuf = [8,1,18,11,120,53,48,57,43,115,104,97,50,53,54,26,161,37,10,188,10,48,130,5,56,48,130,4,32,160,3,2,1,2,2,8,82,132,251,23,70,175,174,71,48,13,6,9,42,134,72,134,247,13,1,1,11,5,0,48,129,180,49,11,48,9,6,3,85,4,6,19,2,85,83,49,16,48,14,6,3,85,4,8,19,7,65,114,105,122,111,110,97,49,19,48,17,6,3,85,4,7,19,10,83,99,111,116,116,115,100,97,108,101,49,26,48,24,6,3,85,4,10,19,17,71,111,68,97,100,100,121,46,99,111,109,44,32,73,110,99,46,49,45,48,43,6,3,85,4,11,19,36,104,116,116,112,58,47,47,99,101,114,116,115,46,103,111,100,97,100,100,121,46,99,111,109,47,114,101,112,111,115,105,116,111,114,121,47,49,51,48,49,6,3,85,4,3,19,42,71,111,32,68,97,100,100,121,32,83,101,99,117,114,101,32,67,101,114,116,105,102,105,99,97,116,101,32,65,117,116,104,111,114,105,116,121,32,45,32,71,50,48,30,23,13,49,55,48,56,48,50,49,52,52,52,48,49,90,23,13,49,56,49,48,48,49,50,49,49,51,51,56,90,48,61,49,33,48,31,6,3,85,4,11,19,24,68,111,109,97,105,110,32,67,111,110,116,114,111,108,32,86,97,108,105,100,97,116,101,100,49,24,48,22,6,3,85,4,3,19,15,116,101,115,116,46,98,105,116,112,97,121,46,99,111,109,48,130,1,34,48,13,6,9,42,134,72,134,247,13,1,1,1,5,0,3,130,1,15,0,48,130,1,10,2,130,1,1,0,209,67,119,182,242,181,10,167,52,39,194,72,145,85,99,210,200,128,77,216,36,177,216,240,21,221,26,226,163,144,200,2,47,217,99,53,88,73,178,23,48,146,8,195,69,10,1,111,244,0,30,227,54,163,24,158,218,220,225,43,196,30,73,153,228,95,111,207,11,0,218,167,233,164,177,46,114,220,225,156,81,174,142,85,184,191,236,2,184,10,88,204,178,193,179,229,189,232,31,103,155,153,147,191,82,200,113,161,250,222,246,187,95,125,141,146,8,136,148,0,186,43,225,210,186,248,46,195,3,71,8,82,87,12,59,187,107,137,51,77,137,116,230,27,136,103,191,41,159,184,2,197,126,155,0,217,185,247,5,114,172,109,129,254,205,48,76,131,170,242,31,79,59,82,158,152,152,234,155,134,143,143,7,180,24,150,104,231,24,84,174,119,107,172,208,217,112,106,139,224,63,82,140,104,173,2,62,59,69,191,165,94,155,66,229,53,170,252,126,184,103,38,69,220,222,175,114,4,164,104,210,184,79,39,237,18,7,42,65,22,39,100,113,8,228,33,171,231,48,142,59,172,48,88,150,241,2,3,1,0,1,163,130,1,194,48,130,1,190,48,12,6,3,85,29,19,1,1,255,4,2,48,0,48,29,6,3,85,29,37,4,22,48,20,6,8,43,6,1,5,5,7,3,1,6,8,43,6,1,5,5,7,3,2,48,14,6,3,85,29,15,1,1,255,4,4,3,2,5,160,48,55,6,3,85,29,31,4,48,48,46,48,44,160,42,160,40,134,38,104,116,116,112,58,47,47,99,114,108,46,103,111,100,97,100,100,121,46,99,111,109,47,103,100,105,103,50,115,49,45,54,50,57,46,99,114,108,48,93,6,3,85,29,32,4,86,48,84,48,72,6,11,96,134,72,1,134,253,109,1,7,23,1,48,57,48,55,6,8,43,6,1,5,5,7,2,1,22,43,104,116,116,112,58,47,47,99,101,114,116,105,102,105,99,97,116,101,115,46,103,111,100,97,100,100,121,46,99,111,109,47,114,101,112,111,115,105,116,111,114,121,47,48,8,6,6,103,129,12,1,2,1,48,118,6,8,43,6,1,5,5,7,1,1,4,106,48,104,48,36,6,8,43,6,1,5,5,7,48,1,134,24,104,116,116,112,58,47,47,111,99,115,112,46,103,111,100,97,100,100,121,46,99,111,109,47,48,64,6,8,43,6,1,5,5,7,48,2,134,52,104,116,116,112,58,47,47,99,101,114,116,105,102,105,99,97,116,101,115,46,103,111,100,97,100,100,121,46,99,111,109,47,114,101,112,111,115,105,116,111,114,121,47,103,100,105,103,50,46,99,114,116,48,31,6,3,85,29,35,4,24,48,22,128,20,64,194,189,39,142,204,52,131,48,162,51,215,251,108,179,240,180,44,128,206,48,47,6,3,85,29,17,4,40,48,38,130,15,116,101,115,116,46,98,105,116,112,97,121,46,99,111,109,130,19,119,119,119,46,116,101,115,116,46,98,105,116,112,97,121,46,99,111,109,48,29,6,3,85,29,14,4,22,4,20,44,216,222,247,214,76,98,12,206,120,189,236,54,95,217,97,207,208,53,225,48,13,6,9,42,134,72,134,247,13,1,1,11,5,0,3,130,1,1,0,103,144,52,138,225,242,249,254,151,178,78,79,230,198,153,173,225,96,72,151,60,119,198,130,227,30,132,219,66,1,131,165,81,194,21,37,255,131,60,156,57,41,133,106,233,178,129,248,28,117,94,118,98,162,85,127,193,222,42,80,107,62,42,64,225,183,7,154,246,211,26,99,214,83,198,211,139,167,236,174,22,214,7,16,188,49,85,166,23,17,181,149,93,105,250,35,62,75,183,232,217,221,234,132,117,208,134,36,225,173,197,143,42,44,204,240,25,28,107,249,191,76,111,200,62,7,33,110,171,255,151,29,182,10,226,19,97,75,199,100,20,254,163,81,116,78,14,3,104,204,83,65,232,73,43,80,2,170,96,194,111,242,244,82,93,23,168,14,176,223,129,170,32,69,123,68,24,170,42,12,95,42,52,79,84,160,128,60,118,23,67,199,230,12,197,12,55,78,121,16,253,137,67,198,154,193,18,85,132,60,143,14,174,12,237,56,42,45,235,220,225,187,104,118,99,121,192,4,80,203,233,88,64,141,67,212,113,172,235,195,95,16,217,221,34,132,102,202,47,223,131,243,247,145,219,23,10,212,9,48,130,4,208,48,130,3,184,160,3,2,1,2,2,1,7,48,13,6,9,42,134,72,134,247,13,1,1,11,5,0,48,129,131,49,11,48,9,6,3,85,4,6,19,2,85,83,49,16,48,14,6,3,85,4,8,19,7,65,114,105,122,111,110,97,49,19,48,17,6,3,85,4,7,19,10,83,99,111,116,116,115,100,97,108,101,49,26,48,24,6,3,85,4,10,19,17,71,111,68,97,100,100,121,46,99,111,109,44,32,73,110,99,46,49,49,48,47,6,3,85,4,3,19,40,71,111,32,68,97,100,100,121,32,82,111,111,116,32,67,101,114,116,105,102,105,99,97,116,101,32,65,117,116,104,111,114,105,116,121,32,45,32,71,50,48,30,23,13,49,49,48,53,48,51,48,55,48,48,48,48,90,23,13,51,49,48,53,48,51,48,55,48,48,48,48,90,48,129,180,49,11,48,9,6,3,85,4,6,19,2,85,83,49,16,48,14,6,3,85,4,8,19,7,65,114,105,122,111,110,97,49,19,48,17,6,3,85,4,7,19,10,83,99,111,116,116,115,100,97,108,101,49,26,48,24,6,3,85,4,10,19,17,71,111,68,97,100,100,121,46,99,111,109,44,32,73,110,99,46,49,45,48,43,6,3,85,4,11,19,36,104,116,116,112,58,47,47,99,101,114,116,115,46,103,111,100,97,100,100,121,46,99,111,109,47,114,101,112,111,115,105,116,111,114,121,47,49,51,48,49,6,3,85,4,3,19,42,71,111,32,68,97,100,100,121,32,83,101,99,117,114,101,32,67,101,114,116,105,102,105,99,97,116,101,32,65,117,116,104,111,114,105,116,121,32,45,32,71,50,48,130,1,34,48,13,6,9,42,134,72,134,247,13,1,1,1,5,0,3,130,1,15,0,48,130,1,10,2,130,1,1,0,185,224,203,16,212,175,118,189,212,147,98,235,48,100,184,129,8,108,195,4,217,98,23,142,47,255,62,101,207,143,206,98,230,60,82,28,218,22,69,75,85,171,120,107,99,131,98,144,206,15,105,108,153,200,26,20,139,76,204,69,51,234,136,220,158,163,175,43,254,128,97,157,121,87,196,207,46,244,63,48,60,93,71,252,154,22,188,195,55,150,65,81,142,17,75,84,248,40,190,208,140,190,240,48,56,30,243,176,38,248,102,71,99,109,222,113,38,71,143,56,71,83,209,70,29,180,227,220,0,234,69,172,189,188,113,217,170,111,0,219,219,205,48,58,121,79,95,76,71,248,29,239,91,194,196,157,96,59,177,178,67,145,216,164,51,78,234,179,214,39,79,173,37,138,165,198,244,213,208,166,174,116,5,100,87,136,181,68,85,212,45,42,58,62,248,184,189,233,50,10,2,148,100,196,22,58,80,241,74,174,231,121,51,175,12,32,7,127,232,223,4,57,194,105,2,108,99,82,250,119,193,27,200,116,135,200,185,147,24,80,84,53,75,105,78,188,59,211,73,46,31,220,193,210,82,251,2,3,1,0,1,163,130,1,26,48,130,1,22,48,15,6,3,85,29,19,1,1,255,4,5,48,3,1,1,255,48,14,6,3,85,29,15,1,1,255,4,4,3,2,1,6,48,29,6,3,85,29,14,4,22,4,20,64,194,189,39,142,204,52,131,48,162,51,215,251,108,179,240,180,44,128,206,48,31,6,3,85,29,35,4,24,48,22,128,20,58,154,133,7,16,103,40,182,239,246,189,5,65,110,32,193,148,218,15,222,48,52,6,8,43,6,1,5,5,7,1,1,4,40,48,38,48,36,6,8,43,6,1,5,5,7,48,1,134,24,104,116,116,112,58,47,47,111,99,115,112,46,103,111,100,97,100,100,121,46,99,111,109,47,48,53,6,3,85,29,31,4,46,48,44,48,42,160,40,160,38,134,36,104,116,116,112,58,47,47,99,114,108,46,103,111,100,97,100,100,121,46,99,111,109,47,103,100,114,111,111,116,45,103,50,46,99,114,108,48,70,6,3,85,29,32,4,63,48,61,48,59,6,4,85,29,32,0,48,51,48,49,6,8,43,6,1,5,5,7,2,1,22,37,104,116,116,112,115,58,47,47,99,101,114,116,115,46,103,111,100,97,100,100,121,46,99,111,109,47,114,101,112,111,115,105,116,111,114,121,47,48,13,6,9,42,134,72,134,247,13,1,1,11,5,0,3,130,1,1,0,8,126,108,147,16,200,56,184,150,169,144,75,255,161,95,79,4,239,108,62,156,136,6,201,80,143,166,115,247,87,49,27,190,188,228,47,219,248,186,211,91,224,180,231,230,121,98,14,12,162,215,106,99,115,49,181,245,168,72,164,59,8,45,162,93,144,215,180,124,37,79,17,86,48,196,182,68,157,123,44,157,229,94,230,239,12,97,170,191,228,42,27,238,132,158,184,131,125,193,67,206,68,167,19,112,13,145,31,244,200,19,173,131,96,217,216,114,168,115,36,30,181,172,34,14,202,23,137,98,88,68,27,171,137,37,1,0,15,205,196,27,98,219,81,180,211,15,81,42,155,244,188,115,252,118,206,54,164,205,217,216,44,234,174,155,245,42,178,144,209,77,117,24,138,63,138,65,144,35,125,91,75,254,164,3,88,155,70,178,195,96,96,131,248,125,80,65,206,194,161,144,195,187,239,2,47,210,21,84,238,68,21,217,10,174,167,138,51,237,177,45,118,54,38,220,4,235,159,247,97,31,21,220,135,111,238,70,150,40,173,161,38,125,10,9,167,46,4,163,141,188,248,188,4,48,1,10,129,9,48,130,4,125,48,130,3,101,160,3,2,1,2,2,3,27,231,21,48,13,6,9,42,134,72,134,247,13,1,1,11,5,0,48,99,49,11,48,9,6,3,85,4,6,19,2,85,83,49,33,48,31,6,3,85,4,10,19,24,84,104,101,32,71,111,32,68,97,100,100,121,32,71,114,111,117,112,44,32,73,110,99,46,49,49,48,47,6,3,85,4,11,19,40,71,111,32,68,97,100,100,121,32,67,108,97,115,115,32,50,32,67,101,114,116,105,102,105,99,97,116,105,111,110,32,65,117,116,104,111,114,105,116,121,48,30,23,13,49,52,48,49,48,49,48,55,48,48,48,48,90,23,13,51,49,48,53,51,48,48,55,48,48,48,48,90,48,129,131,49,11,48,9,6,3,85,4,6,19,2,85,83,49,16,48,14,6,3,85,4,8,19,7,65,114,105,122,111,110,97,49,19,48,17,6,3,85,4,7,19,10,83,99,111,116,116,115,100,97,108,101,49,26,48,24,6,3,85,4,10,19,17,71,111,68,97,100,100,121,46,99,111,109,44,32,73,110,99,46,49,49,48,47,6,3,85,4,3,19,40,71,111,32,68,97,100,100,121,32,82,111,111,116,32,67,101,114,116,105,102,105,99,97,116,101,32,65,117,116,104,111,114,105,116,121,32,45,32,71,50,48,130,1,34,48,13,6,9,42,134,72,134,247,13,1,1,1,5,0,3,130,1,15,0,48,130,1,10,2,130,1,1,0,191,113,98,8,241,250,89,52,247,27,201,24,163,247,128,73,88,233,34,131,19,166,197,32,67,1,59,132,241,230,133,73,159,39,234,246,132,27,78,160,180,219,112,152,199,50,1,177,5,62,7,78,238,244,250,79,47,89,48,34,231,171,25,86,107,226,128,7,252,243,22,117,128,57,81,123,229,249,53,182,116,78,169,141,130,19,228,182,63,169,3,131,250,162,190,138,21,106,127,222,11,195,182,25,20,5,202,234,195,168,4,148,59,70,124,50,13,243,0,102,34,200,141,105,109,54,140,17,24,183,211,178,28,96,180,56,250,2,140,206,211,221,70,7,222,10,62,235,93,124,200,124,251,176,43,83,164,146,98,105,81,37,5,97,26,68,129,140,44,169,67,150,35,223,172,58,129,154,14,41,197,28,169,233,93,30,182,158,158,48,10,57,206,241,136,128,251,75,93,204,50,236,133,98,67,37,52,2,86,39,1,145,180,59,112,42,63,110,177,232,156,136,1,125,159,212,249,219,83,109,96,157,191,44,231,88,171,184,95,70,252,206,196,27,3,60,9,235,73,49,92,105,70,179,224,71,2,3,1,0,1,163,130,1,23,48,130,1,19,48,15,6,3,85,29,19,1,1,255,4,5,48,3,1,1,255,48,14,6,3,85,29,15,1,1,255,4,4,3,2,1,6,48,29,6,3,85,29,14,4,22,4,20,58,154,133,7,16,103,40,182,239,246,189,5,65,110,32,193,148,218,15,222,48,31,6,3,85,29,35,4,24,48,22,128,20,210,196,176,210,145,212,76,17,113,179,97,203,61,161,254,221,168,106,212,227,48,52,6,8,43,6,1,5,5,7,1,1,4,40,48,38,48,36,6,8,43,6,1,5,5,7,48,1,134,24,104,116,116,112,58,47,47,111,99,115,112,46,103,111,100,97,100,100,121,46,99,111,109,47,48,50,6,3,85,29,31,4,43,48,41,48,39,160,37,160,35,134,33,104,116,116,112,58,47,47,99,114,108,46,103,111,100,97,100,100,121,46,99,111,109,47,103,100,114,111,111,116,46,99,114,108,48,70,6,3,85,29,32,4,63,48,61,48,59,6,4,85,29,32,0,48,51,48,49,6,8,43,6,1,5,5,7,2,1,22,37,104,116,116,112,115,58,47,47,99,101,114,116,115,46,103,111,100,97,100,100,121,46,99,111,109,47,114,101,112,111,115,105,116,111,114,121,47,48,13,6,9,42,134,72,134,247,13,1,1,11,5,0,3,130,1,1,0,89,11,83,189,146,134,17,167,36,123,237,91,49,207,29,31,108,112,197,184,110,190,78,187,246,190,151,80,225,48,127,186,40,92,98,148,194,227,126,51,247,251,66,118,133,219,149,28,140,34,88,117,9,12,136,101,103,57,10,22,9,197,160,56,151,164,197,35,147,63,180,24,166,1,6,68,145,227,167,105,39,180,90,37,127,58,183,50,205,221,132,255,42,56,41,51,164,221,103,178,133,254,161,136,32,28,80,137,200,220,42,246,66,3,55,76,230,136,223,213,175,36,242,177,195,223,204,181,236,224,153,94,183,73,84,32,60,148,24,12,199,28,82,24,73,164,109,225,179,88,11,201,216,236,217,174,28,50,142,40,112,13,226,254,166,23,158,132,15,189,87,112,179,90,233,31,160,134,83,187,239,124,255,105,11,224,72,195,183,147,11,200,10,84,196,172,93,20,103,55,108,202,165,47,49,8,55,170,110,111,140,188,155,226,87,93,36,129,175,151,151,156,132,173,108,172,55,76,102,243,97,145,17,32,228,190,48,159,122,164,41,9,176,225,52,95,100,119,24,64,81,223,140,48,166,175,10,132,8,48,130,4,0,48,130,2,232,160,3,2,1,2,2,1,0,48,13,6,9,42,134,72,134,247,13,1,1,5,5,0,48,99,49,11,48,9,6,3,85,4,6,19,2,85,83,49,33,48,31,6,3,85,4,10,19,24,84,104,101,32,71,111,32,68,97,100,100,121,32,71,114,111,117,112,44,32,73,110,99,46,49,49,48,47,6,3,85,4,11,19,40,71,111,32,68,97,100,100,121,32,67,108,97,115,115,32,50,32,67,101,114,116,105,102,105,99,97,116,105,111,110,32,65,117,116,104,111,114,105,116,121,48,30,23,13,48,52,48,54,50,57,49,55,48,54,50,48,90,23,13,51,52,48,54,50,57,49,55,48,54,50,48,90,48,99,49,11,48,9,6,3,85,4,6,19,2,85,83,49,33,48,31,6,3,85,4,10,19,24,84,104,101,32,71,111,32,68,97,100,100,121,32,71,114,111,117,112,44,32,73,110,99,46,49,49,48,47,6,3,85,4,11,19,40,71,111,32,68,97,100,100,121,32,67,108,97,115,115,32,50,32,67,101,114,116,105,102,105,99,97,116,105,111,110,32,65,117,116,104,111,114,105,116,121,48,130,1,32,48,13,6,9,42,134,72,134,247,13,1,1,1,5,0,3,130,1,13,0,48,130,1,8,2,130,1,1,0,222,157,215,234,87,24,73,161,91,235,215,95,72,134,234,190,221,255,228,239,103,28,244,101,104,179,87,113,160,94,119,187,237,155,73,233,112,128,61,86,24,99,8,111,218,242,204,208,63,127,2,84,34,84,16,216,178,129,212,192,117,61,75,127,199,119,195,62,120,171,26,3,181,32,107,47,106,43,177,197,136,126,196,187,30,176,193,216,69,39,111,170,55,88,247,135,38,215,216,45,246,169,23,183,31,114,54,78,166,23,63,101,152,146,219,42,110,93,162,254,136,224,11,222,127,229,141,21,225,235,203,58,213,226,18,162,19,45,216,142,175,95,18,61,160,8,5,8,182,92,165,101,56,4,69,153,30,163,96,96,116,197,65,165,114,98,27,98,197,31,111,95,26,66,190,2,81,101,168,174,35,24,106,252,120,3,169,77,127,128,195,250,171,90,252,161,64,164,202,25,22,254,178,200,239,94,115,13,238,119,189,154,246,121,152,188,177,7,103,162,21,13,221,160,88,198,68,123,10,62,98,40,95,186,65,7,83,88,207,17,126,56,116,197,248,255,181,105,144,143,132,116,234,151,27,175,2,1,3,163,129,192,48,129,189,48,29,6,3,85,29,14,4,22,4,20,210,196,176,210,145,212,76,17,113,179,97,203,61,161,254,221,168,106,212,227,48,129,141,6,3,85,29,35,4,129,133,48,129,130,128,20,210,196,176,210,145,212,76,17,113,179,97,203,61,161,254,221,168,106,212,227,161,103,164,101,48,99,49,11,48,9,6,3,85,4,6,19,2,85,83,49,33,48,31,6,3,85,4,10,19,24,84,104,101,32,71,111,32,68,97,100,100,121,32,71,114,111,117,112,44,32,73,110,99,46,49,49,48,47,6,3,85,4,11,19,40,71,111,32,68,97,100,100,121,32,67,108,97,115,115,32,50,32,67,101,114,116,105,102,105,99,97,116,105,111,110,32,65,117,116,104,111,114,105,116,121,130,1,0,48,12,6,3,85,29,19,4,5,48,3,1,1,255,48,13,6,9,42,134,72,134,247,13,1,1,5,5,0,3,130,1,1,0,50,75,243,178,202,62,145,252,18,198,161,7,140,142,119,160,51,6,20,92,144,30,24,247,8,166,61,10,25,249,135,128,17,110,105,228,150,23,48,255,52,145,99,114,56,238,204,28,1,163,29,148,40,164,49,246,122,196,84,215,246,229,49,88,3,162,204,206,98,219,148,69,115,181,191,69,201,36,181,213,130,2,173,35,121,105,141,184,182,77,206,207,76,202,51,35,232,28,136,170,157,139,65,110,22,201,32,229,137,158,205,59,218,112,247,126,153,38,32,20,84,37,171,110,115,133,230,155,33,157,10,108,130,14,168,248,194,12,250,16,30,108,150,239,135,13,196,15,97,139,173,238,131,43,149,248,142,146,132,114,57,235,32,234,131,237,131,205,151,110,8,188,235,78,38,182,115,43,228,211,246,76,254,38,113,226,97,17,116,74,255,87,26,135,15,117,72,46,207,81,105,23,160,2,18,97,149,213,209,64,178,16,76,238,196,172,16,67,166,165,158,10,213,149,98,154,13,207,136,130,197,50,12,228,43,159,69,230,13,159,40,156,177,185,42,90,87,173,55,15,175,29,127,219,189,159,34,134,2,10,4,116,101,115,116,18,30,8,184,73,18,25,118,169,20,123,206,251,180,53,214,153,182,120,164,72,246,213,50,179,37,246,189,127,0,136,172,24,230,177,215,212,5,32,234,184,215,212,5,42,77,80,97,121,109,101,110,116,32,114,101,113,117,101,115,116,32,102,111,114,32,66,105,116,80,97,121,32,105,110,118,111,105,99,101,32,52,81,90,113,72,115,80,52,50,87,87,122,107,101,99,55,52,106,84,72,99,52,32,102,111,114,32,109,101,114,99,104,97,110,116,32,71,117,115,80,97,121,50,48,104,116,116,112,115,58,47,47,116,101,115,116,46,98,105,116,112,97,121,46,99,111,109,47,105,47,52,81,90,113,72,115,80,52,50,87,87,122,107,101,99,55,52,106,84,72,99,52,58,76,123,34,105,110,118,111,105,99,101,73,100,34,58,34,52,81,90,113,72,115,80,52,50,87,87,122,107,101,99,55,52,106,84,72,99,52,34,44,34,109,101,114,99,104,97,110,116,73,100,34,58,34,85,49,111,90,74,90,115,109,118,99,84,122,84,112,99,82,109,65,88,53,83,101,34,125,69,0,0,128,63,42,128,2,70,114,23,53,204,48,9,189,241,10,199,96,195,112,153,158,199,101,222,248,177,58,95,149,67,105,76,120,70,29,15,61,159,98,68,103,9,217,40,21,24,145,238,240,186,113,52,22,153,88,94,243,75,31,25,113,89,192,84,192,212,123,3,224,103,7,62,66,176,21,108,105,95,202,228,119,23,131,134,41,255,175,80,166,177,160,111,104,243,11,24,141,254,219,37,91,162,123,243,173,233,196,140,38,23,39,183,48,129,49,69,218,83,155,138,67,129,71,36,117,111,21,64,125,49,171,78,85,123,226,137,54,29,112,3,32,117,91,43,55,116,103,71,67,182,26,42,39,34,243,134,231,57,147,253,6,236,157,145,115,134,64,211,6,195,168,84,95,116,43,123,178,82,120,76,96,128,161,141,23,67,229,109,128,224,132,181,52,135,66,240,117,155,11,37,240,11,186,87,204,95,22,84,207,202,76,213,100,111,6,165,152,243,238,106,220,65,145,36,216,201,1,24,182,2,227,122,103,209,182,216,219,196,231,130,125,178,158,85,101,217,111,62,198,58,208,60,104,83,50,92,150,143,52,134,186]; 103 | 104 | 105 | module.exports.history = history; 106 | module.exports.payProBuf = new Buffer(payproHex, 'hex'); 107 | module.exports.payProAckBuf = new Buffer(payAck); 108 | module.exports.payProData = payProData; 109 | module.exports.payProDataBchBuf = new Buffer(payProBufBCH); 110 | module.exports.payProRequestedFeeBuf = new Buffer(payProRequestedFeeBuf); 111 | -------------------------------------------------------------------------------- /test/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _ = require('lodash'); 4 | var chai = require('chai'); 5 | var sinon = require('sinon'); 6 | var should = chai.should(); 7 | var Bitcore = require('bitcore-lib'); 8 | 9 | var Utils = require('../lib/common/utils'); 10 | 11 | describe('Utils', function() { 12 | describe('#hashMessage', function() { 13 | it('should create a hash', function() { 14 | var res = Utils.hashMessage('hola'); 15 | res.toString('hex').should.equal('4102b8a140ec642feaa1c645345f714bc7132d4fd2f7f6202db8db305a96172f'); 16 | }); 17 | }); 18 | 19 | describe('#signMessage', function() { 20 | it('should sign a message', function() { 21 | var sig = Utils.signMessage('hola', '09458c090a69a38368975fb68115df2f4b0ab7d1bc463fc60c67aa1730641d6c'); 22 | should.exist(sig); 23 | sig.should.equal('3045022100f2e3369dd4813d4d42aa2ed74b5cf8e364a8fa13d43ec541e4bc29525e0564c302205b37a7d1ca73f684f91256806cdad4b320b4ed3000bee2e388bcec106e0280e0'); 24 | }); 25 | it('should fail to sign with wrong args', function() { 26 | (function() { 27 | Utils.signMessage('hola', '03bec86ad4a8a91fe7c11ec06af27246ec55094db3d86098b7d8b2f12afe47627f'); 28 | }).should.throw('Number'); 29 | }); 30 | }); 31 | 32 | describe('#verifyMessage', function() { 33 | it('should fail to verify a malformed signature', function() { 34 | var res = Utils.verifyMessage('hola', 'badsignature', '02555a2d45e309c00cc8c5090b6ec533c6880ab2d3bc970b3943def989b3373f16'); 35 | should.exist(res); 36 | res.should.equal(false); 37 | }); 38 | it('should fail to verify a null signature', function() { 39 | var res = Utils.verifyMessage('hola', null, '02555a2d45e309c00cc8c5090b6ec533c6880ab2d3bc970b3943def989b3373f16'); 40 | should.exist(res); 41 | res.should.equal(false); 42 | }); 43 | it('should fail to verify with wrong pubkey', function() { 44 | var res = Utils.verifyMessage('hola', '3045022100d6186930e4cd9984e3168e15535e2297988555838ad10126d6c20d4ac0e74eb502201095a6319ea0a0de1f1e5fb50f7bf10b8069de10e0083e23dbbf8de9b8e02785', '02555a2d45e309c00cc8c5090b6ec533c6880ab2d3bc970b3943def989b3373f16'); 45 | should.exist(res); 46 | res.should.equal(false); 47 | }); 48 | it('should verify', function() { 49 | var res = Utils.verifyMessage('hola', '3045022100d6186930e4cd9984e3168e15535e2297988555838ad10126d6c20d4ac0e74eb502201095a6319ea0a0de1f1e5fb50f7bf10b8069de10e0083e23dbbf8de9b8e02785', '03bec86ad4a8a91fe7c11ec06af27246ec55094db3d86098b7d8b2f12afe47627f'); 50 | should.exist(res); 51 | res.should.equal(true); 52 | }); 53 | }); 54 | 55 | describe('#formatAmount', function() { 56 | it('should successfully format short amount', function() { 57 | var cases = [{ 58 | args: [1, 'bit'], 59 | expected: '0', 60 | }, { 61 | args: [1, 'btc'], 62 | expected: '0.00', 63 | }, { 64 | args: [400050000, 'btc'], 65 | expected: '4.0005', 66 | }, { 67 | args: [400000000, 'btc'], 68 | expected: '4.00', 69 | }, { 70 | args: [49999, 'btc'], 71 | expected: '0.000499', 72 | }, { 73 | args: [100000000, 'btc'], 74 | expected: '1.00', 75 | }, { 76 | args: [0, 'bit'], 77 | expected: '0', 78 | }, { 79 | args: [12345678, 'bit'], 80 | expected: '123,456', 81 | }, { 82 | args: [12345678, 'btc'], 83 | expected: '0.123456', 84 | }, { 85 | args: [12345611, 'btc'], 86 | expected: '0.123456', 87 | }, { 88 | args: [1234, 'btc'], 89 | expected: '0.000012', 90 | }, { 91 | args: [1299, 'btc'], 92 | expected: '0.000012', 93 | }, { 94 | args: [1234567899999, 'btc'], 95 | expected: '12,345.678999', 96 | }, { 97 | args: [12345678, 'bit', { 98 | thousandsSeparator: '.' 99 | }], 100 | expected: '123.456', 101 | }, { 102 | args: [12345678, 'btc', { 103 | decimalSeparator: ',' 104 | }], 105 | expected: '0,123456', 106 | }, { 107 | args: [1234567899999, 'btc', { 108 | thousandsSeparator: ' ', 109 | decimalSeparator: ',' 110 | }], 111 | expected: '12 345,678999', 112 | }, ]; 113 | 114 | _.each(cases, function(testCase) { 115 | Utils.formatAmount.apply(this, testCase.args).should.equal(testCase.expected); 116 | }); 117 | }); 118 | it('should successfully format full amount', function() { 119 | var cases = [{ 120 | args: [1, 'bit'], 121 | expected: '0.01', 122 | }, { 123 | args: [1, 'btc'], 124 | expected: '0.00000001', 125 | }, { 126 | args: [0, 'bit'], 127 | expected: '0.00', 128 | }, { 129 | args: [12345678, 'bit'], 130 | expected: '123,456.78', 131 | }, { 132 | args: [12345678, 'btc'], 133 | expected: '0.12345678', 134 | }, { 135 | args: [1234567, 'btc'], 136 | expected: '0.01234567', 137 | }, { 138 | args: [12345611, 'btc'], 139 | expected: '0.12345611', 140 | }, { 141 | args: [1234, 'btc'], 142 | expected: '0.00001234', 143 | }, { 144 | args: [1299, 'btc'], 145 | expected: '0.00001299', 146 | }, { 147 | args: [1234567899999, 'btc'], 148 | expected: '12,345.67899999', 149 | }, { 150 | args: [12345678, 'bit', { 151 | thousandsSeparator: "'" 152 | }], 153 | expected: "123'456.78", 154 | }, { 155 | args: [12345678, 'btc', { 156 | decimalSeparator: ',' 157 | }], 158 | expected: '0,12345678', 159 | }, { 160 | args: [1234567899999, 'btc', { 161 | thousandsSeparator: ' ', 162 | decimalSeparator: ',' 163 | }], 164 | expected: '12 345,67899999', 165 | }, ]; 166 | 167 | _.each(cases, function(testCase) { 168 | testCase.args[2] = testCase.args[2] || {}; 169 | testCase.args[2].fullPrecision = true; 170 | Utils.formatAmount.apply(this, testCase.args).should.equal(testCase.expected); 171 | }); 172 | }); 173 | }); 174 | 175 | describe('#signMessage #verifyMessage round trip', function() { 176 | it('should sign and verify', function() { 177 | var msg = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; 178 | var sig = Utils.signMessage(msg, '09458c090a69a38368975fb68115df2f4b0ab7d1bc463fc60c67aa1730641d6c'); 179 | Utils.verifyMessage(msg, sig, '03bec86ad4a8a91fe7c11ec06af27246ec55094db3d86098b7d8b2f12afe47627f').should.equal(true); 180 | }); 181 | }); 182 | 183 | describe('#encryptMessage #decryptMessage round trip', function() { 184 | it('should encrypt and decrypt', function() { 185 | var pwd = "ezDRS2NRchMJLf1IWtjL5A=="; 186 | var ct = Utils.encryptMessage('hello world', pwd); 187 | var msg = Utils.decryptMessage(ct, pwd); 188 | msg.should.equal('hello world'); 189 | }); 190 | }); 191 | 192 | 193 | describe('#decryptMessage should throw', function() { 194 | it('should encrypt and decrypt', function() { 195 | var pwd = "ezDRS2NRchMJLf1IWtjL5A=="; 196 | var ct = Utils.encryptMessage('hello world', pwd); 197 | (function(){ 198 | Utils.decryptMessage(ct, 'test') 199 | }).should.throw('invalid aes key size'); 200 | }); 201 | }); 202 | 203 | describe('#decryptMessageNoThrow should not throw', function() { 204 | it('should encrypt and decrypt', function() { 205 | var pwd = "ezDRS2NRchMJLf1IWtjL5A=="; 206 | var ct = Utils.encryptMessage('hello world', pwd); 207 | var msg = Utils.decryptMessageNoThrow(ct, pwd); 208 | 209 | msg.should.equal('hello world'); 210 | }); 211 | 212 | it('should encrypt and fail to decrypt', function() { 213 | var pwd = "ezDRS2NRchMJLf1IWtjL5A=="; 214 | var ct = Utils.encryptMessage('hello world', pwd); 215 | var msg = Utils.decryptMessageNoThrow(ct, 'hola'); 216 | 217 | msg.should.equal(''); 218 | }); 219 | 220 | 221 | it('should failover to decrypt a non-encrypted msg' , function() { 222 | var pwd = "ezDRS2NRchMJLf1IWtjL5A=="; 223 | var msg = Utils.decryptMessageNoThrow('hola mundo', 'hola'); 224 | 225 | msg.should.equal('hola mundo'); 226 | }); 227 | 228 | it('should failover to decrypt a non-encrypted msg (case 2)' , function() { 229 | var pwd = "ezDRS2NRchMJLf1IWtjL5A=="; 230 | var msg = Utils.decryptMessageNoThrow('{"pepe":1}', 'hola'); 231 | 232 | msg.should.equal('{"pepe":1}'); 233 | }); 234 | 235 | 236 | it('should no try to decrypt empty', function() { 237 | var msg = Utils.decryptMessageNoThrow('', 'hola'); 238 | msg.should.equal(''); 239 | }); 240 | 241 | 242 | it('should no try to decrypt null', function() { 243 | var msg = Utils.decryptMessageNoThrow(null, 'hola'); 244 | msg.should.equal(''); 245 | }); 246 | 247 | 248 | }); 249 | 250 | 251 | 252 | describe('#getProposalHash', function() { 253 | it('should compute hash for old style proposals', function() { 254 | var hash = Utils.getProposalHash('msj42CCGruhRsFrGATiUuh25dtxYtnpbTx', 1234, 'the message'); 255 | hash.should.equal('msj42CCGruhRsFrGATiUuh25dtxYtnpbTx|1234|the message|'); 256 | }); 257 | it('should compute hash for arbitrary proposal', function() { 258 | var header1 = { 259 | type: 'simple', 260 | version: '1.0', 261 | toAddress: 'msj42CCGruhRsFrGATiUuh25dtxYtnpbTx', 262 | amount: 1234, 263 | message: { 264 | one: 'one', 265 | two: 'two' 266 | }, 267 | }; 268 | 269 | var header2 = { 270 | toAddress: 'msj42CCGruhRsFrGATiUuh25dtxYtnpbTx', 271 | type: 'simple', 272 | version: '1.0', 273 | message: { 274 | two: 'two', 275 | one: 'one' 276 | }, 277 | amount: 1234, 278 | }; 279 | 280 | var hash1 = Utils.getProposalHash(header1); 281 | var hash2 = Utils.getProposalHash(header2); 282 | 283 | hash1.should.equal(hash2); 284 | }); 285 | }); 286 | 287 | describe('#privateKeyToAESKey', function() { 288 | it('should be ok', function() { 289 | var privKey = new Bitcore.PrivateKey('09458c090a69a38368975fb68115df2f4b0ab7d1bc463fc60c67aa1730641d6c').toString(); 290 | Utils.privateKeyToAESKey(privKey).should.be.equal('2HvmUYBSD0gXLea6z0n7EQ=='); 291 | }); 292 | it('should fail if pk has invalid values', function() { 293 | var values = [ 294 | null, 295 | 123, 296 | 'x123', 297 | ]; 298 | _.each(values, function(value) { 299 | var valid = true; 300 | try { 301 | Utils.privateKeyToAESKey(value); 302 | } catch (e) { 303 | valid = false; 304 | } 305 | valid.should.be.false; 306 | }); 307 | }); 308 | }); 309 | 310 | describe('#verifyRequestPubKey', function() { 311 | it('should generate and check request pub key', function() { 312 | var reqPubKey = (new Bitcore.PrivateKey).toPublicKey(); 313 | var xPrivKey = new Bitcore.HDPrivateKey(); 314 | var xPubKey = new Bitcore.HDPublicKey(xPrivKey); 315 | 316 | 317 | var sig = Utils.signRequestPubKey(reqPubKey.toString(), xPrivKey); 318 | var valid = Utils.verifyRequestPubKey(reqPubKey.toString(), sig, xPubKey); 319 | valid.should.be.equal(true); 320 | }); 321 | 322 | it('should fail to check a request pub key with wrong key', function() { 323 | var reqPubKey = '02c2c1c6e75cfc50235ff4a2eb848385c2871b8c94e285ee82eaced1dcd5dd568e'; 324 | var xPrivKey = new Bitcore.HDPrivateKey(); 325 | var xPubKey = new Bitcore.HDPublicKey(xPrivKey); 326 | var sig = Utils.signRequestPubKey(reqPubKey, xPrivKey); 327 | 328 | var xPrivKey2 = new Bitcore.HDPrivateKey(); 329 | var xPubKey2 = new Bitcore.HDPublicKey(xPrivKey2); 330 | var valid = Utils.verifyRequestPubKey(reqPubKey, sig, xPubKey2); 331 | valid.should.be.equal(false); 332 | }); 333 | }); 334 | }); 335 | --------------------------------------------------------------------------------