diff --git a/src/js/app.js b/src/js/app.js index 44050be..d54d92f 100644 --- a/src/js/app.js +++ b/src/js/app.js @@ -63,7 +63,6 @@ var app = angular.module('mail', [ 'read', 'contacts', 'login-new-device', - 'privatekey-upload', 'infinite-scroll' ]); diff --git a/src/js/controller/app/privatekey-upload.js b/src/js/controller/app/privatekey-upload.js index 779a101..eb70450 100644 --- a/src/js/controller/app/privatekey-upload.js +++ b/src/js/controller/app/privatekey-upload.js @@ -33,26 +33,6 @@ var PrivateKeyUploadCtrl = function($scope, keychain, pgp, dialog, auth) { } }; - $scope.handlePaste = function(event) { - var evt = event; - if (evt.originalEvent) { - evt = evt.originalEvent; - } - - var value = evt.clipboardData.getData('text/plain'); - if (!value) { - return; - } - - value = value.replace(/-/g, ''); - $scope.code0 = value.slice(0, 4); - $scope.code1 = value.slice(4, 8); - $scope.code2 = value.slice(8, 12); - $scope.code3 = value.slice(12, 16); - $scope.code4 = value.slice(16, 20); - $scope.code5 = value.slice(20, 24); - }; - $scope.checkServerForKey = function(callback) { var keyParams = pgp.getKeyParams(); keychain.hasPrivateKey({ @@ -80,14 +60,12 @@ var PrivateKeyUploadCtrl = function($scope, keychain, pgp, dialog, auth) { $scope.code = util.randomString(24); $scope.displayedCode = $scope.code.slice(0, 4) + '-' + $scope.code.slice(4, 8) + '-' + $scope.code.slice(8, 12) + '-' + $scope.code.slice(12, 16) + '-' + $scope.code.slice(16, 20) + '-' + $scope.code.slice(20, 24); - // clear input fields of any previous artifacts - $scope.code0 = $scope.code1 = $scope.code2 = $scope.code3 = $scope.code4 = $scope.code5 = ''; + // clear input field of any previous artifacts + $scope.inputCode = ''; }; $scope.verifyCode = function() { - var inputCode = '' + $scope.code0 + $scope.code1 + $scope.code2 + $scope.code3 + $scope.code4 + $scope.code5; - - if (inputCode.toUpperCase() !== $scope.code) { + if ($scope.inputCode.toUpperCase() !== $scope.code) { var err = new Error('The code does not match. Please go back and check the generated code.'); dialog.error(err); return false; @@ -171,26 +149,4 @@ var PrivateKeyUploadCtrl = function($scope, keychain, pgp, dialog, auth) { }; -// -// Directives -// - -var ngModule = angular.module('privatekey-upload', []); -ngModule.directive('focusNext', function() { - return { - link: function(scope, element, attr) { - var maxLen = element[0].maxLength; - - scope.$watch(attr.ngModel, function(val) { - if (val && val.length === maxLen) { - var nextinput = element.next('input'); - if (nextinput.length) { - nextinput[0].focus(); - } - } - }); - } - }; -}); - module.exports = PrivateKeyUploadCtrl; \ No newline at end of file diff --git a/src/js/controller/login/login-privatekey-download.js b/src/js/controller/login/login-privatekey-download.js index 2d9715b..5c3a58c 100644 --- a/src/js/controller/login/login-privatekey-download.js +++ b/src/js/controller/login/login-privatekey-download.js @@ -70,10 +70,8 @@ var LoginPrivateKeyDownloadCtrl = function($scope, $location, $routeParams, auth }; $scope.decryptAndStorePrivateKeyLocally = function() { - var inputCode = '' + $scope.code0 + $scope.code1 + $scope.code2 + $scope.code3 + $scope.code4 + $scope.code5; - var options = $scope.encryptedPrivateKey; - options.code = inputCode.toUpperCase(); + options.code = $scope.code.toUpperCase(); keychain.decryptAndStorePrivateKeyLocally(options, function(err, privateKey) { if (err) { @@ -108,26 +106,6 @@ var LoginPrivateKeyDownloadCtrl = function($scope, $location, $routeParams, auth }); }; - $scope.handlePaste = function(event) { - var evt = event; - if (evt.originalEvent) { - evt = evt.originalEvent; - } - - var value = evt.clipboardData.getData('text/plain'); - if (!value) { - return; - } - - value = value.replace(/-/g, ''); - $scope.code0 = value.slice(0, 4); - $scope.code1 = value.slice(4, 8); - $scope.code2 = value.slice(8, 12); - $scope.code3 = value.slice(12, 16); - $scope.code4 = value.slice(16, 20); - $scope.code5 = value.slice(20, 24); - }; - // // helper functions // diff --git a/src/js/directive/common.js b/src/js/directive/common.js index bc8a74d..fac43ce 100644 --- a/src/js/directive/common.js +++ b/src/js/directive/common.js @@ -173,4 +173,135 @@ ngModule.directive('woClickFileInput', function() { }; }); +ngModule.directive('woInputCode', function() { + var BLOCK_SIZE = 4; + var NUM_BLOCKS = 6; + var BLOCK_DIVIDER = '-'; + + // helpers + + function getBlockIndex(code, pos) { + return code.substr(0, pos).replace(new RegExp('[^' + BLOCK_DIVIDER + ']', 'g'), '').length; + } + + function getBlockDimensions(code, i) { + var start = 0; + var end = code.length; + var found = 0; + for(var j = 0; j < code.length; j++) { + if(code[j] === BLOCK_DIVIDER) { + found++; + if(found === i) { + start = j + 1; + } + if(found === i + 1) { + end = j - 1; + } + } + } + + return { + start: start, + end: end + }; + } + + function getBlock(code, i) { + var dims = getBlockDimensions(code, i); + return code.substring(dims.start, dims.end + 1); + } + + function setBlock(code, i, val) { + var dims = getBlockDimensions(code, i); + return code.substring(0, dims.start) + val + code.substring(dims.end + 1); + } + + return { + restrict: 'A', + require: 'ngModel', + link: function(scope, elm, attrs, ngModelCtrl) { + function format(val) { + var str = ''; + + // check if value exists + if (!val) { + return str; + } + + for(var i = 0; i < val.length; i++) { + if(i > 0 && i % BLOCK_SIZE === 0) { + str += BLOCK_DIVIDER; + } + str += val[i]; + } + + return str; + } + + function parse(val) { + var parsed = val.replace(new RegExp(BLOCK_DIVIDER, 'g'), '').trim(); + return parsed; + } + + ngModelCtrl.$parsers.push(parse); + ngModelCtrl.$formatters.push(format); + + var maxlength = NUM_BLOCKS * (BLOCK_SIZE + 1) - 1; + + elm.on('input', function() { + var start = this.selectionStart; + var end = this.selectionEnd; + var val = this.value; + + var blockIndex = getBlockIndex(val, start); + var blockDims = getBlockDimensions(val, blockIndex); + var block = getBlock(val, blockIndex); + + // add new block to the end + if(val.length < maxlength && start === val.length && block.length > BLOCK_SIZE) { + val = setBlock(val, blockIndex, block.substr(0, BLOCK_SIZE) + BLOCK_DIVIDER + block.substr(BLOCK_SIZE)); + start = val.length; + end = val.length; + } + // maxsize in last block + else if(start === val.length && block.length > BLOCK_SIZE) { + val = setBlock(val, blockIndex, block.substr(0, BLOCK_SIZE)); + start = val.length; + end = val.length; + } + // overwrite next char if block is full + else if(block.length > BLOCK_SIZE && start <= blockDims.end) { + val = val.substring(0, start) + val.substring(start + 1); + } + // jump to next block if cursor is at the end of the block and block is full + else if(block.length > BLOCK_SIZE && start === blockDims.end + 1) { + var overflow = block.substr(BLOCK_SIZE); + if(overflow.length > BLOCK_SIZE) { + overflow = overflow.substr(0, BLOCK_SIZE); + } + val = setBlock(val, blockIndex, block.substr(0, BLOCK_SIZE)); + + var nextBlock = getBlock(val, blockIndex + 1); + val = setBlock(val, blockIndex + 1, (overflow + nextBlock).substr(0, BLOCK_SIZE)); + + start++; + end++; + } + + ngModelCtrl.$setViewValue(val); + ngModelCtrl.$render(); + + this.setSelectionRange(start, end); + }); + + elm.on('click', function() { + var blockIndex = getBlockIndex(this.value, this.selectionStart); + var dims = getBlockDimensions(this.value, blockIndex); + + this.setSelectionRange(dims.start, dims.end + 1); + }); + } + }; +}); + module.exports = ngModule; \ No newline at end of file diff --git a/src/tpl/login-privatekey-download.html b/src/tpl/login-privatekey-download.html index 578bbc8..af4601e 100644 --- a/src/tpl/login-privatekey-download.html +++ b/src/tpl/login-privatekey-download.html @@ -43,14 +43,8 @@
Please confirm the keychain code you have written down.