Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow autofill and autosubmit configuration on a per site basis #2358

Open
wants to merge 16 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion keepassxc-browser/content/fill.js
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,16 @@ 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) {
// Check for site preference overrides
const sitePreference = kpxc.retrieveSitePreference();
let autoSubmitSitePreference = false;
if (sitePreference !== null && sitePreference !== undefined) {
if (sitePreference.autoSubmit === true || sitePreference.autoSubmit === false) {
varjolintu marked this conversation as resolved.
Show resolved Hide resolved
autoSubmitSitePreference = sitePreference.autoSubmit;
}
}

if (!kpxc.settings.autoSubmit && !autoSubmitSitePreference) {
return;
}

Expand Down
34 changes: 33 additions & 1 deletion keepassxc-browser/content/keepassxc-browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -501,15 +501,47 @@ kpxc.prepareCredentials = async function() {
return;
}

if (kpxc.settings.autoFillSingleEntry && kpxc.credentials.length === 1) {
if (kpxc.credentials.length === 1) {
if (kpxc.settings.autoFillSingleEntry) {
kpxcFill.fillFromAutofill();
return;
}

// Check for site preference overrides
const sitePreference = kpxc.retrieveSitePreference();
if (sitePreference !== null && sitePreference !== undefined) {
if (sitePreference.autoFillCredentials === true) {
kpxcFill.fillFromAutofill();
return;
}
}
}

kpxc.initLoginPopup();
kpxc.initAutocomplete();
};

kpxc.retrieveSitePreference = function() {
varjolintu marked this conversation as resolved.
Show resolved Hide resolved
// Check for autofill site preferences
for (const site of kpxc.settings.sitePreferences) {
let currentLocation;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no reason to run this check inside a loop.

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
Expand Down
12 changes: 11 additions & 1 deletion keepassxc-browser/content/totp-field.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,17 @@ class TOTPFieldIcon extends Icon {

// Fill TOTP automatically if option is enabled
TOTPFieldIcon.prototype.autoFillSingleTotp = async function(field) {
if (kpxc.settings.autoFillSingleTotp) {
// Check for site preference overrides
const sitePreference = kpxc.retrieveSitePreference();
let autoFillSingleTotpSitePreference = false;
if (sitePreference !== null && sitePreference !== undefined) {
if (sitePreference.autoFillTOTP === true || sitePreference.autoFillTOTP === false) {
autoFillSingleTotpSitePreference = sitePreference.autoFillTOTP;
}
}


if (kpxc.settings.autoFillSingleTotp || autoFillSingleTotpSitePreference) {
if (kpxc.credentials.length === 0) {
await kpxc.receiveCredentialsIfNecessary();
}
Expand Down
39 changes: 37 additions & 2 deletions keepassxc-browser/options/options.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ body {
background-color: var(--kpxc-background-color);
color: var(--kpxc-text-color);
font-size: 14px;
max-width: 1440px;
}

a {
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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: '►';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want to go this way, you could just use <details> and <summary>. The About page is already using those standard HTML elements.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is that when I am using a list instead of a table, like I showed in the previous screenshots then the small triangle will move on top of the text as you can see here. Thats why I did that, this way the delete button will wrap with the text if there is no space, instead of taking up half of the horizontal space the entire time. While it looks a bit more inconsistent I think this is better than the previously used horizontal scrolling as for me that felt like a very bad user experience.
image

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI: In my mockup I used <details> and <summary> only for the single cell.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that the delete button now possibly moving to the left is not optimal but I do not have enough bootstrap and flexbox knowledge to solve this problem, if you have any ideas I would be very happy to try those out. I think that going with the current list approach instead of a table would be better if the current problem could be solved. But if you think that having a table with a strict separation line is better than we could go back to a table.

Copy link
Member

@varjolintu varjolintu Oct 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would also want to see a simpler list implementation instead of an older table. It would be easier to manage from JavaScript too. I can try make some mockups later and see if I have the same issue.

EDIT: Made a few tests and it seems the table is much easier to manage in this case.

padding-right: 1rem;
}

#sitePreferencesTable > li > details[open] > summary > div > div:first-child::before {
content: '▼';
padding-right: 1rem;
}
123 changes: 85 additions & 38 deletions keepassxc-browser/options/options.html
Original file line number Diff line number Diff line change
Expand Up @@ -731,45 +731,92 @@ <h2 class="pb-3 mt-0" data-i18n="optionsSitePreferencesTab"></h2>
<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>

<li class="clone d-none list-group-item">
<details>
<summary>
<div class="row justify-content-between">
<div class="col-auto"></div>
<div class="col-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>

<div class="container m-3">
<div class="row align-items-start gx-5">
<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 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>

<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>

<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>
<div class="col">
<div class="form-group">
<div class="form-check">
<label for="autoSubmit" data-i18n="optionsCheckboxAutoSubmit"></label>
<input class="form-check-input" type="checkbox" id="autoSubmit" name="autoSubmit" value="false" data-i18n="[title]optionsColumnAutoSubmit">
<div class="form-text" data-i18n="optionsAutoSubmitHelpText"></div>
</div>
</div>

<div class="form-group">
<div class="form-check">
<label for="autoFillCredentials" data-i18n="optionsCheckboxAutoFillSingleEntry"></label>
<input class="form-check-input" type="checkbox" id="autoFillCredentials" name="autoFillCredentials" value="false" data-i18n="[title]optionsColumnAutoFillCredentials">
<div class="form-text" data-i18n="optionsAutoFillSingleEntryHelpText"></div>
</div>
</div>

<div class="form-group">
<div class="form-check">
<label for="autoFillTOTP" data-i18n="optionsCheckboxAutoFillSingleTotp"></label>
<input class="form-check-input" type="checkbox" id="autoFillTOTP" name="autoFillTOTP" value="false" data-i18n="[title]optionsColumnAutoFillTOTP">
<div class="form-text" data-i18n="optionsAutoFillSingleTotpHelpText"></div>
</div>
</div>
</div>
</div>
</div>
</details>
</li>
</ul>
</div>

<div id="dialogDeleteSite" class="modal fade" tabindex="-1" role="dialog">
Expand Down
Loading