[FIX] Handling public key validation for unfunded accounts

This commit is contained in:
Evan Schwartz
2014-05-01 17:22:20 -07:00
parent 13a6a2c335
commit a2b07d5edd
4 changed files with 109 additions and 27 deletions

View File

@@ -170,7 +170,12 @@ Message.verifyHashSignature = function(data, remote, callback) {
} catch (err) {
return async_callback(err);
}
async_callback(null, public_key);
if (public_key) {
async_callback(null, public_key);
} else {
async_callback(new Error('Could not recover public key from signature'));
}
};

View File

@@ -19,27 +19,6 @@ function PubKeyValidator(remote) {
throw(new Error('Must instantiate the PubKeyValidator with a ripple-lib Remote'));
}
// Convert hex string to UInt160
self._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'));
}
};
}
/**
@@ -60,16 +39,37 @@ PubKeyValidator.prototype.validate = function(address, public_key, callback) {
var public_key_as_uint160;
try {
public_key_as_uint160 = self._parsePublicKey(public_key);
} catch (e) {
return callback(e);
} catch (err) {
return callback(err);
}
function getAccountInfo(async_callback) {
self._remote.account(address).getInfo(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
@@ -101,4 +101,39 @@ PubKeyValidator.prototype.validate = function(address, public_key, 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

@@ -70,8 +70,6 @@ sjcl.ecc.ecdsa.secretKey.prototype.signWithRecoverablePublicKey = function(hash,
*/
sjcl.ecc.ecdsa.publicKey.recoverFromSignature = function(hash, signature, curve) {
var self = this;
if (!signature || signature instanceof sjcl.ecc.curve) {
throw new sjcl.exception.invalid('must supply hash and signature to recover public key');
}