mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-12-01 09:35:48 +00:00
[FIX] Handling public key validation for unfunded accounts
This commit is contained in:
@@ -170,7 +170,12 @@ Message.verifyHashSignature = function(data, remote, callback) {
|
||||
} catch (err) {
|
||||
return async_callback(err);
|
||||
}
|
||||
|
||||
if (public_key) {
|
||||
async_callback(null, public_key);
|
||||
} else {
|
||||
async_callback(new Error('Could not recover public key from signature'));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@ describe('PubKeyValidator', function(){
|
||||
assert('rLpq5RcRzA8FU1yUqEPW4xfsdwon7casuM' === pkv._parsePublicKey('03BFA879C00D58CF55F2B5975FF9B5293008FF49BEFB3EE6BEE2814247BF561A23'));
|
||||
|
||||
assert('rP4yWwjoDGF2iZSBdAQAgpC449YDezEbT1' === pkv._parsePublicKey('02DF0AB18930B6410CA9F55CB37541F1FED891B8EDF8AB1D01D8F23018A4B204A7'));
|
||||
|
||||
assert('rLdfp6eoR948KVxfn6EpaaNTKwfwXhzSeQ' === pkv._parsePublicKey('0310C451A40CAFFD39D6B8A3BD61BF65BCA55246E9DABC3170EBE431D30655B61F'));
|
||||
});
|
||||
|
||||
});
|
||||
@@ -153,5 +155,47 @@ 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) {
|
||||
if (address === 'rLdfp6eoR948KVxfn6EpaaNTKwfwXhzSeQ') {
|
||||
callback({ error: 'remoteError',
|
||||
error_message: 'Remote reported an error.',
|
||||
remote:
|
||||
{ account: 'rLdfp6eoR948KVxfn6EpaaNTKwfwXhzSeQ',
|
||||
error: 'actNotFound',
|
||||
error_code: 15,
|
||||
error_message: 'Account not found.',
|
||||
id: 3,
|
||||
ledger_current_index: 6391106,
|
||||
request:
|
||||
{ account: 'rLdfp6eoR948KVxfn6EpaaNTKwfwXhzSeQ',
|
||||
command: 'account_info',
|
||||
id: 3,
|
||||
ident: 'rLdfp6eoR948KVxfn6EpaaNTKwfwXhzSeQ' },
|
||||
status: 'error',
|
||||
type: 'response' },
|
||||
result: 'remoteError',
|
||||
engine_result: 'remoteError',
|
||||
result_message: 'Remote reported an error.',
|
||||
engine_result_message: 'Remote reported an error.',
|
||||
message: 'Remote reported an error.'
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
pkv.validate('rLdfp6eoR948KVxfn6EpaaNTKwfwXhzSeQ', '0310C451A40CAFFD39D6B8A3BD61BF65BCA55246E9DABC3170EBE431D30655B61F', function(err, is_valid){
|
||||
assert(!err);
|
||||
assert(is_valid);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
Reference in New Issue
Block a user