Add Insight save and register

This commit is contained in:
Esteban Ordano 2014-10-22 00:14:48 -03:00 committed by Matias Alejo Garcia
commit 5d980af518
9 changed files with 168 additions and 43 deletions

15
.jshint Normal file
View file

@ -0,0 +1,15 @@
{
"camelcase": true,
"curly": true,
"eqeqeq": true,
"freeze": true,
"indent": 2,
"newcap": true,
"quotmark": "single",
"maxdepth": 3,
"maxstatements": 15,
"maxlen": 80,
"eqnull": true,
"funcscope": true,
"node": true
}

View file

@ -3,15 +3,7 @@
angular.module('copayApp.controllers').controller('HomeController', function($scope, $rootScope, $location, notification, controllerUtils, pluginManager) {
controllerUtils.redirIfLogged();
$scope.retreiving = true;
copay.Identity.anyProfile({
pluginManager: pluginManager,
}, function(any) {
$scope.retreiving = false;
if (!any)
$location.path('/createProfile');
});
$scope.retreiving = false;
$scope.openProfile = function(form) {
if (form && form.$invalid) {

View file

@ -4,6 +4,9 @@ var preconditions = require('preconditions').singleton();
var _ = require('underscore');
var log = require('../log');
var querystring = require('querystring');
var request = require('request');
var cryptoUtil = require('../util/crypto');
var version = require('../../version').version;
var TxProposals = require('./TxProposals');
var PublicKeyRing = require('./PublicKeyRing');
@ -27,6 +30,8 @@ var Storage = module.exports.Storage = require('./Storage');
function Identity(password, opts) {
preconditions.checkArgument(opts);
opts = _.extend({}, opts);
this.request = opts.request || request;
this.storage = Identity._getStorage(opts, password);
this.networkOpts = {
'livenet': opts.network.livenet,
@ -37,6 +42,7 @@ function Identity(password, opts) {
'testnet': opts.network.testnet,
};
this.insightSaveOpts = opts.insightSave || {};
this.walletDefaults = opts.walletDefaults || {};
this.version = opts.version || version;
@ -50,8 +56,6 @@ Identity._createProfile = function(email, password, storage, cb) {
Profile.create(email, password, storage, cb);
};
Identity._newStorage = function(opts) {
return new Storage(opts);
};
@ -82,8 +86,6 @@ Identity._newAsync = function(opts) {
return new Async(opts);
};
Identity._getStorage = function(opts, password) {
var storageOpts = {};
@ -150,10 +152,16 @@ Identity.create = function(email, password, opts, cb) {
requiredCopayers: 1,
totalCopayers: 1,
password: password,
name: 'general',
name: 'general'
});
iden.createWallet(wopts, function(err, w) {
return cb(null, iden, w);
if (err) {
return cb(err);
}
iden.registerOnInsight(iden.insightSaveOpts, function(error) {
// Ignore error
return cb(null, iden, w);
});
});
});
};
@ -186,7 +194,12 @@ Identity.open = function(email, password, opts, cb) {
var iden = new Identity(password, opts);
Identity._openProfile(email, password, iden.storage, function(err, profile) {
if (err) return cb(err);
if (err) {
if (err.message && err.message.indexOf('PNOTFOUND') !== -1) {
return Identity.readFromInsight(email, password, opts, cb);
}
return cb(err);
}
iden.profile = profile;
var wids = _.pluck(iden.listWallets(), 'id');
@ -335,15 +348,14 @@ Identity.prototype.closeWallet = function(wid, cb) {
});
};
/**
* @desc Return a base64 encrypted version of the wallet
* @return {string} base64 encoded string
*/
Identity.import = function(str, password, opts, cb) {
Identity.importFromJson = function(str, password, opts, cb) {
preconditions.checkArgument(str);
var json = JSON.parse(str);
var json;
try {
json = JSON.parse(str);
} catch (e) {
return cb('Unable to retrieve json from string', str);
}
if (!_.isNumber(json.iterations))
return cb('BADSTR: Missing iterations');
@ -351,25 +363,34 @@ Identity.import = function(str, password, opts, cb) {
if (!json.profile)
return cb('BADSTR: Missing profile');
var iden = new Identity(password, opts);
iden.profile = Profile.import(json.profile, password, iden.storage);
json.wallets = json.wallets || {};
var walletInfoBackup = iden.profile.walletInfos;
iden.profile.walletInfos = {};
var l = json.wallets.length,
var l = _.size(json.wallets),
i = 0;
if (!l)
return cb(null, iden);
_.each(this.wallets, function(wstr) {
iden.importWallet(wstr, password, skipFields, function(err, w) {
_.each(json.wallets, function(wstr) {
iden.importWallet(wstr, password, opts.skipFields, function(err, w) {
if (err) return cb(err);
log.debug('Wallet ' + w.getId() + ' imported');
if (++i == l)
iden.store(cb);
if (++i == l) {
iden.profile.walletInfos = walletInfoBackup;
iden.store(opts, function(err) {
if (err) {
return cb(err);
} else {
return cb(null, iden, iden.openWallets[0]);
}
});
}
})
});
};
@ -378,7 +399,7 @@ Identity.import = function(str, password, opts, cb) {
* @desc Return JSON with base64 encoded strings for wallets and profile, and iteration count
* @return {string} Stringify JSON
*/
Identity.prototype.export = function() {
Identity.prototype.exportAsJson = function() {
var ret = {};
ret.iterations = this.storage.iterations;
ret.profile = this.profile.export();
@ -470,8 +491,59 @@ Identity.prototype.createWallet = function(opts, cb) {
this.addWallet(w, function(err) {
if (err) return cb(err);
self.openWallets.push(w);
w.netStart();
return cb(err, w);
self.triggerInsightSave(self.insightSaveOpts, function(error) {
// Ignore error
w.netStart();
return cb(null, w);
});
});
};
Identity.readFromInsight = function(email, password, opts, callback) {
var key = cryptoUtil.kdf(password, email);
var secret = cryptoUtil.kdf(key, password);
var useRequest = opts.request || request;
var encodedEmail = encodeURIComponent(email);
var retrieveUrl = opts.retrieveUrl || 'http://localhost:3001/api/email/retrieve/' + encodedEmail;
useRequest.get(retrieveUrl + '?' + querystring.encode({secret: secret}),
function(err, response, body) {
if (err) {
return callback('Connection error');
}
if (response.statusCode !== 200) {
return callback('Connection error');
}
var decryptedJson = cryptoUtil.decrypt(key, body);
if (!decryptedJson) {
return callback('Internal Error');
}
return Identity.importFromJson(decryptedJson, password, opts, callback);
}
);
};
Identity.prototype.triggerInsightSave = Identity.prototype.registerOnInsight = function(opts, callback) {
var password = this.profile.password;
var key = cryptoUtil.kdf(password, this.profile.email);
var secret = cryptoUtil.kdf(key, password);
var exportData = this.exportAsJson
var record = cryptoUtil.encrypt(key, this.exportAsJson());
var registerUrl = opts.registerUrl || 'http://localhost:3001/api/email/register';
this.request.post({
url: registerUrl,
body: querystring.encode({
email: this.profile.email,
secret: secret,
record: record
})
}, function(err, response, body) {
if (err) {
return callback('Connection error');
}
if (response.statusCode !== 200) {
return callback('Unable to store data on insight');
}
return callback();
});
};
@ -486,11 +558,8 @@ Identity.prototype.addWallet = function(wallet, cb) {
self.profile.addWallet(wallet.getId(), {
name: wallet.name
}, function(err) {
if (err) return cb(err);
wallet.store(function(err) {
return cb(err);
});
cb();
});
};

View file

@ -10,6 +10,7 @@ function Profile(info, storage) {
preconditions.checkArgument(storage);
preconditions.checkArgument(storage.setPassword, 'bad storage');
this.password = info.password;
this.hash = info.hash;
this.email = info.email;
this.extra = info.extra || {};
@ -19,8 +20,8 @@ function Profile(info, storage) {
this.storage = storage;
};
Profile.hash = function(email, password) {
return bitcore.util.sha256ripe160(email + password).toString('hex');
Profile.hash = function(email) {
return bitcore.util.sha256ripe160(email).toString('hex');
};
Profile.key = function(hash) {
@ -36,6 +37,7 @@ Profile.create = function(email, password, storage, cb) {
var p = new Profile({
email: email,
password: password,
hash: Profile.hash(email, password),
}, storage);
p.store({}, function(err) {
@ -67,7 +69,7 @@ Profile.open = function(email, password, storage, cb) {
};
Profile.prototype.toObj = function() {
return _.clone(_.pick(this, 'hash', 'email', 'extra', 'walletInfos'));
return _.clone(_.pick(this, 'password', 'hash', 'email', 'extra', 'walletInfos'));
};

View file

@ -1,6 +1,6 @@
'use strict';
angular.module('copayApp.services').factory('pluginManager', function(angularLoad){
angular.module('copayApp.services').factory('pluginManager', function(angularLoad) {
var pm = new copay.PluginManager(config);
var scripts = pm.scripts;

44
js/util/crypto.js Normal file
View file

@ -0,0 +1,44 @@
/**
* Small module for some helpers that wrap CryptoJS with some good practices.
*/
var sjcl = require('sjcl');
var log = require('../log.js');
var _ = require('underscore');
var SALT = 'copay random string NWRlNmExMTE4NzIzYzYyYWMwODU1MTdkN';
var SEPARATOR = '&';
var defaultOptions = {
adata: '',
cipher: 'aes',
ks: 128,
iter: 2000,
mode: 'ccm',
ts: 64
};
module.exports = {
kdf: function(value1, value2) {
return sjcl.codec.base64.fromBits(sjcl.misc.pbkdf2(value1 + value2, SALT));
},
/**
* Encrypts symmetrically using a passphrase
*/
encrypt: function(key, message) {
return sjcl.encrypt(key, message);
},
/**
* Decrypts symmetrically using a passphrase
*/
decrypt: function(key, cypher) {
var output = {};
try {
return sjcl.decrypt(key, cypher);
} catch (e) {
log.error('Decryption failed due to error: ' + e.message);
return null;
}
}
};

View file

@ -25,6 +25,7 @@
"inherits": "^2.0.1",
"optimist": "^0.6.1",
"preconditions": "^1.0.7",
"querystring": "^0.2.0",
"request": "^2.40.0",
"underscore": "^1.7.0"
},

View file

@ -7,7 +7,6 @@ function LocalStorage() {
LocalStorage.prototype.init = function() {
};
LocalStorage.prototype.getItem = function(k,cb) {
return cb(localStorage.getItem(k));
};
@ -37,5 +36,4 @@ LocalStorage.prototype.allKeys = function(cb) {
return cb(ret);
};
module.exports = LocalStorage;

View file

@ -46,6 +46,7 @@ var createBundle = function(opts) {
expose: 'request'
});
b.require('underscore');
b.require('querystring');
b.require('assert');
b.require('preconditions');
@ -86,6 +87,9 @@ var createBundle = function(opts) {
b.require('./js/models/PluginManager', {
expose: '../js/models/PluginManager'
});
b.require('./js/util/crypto', {
expose: '../util/crypto'
});
if (!opts.disablePlugins) {
b.require('./plugins/GoogleDrive', {