Issues (615)

lib/blocktrail.js (1 issue)

1
var util = require('util');
2
var assert = require('assert');
3
var CryptoJS = require('crypto-js');
4
var bip39 = require('bip39');
5
6
var blocktrail = {
7
    COIN: 100000000,
8
    PRECISION: 8,
9
    DUST: 2730,
10
    BASE_FEE: 10000,
11
    LOCK_TIME_TIMESTAMP_THRESHOLD: 5000000
12
};
13
14
var convert = function(s, from, to) {
15
    return (new Buffer(s, from)).toString(to);
16
};
17
18
var aesDecryptMnemonic = function(mnemonic, passphrase) {
19
    var hex = bip39.mnemonicToEntropy(mnemonic);
20
    var base64 = convert(hex, 'hex', 'base64');
21
    var decrypted = CryptoJS.AES.decrypt(base64, passphrase).toString(CryptoJS.enc.Utf8);
22
23
    if (!decrypted.length) {
24
        throw new blocktrail.WalletDecryptError();
25
    }
26
27
    return decrypted;
28
};
29
30
var aesDecryptMnemonicToSeed = function(mnemonic, passphrase) {
31
    return aesDecryptMnemonic(mnemonic, passphrase).toString(CryptoJS.enc.Utf8);
32
};
33
34
var aesDecryptMnemonicToSeedHex = function(mnemonic, passphrase) {
35
    return convert(aesDecryptMnemonicToSeed(mnemonic, passphrase), 'base64', 'hex');
36
};
37
38
var aesDecryptMnemonicToSeedBuffer = function(mnemonic, passphrase) {
39
    return new Buffer(aesDecryptMnemonicToSeedHex(mnemonic, passphrase), 'hex');
40
};
41
42
var aesEncryptSeedToMnemonic = function(seed, passphrase) {
43
    var base64 = CryptoJS.AES.encrypt(seed, passphrase).toString(CryptoJS.format.OpenSSL);
44
    var hex = convert(base64, 'base64', 'hex');
45
    var mnemonic = bip39.entropyToMnemonic(hex);
46
47
    return mnemonic;
48
};
49
50
var aesEncryptSeedHexToMnemonic = function(seedHex, passphrase) {
51
    return aesEncryptSeedToMnemonic(convert(seedHex, 'hex', 'base64'), passphrase);
52
};
53
54
var aesEncryptSeedBufferToMnemonic = function(seedBuffer, passphrase) {
55
    return aesEncryptSeedToMnemonic(seedBuffer.toString('base64'), passphrase);
56
};
57
58
blocktrail.convert = convert;
59
blocktrail.aesDecryptMnemonicToSeed = aesDecryptMnemonicToSeed;
60
blocktrail.aesDecryptMnemonicToSeedBuffer = aesDecryptMnemonicToSeedBuffer;
61
blocktrail.aesDecryptMnemonicToSeedHex = aesDecryptMnemonicToSeedHex;
62
blocktrail.aesEncryptSeedToMnemonic = aesEncryptSeedToMnemonic;
63
blocktrail.aesEncryptSeedHexToMnemonic = aesEncryptSeedHexToMnemonic;
64
blocktrail.aesEncryptSeedBufferToMnemonic = aesEncryptSeedBufferToMnemonic;
65
66
blocktrail.V3Crypt = {
67
    KeyDerivation: require('./keyderivation'),
68
    Encryption: require('./encryption'),
69
    EncryptionMnemonic: require('./encryption_mnemonic')
70
};
71
72
/**
73
 * convert a BTC value to Satoshi
74
 *
75
 * @param btc   float       BTC value
76
 * @returns int             Satoshi value (int)
77
 */
78
blocktrail.toSatoshi = function(btc) {
79
    return parseInt((btc * blocktrail.COIN).toFixed(0), 10);
80
};
81
82
/**
83
 * convert a Satoshi value to BTC
84
 *
85
 * @param satoshi   int     Satoshi value
86
 * @returns {string}        BTC value (float)
87
 */
88
blocktrail.toBTC = function(satoshi) {
89
    return (satoshi / blocktrail.COIN).toFixed(blocktrail.PRECISION);
90
};
91
92
/**
93
 * patch the Q module to add spreadNodeify method to promises
94
 *  so that we can support multi parameter callbacks
95
 *
96
 * @param q
97
 */
98
blocktrail.patchQ = function(q) {
99
    /* jshint -W003 */
100
101
    if (q.spreadNodeify && q.spreadDone) {
102
        return;
103
    }
104
105
    q.spreadDone = spreadDone;
106
    function spreadDone(value, fulfilled, rejected) {
107
        return q(value).spreadDone(fulfilled, rejected);
108
    }
109
110
    q.makePromise.prototype.spreadDone = function(fulfilled, rejected) {
111
        return this.all().done(function(array) {
112
            return fulfilled.apply(void 0, array);
113
        }, rejected);
114
    };
115
116
    q.spreadNodeify = spreadNodeify;
117
    function spreadNodeify(object, nodeback) {
118
        return q(object).spreadNodeify(nodeback);
119
    }
120
121
    q.makePromise.prototype.spreadNodeify = function(nodeback) {
122
        if (nodeback) {
123
            this.then(function(value) {
124
                q.nextTick(function() {
125
                    nodeback.apply(void 0, [null].concat(value));
126
                });
127
            }, function(error) {
128
                q.nextTick(function() {
129
                    nodeback(error);
130
                });
131
            });
132
        } else {
133
            return this;
134
        }
135
    };
136
};
137
138
139
/**
140
 * Add extend() method to Error type
141
 *
142
 * @param subTypeName
143
 * @param errorCode [optional]
144
 * @returns {SubType}
145
 */
146
Error.extend = function(subTypeName, errorCode /*optional*/) {
0 ignored issues
show
Compatibility Best Practice introduced by
You are extending the built-in type Error. This may have unintended consequences on other objects using this built-in type. Consider subclassing instead.
Loading history...
147
    assert(subTypeName, 'subTypeName is required');
148
    //define new error type
149
    var SubType = function(message) {
150
151
        //handle constructor call without 'new'
152
        if (!(this instanceof SubType)) {
153
            return new SubType(message);
154
        }
155
156
        //populate error details
157
        this.name = subTypeName;
158
        this.code = errorCode;
159
        this.message = message ? (message.message || message || '') : '';
160
161
        //include stack trace in error object (only supported in v8 browsers)
162
        if (Error.captureStackTrace) {
163
            Error.captureStackTrace(this, this.constructor);
164
        }
165
    };
166
167
    //inherit the base prototype chain
168
    util.inherits(SubType, this);
169
170
    //override the toString method to error type name and inspected message (to expand objects)
171
    SubType.prototype.toString = function() {
172
        return this.name + ': ' + util.inspect(this.message);
173
    };
174
175
    //attach extend() to the SubType to make it extendable further
176
    SubType.extend = this.extend;
177
    return SubType;
178
};
179
180
if (typeof Uint8Array.prototype.reverse !== 'function') {
181
    Buffer.prototype.reverse = function reverse() {
182
        var c;
183
        for (var i = 0, j = this.length - 1; i <= j; ++i, --j) {
184
            c = this[i];
185
            this[i] = this[j];
186
            this[j] = c;
187
        }
188
189
        return this;
190
    };
191
}
192
193
//Wallet Errors
194
blocktrail.WalletInitError = Error.extend("WalletInitError", 400);
195
blocktrail.WalletCreateError = Error.extend("WalletCreateError", 400);
196
blocktrail.WalletUpgradeError = Error.extend("WalletUpgradeError", 400);
197
blocktrail.WalletChecksumError = Error.extend("WalletChecksumError", 400);
198
blocktrail.WalletDeleteError = Error.extend("WalletDeleteError", 400);
199
blocktrail.WalletDecryptError = Error.extend("WalletDecryptError", 400);
200
blocktrail.WalletAddressError = Error.extend("WalletAddressError", 500);
201
blocktrail.WalletSendError = Error.extend("WalletSendError", 400);
202
blocktrail.WalletLockedError = Error.extend("WalletLockedError", 500);
203
blocktrail.WalletFeeError = Error.extend("WalletFeeError", 500);
204
blocktrail.WalletInvalid2FAError = Error.extend("WalletInvalid2FAError", 401);
205
blocktrail.WalletMissing2FAError = Error.extend("WalletMissing2FAError", 401);
206
blocktrail.TransactionSignError = Error.extend("TransactionSignError", 500);
207
blocktrail.TransactionInputError = Error.extend("TransactionInputError", 400);
208
blocktrail.TransactionOutputError = Error.extend("TransactionOutputError", 400);
209
210
blocktrail.KeyPathError = Error.extend("KeyPathError", 400);
211
212
blocktrail.InvalidAddressError = Error.extend("InvalidAddressError", 400);
213
214
//Other Errors
215
blocktrail.Error = Error.extend("Error", 500);
216
217
blocktrail.FEE_STRATEGY_FORCE_FEE = 'force_fee';
218
blocktrail.FEE_STRATEGY_BASE_FEE = 'base_fee';
219
blocktrail.FEE_STRATEGY_HIGH_PRIORITY = 'high_priority';
220
blocktrail.FEE_STRATEGY_OPTIMAL = 'optimal';
221
blocktrail.FEE_STRATEGY_LOW_PRIORITY = 'low_priority';
222
blocktrail.FEE_STRATEGY_MIN_RELAY_FEE = 'min_relay_fee';
223
224
// apply patch to Q to add spreadNodeify for all dependants of this module
225
blocktrail.patchQ(require('q'));
226
227
module.exports = blocktrail;
228