Skip to content

Commit

Permalink
Merge pull request #91 from shekenahglory/develop
Browse files Browse the repository at this point in the history
Necessary updates for vault client integration in ripple trade
  • Loading branch information
wltsmrz committed Jun 5, 2014
2 parents 838180a + 7af4a37 commit 44a9724
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 121 deletions.
157 changes: 104 additions & 53 deletions src/js/ripple/blob.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ var crypt = require('./crypt').Crypt;
var SignedRequest = require('./signedrequest').SignedRequest;
var request = require('superagent');
var extend = require("extend");
var async = require("async");

var BlobClient = {};

Expand Down Expand Up @@ -56,7 +57,7 @@ var entityTypes = [
'individual',
'organization',
'corporation'
]
];

var addressFields = [
'contact',
Expand Down Expand Up @@ -274,6 +275,10 @@ BlobObj.prototype.decryptBlobCrypt = function(secret) {
*/

BlobObj.prototype.set = function(pointer, value, fn) {
if (pointer == "/" + identityRoot && this.data[identityRoot]) {
return fn(new Error('Cannot overwrite Identity Vault'));
}

this.applyUpdate('set', pointer, [value]);
this.postUpdate('set', pointer, [value], fn);
};
Expand All @@ -283,6 +288,10 @@ BlobObj.prototype.set = function(pointer, value, fn) {
*/

BlobObj.prototype.unset = function(pointer, fn) {
if (pointer == "/" + identityRoot) {
return fn(new Error('Cannot remove Identity Vault'));
}

this.applyUpdate('unset', pointer, []);
this.postUpdate('unset', pointer, [], fn);
};
Expand All @@ -300,7 +309,7 @@ BlobObj.prototype.extend = function(pointer, value, fn) {
* Prepend blob array
*/

BlobObj.prototype.unshift = function(pointer, value, fn) {
BlobObj.prototype.unshift = function(pointer, value, fn) {
this.applyUpdate('unshift', pointer, [value]);
this.postUpdate('unshift', pointer, [value], fn);
};
Expand Down Expand Up @@ -555,19 +564,8 @@ function normalizeSubcommands(subcommands, compress) {
*/

var Identity = function (blob) {
var self = this;
self.blob = blob;

//make sure the identity setup is valid
self.validate = function(fn) {
if (!self.blob) return fn(new Error("Identity must be associated with a blob"));
else if (!self.blob.data) return fn(new Error("Invalid Blob"));
else if (!self.blob.data[identityRoot]) {
self.blob.set(identityRoot, {}, function(err, res){
if (err) return fn(err);
else return fn(null, true);
});
} else return fn(null, true);
this._getBlob = function() {
return blob;
};
};

Expand All @@ -578,10 +576,11 @@ var Identity = function (blob) {
*/

Identity.prototype.getFullAddress = function (key) {
if (!this.blob ||
!this.blob.data ||
!this.blob.data[identityRoot] ||
!this.blob.data[identityRoot].address) {
var blob = this._getBlob();
if (!blob ||
!blob.data ||
!blob.data[identityRoot] ||
!blob.data[identityRoot].address) {
return "";
}

Expand All @@ -606,12 +605,12 @@ Identity.prototype.getFullAddress = function (key) {
*/

Identity.prototype.getAll = function (key) {

if (!this.blob || !this.blob.data || !this.blob.data[identityRoot]) {
var blob = this._getBlob();
if (!blob || !blob.data || !blob.data[identityRoot]) {
return {};
}

var result = {}, identity = this.blob.data[identityRoot];
var result = {}, identity = blob.data[identityRoot];
for (var i in identity) {
result[i] = this.get(i, key);
}
Expand All @@ -627,11 +626,12 @@ Identity.prototype.getAll = function (key) {
*/

Identity.prototype.get = function (pointer, key) {
if (!this.blob || !this.blob.data || !this.blob.data[identityRoot]) {
var blob = this._getBlob();
if (!blob || !blob.data || !blob.data[identityRoot]) {
return null;
}

var data = this.blob.data[identityRoot][pointer];
var data = blob.data[identityRoot][pointer];
if (data && data.encrypted) {
return decrypt(key, data);

Expand Down Expand Up @@ -674,7 +674,7 @@ Identity.prototype.get = function (pointer, key) {
*/

Identity.prototype.set = function (pointer, key, value, fn) {
var self = this;
var self = this, blob = this._getBlob();

if (!fn) fn = function(){ };

Expand Down Expand Up @@ -718,10 +718,24 @@ Identity.prototype.set = function (pointer, key, value, fn) {
return fn(new Error("invalid entity type"));
}
}

this.validate(function(err, res){
if (err) return fn(err);

async.waterfall([ validate, set ], fn);

//make sure the identity setup is valid
function validate (callback) {

if (!blob) return fn(new Error("Identity must be associated with a blob"));
else if (!blob.data) return fn(new Error("Invalid Blob"));
else if (!blob.data[identityRoot]) {
blob.set("/" + identityRoot, {}, function(err, res){
if (err) return callback (err);
else return callback (null);
});
} else return callback (null);
};

function set (callback) {

//NOTE: currently we will overwrite if it already exists
//the other option would be to require decrypting with the
//existing key as a form of authorization
Expand All @@ -736,8 +750,8 @@ Identity.prototype.set = function (pointer, key, value, fn) {
value : key ? encrypt(key, value) : value
};

self.blob.extend("/" + identityRoot, data, fn);
});
self._getBlob().extend("/" + identityRoot, data, callback);
};

function encrypt (key, value) {
if (typeof value === 'object') value = JSON.stringify(value);
Expand Down Expand Up @@ -765,7 +779,7 @@ Identity.prototype.unset = function (pointer, key, fn) {
return fn(data.error);
}

this.blob.unset("/" + identityRoot+"/" + pointer, fn);
this._getBlob().unset("/" + identityRoot+"/" + pointer, fn);
};

/***** blob client methods ****/
Expand Down Expand Up @@ -815,16 +829,52 @@ BlobClient.get = function (url, id, crypt, fn) {
BlobClient.verify = function(url, username, token, fn) {
url += '/v1/user/' + username + '/verify/' + token;
request.get(url, function(err, resp){
if (err) {
fn(err);
if (err) {
fn(new Error("Failed to verify the account - XHR error"));
} else if (resp.body && resp.body.result === 'success') {
fn(null, data);
fn(null, resp.body);
} else {
fn(new Error('Failed to verify the account'));
}
});
};

/**
* ResendEmail
* resend verification email
*/
BlobClient.resendEmail = function (opts, fn) {
var config = {
method : 'POST',
url : opts.url + '/v1/user/email',
data : {
blob_id : opts.id,
username : opts.username,
email : opts.email,
hostlink : opts.activateLink
}
};

var signedRequest = new SignedRequest(config);
var signed = signedRequest.signAsymmetric(opts.masterkey, opts.account_id, opts.id);

request.post(signed.url)
.send(signed.data)
.end(function(err, resp) {
if (err) {
console.log("blob: could not resend the token:", err);
fn(new Error("Failed to resend the token"));
} else if (resp.body && resp.body.result === 'success') {
fn(null, resp.body);
} else if (resp.body && resp.body.result === 'error') {
console.log("blob: could not resend the token:", resp.body.message);
fn(new Error("Failed to resend the token"));
} else {
fn(new Error("Failed to resend the token"));
}
});
};

/**
* Create a blob object
*
Expand All @@ -845,11 +895,11 @@ BlobClient.create = function(options, fn) {
blob.revision = 0;

blob.data = {
auth_secret: crypt.createSecret(8),
account_id: crypt.getAddress(options.masterkey),
email: options.email,
contacts: [],
created: (new Date()).toJSON()
auth_secret : crypt.createSecret(8),
account_id : crypt.getAddress(options.masterkey),
email : options.email,
contacts : [],
created : (new Date()).toJSON()
};

blob.encrypted_secret = blob.encryptSecret(options.unlock, options.masterkey);
Expand All @@ -861,32 +911,33 @@ BlobClient.create = function(options, fn) {

//post to the blob vault to create
var config = {
method: 'POST',
url: options.url + '/v1/user',
data: {
blob_id: options.id,
username: options.username,
address: blob.data.account_id,
auth_secret: blob.data.auth_secret,
data: blob.encrypt(),
email: options.email,
hostlink: options.activateLink,
encrypted_blobdecrypt_key: blob.encryptBlobCrypt(options.masterkey, options.crypt),
encrypted_secret: blob.encrypted_secret
method : 'POST',
url : options.url + '/v1/user',
data : {
blob_id : options.id,
username : options.username,
address : blob.data.account_id,
auth_secret : blob.data.auth_secret,
data : blob.encrypt(),
email : options.email,
hostlink : options.activateLink,
encrypted_blobdecrypt_key : blob.encryptBlobCrypt(options.masterkey, options.crypt),
encrypted_secret : blob.encrypted_secret
}
};

var signedRequest = new SignedRequest(config);

var signed = signedRequest.signAsymmetric(options.masterkey, blob.data.account_id, options.id);

request.post(signed)
request.post(signed.url)
.send(signed.data)
.end(function(err, resp) {
if (err) {
fn(err);
} else if (resp.body && resp.body.result === 'success') {
fn(null, blob,resp.body);
} else if (resp.body && resp.body.result === 'error') {
fn(new Error(resp.body.message));
} else {
fn(new Error('Could not create blob'));
}
Expand Down
57 changes: 4 additions & 53 deletions src/js/ripple/crypt.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
var sjcl = require('./utils').sjcl;
var base = require('./base').Base;
var Seed = require('./seed').Seed;
var UInt160 = require('./uint160').UInt160;
var UInt256 = require('./uint256').UInt256;
var request = require('superagent');
Expand Down Expand Up @@ -143,56 +144,7 @@ Crypt.derive = function(opts, purpose, username, secret, fn) {
* Imported from ripple-client
*/

Crypt.RippleAddress = (function() {

function append_int(a, i) {
return [].concat(a, i >> 24, (i >> 16) & 0xff, (i >> 8) & 0xff, i & 0xff);
}

function firstHalfOfSHA512(bytes) {
return sjcl.bitArray.bitSlice(
sjcl.hash.sha512.hash(sjcl.codec.bytes.toBits(bytes)),
0, 256
);
};

function SHA256_RIPEMD160(bits) {
return sjcl.hash.ripemd160.hash(sjcl.hash.sha256.hash(bits));
};

return function(seed) {
this.seed = base.decode_check(33, seed);

if (!this.seed) {
throw new Error('Invalid seed.');
}

this.getAddress = function(seq) {
seq = seq || 0;

var private_gen, public_gen, i = 0;

do {
private_gen = sjcl.bn.fromBits(firstHalfOfSHA512(append_int(this.seed, i)));
i++;
} while (!sjcl.ecc.curves.c256.r.greaterEquals(private_gen));

public_gen = sjcl.ecc.curves.c256.G.mult(private_gen);

var sec;
i = 0;

do {
sec = sjcl.bn.fromBits(firstHalfOfSHA512(append_int(append_int(public_gen.toBytesCompressed(), seq), i)));
i++;
} while (!sjcl.ecc.curves.c256.r.greaterEquals(sec));

var pubKey = sjcl.ecc.curves.c256.G.mult(sec).toJac().add(public_gen).toAffine();

return base.encode_check(0, sjcl.codec.bytes.fromBits(SHA256_RIPEMD160(sjcl.codec.bytes.toBits(pubKey.toBytesCompressed()))));
};
};
})();

/**
* Encrypt data
Expand Down Expand Up @@ -255,7 +207,7 @@ Crypt.isValidAddress = function (address) {
};

/**
* Validate a ripple address
* Create an encryption key
*
* @param {integer} nWords - number of words
*/
Expand All @@ -280,7 +232,7 @@ Crypt.createMaster = function () {
*/

Crypt.getAddress = function (masterkey) {
return new Crypt.RippleAddress(masterkey).getAddress();
return Seed.from_json(masterkey).get_key().get_address().to_json();
};

/**
Expand All @@ -293,7 +245,7 @@ Crypt.getAddress = function (masterkey) {
Crypt.hashSha512 = function (data) {
// XXX Should return a UInt512
return sjcl.codec.hex.fromBits(sjcl.hash.sha512.hash(data));
}
};

/**
* Hash data using SHA-512 and return the first 256 bits.
Expand Down Expand Up @@ -358,5 +310,4 @@ Crypt.base64UrlToBase64 = function(encodedData) {
return encodedData;
};


exports.Crypt = Crypt;

0 comments on commit 44a9724

Please sign in to comment.