[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;