Emit Connection errors on RippleAPI, remove unused exports, use ripple-hashes in sign

This commit is contained in:
Chris Clark
2015-10-28 10:57:39 -07:00
parent 85c1a3cc42
commit c238596a81
10 changed files with 33 additions and 86 deletions

30
npm-shrinkwrap.json generated
View File

@@ -18,16 +18,6 @@
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-2.1.0.tgz" "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-2.1.0.tgz"
}, },
"hash.js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.0.3.tgz",
"dependencies": {
"inherits": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
}
}
},
"https-proxy-agent": { "https-proxy-agent": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz",
@@ -94,6 +84,16 @@
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/ripple-address-codec/-/ripple-address-codec-2.0.1.tgz", "resolved": "https://registry.npmjs.org/ripple-address-codec/-/ripple-address-codec-2.0.1.tgz",
"dependencies": { "dependencies": {
"hash.js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.0.3.tgz",
"dependencies": {
"inherits": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
}
}
},
"x-address-codec": { "x-address-codec": {
"version": "0.7.2", "version": "0.7.2",
"resolved": "https://registry.npmjs.org/x-address-codec/-/x-address-codec-0.7.2.tgz", "resolved": "https://registry.npmjs.org/x-address-codec/-/x-address-codec-0.7.2.tgz",
@@ -191,6 +191,16 @@
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
} }
} }
},
"hash.js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.0.3.tgz",
"dependencies": {
"inherits": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
}
}
} }
} }
}, },

View File

@@ -17,7 +17,6 @@
"dependencies": { "dependencies": {
"babel-runtime": "^5.5.4", "babel-runtime": "^5.5.4",
"bignumber.js": "^2.0.3", "bignumber.js": "^2.0.3",
"hash.js": "^1.0.3",
"https-proxy-agent": "^1.0.0", "https-proxy-agent": "^1.0.0",
"is-my-json-valid": "^2.12.2", "is-my-json-valid": "^2.12.2",
"lodash": "^3.1.0", "lodash": "^3.1.0",

View File

@@ -14,7 +14,6 @@ module.exports = {
generateAddress: utils.generateAddress, generateAddress: utils.generateAddress,
generateAddressAPI: utils.generateAddressAPI, generateAddressAPI: utils.generateAddressAPI,
removeUndefined: utils.removeUndefined, removeUndefined: utils.removeUndefined,
convertExceptions: utils.convertExceptions,
convertKeysFromSnakeCaseToCamelCase: convertKeysFromSnakeCaseToCamelCase:
utils.convertKeysFromSnakeCaseToCamelCase, utils.convertKeysFromSnakeCaseToCamelCase,
rippleToUnixTimestamp: utils.rippleToUnixTimestamp, rippleToUnixTimestamp: utils.rippleToUnixTimestamp,

View File

@@ -112,6 +112,5 @@ function schemaValidate(schemaName: string, object: any): void {
SCHEMAS = loadSchemas(); SCHEMAS = loadSchemas();
module.exports = { module.exports = {
schemaValidate: schemaValidate, schemaValidate
SCHEMAS: SCHEMAS
}; };

View File

@@ -18,19 +18,6 @@ function isValidSecret(secret) {
} }
} }
function validateAddressAndSecret(obj: {address: string, secret: string}
): void {
const address = obj.address;
const secret = obj.secret;
schemaValidate('address', address);
if (!secret) {
throw error('Parameter missing: secret');
}
if (!isValidSecret(secret)) {
throw error('Invalid parameter: secret');
}
}
function validateSecret(secret: string): void { function validateSecret(secret: string): void {
if (!secret) { if (!secret) {
throw error('Parameter missing: secret'); throw error('Parameter missing: secret');
@@ -57,7 +44,6 @@ function validateOptions(schema, options) {
module.exports = { module.exports = {
address: _.partial(schemaValidate, 'address'), address: _.partial(schemaValidate, 'address'),
addressAndSecret: validateAddressAndSecret,
secret: validateSecret, secret: validateSecret,
currency: _.partial(schemaValidate, 'currency'), currency: _.partial(schemaValidate, 'currency'),
identifier: _.partial(schemaValidate, 'hash256'), identifier: _.partial(schemaValidate, 'hash256'),

View File

@@ -64,6 +64,9 @@ class RippleAPI extends EventEmitter {
this.connection.on('ledgerClosed', message => { this.connection.on('ledgerClosed', message => {
this.emit('ledgerClosed', server.formatLedgerClose(message)); this.emit('ledgerClosed', server.formatLedgerClose(message));
}); });
this.connection.on('error', (type, info) => {
this.emit('error', type, info);
});
} else { } else {
throw new errors.RippleError('Multi-server not implemented'); throw new errors.RippleError('Multi-server not implemented');
} }

View File

@@ -126,7 +126,6 @@ module.exports = {
getXRPBalance, getXRPBalance,
ensureLedgerVersion, ensureLedgerVersion,
compareTransactions, compareTransactions,
renameCounterpartyToIssuer,
renameCounterpartyToIssuerInOrder, renameCounterpartyToIssuerInOrder,
getRecursive, getRecursive,
hasCompleteLedgerRange, hasCompleteLedgerRange,

View File

@@ -3,34 +3,9 @@
const utils = require('./utils'); const utils = require('./utils');
const keypairs = require('ripple-keypairs'); const keypairs = require('ripple-keypairs');
const binary = require('ripple-binary-codec'); const binary = require('ripple-binary-codec');
const sha512 = require('hash.js').sha512; const {computeBinaryTransactionHash} = require('ripple-hashes');
const validate = utils.common.validate; const validate = utils.common.validate;
/**
* These prefixes are inserted before the source material used to
* generate various hashes. This is done to put each hash in its own
* "space." This way, two different types of objects with the
* same binary data will produce different hashes.
*
* Each prefix is a 4-byte value with the last byte set to zero
* and the first three bytes formed from the ASCII equivalent of
* some arbitrary string. For example "TXN".
*/
const HASH_TX_ID = 0x54584E00; // 'TXN'
// For a hash function, rippled uses SHA-512 and then truncates the result
// to the first 256 bytes. This algorithm, informally called SHA-512Half,
// provides an output that has comparable security to SHA-256, but runs
// faster on 64-bit processors.
function sha512half(buffer) {
return sha512().update(buffer).digest('hex').toUpperCase().slice(0, 64);
}
function hashSerialization(serialized, prefix) {
const hexPrefix = prefix.toString(16).toUpperCase();
return sha512half(new Buffer(hexPrefix + serialized, 'hex'));
}
function computeSignature(txJSON, privateKey) { function computeSignature(txJSON, privateKey) {
const signingData = binary.encodeForSigning(txJSON); const signingData = binary.encodeForSigning(txJSON);
return keypairs.sign(signingData, privateKey); return keypairs.sign(signingData, privateKey);
@@ -40,6 +15,8 @@ function sign(txJSON: string, secret: string
): {signedTransaction: string; id: string} { ): {signedTransaction: string; id: string} {
const tx = JSON.parse(txJSON); const tx = JSON.parse(txJSON);
validate.txJSON(tx); validate.txJSON(tx);
// we can't validate that the secret matches the account because
// the secret could correspond to the regular key
validate.secret(secret); validate.secret(secret);
const keypair = keypairs.deriveKeypair(secret); const keypair = keypairs.deriveKeypair(secret);
@@ -50,7 +27,7 @@ function sign(txJSON: string, secret: string
const serialized = binary.encode(tx); const serialized = binary.encode(tx);
return { return {
signedTransaction: serialized, signedTransaction: serialized,
id: hashSerialization(serialized, HASH_TX_ID) id: computeBinaryTransactionHash(serialized)
}; };
} }

View File

@@ -15,7 +15,6 @@ const validate = common.validate;
const utils = RippleAPI._PRIVATE.ledgerUtils; const utils = RippleAPI._PRIVATE.ledgerUtils;
const ledgerClosed = require('./fixtures/api/rippled/ledger-close-newer'); const ledgerClosed = require('./fixtures/api/rippled/ledger-close-newer');
const schemaValidator = RippleAPI._PRIVATE.schemaValidator; const schemaValidator = RippleAPI._PRIVATE.schemaValidator;
const ledgerHashSchema = require('./fixtures/schemas/ledgerhash.json');
const orderbook = { const orderbook = {
base: { base: {
@@ -752,12 +751,6 @@ describe('RippleAPI', function() {
assert.strictEqual(utils.compareTransactions(first, second), 1); assert.strictEqual(utils.compareTransactions(first, second), 1);
}); });
it('ledger utils - renameCounterpartyToIssuer', function() {
assert.strictEqual(utils.renameCounterpartyToIssuer(undefined), undefined);
const amountArg = {issuer: '1'};
assert.deepEqual(utils.renameCounterpartyToIssuer(amountArg), amountArg);
});
it('ledger utils - getRecursive', function() { it('ledger utils - getRecursive', function() {
function getter(marker, limit) { function getter(marker, limit) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@@ -776,26 +769,22 @@ describe('RippleAPI', function() {
}); });
describe('schema-validator', function() { describe('schema-validator', function() {
beforeEach(function() {
schemaValidator.SCHEMAS.ledgerhash = ledgerHashSchema;
});
it('valid', function() { it('valid', function() {
assert.doesNotThrow(function() { assert.doesNotThrow(function() {
schemaValidator.schemaValidate('ledgerhash', schemaValidator.schemaValidate('hash256',
'0F7ED9F40742D8A513AE86029462B7A6768325583DF8EE21B7EC663019DD6A0F'); '0F7ED9F40742D8A513AE86029462B7A6768325583DF8EE21B7EC663019DD6A0F');
}); });
}); });
it('invalid', function() { it('invalid', function() {
assert.throws(function() { assert.throws(function() {
schemaValidator.schemaValidate('ledgerhash', 'invalid'); schemaValidator.schemaValidate('hash256', 'invalid');
}, this.api.errors.ValidationError); }, this.api.errors.ValidationError);
}); });
it('invalid - empty value', function() { it('invalid - empty value', function() {
assert.throws(function() { assert.throws(function() {
schemaValidator.schemaValidate('ledgerhash', ''); schemaValidator.schemaValidate('hash256', '');
}, this.api.errors.ValidationError); }, this.api.errors.ValidationError);
}); });
@@ -820,21 +809,6 @@ describe('RippleAPI', function() {
/minLedgerVersion must not be greater than maxLedgerVersion/); /minLedgerVersion must not be greater than maxLedgerVersion/);
}); });
it('addressAndSecret', function() {
const noSecret = {address: address};
assert.throws(_.partial(validate.addressAndSecret, noSecret),
this.api.errors.ValidationError);
assert.throws(_.partial(validate.addressAndSecret, noSecret),
/Parameter missing/);
const badSecret = {address: address, secret: 'sbad'};
assert.throws(_.partial(validate.addressAndSecret, badSecret),
this.api.errors.ValidationError);
const goodWallet = {address: 'rpZMK8hwyrBvLorFNWHRCGt88nCJWbixur',
secret: 'shzjfakiK79YQdMjy4h8cGGfQSV6u'
};
assert.doesNotThrow(_.partial(validate.addressAndSecret, goodWallet));
});
it('secret', function() { it('secret', function() {
assert.doesNotThrow(_.partial(validate.secret, assert.doesNotThrow(_.partial(validate.secret,
'shzjfakiK79YQdMjy4h8cGGfQSV6u')); 'shzjfakiK79YQdMjy4h8cGGfQSV6u'));

View File

@@ -292,7 +292,8 @@ describe('integration tests', function() {
it('generateWallet', function() { it('generateWallet', function() {
const newWallet = this.api.generateAddress(); const newWallet = this.api.generateAddress();
assert(newWallet && newWallet.address && newWallet.secret); assert(newWallet && newWallet.address && newWallet.secret);
validate.addressAndSecret(newWallet); validate.address(newWallet.address);
validate.secret(newWallet.secret);
}); });
}); });