mirror of
https://github.com/keepassxreboot/keepassxc-browser.git
synced 2026-03-11 08:54:43 +00:00
parent
dd9d316f13
commit
4564172a0d
22 changed files with 116 additions and 239 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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 });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@
|
|||
"applications": {
|
||||
"gecko": {
|
||||
"id": "keepassxc-browser@keepassxc.org",
|
||||
"strict_min_version": "74.0"
|
||||
"strict_min_version": "91.0"
|
||||
}
|
||||
},
|
||||
"default_locale": "en"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -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 [];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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) => {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue