[CHORE] Merged PubKeyValidator into Account class

This commit is contained in:
Evan Schwartz
2014-05-01 20:23:20 -07:00
parent d8504a3001
commit cf3a21a712
5 changed files with 491 additions and 203 deletions

View File

@@ -10,13 +10,15 @@
//
// var network = require("./network.js");
var async = require('async');
var EventEmitter = require('events').EventEmitter;
var util = require('util');
var extend = require('extend');
var Amount = require('./amount').Amount;
var UInt160 = require('./uint160').UInt160;
var TransactionManager = require('./transactionmanager').TransactionManager;
var sjcl = require('./utils').sjcl;
var Base = require('./base').Base;
/**
* @constructor Account
@@ -278,6 +280,124 @@ Account.prototype.submit = function(transaction) {
this._transactionManager.submit(transaction);
};
/**
* Check whether the given public key is valid for this account
*
* @param {Hex-encoded String|RippleAddress} public_key
* @param {Function} callback
*
* @callback
* @param {Error} err
* @param {Boolean} true if the public key is valid and active, false otherwise
*/
Account.prototype.publicKeyIsActive = function(public_key, callback) {
var self = this;
var public_key_as_uint160;
try {
public_key_as_uint160 = Account._publicKeyToAddress(public_key);
} catch (err) {
return callback(err);
}
function getAccountInfo(async_callback) {
self.getInfo(function(err, account_info_res){
// If the remote responds with an Account Not Found error then the account
// is unfunded and thus we can assume that the master key is active
if (err && err.remote && err.remote.error === 'actNotFound') {
async_callback(null, null);
} else {
async_callback(err, account_info_res);
}
});
};
function publicKeyIsValid(account_info_res, async_callback) {
// Catch the case of unfunded accounts
if (!account_info_res) {
if (public_key_as_uint160 === self._account_id) {
async_callback(null, true);
} else {
async_callback(null, false);
}
return;
}
var account_info = account_info_res.account_data;
// Respond with true if the RegularKey is set and matches the given public key or
// if the public key matches the account address and the lsfDisableMaster is not set
if (account_info.RegularKey &&
account_info.RegularKey === public_key_as_uint160) {
async_callback(null, true);
} else if (account_info.Account === public_key_as_uint160 &&
((account_info.Flags & 0x00100000) === 0)) {
async_callback(null, true);
} else {
async_callback(null, false);
}
};
var steps = [
getAccountInfo,
publicKeyIsValid
];
async.waterfall(steps, callback);
};
/**
* Convert a hex-encoded public key to a Ripple Address
*
* @static
*
* @param {Hex-encoded string|RippleAddress} public_key
* @returns {RippleAddress}
*/
Account._publicKeyToAddress = function(public_key) {
// Based on functions in /src/js/ripple/keypair.js
function hexToUInt160(public_key) {
var bits = sjcl.codec.hex.toBits(public_key);
var hash = sjcl.hash.ripemd160.hash(sjcl.hash.sha256.hash(bits));
var address = UInt160.from_bits(hash);
address.set_version(Base.VER_ACCOUNT_ID);
return address.to_json();
}
if (UInt160.is_valid(public_key)) {
return public_key;
} else if (/^[0-9a-fA-F]+$/.test(public_key)) {
return hexToUInt160(public_key);
} else {
throw(new Error('Public key is invalid. Must be a UInt160 or a hex string'));
}
};
exports.Account = Account;
// vim:sw=2:sts=2:ts=8:et

View File

@@ -4,7 +4,7 @@ var sjcl = require('./utils').sjcl;
var Remote = require('./remote').Remote;
var Seed = require('./seed').Seed;
var KeyPair = require('./keypair').KeyPair;
var PublicKeyValidator = require('./pubkeyvalidator');
var Account = require('./account').Account;
var UInt160 = require('./uint160').UInt160;
// Message class (static)
@@ -186,8 +186,8 @@ Message.verifyHashSignature = function(data, remote, callback) {
key_pair._pubkey = public_key;
var public_key_hex = key_pair.to_hex_pub();
var public_key_validator = new PublicKeyValidator(remote);
public_key_validator.validate(account, public_key_hex, async_callback);
var account_class_instance = new Account(remote, account);
account_class_instance.publicKeyIsActive(public_key_hex, async_callback);
};

View File

@@ -1,139 +0,0 @@
var async = require('async');
var UInt160 = require('./uint160').UInt160;
var sjcl = require('./utils').sjcl;
var Base = require('./base').Base;
/**
* @constructor PubKeyValidator
* @param {Remote} remote
*/
function PubKeyValidator(remote) {
var self = this;
if (remote) {
self._remote = remote;
} else {
throw(new Error('Must instantiate the PubKeyValidator with a ripple-lib Remote'));
}
}
/**
* Check whether the public key is valid for the specified address.
*
* @param {String} address
* @param {String} public_key
* @param {Function} callback
*
* callback function is called with (err, is_valid), where is_valid
* is a boolean indicating whether the public_key supplied is active
*/
PubKeyValidator.prototype.validate = function(address, public_key, callback) {
var self = this;
var public_key_as_uint160;
try {
public_key_as_uint160 = self._parsePublicKey(public_key);
} catch (err) {
return callback(err);
}
function getAccountInfo(async_callback) {
self._remote.account(address).getInfo(function(err, account_info_res){
// If the remote responds with an Account Not Found error then the account
// is unfunded and thus we can assume that the master key is active
if (err && err.remote && err.remote.error === 'actNotFound') {
async_callback(null, null);
} else {
async_callback(err, account_info_res);
}
});
};
function publicKeyIsValid(account_info_res, async_callback) {
// Catch the case of unfunded accounts
if (!account_info_res) {
if (public_key_as_uint160 === address) {
async_callback(null, true);
} else {
async_callback(null, false);
}
return;
}
var account_info = account_info_res.account_data;
// Respond with true if the RegularKey is set and matches the given public key or
// if the public key matches the account address and the lsfDisableMaster is not set
if (account_info.RegularKey &&
account_info.RegularKey === public_key_as_uint160) {
async_callback(null, true);
} else if (account_info.Account === public_key_as_uint160 &&
((account_info.Flags & 0x00100000) === 0)) {
async_callback(null, true);
} else {
async_callback(null, false);
}
};
var steps = [
getAccountInfo,
publicKeyIsValid
];
async.waterfall(steps, callback);
};
/**
* Convert a hex-encoded public key to a Ripple Address
*
* @param {Hex-encoded string|RippleAddress} public_key
* @returns {RippleAddress}
*/
PubKeyValidator.prototype._parsePublicKey = function(public_key) {
// Based on functions in /src/js/ripple/keypair.js
function hexToUInt160(public_key) {
var bits = sjcl.codec.hex.toBits(public_key);
var hash = sjcl.hash.ripemd160.hash(sjcl.hash.sha256.hash(bits));
var address = UInt160.from_bits(hash);
address.set_version(Base.VER_ACCOUNT_ID);
return address.to_json();
}
if (UInt160.is_valid(public_key)) {
return public_key;
} else if (/^[0-9a-fA-F]+$/.test(public_key)) {
return hexToUInt160(public_key);
} else {
throw(new Error('Public key is invalid. Must be a UInt160 or a hex string'));
}
};
module.exports = PubKeyValidator;

View File

@@ -1,44 +1,41 @@
var assert = require('assert');
var PubKeyValidator = require('../src/js/ripple/pubkeyvalidator');
var Account = require('../src/js/ripple/account').Account;
describe('PubKeyValidator', function(){
describe('Account', function(){
describe('._parsePublicKey()', function(){
var pkv = new PubKeyValidator({});
describe('._publicKeyToAddress()', function(){
it('should throw an error if the key is invalid', function(){
try {
pkv._parsePublicKey('not a real key');
Account._publicKeyToAddress('not a real key');
} catch (e) {
assert(e);
}
});
it('should return unchanged a valid UINT160', function(){
assert('rKXCummUHnenhYudNb9UoJ4mGBR75vFcgz' === pkv._parsePublicKey('rKXCummUHnenhYudNb9UoJ4mGBR75vFcgz'));
assert('rKXCummUHnenhYudNb9UoJ4mGBR75vFcgz' === Account._publicKeyToAddress('rKXCummUHnenhYudNb9UoJ4mGBR75vFcgz'));
});
it('should parse a hex-encoded public key as a UINT160', function(){
assert('rKXCummUHnenhYudNb9UoJ4mGBR75vFcgz' === pkv._parsePublicKey('025B32A54BFA33FB781581F49B235C0E2820C929FF41E677ADA5D3E53CFBA46332'));
assert('rKXCummUHnenhYudNb9UoJ4mGBR75vFcgz' === Account._publicKeyToAddress('025B32A54BFA33FB781581F49B235C0E2820C929FF41E677ADA5D3E53CFBA46332'));
assert('rLpq5RcRzA8FU1yUqEPW4xfsdwon7casuM' === pkv._parsePublicKey('03BFA879C00D58CF55F2B5975FF9B5293008FF49BEFB3EE6BEE2814247BF561A23'));
assert('rLpq5RcRzA8FU1yUqEPW4xfsdwon7casuM' === Account._publicKeyToAddress('03BFA879C00D58CF55F2B5975FF9B5293008FF49BEFB3EE6BEE2814247BF561A23'));
assert('rP4yWwjoDGF2iZSBdAQAgpC449YDezEbT1' === pkv._parsePublicKey('02DF0AB18930B6410CA9F55CB37541F1FED891B8EDF8AB1D01D8F23018A4B204A7'));
assert('rP4yWwjoDGF2iZSBdAQAgpC449YDezEbT1' === Account._publicKeyToAddress('02DF0AB18930B6410CA9F55CB37541F1FED891B8EDF8AB1D01D8F23018A4B204A7'));
assert('rLdfp6eoR948KVxfn6EpaaNTKwfwXhzSeQ' === pkv._parsePublicKey('0310C451A40CAFFD39D6B8A3BD61BF65BCA55246E9DABC3170EBE431D30655B61F'));
assert('rLdfp6eoR948KVxfn6EpaaNTKwfwXhzSeQ' === Account._publicKeyToAddress('0310C451A40CAFFD39D6B8A3BD61BF65BCA55246E9DABC3170EBE431D30655B61F'));
});
});
describe('.validate()', function(){
describe('.publicKeyIsActive()', function(){
it('should respond true if the public key corresponds to the account address and the master key IS NOT disabled', function(){
var pkv = new PubKeyValidator({
account: function(address){
return {
getInfo: function(callback) {
var account = new Account({
on: function(){},
request_account_info: function(address, callback) {
if (address === 'rKXCummUHnenhYudNb9UoJ4mGBR75vFcgz') {
callback(null, { account_data: {
Account: 'rKXCummUHnenhYudNb9UoJ4mGBR75vFcgz',
@@ -47,10 +44,8 @@ describe('PubKeyValidator', function(){
}});
}
}
}
}
});
pkv.validate('rKXCummUHnenhYudNb9UoJ4mGBR75vFcgz', '025B32A54BFA33FB781581F49B235C0E2820C929FF41E677ADA5D3E53CFBA46332', function(err, is_valid){
}, 'rKXCummUHnenhYudNb9UoJ4mGBR75vFcgz');
account.publicKeyIsActive('025B32A54BFA33FB781581F49B235C0E2820C929FF41E677ADA5D3E53CFBA46332', function(err, is_valid){
assert(err === null);
assert(is_valid === true);
});
@@ -59,10 +54,9 @@ describe('PubKeyValidator', function(){
it('should respond false if the public key corresponds to the account address and the master key IS disabled', function(){
var pkv = new PubKeyValidator({
account: function(address){
return {
getInfo: function(callback) {
var account = new Account({
on: function(){},
request_account_info: function(address, callback) {
if (address === 'rKXCummUHnenhYudNb9UoJ4mGBR75vFcgz') {
callback(null, { account_data: {
Account: 'rKXCummUHnenhYudNb9UoJ4mGBR75vFcgz',
@@ -71,10 +65,8 @@ describe('PubKeyValidator', function(){
}});
}
}
}
}
});
pkv.validate('rKXCummUHnenhYudNb9UoJ4mGBR75vFcgz', '025B32A54BFA33FB781581F49B235C0E2820C929FF41E677ADA5D3E53CFBA46332', function(err, is_valid){
}, 'rKXCummUHnenhYudNb9UoJ4mGBR75vFcgz');
account.publicKeyIsActive('025B32A54BFA33FB781581F49B235C0E2820C929FF41E677ADA5D3E53CFBA46332', function(err, is_valid){
assert(err === null);
assert(is_valid === false);
});
@@ -83,10 +75,9 @@ describe('PubKeyValidator', function(){
it('should respond true if the public key corresponds to the regular key', function(){
var pkv = new PubKeyValidator({
account: function(address){
return {
getInfo: function(callback) {
var account = new Account({
on: function(){},
request_account_info: function(address, callback) {
if (address === 'rKXCummUHnenhYudNb9UoJ4mGBR75vFcgz') {
callback(null, { account_data: {
Account: 'rKXCummUHnenhYudNb9UoJ4mGBR75vFcgz',
@@ -96,10 +87,8 @@ describe('PubKeyValidator', function(){
}});
}
}
}
}
});
pkv.validate('rKXCummUHnenhYudNb9UoJ4mGBR75vFcgz', '02BE53B7ACBB0900E0BB7729C9CAC1033A0137993B17800BD1191BBD1B29D96A8C', function(err, is_valid){
}, 'rKXCummUHnenhYudNb9UoJ4mGBR75vFcgz');
account.publicKeyIsActive('02BE53B7ACBB0900E0BB7729C9CAC1033A0137993B17800BD1191BBD1B29D96A8C', function(err, is_valid){
assert(err === null);
assert(is_valid === true);
});
@@ -108,10 +97,9 @@ describe('PubKeyValidator', function(){
it('should respond false if the public key does not correspond to an active public key for the account', function(){
var pkv = new PubKeyValidator({
account: function(address){
return {
getInfo: function(callback) {
var account = new Account({
on: function(){},
request_account_info: function(address, callback) {
if (address === 'rKXCummUHnenhYudNb9UoJ4mGBR75vFcgz') {
callback(null, { account_data: {
Account: 'rKXCummUHnenhYudNb9UoJ4mGBR75vFcgz',
@@ -121,10 +109,8 @@ describe('PubKeyValidator', function(){
}});
}
}
}
}
});
pkv.validate('rKXCummUHnenhYudNb9UoJ4mGBR75vFcgz', '032ECDA93970BC7E8872EF6582CB52A5557F117244A949EB4FA8AC7688CF24FBC8', function(err, is_valid){
}, 'rKXCummUHnenhYudNb9UoJ4mGBR75vFcgz');
account.publicKeyIsActive('032ECDA93970BC7E8872EF6582CB52A5557F117244A949EB4FA8AC7688CF24FBC8', function(err, is_valid){
assert(err === null);
assert(is_valid === false);
});
@@ -133,10 +119,9 @@ describe('PubKeyValidator', function(){
it('should respond false if the public key is invalid', function(){
var pkv = new PubKeyValidator({
account: function(address){
return {
getInfo: function(callback) {
var account = new Account({
on: function(){},
request_account_info: function(address, callback) {
if (address === 'rKXCummUHnenhYudNb9UoJ4mGBR75vFcgz') {
callback(null, { account_data: {
Account: 'rKXCummUHnenhYudNb9UoJ4mGBR75vFcgz',
@@ -146,10 +131,8 @@ describe('PubKeyValidator', function(){
}});
}
}
}
}
});
pkv.validate('rKXCummUHnenhYudNb9UoJ4mGBR75vFcgz', 'not a real public key', function(err, is_valid){
}, 'rKXCummUHnenhYudNb9UoJ4mGBR75vFcgz');
account.publicKeyIsActive('not a real public key', function(err, is_valid){
assert(err);
});
@@ -157,10 +140,9 @@ describe('PubKeyValidator', function(){
it('should assume the master key is valid for unfunded accounts', function(){
var pkv = new PubKeyValidator({
account: function(address){
return {
getInfo: function(callback) {
var account = new Account({
on: function(){},
request_account_info: function(address, callback) {
if (address === 'rLdfp6eoR948KVxfn6EpaaNTKwfwXhzSeQ') {
callback({ error: 'remoteError',
error_message: 'Remote reported an error.',
@@ -186,10 +168,8 @@ describe('PubKeyValidator', function(){
});
}
}
}
}
});
pkv.validate('rLdfp6eoR948KVxfn6EpaaNTKwfwXhzSeQ', '0310C451A40CAFFD39D6B8A3BD61BF65BCA55246E9DABC3170EBE431D30655B61F', function(err, is_valid){
}, 'rLdfp6eoR948KVxfn6EpaaNTKwfwXhzSeQ');
account.publicKeyIsActive('0310C451A40CAFFD39D6B8A3BD61BF65BCA55246E9DABC3170EBE431D30655B61F', function(err, is_valid){
assert(!err);
assert(is_valid);
});

327
test/message-test.js Normal file
View File

@@ -0,0 +1,327 @@
var assert = require('assert');
var sjcl = require('../build/sjcl');
var Message = require('../src/js/ripple/message');
var Seed = require('../src/js/ripple/seed').Seed;
var Remote = require('../src/js/ripple/remote').Remote;
describe('Message', function(){
describe('signMessage', function(){
it('should prepend the MAGIC_BYTES, call the HASH_FUNCTION, and then call signHash', function(){
var normal_signHash = Message.signHash;
var message_text = 'Hello World!';
var signHash_called = false;
Message.signHash = function(hash) {
signHash_called = true;
assert.deepEqual(hash, Message.HASH_FUNCTION(Message.MAGIC_BYTES + message_text));
};
Message.signMessage(message_text);
assert(signHash_called);
Message.signHash = normal_signHash;
});
});
describe('signHash', function(){
it('should accept the hash as either a hex string or a bitArray', function(){
var normal_random = sjcl.random.randomWords;
sjcl.random.randomWords = function(num_words){
var words = [];
for (var w = 0; w < num_words; w++) {
words.push(sjcl.codec.hex.toBits('00000000'));
}
return words;
};
var secret_string = 'safRpB5euNL52PZPTSqrE9gvuFwTC';
// var address = 'rLLzaq61D633b5hhbNXKM9CkrYHboobVv3';
var hash = 'e865bcc63a86ef21585ac8340a7cc8590ed85175a2a718c6fb2bfb2715d13778';
var signature1 = Message.signHash(hash, secret_string);
var signature2 = Message.signHash(sjcl.codec.hex.toBits(hash), secret_string);
assert.strictEqual(signature1, signature2);
sjcl.random.randomWords = normal_random;
});
it('should accept the secret as a string or scjl.ecc.ecdsa.secretKey object', function(){
var normal_random = sjcl.random.randomWords;
sjcl.random.randomWords = function(num_words){
var words = [];
for (var w = 0; w < num_words; w++) {
words.push(sjcl.codec.hex.toBits('00000000'));
}
return words;
};
var secret_string = 'safRpB5euNL52PZPTSqrE9gvuFwTC';
// var address = 'rLLzaq61D633b5hhbNXKM9CkrYHboobVv3';
var hash = 'e865bcc63a86ef21585ac8340a7cc8590ed85175a2a718c6fb2bfb2715d13778';
var signature1 = Message.signHash(hash, secret_string);
var signature2 = Message.signHash(hash, Seed.from_json(secret_string).get_key()._secret);
assert.strictEqual(signature1, signature2);
sjcl.random.randomWords = normal_random;
});
it('should throw an error if given an invalid secret key', function(){
var secret_string = 'badsafRpB5euNL52PZPTSqrE9gvuFwTC';
var hash = 'e865bcc63a86ef21585ac8340a7cc8590ed85175a2a718c6fb2bfb2715d13778';
assert.throws(function(){
Message.signHash(hash, secret_string);
}, /Cannot\ generate\ keys\ from\ invalid\ seed/);
});
it('should throw an error if the parameters are reversed', function(){
var secret_string = 'safRpB5euNL52PZPTSqrE9gvuFwTC';
var hash = 'e865bcc63a86ef21585ac8340a7cc8590ed85175a2a718c6fb2bfb2715d13778';
assert.throws(function(){
Message.signHash(secret_string, hash);
}, Error);
assert.throws(function(){
Message.signHash(secret_string, sjcl.codec.hex.toBits(hash));
}, Error);
assert.throws(function(){
Message.signHash(Seed.from_json(secret_string).get_key()._secret, hash);
}, Error);
assert.throws(function(){
Message.signHash(Seed.from_json(secret_string).get_key()._secret, sjcl.codec.hex.toBits(hash));
}, Error);
});
it('should produce a base64-encoded signature', function(){
var REGEX_BASE64 = /^([A-Za-z0-9\+]{4})*([A-Za-z0-9\+]{2}==)|([A-Za-z0-9\+]{3}=)?$/;
var normal_random = sjcl.random.randomWords;
sjcl.random.randomWords = function(num_words){
var words = [];
for (var w = 0; w < num_words; w++) {
words.push(sjcl.codec.hex.toBits('00000000'));
}
return words;
};
var secret_string = 'safRpB5euNL52PZPTSqrE9gvuFwTC';
// var address = 'rLLzaq61D633b5hhbNXKM9CkrYHboobVv3';
var hash = 'e865bcc63a86ef21585ac8340a7cc8590ed85175a2a718c6fb2bfb2715d13778';
var signature = Message.signHash(hash, secret_string);
assert(REGEX_BASE64.test(signature));
sjcl.random.randomWords = normal_random;
});
});
describe('verifyMessageSignature', function(){
it('should prepend the MAGIC_BYTES, call the HASH_FUNCTION, and then call verifyHashSignature', function(){
var normal_verifyHashSignature = Message.verifyHashSignature;
var data = {
message: 'Hello world!',
signature: 'AAAAGzFa1pYjhssCpDFZgFSnYQ8qCnMkLaZrg0mXZyNQ2NxgMQ8z9U3ngYerxSZCEt3Q4raMIpt03db7jDNGbfmHy8I='
};
var verifyHashSignature_called = false;
Message.verifyHashSignature = function(vhs_data, remote, callback) {
verifyHashSignature_called = true;
assert.deepEqual(vhs_data.hash, Message.HASH_FUNCTION(Message.MAGIC_BYTES + data.message));
assert.strictEqual(vhs_data.signature, data.signature);
callback();
};
Message.verifyMessageSignature(data, {}, function(err){
assert(!err);
});
assert(verifyHashSignature_called);
Message.verifyHashSignature = normal_verifyHashSignature;
});
});
describe('verifyHashSignature', function(){
it('should throw an error if a callback function is not supplied', function(){
var data = {
message: 'Hello world!',
hash: '861844d6704e8573fec34d967e20bcfef3d424cf48be04e6dc08f2bd58c729743371015ead891cc3cf1c9d34b49264b510751b1ff9e537937bc46b5d6ff4ecc8',
signature: 'AAAAHOUJQzG/7BO82fGNt1TNE+GGVXKuQQ0N2nTO+iJETE69PiHnaAkkOzovM177OosxbKjpt3KvwuJflgUB2YGvgjk=',
account: 'rKXCummUHnenhYudNb9UoJ4mGBR75vFcgz'
};
Remote.prototype.addServer = function(){};
var test_remote = new Remote({});
assert.throws(function(){
Message.verifyHashSignature(data);
}, /(?=.*callback\ function).*/);
});
it('should respond with an error if the hash is missing or invalid', function(done){
var data = {
message: 'Hello world!',
signature: 'AAAAHOUJQzG/7BO82fGNt1TNE+GGVXKuQQ0N2nTO+iJETE69PiHnaAkkOzovM177OosxbKjpt3KvwuJflgUB2YGvgjk=',
account: 'rKXCummUHnenhYudNb9UoJ4mGBR75vFcgz'
};
Remote.prototype.addServer = function(){};
var test_remote = new Remote({});
test_remote.state = 'online';
Message.verifyHashSignature(data, test_remote, function(err, valid){
assert(/hash/i.test(err.message));
done();
});
});
it('should respond with an error if the account is missing or invalid', function(done){
var data = {
message: 'Hello world!',
hash: '861844d6704e8573fec34d967e20bcfef3d424cf48be04e6dc08f2bd58c729743371015ead891cc3cf1c9d34b49264b510751b1ff9e537937bc46b5d6ff4ecc8',
signature: 'AAAAHOUJQzG/7BO82fGNt1TNE+GGVXKuQQ0N2nTO+iJETE69PiHnaAkkOzovM177OosxbKjpt3KvwuJflgUB2YGvgjk='
};
Remote.prototype.addServer = function(){};
var test_remote = new Remote({});
test_remote.state = 'online';
Message.verifyHashSignature(data, test_remote, function(err, valid){
assert(/account|address/i.test(err.message));
done();
});
});
it('should respond with an error if the signature is missing or invalid', function(done){
var data = {
message: 'Hello world!',
hash: '861844d6704e8573fec34d967e20bcfef3d424cf48be04e6dc08f2bd58c729743371015ead891cc3cf1c9d34b49264b510751b1ff9e537937bc46b5d6ff4ecc8',
account: 'rKXCummUHnenhYudNb9UoJ4mGBR75vFcgz'
};
Remote.prototype.addServer = function(){};
var test_remote = new Remote({});
test_remote.state = 'online';
Message.verifyHashSignature(data, test_remote, function(err, valid){
assert(/signature/i.test(err.message));
done();
});
});
it('should respond true if the signature is valid and corresponds to an active public key for the account', function(done){
var data = {
message: 'Hello world!',
hash: 'e9a82ea40514787918959b1100481500a5d384030f8770575c6a587675025fe212e6623e25643f251666a7b8b23af476c2850a8ea92153de5724db432892c752',
account: 'rKXCummUHnenhYudNb9UoJ4mGBR75vFcgz',
signature: 'AAAAHMIPCQGLgdnpX1Ccv1wHb56H4NggxIM6U08Qkb9mUjN2Vn9pZ3CHvq1yWLBi6NqpW+7kedLnmfu4VG2+y43p4Xs='
};
Remote.prototype.addServer = function(){};
var test_remote = new Remote({});
test_remote.state = 'online';
test_remote.request_account_info = function(account, callback) {
if (account === data.account) {
callback(null, {
"account_data": {
"Account": "rKXCummUHnenhYudNb9UoJ4mGBR75vFcgz",
"Flags": 1114112,
"LedgerEntryType": "AccountRoot",
"RegularKey": "rHq2wyUtLkAad3vURUk33q9gozd97skhSf"
}
});
} else {
callback(new Error('wrong account'));
}
};
Message.verifyHashSignature(data, test_remote, function(err, valid){
assert(!err);
assert(valid);
done();
});
});
it('should respond false if a key can be recovered from the signature but it does not correspond to an active public key', function(done){
// Signature created by disabled master key
var data = {
message: 'Hello world!',
hash: 'e9a82ea40514787918959b1100481500a5d384030f8770575c6a587675025fe212e6623e25643f251666a7b8b23af476c2850a8ea92153de5724db432892c752',
account: 'rKXCummUHnenhYudNb9UoJ4mGBR75vFcgz',
signature: 'AAAAG+dB/rAjZ5m8eQ/opcqQOJsFbKxOu9jq9KrOAlNO4OdcBDXyCBlkZqS9Xr8oZI2uh0boVsgYOS3pOLJz+Dh3Otk='
};
Remote.prototype.addServer = function(){};
var test_remote = new Remote({});
test_remote.state = 'online';
test_remote.request_account_info = function(account, callback) {
if (account === data.account) {
callback(null, {
"account_data": {
"Account": "rKXCummUHnenhYudNb9UoJ4mGBR75vFcgz",
"Flags": 1114112,
"LedgerEntryType": "AccountRoot",
"RegularKey": "rHq2wyUtLkAad3vURUk33q9gozd97skhSf"
}
});
} else {
callback(new Error('wrong account'));
}
};
Message.verifyHashSignature(data, test_remote, function(err, valid){
assert(!err);
assert(!valid);
done();
});
});
});
});