validation: use stricter validation for ints.

This commit is contained in:
Christopher Jeffrey 2017-08-06 14:42:10 -07:00
parent d8aea55f97
commit 4ce070fad4
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
35 changed files with 208 additions and 180 deletions

View File

@ -1,5 +1,6 @@
'use strict';
const assert = require('assert');
const net = require('net');
const EventEmitter = require('events').EventEmitter;
const IOServer = require('socket.io');
@ -26,27 +27,32 @@ function WSProxy(options) {
this.options = options;
this.target = options.target || TARGET;
this.pow = options.pow === true;
this.ports = options.ports || [];
this.ports = new Set();
this.io = new IOServer();
this.sockets = new WeakMap();
this._init();
if (options.ports) {
for (const port of options.ports)
this.ports.add(port);
}
this.init();
}
util.inherits(WSProxy, EventEmitter);
WSProxy.prototype._init = function _init() {
WSProxy.prototype.init = function init() {
this.io.on('error', (err) => {
this.emit('error', err);
});
this.io.on('connection', (ws) => {
this._handleSocket(ws);
this.handleSocket(ws);
});
};
WSProxy.prototype._handleSocket = function _handleSocket(ws) {
let state = new SocketState(this, ws);
WSProxy.prototype.handleSocket = function handleSocket(ws) {
const state = new SocketState(this, ws);
// Use a weak map to avoid
// mutating the websocket object.
@ -59,20 +65,20 @@ WSProxy.prototype._handleSocket = function _handleSocket(ws) {
});
ws.on('tcp connect', (port, host, nonce) => {
this._handleConnect(ws, port, host, nonce);
this.handleConnect(ws, port, host, nonce);
});
};
WSProxy.prototype._handleConnect = function _handleConnect(ws, port, host, nonce) {
let state = this.sockets.get(ws);
let socket, pow, raw;
WSProxy.prototype.handleConnect = function handleConnect(ws, port, host, nonce) {
const state = this.sockets.get(ws);
assert(state);
if (state.socket) {
this.log('Client is trying to reconnect (%s).', state.host);
return;
}
if (!util.isNumber(port)
if (!util.isU16(port)
|| typeof host !== 'string'
|| host.length === 0) {
this.log('Client gave bad arguments (%s).', state.host);
@ -82,19 +88,20 @@ WSProxy.prototype._handleConnect = function _handleConnect(ws, port, host, nonce
}
if (this.pow) {
if (!util.isNumber(nonce)) {
if (!util.isU32(nonce)) {
this.log('Client did not solve proof of work (%s).', state.host);
ws.emit('tcp close');
ws.disconnect();
return;
}
pow = new BufferWriter();
pow.writeU32(nonce);
pow.writeBytes(state.snonce);
pow.writeU32(port);
pow.writeString(host, 'ascii');
pow = pow.render();
const bw = new BufferWriter();
bw.writeU32(nonce);
bw.writeBytes(state.snonce);
bw.writeU32(port);
bw.writeString(host, 'ascii');
const pow = bw.render();
if (digest.hash256(pow).compare(this.target) > 0) {
this.log('Client did not solve proof of work (%s).', state.host);
@ -104,9 +111,10 @@ WSProxy.prototype._handleConnect = function _handleConnect(ws, port, host, nonce
}
}
let raw, addr;
try {
raw = IP.toBuffer(host);
host = IP.toString(raw);
addr = IP.toString(raw);
} catch (e) {
this.log('Client gave a bad host: %s (%s).', host, state.host);
ws.emit('tcp error', {
@ -120,7 +128,7 @@ WSProxy.prototype._handleConnect = function _handleConnect(ws, port, host, nonce
if (!IP.isRoutable(raw) || IP.isOnion(raw)) {
this.log(
'Client is trying to connect to a bad ip: %s (%s).',
host, state.host);
addr, state.host);
ws.emit('tcp error', {
message: 'ENETUNREACH',
code: 'ENETUNREACH'
@ -129,7 +137,7 @@ WSProxy.prototype._handleConnect = function _handleConnect(ws, port, host, nonce
return;
}
if (this.ports.indexOf(port) === -1) {
if (!this.ports.has(port)) {
this.log('Client is connecting to non-whitelist port (%s).', state.host);
ws.emit('tcp error', {
message: 'ENETUNREACH',
@ -139,8 +147,9 @@ WSProxy.prototype._handleConnect = function _handleConnect(ws, port, host, nonce
return;
}
let socket;
try {
socket = state.connect(port, host);
socket = state.connect(port, addr);
this.log('Connecting to %s (%s).', state.remoteHost, state.host);
} catch (e) {
this.log(e.message);

View File

@ -64,12 +64,12 @@ PaymentDetails.prototype.fromOptions = function fromOptions(options) {
}
if (options.time != null) {
assert(util.isNumber(options.time));
assert(util.isInt(options.time));
this.time = options.time;
}
if (options.expires != null) {
assert(util.isNumber(options.expires));
assert(util.isInt(options.expires));
this.expires = options.expires;
}

View File

@ -50,7 +50,7 @@ function PaymentRequest(options) {
PaymentRequest.prototype.fromOptions = function fromOptions(options) {
if (options.version != null) {
assert(util.isNumber(options.version));
assert(util.isInt(options.version));
this.version = options.version;
}

View File

@ -2455,12 +2455,12 @@ ChainOptions.prototype.fromOptions = function fromOptions(options) {
}
if (options.maxFiles != null) {
assert(util.isNumber(options.maxFiles));
assert(util.isU32(options.maxFiles));
this.maxFiles = options.maxFiles;
}
if (options.cacheSize != null) {
assert(util.isNumber(options.cacheSize));
assert(util.isU64(options.cacheSize));
this.cacheSize = options.cacheSize;
}
@ -2500,17 +2500,17 @@ ChainOptions.prototype.fromOptions = function fromOptions(options) {
}
if (options.coinCache != null) {
assert(util.isNumber(options.coinCache));
assert(util.isU64(options.coinCache));
this.coinCache = options.coinCache;
}
if (options.entryCache != null) {
assert(util.isNumber(options.entryCache));
assert(util.isU32(options.entryCache));
this.entryCache = options.entryCache;
}
if (options.maxOrphans != null) {
assert(util.isNumber(options.maxOrphans));
assert(util.isU32(options.maxOrphans));
this.maxOrphans = options.maxOrphans;
}

View File

@ -56,7 +56,7 @@ function ChainEntry(chain, options, prev) {
this.time = 0;
this.bits = 0;
this.nonce = 0;
this.height = -1;
this.height = 0;
this.chainwork = ZERO;
if (options)
@ -88,12 +88,13 @@ ChainEntry.MEDIAN_TIMESPAN = 11;
ChainEntry.prototype.fromOptions = function fromOptions(options, prev) {
assert(options, 'Block data is required.');
assert(typeof options.hash === 'string');
assert(util.isNumber(options.version));
assert(util.isU32(options.version));
assert(typeof options.prevBlock === 'string');
assert(typeof options.merkleRoot === 'string');
assert(util.isNumber(options.time));
assert(util.isNumber(options.bits));
assert(util.isNumber(options.nonce));
assert(util.isU32(options.time));
assert(util.isU32(options.bits));
assert(util.isU32(options.nonce));
assert(util.isU32(options.height));
assert(!options.chainwork || BN.isBN(options.chainwork));
this.hash = options.hash;
@ -104,7 +105,7 @@ ChainEntry.prototype.fromOptions = function fromOptions(options, prev) {
this.bits = options.bits;
this.nonce = options.nonce;
this.height = options.height;
this.chainwork = options.chainwork;
this.chainwork = options.chainwork || ZERO;
if (!this.chainwork)
this.chainwork = this.getChainwork(prev);

View File

@ -371,10 +371,8 @@ Amount.encode = function encode(value, exp, num) {
*/
Amount.decode = function decode(str, exp, num) {
if (num && typeof str === 'number') {
assert(util.isNumber(str), 'Non-BTC value for conversion.');
if (num && typeof str === 'number')
str = str.toString(10);
}
return util.fromFixed(str, exp);
};

View File

@ -77,7 +77,7 @@ Mnemonic.prototype.fromOptions = function fromOptions(options) {
options = { phrase: options };
if (options.bits != null) {
assert(util.isNumber(options.bits));
assert(util.isU16(options.bits));
assert(options.bits >= common.MIN_ENTROPY);
assert(options.bits <= common.MAX_ENTROPY);
assert(options.bits % 32 === 0);
@ -377,7 +377,7 @@ Mnemonic.prototype.toJSON = function toJSON() {
*/
Mnemonic.prototype.fromJSON = function fromJSON(json) {
assert(util.isNumber(json.bits));
assert(util.isU16(json.bits));
assert(typeof json.language === 'string');
assert(typeof json.entropy === 'string');
assert(typeof json.phrase === 'string');

View File

@ -70,10 +70,9 @@ function HDPrivateKey(options) {
HDPrivateKey.prototype.fromOptions = function fromOptions(options) {
assert(options, 'No options for HD private key.');
assert(util.isNumber(options.depth));
assert(options.depth >= 0 && options.depth <= 0xff);
assert(util.isU8(options.depth));
assert(Buffer.isBuffer(options.parentFingerPrint));
assert(util.isNumber(options.childIndex));
assert(util.isU32(options.childIndex));
assert(Buffer.isBuffer(options.chainCode));
assert(Buffer.isBuffer(options.privateKey));
@ -258,7 +257,7 @@ HDPrivateKey.prototype.getID = function getID(index) {
*/
HDPrivateKey.prototype.deriveBIP44 = function deriveBIP44(account, bip48) {
assert(util.isNumber(account), 'Account index must be a number.');
assert(util.isU32(account), 'Account index must be a number.');
assert(this.isMaster(), 'Cannot derive account index.');
return this
.derive(bip48 ? 48 : 44, true)

View File

@ -64,10 +64,9 @@ function HDPublicKey(options) {
HDPublicKey.prototype.fromOptions = function fromOptions(options) {
assert(options, 'No options for HDPublicKey');
assert(util.isNumber(options.depth));
assert(options.depth >= 0 && options.depth <= 0xff);
assert(util.isU8(options.depth));
assert(Buffer.isBuffer(options.parentFingerPrint));
assert(util.isNumber(options.childIndex));
assert(util.isU32(options.childIndex));
assert(Buffer.isBuffer(options.chainCode));
assert(Buffer.isBuffer(options.publicKey));

View File

@ -427,7 +427,7 @@ MinerOptions.prototype.fromOptions = function fromOptions(options) {
}
if (options.version != null) {
assert(util.isNumber(options.version));
assert(util.isInt(options.version));
this.version = options.version;
}
@ -461,41 +461,41 @@ MinerOptions.prototype.fromOptions = function fromOptions(options) {
}
if (options.minWeight != null) {
assert(util.isNumber(options.minWeight));
assert(util.isU32(options.minWeight));
this.minWeight = options.minWeight;
}
if (options.maxWeight != null) {
assert(util.isNumber(options.maxWeight));
assert(util.isU32(options.maxWeight));
assert(options.maxWeight <= consensus.MAX_BLOCK_WEIGHT,
'Max weight must be below MAX_BLOCK_WEIGHT');
this.maxWeight = options.maxWeight;
}
if (options.maxSigops != null) {
assert(util.isNumber(options.maxSigops));
assert(util.isU32(options.maxSigops));
assert(options.maxSigops <= consensus.MAX_BLOCK_SIGOPS_COST,
'Max sigops must be below MAX_BLOCK_SIGOPS_COST');
this.maxSigops = options.maxSigops;
}
if (options.priorityWeight != null) {
assert(util.isNumber(options.priorityWeight));
assert(util.isU32(options.priorityWeight));
this.priorityWeight = options.priorityWeight;
}
if (options.priorityThreshold != null) {
assert(util.isNumber(options.priorityThreshold));
assert(util.isU32(options.priorityThreshold));
this.priorityThreshold = options.priorityThreshold;
}
if (options.reservedWeight != null) {
assert(util.isNumber(options.reservedWeight));
assert(util.isU32(options.reservedWeight));
this.reservedWeight = options.reservedWeight;
}
if (options.reservedSigops != null) {
assert(util.isNumber(options.reservedSigops));
assert(util.isU32(options.reservedSigops));
this.reservedSigops = options.reservedSigops;
}

View File

@ -1374,13 +1374,13 @@ HostEntry.prototype.fromJSON = function fromJSON(json, network) {
assert(typeof json.services === 'string');
assert(json.services.length > 0);
assert(json.services.length <= 32);
this.addr.services = parseInt(json.services, 2);
assert(util.isU32(this.addr.services));
const services = parseInt(json.services, 2);
assert(util.isU32(services));
this.addr.services = services;
}
if (json.time != null) {
assert(util.isNumber(json.time));
assert(json.time >= 0);
assert(util.isU64(json.time));
this.addr.time = json.time;
}
@ -1390,20 +1390,17 @@ HostEntry.prototype.fromJSON = function fromJSON(json, network) {
}
if (json.attempts != null) {
assert(util.isNumber(json.attempts));
assert(json.attempts >= 0);
assert(util.isU64(json.attempts));
this.attempts = json.attempts;
}
if (json.lastSuccess != null) {
assert(util.isNumber(json.lastSuccess));
assert(json.lastSuccess >= 0);
assert(util.isU64(json.lastSuccess));
this.lastSuccess = json.lastSuccess;
}
if (json.lastAttempt != null) {
assert(util.isNumber(json.lastAttempt));
assert(json.lastAttempt >= 0);
assert(util.isU64(json.lastAttempt));
this.lastAttempt = json.lastAttempt;
}

View File

@ -202,9 +202,14 @@ Config.prototype.get = function get(key, fallback) {
if (typeof key === 'number') {
assert(key >= 0, 'Index must be positive.');
if (key >= this.argv.length)
return fallback;
return this.argv[key];
if (this.argv[key] != null)
return this.argv[key];
return fallback;
}
assert(typeof key === 'string', 'Key must be a string.');
@ -232,6 +237,21 @@ Config.prototype.get = function get(key, fallback) {
return fallback;
};
/**
* Get a value's type.
* @param {String} key
* @returns {String}
*/
Config.prototype.typeOf = function typeOf(key) {
const value = this.get(key);
if (value === null)
return 'null';
return typeof value;
};
/**
* Get a config option (as a string).
* @param {String} key
@ -275,10 +295,7 @@ Config.prototype.int = function int(key, fallback) {
throw new Error(`${fmt(key)} must be an int.`);
if (!Number.isSafeInteger(value))
throw new Error(`${fmt(key)} must be an int (53 bit max).`);
if (value % 1 !== 0)
throw new Error(`${fmt(key)} must be an int (float).`);
throw new Error(`${fmt(key)} must be an int.`);
return value;
}
@ -289,7 +306,7 @@ Config.prototype.int = function int(key, fallback) {
value = parseInt(value, 10);
if (!Number.isSafeInteger(value))
throw new Error(`${fmt(key)} must be an int (53 bit max).`);
throw new Error(`${fmt(key)} must be an int.`);
return value;
};
@ -441,6 +458,15 @@ Config.prototype.bool = function bool(key, fallback) {
if (value === null)
return fallback;
// Bitcoin Core compat.
if (typeof value === 'number') {
if (value === 1)
return true;
if (value === 0)
return false;
}
if (typeof value !== 'string') {
if (typeof value !== 'boolean')
throw new Error(`${fmt(key)} must be a boolean.`);
@ -484,7 +510,7 @@ Config.prototype.buf = function buf(key, fallback, enc) {
const data = Buffer.from(value, enc);
if (data.length !== Buffer.byteLength(value, enc))
throw new Error(`${fmt(key)} must be a hex string.`);
throw new Error(`${fmt(key)} must be a ${enc} string.`);
return data;
};
@ -540,7 +566,7 @@ Config.prototype.obj = function obj(key, fallback) {
if (value === null)
return fallback;
if (!value || typeof value !== 'object')
if (typeof value !== 'object')
throw new Error(`${fmt(key)} must be an object.`);
return value;

View File

@ -57,12 +57,12 @@ function AbstractBlock() {
AbstractBlock.prototype.parseOptions = function parseOptions(options) {
assert(options, 'Block data is required.');
assert(util.isNumber(options.version));
assert(util.isU32(options.version));
assert(typeof options.prevBlock === 'string');
assert(typeof options.merkleRoot === 'string');
assert(util.isNumber(options.time));
assert(util.isNumber(options.bits));
assert(util.isNumber(options.nonce));
assert(util.isU32(options.time));
assert(util.isU32(options.bits));
assert(util.isU32(options.nonce));
this.version = options.version;
this.prevBlock = options.prevBlock;
@ -85,12 +85,12 @@ AbstractBlock.prototype.parseOptions = function parseOptions(options) {
AbstractBlock.prototype.parseJSON = function parseJSON(json) {
assert(json, 'Block data is required.');
assert(util.isNumber(json.version));
assert(util.isU32(json.version));
assert(typeof json.prevBlock === 'string');
assert(typeof json.merkleRoot === 'string');
assert(util.isNumber(json.time));
assert(util.isNumber(json.bits));
assert(util.isNumber(json.nonce));
assert(util.isU32(json.time));
assert(util.isU32(json.bits));
assert(util.isU32(json.nonce));
this.version = json.version;
this.prevBlock = util.revHex(json.prevBlock);

View File

@ -579,8 +579,8 @@ Address.prototype.fromHash = function fromHash(hash, type, version, network) {
network = Network.get(network);
assert(Buffer.isBuffer(hash));
assert(util.isNumber(type));
assert(util.isNumber(version));
assert(util.isU8(type));
assert(util.isI8(version));
assert(type >= Address.types.PUBKEYHASH && type <= Address.types.WITNESS,
'Not a valid address type.');

View File

@ -1519,37 +1519,36 @@ CoinSelector.prototype.fromOptions = function fromOptions(options) {
}
if (options.height != null) {
assert(util.isNumber(options.height));
assert(util.isInt(options.height));
assert(options.height >= -1);
this.height = options.height;
}
if (options.confirmations != null) {
assert(util.isNumber(options.confirmations));
assert(util.isInt(options.confirmations));
assert(options.confirmations >= -1);
this.depth = options.confirmations;
}
if (options.depth != null) {
assert(util.isNumber(options.depth));
assert(util.isInt(options.depth));
assert(options.depth >= -1);
this.depth = options.depth;
}
if (options.hardFee != null) {
assert(util.isNumber(options.hardFee));
assert(util.isInt(options.hardFee));
assert(options.hardFee >= -1);
this.hardFee = options.hardFee;
}
if (options.rate != null) {
assert(util.isNumber(options.rate));
assert(options.rate >= 0);
assert(util.isU64(options.rate));
this.rate = options.rate;
}
if (options.maxFee != null) {
assert(util.isNumber(options.maxFee));
assert(util.isInt(options.maxFee));
assert(options.maxFee >= -1);
this.maxFee = options.maxFee;
}

View File

@ -439,10 +439,9 @@ NetAddress.prototype.toJSON = function toJSON() {
*/
NetAddress.prototype.fromJSON = function fromJSON(json) {
assert(util.isNumber(json.port));
assert(json.port >= 0 && json.port <= 0xffff);
assert(util.isNumber(json.services));
assert(util.isNumber(json.time));
assert(util.isU16(json.port));
assert(util.isU32(json.services));
assert(util.isU32(json.time));
this.raw = IP.toBuffer(json.host);
this.host = json.host;
this.port = json.port;

View File

@ -28,7 +28,7 @@ function TXMeta(options) {
this.height = -1;
this.block = null;
this.time = 0;
this.index = 0;
this.index = -1;
if (options)
this.fromOptions(options);
@ -47,12 +47,12 @@ TXMeta.prototype.fromOptions = function fromOptions(options) {
}
if (options.mtime != null) {
assert(util.isNumber(options.mtime));
assert(util.isU32(options.mtime));
this.mtime = options.mtime;
}
if (options.height != null) {
assert(util.isNumber(options.height));
assert(util.isInt(options.height));
this.height = options.height;
}
@ -62,12 +62,12 @@ TXMeta.prototype.fromOptions = function fromOptions(options) {
}
if (options.time != null) {
assert(util.isNumber(options.time));
assert(util.isU32(options.time));
this.time = options.time;
}
if (options.index != null) {
assert(util.isNumber(options.index));
assert(util.isInt(options.index));
this.index = options.index;
}
@ -169,11 +169,11 @@ TXMeta.prototype.getJSON = function getJSON(network, view) {
TXMeta.prototype.fromJSON = function fromJSON(json) {
this.tx.fromJSON(json);
assert(util.isNumber(json.mtime));
assert(util.isNumber(json.height));
assert(util.isU32(json.mtime));
assert(util.isInt(json.height));
assert(!json.block || typeof json.block === 'string');
assert(util.isNumber(json.time));
assert(util.isNumber(json.index));
assert(util.isU32(json.time));
assert(util.isInt(json.index));
this.mtime = json.mtime;
this.height = json.height;

View File

@ -758,8 +758,10 @@ exports.num = function num(value, minimal, size) {
*/
exports.array = function array(value) {
if (util.isNumber(value))
if (typeof value === 'number') {
assert(util.isInt(value));
value = new BN(value);
}
assert(BN.isBN(value));

View File

@ -357,7 +357,7 @@ Opcode.fromNumber = function fromNumber(num) {
*/
Opcode.fromSmall = function fromSmall(num) {
assert(util.isNumber(num) && num >= 0 && num <= 16);
assert(util.isU8(num) && num >= 0 && num <= 16);
return Opcode.fromOp(num === 0 ? 0 : num + 0x50);
};

View File

@ -29,9 +29,9 @@ function Program(version, data) {
if (!(this instanceof Program))
return new Program(version, data);
assert(util.isNumber(version));
assert(Buffer.isBuffer(data));
assert(util.isU8(version));
assert(version >= 0 && version <= 16);
assert(Buffer.isBuffer(data));
assert(data.length >= 2 && data.length <= 40);
this.version = version;

View File

@ -1470,7 +1470,7 @@ Script.fromPubkeyhash = function fromPubkeyhash(hash) {
*/
Script.prototype.fromMultisig = function fromMultisig(m, n, keys) {
assert(util.isNumber(m) && util.isNumber(n));
assert(util.isU8(m) && util.isU8(n));
assert(Array.isArray(keys));
assert(keys.length === n, '`n` keys are required for multisig.');
assert(m >= 1 && m <= n);
@ -1570,7 +1570,7 @@ Script.fromNulldata = function fromNulldata(flags) {
*/
Script.prototype.fromProgram = function fromProgram(version, data) {
assert(util.isNumber(version) && version >= 0 && version <= 16);
assert(util.isU8(version) && version >= 0 && version <= 16);
assert(Buffer.isBuffer(data) && data.length >= 2 && data.length <= 40);
const op = Opcode.fromSmall(version);

View File

@ -27,8 +27,7 @@ function SigCache(size) {
if (size == null)
size = 10000;
assert(util.isNumber(size));
assert(size >= 0);
assert(util.isU32(size));
this.size = size;
this.keys = [];
@ -41,8 +40,7 @@ function SigCache(size) {
*/
SigCache.prototype.resize = function resize(size) {
assert(util.isNumber(size));
assert(size >= 0);
assert(util.isU32(size));
this.size = size;
this.keys.length = 0;

View File

@ -152,7 +152,7 @@ AsyncEmitter.prototype.removeListener = function removeListener(type, handler) {
AsyncEmitter.prototype.setMaxListeners = function setMaxListeners(max) {
assert(typeof max === 'number', '`max` must be a number.');
assert(max >= 0, '`max` must be non-negative.');
assert(max % 1 === 0, '`max` must be an integer.');
assert(Number.isSafeInteger(max), '`max` must be an integer.');
};
/**

View File

@ -119,7 +119,7 @@ Bloom.flagsByVal = {
Bloom.prototype.fromOptions = function fromOptions(size, n, tweak, update) {
assert(typeof size === 'number', '`size` must be a number.');
assert(size > 0, '`size` must be greater than zero.');
assert(size % 1 === 0, '`size` must be an integer.');
assert(Number.isSafeInteger(size), '`size` must be an integer.');
size -= size % 8;
@ -139,9 +139,9 @@ Bloom.prototype.fromOptions = function fromOptions(size, n, tweak, update) {
assert(size > 0, '`size` must be greater than zero.');
assert(n > 0, '`n` must be greater than zero.');
assert(n % 1 === 0, '`n` must be an integer.');
assert(Number.isSafeInteger(n), '`n` must be an integer.');
assert(typeof tweak === 'number', '`tweak` must be a number.');
assert(tweak % 1 === 0, '`tweak` must be an integer.');
assert(Number.isSafeInteger(tweak), '`tweak` must be an integer.');
assert(Bloom.flagsByVal[update], 'Unknown update flag.');
this.filter = filter;
@ -258,7 +258,7 @@ Bloom.prototype.added = function added(val, enc) {
Bloom.fromRate = function fromRate(items, rate, update) {
assert(typeof items === 'number', '`items` must be a number.');
assert(items > 0, '`items` must be greater than zero.');
assert(items % 1 === 0, '`items` must be an integer.');
assert(Number.isSafeInteger(items), '`items` must be an integer.');
assert(typeof rate === 'number', '`rate` must be a number.');
assert(rate >= 0 && rate <= 1, '`rate` must be between 0.0 and 1.0.');

View File

@ -12,6 +12,7 @@
*/
const BN = require('bn.js');
const util = require('./util');
const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER;
const encoding = exports;
@ -1037,7 +1038,7 @@ encoding.EncodingError = function EncodingError(offset, reason) {
Error.captureStackTrace(this, EncodingError);
};
inherits(encoding.EncodingError, Error);
util.inherits(encoding.EncodingError, Error);
/*
* Helpers
@ -1048,15 +1049,6 @@ function Varint(size, value) {
this.value = value;
}
function inherits(child, parent) {
child.super_ = parent;
Object.setPrototypeOf(child.prototype, parent.prototype);
Object.defineProperty(child.prototype, 'constructor', {
value: child,
enumerable: false
});
}
function enforce(value, offset, reason) {
if (!value)
throw new encoding.EncodingError(offset, reason);

View File

@ -50,7 +50,7 @@ function RollingFilter(items, rate) {
RollingFilter.prototype.fromRate = function fromRate(items, rate) {
assert(typeof items === 'number', '`items` must be a number.');
assert(items > 0, '`items` must be greater than zero.');
assert(items % 1 === 0, '`items` must be an integer.');
assert(Number.isSafeInteger(items), '`items` must be an integer.');
assert(typeof rate === 'number', '`rate` must be a number.');
assert(rate >= 0 && rate <= 1, '`rate` must be between 0.0 and 1.0.');

View File

@ -38,7 +38,10 @@ const inspectOptions = {
*/
util.isNumber = function isNumber(value) {
return Number.isSafeInteger(value);
return typeof value === 'number'
&& isFinite(value)
&& value >= -Number.MAX_SAFE_INTEGER
&& value <= Number.MAX_SAFE_INTEGER;
};
/**
@ -48,11 +51,11 @@ util.isNumber = function isNumber(value) {
*/
util.isInt = function isInt(value) {
return util.isNumber(value) && value % 1 === 0;
return Number.isSafeInteger(value);
};
/**
* Test whether an object is an int.
* Test whether an object is a uint.
* @param {Number?} value
* @returns {Boolean}
*/
@ -844,7 +847,7 @@ util.memoryUsage = function memoryUsage() {
util.toFixed = function toFixed(num, exp) {
assert(typeof num === 'number');
assert(Number.isSafeInteger(num) && num % 1 === 0, 'Invalid integer value.');
assert(Number.isSafeInteger(num), 'Invalid integer value.');
let sign = '';

View File

@ -97,6 +97,21 @@ Validator.prototype.get = function get(key, fallback) {
return fallback;
};
/**
* Get a value's type.
* @param {String} key
* @returns {String}
*/
Validator.prototype.typeOf = function typeOf(key) {
const value = this.get(key);
if (value == null)
return 'null';
return typeof value;
};
/**
* Get a value (as a string).
* @param {String} key
@ -140,10 +155,7 @@ Validator.prototype.int = function int(key, fallback) {
throw new ValidationError(key, 'int');
if (!Number.isSafeInteger(value))
throw new ValidationError(key, 'int (53 bit max)');
if (value % 1 !== 0)
throw new ValidationError(key, 'int (float)');
throw new ValidationError(key, 'int');
return value;
}
@ -154,7 +166,7 @@ Validator.prototype.int = function int(key, fallback) {
value = parseInt(value, 10);
if (!Number.isSafeInteger(value))
throw new ValidationError(key, 'int (53 bit max)');
throw new ValidationError(key, 'int');
return value;
};
@ -492,15 +504,9 @@ Validator.prototype.hash = function hash(key, fallback) {
*/
Validator.prototype.numhash = function numhash(key, fallback) {
const value = this.get(key);
if (value === null)
return fallback;
if (typeof value === 'string')
return this.hash(key);
return this.uint(key);
if (this.typeOf(key) === 'string')
return this.hash(key, fallback);
return this.uint(key, fallback);
};
/**
@ -519,14 +525,14 @@ Validator.prototype.bool = function bool(key, fallback) {
if (value === null)
return fallback;
// Bitcoin Core mixes semantics of truthiness
// amoung rpc methods most "verbose" parameters
// are bools, but getrawtransaction is 1/0.
if (value === 1)
return true;
// Bitcoin Core compat.
if (typeof value === 'number') {
if (value === 1)
return true;
if (value === 0)
return false;
if (value === 0)
return false;
}
if (typeof value !== 'string') {
if (typeof value !== 'boolean')
@ -628,7 +634,7 @@ Validator.prototype.obj = function obj(key, fallback) {
if (value === null)
return fallback;
if (!value || typeof value !== 'object')
if (typeof value !== 'object')
throw new ValidationError(key, 'object');
return value;

View File

@ -105,10 +105,10 @@ Account.typesByVal = {
Account.prototype.fromOptions = function fromOptions(options) {
assert(options, 'Options are required.');
assert(util.isNumber(options.wid));
assert(util.isU32(options.wid));
assert(common.isName(options.id), 'Bad Wallet ID.');
assert(HD.isHD(options.accountKey), 'Account key is required.');
assert(util.isNumber(options.accountIndex), 'Account index is required.');
assert(util.isU32(options.accountIndex), 'Account index is required.');
this.wid = options.wid;
this.id = options.id;
@ -145,37 +145,37 @@ Account.prototype.fromOptions = function fromOptions(options) {
}
if (options.m != null) {
assert(util.isNumber(options.m));
assert(util.isU8(options.m));
this.m = options.m;
}
if (options.n != null) {
assert(util.isNumber(options.n));
assert(util.isU8(options.n));
this.n = options.n;
}
if (options.accountIndex != null) {
assert(util.isNumber(options.accountIndex));
assert(util.isU32(options.accountIndex));
this.accountIndex = options.accountIndex;
}
if (options.receiveDepth != null) {
assert(util.isNumber(options.receiveDepth));
assert(util.isU32(options.receiveDepth));
this.receiveDepth = options.receiveDepth;
}
if (options.changeDepth != null) {
assert(util.isNumber(options.changeDepth));
assert(util.isU32(options.changeDepth));
this.changeDepth = options.changeDepth;
}
if (options.nestedDepth != null) {
assert(util.isNumber(options.nestedDepth));
assert(util.isU32(options.nestedDepth));
this.nestedDepth = options.nestedDepth;
}
if (options.lookahead != null) {
assert(util.isNumber(options.lookahead));
assert(util.isU32(options.lookahead));
assert(options.lookahead >= 0);
assert(options.lookahead <= Account.MAX_LOOKAHEAD);
this.lookahead = options.lookahead;

View File

@ -129,22 +129,22 @@ MasterKey.prototype.fromOptions = function fromOptions(options) {
}
if (options.rounds != null) {
assert(util.isNumber(options.rounds));
assert(util.isU32(options.rounds));
this.N = options.rounds;
}
if (options.N != null) {
assert(util.isNumber(options.N));
assert(util.isU32(options.N));
this.N = options.N;
}
if (options.r != null) {
assert(util.isNumber(options.r));
assert(util.isU32(options.r));
this.r = options.r;
}
if (options.p != null) {
assert(util.isNumber(options.p));
assert(util.isU32(options.p));
this.p = options.p;
}

View File

@ -124,7 +124,7 @@ Wallet.prototype.fromOptions = function fromOptions(options) {
this.master.fromKey(key, mnemonic);
if (options.wid != null) {
assert(util.isNumber(options.wid));
assert(util.isU32(options.wid));
this.wid = options.wid;
}
@ -144,7 +144,7 @@ Wallet.prototype.fromOptions = function fromOptions(options) {
}
if (options.accountDepth != null) {
assert(util.isNumber(options.accountDepth));
assert(util.isU32(options.accountDepth));
this.accountDepth = options.accountDepth;
}
@ -155,7 +155,7 @@ Wallet.prototype.fromOptions = function fromOptions(options) {
}
if (options.tokenDepth != null) {
assert(util.isNumber(options.tokenDepth));
assert(util.isU32(options.tokenDepth));
this.tokenDepth = options.tokenDepth;
}

View File

@ -2220,12 +2220,12 @@ WalletOptions.prototype.fromOptions = function fromOptions(options) {
}
if (options.maxFiles != null) {
assert(util.isNumber(options.maxFiles));
assert(util.isU32(options.maxFiles));
this.maxFiles = options.maxFiles;
}
if (options.cacheSize != null) {
assert(util.isNumber(options.cacheSize));
assert(util.isU64(options.cacheSize));
this.cacheSize = options.cacheSize;
}

View File

@ -68,14 +68,14 @@ WorkerPool.prototype.set = function set(options) {
}
if (options.size != null) {
assert(util.isNumber(options.size));
assert(util.isU32(options.size));
assert(options.size > 0);
this.size = options.size;
}
if (options.timeout != null) {
assert(util.isNumber(options.timeout));
assert(options.timeout > 0);
assert(util.isInt(options.timeout));
assert(options.timeout >= -1);
this.timeout = options.timeout;
}

View File

@ -52,7 +52,7 @@ function Coins(options) {
Coins.prototype.fromOptions = function fromOptions(options) {
if (options.version != null) {
assert(util.isNumber(options.version));
assert(util.isU32(options.version));
this.version = options.version;
}
@ -62,7 +62,7 @@ Coins.prototype.fromOptions = function fromOptions(options) {
}
if (options.height != null) {
assert(util.isNumber(options.height));
assert(util.isInt(options.height));
this.height = options.height;
}

View File

@ -64,7 +64,7 @@ Coins.prototype.fromOptions = function fromOptions(options) {
}
if (options.height != null) {
assert(util.isNumber(options.height));
assert(util.isInt(options.height));
this.height = options.height;
}