mirror of
https://github.com/keepassxreboot/keepassxc-browser.git
synced 2026-03-11 08:54:43 +00:00
Improvements to Ignored Sites
This commit is contained in:
parent
15b889fa78
commit
057a86e929
6 changed files with 211 additions and 51 deletions
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
};
|
||||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -297,21 +297,36 @@
|
|||
Sites in this list are ignored when new credentials are detected.
|
||||
<br />
|
||||
Go to the page with new credentials, click the blinking KeePassXC-Browser icon or the notification and select <em>Never ask for this page</em>.
|
||||
<br />
|
||||
If full ignore is enabled, no input fields are detected and no credentials are received for that site.
|
||||
</p>
|
||||
<hr />
|
||||
<div class="form-group">
|
||||
<label for="ignoreManualAdd">Add URL manually:</label>
|
||||
<div class="control-group">
|
||||
<div class="input-append">
|
||||
<input type="url" id="ignoreUrl"/>
|
||||
<button class="btn btn-sm btn-primary" id="ignoreManualAddButton" type="button"><span class="glyphicon glyphicon-plus-sign"></span> Add</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<table class="table table-striped table-bordered table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Page URL</th>
|
||||
<th>Delete</th>
|
||||
<th>Full ignore</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="empty">
|
||||
<td colspan="2">No ignored sites found.</td>
|
||||
<td colspan="3">No ignored sites found.</td>
|
||||
</tr>
|
||||
<tr class="clone">
|
||||
<td></td>
|
||||
<td><button class="btn delete btn-danger btn"><span class="glyphicon glyphicon-remove-sign"></span> Remove</button></td>
|
||||
<td><input type="checkbox" name="fullIgnore" value="false" /></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Reference in a new issue