Add debug logging option (#1540)

Add debug logging option
This commit is contained in:
Sami Vänttinen 2022-01-24 12:32:26 +02:00 committed by GitHub
parent 0ec9f4831f
commit 43c4446b8c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 138 additions and 55 deletions

View file

@ -663,6 +663,14 @@
"message": "Automatically fill in HTTP Basic Auth dialogs and submit them.",
"description": "Auto fill HTTP Basic Auth dialogs and send them checkbox text."
},
"optionsDebugLogging": {
"message": "Debug logging",
"description": "Debug logging checkbox text."
},
"optionsDebugLoggingHelpText": {
"message": "Enable debug logging. Additional console messages will be visible in both background and content scripts.",
"description": "Debug logging help text."
},
"optionsRadioText": {
"message": "Check for updates of KeePassXC:",
"description": "Text above radio buttons in the settings page."

View file

@ -29,7 +29,7 @@ browserAction.showDefault = async function(tab) {
};
const response = await keepass.isConfigured().catch((err) => {
console.log('Error: Cannot show default popup: ' + err);
logError('Cannot show default popup: ' + err);
});
if (!response && !keepass.isKeePassXCAvailable) {

View file

@ -205,7 +205,7 @@ keepassClient.verifyKeyResponse = function(response, key, nonce) {
}
if (!keepassClient.checkNonceLength(response.nonce)) {
console.log(`${EXTENSION_NAME}: Error. Invalid nonce length`);
logError('Invalid nonce length.');
return false;
}
@ -233,7 +233,7 @@ keepassClient.verifyResponse = function(response, nonce, id) {
keepass.associated.value = (response.nonce === nonce);
if (keepass.associated.value === false) {
console.log(`${EXTENSION_NAME}: Error. Nonce compare failed`);
logError('Nonce compare failed');
return false;
}
@ -252,12 +252,12 @@ keepassClient.verifyDatabaseResponse = function(response, nonce) {
}
if (!keepassClient.checkNonceLength(response.nonce)) {
console.log(`${EXTENSION_NAME}: Error. Invalid nonce length`);
logError('Invalid nonce length.');
return false;
}
if (response.nonce !== nonce) {
console.log(`${EXTENSION_NAME}: Error- Nonce compare failed`);
logError('Nonce compare failed.');
return false;
}
@ -322,12 +322,10 @@ function onDisconnected() {
page.clearCredentials(page.currentTabId, true);
keepass.updatePopup('cross');
keepass.updateDatabaseHashToContent();
console.log(`${EXTENSION_NAME}: Failed to connect: ${(browser.runtime.lastError === null ? 'Unknown error' : browser.runtime.lastError.message)}`);
logError(`Failed to connect: ${(browser.runtime.lastError === null ? 'Unknown error' : browser.runtime.lastError.message)}`);
}
keepassClient.onNativeMessage = function(response) {
//console.log('Received message: ' + JSON.stringify(response));
// Handle database lock/unlock status
if (response.action === kpActions.DATABASE_LOCKED || response.action === kpActions.DATABASE_UNLOCKED) {
keepass.updateDatabase();

View file

@ -38,14 +38,14 @@ kpxcEvent.showStatus = async function(tab, configured, internalPoll) {
kpxcEvent.onLoadSettings = async function() {
return await page.initSettings().catch((err) => {
console.log('onLoadSettings error: ' + err);
logError('onLoadSettings error: ' + err);
return Promise.reject();
});
};
kpxcEvent.onLoadKeyRing = async function() {
const item = await browser.storage.local.get({ 'keyRing': {} }).catch((err) => {
console.log('kpxcEvent.onLoadKeyRing error: ' + err);
logError('kpxcEvent.onLoadKeyRing error: ' + err);
return Promise.reject();
});
@ -79,7 +79,7 @@ kpxcEvent.onGetStatus = async function(tab, args = []) {
const configured = await keepass.isConfigured();
return kpxcEvent.showStatus(tab, configured, internalPoll);
} catch (err) {
console.log('Error: No status shown: ' + err);
logError('No status shown: ' + err);
return Promise.reject();
}
};
@ -90,7 +90,7 @@ kpxcEvent.onReconnect = async function(tab) {
browser.tabs.sendMessage(tab.id, {
action: 'redetect_fields'
}).catch((err) => {
console.log(err);
logError(err);
return;
});
}
@ -103,7 +103,7 @@ kpxcEvent.lockDatabase = async function(tab) {
await keepass.lockDatabase(tab);
return kpxcEvent.showStatus(tab, false);
} catch (err) {
console.log('kpxcEvent.lockDatabase error: ' + err);
logError('kpxcEvent.lockDatabase error: ' + err);
return false;
}
};

View file

@ -49,7 +49,7 @@ httpAuth.handleRequestCallback = function(details, callback) {
httpAuth.retrieveCredentials = async function(tabId, url, submitUrl) {
return await keepass.retrieveCredentials(tabId, [ url, submitUrl, false, true ]).catch((err) => {
console.log('httpAuth.retrieveCredentials error: ' + err);
logError('httpAuth.retrieveCredentials error: ' + err);
return Promise.reject();
});
};
@ -93,6 +93,7 @@ httpAuth.loginOrShowCredentials = function(logins, details, resolve, reject) {
kpxcEvent.onHTTPAuthPopup({ 'id': details.tabId }, { 'logins': logins, 'url': details.searchUrl, 'resolve': resolve });
}
} else {
logError('No logins found for HTTP Basic Auth.');
reject({ cancel: false }); // No logins found
}
};

View file

@ -11,7 +11,7 @@
await keepass.enableAutomaticReconnect();
await keepass.updateDatabase();
} catch (e) {
console.log('init.js failed');
logError('init.js failed');
}
})();
@ -62,7 +62,7 @@ browser.tabs.onActivated.addListener(async function(activeInfo) {
}
}
} catch (err) {
console.log('Error: ' + err.message);
logError(err.message);
}
});
@ -135,7 +135,7 @@ for (const item of contextMenuItems) {
browser.tabs.sendMessage(tab.id, {
action: item.action
}).catch((err) => {
console.log(err);
logError(err);
});
}
});

View file

@ -98,7 +98,7 @@ keepass.updateCredentials = async function(tab, args = []) {
return 'error';
}
} catch (err) {
console.log(`${EXTENSION_NAME}: updateCredentials failed: ${err}`);
logError(`updateCredentials failed: ${err}`);
return [];
}
};
@ -158,13 +158,14 @@ keepass.retrieveCredentials = async function(tab, args = []) {
browserAction.showDefault(tab);
}
logDebug(`Found ${entries.length} entries for url ${url}`);
return entries;
}
browserAction.showDefault(tab);
return [];
} catch (err) {
console.log(`${EXTENSION_NAME}: retrieveCredentials failed: ${err}`);
logError(`retrieveCredentials failed: ${err}`);
return [];
}
};
@ -200,12 +201,12 @@ keepass.generatePassword = async function(tab) {
password = response.entries ?? response.password;
keepass.updateLastUsed(keepass.databaseHash);
} else {
console.log(`${EXTENSION_NAME}: generatePassword rejected`);
logError('generatePassword rejected');
}
return password;
} catch (err) {
console.log(`${EXTENSION_NAME}: generatePassword failed: ${err}`);
logError(`generatePassword failed: ${err}`);
return [];
}
};
@ -252,7 +253,7 @@ keepass.associate = async function(tab) {
keepass.handleError(tab, kpErrors.ASSOCIATION_FAILED);
return AssociatedAction.NOT_ASSOCIATED;
} catch (err) {
console.log(`${EXTENSION_NAME}: associate failed: ${err}`);
logError(`associate failed: ${err}`);
}
return AssociatedAction.NOT_ASSOCIATED;
@ -321,7 +322,7 @@ keepass.testAssociation = async function(tab, args = []) {
return keepass.isAssociated();
} catch (err) {
console.log(`${EXTENSION_NAME}: testAssociation failed: ${err}`);
logError(`testAssociation failed: ${err}`);
return false;
}
};
@ -403,7 +404,7 @@ keepass.getDatabaseHash = async function(tab, args = []) {
}
return keepass.databaseHash;
} catch (err) {
console.log(`${EXTENSION_NAME}: getDatabaseHash failed: ${err}`);
logError(`getDatabaseHash failed: ${err}`);
return keepass.databaseHash;
}
};
@ -443,7 +444,7 @@ keepass.changePublicKeys = async function(tab, enableTimeout = false, connection
console.log(`${EXTENSION_NAME}: Server public key: ${nacl.util.encodeBase64(keepass.serverPublicKey)}`);
return true;
} catch (err) {
console.log(`${EXTENSION_NAME}: changePublicKeys failed: ${err}`);
logError(`changePublicKeys failed: ${err}`);
return false;
}
};
@ -477,7 +478,7 @@ keepass.lockDatabase = async function(tab) {
return false;
} catch (err) {
console.log(`${EXTENSION_NAME}: lockDatabase failed: ${err}`);
logError(`ockDatabase failed: ${err}`);
return false;
}
};
@ -518,7 +519,7 @@ keepass.getDatabaseGroups = async function(tab) {
browserAction.showDefault(tab);
return [];
} catch (err) {
console.log(`${EXTENSION_NAME}: getDatabaseGroups failed: ${err}`);
logError(`getDatabaseGroups failed: ${err}`);
return [];
}
};
@ -553,13 +554,13 @@ keepass.createNewGroup = async function(tab, args = []) {
keepass.updateLastUsed(keepass.databaseHash);
return response;
} else {
console.log(`${EXTENSION_NAME}: getDatabaseGroups rejected`);
logError(`getDatabaseGroups rejected`);
}
browserAction.showDefault(tab);
return [];
} catch (err) {
console.log(`${EXTENSION_NAME}: createNewGroup failed: ${err}`);
logError(`createNewGroup failed: ${err}`);
return [];
}
};
@ -592,7 +593,7 @@ keepass.getTotp = async function(tab, args = []) {
return;
} catch (err) {
console.log(`${EXTENSION_NAME}: getTotp failed: ${err}`);
logError(`getTotp failed: ${err}`);
}
};
@ -615,7 +616,7 @@ keepass.requestAutotype = async function(tab, args = []) {
const response = await keepassClient.sendMessage(kpAction, tab, messageData, nonce);
return response;
} catch (err) {
console.log(`${EXTENSION_NAME}: requestAutotype failed: ${err}`);
logError(`requestAutotype failed: ${err}`);
return false;
}
};
@ -774,7 +775,6 @@ keepass.reconnect = async function(tab, connectionTimeout) {
keepass.generateNewKeyPair = function() {
keepass.keyPair = nacl.box.keyPair();
//console.log(nacl.util.encodeBase64(keepass.keyPair.publicKey) + ' ' + nacl.util.encodeBase64(keepass.keyPair.secretKey));
};
keepass.isConfigured = async function() {
@ -833,14 +833,14 @@ keepass.checkForNewKeePassXCVersion = function() {
};
xhr.onerror = function(err) {
console.log(`${EXTENSION_NAME}: checkForNewKeePassXCVersion error: ${err}`);
logError(`checkForNewKeePassXCVersion error: ${err}`);
};
try {
xhr.open('GET', keepass.latestVersionUrl, true);
xhr.send();
} catch (ex) {
console.log(ex);
logError(ex);
}
keepass.latestKeePassXC.lastChecked = new Date().valueOf();
};
@ -849,7 +849,8 @@ keepass.handleError = function(tab, errorCode, errorMessage = '') {
if (errorMessage.length === 0) {
errorMessage = kpErrors.getError(errorCode);
}
console.log(`${EXTENSION_NAME}: Error ${errorCode}: ${errorMessage}`);
logError(`${errorCode}: ${errorMessage}`);
if (tab && page.tabs[tab.id]) {
page.tabs[tab.id].errorMessage = errorMessage;
}
@ -884,12 +885,12 @@ keepass.updateDatabaseHashToContent = async function() {
hash: { old: keepass.previousDatabaseHash, new: keepass.databaseHash },
connected: keepass.isKeePassXCAvailable
}).catch((err) => {
console.log(`${EXTENSION_NAME}: Error. No content script available for this tab.`);
logError(`No content script available for this tab.`);
});
keepass.previousDatabaseHash = keepass.databaseHash;
}
} catch (err) {
console.log(`${EXTENSION_NAME}: updateDatabaseHashToContent failed: ${err}`);
logError(`updateDatabaseHashToContent failed: ${err}`);
}
};

View file

@ -12,6 +12,7 @@ const defaultSettings = {
clearCredentialsTimeout: 10,
colorTheme: 'system',
credentialSorting: SORT_BY_GROUP_AND_TITLE,
debugLogging: false,
defaultGroup: '',
defaultGroupAlwaysAsk: false,
downloadFaviconAfterSave: false,
@ -93,6 +94,10 @@ page.initSettings = async function() {
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;
}
@ -148,7 +153,7 @@ page.initSettings = async function() {
await browser.storage.local.set({ 'settings': page.settings });
return page.settings;
} catch (err) {
console.log('page.initSettings error: ' + err);
logError('page.initSettings error: ' + err);
return Promise.reject();
}
};
@ -169,7 +174,7 @@ page.initOpenedTabs = async function() {
page.currentTabId = currentTabs[0].id;
browserAction.showDefault(currentTabs[0]);
} catch (err) {
console.log('page.initOpenedTabs error: ' + err);
logError('page.initOpenedTabs error: ' + err);
return Promise.reject();
}
};
@ -205,7 +210,7 @@ page.switchTab = async function(tab) {
browserAction.showDefault(tab);
browser.tabs.sendMessage(tab.id, { action: 'activated_tab' }).catch((e) => {
console.log('Cannot send activated_tab message: ', e);
logError('Cannot send activated_tab message: ' + e.message);
});
};
@ -372,9 +377,15 @@ const createContextMenuItem = function({action, args, ...options}) {
action: action,
args: args
}).catch((err) => {
console.log(err);
logError(err);
});
},
...options
});
};
const logDebug = function(message, extra) {
if (page.settings.debugLogging) {
debugLogMessage(message, extra);
}
};

View file

@ -163,3 +163,24 @@ function tr(key, params) {
const trimURL = function(url) {
return url.indexOf('?') !== -1 ? url.split('?')[0] : url;
};
const debugLogMessage = function(message, extra) {
console.log(`[Debug ${getFileAndLine()}] ${EXTENSION_NAME} - ${message}`);
if (extra) {
console.log(extra);
}
};
const logError = function(message) {
console.log(`[Error ${getFileAndLine()}] ${EXTENSION_NAME} - ${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 result = line.substring(line.lastIndexOf('/') + 1, line.lastIndexOf(':'));
return result;
};

View file

@ -149,7 +149,7 @@ kpxcBanner.saveNewCredentials = async function(credentials = {}) {
const result = await sendMessage('get_database_groups');
if (!result || !result.groups) {
console.log('Error: Empty result from get_database_groups');
logError('Empty result from get_database_groups');
await saveToDefaultGroup(credentials);
return;
}

View file

@ -24,6 +24,7 @@ kpxcFill.fillAttributeToActiveElementWith = async function(attr) {
// Fill requested from the context menu. Active element is used for combination detection
kpxcFill.fillInFromActiveElement = async function(passOnly = false) {
if (kpxc.credentials.length === 0) {
logDebug('Error: Credential list is empty.');
return;
}
@ -32,11 +33,13 @@ kpxcFill.fillInFromActiveElement = async function(passOnly = false) {
? kpxc.combinations.find(c => c.password)
: kpxc.combinations.find(c => c.username);
if (!combination) {
logDebug('Error: No combination found.');
return;
}
const field = passOnly ? combination.password : combination.username;
if (!field) {
logDebug('Error: No input field found.');
return;
}
@ -79,6 +82,7 @@ kpxcFill.fillInFromActiveElement = async function(passOnly = false) {
// Fill requested by Auto-Fill
kpxcFill.fillFromAutofill = async function() {
if (kpxc.credentials.length !== 1 || kpxc.combinations.length === 0) {
logDebug('Error: Credential list is empty or contains more than one entry.');
return;
}
@ -93,13 +97,14 @@ kpxcFill.fillFromAutofill = async function() {
// Fill requested by selecting credentials from the popup
kpxcFill.fillFromPopup = async function(id, uuid) {
if (!kpxc.credentials.length === 0 || !kpxc.credentials[id] || kpxc.combinations.length === 0) {
logDebug('Error: Credential list is empty.');
return;
}
await sendMessage('page_set_login_id', uuid);
const selectedCredentials = kpxc.credentials.find(c => c.uuid === uuid);
if (!selectedCredentials) {
console.log('Error: Uuid not found: ', uuid);
logError('Uuid not found: ', uuid);
return;
}
@ -135,11 +140,13 @@ kpxcFill.fillFromTOTP = async function(target) {
// Fill TOTP with matching uuid
kpxcFill.fillTOTPFromUuid = async function(el, uuid) {
if (!el || !uuid) {
logDebug('Error: Element or uuid is empty');
return;
}
const user = kpxc.credentials.find(c => c.uuid === uuid);
if (!user) {
logDebug('Error: No entry found with uuid: ' + uuid);
return;
}
@ -166,6 +173,7 @@ kpxcFill.fillTOTPFromUuid = async function(el, uuid) {
// Set normal or segmented TOTP value
kpxcFill.setTOTPValue = function(elem, val) {
if (kpxc.combinations.length === 0) {
logDebug('Error: Credential list is empty.');
return;
}
@ -194,6 +202,7 @@ kpxcFill.fillSegmentedTotp = function(elem, val, totpInputs) {
kpxcFill.fillFromUsernameIcon = async function(combination) {
await kpxc.receiveCredentialsIfNecessary();
if (kpxc.credentials.length === 0) {
logDebug('Error: Credential list is empty.');
return;
} else if (kpxc.credentials.length > 1 && kpxc.settings.autoCompleteUsernames) {
kpxcUserAutocomplete.showList(combination.username || combination.password);
@ -218,6 +227,7 @@ kpxcFill.fillInCredentials = async function(combination, predefinedUsername, uui
}
if (!combination || (!combination.username && !combination.password)) {
logDebug('Error: Empty login combination.');
return;
}
@ -231,7 +241,7 @@ kpxcFill.fillInCredentials = async function(combination, predefinedUsername, uui
// Find the correct credentials
const selectedCredentials = kpxc.credentials.find(c => c.uuid === uuid);
if (!selectedCredentials) {
console.log('Error: Uuid not found: ', uuid);
logError('Uuid not found: ' + uuid);
return;
}

View file

@ -61,12 +61,14 @@ kpxcForm.getFormSubmitButton = function(form) {
}
}
logDebug('No form submit button found.');
return undefined;
};
// Retrieve new password from a form with three elements: Current, New, Repeat New
kpxcForm.getNewPassword = function(passwordInputs = []) {
if (passwordInputs.length < 2) {
logDebug('Error: Not enough input fields to detect possible new password.')
return '';
}
@ -85,12 +87,14 @@ kpxcForm.getNewPassword = function(passwordInputs = []) {
return newPass;
}
logDebug('Error: No valid new password found.');
return '';
};
// Initializes form and attaches the submit button to our own callback
kpxcForm.init = function(form, credentialFields) {
if (!form.action || typeof form.action !== 'string') {
logDebug('Error: Form action is not found.');
return;
}
@ -132,6 +136,7 @@ kpxcForm.onSubmit = async function(e) {
}
if (!form) {
logDebug('Error: No form found for submit detection.');
return;
}

View file

@ -279,6 +279,7 @@ kpxc.initCombinations = async function(inputs = []) {
}
}
logDebug('Login field combinations identified:', combinations);
return combinations;
};
@ -430,6 +431,7 @@ kpxc.passwordFilledWithExceptions = async function(currentForm) {
// Prepares autocomplete and login popup ready for user interaction
kpxc.prepareCredentials = async function() {
if (kpxc.credentials.length === 0) {
logDebug('Error: No combination found.');
return;
}
@ -453,6 +455,7 @@ kpxc.prepareCredentials = async function() {
kpxc.rememberCredentials = async function(usernameValue, passwordValue, urlValue, oldCredentials, useBanner = true) {
const credentials = (oldCredentials !== undefined && oldCredentials.length > 0) ? oldCredentials : kpxc.credentials;
if (passwordValue === '') {
logDebug('Error: Empty password.');
return undefined;
}
@ -531,6 +534,7 @@ kpxc.rememberCredentialsFromContextMenu = async function() {
const type = el.getAttribute('type');
const combination = await kpxcFields.getCombination(el, (type === 'password' ? type : 'username'));
if (!combination) {
logDebug('Error: No combination found.');
return;
}
@ -591,6 +595,7 @@ kpxc.receiveCredentialsIfNecessary = async function() {
// Sets triggerUnlock to true
const credentials = await sendMessage('retrieve_credentials', [ kpxc.url, kpxc.submitUrl, true ]);
if (credentials.length === 0) {
logDebug('Error: No credentials found.');
return [];
}
@ -701,6 +706,7 @@ kpxc.updateTOTPList = async function() {
let uuid = await sendMessage('page_get_login_id');
if (uuid === undefined || kpxc.credentials.length === 0) {
// Credential haven't been selected
logDebug('Error: No credentials selected for TOTP.');
return;
}
@ -734,13 +740,14 @@ const initContentScript = async function() {
try {
const settings = await sendMessage('load_settings');
if (!settings) {
console.log('Error: Cannot load extension settings');
logError('Error: Cannot load extension settings');
return;
}
kpxc.settings = settings;
if (await kpxc.siteIgnored()) {
logDebug('This site is ignored in Site Preferences.');
return;
}
@ -770,7 +777,7 @@ const initContentScript = async function() {
kpxc.rememberCredentials(creds.username, creds.password, creds.url, creds.oldCredentials);
}
} catch (err) {
console.log('initContentScript error: ', err);
logError('initContentScript error: ' + err);
}
};
@ -785,6 +792,7 @@ browser.runtime.onMessage.addListener(async function(req, sender) {
if ('action' in req) {
// Don't allow any actions if the site is ignored
if (await kpxc.siteIgnored()) {
logDebug('This site is ignored in Site Preferences.');
return;
}

View file

@ -181,6 +181,7 @@ kpxcObserverHelper.getInputs = function(target, ignoreVisibility = false) {
}
}
logDebug('Input fields found:', inputs);
return inputs;
};

View file

@ -75,6 +75,7 @@ kpxcTOTPIcons.isValid = function(field, forced) {
|| field.placeholder.match(ignoreRegex)
|| field.readOnly
|| field.inputMode === 'email') {
logDebug('Error: TOTP field found but it is not valid:', field);
return false;
}
} else {

View file

@ -40,7 +40,7 @@ class Icon {
kpxcUI.updateFromIntersectionObserver(this, entries);
});
} catch (err) {
console.log(err);
logError(err);
}
}
@ -210,6 +210,8 @@ kpxcUI.createNotification = function(type, message) {
return;
}
logDebug(message);
const notification = kpxcUI.createElement('div', 'kpxc-notification kpxc-notification-' + type, {});
type = type.charAt(0).toUpperCase() + type.slice(1) + '!';
@ -272,6 +274,12 @@ const createStylesheet = function(file) {
return stylesheet;
};
const logDebug = function(message, extra) {
if (kpxc.settings.debugLogging) {
debugLogMessage(message, extra);
}
};
// Enables dragging
document.addEventListener('mousemove', function(e) {
if (!kpxcUI.mouseDown) {
@ -332,7 +340,7 @@ Element.prototype.attachShadow = function () {
try {
return this._attachShadow({ mode: 'closed' });
} catch (e) {
console.log('Error: ', e);
logError(e);
}
};

View file

@ -43,7 +43,7 @@
<li class="nav-item"><a class="nav-link text-light rounded-sm" href="#about" tabindex="5"><i class="fa fa-info-circle fa-lg pr-2" aria-hidden="true"></i><span data-i18n="optionsMenuAbout"></span></a></li>
</ul>
<footer class="d-none d-md-flex px-3 mt-4 mb-1 text-uppercase position-absolute small text-muted">
(C) 2017-2021 - KeePassXC Team
(C) 2017-2022 - KeePassXC Team
</footer>
</div>
</nav>
@ -381,11 +381,21 @@
<!-- Clear credential timeout -->
<div class="form-group">
<form>
<label for="clearCredentialTimeout" data-i18n="optionsClearCredentialsTimeout"></label>
<br />
<input class="form-input" type="number" id="clearCredentialTimeout" min="0" max="3600" required/>
<span class="form-text text-muted" data-i18n="optionsClearCredentialsTimeoutHelpText"></span>
</form>
<label for="clearCredentialTimeout" data-i18n="optionsClearCredentialsTimeout"></label>
<div class="form-check">
<input class="form-input" type="number" id="clearCredentialTimeout" min="0" max="3600" required/>
<span class="form-text text-muted" data-i18n="optionsClearCredentialsTimeoutHelpText"></span>
</div>
</form>
</div>
<!-- Debug logging -->
<div class="form-group">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="debugLogging" id="debugLogging" value="false" />
<label class="form-check-label" for="debugLogging" data-i18n="optionsDebugLogging"></label>
<span class="form-text text-muted" data-i18n="optionsDebugLoggingHelpText"></span>
</div>
</div>
</div>
</div>

View file

@ -109,6 +109,6 @@ $(async () => {
statusResponse(await browser.runtime.sendMessage({
action: 'get_status'
}).catch((err) => {
console.log('Error: Could not get status: ' + err);
logError('Could not get status: ' + err);
}));
});