diff --git a/jslib b/jslib index 0d80216921..848f50afe7 160000 --- a/jslib +++ b/jslib @@ -1 +1 @@ -Subproject commit 0d80216921efa53dfc095fd25dde9b370a070da8 +Subproject commit 848f50afe7b9dc9e193a036c062ef2f0e4d93018 diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json index 1df3866af0..b80d588d3b 100644 --- a/src/_locales/en/messages.json +++ b/src/_locales/en/messages.json @@ -455,6 +455,9 @@ "uri": { "message": "URI" }, + "newUri": { + "message": "New URI" + }, "addedItem": { "message": "Added item" }, @@ -989,5 +992,33 @@ }, "passwordSafe": { "message": "This password was not found in any known data breaches. It should be safe to use." + }, + "baseDomain": { + "message": "Base domain" + }, + "host": { + "message": "Host", + "description": "A URL's host value. For example, the host of https://sub.domain.com:443 is 'sub.domain.com:443'." + }, + "exact": { + "message": "Exact" + }, + "startsWith": { + "message": "Starts with" + }, + "regEx": { + "message": "Regular expression", + "description": "A programming term, also known as 'RegEx'." + }, + "autofillDetection": { + "message": "Auto-fill Detection", + "description": "URI auto-fill match detection." + }, + "defaultAutofillDetection": { + "message": "Default auto-fill detection", + "description": "Default URI auto-fill match detection." + }, + "toggleOptions": { + "message": "Toggle Options" } } diff --git a/src/popup/app/vault/vaultAddCipherController.js b/src/popup/app/vault/vaultAddCipherController.js index 5845c48399..6a9d6e8362 100644 --- a/src/popup/app/vault/vaultAddCipherController.js +++ b/src/popup/app/vault/vaultAddCipherController.js @@ -14,7 +14,12 @@ angular folderId: folderId, name: $stateParams.name, type: constantsService.cipherType.login, - login: {}, + login: { + uris: [{ + uri: null, + match: null + }] + }, identity: {}, card: {}, secureNote: { @@ -23,13 +28,15 @@ angular }; if ($stateParams.uri) { - $scope.cipher.login.uri = $stateParams.uri; + $scope.cipher.login.uris[0].uri = $stateParams.uri; } if ($stateParams.cipher) { angular.extend($scope.cipher, $stateParams.cipher); } + setUriMatchValues(); + $timeout(function () { popupUtilsService.initListSectionItemListeners(document, angular); @@ -109,6 +116,50 @@ angular }); }; + $scope.addUri = function () { + if (!$scope.cipher.login) { + return; + } + + if (!$scope.cipher.login.uris) { + $scope.cipher.login.uris = []; + } + + $scope.cipher.login.uris.push({ + uri: null, + match: null, + }); + + $timeout(function () { + popupUtilsService.initListSectionItemListeners(document, angular); + }, 500); + }; + + $scope.removeUri = function (uri) { + if (!$scope.cipher.login || !$scope.cipher.login.uris) { + return; + } + + var index = $scope.cipher.login.uris.indexOf(uri); + if (index > -1) { + $scope.cipher.login.uris.splice(index, 1); + } + }; + + $scope.uriMatchChanged = function (uri) { + uri.showOptions = uri.showOptions == null ? true : uri.showOptions; + if ((!uri.matchValue && uri.matchValue !== 0) || uri.matchValue === '') { + uri.match = null; + } + else { + uri.match = parseInt(uri.matchValue); + } + }; + + $scope.toggleUriOptions = function (u) { + u.showOptions = u.showOptions == null && u.match != null ? false : !u.showOptions; + }; + $scope.addField = function (type) { if (!$scope.cipher.fields) { $scope.cipher.fields = []; @@ -142,4 +193,14 @@ angular } }); }; + + function setUriMatchValues() { + if ($scope.cipher.login && $scope.cipher.login.uris) { + for (var i = 0; i < $scope.cipher.login.uris.length; i++) { + $scope.cipher.login.uris[i].matchValue = + $scope.cipher.login.uris[i].match || $scope.cipher.login.uris[i].match === 0 ? + $scope.cipher.login.uris[i].match.toString() : ''; + } + } + } }); diff --git a/src/popup/app/vault/vaultEditCipherController.js b/src/popup/app/vault/vaultEditCipherController.js index 5890d72fa9..e8bbfc32e0 100644 --- a/src/popup/app/vault/vaultEditCipherController.js +++ b/src/popup/app/vault/vaultEditCipherController.js @@ -24,12 +24,14 @@ angular if ($stateParams.cipher) { angular.extend($scope.cipher, $stateParams.cipher); + setUriMatchValues(); } else { cipherService.get(cipherId).then(function (cipher) { return cipher.decrypt(); }).then(function (model) { $scope.cipher = model; + setUriMatchValues(); }); } @@ -127,6 +129,50 @@ angular }); }; + $scope.addUri = function () { + if (!$scope.cipher.login) { + return; + } + + if (!$scope.cipher.login.uris) { + $scope.cipher.login.uris = []; + } + + $scope.cipher.login.uris.push({ + uri: null, + match: null, + }); + + $timeout(function () { + popupUtilsService.initListSectionItemListeners(document, angular); + }, 500); + }; + + $scope.removeUri = function (uri) { + if (!$scope.cipher.login || !$scope.cipher.login.uris) { + return; + } + + var index = $scope.cipher.login.uris.indexOf(uri); + if (index > -1) { + $scope.cipher.login.uris.splice(index, 1); + } + }; + + $scope.uriMatchChanged = function (uri) { + uri.showOptions = uri.showOptions == null ? true : uri.showOptions; + if ((!uri.matchValue && uri.matchValue !== 0) || uri.matchValue === '') { + uri.match = null; + } + else { + uri.match = parseInt(uri.matchValue); + } + }; + + $scope.toggleUriOptions = function (u) { + u.showOptions = u.showOptions == null && u.match != null ? false : !u.showOptions; + }; + $scope.addField = function (type) { if (!$scope.cipher.fields) { $scope.cipher.fields = []; @@ -182,4 +228,14 @@ angular } }); } + + function setUriMatchValues() { + if ($scope.cipher.login && $scope.cipher.login.uris) { + for (var i = 0; i < $scope.cipher.login.uris.length; i++) { + $scope.cipher.login.uris[i].matchValue = + $scope.cipher.login.uris[i].match || $scope.cipher.login.uris[i].match === 0 ? + $scope.cipher.login.uris[i].match.toString() : ''; + } + } + } }); diff --git a/src/popup/app/vault/vaultViewCipherController.js b/src/popup/app/vault/vaultViewCipherController.js index 942fe05cc7..eaead5d496 100644 --- a/src/popup/app/vault/vaultViewCipherController.js +++ b/src/popup/app/vault/vaultViewCipherController.js @@ -28,20 +28,6 @@ angular if (model.login.password) { $scope.cipher.maskedPassword = $scope.maskValue(model.login.password); } - - if (model.login.uri) { - $scope.cipher.showLaunch = model.login.uri.startsWith('http://') || model.login.uri.startsWith('https://'); - var domain = platformUtilsService.getDomain(model.login.uri); - if (domain) { - $scope.cipher.login.website = domain; - } - else { - $scope.cipher.login.website = model.login.uri; - } - } - else { - $scope.cipher.showLaunch = false; - } } if (model.login && model.login.totp && (cipherObj.organizationUseTotp || tokenService.getPremium())) { @@ -90,11 +76,13 @@ angular } }; - $scope.launchWebsite = function (cipher) { - if (cipher.showLaunch) { - $analytics.eventTrack('Launched Website'); - BrowserApi.createNewTab(cipher.login.uri); + $scope.launch = function (uri) { + if (!uri.canLaunch) { + return; } + + $analytics.eventTrack('Launched Login URI'); + BrowserApi.createNewTab(uri.uri); }; $scope.clipboardError = function (e, password) { diff --git a/src/popup/app/vault/views/vaultAddCipher.html b/src/popup/app/vault/views/vaultAddCipher.html index 6aed1d396b..ab1910c043 100644 --- a/src/popup/app/vault/views/vaultAddCipher.html +++ b/src/popup/app/vault/views/vaultAddCipher.html @@ -30,10 +30,6 @@
-
- - -
@@ -50,12 +46,15 @@ + + +
- - {{i18n.generatePassword}} - - +
+ + +
@@ -202,12 +201,44 @@
+
+
+
+ + + +
+ + + + +
+ + + +
+ + {{i18n.newUri}} + +
+
-
- - -
-
- - -
@@ -43,12 +39,15 @@ + + +
- - {{i18n.generatePassword}} - - +
+ + +
@@ -195,12 +194,44 @@
+
+
+
+ + + +
+ + + + +
+ + + +
+ + {{i18n.newUri}} + +
+
-
- - -
-
- - {{i18n.website}} - {{cipher.login.website}} -
+
+
+
+ + {{i18n.website}} + {{i18n.uri}} + {{u.domainOrUri}} +
+
+
{{i18n.notes}} diff --git a/src/popup/less/components.less b/src/popup/less/components.less index cbfa48b958..1b10677429 100644 --- a/src/popup/less/components.less +++ b/src/popup/less/components.less @@ -329,7 +329,7 @@ } .action-button { - padding: 8px 10px 8px 5px; + padding: 8px 8px 8px 4px; display: table-cell; width: 20px; vertical-align: middle; @@ -342,6 +342,14 @@ .action-button-content { display: table-cell; vertical-align: middle; + + input + label.sr-only + select { + margin-top: 5px; + } + } + + .action-button-content + .action-button { + padding: 8px 0 8px 14px; } .field-type {