diff --git a/keepassxc-browser/background/browserAction.js b/keepassxc-browser/background/browserAction.js
index 3d0f486..6847bd9 100755
--- a/keepassxc-browser/background/browserAction.js
+++ b/keepassxc-browser/background/browserAction.js
@@ -206,8 +206,8 @@ browserAction.setRememberPopup = function(tabId, username, password, url, userna
const settings = item.settings;
// Don't show anything if the site is in the ignore list
- for (const site in settings.ignoredSites) {
- if (site === url) {
+ for (const site of settings.ignoredSites) {
+ if (siteMatch(site.url, url)) {
return;
}
}
diff --git a/keepassxc-browser/global.js b/keepassxc-browser/global.js
index 55456cd..8fe6432 100755
--- a/keepassxc-browser/global.js
+++ b/keepassxc-browser/global.js
@@ -15,3 +15,74 @@ var showNotification = function(message) {
'message': message
});
};
+
+/**
+ * Transforms a valid match pattern into a regular expression
+ * which matches all URLs included by that pattern.
+ *
+ * @param {string} pattern The pattern to transform.
+ * @return {RegExp} The pattern's equivalent as a RegExp.
+ * @throws {TypeError} If the pattern is not a valid MatchPattern
+ *
+ * https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Match_patterns
+ */
+var matchPatternToRegExp = function(pattern) {
+ if (pattern === '') {
+ return (/^(?:http|https|file|ftp|app):\/\//);
+ }
+
+ const schemeSegment = '(\\*|http|https|ws|wss|file|ftp)';
+ const hostSegment = '(\\*|(?:\\*\\.)?(?:[^/*]+))?';
+ const pathSegment = '(.*)';
+ const matchPatternRegExp = new RegExp(
+ `^${schemeSegment}://${hostSegment}/${pathSegment}$`
+ );
+
+ let match = matchPatternRegExp.exec(pattern);
+ if (!match) {
+ throw new TypeError('"${pattern}" is not a valid MatchPattern');
+ }
+
+ let [, scheme, host, path] = match;
+ if (!host) {
+ throw new TypeError('"${pattern}" does not have a valid host');
+ }
+
+ let regex = '^';
+
+ if (scheme === '*') {
+ regex += '(http|https)';
+ } else {
+ regex += scheme;
+ }
+
+ regex += '://';
+
+ if (host && host === '*') {
+ regex += '[^/]+?';
+ } else if (host) {
+ if (host.match(/^\*\./)) {
+ regex += '[^/]*?';
+ host = host.substring(2);
+ }
+ regex += host.replace(/\./g, '\\.');
+ }
+
+ if (path) {
+ if (path === '*') {
+ regex += '(/.*)?';
+ } else if (path.charAt(0) !== '/') {
+ regex += '/';
+ regex += path.replace(/\./g, '\\.').replace(/\*/g, '.*?');
+ regex += '/?';
+ }
+ }
+
+ regex += '$';
+ return new RegExp(regex);
+};
+
+var siteMatch = function(site, url) {
+ const rx = matchPatternToRegExp(site);
+ return url.match(rx);
+};
\ No newline at end of file
diff --git a/keepassxc-browser/keepassxc-browser.js b/keepassxc-browser/keepassxc-browser.js
index aaa9b88..b1a59d7 100755
--- a/keepassxc-browser/keepassxc-browser.js
+++ b/keepassxc-browser/keepassxc-browser.js
@@ -1311,6 +1311,16 @@ cip.initCredentialFields = function(forceCall) {
browser.runtime.sendMessage({ 'action': 'page_clear_logins', args: [_called.clearLogins] }).then(() => {
_called.clearLogins = true;
+
+ // Ignore sites with full ignore
+ if (cip.settings.ignoredSites) {
+ for (const site of cip.settings.ignoredSites) {
+ if (site.fullIgnore && siteMatch(site.url, document.location.href)) {
+ return;
+ }
+ }
+ }
+
const inputs = cipFields.getAllFields();
if (inputs.length === 0) {
return;
@@ -1917,14 +1927,20 @@ cip.ignoreSite = function(sites) {
return;
}
- const site = sites[0];
- if (!cip.settings['ignoredSites']) {
- cip.settings['ignoredSites'] = {};
+ // Delete previously created Object if it exists. It will be replaced by an Array
+ if (cip.settings['ignoredSites'] !== null && cip.settings['ignoredSites'].constructor === Object) {
+ delete cip.settings['ignoredSites'];
}
- cip.settings['ignoredSites'][site] = {
- url: site
- };
+ const site = sites[0];
+ if (!cip.settings['ignoredSites']) {
+ cip.settings['ignoredSites'] = [];
+ }
+
+ cip.settings['ignoredSites'].push({
+ url: site,
+ fullIgnore: false
+ });
browser.runtime.sendMessage({
action: 'save_settings',
diff --git a/keepassxc-browser/options/options.css b/keepassxc-browser/options/options.css
index 47a9cd9..5af1947 100644
--- a/keepassxc-browser/options/options.css
+++ b/keepassxc-browser/options/options.css
@@ -3,6 +3,10 @@ body {
padding-bottom: 60px;
}
+table td {
+ width: 100%;
+}
+
/* Custom container */
.container {
margin: 0 auto;
@@ -111,6 +115,10 @@ h2+hr {
margin-right: 5px;
}
+#ignoreUrl {
+ width: 75%;
+}
+
tr.clone {
display: none;
}
diff --git a/keepassxc-browser/options/options.html b/keepassxc-browser/options/options.html
index 597b2af..9f5e745 100644
--- a/keepassxc-browser/options/options.html
+++ b/keepassxc-browser/options/options.html
@@ -297,21 +297,36 @@
Sites in this list are ignored when new credentials are detected.
Go to the page with new credentials, click the blinking KeePassXC-Browser icon or the notification and select Never ask for this page.
+
+ If full ignore is enabled, no input fields are detected and no credentials are received for that site.
+
+
+
diff --git a/keepassxc-browser/options/options.js b/keepassxc-browser/options/options.js
index 19bfbf2..eec34da 100644
--- a/keepassxc-browser/options/options.js
+++ b/keepassxc-browser/options/options.js
@@ -52,9 +52,9 @@ options.saveSettingsPromise = function() {
}
options.saveSetting = function(name) {
- const $id = '#' + name;
- $($id).closest('.control-group').removeClass('error').addClass('success');
- setTimeout(() => { $($id).closest('.control-group').removeClass('success'); }, 2500);
+ const id = '#' + name;
+ $(id).closest('.control-group').removeClass('error').addClass('success');
+ setTimeout(() => { $(id).closest('.control-group').removeClass('success'); }, 2500);
browser.storage.local.set({'settings': options.settings});
browser.runtime.sendMessage({
@@ -168,10 +168,10 @@ options.initConnectedDatabases = function() {
$('#dialogDeleteConnectedDatabase .modal-footer:first button.yes:first').click(function(e) {
$('#dialogDeleteConnectedDatabase').modal('hide');
- const $hash = $('#dialogDeleteConnectedDatabase').data('hash');
- $('#tab-connected-databases #tr-cd-' + $hash).remove();
+ const hash = $('#dialogDeleteConnectedDatabase').data('hash');
+ $('#tab-connected-databases #tr-cd-' + hash).remove();
- delete options.keyRing[$hash];
+ delete options.keyRing[hash];
options.saveKeyRing();
if ($('#tab-connected-databases table tbody:first tr').length > 2) {
@@ -183,22 +183,22 @@ options.initConnectedDatabases = function() {
$('#tab-connected-databases tr.clone:first .dropdown-menu:first').width('230px');
- const $trClone = $('#tab-connected-databases table tr.clone:first').clone(true);
- $trClone.removeClass('clone');
+ const trClone = $('#tab-connected-databases table tr.clone:first').clone(true);
+ trClone.removeClass('clone');
for (let hash in options.keyRing) {
- const $tr = $trClone.clone(true);
- $tr.data('hash', hash);
- $tr.attr('id', 'tr-cd-' + hash);
+ const tr = trClone.clone(true);
+ tr.data('hash', hash);
+ tr.attr('id', 'tr-cd-' + hash);
- $('a.dropdown-toggle:first img:first', $tr).attr('src', '/icons/19x19/icon_normal_19x19.png');
+ $('a.dropdown-toggle:first img:first', tr).attr('src', '/icons/19x19/icon_normal_19x19.png');
- $tr.children('td:first').text(options.keyRing[hash].id);
- $tr.children('td:eq(1)').text(options.keyRing[hash].key);
+ tr.children('td:first').text(options.keyRing[hash].id);
+ tr.children('td:eq(1)').text(options.keyRing[hash].key);
const lastUsed = (options.keyRing[hash].lastUsed) ? new Date(options.keyRing[hash].lastUsed).toLocaleString() : 'unknown';
- $tr.children('td:eq(2)').text(lastUsed);
+ tr.children('td:eq(2)').text(lastUsed);
const date = (options.keyRing[hash].created) ? new Date(options.keyRing[hash].created).toLocaleDateString() : 'unknown';
- $tr.children('td:eq(3)').text(date);
- $('#tab-connected-databases table tbody:first').append($tr);
+ tr.children('td:eq(3)').text(date);
+ $('#tab-connected-databases table tbody:first').append(tr);
}
if ($('#tab-connected-databases table tbody:first tr').length > 2) {
@@ -227,11 +227,11 @@ options.initSpecifiedCredentialFields = function() {
$('#dialogDeleteSpecifiedCredentialFields .modal-footer:first button.yes:first').click(function(e) {
$('#dialogDeleteSpecifiedCredentialFields').modal('hide');
- const $url = $('#dialogDeleteSpecifiedCredentialFields').data('url');
- const $trId = $('#dialogDeleteSpecifiedCredentialFields').data('tr-id');
- $('#tab-specified-fields #' + $trId).remove();
+ const url = $('#dialogDeleteSpecifiedCredentialFields').data('url');
+ const trId = $('#dialogDeleteSpecifiedCredentialFields').data('tr-id');
+ $('#tab-specified-fields #' + trId).remove();
- delete options.settings['defined-credential-fields'][$url];
+ delete options.settings['defined-credential-fields'][url];
options.saveSettings();
if ($('#tab-specified-fields table tbody:first tr').length > 2) {
@@ -241,17 +241,17 @@ options.initSpecifiedCredentialFields = function() {
}
});
- const $trClone = $('#tab-specified-fields table tr.clone:first').clone(true);
- $trClone.removeClass('clone');
+ const trClone = $('#tab-specified-fields table tr.clone:first').clone(true);
+ trClone.removeClass('clone');
let counter = 1;
for (let url in options.settings['defined-credential-fields']) {
- const $tr = $trClone.clone(true);
- $tr.data('url', url);
- $tr.attr('id', 'tr-scf' + counter);
+ const tr = trClone.clone(true);
+ tr.data('url', url);
+ tr.attr('id', 'tr-scf' + counter);
++counter;
- $tr.children('td:first').text(url);
- $('#tab-specified-fields table tbody:first').append($tr);
+ tr.children('td:first').text(url);
+ $('#tab-specified-fields table tbody:first').append(tr);
}
if ($('#tab-specified-fields table tbody:first tr').length > 2) {
@@ -271,14 +271,61 @@ options.initIgnoredSites = function() {
$('#dialogDeleteIgnoredSite').modal('show');
});
+ $('#tab-ignored-sites tr.clone:first input[type=checkbox]:first').change(function() {
+ const url = $(this).closest('tr').data('url');
+ for (let site of options.settings['ignoredSites']) {
+ if (site.url === url) {
+ site.fullIgnore = $(this).is(':checked');
+ }
+ }
+ options.saveSettings();
+ });
+
+ $("#ignoreUrl").keyup(function(event) {
+ if (event.keyCode === 13) {
+ $("#ignoreManualAddButton").click();
+ }
+ });
+
+ $('#ignoreManualAddButton').click(function(e) {
+ e.preventDefault();
+ const value = $('#ignoreUrl').val();
+ if (value.length > 10 && value.length <= 2000) {
+ if (options.settings['ignoredSites'] === undefined) {
+ options.settings['ignoredSites'] = [];
+ }
+
+ const newValue = options.settings['ignoredSites'].length + 1;
+ const trClone = $('#tab-ignored-sites table tr.clone:first').clone(true);
+ trClone.removeClass('clone');
+
+ const tr = trClone.clone(true);
+ tr.data('url', value);
+ tr.attr('id', 'tr-scf' + newValue);
+ tr.children('td:first').text(value);
+ tr.children('td:nth-child(3)').children('input[type=checkbox]').attr('checked', false);
+ $('#tab-ignored-sites table tbody:first').append(tr);
+ $('#tab-ignored-sites table tbody:first tr.empty:first').hide();
+
+ options.settings['ignoredSites'].push({url: value, fullIgnore: false});
+ options.saveSettings();
+
+ $('#ignoreUrl').val('');
+ }
+ });
+
$('#dialogDeleteIgnoredSite .modal-footer:first button.yes:first').click(function(e) {
$('#dialogDeleteIgnoredSite').modal('hide');
- const $url = $('#dialogDeleteIgnoredSite').data('url');
- const $trId = $('#dialogDeleteIgnoredSite').data('tr-id');
- $('#tab-ignored-sites #' + $trId).remove();
+ const url = $('#dialogDeleteIgnoredSite').data('url');
+ const trId = $('#dialogDeleteIgnoredSite').data('tr-id');
+ $('#tab-ignored-sites #' + trId).remove();
- delete options.settings['ignoredSites'][$url];
+ for (let i = 0; i < options.settings['ignoredSites'].length; ++i) {
+ if (options.settings['ignoredSites'][i].url === url) {
+ options.settings['ignoredSites'].splice(i, 1);
+ }
+ }
options.saveSettings();
if ($('#tab-ignored-sites table tbody:first tr').length > 2) {
@@ -288,19 +335,22 @@ options.initIgnoredSites = function() {
}
});
- const $trClone = $('#tab-ignored-sites table tr.clone:first').clone(true);
- $trClone.removeClass('clone');
+ const trClone = $('#tab-ignored-sites table tr.clone:first').clone(true);
+ trClone.removeClass('clone');
let counter = 1;
- for (let url in options.settings['ignoredSites']) {
- const $tr = $trClone.clone(true);
- $tr.data('url', url);
- $tr.attr('id', 'tr-scf' + counter);
- ++counter;
+ if (options.settings['ignoredSites']){
+ for (let site of options.settings['ignoredSites']) {
+ const tr = trClone.clone(true);
+ tr.data('url', site.url);
+ tr.attr('id', 'tr-scf' + counter);
+ ++counter;
- $tr.children('td:first').text(url);
- $('#tab-ignored-sites table tbody:first').append($tr);
+ tr.children('td:first').text(site.url);
+ tr.children('td:nth-child(3)').children('input[type=checkbox]').attr('checked', site.fullIgnore);
+ $('#tab-ignored-sites table tbody:first').append(tr);
+ }
}
-
+
if ($('#tab-ignored-sites table tbody:first tr').length > 2) {
$('#tab-ignored-sites table tbody:first tr.empty:first').hide();
} else {