mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-15 18:15:49 +00:00
Merge pull request #355 from ripple/validate-uint-hex-input
Validate UInt* hex input
This commit is contained in:
@@ -54,7 +54,7 @@ SerializedObject.from_json = function(obj_) {
|
||||
// Create a copy of the object so we don't modify it
|
||||
const obj = extend(true, {}, obj_);
|
||||
|
||||
let so = new SerializedObject();
|
||||
const so = new SerializedObject();
|
||||
let typedef;
|
||||
|
||||
if (typeof obj.TransactionType === 'number') {
|
||||
@@ -216,7 +216,7 @@ SerializedObject.prototype.to_json = function() {
|
||||
|
||||
this.resetPointer();
|
||||
|
||||
let output = { };
|
||||
const output = { };
|
||||
|
||||
while (this.pointer < this.buffer.length) {
|
||||
const key_and_value = stypes.parse(this);
|
||||
@@ -265,10 +265,10 @@ SerializedObject.jsonify_structure = function(structure, field_name) {
|
||||
// new Array or Object
|
||||
output = new structure.constructor();
|
||||
|
||||
let keys = Object.keys(structure);
|
||||
const keys = Object.keys(structure);
|
||||
|
||||
for (let i = 0, l = keys.length; i < l; i++) {
|
||||
let key = keys[i];
|
||||
const key = keys[i];
|
||||
output[key] = SerializedObject.jsonify_structure(structure[key], key);
|
||||
}
|
||||
}
|
||||
@@ -297,7 +297,7 @@ SerializedObject.prototype.serialize = function(typedef, obj) {
|
||||
};
|
||||
|
||||
SerializedObject.prototype.hash = function(prefix) {
|
||||
let sign_buffer = new SerializedObject();
|
||||
const sign_buffer = new SerializedObject();
|
||||
|
||||
// Add hashing prefix
|
||||
if (typeof prefix !== 'undefined') {
|
||||
@@ -310,7 +310,7 @@ SerializedObject.prototype.hash = function(prefix) {
|
||||
const bits = sjcl.codec.bytes.toBits(sign_buffer.buffer);
|
||||
const sha512hex = sjcl.codec.hex.fromBits(sjcl.hash.sha512.hash(bits));
|
||||
|
||||
return UInt256.from_hex(sha512hex.substr(0, 64));
|
||||
return UInt256.from_hex(sha512hex.substr(0, 64).toUpperCase());
|
||||
};
|
||||
|
||||
// DEPRECATED
|
||||
@@ -334,7 +334,7 @@ SerializedObject.prototype.serialize_field = function(spec, obj) {
|
||||
};
|
||||
|
||||
SerializedObject.get_field_header = function(type_id, field_id) {
|
||||
let buffer = [0];
|
||||
const buffer = [0];
|
||||
|
||||
if (type_id > 0xF) {
|
||||
buffer.push(type_id & 0xFF);
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
|
||||
/*eslint new-cap: 1*/
|
||||
|
||||
var utils = require('./utils');
|
||||
var sjcl = utils.sjcl;
|
||||
const assert = require('assert');
|
||||
const lodash = require('lodash');
|
||||
const utils = require('./utils');
|
||||
const sjcl = utils.sjcl;
|
||||
|
||||
//
|
||||
// Abstract UInt class
|
||||
@@ -14,7 +16,6 @@ var sjcl = utils.sjcl;
|
||||
function UInt() {
|
||||
// Internal form: NaN or sjcl.bn
|
||||
this._value = NaN;
|
||||
this._update();
|
||||
}
|
||||
|
||||
UInt.json_rewrite = function(j, opts) {
|
||||
@@ -26,6 +27,7 @@ UInt.from_generic = function(j) {
|
||||
if (j instanceof this) {
|
||||
return j.clone();
|
||||
}
|
||||
|
||||
return (new this()).parse_generic(j);
|
||||
};
|
||||
|
||||
@@ -34,6 +36,7 @@ UInt.from_hex = function(j) {
|
||||
if (j instanceof this) {
|
||||
return j.clone();
|
||||
}
|
||||
|
||||
return (new this()).parse_hex(j);
|
||||
};
|
||||
|
||||
@@ -42,6 +45,7 @@ UInt.from_json = function(j) {
|
||||
if (j instanceof this) {
|
||||
return j.clone();
|
||||
}
|
||||
|
||||
return (new this()).parse_json(j);
|
||||
};
|
||||
|
||||
@@ -50,6 +54,7 @@ UInt.from_bits = function(j) {
|
||||
if (j instanceof this) {
|
||||
return j.clone();
|
||||
}
|
||||
|
||||
return (new this()).parse_bits(j);
|
||||
};
|
||||
|
||||
@@ -58,6 +63,7 @@ UInt.from_bytes = function(j) {
|
||||
if (j instanceof this) {
|
||||
return j.clone();
|
||||
}
|
||||
|
||||
return (new this()).parse_bytes(j);
|
||||
};
|
||||
|
||||
@@ -66,6 +72,7 @@ UInt.from_bn = function(j) {
|
||||
if (j instanceof this) {
|
||||
return j.clone();
|
||||
}
|
||||
|
||||
return (new this()).parse_bn(j);
|
||||
};
|
||||
|
||||
@@ -74,6 +81,7 @@ UInt.from_number = function(j) {
|
||||
if (j instanceof this) {
|
||||
return j.clone();
|
||||
}
|
||||
|
||||
return (new this()).parse_number(j);
|
||||
};
|
||||
|
||||
@@ -130,34 +138,46 @@ UInt.prototype._update = function() {
|
||||
|
||||
// value = NaN on error.
|
||||
UInt.prototype.parse_generic = function(j) {
|
||||
const subclass = this.constructor;
|
||||
|
||||
assert(typeof subclass.width === 'number', 'UInt missing width');
|
||||
|
||||
this._value = NaN;
|
||||
|
||||
switch (j) {
|
||||
case undefined:
|
||||
case '0':
|
||||
case this.constructor.STR_ZERO:
|
||||
case this.constructor.ACCOUNT_ZERO:
|
||||
case this.constructor.HEX_ZERO:
|
||||
case subclass.STR_ZERO:
|
||||
case subclass.ACCOUNT_ZERO:
|
||||
case subclass.HEX_ZERO:
|
||||
this._value = new sjcl.bn(0);
|
||||
break;
|
||||
|
||||
case '1':
|
||||
case this.constructor.STR_ONE:
|
||||
case this.constructor.ACCOUNT_ONE:
|
||||
case this.constructor.HEX_ONE:
|
||||
case subclass.STR_ONE:
|
||||
case subclass.ACCOUNT_ONE:
|
||||
case subclass.HEX_ONE:
|
||||
this._value = new sjcl.bn(1);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (typeof j !== 'string') {
|
||||
this._value = NaN;
|
||||
} else if (this.constructor.width === j.length) {
|
||||
var hex = utils.arrayToHex(utils.stringToArray(j));
|
||||
this._value = new sjcl.bn(hex, 16);
|
||||
} else if ((this.constructor.width * 2) === j.length) {
|
||||
// XXX Check char set!
|
||||
this._value = new sjcl.bn(j, 16);
|
||||
} else {
|
||||
this._value = NaN;
|
||||
if (lodash.isString(j)) {
|
||||
switch (j.length) {
|
||||
case subclass.width:
|
||||
const hex = utils.arrayToHex(utils.stringToArray(j));
|
||||
this._value = new sjcl.bn(hex, 16);
|
||||
break;
|
||||
case subclass.width * 2:
|
||||
// Assume hex, check char set
|
||||
this.parse_hex(j);
|
||||
break;
|
||||
}
|
||||
} else if (lodash.isNumber(j)) {
|
||||
this.parse_number(j);
|
||||
} else if (lodash.isArray(j)) {
|
||||
// Assume bytes array
|
||||
this.parse_bytes(j);
|
||||
}
|
||||
}
|
||||
|
||||
this._update();
|
||||
@@ -166,7 +186,7 @@ UInt.prototype.parse_generic = function(j) {
|
||||
};
|
||||
|
||||
UInt.prototype.parse_hex = function(j) {
|
||||
if (typeof j === 'string' && j.length === (this.constructor.width * 2)) {
|
||||
if (new RegExp(`^[0-9A-Fa-f]{${this.constructor.width * 2}}$`).test(j)) {
|
||||
this._value = new sjcl.bn(j, 16);
|
||||
} else {
|
||||
this._value = NaN;
|
||||
@@ -178,12 +198,12 @@ UInt.prototype.parse_hex = function(j) {
|
||||
};
|
||||
|
||||
UInt.prototype.parse_bits = function(j) {
|
||||
if (sjcl.bitArray.bitLength(j) !== this.constructor.width * 8) {
|
||||
this._value = NaN;
|
||||
} else {
|
||||
if (sjcl.bitArray.bitLength(j) === this.constructor.width * 8) {
|
||||
this._value = sjcl.bn.fromBits(j);
|
||||
// var bytes = sjcl.codec.bytes.fromBits(j);
|
||||
// let bytes = sjcl.codec.bytes.fromBits(j);
|
||||
// this.parse_bytes(bytes);
|
||||
} else {
|
||||
this._value = NaN;
|
||||
}
|
||||
|
||||
this._update();
|
||||
@@ -193,11 +213,11 @@ UInt.prototype.parse_bits = function(j) {
|
||||
|
||||
|
||||
UInt.prototype.parse_bytes = function(j) {
|
||||
if (!Array.isArray(j) || j.length !== this.constructor.width) {
|
||||
this._value = NaN;
|
||||
} else {
|
||||
var bits = sjcl.codec.bytes.toBits(j);
|
||||
if (Array.isArray(j) && j.length === this.constructor.width) {
|
||||
const bits = sjcl.codec.bytes.toBits(j);
|
||||
this._value = sjcl.bn.fromBits(bits);
|
||||
} else {
|
||||
this._value = NaN;
|
||||
}
|
||||
|
||||
this._update();
|
||||
@@ -209,8 +229,7 @@ UInt.prototype.parse_bytes = function(j) {
|
||||
UInt.prototype.parse_json = UInt.prototype.parse_hex;
|
||||
|
||||
UInt.prototype.parse_bn = function(j) {
|
||||
if ((j instanceof sjcl.bn) &&
|
||||
j.bitLength() <= this.constructor.width * 8) {
|
||||
if ((j instanceof sjcl.bn) && j.bitLength() <= this.constructor.width * 8) {
|
||||
this._value = new sjcl.bn(j);
|
||||
} else {
|
||||
this._value = NaN;
|
||||
@@ -238,6 +257,7 @@ UInt.prototype.to_bytes = function() {
|
||||
if (!this.is_valid()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return sjcl.codec.bytes.fromBits(this.to_bits());
|
||||
};
|
||||
|
||||
@@ -245,6 +265,7 @@ UInt.prototype.to_hex = function() {
|
||||
if (!this.is_valid()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return sjcl.codec.hex.fromBits(this.to_bits()).toUpperCase();
|
||||
};
|
||||
|
||||
@@ -263,7 +284,7 @@ UInt.prototype.to_bn = function() {
|
||||
return null;
|
||||
}
|
||||
|
||||
var bits = this.to_bits();
|
||||
const bits = this.to_bits();
|
||||
|
||||
return sjcl.bn.fromBits(bits);
|
||||
};
|
||||
|
||||
1675
test/fixtures/uint.json
vendored
Normal file
1675
test/fixtures/uint.json
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,23 +1,104 @@
|
||||
var assert = require('assert');
|
||||
var UInt128 = require('ripple-lib').UInt128;
|
||||
'use strict';
|
||||
|
||||
describe('UInt', function() {
|
||||
describe('128', function() {
|
||||
describe('#parse_number', function () {
|
||||
it('should create 00000000000000000000000000000000 when called with 0', function () {
|
||||
var val = UInt128.from_number(0);
|
||||
assert.strictEqual(val.to_hex(), '00000000000000000000000000000000');
|
||||
/* eslint-disable max-len */
|
||||
|
||||
const assert = require('assert-diff');
|
||||
const lodash = require('lodash');
|
||||
const ripple = require('ripple-lib');
|
||||
const fixtures = require('./fixtures/uint');
|
||||
|
||||
function resultError(test, result) {
|
||||
function type(e) {
|
||||
return Object.prototype.toString.call(e);
|
||||
}
|
||||
return `Expected ${type(test.input)}: ${test.input} to yield ${type(test.expected)}: ${test.expected === 'null' ? NaN : test.expected}. Actual: ${type(result)}: ${result}`;
|
||||
}
|
||||
|
||||
function makeTests(uIntType) {
|
||||
describe(uIntType, function() {
|
||||
const rippleType = ripple[uIntType];
|
||||
const tests = fixtures[uIntType];
|
||||
|
||||
it('from_json().to_json()', function() {
|
||||
tests['from_json().to_json()'].forEach(function(test) {
|
||||
let result = rippleType.from_json(test.input);
|
||||
assert.strictEqual(result.is_valid(), String(test.expected) !== 'null', `Validity check failed: ${test.input}`);
|
||||
result = result.to_json();
|
||||
|
||||
if (test.expected === 'null') {
|
||||
// XXX
|
||||
// UInt160.to_json() returns NaN rather than null if input is invalid
|
||||
assert.strictEqual(lodash.isNaN(result), true, resultError(test, result));
|
||||
} else {
|
||||
assert.strictEqual(result, test.expected, resultError(test, result));
|
||||
}
|
||||
});
|
||||
it('should create 00000000000000000000000000000001 when called with 1', function () {
|
||||
var val = UInt128.from_number(1);
|
||||
assert.strictEqual(val.to_hex(), '00000000000000000000000000000001');
|
||||
});
|
||||
it('from_json().to_bytes()', function() {
|
||||
tests['from_json().to_bytes()'].forEach(function(test) {
|
||||
const result = rippleType.from_json(test.input);
|
||||
assert.strictEqual(result.is_valid(), String(test.expected) !== 'null', `Validity check failed: ${test.input}`);
|
||||
assert.deepEqual(result.to_bytes(), test.expected, resultError(test, result));
|
||||
});
|
||||
it('should create 000000000000000000000000FFFFFFFF when called with 0xFFFFFFFF', function () {
|
||||
var val = UInt128.from_number(0xFFFFFFFF);
|
||||
assert.strictEqual(val.to_hex(), '000000000000000000000000FFFFFFFF');
|
||||
});
|
||||
it('from_number().to_json()', function() {
|
||||
tests['from_number().to_json()'].forEach(function(test) {
|
||||
let result = rippleType.from_number(test.input);
|
||||
assert.strictEqual(result.is_valid(), String(test.expected) !== 'null', `Validity check failed: ${test.input}`);
|
||||
result = result.to_json();
|
||||
|
||||
if (test.expected === 'null') {
|
||||
// XXX
|
||||
// UInt160.to_json() returns NaN rather than null if input is invalid
|
||||
assert.strictEqual(lodash.isNaN(result), true, resultError(test, result));
|
||||
} else {
|
||||
assert.strictEqual(result, test.expected, resultError(test, result));
|
||||
}
|
||||
});
|
||||
});
|
||||
it('from_number().to_hex()', function() {
|
||||
tests['from_number().to_hex()'].forEach(function(test) {
|
||||
const result = rippleType.from_number(test.input);
|
||||
assert.strictEqual(result.is_valid(), String(test.expected) !== 'null', `Validity check failed: ${test.input}`);
|
||||
assert.strictEqual(result.to_hex(), test.expected, resultError(test, result));
|
||||
});
|
||||
});
|
||||
it('from_generic().to_*()', function() {
|
||||
tests['from_generic().to_*()'].forEach(function(test) {
|
||||
let result = rippleType.from_generic(test.input);
|
||||
|
||||
switch (test.input) {
|
||||
// XXX
|
||||
// from_generic() accepts these as "zero"
|
||||
case 0:
|
||||
case '0':
|
||||
case undefined:
|
||||
switch (test.outputMethod) {
|
||||
case 'to_bytes':
|
||||
test.expected = Array(rippleType.width).fill(0);
|
||||
break;
|
||||
case 'to_json':
|
||||
case 'to_hex':
|
||||
test.expected = Array(rippleType.width * 2).fill(0).join('');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert.strictEqual(result.is_valid(), String(test.expected) !== 'null',
|
||||
`Validity check failed: ${test.input} > ${test.expected}`);
|
||||
|
||||
result = result[test.outputMethod]();
|
||||
|
||||
if (test.expected === 'null') {
|
||||
// XXX
|
||||
// UInt160.to_json() returns NaN rather than null if input is invalid
|
||||
assert.strictEqual(lodash.isNaN(result), true, resultError(test, result));
|
||||
} else {
|
||||
assert.deepEqual(result, test.expected, resultError(test, result));
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// vim:sw=2:sts=2:ts=8:et
|
||||
['UInt128', 'UInt160', 'UInt256'].forEach(makeTests);
|
||||
|
||||
Reference in New Issue
Block a user