From fd9e01985d007d294b7cbbc6b69f8538261d1b2a Mon Sep 17 00:00:00 2001 From: varjolintu Date: Fri, 11 May 2018 11:44:32 +0300 Subject: [PATCH 01/34] Fix save domain only option --- keepassxc-browser/keepassxc-browser.js | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/keepassxc-browser/keepassxc-browser.js b/keepassxc-browser/keepassxc-browser.js index 490f675..245667e 100755 --- a/keepassxc-browser/keepassxc-browser.js +++ b/keepassxc-browser/keepassxc-browser.js @@ -632,7 +632,8 @@ cipDefine.initDescription = function() { fieldIds.push(cipFields.prepareId(i)); } - cip.settings['defined-credential-fields'][document.location.href] = { + const location = cip.getDocumentLocation(); + cip.settings['defined-credential-fields'][location] = { username: cipDefine.selection.username, password: cipDefine.selection.password, fields: fieldIds @@ -652,7 +653,8 @@ cipDefine.initDescription = function() { $description.append($btnAgain); $description.append($btnDismiss); - if (cip.settings['defined-credential-fields'] && cip.settings['defined-credential-fields'][document.location.href]) { + const location = cip.getDocumentLocation(); + if (cip.settings['defined-credential-fields'] && cip.settings['defined-credential-fields'][location]) { const $p = jQuery('

').html('For this page credential fields are already selected and will be overwritten.
'); const $btnDiscard = jQuery(' + + + +


+ - + +
Page URL DeleteFull ignore
No ignored sites found.No ignored sites found.
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 { From 43c5cfcafcef91f5231295ebeb6491aa94bb29b4 Mon Sep 17 00:00:00 2001 From: varjolintu Date: Fri, 25 May 2018 15:03:22 +0300 Subject: [PATCH 10/34] Improved field ignore --- keepassxc-browser/keepassxc-browser.js | 49 ++++++++++++++++++++------ 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/keepassxc-browser/keepassxc-browser.js b/keepassxc-browser/keepassxc-browser.js index cc0408e..dc1771a 100755 --- a/keepassxc-browser/keepassxc-browser.js +++ b/keepassxc-browser/keepassxc-browser.js @@ -741,7 +741,7 @@ cipDefine.markFields = function ($chooser, $pattern) { return true; } - if (jQuery(this).is(':visible') && jQuery(this).css('visibility') !== 'hidden' && jQuery(this).css('visibility') !== 'collapsed') { + if (cipFields.isVisible(this)) { const $field = jQuery('
').addClass('b2c-fixed-field') .css('top', jQuery(this).offset().top) .css('left', jQuery(this).offset().left) @@ -821,9 +821,20 @@ cipFields.prepareId = function(id) { // Check aria-hidden attribute by looping the parent elements of input field cipFields.getAriaHidden = function(field) { - let $par = jQuery(field).parents(); - for (const p of $par) { - const val = $(p).attr('aria-hidden'); + // Check the main element + const val = field.getAttribute('aria-hidden'); + if (val) { + return val; + } + + // Check parents + let parents = []; + while (field.parentElement) { + parents.push(field = field.parentElement); + } + + for (const p of parents) { + const val = p.getAttribute('aria-hidden'); if (val) { return val; } @@ -842,18 +853,36 @@ cipFields.getOverflowHidden = function(field) { return false; }; +cipFields.isVisible = function(field) { + const rect = field.getBoundingClientRect(); + + // Check CSS visibility + if (field.style.visibility && (field.style.visibility === 'hidden' || field.style.visibility === 'collapse')) { + return false; + } + + // Check element position and size + if (rect.x < 0 || rect.y < 0 || rect.width < 16 || rect.height < 16) { + return false; + } + + // Check aria-hidden property + if (cipFields.getAriaHidden(field) !== 'false') { + return false; + } + + return true; +}; + cipFields.getAllFields = function() { let fields = []; const inputs = cipObserverHelper.getInputs(document); for (const i of inputs) { - const ariaHidden = cipFields.getAriaHidden(i); - const overflowHidden = cipFields.getOverflowHidden(i); - - if (jQuery(i).is(':visible') && jQuery(i).css('visibility') !== 'hidden' && jQuery(i).css('visibility') !== 'collapsed' && ariaHidden === 'false') { + if (cipFields.isVisible(i)) { cipFields.setUniqueId(jQuery(i)); fields.push(jQuery(i)); } - } + }; _detectedFields = fields.length; return fields; @@ -861,7 +890,7 @@ cipFields.getAllFields = function() { cipFields.prepareVisibleFieldsWithID = function($pattern) { jQuery($pattern).each(function() { - if (jQuery(this).is(':visible') && jQuery(this).css('visibility') !== 'hidden' && jQuery(this).css('visibility') !== 'collapsed') { + if (cipField.isVisible(this)) { cipFields.setUniqueId(jQuery(this)); } }); From b84e5b6611500288a37ed5c51a18e4084d73f8a4 Mon Sep 17 00:00:00 2001 From: varjolintu Date: Fri, 8 Jun 2018 12:38:18 +0300 Subject: [PATCH 11/34] Add check to page tab ID --- keepassxc-browser/background/page.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/keepassxc-browser/background/page.js b/keepassxc-browser/background/page.js index 20995cb..f56ebac 100755 --- a/keepassxc-browser/background/page.js +++ b/keepassxc-browser/background/page.js @@ -105,6 +105,10 @@ page.clearCredentials = function(tabId, complete) { }; page.clearLogins = function(tabId) { + if (!page.tabs[tabId]) { + return; + } + page.tabs[tabId].loginList = []; }; From cd56d832afb10721a3e55b00c9066a158f961ffb Mon Sep 17 00:00:00 2001 From: varjolintu Date: Sun, 10 Jun 2018 10:53:35 +0300 Subject: [PATCH 12/34] Ignore comment nodes --- keepassxc-browser/keepassxc-browser.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/keepassxc-browser/keepassxc-browser.js b/keepassxc-browser/keepassxc-browser.js index dc1771a..8928004 100755 --- a/keepassxc-browser/keepassxc-browser.js +++ b/keepassxc-browser/keepassxc-browser.js @@ -1180,7 +1180,7 @@ cipObserverHelper.inputTypes = [ ]; cipObserverHelper.getInputs = function(target) { - if (target.nodeType === Node.TEXT_NODE) { + if (target.nodeType === Node.TEXT_NODE || target.nodeType === Node.COMMENT_NODE) { return []; } From 1217769e6789bde8b6ffcde8a2a5f3e8fa495f41 Mon Sep 17 00:00:00 2001 From: Janek Bevendorff Date: Sun, 10 Jun 2018 14:33:32 +0200 Subject: [PATCH 13/34] Version 1.1.4 --- CHANGELOG | 11 +++++++++++ keepassxc-browser/manifest.json | 4 ++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 4c27d13..55e8446 100755 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,14 @@ +1.1.4 (10-06-2018) +========================= +- Improve performance of field detection and limit it to 100 fields [#166,#157,185] +- Improve option to ignore fields [#170] +- Automatically retrieve credentials after unlocking the database [#153] +- Fix option to only save the domain name not working as intended [#151] +- Fix credentials popup not being shown on some websites [#154] +- Improve detection of username fields [#164] +- Allow filling of TOTP fields when they are on a separate page [#162] +- Ignore invisible input fields more strictly [#176] + 1.1.3 (11-05-2018) ========================= - Remove autoreconnect to prevent proxy process leakage on Windows [#147] diff --git a/keepassxc-browser/manifest.json b/keepassxc-browser/manifest.json index 6c80b76..31cc3d5 100755 --- a/keepassxc-browser/manifest.json +++ b/keepassxc-browser/manifest.json @@ -1,8 +1,8 @@ { "manifest_version": 2, "name": "KeePassXC-Browser", - "version": "1.1.3", - "version_name": "1.1.3", + "version": "1.1.4", + "version_name": "1.1.4", "description": "KeePassXC integration for modern web browsers", "author": "KeePassXC Team", "icons": { From 78e2b81d37b37b6ed304c984b39959681b0615fb Mon Sep 17 00:00:00 2001 From: varjolintu Date: Mon, 11 Jun 2018 13:18:15 +0300 Subject: [PATCH 14/34] Ignore search fields --- keepassxc-browser/keepassxc-browser.js | 67 ++++++++++++++++++-------- 1 file changed, 47 insertions(+), 20 deletions(-) diff --git a/keepassxc-browser/keepassxc-browser.js b/keepassxc-browser/keepassxc-browser.js index 8928004..311f1af 100755 --- a/keepassxc-browser/keepassxc-browser.js +++ b/keepassxc-browser/keepassxc-browser.js @@ -819,7 +819,22 @@ cipFields.prepareId = function(id) { return id.replace(/[:#.,\[\]\(\)' "]/g, function(m) { return '\\'+m; }); }; -// Check aria-hidden attribute by looping the parent elements of input field +/** + * Returns the first parent element satifying the {@code predicate} mapped by {@code resultFn} or else {@code defaultVal}. + * @param {HTMLElement} element The start element (excluded, starting with the parents) + * @param {function} predicate Matcher for the element to find, type (HTMLElement) => boolean + * @param {function} resultFn Callback function of type (HTMLElement) => {*} called for the first matching element + * @param {fun} defaultValFn Fallback return value supplier, if no element matching the predicate can be found + */ +cipFields.traverseParents = function(element, predicate, resultFn = () => true, defaultValFn = () => false) { + for (let f = element.parentElement; f !== null; f = f.parentElement) { + if (predicate(f)) { + return resultFn(f); + } + } + return defaultValFn(); +}; + cipFields.getAriaHidden = function(field) { // Check the main element const val = field.getAttribute('aria-hidden'); @@ -827,29 +842,41 @@ cipFields.getAriaHidden = function(field) { return val; } - // Check parents - let parents = []; - while (field.parentElement) { - parents.push(field = field.parentElement); - } - - for (const p of parents) { - const val = p.getAttribute('aria-hidden'); - if (val) { - return val; - } - } - return 'false'; + const ariaFunc = f => f.getAttribute('aria-hidden'); + return cipFields.traverseParents(field, ariaFunc, ariaFunc, () => 'false'); }; cipFields.getOverflowHidden = function(field) { - let $par = jQuery(field).parents(); - for (const p of $par) { - const val = $(p).css('overflow'); - if (val === 'hidden') { + return cipFields.traverseParents(field, f => f.style.overflow === 'hidden'); +}; + + +// Checks if input field is a search field. Attributes or form action containing 'search', or parent element holding +// role="search" will be identified as a search field. +cipFields.isSearchField = function(target) { + const attributes = target.attributes; + + // Check element attributes + for (const attr of attributes) { + if ((attr.value && (attr.value.toLowerCase().includes('search')) || attr.value === 'q')) { return true; } } + + // Check form action + const closestForm = target.closest('form'); + const formAction = closestForm ? closestForm.getAttribute('action') : null; + if (formAction && formAction.includes('search')) { + return true; + } + + // Check parent elements for role="search" + const roleFunc = f => f.getAttribute('role'); + const roleValue = cipFields.traverseParents(target, roleFunc, roleFunc, () => null); + if (roleValue && roleValue === 'search') { + return true; + } + return false; }; @@ -878,7 +905,7 @@ cipFields.getAllFields = function() { let fields = []; const inputs = cipObserverHelper.getInputs(document); for (const i of inputs) { - if (cipFields.isVisible(i)) { + if (cipFields.isVisible(i) && !cipFields.isSearchField(i)) { cipFields.setUniqueId(jQuery(i)); fields.push(jQuery(i)); } @@ -890,7 +917,7 @@ cipFields.getAllFields = function() { cipFields.prepareVisibleFieldsWithID = function($pattern) { jQuery($pattern).each(function() { - if (cipField.isVisible(this)) { + if (cipFields.isVisible(this) && !cipFields.isSearchField(this)) { cipFields.setUniqueId(jQuery(this)); } }); From f3ed86b971f6173ce5d014ae4e8450f68e1d339d Mon Sep 17 00:00:00 2001 From: Janek Bevendorff Date: Mon, 11 Jun 2018 22:45:41 +0200 Subject: [PATCH 15/34] Version 1.1.5 --- CHANGELOG | 4 ++++ keepassxc-browser/manifest.json | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 55e8446..3616294 100755 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,7 @@ +1.1.5 (11-06-2018) +========================= +- Fix search fields being detected as username fields [#189] + 1.1.4 (10-06-2018) ========================= - Improve performance of field detection and limit it to 100 fields [#166,#157,185] diff --git a/keepassxc-browser/manifest.json b/keepassxc-browser/manifest.json index 31cc3d5..78d3d4f 100755 --- a/keepassxc-browser/manifest.json +++ b/keepassxc-browser/manifest.json @@ -1,8 +1,8 @@ { "manifest_version": 2, "name": "KeePassXC-Browser", - "version": "1.1.4", - "version_name": "1.1.4", + "version": "1.1.5", + "version_name": "1.1.5", "description": "KeePassXC integration for modern web browsers", "author": "KeePassXC Team", "icons": { From 595a2601b9da7098bc2aa8084f67fb81bb0ddccb Mon Sep 17 00:00:00 2001 From: varjolintu Date: Tue, 12 Jun 2018 10:05:49 +0300 Subject: [PATCH 16/34] Disable single inputs --- keepassxc-browser/keepassxc-browser.js | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/keepassxc-browser/keepassxc-browser.js b/keepassxc-browser/keepassxc-browser.js index 311f1af..f85cf2a 100755 --- a/keepassxc-browser/keepassxc-browser.js +++ b/keepassxc-browser/keepassxc-browser.js @@ -6,6 +6,7 @@ _called.retrieveCredentials = false; _called.clearLogins = false; _called.manualFillRequested = 'none'; let _loginId = -1; +let _singleInputEnabledForPage = false; const _maximumInputs = 100; // Count of detected form fields on the page @@ -502,7 +503,7 @@ cipForm.init = function(form, credentialFields) { // TODO: could be called multiple times --> update credentialFields // not already initialized && password-field is not null - if (!form.data('cipForm-initialized') && (credentialFields.password || credentialFields.username)) { + if (!form.data('cipForm-initialized') && (credentialFields.password || (_singleInputEnabledForPage && credentialFields.username))) { form.data('cipForm-initialized', true); cipForm.setInputFields(form, credentialFields); form.submit(cipForm.onSubmit); @@ -884,7 +885,8 @@ cipFields.isVisible = function(field) { const rect = field.getBoundingClientRect(); // Check CSS visibility - if (field.style.visibility && (field.style.visibility === 'hidden' || field.style.visibility === 'collapse')) { + const fieldStyle = getComputedStyle(field); + if (fieldStyle.visibility && (fieldStyle.visibility === 'hidden' || fieldStyle.visibility === 'collapse')) { return false; } @@ -948,7 +950,7 @@ cipFields.getAllCombinations = function(inputs) { } } - if (fields.length === 0 && uField) { + if (_singleInputEnabledForPage && fields.length === 0 && uField) { const combination = { username: uField[0].getAttribute('data-cip-id'), password: null @@ -1230,6 +1232,10 @@ cipObserverHelper.getId = function(target) { }; cipObserverHelper.handleObserverAdd = function(target) { + if (target.className && (target.className.includes('kpxc') || target.className.includes('ui-helper'))) { + return; + } + const inputs = cipObserverHelper.getInputs(target); if (inputs.length === 0) { return; @@ -1251,6 +1257,10 @@ cipObserverHelper.handleObserverAdd = function(target) { }; cipObserverHelper.handleObserverRemove = function(target) { + if (target.className && (target.className.includes('kpxc') || target.className.includes('ui-helper'))) { + return; + } + const inputs = cipObserverHelper.getInputs(target); if (inputs.length === 0) { return; @@ -1406,9 +1416,9 @@ cip.initCredentialFields = function(forceCall) { cip.submitUrl = cip.getFormActionUrl(cipFields.combinations[0]); // Get submitUrl for a single input - if (!cip.submitUrl && cipFields.combinations.length === 1 && inputs.length === 1) { + if (_singleInputEnabledForPage && !cip.submitUrl && cipFields.combinations.length === 1 && inputs.length === 1) { cip.submitUrl = cip.getFormActionUrlFromSingleInput(inputs[0]); - } + } if (cip.settings.autoRetrieveCredentials && _called.retrieveCredentials === false && (cip.url && cip.submitUrl)) { browser.runtime.sendMessage({ @@ -1417,8 +1427,6 @@ cip.initCredentialFields = function(forceCall) { }).then(cip.retrieveCredentialsCallback).catch((e) => { console.log(e); }); - } else { - cip.preparePageForMultipleCredentials(cip.credentials); } }); }; From c29a51e141712db675736afb1c0befcde8814748 Mon Sep 17 00:00:00 2001 From: varjolintu Date: Tue, 12 Jun 2018 14:41:09 +0300 Subject: [PATCH 17/34] Add check function for site ignore settings --- keepassxc-browser/keepassxc-browser.js | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/keepassxc-browser/keepassxc-browser.js b/keepassxc-browser/keepassxc-browser.js index 311f1af..c23df33 100755 --- a/keepassxc-browser/keepassxc-browser.js +++ b/keepassxc-browser/keepassxc-browser.js @@ -1373,6 +1373,7 @@ cip.initCredentialFields = function(forceCall) { _called.clearLogins = true; // Ignore sites with full ignore + cip.initializeIgnoredSites(); if (cip.settings.ignoredSites) { for (const site of cip.settings.ignoredSites) { if (site.fullIgnore && siteMatch(site.url, document.location.href)) { @@ -1998,16 +1999,9 @@ cip.ignoreSite = function(sites) { return; } - // 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.initializeIgnoredSites(); const site = sites[0]; - if (!cip.settings['ignoredSites']) { - cip.settings['ignoredSites'] = []; - } - cip.settings['ignoredSites'].push({ url: site, fullIgnore: false @@ -2019,6 +2013,16 @@ cip.ignoreSite = function(sites) { }); }; + // Delete previously created Object if it exists. It will be replaced by an Array +cip.initializeIgnoredSites = function() { + if (cip.settings['ignoredSites'] !== null && cip.settings['ignoredSites'].constructor === Object) { + delete cip.settings['ignoredSites']; + } + + if (!cip.settings['ignoredSites']) { + cip.settings['ignoredSites'] = []; + } +}; cip.getDocumentLocation = function() { return cip.settings.saveDomainOnly ? document.location.origin : document.location.href; From 296a996e0094bc41fa3682ab17cd33775ae52947 Mon Sep 17 00:00:00 2001 From: varjolintu Date: Tue, 12 Jun 2018 18:39:57 +0300 Subject: [PATCH 18/34] Fix getInputs --- keepassxc-browser/keepassxc-browser.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/keepassxc-browser/keepassxc-browser.js b/keepassxc-browser/keepassxc-browser.js index 311f1af..ebe93be 100755 --- a/keepassxc-browser/keepassxc-browser.js +++ b/keepassxc-browser/keepassxc-browser.js @@ -1203,7 +1203,7 @@ cipObserverHelper.inputTypes = [ 'password', 'tel', 'number', - '' + null // Input field can be without any type. Include these to the list. ]; cipObserverHelper.getInputs = function(target) { From a38c77fc80cdac5e0070abc7592fafc29b4443e4 Mon Sep 17 00:00:00 2001 From: Janek Bevendorff Date: Tue, 12 Jun 2018 21:29:03 +0200 Subject: [PATCH 19/34] Version 1.1.6 --- CHANGELOG | 6 ++++++ keepassxc-browser/manifest.json | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 3616294..fb296f9 100755 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,9 @@ +1.1.6 (12-06-2018) +========================= +- Disable single username field detection [#194] +- Fix ignored sites [#196] +- Detect credential fields without type [#198] + 1.1.5 (11-06-2018) ========================= - Fix search fields being detected as username fields [#189] diff --git a/keepassxc-browser/manifest.json b/keepassxc-browser/manifest.json index 78d3d4f..1c08d6a 100755 --- a/keepassxc-browser/manifest.json +++ b/keepassxc-browser/manifest.json @@ -1,8 +1,8 @@ { "manifest_version": 2, "name": "KeePassXC-Browser", - "version": "1.1.5", - "version_name": "1.1.5", + "version": "1.1.6", + "version_name": "1.1.6", "description": "KeePassXC integration for modern web browsers", "author": "KeePassXC Team", "icons": { From 0f1b62d92ebce44393ee5c99fcd6b1bf46e48ea6 Mon Sep 17 00:00:00 2001 From: Janek Bevendorff Date: Tue, 12 Jun 2018 23:30:50 +0200 Subject: [PATCH 20/34] Check for undefined instead of null to fix regression introduced by f9abcb888 --- keepassxc-browser/keepassxc-browser.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/keepassxc-browser/keepassxc-browser.js b/keepassxc-browser/keepassxc-browser.js index 0fdfb45..f2354f4 100755 --- a/keepassxc-browser/keepassxc-browser.js +++ b/keepassxc-browser/keepassxc-browser.js @@ -2023,7 +2023,7 @@ cip.ignoreSite = function(sites) { // Delete previously created Object if it exists. It will be replaced by an Array cip.initializeIgnoredSites = function() { - if (cip.settings['ignoredSites'] !== null && cip.settings['ignoredSites'].constructor === Object) { + if (cip.settings['ignoredSites'] !== undefined && cip.settings['ignoredSites'].constructor === Object) { delete cip.settings['ignoredSites']; } From 00f70716575e7e9528719c5f3504d574b93e8078 Mon Sep 17 00:00:00 2001 From: varjolintu Date: Tue, 12 Jun 2018 12:59:25 +0300 Subject: [PATCH 21/34] Improvements to isSearchField --- keepassxc-browser/keepassxc-browser.js | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/keepassxc-browser/keepassxc-browser.js b/keepassxc-browser/keepassxc-browser.js index 0fdfb45..671e874 100755 --- a/keepassxc-browser/keepassxc-browser.js +++ b/keepassxc-browser/keepassxc-browser.js @@ -864,11 +864,22 @@ cipFields.isSearchField = function(target) { } } - // Check form action + // Check closest form const closestForm = target.closest('form'); - const formAction = closestForm ? closestForm.getAttribute('action') : null; - if (formAction && formAction.includes('search')) { - return true; + if (closestForm) { + // Check form action + const formAction = closestForm.getAttribute('action'); + if (formAction && formAction.includes('search')) { + return true; + } + + // Check form class and id + const closestFormId = closestForm.getAttribute('id'); + const closestFormClass = closestForm.className; + if (closestFormClass && (closestForm.className.toLowerCase().includes('search') || + (closestFormId && closestFormId.toLowerCase().includes('search')))) { + return true; + } } // Check parent elements for role="search" From 6ba29a70f2a53c3b5a0ea31ad37b8f7a1a85533c Mon Sep 17 00:00:00 2001 From: Janek Bevendorff Date: Wed, 13 Jun 2018 08:03:17 +0200 Subject: [PATCH 22/34] Version 1.1.7 --- CHANGELOG | 4 ++++ keepassxc-browser/manifest.json | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index fb296f9..8b52766 100755 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,7 @@ +1.1.7 (13-06-2018) +========================= +- Fix credential field detection regression [#199] + 1.1.6 (12-06-2018) ========================= - Disable single username field detection [#194] diff --git a/keepassxc-browser/manifest.json b/keepassxc-browser/manifest.json index 1c08d6a..093266e 100755 --- a/keepassxc-browser/manifest.json +++ b/keepassxc-browser/manifest.json @@ -1,8 +1,8 @@ { "manifest_version": 2, "name": "KeePassXC-Browser", - "version": "1.1.6", - "version_name": "1.1.6", + "version": "1.1.7", + "version_name": "1.1.7", "description": "KeePassXC integration for modern web browsers", "author": "KeePassXC Team", "icons": { From cff6324c411c0e75b185b69840726bfac07947c8 Mon Sep 17 00:00:00 2001 From: varjolintu Date: Sat, 16 Jun 2018 20:38:03 +0300 Subject: [PATCH 23/34] Fix undefined check --- keepassxc-browser/background/browserAction.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/keepassxc-browser/background/browserAction.js b/keepassxc-browser/background/browserAction.js index 6847bd9..de1efc6 100755 --- a/keepassxc-browser/background/browserAction.js +++ b/keepassxc-browser/background/browserAction.js @@ -206,9 +206,11 @@ 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 of settings.ignoredSites) { - if (siteMatch(site.url, url)) { - return; + if (settings.ignoredSites !== undefined) { + for (const site of settings.ignoredSites) { + if (siteMatch(site.url, url)) { + return; + } } } From 38cf721c5ba27d6ed6e289d985fc45b695be2e58 Mon Sep 17 00:00:00 2001 From: varjolintu Date: Wed, 20 Jun 2018 11:38:52 +0300 Subject: [PATCH 24/34] Ignore SVG elements --- keepassxc-browser/keepassxc-browser.js | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/keepassxc-browser/keepassxc-browser.js b/keepassxc-browser/keepassxc-browser.js index f2354f4..468c221 100755 --- a/keepassxc-browser/keepassxc-browser.js +++ b/keepassxc-browser/keepassxc-browser.js @@ -1231,8 +1231,22 @@ cipObserverHelper.getId = function(target) { return target.classList.length === 0 ? target.id : target.classList; }; -cipObserverHelper.handleObserverAdd = function(target) { +cipObserverHelper.ignoredElement = function(target) { + // Ignore SVG elements + if (target.className && (target.nodeName !== 'svg' || target.parentNode.nodeName !== 'svg')) { + return true; + } + + // Ignore KeePassXC-Browser classes if (target.className && (target.className.includes('kpxc') || target.className.includes('ui-helper'))) { + return true; + } + + return false; +}; + +cipObserverHelper.handleObserverAdd = function(target) { + if (cipObserverHelper.ignoredElement(target)) { return; } @@ -1257,7 +1271,7 @@ cipObserverHelper.handleObserverAdd = function(target) { }; cipObserverHelper.handleObserverRemove = function(target) { - if (target.className && (target.className.includes('kpxc') || target.className.includes('ui-helper'))) { + if (cipObserverHelper.ignoredElement(target)) { return; } From 92cde01e0399ab303e7a9c0bebae729ae2dad442 Mon Sep 17 00:00:00 2001 From: varjolintu Date: Tue, 19 Jun 2018 14:39:20 +0300 Subject: [PATCH 25/34] Ignore nodes which does not contain elements --- keepassxc-browser/keepassxc-browser.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/keepassxc-browser/keepassxc-browser.js b/keepassxc-browser/keepassxc-browser.js index f2354f4..e1ba840 100755 --- a/keepassxc-browser/keepassxc-browser.js +++ b/keepassxc-browser/keepassxc-browser.js @@ -1208,8 +1208,22 @@ cipObserverHelper.inputTypes = [ null // Input field can be without any type. Include these to the list. ]; +// Ignores all nodes that doesn't contain elements +cipObserverHelper.ignoredNode = function(target) { + if (target.nodeType === Node.ATTRIBUTE_NODE || + target.nodeType === Node.TEXT_NODE || + target.nodeType === Node.CDATA_SECTION_NODE || + target.nodeType === Node.PROCESSING_INSTRUCTION_NODE || + target.nodeType === Node.COMMENT_NODE || + target.nodeType === Node.DOCUMENT_TYPE_NODE || + target.nodeType === Node.NOTATION_NODE) { + return true; + } + return false; +}; + cipObserverHelper.getInputs = function(target) { - if (target.nodeType === Node.TEXT_NODE || target.nodeType === Node.COMMENT_NODE) { + if (cipObserverHelper.ignoredNode(target)) { return []; } From 6bb319ce86df1bd2d46d09c2af77cfabaef972b3 Mon Sep 17 00:00:00 2001 From: varjolintu Date: Wed, 20 Jun 2018 14:19:36 +0300 Subject: [PATCH 26/34] Rename Specified credential fields to Custom credential fields --- keepassxc-browser/keepassxc-browser.js | 16 +++---- keepassxc-browser/options/options.html | 22 ++++----- keepassxc-browser/options/options.js | 46 +++++++++---------- keepassxc-browser/popups/popup.html | 2 +- keepassxc-browser/popups/popup_httpauth.html | 2 +- keepassxc-browser/popups/popup_login.html | 2 +- .../popups/popup_multiple-fields.html | 2 +- 7 files changed, 46 insertions(+), 46 deletions(-) diff --git a/keepassxc-browser/keepassxc-browser.js b/keepassxc-browser/keepassxc-browser.js index f2354f4..22cf2fa 100755 --- a/keepassxc-browser/keepassxc-browser.js +++ b/keepassxc-browser/keepassxc-browser.js @@ -620,8 +620,8 @@ cipDefine.initDescription = function() { .addClass('btn').addClass('btn-primary') .css('margin-right', '15px') .click(function(e) { - if (!cip.settings['defined-credential-fields']) { - cip.settings['defined-credential-fields'] = {}; + if (!cip.settings['defined-custom-fields']) { + cip.settings['defined-custom-fields'] = {}; } if (cipDefine.selection.username) { @@ -639,7 +639,7 @@ cipDefine.initDescription = function() { } const location = cip.getDocumentLocation(); - cip.settings['defined-credential-fields'][location] = { + cip.settings['defined-custom-fields'][location] = { username: cipDefine.selection.username, password: cipDefine.selection.password, fields: fieldIds @@ -660,7 +660,7 @@ cipDefine.initDescription = function() { $description.append($btnDismiss); const location = cip.getDocumentLocation(); - if (cip.settings['defined-credential-fields'] && cip.settings['defined-credential-fields'][location]) { + if (cip.settings['defined-custom-fields'] && cip.settings['defined-custom-fields'][location]) { const $p = jQuery('

').html('For this page credential fields are already selected and will be overwritten.
'); const $btnDiscard = jQuery('

- -
-

Specified credential fields

+ +
+

Custom credential fields


If KeePassXC-Browser detects the wrong credential fields, you are able to specify the correct fields by yourself.
- Just go to the page and click on the KeePassXC-Browser-Icon, now select Choose own credential fields for this page. + Go to the page and click on the KeePassXC-Browser-Icon, now select Choose custom credential fields for this page.
- On this page you can manage theses specified credential fields. + On this page you can manage saved custom credential fields.

@@ -261,7 +261,7 @@ - + @@ -269,16 +269,16 @@
No specified credential fields found.No saved custom credential fields found.
-