From 4c684fcb1c5454ea1ef536ee5d95022160c7c9b6 Mon Sep 17 00:00:00 2001 From: varjolintu Date: Thu, 1 Feb 2024 17:29:16 +0200 Subject: [PATCH] Do not allow filling password (only) to plain text fields --- keepassxc-browser/_locales/en/messages.json | 4 +++ keepassxc-browser/content/fill.js | 29 +++++++++++++++++++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/keepassxc-browser/_locales/en/messages.json b/keepassxc-browser/_locales/en/messages.json index b6140ee..c4844ed 100644 --- a/keepassxc-browser/_locales/en/messages.json +++ b/keepassxc-browser/_locales/en/messages.json @@ -347,6 +347,10 @@ "message": "Error: Unable to find a password field.", "description": "Message shown when no password fields are found." }, + "fieldsPasswordFillNotAccepted": { + "message": "Filling password to a plain text field is prevented.", + "description": "Message shown when password fill to a plain text field is prevented." + }, "rememberNothingChanged": { "message": "Error: Could not detect changed credentials.", "description": "Message shown when trying to save credentials that haven't changed." diff --git a/keepassxc-browser/content/fill.js b/keepassxc-browser/content/fill.js index bb78cca..bd1afca 100644 --- a/keepassxc-browser/content/fill.js +++ b/keepassxc-browser/content/fill.js @@ -23,6 +23,12 @@ kpxcFill.fillAttributeToActiveElementWith = async function(attr) { // Fill requested from the context menu. Active element is used for combination detection kpxcFill.fillInFromActiveElement = async function(passOnly = false) { + const elem = document.activeElement; + if (passOnly && !passwordFillIsAllowed(elem)) { + kpxcUI.createNotification('warning', tr('fieldsPasswordFillNotAccepted')); + return; + } + await kpxc.receiveCredentialsIfNecessary(); if (kpxc.credentials.length === 0) { logDebug(`Error: Credential list is empty for: ${document.location.origin}`); @@ -30,7 +36,6 @@ kpxcFill.fillInFromActiveElement = async function(passOnly = false) { return; } - const elem = document.activeElement; if (kpxc.combinations.length > 0) { if (await kpxcFill.fillFromCombination(elem, passOnly)) { // Combination found and filled @@ -88,7 +93,9 @@ kpxcFill.fillFromAutofill = async function() { kpxcFill.fillInCredentials(kpxc.combinations[index], kpxc.credentials[0].login, kpxc.credentials[0].uuid); // Generate popup-list of usernames + descriptions - sendMessage('popup_login', [ { text: `${kpxc.credentials[0].login} (${kpxc.credentials[0].name})`, uuid: kpxc.credentials[0].uuid } ]); + sendMessage('popup_login', [ + { text: `${kpxc.credentials[0].login} (${kpxc.credentials[0].name})`, uuid: kpxc.credentials[0].uuid }, + ]); }; // Fill requested by selecting credentials from the popup @@ -329,3 +336,21 @@ kpxcFill.performAutoSubmit = async function(combination, skipAutoSubmit) { (combination.username || combination.password).focus(); } }; + +// Check if password fill is done to a plain text field +const passwordFillIsAllowed = function(elem) { + const elementIsPasswordField = + kpxc.combinations?.some(c => c.password === elem || c?.passwordInputs.some(p => p === elem)); + + // Allow if Custom Login fields are used + if (kpxcFields.isCustomLoginFieldsUsed() && elementIsPasswordField) { + return true; + } + + if (elem?.getLowerCaseAttribute('type') !== 'password') { + kpxcUI.createNotification('warning', tr('fieldsPasswordFillNotAccepted')); + return false; + } + + return true; +};