From 328ec337e1fa9cb5384d4c95cff69f4b46752306 Mon Sep 17 00:00:00 2001 From: JDonadio Date: Thu, 20 Apr 2017 12:59:15 -0300 Subject: [PATCH 1/4] request PIN to disable it - add disabled options --- src/js/controllers/lockSetup.js | 41 +++++++++++++++++++++++++-------- www/views/lockSetup.html | 4 ++-- 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/src/js/controllers/lockSetup.js b/src/js/controllers/lockSetup.js index b9ad3a431..bce070ae9 100644 --- a/src/js/controllers/lockSetup.js +++ b/src/js/controllers/lockSetup.js @@ -12,6 +12,7 @@ angular.module('copayApp.controllers').controller('lockSetupController', functio method: 'pin', label: gettextCatalog.getString('Lock by PIN'), needsBackup: null, + disabled: null, }, ]; @@ -20,15 +21,11 @@ angular.module('copayApp.controllers').controller('lockSetupController', functio method: 'fingerprint', label: gettextCatalog.getString('Lock by Fingerprint'), needsBackup: null, + disabled: null, }); } - var config = configService.getSync(); - var method = config.lock && config.lock.method; - if (!method) $scope.currentOption = $scope.options[0]; - else $scope.currentOption = lodash.find($scope.options, { - 'method': method - }); + checkAndSelectOption(); processWallets(); }; @@ -36,6 +33,26 @@ angular.module('copayApp.controllers').controller('lockSetupController', functio init(); }); + function checkAndSelectOption() { + var config = configService.getSync(); + var method = config.lock && config.lock.method; + + if (!method) { + $scope.currentOption = $scope.options[0]; + $scope.options[1].disabled = false; + $scope.options[2].disabled = false; + } else { + if (method == 'fingerprint') $scope.options[1].disabled = true; + if (method == 'pin') $scope.options[2].disabled = true; + $scope.currentOption = lodash.find($scope.options, { + 'method': method + }); + } + $timeout(function() { + $scope.$apply(); + }); + }; + function processWallets() { var wallets = profileService.getWallets(); var singleLivenetWallet = wallets.length == 1 && wallets[0].network == 'livenet' && wallets[0].needsBackup; @@ -73,9 +90,14 @@ angular.module('copayApp.controllers').controller('lockSetupController', functio var config = configService.getSync(); var savedMethod = config.lock && config.lock.method; - if (!selectedMethod) - saveConfig(); - else if (selectedMethod == 'fingerprint') { + if (!selectedMethod) { + if (!savedMethod) return; + if (savedMethod == 'pin') $state.transitionTo('tabs.pin', { + fromSettings: true, + locking: false, + }); + else saveConfig(); + } else if (selectedMethod == 'fingerprint') { if (savedMethod == 'pin') { askForDisablePin(function(disablePin) { if (disablePin) saveConfig('fingerprint'); @@ -116,6 +138,7 @@ angular.module('copayApp.controllers').controller('lockSetupController', functio configService.set(opts, function(err) { if (err) $log.debug(err); + checkAndSelectOption(); }); }; }); diff --git a/www/views/lockSetup.html b/www/views/lockSetup.html index 1bab91b8b..9ac50b6d6 100644 --- a/www/views/lockSetup.html +++ b/www/views/lockSetup.html @@ -6,8 +6,8 @@ - - {{opt.label}} + + {{opt.label}}
From 6b4b6759409692989f0534db6e310787380ed6c7 Mon Sep 17 00:00:00 2001 From: JDonadio Date: Thu, 20 Apr 2017 13:05:33 -0300 Subject: [PATCH 2/4] remove popup confirmation --- src/js/controllers/lockSetup.js | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/src/js/controllers/lockSetup.js b/src/js/controllers/lockSetup.js index bce070ae9..072979cb4 100644 --- a/src/js/controllers/lockSetup.js +++ b/src/js/controllers/lockSetup.js @@ -1,6 +1,6 @@ 'use strict'; -angular.module('copayApp.controllers').controller('lockSetupController', function($state, $scope, $timeout, $log, configService, popupService, gettextCatalog, appConfigService, fingerprintService, profileService, lodash) { +angular.module('copayApp.controllers').controller('lockSetupController', function($state, $scope, $timeout, $log, configService, gettextCatalog, fingerprintService, profileService, lodash) { function init() { $scope.options = [ @@ -97,37 +97,21 @@ angular.module('copayApp.controllers').controller('lockSetupController', functio locking: false, }); else saveConfig(); - } else if (selectedMethod == 'fingerprint') { - if (savedMethod == 'pin') { - askForDisablePin(function(disablePin) { - if (disablePin) saveConfig('fingerprint'); - else init(); - }); - } else saveConfig('fingerprint'); } else if (selectedMethod == 'pin') { if (savedMethod == 'pin') return; $state.transitionTo('tabs.pin', { fromSettings: true, locking: savedMethod == 'pin' ? false : true }); + } else if (selectedMethod == 'fingerprint') { + if (savedMethod == 'fingerprint') return; + else saveConfig('fingerprint'); } $timeout(function() { $scope.$apply(); }); }; - function askForDisablePin(cb) { - var message = gettextCatalog.getString('{{appName}} startup is locked by PIN. Are you sure you want to disable it?', { - appName: appConfigService.nameCase - }); - var okText = gettextCatalog.getString('Continue'); - var cancelText = gettextCatalog.getString('Cancel'); - popupService.showConfirm(null, message, okText, cancelText, function(ok) { - if (!ok) return cb(false); - return cb(true); - }); - }; - function saveConfig(method) { var opts = { lock: { From dd154a3c4a08cd87d36a7b5bdebdf5cfcafb4c0a Mon Sep 17 00:00:00 2001 From: JDonadio Date: Thu, 20 Apr 2017 15:48:05 -0300 Subject: [PATCH 3/4] refactor --- src/js/controllers/lockSetup.js | 116 +++++++++++++++--------- src/js/controllers/pin.js | 138 ++++++++++++++++++----------- src/js/controllers/tab-settings.js | 5 +- src/js/routes.js | 10 ++- src/js/services/configService.js | 1 - www/views/pin.html | 2 +- 6 files changed, 172 insertions(+), 100 deletions(-) diff --git a/src/js/controllers/lockSetup.js b/src/js/controllers/lockSetup.js index 072979cb4..0503a7aee 100644 --- a/src/js/controllers/lockSetup.js +++ b/src/js/controllers/lockSetup.js @@ -5,14 +5,15 @@ angular.module('copayApp.controllers').controller('lockSetupController', functio function init() { $scope.options = [ { - method: null, + method: 'none', label: gettextCatalog.getString('Disabled'), + disabled: false, }, { method: 'pin', label: gettextCatalog.getString('Lock by PIN'), - needsBackup: null, - disabled: null, + needsBackup: false, + disabled: false, }, ]; @@ -20,12 +21,12 @@ angular.module('copayApp.controllers').controller('lockSetupController', functio $scope.options.push({ method: 'fingerprint', label: gettextCatalog.getString('Lock by Fingerprint'), - needsBackup: null, - disabled: null, + needsBackup: false, + disabled: false, }); } - checkAndSelectOption(); + initMethodSelector(); processWallets(); }; @@ -33,21 +34,40 @@ angular.module('copayApp.controllers').controller('lockSetupController', functio init(); }); - function checkAndSelectOption() { + function getSavedMethod() { var config = configService.getSync(); - var method = config.lock && config.lock.method; + if (config.lock) return config.lock.method; + return 'none'; + }; - if (!method) { - $scope.currentOption = $scope.options[0]; - $scope.options[1].disabled = false; - $scope.options[2].disabled = false; - } else { - if (method == 'fingerprint') $scope.options[1].disabled = true; - if (method == 'pin') $scope.options[2].disabled = true; - $scope.currentOption = lodash.find($scope.options, { - 'method': method - }); + function initMethodSelector() { + function disable(method) { + lodash.find($scope.options, { + method: method + }).disabled = true; + }; + + var savedMethod = getSavedMethod(); + + lodash.each($scope.options, function(o) { + o.disabled = false; + }); + + // HACK: Disable untill we allow to change between methods directly + if (fingerprintService.isAvailable()) { + switch (savedMethod) { + case 'pin': + disable('fingerprint'); + break; + case 'fingerprint': + disable('pin'); + break; + } } + + $scope.currentOption = lodash.find($scope.options, { + method: savedMethod + }); $timeout(function() { $scope.$apply(); }); @@ -87,42 +107,56 @@ angular.module('copayApp.controllers').controller('lockSetupController', functio }; $scope.select = function(selectedMethod) { - var config = configService.getSync(); - var savedMethod = config.lock && config.lock.method; + var savedMethod = getSavedMethod(); + if (savedMethod == selectedMethod) return; - if (!selectedMethod) { - if (!savedMethod) return; - if (savedMethod == 'pin') $state.transitionTo('tabs.pin', { - fromSettings: true, - locking: false, - }); - else saveConfig(); - } else if (selectedMethod == 'pin') { - if (savedMethod == 'pin') return; - $state.transitionTo('tabs.pin', { - fromSettings: true, - locking: savedMethod == 'pin' ? false : true - }); - } else if (selectedMethod == 'fingerprint') { - if (savedMethod == 'fingerprint') return; - else saveConfig('fingerprint'); + if (selectedMethod == 'none') { + disableMethod(savedMethod); + } else { + enableMethod(selectedMethod); + } + }; + + function disableMethod(method) { + switch (method) { + case 'pin': + $state.transitionTo('tabs.pin', { + action: 'disable' + }); + break; + case 'fingerprint': + fingerprintService.check('unlockingApp', function(err) { + if (err) init(); + else saveConfig('none'); + }); + break; + } + }; + + function enableMethod(method) { + switch (method) { + case 'pin': + $state.transitionTo('tabs.pin', { + action: 'setup' + }); + break; + case 'fingerprint': + saveConfig('fingerprint'); + break; } - $timeout(function() { - $scope.$apply(); - }); }; function saveConfig(method) { var opts = { lock: { - method: method || null, + method: method, value: null, } }; configService.set(opts, function(err) { if (err) $log.debug(err); - checkAndSelectOption(); + initMethodSelector(); }); }; }); diff --git a/src/js/controllers/pin.js b/src/js/controllers/pin.js index 3156320fd..2790fd9af 100644 --- a/src/js/controllers/pin.js +++ b/src/js/controllers/pin.js @@ -3,11 +3,11 @@ angular.module('copayApp.controllers').controller('pinController', function($state, $interval, $stateParams, $ionicHistory, $timeout, $scope, $log, configService, appConfigService) { var ATTEMPT_LIMIT = 3; var ATTEMPT_LOCK_OUT_TIME = 5 * 60; + var currentPin; $scope.$on("$ionicView.beforeEnter", function(event) { - $scope.currentPin = $scope.confirmPin = ''; - $scope.fromSettings = $stateParams.fromSettings == 'true' ? true : false; - $scope.locking = $stateParams.locking == 'true' ? true : false; + currentPin = $scope.confirmPin = ''; + $scope.action = $stateParams.action; $scope.match = $scope.error = $scope.disableButtons = false; $scope.currentAttempts = 0; $scope.appName = appConfigService.name; @@ -27,26 +27,19 @@ angular.module('copayApp.controllers').controller('pinController', function($sta }); }); + function getSavedMethod() { + var config = configService.getSync(); + if (config.lock) return config.lock.method; + return 'none'; + }; + function checkAttempts() { $scope.currentAttempts += 1; $log.debug('Attempts to unlock:', $scope.currentAttempts); if ($scope.currentAttempts === ATTEMPT_LIMIT) { $scope.currentAttempts = 0; var limitTime = Math.floor(Date.now() / 1000) + ATTEMPT_LOCK_OUT_TIME; - var config = configService.getSync(); - var opts = { - lock: { - method: 'pin', - value: config.lock.value, - bannedUntil: limitTime, - attempts: config.lock.attempts + 1, - } - }; - - configService.set(opts, function(err) { - if (err) $log.debug(err); - lockTimeControl(limitTime); - }); + saveFailedAttempt(limitTime); } }; @@ -74,7 +67,7 @@ angular.module('copayApp.controllers').controller('pinController', function($sta function reset() { $scope.expires = $scope.error = $scope.disableButtons = null; - $scope.currentPin = $scope.confirmPin = ''; + currentPin = $scope.confirmPin = ''; $interval.cancel(countDown); $timeout(function() { $scope.$apply(); @@ -84,20 +77,20 @@ angular.module('copayApp.controllers').controller('pinController', function($sta }; $scope.getFilledClass = function(limit) { - return $scope.currentPin.length >= limit ? 'filled-' + $scope.appName : null; + return currentPin.length >= limit ? 'filled-' + $scope.appName : null; }; $scope.delete = function() { if ($scope.disableButtons) return; - if ($scope.currentPin.length > 0) { - $scope.currentPin = $scope.currentPin.substring(0, $scope.currentPin.length - 1); + if (currentPin.length > 0) { + currentPin = currentPin.substring(0, currentPin.length - 1); $scope.error = false; $scope.updatePin(); } }; $scope.isComplete = function() { - if ($scope.currentPin.length < 4) return false; + if (currentPin.length < 4) return false; else return true; }; @@ -105,7 +98,7 @@ angular.module('copayApp.controllers').controller('pinController', function($sta if ($scope.disableButtons) return; $scope.error = false; if (value && !$scope.isComplete()) { - $scope.currentPin = $scope.currentPin + value; + currentPin = currentPin + value; $timeout(function() { $scope.$apply(); }); @@ -113,40 +106,56 @@ angular.module('copayApp.controllers').controller('pinController', function($sta $scope.save(); }; + function isMatch(pin) { + var config = configService.getSync(); + return config.lock.value == pin; + }; + $scope.save = function() { if (!$scope.isComplete()) return; - var config = configService.getSync(); - $scope.match = config.lock && config.lock.method == 'pin' && config.lock.value == $scope.currentPin ? true : false; - if (!$scope.locking) { - if ($scope.match) { - if ($scope.fromSettings) saveSettings(); - else { - saveSettings('pin', $scope.currentPin); - $scope.error = false; + var savedMethod = getSavedMethod(); + + switch ($scope.action) { + case 'setup': + applyAndCheckPin(); + break; + case 'disable': + if (isMatch(currentPin)) { + deletePin(); + } else { + showError(); + checkAttempts(); } - } else { - $timeout(function() { - $scope.confirmPin = $scope.currentPin = ''; - $scope.error = true; - }, 200); - checkAttempts(); - } - } else { - processCodes(); + break; + case 'check': + if (isMatch(currentPin)) return $scope.close(); + showError(); + break; } }; - function processCodes() { + function showError() { + $timeout(function() { + $scope.confirmPin = currentPin = ''; + $scope.error = true; + }, 200); + + $timeout(function() { + $scope.$apply(); + }); + }; + + function applyAndCheckPin() { if (!$scope.confirmPin) { $timeout(function() { - $scope.confirmPin = $scope.currentPin; - $scope.currentPin = ''; + $scope.confirmPin = currentPin; + currentPin = ''; }, 200); } else { - if ($scope.confirmPin == $scope.currentPin) - saveSettings('pin', $scope.confirmPin); + if ($scope.confirmPin == currentPin) + savePin($scope.confirmPin); else { - $scope.confirmPin = $scope.currentPin = ''; + $scope.confirmPin = currentPin = ''; $scope.error = true; } } @@ -155,15 +164,12 @@ angular.module('copayApp.controllers').controller('pinController', function($sta }); }; - function saveSettings(method, value) { - var config = configService.getSync(); - var attempts = config.lock && config.lock.attempts ? config.lock.attempts : 0; + function deletePin() { var opts = { lock: { - method: method || null, - value: value || null, + method: 'none', + value: null, bannedUntil: null, - attempts: attempts + 1, } }; @@ -173,6 +179,34 @@ angular.module('copayApp.controllers').controller('pinController', function($sta }); }; + function savePin(value) { + var opts = { + lock: { + method: 'pin', + value: value, + bannedUntil: null, + } + }; + + configService.set(opts, function(err) { + if (err) $log.debug(err); + $scope.close(); + }); + }; + + function saveFailedAttempt(bannedUntil) { + var opts = { + lock: { + bannedUntil: bannedUntil, + } + }; + + configService.set(opts, function(err) { + if (err) $log.debug(err); + lockTimeControl(limitTime); + }); + }; + $scope.close = function(delay) { $timeout(function() { var shouldReturn = $ionicHistory.viewHistory().backView && $ionicHistory.viewHistory().backView.stateName != 'starting'; diff --git a/src/js/controllers/tab-settings.js b/src/js/controllers/tab-settings.js index 843059c84..a245418c7 100644 --- a/src/js/controllers/tab-settings.js +++ b/src/js/controllers/tab-settings.js @@ -55,7 +55,10 @@ angular.module('copayApp.controllers').controller('tabSettingsController', funct $scope.appName = appConfigService.nameCase; configService.whenAvailable(function(config) { $scope.locked = config.lock && config.lock.method; - $scope.method = $scope.locked ? config.lock.method.charAt(0).toUpperCase() + config.lock.method.slice(1) : gettextCatalog.getString('Disabled'); + if (!$scope.locked || $scope.locked == 'none') + $scope.method = gettextCatalog.getString('Disabled'); + else + $scope.method = $scope.locked.charAt(0).toUpperCase() + config.lock.method.slice(1); }); }); diff --git a/src/js/routes.js b/src/js/routes.js index 9e6a82016..e55d65401 100644 --- a/src/js/routes.js +++ b/src/js/routes.js @@ -126,7 +126,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr */ .state('pin', { - url: '/pin/', + url: '/pin/:action', controller: 'pinController', templateUrl: 'views/pin.html', }) @@ -473,7 +473,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr } }) .state('tabs.pin', { - url: '/pin/:fromSettings/:locking', + url: '/pin/:action', views: { 'tab-settings@tabs': { controller: 'pinController', @@ -1214,7 +1214,9 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr function goTo(nextView) { nextView = nextView || defaultView; - $state.transitionTo(nextView).then(function() { + $state.transitionTo(nextView, { + action: 'check' + }).then(function() { if (nextView == 'lockedView') $ionicHistory.clearHistory(); }); @@ -1230,7 +1232,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr fingerprintService.check('unlockingApp', function(err) { if (err) goTo('lockedView'); - if ($ionicHistory.currentStateName() == 'lockedView' || !onResume) + else if ($ionicHistory.currentStateName() == 'lockedView' || !onResume) goTo('tabs.home'); }); } else if (lockMethod == 'pin') { diff --git a/src/js/services/configService.js b/src/js/services/configService.js index 2b92e58ff..4a8021b55 100644 --- a/src/js/services/configService.js +++ b/src/js/services/configService.js @@ -57,7 +57,6 @@ angular.module('copayApp.services').factory('configService', function(storageSer method: null, value: null, bannedUntil: null, - attempts: null, }, // External services diff --git a/www/views/pin.html b/www/views/pin.html index 34816f2a2..ab1b67dec 100644 --- a/www/views/pin.html +++ b/www/views/pin.html @@ -1,4 +1,4 @@ - + From cc3b2d6147f157ce9aa944c7664d8c5d11f4c916 Mon Sep 17 00:00:00 2001 From: JDonadio Date: Sat, 22 Apr 2017 12:54:25 -0300 Subject: [PATCH 4/4] fix lock by attempts reached --- src/js/controllers/pin.js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/js/controllers/pin.js b/src/js/controllers/pin.js index 2790fd9af..20862c9d0 100644 --- a/src/js/controllers/pin.js +++ b/src/js/controllers/pin.js @@ -38,13 +38,12 @@ angular.module('copayApp.controllers').controller('pinController', function($sta $log.debug('Attempts to unlock:', $scope.currentAttempts); if ($scope.currentAttempts === ATTEMPT_LIMIT) { $scope.currentAttempts = 0; - var limitTime = Math.floor(Date.now() / 1000) + ATTEMPT_LOCK_OUT_TIME; - saveFailedAttempt(limitTime); + var bannedUntil = Math.floor(Date.now() / 1000) + ATTEMPT_LOCK_OUT_TIME; + saveFailedAttempt(bannedUntil); } }; - function lockTimeControl(limitTime) { - $scope.limitTimeExpired = false; + function lockTimeControl(bannedUntil) { setExpirationTime(); var countDown = $interval(function() { @@ -53,12 +52,11 @@ angular.module('copayApp.controllers').controller('pinController', function($sta function setExpirationTime() { var now = Math.floor(Date.now() / 1000); - if (now > limitTime) { - $scope.limitTimeExpired = true; + if (now > bannedUntil) { if (countDown) reset(); } else { $scope.disableButtons = true; - var totalSecs = limitTime - now; + var totalSecs = bannedUntil - now; var m = Math.floor(totalSecs / 60); var s = totalSecs % 60; $scope.expires = ('0' + m).slice(-2) + ":" + ('0' + s).slice(-2); @@ -130,6 +128,7 @@ angular.module('copayApp.controllers').controller('pinController', function($sta case 'check': if (isMatch(currentPin)) return $scope.close(); showError(); + checkAttempts(); break; } }; @@ -203,7 +202,7 @@ angular.module('copayApp.controllers').controller('pinController', function($sta configService.set(opts, function(err) { if (err) $log.debug(err); - lockTimeControl(limitTime); + lockTimeControl(bannedUntil); }); };