diff --git a/js/controllers/home.js b/js/controllers/home.js index c459cb545..b3d804f85 100644 --- a/js/controllers/home.js +++ b/js/controllers/home.js @@ -15,7 +15,9 @@ angular.module('copayApp.controllers').controller('HomeController', function($sc $rootScope.fromEmailConfirmation = false; } Compatibility.check($scope); - $scope.hasPin = pinService.check(); + pinService.check(function(err, value) { + $scope.hasPin = value; + }); }; Object.defineProperty($scope, @@ -23,24 +25,21 @@ angular.module('copayApp.controllers').controller('HomeController', function($sc get: function() { return this._pin; }, - set: function(newValue) { - console.log('[home.js:26]',newValue, this._pin); //TODO - this._pin = newValue; - if (newValue && newValue.length == 4) { - console.log('[home.js:26] INGRESANDO AUTOMATICAMENTE',newValue); //TODO - $scope.openPin(newValue); - } - if (!newValue) { - $scope.error = null; - } - }, - enumerable: true, - configurable: true + set: function(newValue) { + this._pin = newValue; + if (newValue && newValue.length == 4) { + $scope.openPin(newValue); + } + if (!newValue) { + $scope.error = null; + } + }, + enumerable: true, + configurable: true }); $scope.done = function() { - $scope.hasPin = pinService.check(); $rootScope.starting = false; $rootScope.$digest(); }; @@ -49,8 +48,8 @@ angular.module('copayApp.controllers').controller('HomeController', function($sc $scope.$on("$destroy", function() { var iden = $rootScope.iden; if (iden) { - iden.removeListener('newWallet', $scope.done ); - iden.removeListener('noWallets', $scope.done ); + iden.removeListener('newWallet', $scope.done); + iden.removeListener('noWallets', $scope.done); } }); @@ -60,25 +59,26 @@ angular.module('copayApp.controllers').controller('HomeController', function($sc $scope.error = 'Please enter the required fields'; return; } - $scope.openPin(pin); + $scope.openPin(pin); }; $scope.openPin = function(pin) { - var credentials = pinService.get(parseInt(pin)); - if (!credentials) { - $scope.error = 'Wrong PIN'; - return; - } - - $rootScope.starting = true; - $scope.open(credentials.email, credentials.password); + var credentials = pinService.get(pin, function(err, credentials) { + if (err || !credentials) { + $scope.error = 'Wrong PIN'; + return; + } + $rootScope.starting = true; + $scope.open(credentials.email, credentials.password); + }); }; $scope.createPin = function(form) { - if (form) { - pinService.save(form.repeatpin.$modelValue, $scope.email, $scope.password); - } - $scope.open($scope.email, $scope.password); + if (!form) return; + + pinService.save(form.repeatpin.$modelValue, $scope.email, $scope.password, function(err) { + $scope.open($scope.email, $scope.password); + }); }; $scope.openWithCredentials = function(form) { @@ -96,6 +96,15 @@ angular.module('copayApp.controllers').controller('HomeController', function($sc $scope.open(form.email.$modelValue, form.password.$modelValue); }; + + $scope.pinLogout = function() { + pinService.clear(function() { + copay.logger.debug('PIN erased'); + $scope.hasPin = null; + $scope.$digest(); + }); + }; + $scope.open = function(email, password) { $rootScope.starting = true; identityService.open(email, password, function(err, iden) { @@ -104,7 +113,9 @@ angular.module('copayApp.controllers').controller('HomeController', function($sc copay.logger.warn(err); if ((err.toString() || '').match('PNOTFOUND')) { $scope.error = 'Invalid email or password'; - pinService.clear(); + pinService.clear(function() { + copay.logger.debug('PIN erased'); + }); } else if ((err.toString() || '').match('Connection')) { $scope.error = 'Could not connect to Insight Server'; } else if ((err.toString() || '').match('Unable')) { diff --git a/js/services/pinService.js b/js/services/pinService.js index b6d30192c..a104d61fc 100644 --- a/js/services/pinService.js +++ b/js/services/pinService.js @@ -1,38 +1,52 @@ 'use strict'; angular.module('copayApp.services') - .factory('pinService', function($rootScope) { - var root = {}; - var storage = { - pinData: { - pin: 1234, - credentials: { - email: '4@queparece', - password: '1', - } - } - }; - root.check = function() { - return storage.pinData ? true : false; - }; - root.get = function(pin) { - var storedPin = storage.pinData.pin; - if (storedPin !== pin) - return; + .factory('pinService', function($rootScope, localstorageService) { - return storage.pinData.credentials; + var KEY = 'pinDATA'; + var SALT = '4gllotIKguqi0EkIslC0'; + var ITER = 2000; + + var ls = localstorageService; + var root = {}; + + root.check = function(cb) { + ls.getItem(KEY, function(err, value) { + return cb(err, value ? true : false); + }); }; - root.save = function(pin, email, password) { - storage.pinData = { - pin: pin, - credentials: { - email: email, - password: password + + root.get = function(pin, cb) { + ls.getItem(KEY, function(err, value) { + if (!value) return cb(null); + var enc = value; + var data = copay.crypto.decrypt('' + parseInt(pin), enc); + var err = new Error('Could not decrypt'); + if (data) { + var obj; + try { + obj = JSON.parse(data); + err = null; + } catch (e) {}; } + return cb(err, obj); + }); + }; + + root.save = function(pin, email, password, cb) { + var credentials = { + email: email, + password: password, }; + var enc = copay.crypto.encrypt('' + parseInt(pin), credentials, SALT, ITER); + ls.setItem(KEY, enc, function(err) { + return cb(err); + }); }; - root.clear = function(){ - delete storage['pinData']; + + root.clear = function(cb) { + ls.removeItem(KEY, cb); }; + return root; }); diff --git a/js/util/crypto.js b/js/util/crypto.js index cb438ea18..72679f18f 100644 --- a/js/util/crypto.js +++ b/js/util/crypto.js @@ -59,22 +59,22 @@ module.exports = { /** * Encrypts symmetrically using a passphrase */ - encrypt: function(key, message) { + encrypt: function(key, message, salt, iter) { if (!_.isString(message)) { message = JSON.stringify(message); } - sjcl.json.defaults.salt = defaultSalt; - sjcl.json.defaults.iter = defaultIterations; + sjcl.json.defaults.salt = salt || defaultSalt; + sjcl.json.defaults.iter = iter || defaultIterations; return sjcl.encrypt(key, message); }, /** * Decrypts symmetrically using a passphrase */ - decrypt: function(key, cyphertext) { + decrypt: function(key, sjclEncryptedJson) { var output = {}; try { - return sjcl.decrypt(key, cyphertext); + return sjcl.decrypt(key, sjclEncryptedJson); } catch (e) { log.info('Decryption failed due to error: ' + e.message); return null; diff --git a/test/unit/services/servicesSpec.js b/test/unit/services/servicesSpec.js index f468f5917..a448187ce 100644 --- a/test/unit/services/servicesSpec.js +++ b/test/unit/services/servicesSpec.js @@ -102,6 +102,48 @@ describe("Angular services", function() { })); }); + describe("Unit: identityService Service", function() { + it('should contain a identityService service', inject(function(identityService) { + expect(identityService).not.to.equal(null); + })); + }); + + describe("Unit: pinService", function() { + it('should contain a pinService service', inject(function(pinService) { + expect(pinService).not.to.equal(null); + })); + it('should be able to check -> save -> get -> clear -> check', function(done) { + inject(function(pinService) { + pinService.save('123', 'user', 'pass', function(err) { + pinService.check(function(err, value) { + should.not.exist(err); + value.should.equal(true); + pinService.get('123', function(err, data) { + should.not.exist(err); + data.email.should.be.equal('user'); + data.password.should.be.equal('pass'); + pinService.clear(function(err) { + should.not.exist(err); + pinService.check(function(err, value) { + should.not.exist(err); + value.should.equal(false); + done(); + }); + }); + }); + }); + }) + }) + }); + }); + + describe("Unit: localstorageService", function() { + it('should contain a localstorageService service', inject(function(localstorageService) { + expect(localstorageService).not.to.equal(null); + })); + }); + + describe("Unit: Backup Service", function() { it('should contain a backup service', inject(function(backupService) { expect(backupService).not.to.equal(null);