Code cleanup for 1.8.6 (#1880)

Code cleanup for 1.8.6
This commit is contained in:
Sami Vänttinen 2023-03-12 14:06:40 +02:00 committed by GitHub
parent dd9d316f13
commit 4564172a0d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 116 additions and 239 deletions

View file

@ -3,12 +3,12 @@
"ignorePatterns": ["**/*.min.js"],
"env": {
"browser": true,
"es6": true,
"es2022": true,
"jquery": true,
"webextensions": true
},
"parserOptions": {
"ecmaVersion": 2020
"ecmaVersion": 13
},
"rules": {
"array-bracket-spacing": ["error", "always"],
@ -101,6 +101,7 @@
"DatabaseState": true,
"debugLogMessage": true,
"EXTENSION_NAME": true,
"getCurrentTab": true,
"getTopLevelDomainFromUrl": true,
"httpAuth": true,
"Icon": true,

View file

@ -3,10 +3,7 @@
const browserAction = {};
browserAction.show = function(tab, popupData) {
if (!popupData) {
popupData = page.popupData;
}
popupData ??= page.popupData;
page.popupData = popupData;
browser.browserAction.setIcon({
@ -38,13 +35,9 @@ browserAction.showDefault = async function(tab) {
}
// Get the current tab if no tab given
tab ??= await getCurrentTab();
if (!tab) {
const tabs = await browser.tabs.query({ active: true, currentWindow: true });
if (tabs.length === 0) {
return;
}
tab = tabs[0];
return;
}
if (page.tabs[tab.id]?.loginList.length > 0) {
@ -65,10 +58,7 @@ browserAction.generateIconName = function(iconType) {
browserAction.ignoreSite = async function(url) {
await browser.windows.getCurrent();
// Get current active window
const tabs = await browser.tabs.query({ active: true, currentWindow: true });
const tab = tabs[0];
const tab = await getCurrentTab();
// Send the message to the current tab's content script
await browser.runtime.getBackgroundPage();

View file

@ -81,7 +81,7 @@ keepassClient.sendNativeMessage = function(request, enableTimeout = false, timeo
const listener = ((port, action) => {
const handler = (msg) => {
if (msg && msg.action === action) {
if (msg && msg?.action === action) {
// If the request has a separate requestID, check if it matches when there's no nonce (an error message)
const isNotificationOrError = !msg.nonce && request.requestID === msg.requestID;

View file

@ -4,7 +4,7 @@ const kpxcEvent = {};
kpxcEvent.onMessage = async function(request, sender) {
if (request.action in kpxcEvent.messageHandlers) {
if (!sender.hasOwnProperty('tab') || sender.tab.id < 1) {
if (!Object.hasOwn(sender, 'tab') || sender.tab.id < 1) {
sender.tab = {};
sender.tab.id = page.currentTabId;
}
@ -56,8 +56,8 @@ kpxcEvent.onLoadKeyRing = async function() {
keepass.keyRing = item.keyRing;
if (keepass.isAssociated() && !keepass.keyRing[keepass.associated.hash]) {
keepass.associated = {
'value': false,
'hash': null
value: false,
hash: null
};
}
@ -113,7 +113,7 @@ kpxcEvent.lockDatabase = async function(tab) {
};
kpxcEvent.onGetTabInformation = async function(tab) {
const id = tab.id || page.currentTabId;
const id = tab?.id || page.currentTabId;
return page.tabs[id];
};
@ -143,7 +143,7 @@ kpxcEvent.onUpdateAvailableKeePassXC = async function() {
};
kpxcEvent.onRemoveCredentialsFromTabInformation = async function(tab) {
const id = tab.id || page.currentTabId;
const id = tab?.id || page.currentTabId;
page.clearCredentials(id);
page.clearSubmittedCredentials();
};

View file

@ -21,14 +21,14 @@
* @param {object} tab
*/
browser.tabs.onCreated.addListener((tab) => {
if (tab.id > 0) {
if (tab.selected) {
page.currentTabId = tab.id;
if (!page.tabs[tab.id]) {
page.createTabEntry(tab.id);
}
page.switchTab(tab);
if (tab?.id > 0 && tab?.selected) {
page.currentTabId = tab.id;
if (!page.tabs[tab.id]) {
page.createTabEntry(tab.id);
}
page.switchTab(tab);
}
});
@ -39,12 +39,8 @@ browser.tabs.onCreated.addListener((tab) => {
*/
browser.tabs.onRemoved.addListener(async function(tabId, removeInfo) {
if (page.currentTabId === tabId) {
const activeTabs = await browser.tabs.query({ active: true, currentWindow: true });
if (activeTabs.length > 0) {
page.currentTabId = activeTabs[0].id;
} else {
page.currentTabId = -1;
}
const currentTab = await getCurrentTab();
page.currentTabId = currentTab ? currentTab.id : -1;
}
delete page.tabs[tabId];
});
@ -97,8 +93,7 @@ browser.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
* @param {object} details
*/
browser.webNavigation.onCommitted.addListener((details) => {
if ((details.transitionQualifiers.length > 0 && details.transitionQualifiers[0] === 'client_redirect')
|| details.transitionType === 'form_submit') {
if (details.transitionQualifiers?.[0] === 'client_redirect' || details.transitionType === 'form_submit') {
page.redirectCount += 1;
return;
}
@ -153,9 +148,9 @@ browser.commands.onCommand.addListener(async (command) => {
|| command === 'choose_credential_fields'
|| command === 'retrive_credentials_forced'
|| command === 'reload_extension') {
const tabs = await browser.tabs.query({ active: true, currentWindow: true });
if (tabs.length) {
browser.tabs.sendMessage(tabs[0].id, { action: command });
const tab = await getCurrentTab();
if (tab) {
browser.tabs.sendMessage(tab.id, { action: command });
}
}
});

View file

@ -15,8 +15,6 @@ keepass.latestVersionUrl = 'https://api.github.com/repos/keepassxreboot/keepassx
keepass.cacheTimeout = 30 * 1000; // Milliseconds
keepass.databaseHash = '';
keepass.previousDatabaseHash = '';
keepass.keyId = 'keepassxc-browser-cryptokey-name';
keepass.keyBody = 'keepassxc-browser-key';
keepass.reconnectLoop = null;
const kpActions = {
@ -644,7 +642,7 @@ keepass.migrateKeyRing = function() {
};
keepass.saveKey = function(hash, id, key) {
if (!(hash in keepass.keyRing)) {
if (!Object.hasOwn(keepass.keyRing, hash)) {
keepass.keyRing[hash] = {
id: id,
key: key,
@ -663,7 +661,7 @@ keepass.saveKey = function(hash, id, key) {
};
keepass.updateLastUsed = function(hash) {
if ((hash in keepass.keyRing)) {
if (Object.hasOwn(keepass.keyRing, hash)) {
keepass.keyRing[hash].lastUsed = new Date().valueOf();
browser.storage.local.set({ 'keyRing': keepass.keyRing });
}
@ -691,6 +689,7 @@ keepass.deleteKey = function(hash) {
keepass.getCryptoKey = function() {
let dbkey = null;
let dbid = null;
if (!(keepass.databaseHash in keepass.keyRing)) {
return [ dbid, dbkey ];
}
@ -712,7 +711,7 @@ keepass.setCryptoKey = function(id, key) {
// Connection
//--------------------------------------------------------------------------
keepass.enableAutomaticReconnect = function() {
keepass.enableAutomaticReconnect = async function() {
// Disable for Windows if KeePassXC is older than 2.3.4
if (!page.settings.autoReconnect
|| (navigator.platform.toLowerCase().includes('win')
@ -767,7 +766,7 @@ keepass.generateNewKeyPair = function() {
keepass.isConfigured = async function() {
if (typeof(keepass.databaseHash) === 'undefined') {
const hash = keepass.getDatabaseHash();
return hash in keepass.keyRing;
return Object.hasOwn(keepass.keyRing, hash);
}
return keepass.databaseHash in keepass.keyRing;
@ -870,10 +869,10 @@ keepass.updateDatabase = async function() {
keepass.updateDatabaseHashToContent = async function() {
try {
const tabs = await browser.tabs.query({ active: true, currentWindow: true });
if (tabs.length) {
const tab = await getCurrentTab();
if (tab) {
// Send message to content script
browser.tabs.sendMessage(tabs[0].id, {
browser.tabs.sendMessage(tab.id, {
action: 'check_database_hash',
hash: { old: keepass.previousDatabaseHash, new: keepass.databaseHash },
connected: keepass.isKeePassXCAvailable

View file

@ -58,116 +58,11 @@ page.initSettings = async function() {
page.settings = item.settings;
page.settings.autoReconnect = false;
if (!('afterFillSorting' in page.settings)) {
page.settings.afterFillSorting = defaultSettings.afterFillSorting;
}
if (!('afterFillSortingTotp' in page.settings)) {
page.settings.afterFillSortingTotp = defaultSettings.afterFillSortingTotp;
}
if (!('autoCompleteUsernames' in page.settings)) {
page.settings.autoCompleteUsernames = defaultSettings.autoCompleteUsernames;
}
if (!('showGroupNameInAutocomplete' in page.settings)) {
page.settings.showGroupNameInAutocomplete = defaultSettings.showGroupNameInAutocomplete;
}
if (!('autoFillAndSend' in page.settings)) {
page.settings.autoFillAndSend = defaultSettings.autoFillAndSend;
}
if (!('autoFillSingleEntry' in page.settings)) {
page.settings.autoFillSingleEntry = defaultSettings.autoFillSingleEntry;
}
if (!('autoRetrieveCredentials' in page.settings)) {
page.settings.autoRetrieveCredentials = defaultSettings.autoRetrieveCredentials;
}
if (!('autoSubmit' in page.settings)) {
page.settings.autoSubmit = defaultSettings.autoSubmit;
}
if (!('checkUpdateKeePassXC' in page.settings)) {
page.settings.checkUpdateKeePassXC = defaultSettings.checkUpdateKeePassXC;
}
if (!('colorTheme' in page.settings)) {
page.settings.colorTheme = defaultSettings.colorTheme;
}
if (!('clearCredentialsTimeout' in page.settings)) {
page.settings.clearCredentialsTimeout = defaultSettings.clearCredentialsTimeout;
}
if (!('credentialSorting' in page.settings)) {
page.settings.credentialSorting = defaultSettings.credentialSorting;
}
if (!('debugLogging' in page.settings)) {
page.settings.debugLogging = defaultSettings.debugLogging;
}
if (!('defaultGroup' in page.settings)) {
page.settings.defaultGroup = defaultSettings.defaultGroup;
}
if (!('defaultGroupAlwaysAsk' in page.settings)) {
page.settings.defaultGroupAlwaysAsk = defaultSettings.defaultGroupAlwaysAsk;
}
if (!('downloadFaviconAfterSave' in page.settings)) {
page.settings.downloadFaviconAfterSave = defaultSettings.downloadFaviconAfterSave;
}
if (!('redirectAllowance' in page.settings)) {
page.settings.redirectAllowance = defaultSettings.redirectAllowance;
}
if (!('saveDomainOnly' in page.settings)) {
page.settings.saveDomainOnly = defaultSettings.saveDomainOnly;
}
if (!('showGettingStartedGuideAlert' in page.settings)) {
page.settings.showGettingStartedGuideAlert = defaultSettings.showGettingStartedGuideAlert;
}
if (!('showTroubleshootingGuideAlert' in page.settings)) {
page.settings.showTroubleshootingGuideAlert = defaultSettings.showTroubleshootingGuideAlert;
}
if (!('showLoginFormIcon' in page.settings)) {
page.settings.showLoginFormIcon = defaultSettings.showLoginFormIcon;
}
if (!('showLoginNotifications' in page.settings)) {
page.settings.showLoginNotifications = defaultSettings.showLoginNotifications;
}
if (!('showNotifications' in page.settings)) {
page.settings.showNotifications = defaultSettings.showNotifications;
}
if (!('showOTPIcon' in page.settings)) {
page.settings.showOTPIcon = defaultSettings.showOTPIcon;
}
if (!('usePasswordGeneratorIcons' in page.settings)) {
page.settings.usePasswordGeneratorIcons = defaultSettings.usePasswordGeneratorIcons;
}
if (!('useObserver' in page.settings)) {
page.settings.useObserver = defaultSettings.useObserver;
}
if (!('usePasswordGeneratorIcons' in page.settings)) {
page.settings.usePasswordGeneratorIcons = defaultSettings.usePasswordGeneratorIcons;
}
if (!('usePredefinedSites' in page.settings)) {
page.settings.usePredefinedSites = defaultSettings.usePredefinedSites;
// Set default settings if needed
for (const [ key, value ] of Object.entries(defaultSettings)) {
if (!Object.hasOwn(page.settings, key)) {
page.settings[key] = value;
}
}
await browser.storage.local.set({ 'settings': page.settings });
@ -186,13 +81,13 @@ page.initOpenedTabs = async function() {
}
// Set initial tab-ID
const currentTabs = await browser.tabs.query({ active: true, currentWindow: true });
if (currentTabs.length === 0) {
const currentTab = await getCurrentTab();
if (!currentTab) {
return;
}
page.currentTabId = currentTabs[0].id;
browserAction.showDefault(currentTabs[0]);
page.currentTabId = currentTab.id;
browserAction.showDefault(currentTab);
} catch (err) {
logError('page.initOpenedTabs error: ' + err);
return Promise.reject();
@ -372,11 +267,7 @@ page.setAutoSubmitPerformed = async function(tab) {
};
page.getLoginList = async function(tab) {
if (page.tabs[tab.id]) {
return page.tabs[tab.id].loginList;
}
return [];
return page.tabs[tab.id] ? page.tabs[tab.id].loginList : [];
};
page.fillHttpAuth = async function(tab, credentials) {
@ -410,8 +301,8 @@ page.updateContextMenu = async function(tab, credentials) {
// Show username inside [] if there are KPH attributes inside multiple credentials
const attributeName = Object.keys(attribute)[0].slice(5);
const finalName = credentials.length > 1
? `[${cred.login}] ${attributeName}`
: attributeName;
? `[${cred.login}] ${attributeName}`
: attributeName;
page.attributeMenuItemIds.push(createContextMenuItem({
action: 'fill_attribute',

View file

@ -148,12 +148,17 @@ const logError = function(message) {
// Returns file name and line number from error stack
const getFileAndLine = function() {
const err = new Error().stack.split('\n');
const line = err[4] ?? err[err.length - 1];
const line = err[4] ?? err.at(-1);
const result = line.substring(line.lastIndexOf('/') + 1, line.lastIndexOf(':'));
return result;
};
const getCurrentTab = async function() {
const tabs = await browser.tabs.query({ active: true, currentWindow: true });
return tabs.length > 0 ? tabs[0] : undefined;
};
HTMLElement.prototype.show = function() {
this.style.display = 'block';
};

View file

@ -172,7 +172,7 @@ kpxcSites.formSubmitButtonExceptionFound = function(form) {
'login.microsoftonline.us',
].some(u => form.action.includes(u))) {
const buttons = Array.from(form.querySelectorAll(kpxcForm.formButtonQuery));
if (buttons && buttons.length > 1) {
if (buttons?.length > 1) {
return buttons[1];
}
}
@ -186,7 +186,7 @@ kpxcSites.formSubmitButtonExceptionFound = function(form) {
* @returns {boolean} True if exception found
*/
kpxcSites.popupExceptionFound = function(combinations) {
if (combinations.length > 1 && combinations[0].form && combinations[0].form.action.startsWith(googleUrl)) {
if (combinations?.[0].form?.action.startsWith(googleUrl)) {
return true;
}

View file

@ -61,9 +61,9 @@ kpxcBanner.create = async function(credentials = {}) {
const usernameText = kpxcUI.createElement('span', 'small', {}, tr('popupUsername') + ' ');
const usernameSpan = kpxcUI.createElement('span', 'small info information-username', {}, credentials.username);
const newButton = kpxcUI.createElement('button', 'kpxc-button kpxc-green-button', { 'id': 'kpxc-banner-btn-new' }, tr('popupButtonNew'));
const updateButton = kpxcUI.createElement('button', 'kpxc-button kpxc-orange-button', { 'id': 'kpxc-banner-btn-update' }, tr('popupButtonUpdate'));
const dismissButton = kpxcUI.createElement('button', 'kpxc-button kpxc-red-button', { 'id': 'kpxc-banner-btn-dismiss' }, tr('popupButtonDismiss'));
const newButton = kpxcUI.createElement('button', GREEN_BUTTON, { 'id': 'kpxc-banner-btn-new' }, tr('popupButtonNew'));
const updateButton = kpxcUI.createElement('button', ORANGE_BUTTON, { 'id': 'kpxc-banner-btn-update' }, tr('popupButtonUpdate'));
const dismissButton = kpxcUI.createElement('button', RED_BUTTON, { 'id': 'kpxc-banner-btn-dismiss' }, tr('popupButtonDismiss'));
const separator = kpxcUI.createElement('div', 'kpxc-separator');
const ignoreCheckbox = kpxcUI.createElement('input', 'kpxc-checkbox', { type: 'checkbox', name: 'ignoreCheckbox', id: 'kpxc-banner-ignoreCheckbox' });
@ -238,11 +238,9 @@ kpxcBanner.saveNewCredentials = async function(credentials = {}) {
kpxcBanner.updateCredentials = async function(credentials = {}) {
// Only one entry which could be updated
if (credentials.list.length === 1) {
if (credentials.list?.length === 1) {
// Use the current username if it's empty
if (!credentials.username) {
credentials.username = credentials.list[0].login;
}
credentials.username ??= credentials.list[0].login;
const res = await sendMessage('update_credentials', [ credentials.list[0].uuid, credentials.username, credentials.password, credentials.url ]);
kpxcBanner.verifyResult(res);
@ -259,8 +257,8 @@ kpxcBanner.updateCredentials = async function(credentials = {}) {
kpxcBanner.shadowSelector('.kpxc-banner-dialog .username-exists').style.display = 'none';
}
for (let i = 0; i < credentials.list.length; i++) {
const a = kpxcUI.createElement('a', 'list-group-item', { 'href': '#', 'entryId': i }, `${credentials.list[i].login} (${credentials.list[i].name})`);
for (const [ i, cred ] of credentials.list.entries()) {
const a = kpxcUI.createElement('a', 'list-group-item', { 'href': '#', 'entryId': i }, `${cred.login} (${cred.name})`);
a.addEventListener('click', function(e) {
e.preventDefault();
if (!e.isTrusted) {
@ -271,7 +269,7 @@ kpxcBanner.updateCredentials = async function(credentials = {}) {
// Use the current username if it's empty
if (!credentials.username) {
credentials.username = credentials.list[entryId].login;
credentials.username = cred.login;
}
let url = credentials.url;
@ -292,7 +290,7 @@ kpxcBanner.updateCredentials = async function(credentials = {}) {
});
});
if (credentials.usernameExists && credentials.username === credentials.list[i].login) {
if (credentials.usernameExists && credentials.username === cred.login) {
a.style.fontWeight = 'bold';
}

View file

@ -6,12 +6,6 @@ const STEP_SELECT_PASSWORD = 2;
const STEP_SELECT_TOTP = 3;
const STEP_SELECT_STRING_FIELDS = 4;
const BLUE_BUTTON = 'kpxc-button kpxc-blue-button';
const GREEN_BUTTON = 'kpxc-button kpxc-green-button';
const ORANGE_BUTTON = 'kpxc-button kpxc-orange-button';
const RED_BUTTON = 'kpxc-button kpxc-red-button';
const GRAY_BUTTON_CLASS = 'kpxc-gray-button';
const DEFINED_CUSTOM_FIELDS = 'defined-custom-fields';
const FIXED_FIELD_CLASS = 'kpxcDefine-fixed-field';
const DARK_FIXED_FIELD_CLASS = 'kpxcDefine-fixed-field-dark';
@ -309,11 +303,11 @@ kpxcCustomLoginFieldsBanner.confirm = async function() {
// If the new selection is already used in some other field, clear it
const clearIdenticalField = function(path, location) {
const currentSite = kpxc.settings[DEFINED_CUSTOM_FIELDS][location];
if (currentSite.username && currentSite.username[0] === path[0]) {
if (currentSite.username?.[0] === path[0]) {
kpxc.settings[DEFINED_CUSTOM_FIELDS][location].username = undefined;
} else if (currentSite.password && currentSite.password[0] === path[0]) {
} else if (currentSite.password?.[0] === path[0]) {
kpxc.settings[DEFINED_CUSTOM_FIELDS][location].password = undefined;
} else if (currentSite.totp && currentSite.totp[0] === path[0]) {
} else if (currentSite.totp?.[0] === path[0]) {
kpxc.settings[DEFINED_CUSTOM_FIELDS][location].totp = undefined;
}
};

View file

@ -111,9 +111,9 @@ kpxcFields.getSegmentedTOTPFields = function(inputs, combinations) {
combinations.push(combination);
// Create an icon to the right side of the segmented fields
kpxcTOTPIcons.newIcon(totpInputs[totpInputs.length - 1], kpxc.databaseState, true);
kpxcTOTPIcons.newIcon(totpInputs.at(-1), kpxc.databaseState, true);
kpxcIcons.icons.push({
field: totpInputs[totpInputs.length - 1],
field: totpInputs.at(-1),
iconType: kpxcIcons.iconTypes.TOTP,
segmented: true
});
@ -272,7 +272,7 @@ kpxcFields.getIdFromProperties = function(target) {
return `${target.nodeName} ${target.type} ${target.name} ${target.placeholder}`;
}
if (target.classList && target.classList.length > 0) {
if (target.classList?.length > 0) {
return `${target.nodeName} ${target.type} ${target.classList.value} ${target.placeholder}`;
}
@ -285,11 +285,11 @@ kpxcFields.getIdFromProperties = function(target) {
// Legacy unique ID generation for converting
kpxcFields.getLegacyId = function(target) {
if (target.classList.length > 0) {
if (target.classList?.length > 0) {
return `${target.nodeName} ${target.type} ${target.classList.value} ${target.name} ${target.placeholder}`;
}
if (target.id && target.id !== '') {
if (target.id && target?.id !== '') {
return `${target.nodeName} ${target.type} ${kpxcFields.prepareId(target.id)} ${target.name} ${target.placeholder}`;
}
@ -316,14 +316,13 @@ kpxcFields.isCustomLoginFieldsUsed = function() {
kpxcFields.isSearchForm = function(form) {
// Check form action
const formAction = form.getLowerCaseAttribute('action');
if (formAction && (formAction.includes('search') && !formAction.includes('research'))) {
if (formAction?.includes('search') && !formAction?.includes('research')) {
return true;
}
// Ignore form with search classes
const formId = form.getLowerCaseAttribute('id');
if (form.className && (form.className.includes('search')
|| (formId && formId.includes('search') && !formId.includes('research')))) {
if (form.className?.includes('search') || (formId?.includes('search') && !formId?.includes('research'))) {
return true;
}

View file

@ -114,12 +114,12 @@ kpxcFill.fillFromTOTP = async function(target) {
const el = target || document.activeElement;
const credentialList = await kpxc.updateTOTPList();
if (credentialList && credentialList.length === 0) {
if (credentialList?.length === 0) {
kpxcUI.createNotification('warning', tr('credentialsNoTOTPFound'));
return;
}
if (credentialList && credentialList.length === 1) {
if (credentialList?.length === 1) {
kpxcFill.fillTOTPFromUuid(el, credentialList[0].uuid);
return;
}
@ -140,7 +140,7 @@ kpxcFill.fillTOTPFromUuid = async function(el, uuid) {
return;
}
if (user.totp && user.totp.length > 0) {
if (user.totp?.length > 0) {
// Retrieve a new TOTP value
const totp = await sendMessage('get_totp', [ user.uuid, user.totp ]);
if (!totp) {
@ -149,7 +149,7 @@ kpxcFill.fillTOTPFromUuid = async function(el, uuid) {
}
kpxcFill.setTOTPValue(el, totp);
} else if (user.stringFields && user.stringFields.length > 0) {
} else if (user.stringFields?.length > 0) {
const stringFields = user.stringFields;
for (const s of stringFields) {
const val = s['KPH: {TOTP}'];
@ -168,7 +168,7 @@ kpxcFill.setTOTPValue = function(elem, val) {
}
for (const comb of kpxc.combinations) {
if (comb.totpInputs && comb.totpInputs.length > 0) {
if (comb.totpInputs?.length > 0) {
kpxcFill.fillSegmentedTotp(elem, val, comb.totpInputs);
return;
}
@ -223,10 +223,9 @@ kpxcFill.fillInCredentials = async function(combination, predefinedUsername, uui
// Use predefined username as default
let usernameValue = predefinedUsername;
if (!usernameValue) {
// With single password field the combination.password is used instead
usernameValue = combination.username ? combination.username.value : combination.password.value;
}
// With single password field the combination.password is used instead
usernameValue ??= combination.username ? combination.username.value : combination.password.value;
// Find the correct credentials
const selectedCredentials = kpxc.credentials.find(c => c.uuid === uuid);
@ -262,7 +261,7 @@ kpxcFill.fillInCredentials = async function(combination, predefinedUsername, uui
}
// Fill StringFields
if (selectedCredentials.stringFields && selectedCredentials.stringFields.length > 0) {
if (selectedCredentials.stringFields?.length > 0) {
kpxcFill.fillInStringFields(combination.fields, selectedCredentials.stringFields);
}
@ -278,7 +277,7 @@ kpxcFill.fillInCredentials = async function(combination, predefinedUsername, uui
// Fills StringFields defined in Custom Fields
kpxcFill.fillInStringFields = function(fields, stringFields) {
const filledInFields = [];
if (fields && stringFields && fields.length > 0 && stringFields.length > 0) {
if (fields && stringFields && fields?.length > 0 && stringFields?.length > 0) {
for (let i = 0; i < fields.length; i++) {
if (i >= stringFields.length) {
continue;

View file

@ -51,7 +51,7 @@ kpxcForm.getFormSubmitButton = function(form) {
// If any formaction overriding the default action is set, ignore those buttons.
const buttons = Array.from(form.querySelectorAll(kpxcForm.formButtonQuery)).filter(b => !b.getAttribute('formAction'));
if (buttons.length > 0) {
return buttons[buttons.length - 1];
return buttons.at(-1);
}
// Try to find similar buttons outside the form which are added via 'form' property

View file

@ -153,7 +153,7 @@ kpxc.getFormActionUrl = function(combination) {
}
let action = null;
if (combination.form && combination.form.length > 0) {
if (combination.form?.length > 0) {
action = combination.form.action;
}
@ -386,13 +386,13 @@ kpxc.initLoginPopup = function() {
// Initialize login items
const loginItems = [];
for (let i = 0; i < kpxc.credentials.length; i++) {
const loginItem = getLoginItem(kpxc.credentials[i], showGroupNameInAutocomplete, i);
for (const [ i, login ] of kpxc.credentials.entries()) {
const loginItem = getLoginItem(login, showGroupNameInAutocomplete, i);
// Ignore a duplicate entry if the password is empty, but there's already a similar entry with a password.
// An usual use case with TOTP in a separate database.
const similarEntryFound = kpxc.credentials.some(c => c.password !== '' && c.login === loginItem.login);
if (kpxc.credentials[i].password === '' && similarEntryFound) {
if (login.password === '' && similarEntryFound) {
continue;
}
@ -586,7 +586,7 @@ kpxc.retrieveCredentials = async function(force = false) {
// Handles credentials from 'retrieve_credentials' response
kpxc.retrieveCredentialsCallback = async function(credentials) {
_called.retrieveCredentials = true;
if (credentials && credentials.length > 0) {
if (credentials?.length > 0) {
kpxc.credentials = credentials;
await kpxc.prepareCredentials();
}
@ -599,7 +599,7 @@ kpxc.retrieveCredentialsCallback = async function(credentials) {
// Retrieve submitted credentials if available
const creds = await sendMessage('page_get_submitted');
if (creds && creds.submitted) {
if (creds?.submitted) {
await sendMessage('page_clear_submitted');
kpxc.rememberCredentials(creds.username, creds.password, creds.url, creds.oldCredentials);
}

View file

@ -54,8 +54,8 @@ kpxcTOTPIcons.isAcceptedTOTPField = function(field) {
const placeholder = field.getLowerCaseAttribute('placeholder');
// Checks if the field id, name or placeholder includes some of the acceptedOTPFields but not any from ignoredTypes
if ((acceptedOTPFields.some(f => (id && id.includes(f)) || (name && name.includes(f) || placeholder && placeholder.includes(f))) || acceptedParents.some(s => field.closest(s)))
&& !ignoredTypes.some(f => (id && id.includes(f)) || (name && name.includes(f) || placeholder && placeholder.includes(f)))) {
if ((acceptedOTPFields.some(f => id?.includes(f) || (name?.includes(f) || placeholder?.includes(f))) || acceptedParents.some(s => field.closest(s)))
&& !ignoredTypes.some(f => id?.includes(f) || (name?.includes(f) || placeholder?.includes(f)))) {
return true;
}

View file

@ -7,6 +7,12 @@ const MIN_INPUT_FIELD_OFFSET_WIDTH = 60;
const MIN_OPACITY = 0.7;
const MAX_OPACITY = 1;
const BLUE_BUTTON = 'kpxc-button kpxc-blue-button';
const GREEN_BUTTON = 'kpxc-button kpxc-green-button';
const ORANGE_BUTTON = 'kpxc-button kpxc-orange-button';
const RED_BUTTON = 'kpxc-button kpxc-red-button';
const GRAY_BUTTON_CLASS = 'kpxc-gray-button';
const DatabaseState = {
DISCONNECTED: 0,
LOCKED: 1,
@ -107,7 +113,7 @@ kpxcUI.monitorIconPosition = function(iconClass) {
});
window.addEventListener('transitionend', function(e) {
if (e.target && (e.target.nodeName === 'INPUT' || e.target.nodeName === 'TEXTAREA')) {
if (e.target?.nodeName === 'INPUT' || e.target?.nodeName === 'TEXTAREA') {
kpxcUI.updateIconPosition(iconClass);
}
});

View file

@ -158,7 +158,7 @@
"applications": {
"gecko": {
"id": "keepassxc-browser@keepassxc.org",
"strict_min_version": "74.0"
"strict_min_version": "91.0"
}
},
"default_locale": "en"

View file

@ -61,12 +61,12 @@ function statusResponse(r) {
}
const sendMessageToTab = async function(message) {
const tabs = await browser.tabs.query({ active: true, currentWindow: true });
if (tabs.length === 0) {
const tab = await getCurrentTab();
if (!tab) {
return false; // Only the background devtools or a popup are opened
}
await browser.tabs.sendMessage(tabs[0].id, {
await browser.tabs.sendMessage(tab.id, {
action: message
});

View file

@ -25,11 +25,10 @@ async function initSettings() {
customLoginFieldsButton.addEventListener('click', async () => {
await browser.windows.getCurrent();
const tabs = await browser.tabs.query({ active: true, currentWindow: true });
const tab = tabs[0];
const tab = await getCurrentTab();
await browser.runtime.getBackgroundPage();
browser.tabs.sendMessage(tab.id, {
browser.tabs.sendMessage(tab?.id, {
action: 'choose_credential_fields'
});
close();
@ -49,8 +48,8 @@ async function initColorTheme() {
}
async function getLoginData() {
const tabs = await browser.tabs.query({ active: true, currentWindow: true });
if (tabs.length === 0) {
const tab = getCurrentTab();
if (!tab) {
return [];
}

View file

@ -8,10 +8,11 @@
const data = await getLoginData();
const ll = document.getElementById('login-list');
for (let i = 0; i < data.logins.length; ++i) {
for (const [ i, login ] of data.logins.entries()) {
const a = document.createElement('a');
a.setAttribute('class', 'list-group-item');
a.textContent = data.logins[i].login + ' (' + data.logins[i].name + ')';
a.textContent = login.login + ' (' + login.name + ')';
a.setAttribute('id', '' + i);
a.addEventListener('click', (e) => {

View file

@ -6,18 +6,18 @@
$('#lock-database-button').show();
const tabs = await browser.tabs.query({ active: true, currentWindow: true });
if (tabs.length === 0) {
const tab = await getCurrentTab();
if (!tab) {
return [];
}
const logins = await getLoginData();
const ll = document.getElementById('login-list');
for (let i = 0; i < logins.length; i++) {
const uuid = logins[i].uuid;
for (const [ i, login ] of logins.entries()) {
const uuid = login.uuid;
const a = document.createElement('a');
a.textContent = logins[i].text;
a.textContent = login.text;
a.setAttribute('class', 'list-group-item');
a.setAttribute('id', '' + i);
@ -27,7 +27,7 @@
}
const id = e.target.id;
browser.tabs.sendMessage(tabs[0].id, {
browser.tabs.sendMessage(tab.id, {
action: 'fill_user_pass_with_specific_login',
id: Number(id),
uuid: uuid