mirror of
https://github.com/keepassxreboot/keepassxc-browser.git
synced 2026-03-11 08:54:43 +00:00
Merge 8da82cae66 into c697bcae6b
This commit is contained in:
commit
1f9db49c2c
6 changed files with 212 additions and 67 deletions
|
|
@ -316,7 +316,7 @@ kpxcFill.fillInStringFields = function(fields, stringFields) {
|
|||
|
||||
// Performs Auto-Submit. If filling single credentials is enabled, a 5 second timeout will be needed for fill
|
||||
kpxcFill.performAutoSubmit = async function(combination, skipAutoSubmit) {
|
||||
if (!kpxc.settings.autoSubmit) {
|
||||
if (!kpxc.settings.autoSubmit && !kpxc.preferencesForPage?.autoSubmit) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ kpxc.detectedFields = 0;
|
|||
kpxc.improvedFieldDetectionEnabledForPage = false;
|
||||
kpxc.inputs = [];
|
||||
kpxc.settings = {};
|
||||
kpxc.preferencesForPage = null;
|
||||
kpxc.singleInputEnabledForPage = false;
|
||||
kpxc.submitUrl = null;
|
||||
kpxc.url = null;
|
||||
|
|
@ -506,15 +507,38 @@ kpxc.prepareCredentials = async function() {
|
|||
return;
|
||||
}
|
||||
|
||||
if (kpxc.settings.autoFillSingleEntry && kpxc.credentials.length === 1) {
|
||||
if (kpxc.credentials.length === 1) {
|
||||
if (kpxc.preferencesForPage?.autoFillSingleEntry || kpxc.settings.autoFillSingleEntry) {
|
||||
kpxcFill.fillFromAutofill();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
kpxc.initLoginPopup();
|
||||
kpxc.initAutocomplete();
|
||||
};
|
||||
|
||||
kpxc.retrieveSitePreference = function() {
|
||||
// Check for autofill site preferences
|
||||
for (const site of kpxc.settings.sitePreferences) {
|
||||
let currentLocation;
|
||||
try {
|
||||
currentLocation = window.top.location.href;
|
||||
} catch (err) {
|
||||
// Cross-domain security error inspecting window.top.location.href.
|
||||
// This catches an error when an iframe is being accessed from another (sub)domain
|
||||
// -> use the iframe URL instead.
|
||||
currentLocation = window.self.location.href;
|
||||
}
|
||||
|
||||
if (siteMatch(site.url, currentLocation) || site.url === currentLocation) {
|
||||
return site;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the credential list and shows the update banner
|
||||
* @param {string} usernameValue Submitted username
|
||||
|
|
@ -958,6 +982,7 @@ const initContentScript = async function() {
|
|||
}
|
||||
|
||||
kpxc.settings = settings;
|
||||
kpxc.preferencesForPage = kpxc.retrieveSitePreference();
|
||||
|
||||
if (await kpxc.siteIgnored()) {
|
||||
logDebug('This site is ignored in Site Preferences.');
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ class TOTPFieldIcon extends Icon {
|
|||
|
||||
// Fill TOTP automatically if option is enabled
|
||||
TOTPFieldIcon.prototype.autoFillSingleTotp = async function(field) {
|
||||
if (kpxc.settings.autoFillSingleTotp) {
|
||||
if (kpxc.preferencesForPage?.autoFillSingleTotp || kpxc.settings.autoFillSingleTotp) {
|
||||
if (kpxc.credentials.length === 0) {
|
||||
await kpxc.receiveCredentialsIfNecessary();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ body {
|
|||
background-color: var(--kpxc-background-color);
|
||||
color: var(--kpxc-text-color);
|
||||
font-size: 14px;
|
||||
max-width: 1440px;
|
||||
}
|
||||
|
||||
a {
|
||||
|
|
@ -123,7 +122,7 @@ table tbody tr.empty:not(:nth-last-child(2)) {
|
|||
|
||||
#tab-site-preferences td:nth-of-type(2),
|
||||
#tab-site-preferences td:nth-of-type(2) select {
|
||||
width: 200px;
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
#tab-site-preferences td:nth-of-type(3),
|
||||
|
|
@ -227,8 +226,44 @@ table td:last-of-type {
|
|||
.sidebar {
|
||||
width: 240px;
|
||||
}
|
||||
|
||||
main {
|
||||
margin-left: 240px !important;
|
||||
min-width: calc(0.8333333333 * 1440px) !important;
|
||||
max-width: calc(100% - 240px) !important;
|
||||
width: unset !important;
|
||||
}
|
||||
|
||||
footer {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.form-text, .form-group {
|
||||
max-width: calc(0.8333333333 * 1440px);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#sitePreferencesTable > li > details > summary {
|
||||
list-style: none;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
#sitePreferencesTable > li > details > summary::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#sitePreferencesTable > li > details > summary > div > div:first-child{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#sitePreferencesTable > li > details > summary > div > div:first-child::before {
|
||||
content: '►';
|
||||
padding-right: 1rem;
|
||||
}
|
||||
|
||||
#sitePreferencesTable > li > details[open] > summary > div > div:first-child::before {
|
||||
content: '▼';
|
||||
padding-right: 1rem;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -731,45 +731,107 @@
|
|||
<span class="invalid-feedback d-block" data-i18n="optionsSitePreferencesManualAddHelp"></span>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-sm table-striped table-bordered">
|
||||
<div class="table-responsive mt-3">
|
||||
<ul id="sitePreferencesTable" class="list-group list-group-flush">
|
||||
<caption data-i18n="optionsSitePreferencesTableCaption"></caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col"><span data-i18n="optionsColumnPageURL"></span></th>
|
||||
<th scope="col"><span data-i18n="optionsColumnIgnore"></span></th>
|
||||
<th scope="col"><span data-i18n="optionsColumnUsernameOnly"></span></th>
|
||||
<th scope="col"><span data-i18n="optionsColumnImprovedInputFieldDetection"></span></th>
|
||||
<th scope="col"><span data-i18n="optionsColumnAllowIframes"></span></th>
|
||||
<th scope="col"><span data-i18n="optionsColumnDelete"></span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="empty">
|
||||
<td colspan="5"><span data-i18n="optionsSitePreferencesNotFound"></span></td>
|
||||
</tr>
|
||||
<tr class="clone d-none">
|
||||
<td class="text-nowrap"></td>
|
||||
<td>
|
||||
<select class="form-select form-select-sm" name="ignore" data-i18n="[title]optionsSitePreferencesSelect">
|
||||
<option value="ignoreNothing" data-i18n="optionsSelectionNothing"></option>
|
||||
<option value="ignoreNormal" data-i18n="optionsSelectionNormal"></option>
|
||||
<option value="ignoreAutoSubmit" data-i18n="optionsSelectionAutoSubmit"></option>
|
||||
<option value="ignoreFull" data-i18n="optionsSelectionFull"></option>
|
||||
</select>
|
||||
</td>
|
||||
<td><input class="form-check-input" type="checkbox" name="usernameOnly" value="false" data-i18n="[title]optionsColumnUsernameOnly"></td>
|
||||
<td><input class="form-check-input" type="checkbox" name="improvedFieldDetection" value="false" data-i18n="[title]optionsColumnImprovedInputFieldDetection"></td>
|
||||
<td><input class="form-check-input" type="checkbox" name="allowIframes" value="false" data-i18n="[title]optionsColumnAllowIframes"></td>
|
||||
<td class="text-nowrap">
|
||||
<button class="btn btn-sm delete btn-danger btn" data-i18n="[title]removeSitePreferencesButtonTitle">
|
||||
<i class="fa fa-remove" aria-hidden="true"></i>
|
||||
<span data-i18n="optionsButtonRemove"></span>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<li class="empty list-group-item">
|
||||
<span data-i18n="optionsSitePreferencesNotFound"></span>
|
||||
</li>
|
||||
|
||||
<!-- Template row -->
|
||||
<li class="clone d-none list-group-item">
|
||||
<details>
|
||||
<summary>
|
||||
<div class="row justify-content-between">
|
||||
<!-- Text field for the URL -->
|
||||
<div class="col-auto pe-0" style="word-break: break-all;"></div>
|
||||
|
||||
<!-- Delete button -->
|
||||
<div class="col-auto" style="margin-left: auto;">
|
||||
<button id="deleteButton" class="btn btn-sm delete btn-danger btn" data-i18n="[title]removeSitePreferencesButtonTitle">
|
||||
<i class="fa fa-remove" aria-hidden="true"></i>
|
||||
<span data-i18n="optionsButtonRemove"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</summary>
|
||||
|
||||
<!-- Site preference settings -->
|
||||
<div class="container m-3">
|
||||
<div class="row align-items-start gx-5">
|
||||
<!-- Ignore settings -->
|
||||
<div class="col-auto">
|
||||
<div class="form-group mb-3">
|
||||
<label for="ignore" class="form-label" data-i18n="optionsColumnIgnore"></label>
|
||||
<select class="form-select" id="ignore" name="ignore" data-i18n="[title]optionsSitePreferencesSelect">
|
||||
<option value="ignoreNothing" data-i18n="optionsSelectionNothing"></option>
|
||||
<option value="ignoreNormal" data-i18n="optionsSelectionNormal"></option>
|
||||
<option value="ignoreAutoSubmit" data-i18n="optionsSelectionAutoSubmit"></option>
|
||||
<option value="ignoreFull" data-i18n="optionsSelectionFull"></option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Filling credentials -->
|
||||
<div class="col-auto">
|
||||
<!-- Username only detection -->
|
||||
<div class="form-group">
|
||||
<div class="form-check">
|
||||
<label for="usernameOnly" data-i18n="optionsColumnUsernameOnly"></label>
|
||||
<input class="form-check-input" type="checkbox" id="usernameOnly" name="usernameOnly" value="false" data-i18n="[title]optionsColumnUsernameOnly">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Improved input field detection -->
|
||||
<div class="form-group">
|
||||
<div class="form-check">
|
||||
<label for="improvedFieldDetection" data-i18n="optionsColumnImprovedInputFieldDetection"></label>
|
||||
<input class="form-check-input" type="checkbox" id="improvedFieldDetection" name="improvedFieldDetection" value="false" data-i18n="[title]optionsColumnImprovedInputFieldDetection">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Allow iFrames -->
|
||||
<div class="form-group">
|
||||
<div class="form-check">
|
||||
<label for="allowIframes" data-i18n="optionsColumnAllowIframes"></label>
|
||||
<input class="form-check-input" type="checkbox" id="allowIframes" name="allowIframes" value="false" data-i18n="[title]optionsColumnAllowIframes">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Filling credentials -->
|
||||
<div class="col-auto">
|
||||
|
||||
<!-- Use Auto-Submit -->
|
||||
<div class="form-group">
|
||||
<div class="form-check" data-i18n="[title]optionsAutoSubmitHelpText">
|
||||
<label for="autoSubmit" data-i18n="optionsCheckboxAutoSubmit"></label>
|
||||
<input class="form-check-input" type="checkbox" id="autoSubmit" name="autoSubmit" value="false" data-i18n="[title]optionsAutoSubmitHelpText">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Automatically fill single-credential entries -->
|
||||
<div class="form-group">
|
||||
<div class="form-check" data-i18n="[title]optionsAutoFillSingleEntryHelpText">
|
||||
<label for="autoFillSingleEntry" data-i18n="optionsCheckboxAutoFillSingleEntry"></label>
|
||||
<input class="form-check-input" type="checkbox" id="autoFillSingleEntry" name="autoFillSingleEntry" value="false" data-i18n="[title]optionsAutoFillSingleEntryHelpText">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Automatically fill single-credential TOTP fields -->
|
||||
<div class="form-group">
|
||||
<div class="form-check" data-i18n="[title]optionsAutoFillSingleTotpHelpText">
|
||||
<label for="autoFillSingleTotp" data-i18n="optionsCheckboxAutoFillSingleTotp"></label>
|
||||
<input class="form-check-input" type="checkbox" id="autoFillSingleTotp" name="autoFillSingleTotp" value="false" data-i18n="[title]optionsAutoFillSingleTotpHelpText">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div id="dialogDeleteSite" class="modal fade" tabindex="-1" role="dialog">
|
||||
|
|
|
|||
|
|
@ -517,17 +517,17 @@ options.initSitePreferences = function() {
|
|||
const removeButtonClicked = function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const closestTr = this.closest('tr');
|
||||
$('#dialogDeleteSite').setAttribute('url', closestTr.getAttribute('url'));
|
||||
$('#dialogDeleteSite').setAttribute('tr-id', closestTr.getAttribute('id'));
|
||||
$('#dialogDeleteSite .modal-body strong').textContent = closestTr.children[0].textContent;
|
||||
const closestLi = this.closest('li');
|
||||
$('#dialogDeleteSite').setAttribute('url', closestLi.getAttribute('url'));
|
||||
$('#dialogDeleteSite').setAttribute('tr-id', closestLi.getAttribute('id'));
|
||||
$('#dialogDeleteSite .modal-body strong').textContent = closestLi.children[0].children[0].children[0].children[0].textContent;
|
||||
|
||||
dialogDeleteSiteModal.show();
|
||||
};
|
||||
|
||||
const checkboxClicked = function() {
|
||||
const closestTr = this.closest('tr');
|
||||
const url = closestTr.getAttribute('url');
|
||||
const closestLi = this.closest('li');
|
||||
const url = closestLi.getAttribute('url');
|
||||
|
||||
for (const site of options.settings['sitePreferences']) {
|
||||
if (site.url === url) {
|
||||
|
|
@ -537,6 +537,12 @@ options.initSitePreferences = function() {
|
|||
site.improvedFieldDetection = this.checked;
|
||||
} else if (this.name === 'allowIframes') {
|
||||
site.allowIframes = this.checked;
|
||||
} else if (this.name === 'autoSubmit') {
|
||||
site.autoSubmit = this.checked;
|
||||
} else if (this.name === 'autoFillSingleEntry') {
|
||||
site.autoFillSingleEntry = this.checked;
|
||||
} else if (this.name === 'autoFillSingleTotp') {
|
||||
site.autoFillSingleTotp = this.checked;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -545,8 +551,8 @@ options.initSitePreferences = function() {
|
|||
};
|
||||
|
||||
const selectionChanged = function() {
|
||||
const closestTr = this.closest('tr');
|
||||
const url = closestTr.getAttribute('url');
|
||||
const closestLi = this.closest('li');
|
||||
const url = closestLi.getAttribute('url');
|
||||
|
||||
for (const site of options.settings['sitePreferences']) {
|
||||
if (site.url === url) {
|
||||
|
|
@ -557,22 +563,30 @@ options.initSitePreferences = function() {
|
|||
options.saveSettings();
|
||||
};
|
||||
|
||||
const addNewRow = function(rowClone, newIndex, url, ignore, usernameOnly, improvedFieldDetection, allowIframes) {
|
||||
const addNewRow = function(rowClone, newIndex, url, ignore, usernameOnly, improvedFieldDetection, allowIframes, autoSubmit, autoFillSingleEntry, autoFillSingleTotp) {
|
||||
const row = rowClone.cloneNode(true);
|
||||
row.setAttribute('url', url);
|
||||
row.setAttribute('id', 'tr-scf' + newIndex);
|
||||
row.children[0].textContent = url;
|
||||
row.children[1].children[0].value = ignore;
|
||||
row.children[1].children[0].addEventListener('change', selectionChanged);
|
||||
row.children[2].children['usernameOnly'].checked = usernameOnly;
|
||||
row.children[2].children['usernameOnly'].addEventListener('change', checkboxClicked);
|
||||
row.children[3].children['improvedFieldDetection'].checked = improvedFieldDetection;
|
||||
row.children[3].children['improvedFieldDetection'].addEventListener('change', checkboxClicked);
|
||||
row.children[4].children['allowIframes'].checked = allowIframes;
|
||||
row.children[4].children['allowIframes'].addEventListener('change', checkboxClicked);
|
||||
row.children[5].addEventListener('click', removeButtonClicked);
|
||||
|
||||
$('#tab-site-preferences table tbody').append(row);
|
||||
const details = row.children[0];
|
||||
details.children[0].children[0].children[0].textContent = url;
|
||||
details.querySelector('#ignore').value = ignore;
|
||||
details.querySelector('#ignore').addEventListener('change', selectionChanged);
|
||||
details.querySelector('#usernameOnly').checked = usernameOnly;
|
||||
details.querySelector('#usernameOnly').addEventListener('change', checkboxClicked);
|
||||
details.querySelector('#improvedFieldDetection').checked = improvedFieldDetection;
|
||||
details.querySelector('#improvedFieldDetection').addEventListener('change', checkboxClicked);
|
||||
details.querySelector('#allowIframes').checked = allowIframes;
|
||||
details.querySelector('#allowIframes').addEventListener('change', checkboxClicked);
|
||||
details.querySelector('#autoSubmit').checked = autoSubmit;
|
||||
details.querySelector('#autoSubmit').addEventListener('change', checkboxClicked);
|
||||
details.querySelector('#autoFillSingleEntry').checked = autoFillSingleEntry;
|
||||
details.querySelector('#autoFillSingleEntry').addEventListener('change', checkboxClicked);
|
||||
details.querySelector('#autoFillSingleTotp').checked = autoFillSingleTotp;
|
||||
details.querySelector('#autoFillSingleTotp').addEventListener('change', checkboxClicked);
|
||||
details.querySelector('#deleteButton').addEventListener('click', removeButtonClicked);
|
||||
|
||||
$('#tab-site-preferences #sitePreferencesTable').append(row);
|
||||
};
|
||||
|
||||
$('#dialogDeleteSite .modal-footer button.yes').addEventListener('click', function(e) {
|
||||
|
|
@ -627,11 +641,13 @@ options.initSitePreferences = function() {
|
|||
}
|
||||
|
||||
const newIndex = options.settings['sitePreferences'].length + 1;
|
||||
const rowClone = $('#tab-site-preferences table tr.clone').cloneNode(true);
|
||||
const rowClone = $('#tab-site-preferences #sitePreferencesTable li.clone').cloneNode(true);
|
||||
rowClone.classList.remove('clone', 'd-none');
|
||||
|
||||
addNewRow(rowClone, newIndex, value, IGNORE_NOTHING, false, false, false);
|
||||
$('#tab-site-preferences table tbody tr.empty').hide();
|
||||
|
||||
addNewRow(rowClone, newIndex, value, IGNORE_NOTHING, false, false, false, false, false, false);
|
||||
$('#tab-site-preferences #sitePreferencesTable li.empty').hide();
|
||||
|
||||
|
||||
options.settings['sitePreferences'].push({
|
||||
url: value,
|
||||
|
|
@ -644,7 +660,7 @@ options.initSitePreferences = function() {
|
|||
manualUrl.value = '';
|
||||
});
|
||||
|
||||
const rowClone = $('#tab-site-preferences table tr.clone').cloneNode(true);
|
||||
const rowClone = $('#tab-site-preferences ul li.clone').cloneNode(true);
|
||||
rowClone.classList.remove('clone', 'd-none');
|
||||
let counter = 1;
|
||||
if (options.settings['sitePreferences']) {
|
||||
|
|
@ -657,10 +673,17 @@ options.initSitePreferences = function() {
|
|||
site.usernameOnly,
|
||||
site.improvedFieldDetection,
|
||||
site.allowIframes,
|
||||
site.autoSubmit,
|
||||
site.autoFillSingleEntry,
|
||||
site.autoFillSingleTotp,
|
||||
);
|
||||
++counter;
|
||||
}
|
||||
}
|
||||
|
||||
if (counter > 1) {
|
||||
$('#tab-site-preferences #sitePreferencesTable li.empty').hide();
|
||||
}
|
||||
};
|
||||
|
||||
options.initAbout = function() {
|
||||
|
|
|
|||
Loading…
Reference in a new issue