├── bitcore-wallet-client.min.js
├── .coveralls.yml
├── index.js
├── test
├── test-config.js
├── log.js
├── paypro.js
├── utils.js
├── credentials.js
├── testdata.js
└── legacyImportData.js
├── README.md
├── lib
├── common
│ ├── index.js
│ ├── defaults.js
│ ├── constants.js
│ └── utils.js
├── index.js
├── errors
│ ├── index.js
│ └── spec.js
├── log.js
├── verifier.js
├── paypro.js
└── credentials.js
├── Gruntfile.js
├── .editorconfig
├── Makefile
├── bower.json
├── .gitignore
├── .circleci
└── config.yml
├── LICENSE
├── package.json
└── README.header.md
/bitcore-wallet-client.min.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.coveralls.yml:
--------------------------------------------------------------------------------
1 | repo_token: JrJM1SMeS0mtVEmRlgijo9LiovuFjVlLX
2 |
3 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/test/test-config.js:
--------------------------------------------------------------------------------
1 | var config = {
2 | mongoDb: {
3 | uri: 'mongodb://localhost:27017/bwc_test',
4 | },
5 | };
6 |
7 | module.exports = config;
8 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/README.header.md:
--------------------------------------------------------------------------------
1 | # bitcore-wallet-client
2 |
3 | [](https://www.npmjs.org/package/bitcore-wallet-client)
4 | [](https://travis-ci.org/bitpay/bitcore-wallet-client)
5 | [](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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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/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":"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"}',
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 |
--------------------------------------------------------------------------------