mirror of
https://github.com/keepassxreboot/keepassxc-browser.git
synced 2026-03-11 08:54:43 +00:00
Merge branch 'develop'
This commit is contained in:
commit
da2685c6d8
22 changed files with 472 additions and 151 deletions
15
.github/ISSUE_TEMPLATE.md
vendored
15
.github/ISSUE_TEMPLATE.md
vendored
|
|
@ -1,17 +1,19 @@
|
|||
<!--- Provide a general summary of the issue in the title above -->
|
||||
|
||||
## Expected Behavior
|
||||
<!--- If you're describing a bug, tell us what should happen -->
|
||||
<!--- If you're suggesting a change/improvement, tell us how it should work -->
|
||||
|
||||
|
||||
## Current Behavior
|
||||
<!--- If describing a bug, tell us what happens instead of the expected behavior -->
|
||||
<!--- If suggesting a change/improvement, explain the difference from the current behavior -->
|
||||
|
||||
|
||||
## Possible Solution
|
||||
<!--- Not obligatory, but suggest a fix/reason for the bug, -->
|
||||
<!--- or ideas how to implement the addition or change -->
|
||||
|
||||
|
||||
## Steps to Reproduce (for bugs)
|
||||
<!--- Provide a link to a live example, or an unambiguous set of steps to -->
|
||||
<!--- reproduce this bug. Include code to reproduce, if relevant -->
|
||||
|
|
@ -22,11 +24,8 @@
|
|||
|
||||
## Debug info
|
||||
<!--- Please copy/paste the browser's JavaScript console messages and errors here -->
|
||||
|
||||
## General Info
|
||||
KeePassXC fork - VERSION
|
||||
keepassxc-browser - VERSION
|
||||
|
||||
Operating system: OS
|
||||
Browser: BROWSER
|
||||
KeePassXC - {VERSION}
|
||||
keepassxc-browser - {VERSION}
|
||||
Operating system: Mac/Win/Linux
|
||||
Browser: Chrome/Firefox/Vivaldi/Chromium
|
||||
Proxy used: YES/NO
|
||||
|
|
|
|||
12
CHANGELOG
12
CHANGELOG
|
|
@ -1,3 +1,15 @@
|
|||
1.1.0 (09-05-2018)
|
||||
=========================
|
||||
- Allow specifying ignored sites
|
||||
- Add new notification options
|
||||
- Improve detection of username fields
|
||||
- Change conflicting shortcuts
|
||||
- Redetect credential fields after reload
|
||||
- Don't show popup when database is closed
|
||||
- Various password generator fixes
|
||||
- Fix various resource leaks
|
||||
- Fix searching in all databases
|
||||
|
||||
1.0.1 (04-03-2018)
|
||||
=========================
|
||||
- Don't fill password fields if they already have data
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
'use strict';
|
||||
|
||||
const browserAction = {};
|
||||
|
||||
const BLINK_TIMEOUT_DEFAULT = 7500;
|
||||
|
|
@ -202,6 +204,14 @@ browserAction.removeRememberPopup = function(callback, tab, removeImmediately) {
|
|||
browserAction.setRememberPopup = function(tabId, username, password, url, usernameExists, credentialsList) {
|
||||
browser.storage.local.get({'settings': {}}).then(function(item) {
|
||||
const settings = item.settings;
|
||||
|
||||
// Don't show anything if the site is in the ignore list
|
||||
for (const site in settings.ignoredSites) {
|
||||
if (site === url) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const id = tabId || page.currentTabId;
|
||||
let timeoutMinMillis = Number(getValueOrDefault(settings, 'blinkMinTimeout', BLINK_TIMEOUT_REDIRECT_THRESHOLD_TIME_DEFAULT, 0));
|
||||
|
||||
|
|
@ -239,8 +249,30 @@ browserAction.setRememberPopup = function(tabId, username, password, url, userna
|
|||
|
||||
browserAction.show(null, {'id': id});
|
||||
|
||||
if (page.settings.showNotifications) {
|
||||
showNotification('Create or modify the credentials by clicking on the extension icon.');
|
||||
if (page.settings.showLoginNotifications) {
|
||||
const message = 'Create or modify the credentials by clicking on the extension icon.';
|
||||
const buttons = [
|
||||
{
|
||||
'title': 'Close'
|
||||
},
|
||||
{
|
||||
'title': 'Never ask for this page'
|
||||
}];
|
||||
|
||||
browser.notifications.create({
|
||||
'type': 'basic',
|
||||
'iconUrl': browser.extension.getURL('icons/keepassxc_64x64.png'),
|
||||
'title': 'KeePassXC-Browser',
|
||||
'message': message,
|
||||
'buttons': buttons
|
||||
});
|
||||
|
||||
browser.notifications.onButtonClicked.addListener((id, index) => {
|
||||
browser.notifications.clear(id);
|
||||
if (index === 1) {
|
||||
browserAction.ignoreSite(url);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
@ -269,3 +301,21 @@ browserAction.generateIconName = function(iconType, icon) {
|
|||
|
||||
return name;
|
||||
};
|
||||
|
||||
browserAction.ignoreSite = function(url) {
|
||||
browser.windows.getCurrent().then((win) => {
|
||||
// Get current active window
|
||||
browser.tabs.query({ 'active': true, 'currentWindow': true }).then((tabs) => {
|
||||
const tab = tabs[0];
|
||||
|
||||
// Send the message to the current tab's content script
|
||||
browser.runtime.getBackgroundPage().then((global) => {
|
||||
browser.tabs.sendMessage(tab.id, {
|
||||
action: 'ignore-site',
|
||||
args: [url]
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
'use strict';
|
||||
|
||||
const kpxcEvent = {};
|
||||
|
||||
kpxcEvent.onMessage = function(request, sender, callback) {
|
||||
|
|
@ -72,12 +74,15 @@ kpxcEvent.invoke = function(handler, callback, senderTabId, args, secondTime) {
|
|||
else {
|
||||
console.log('undefined handler for tab ' + tab.id);
|
||||
}
|
||||
}).catch((e) => {console.log(e);});
|
||||
}).catch((e) => {
|
||||
console.log(e);
|
||||
});
|
||||
};
|
||||
|
||||
kpxcEvent.onShowAlert = function(callback, tab, message) {
|
||||
if (page.settings.supressAlerts) { console.log(message); }
|
||||
else { alert(message); }
|
||||
kpxcEvent.onShowNotification = function(callback, tab, message) {
|
||||
if (page.settings.showNotifications) {
|
||||
showNotification(message);
|
||||
}
|
||||
};
|
||||
|
||||
kpxcEvent.showStatus = function(configured, tab, callback) {
|
||||
|
|
@ -159,13 +164,18 @@ kpxcEvent.onReconnect = function(callback, tab) {
|
|||
if (gdRes) {
|
||||
keepass.testAssociation((response) => {
|
||||
keepass.isConfigured().then((configured) => {
|
||||
browser.tabs.sendMessage(tab.id, {
|
||||
action: 'redetect_fields'
|
||||
});
|
||||
kpxcEvent.showStatus(configured, tab, callback);
|
||||
}).catch((e) => {console.log(e);});
|
||||
}).catch((e) => {
|
||||
console.log(e);
|
||||
});
|
||||
}, tab);
|
||||
}
|
||||
}, null);
|
||||
});
|
||||
}, 2000);
|
||||
}, 500);
|
||||
};
|
||||
|
||||
kpxcEvent.lockDatabase = function(callback, tab) {
|
||||
|
|
@ -216,7 +226,17 @@ kpxcEvent.onRemoveCredentialsFromTabInformation = function(callback, tab) {
|
|||
};
|
||||
|
||||
kpxcEvent.onSetRememberPopup = function(callback, tab, username, password, url, usernameExists, credentialsList) {
|
||||
browserAction.setRememberPopup(tab.id, username, password, url, usernameExists, credentialsList);
|
||||
keepass.testAssociation((response) => {
|
||||
if (response) {
|
||||
keepass.isConfigured().then((configured) => {
|
||||
if (configured) {
|
||||
browserAction.setRememberPopup(tab.id, username, password, url, usernameExists, credentialsList);
|
||||
}
|
||||
}).catch((e) => {
|
||||
console.log(e);
|
||||
});
|
||||
}
|
||||
}, tab);
|
||||
};
|
||||
|
||||
kpxcEvent.onLoginPopup = function(callback, tab, logins) {
|
||||
|
|
@ -263,20 +283,10 @@ kpxcEvent.pageClearLogins = function(callback, tab, alreadyCalled) {
|
|||
callback();
|
||||
};
|
||||
|
||||
kpxcEvent.oldDatabaseHash = 'no-hash';
|
||||
kpxcEvent.checkDatabaseHash = function(callback, tab) {
|
||||
keepass.checkDatabaseHash((response) => {
|
||||
callback({old: kpxcEvent.oldDatabaseHash, new: response});
|
||||
kpxcEvent.oldDatabaseHash = response;
|
||||
});
|
||||
};
|
||||
|
||||
// all methods named in this object have to be declared BEFORE this!
|
||||
kpxcEvent.messageHandlers = {
|
||||
'add_credentials': keepass.addCredentials,
|
||||
'alert': kpxcEvent.onShowAlert,
|
||||
'associate': keepass.associate,
|
||||
'check_databasehash': kpxcEvent.checkDatabaseHash,
|
||||
'check_update_keepassxc': kpxcEvent.onCheckUpdateKeePassXC,
|
||||
'generate_password': keepass.generatePassword,
|
||||
'get_connected_database': kpxcEvent.onGetConnectedDatabase,
|
||||
|
|
@ -298,6 +308,7 @@ kpxcEvent.messageHandlers = {
|
|||
'update_credentials': keepass.updateCredentials,
|
||||
'save_settings': kpxcEvent.onSaveSettings,
|
||||
'set_remember_credentials': kpxcEvent.onSetRememberPopup,
|
||||
'show_notification': kpxcEvent.onShowNotification,
|
||||
'stack_add': browserAction.stackAdd,
|
||||
'update_available_keepassxc': kpxcEvent.onUpdateAvailableKeePassXC
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
'use strict';
|
||||
|
||||
const httpAuth = {};
|
||||
|
||||
httpAuth.requests = [];
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
'use strict';
|
||||
|
||||
keepass.migrateKeyRing().then(() => {
|
||||
page.initSettings().then(() => {
|
||||
page.initOpenedTabs().then(() => {
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ keepass.keySize = 24;
|
|||
keepass.latestVersionUrl = 'https://api.github.com/repos/keepassxreboot/keepassxc/releases/latest';
|
||||
keepass.cacheTimeout = 30 * 1000; // milliseconds
|
||||
keepass.databaseHash = 'no-hash'; //no-hash = KeePassXC is too old and does not return a hash value
|
||||
keepass.previousDatabaseHash = 'no-hash';
|
||||
keepass.keyId = 'keepassxc-browser-cryptokey-name';
|
||||
keepass.keyBody = 'keepassxc-browser-key';
|
||||
keepass.messageTimeout = 500; // milliseconds
|
||||
|
|
@ -214,15 +215,24 @@ keepass.retrieveCredentials = function(callback, tab, url, submiturl, forceCallb
|
|||
}
|
||||
|
||||
let entries = [];
|
||||
let keys = [];
|
||||
const kpAction = kpActions.GET_LOGINS;
|
||||
const nonce = keepass.getNonce();
|
||||
const incrementedNonce = keepass.incrementedNonce(nonce);
|
||||
const {dbid} = keepass.getCryptoKey();
|
||||
|
||||
for (let keyHash in keepass.keyRing) {
|
||||
keys.push({
|
||||
id: keepass.keyRing[keyHash].id,
|
||||
key: keepass.keyRing[keyHash].key
|
||||
});
|
||||
}
|
||||
|
||||
let messageData = {
|
||||
action: kpAction,
|
||||
id: dbid,
|
||||
url: url
|
||||
url: url,
|
||||
keys: keys
|
||||
};
|
||||
|
||||
if (submiturl) {
|
||||
|
|
@ -704,7 +714,7 @@ keepass.isAssociated = function() {
|
|||
keepass.migrateKeyRing = function() {
|
||||
return new Promise((resolve, reject) => {
|
||||
browser.storage.local.get('keyRing').then((item) => {
|
||||
const keyring = item.keyRing;
|
||||
const keyring = item.keyRing;
|
||||
// Change dates to numbers, for compatibilty with Chromium based browsers
|
||||
if (keyring) {
|
||||
let num = 0;
|
||||
|
|
@ -826,11 +836,22 @@ keepass.onNativeMessage = function(response) {
|
|||
|
||||
// Handle database lock/unlock status
|
||||
if (response.action === kpActions.DATABASE_LOCKED || response.action === kpActions.DATABASE_UNLOCKED) {
|
||||
keepass.testAssociation((response) => {
|
||||
keepass.testAssociation((associationResponse) => {
|
||||
keepass.isConfigured().then((configured) => {
|
||||
let data = page.tabs[page.currentTabId].stack[page.tabs[page.currentTabId].stack.length - 1];
|
||||
data.iconType = configured ? 'normal' : 'cross';
|
||||
browserAction.show(null, {'id': page.currentTabId});
|
||||
|
||||
// Send message to content script
|
||||
browser.tabs.query({ active: true, currentWindow: true }).then((tabs) => {
|
||||
if (tabs.length) {
|
||||
browser.tabs.sendMessage(tabs[0].id, {
|
||||
action: 'check_database_hash',
|
||||
hash: {old: kpxcEvent.previousDatabaseHash, new: keepass.databaseHash}
|
||||
});
|
||||
keepass.previousDatabaseHash = keepass.databaseHash;
|
||||
}
|
||||
});
|
||||
});
|
||||
}, null);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
'use strict';
|
||||
|
||||
const defaultSettings = {
|
||||
checkUpdateKeePassXC: 3,
|
||||
autoCompleteUsernames: true,
|
||||
|
|
@ -5,13 +7,15 @@ const defaultSettings = {
|
|||
usePasswordGenerator: true,
|
||||
autoFillSingleEntry: false,
|
||||
autoRetrieveCredentials: true,
|
||||
showNotifications: true
|
||||
showNotifications: true,
|
||||
showLoginNotifications: true,
|
||||
saveDomainOnly: true
|
||||
};
|
||||
|
||||
var page = {};
|
||||
page.tabs = {};
|
||||
page.tabs = [];
|
||||
page.currentTabId = -1;
|
||||
page.blockedTabs = {};
|
||||
page.blockedTabs = [];
|
||||
|
||||
page.initSettings = function() {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
|
@ -38,6 +42,12 @@ page.initSettings = function() {
|
|||
if (!('showNotifications' in page.settings)) {
|
||||
page.settings.showNotifications = defaultSettings.showNotifications;
|
||||
}
|
||||
if (!('showLoginNotifications' in page.settings)) {
|
||||
page.settings.showLoginNotifications = defaultSettings.showLoginNotifications;
|
||||
}
|
||||
if (!('saveDomainOnly' in page.settings)) {
|
||||
page.settings.saveDomainOnly = defaultSettings.saveDomainOnly;
|
||||
}
|
||||
browser.storage.local.set({'settings': page.settings});
|
||||
resolve(page.settings);
|
||||
});
|
||||
|
|
@ -101,7 +111,7 @@ page.createTabEntry = function(tabId) {
|
|||
page.tabs[tabId] = {
|
||||
'stack': [],
|
||||
'errorMessage': null,
|
||||
'loginList': {}
|
||||
'loginList': []
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
'use strict';
|
||||
|
||||
var isFirefox = function() {
|
||||
if (!(/Chrome/.test(navigator.userAgent) && /Google/.test(navigator.vendor))) {
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
.kpxc .ui-dialog {
|
||||
font-size: 12px !important;
|
||||
box-shadow: 0 4px 6px 0 hsla(0, 0%, 0%, 0.2);
|
||||
z-index: 2147483645;
|
||||
}
|
||||
|
||||
.kpxc .ui-widget-overlay {
|
||||
|
|
@ -57,10 +58,10 @@ input.genpw-text {
|
|||
}
|
||||
|
||||
.genpw-input-group-addon {
|
||||
font-size: inherit !important;
|
||||
font-size: .9em !important;
|
||||
background-color: #eee;
|
||||
border: 1px solid #ccc;
|
||||
padding: .4em;
|
||||
padding: .2em;
|
||||
border-radius: 4px;
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
|
|
@ -102,6 +103,10 @@ input.genpw-text {
|
|||
margin-right: 5px;
|
||||
}
|
||||
|
||||
#cip-genpw-quality {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.b2c-modal-backdrop {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
'use strict';
|
||||
|
||||
// contains already called method names
|
||||
var _called = {};
|
||||
_called.retrieveCredentials = false;
|
||||
_called.clearLogins = false;
|
||||
_called.manualFillRequested = 'none';
|
||||
let _loginId = -1;
|
||||
|
||||
// Count of detected form fields on the page
|
||||
var _detectedFields = 0;
|
||||
|
|
@ -15,10 +18,12 @@ browser.runtime.onMessage.addListener(function(req, sender, callback) {
|
|||
if (cip.u) {
|
||||
cip.setValueWithChange(cip.u, cip.credentials[req.id].login);
|
||||
combination = cipFields.getCombination('username', cip.u);
|
||||
_loginId = req.id;
|
||||
cip.u.focus();
|
||||
}
|
||||
if (cip.p) {
|
||||
cip.setValueWithChange(cip.p, cip.credentials[req.id].password);
|
||||
_loginId = req.id;
|
||||
combination = cipFields.getCombination('password', cip.p);
|
||||
}
|
||||
|
||||
|
|
@ -27,48 +32,44 @@ browser.runtime.onMessage.addListener(function(req, sender, callback) {
|
|||
cipForm.destroy(false, {'password': list.list[0], 'username': list.list[1]});
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (req.action === 'fill_user_pass') {
|
||||
} else if (req.action === 'fill_user_pass') {
|
||||
_called.manualFillRequested = 'both';
|
||||
cip.receiveCredentialsIfNecessary().then((response) => {
|
||||
cip.fillInFromActiveElement(false);
|
||||
});
|
||||
}
|
||||
else if (req.action === 'fill_pass_only') {
|
||||
} else if (req.action === 'fill_pass_only') {
|
||||
_called.manualFillRequested = 'pass';
|
||||
cip.receiveCredentialsIfNecessary().then((response) => {
|
||||
cip.fillInFromActiveElement(false, true); // passOnly to true
|
||||
});
|
||||
}
|
||||
else if (req.action === 'fill_totp') {
|
||||
} else if (req.action === 'fill_totp') {
|
||||
cip.receiveCredentialsIfNecessary().then((response) => {
|
||||
cip.fillInFromActiveElementTOTPOnly(false);
|
||||
});
|
||||
}
|
||||
else if (req.action === 'activate_password_generator') {
|
||||
} else if (req.action === 'activate_password_generator') {
|
||||
cip.initPasswordGenerator(cipFields.getAllFields());
|
||||
}
|
||||
else if (req.action === 'remember_credentials') {
|
||||
} else if (req.action === 'remember_credentials') {
|
||||
cip.contextMenuRememberCredentials();
|
||||
}
|
||||
else if (req.action === 'choose_credential_fields') {
|
||||
} else if (req.action === 'choose_credential_fields') {
|
||||
cipDefine.init();
|
||||
}
|
||||
else if (req.action === 'clear_credentials') {
|
||||
} else if (req.action === 'clear_credentials') {
|
||||
cipEvents.clearCredentials();
|
||||
callback();
|
||||
}
|
||||
else if (req.action === 'activated_tab') {
|
||||
} else if (req.action === 'activated_tab') {
|
||||
cipEvents.triggerActivatedTab();
|
||||
callback();
|
||||
}
|
||||
else if (req.action === 'redetect_fields') {
|
||||
} else if (req.action === 'redetect_fields') {
|
||||
browser.runtime.sendMessage({
|
||||
action: 'load_settings',
|
||||
}).then((response) => {
|
||||
cip.settings = response;
|
||||
cip.initCredentialFields(true);
|
||||
});
|
||||
} else if (req.action === 'ignore-site') {
|
||||
cip.ignoreSite(req.args);
|
||||
}
|
||||
else if (req.action === 'check_database_hash' && 'hash' in req) {
|
||||
cip.detectDatabaseChange(req.hash);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -231,7 +232,7 @@ cipPassword.createDialog = function() {
|
|||
.addClass('genpw-input-group-addon')
|
||||
.addClass('b2c-add-on')
|
||||
.attr('id', 'cip-genpw-quality')
|
||||
.text('123 Bits');
|
||||
.text('??? Bits');
|
||||
$inputGroup.append($textfieldPassword).append($quality);
|
||||
|
||||
const $checkGroup = jQuery('<div>').addClass('genpw-input-group');
|
||||
|
|
@ -305,7 +306,11 @@ cipPassword.createDialog = function() {
|
|||
$password = $password.substring(0, field.attr('maxlength'));
|
||||
jQuery('input#cip-genpw-textfield-password:first').val($password);
|
||||
jQuery('#cip-genpw-btn-clipboard:first').removeClass('b2c-btn-success');
|
||||
alert('The generated password is longer than the allowed length!\nIt has been cut to fit the length.\n\nPlease remember the new password!');
|
||||
const message = 'Error:\nThe generated password is longer than the allowed length!\nIt has been cut to fit the length.\n\nPlease remember the new password!';
|
||||
browser.runtime.sendMessage({
|
||||
action: 'show_notification',
|
||||
args: [message]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -489,7 +494,7 @@ cipForm.init = function(form, credentialFields) {
|
|||
// TODO: could be called multiple times --> update credentialFields
|
||||
|
||||
// not already initialized && password-field is not null
|
||||
if (!form.data('cipForm-initialized') && credentialFields.password) {
|
||||
if (!form.data('cipForm-initialized') && (credentialFields.password || credentialFields.username)) {
|
||||
form.data('cipForm-initialized', true);
|
||||
cipForm.setInputFields(form, credentialFields);
|
||||
form.submit(cipForm.onSubmit);
|
||||
|
|
@ -807,7 +812,7 @@ cipFields.prepareId = function(id) {
|
|||
// Check aria-hidden attribute by looping the parent elements of input field
|
||||
cipFields.getAriaHidden = function(field) {
|
||||
let $par = jQuery(field).parents();
|
||||
for (p of $par) {
|
||||
for (const p of $par) {
|
||||
const val = $(p).attr('aria-hidden');
|
||||
if (val) {
|
||||
return val;
|
||||
|
|
@ -818,7 +823,7 @@ cipFields.getAriaHidden = function(field) {
|
|||
|
||||
cipFields.getOverflowHidden = function(field) {
|
||||
let $par = jQuery(field).parents();
|
||||
for (p of $par) {
|
||||
for (const p of $par) {
|
||||
const val = $(p).css('overflow');
|
||||
if (val === 'hidden') {
|
||||
return true;
|
||||
|
|
@ -889,6 +894,15 @@ cipFields.getAllCombinations = function(inputs) {
|
|||
}
|
||||
}
|
||||
|
||||
// If only username field found, add it to the array
|
||||
if (fields.length === 0 && uField) {
|
||||
const combination = {
|
||||
username: uField[0].getAttribute('data-cip-id'),
|
||||
password: null
|
||||
};
|
||||
fields.push(combination);
|
||||
}
|
||||
|
||||
return fields;
|
||||
};
|
||||
|
||||
|
|
@ -1033,7 +1047,7 @@ cipFields.getPasswordField = function(usernameId, checkDisabled) {
|
|||
// search all inputs on this one form
|
||||
if (form) {
|
||||
passwordField = jQuery('input[type=\'password\']:first', form);
|
||||
if (passwordField.length < 1) {
|
||||
if (passwordField && passwordField.length < 1) {
|
||||
passwordField = null;
|
||||
}
|
||||
|
||||
|
|
@ -1139,7 +1153,6 @@ cip.credentials = [];
|
|||
jQuery(function() {
|
||||
cip.init();
|
||||
cip.detectNewActiveFields();
|
||||
cip.detectDatabaseChange();
|
||||
});
|
||||
|
||||
cip.init = function() {
|
||||
|
|
@ -1166,46 +1179,36 @@ cip.detectNewActiveFields = function() {
|
|||
};
|
||||
|
||||
// Switch credentials if database is changed or closed
|
||||
cip.detectDatabaseChange = function() {
|
||||
let dbDetectInterval = setInterval(function() {
|
||||
if (document.visibilityState !== 'hidden') {
|
||||
cip.detectDatabaseChange = function(response) {
|
||||
if (document.visibilityState !== 'hidden') {
|
||||
if (response.new === 'no-hash' && response.old !== 'no-hash') {
|
||||
cipEvents.clearCredentials();
|
||||
|
||||
browser.runtime.sendMessage({
|
||||
action: 'check_databasehash'
|
||||
action: 'page_clear_logins'
|
||||
});
|
||||
|
||||
// Switch back to default popup
|
||||
browser.runtime.sendMessage({
|
||||
action: 'get_status',
|
||||
args: [ true ] // Set polling to true, this is an internal function call
|
||||
});
|
||||
} else if (response.new !== 'no-hash' && response.new !== response.old) {
|
||||
browser.runtime.sendMessage({
|
||||
action: 'load_settings',
|
||||
}).then((response) => {
|
||||
if (response.new === 'no-hash') {
|
||||
cipEvents.clearCredentials();
|
||||
cip.settings = response;
|
||||
cip.initCredentialFields(true);
|
||||
|
||||
browser.runtime.sendMessage({
|
||||
action: 'page_clear_logins'
|
||||
});
|
||||
|
||||
// Switch back to default popup
|
||||
browser.runtime.sendMessage({
|
||||
action: 'get_status',
|
||||
args: [ true ] // Set polling to true, this is an internal function call
|
||||
});
|
||||
} else {
|
||||
if (response.new !== 'no-hash' && response.new !== response.old) {
|
||||
browser.runtime.sendMessage({
|
||||
action: 'load_settings',
|
||||
}).then((response) => {
|
||||
cip.settings = response;
|
||||
cip.initCredentialFields(true);
|
||||
|
||||
// If user has requested a manual fill through context menu the actual credential filling
|
||||
// is handled here when the opened database has been regognized. It's not a pretty hack.
|
||||
if (_called.manualFillRequested && _called.manualFillRequested !== 'none') {
|
||||
cip.fillInFromActiveElement(false, (_called.manualFillRequested === 'pass' ? true : false));
|
||||
_called.manualFillRequested = 'none';
|
||||
}
|
||||
});
|
||||
}
|
||||
// If user has requested a manual fill through context menu the actual credential filling
|
||||
// is handled here when the opened database has been regognized. It's not a pretty hack.
|
||||
if (_called.manualFillRequested && _called.manualFillRequested !== 'none') {
|
||||
cip.fillInFromActiveElement(false, _called.manualFillRequested === 'pass');
|
||||
_called.manualFillRequested = 'none';
|
||||
}
|
||||
}).catch((e) => {
|
||||
console.log(e);
|
||||
});
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
};
|
||||
|
||||
cip.initCredentialFields = function(forceCall) {
|
||||
|
|
@ -1236,6 +1239,11 @@ cip.initCredentialFields = function(forceCall) {
|
|||
cip.url = document.location.origin;
|
||||
cip.submitUrl = cip.getFormActionUrl(cipFields.combinations[0]);
|
||||
|
||||
// Get submitUrl for a single input
|
||||
if (!cip.submitUrl && cipFields.combinations.length === 1 && inputs.length === 1) {
|
||||
cip.submitUrl = cip.getFormActionUrlFromSingleInput(inputs[0]);
|
||||
}
|
||||
|
||||
if (cip.settings.autoRetrieveCredentials && _called.retrieveCredentials === false && (cip.url && cip.submitUrl)) {
|
||||
browser.runtime.sendMessage({
|
||||
action: 'retrieve_credentials',
|
||||
|
|
@ -1358,7 +1366,9 @@ cip.preparePageForMultipleCredentials = function(credentials) {
|
|||
cipAutocomplete.init(_f(i.username));
|
||||
}
|
||||
} else if (_detectedFields == 1) {
|
||||
// If only password field is the visible one
|
||||
if (_f(i.username)) {
|
||||
cipAutocomplete.init(_f(i.username));
|
||||
}
|
||||
if (_f(i.password)) {
|
||||
cipAutocomplete.init(_f(i.password));
|
||||
}
|
||||
|
|
@ -1392,6 +1402,20 @@ cip.getFormActionUrl = function(combination) {
|
|||
return action;
|
||||
};
|
||||
|
||||
cip.getFormActionUrlFromSingleInput = function(field) {
|
||||
if (!field) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let action = field.formAction;
|
||||
|
||||
if (typeof(action) !== 'string' || action === '') {
|
||||
action = document.location.origin + document.location.pathname;
|
||||
}
|
||||
|
||||
return action;
|
||||
};
|
||||
|
||||
cip.fillInCredentials = function(combination, onlyPassword, suppressWarnings) {
|
||||
const action = cip.getFormActionUrl(combination);
|
||||
|
||||
|
|
@ -1455,9 +1479,9 @@ cip.fillInFromActiveElement = function(suppressWarnings, passOnly = false) {
|
|||
|
||||
if (passOnly) {
|
||||
if (!_f(combination.password)) {
|
||||
const message = 'Unable to find a password field';
|
||||
const message = 'Error:\nUnable to find a password field';
|
||||
browser.runtime.sendMessage({
|
||||
action: 'alert',
|
||||
action: 'show_notification',
|
||||
args: [message]
|
||||
});
|
||||
return;
|
||||
|
|
@ -1473,17 +1497,21 @@ cip.fillInFromActiveElementTOTPOnly = function(suppressWarnings) {
|
|||
const el = document.activeElement;
|
||||
cipFields.setUniqueId(jQuery(el));
|
||||
const fieldId = cipFields.prepareId(jQuery(el).attr('data-cip-id'));
|
||||
const pos = _loginId;
|
||||
|
||||
if (cip.credentials[0]) {
|
||||
if (pos >= 0 && cip.credentials[pos]) {
|
||||
// Check the value from stringFields (to be removed)
|
||||
const $sf = _fs(fieldId);
|
||||
if (cip.credentials[0].stringFields && cip.credentials[0].stringFields.length > 0) {
|
||||
const sFields = cip.credentials[0].stringFields;
|
||||
if (cip.credentials[pos].stringFields && cip.credentials[pos].stringFields.length > 0) {
|
||||
const sFields = cip.credentials[pos].stringFields;
|
||||
for (const s of sFields) {
|
||||
const val = s["KPH: {TOTP}"];
|
||||
if (val) {
|
||||
cip.setValue($sf, val);
|
||||
}
|
||||
}
|
||||
} else if (cip.credentials[pos].totp && cip.credentials[pos].totp.length > 0) {
|
||||
cip.setValue($sf, cip.credentials[pos].totp);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -1539,9 +1567,9 @@ cip.setValueWithChange = function(field, value) {
|
|||
cip.fillIn = function(combination, onlyPassword, suppressWarnings) {
|
||||
// no credentials available
|
||||
if (cip.credentials.length === 0 && !suppressWarnings) {
|
||||
const message = 'No logins found.';
|
||||
const message = 'Error:\nNo logins found.';
|
||||
browser.runtime.sendMessage({
|
||||
action: 'alert',
|
||||
action: 'show_notification',
|
||||
args: [message]
|
||||
});
|
||||
return;
|
||||
|
|
@ -1555,12 +1583,14 @@ cip.fillIn = function(combination, onlyPassword, suppressWarnings) {
|
|||
let filledIn = false;
|
||||
if (uField && !onlyPassword) {
|
||||
cip.setValueWithChange(uField, cip.credentials[0].login);
|
||||
_loginId = 0;
|
||||
filledIn = true;
|
||||
}
|
||||
if (pField) {
|
||||
pField.attr('type', 'password');
|
||||
cip.setValueWithChange(pField, cip.credentials[0].password);
|
||||
pField.data('unchanged', true);
|
||||
_loginId = 0;
|
||||
filledIn = true;
|
||||
}
|
||||
|
||||
|
|
@ -1572,9 +1602,9 @@ cip.fillIn = function(combination, onlyPassword, suppressWarnings) {
|
|||
|
||||
if (!filledIn) {
|
||||
if (!suppressWarnings) {
|
||||
const message = 'Error #101\nCannot find fields to fill in.';
|
||||
const message = 'Error:\nCannot find fields to fill in.';
|
||||
browser.runtime.sendMessage({
|
||||
action: 'alert',
|
||||
action: 'show_notification',
|
||||
args: [message]
|
||||
});
|
||||
}
|
||||
|
|
@ -1585,12 +1615,14 @@ cip.fillIn = function(combination, onlyPassword, suppressWarnings) {
|
|||
let filledIn = false;
|
||||
if (uField) {
|
||||
cip.setValueWithChange(uField, cip.credentials[combination.loginId].login);
|
||||
_loginId = combination.loginId;
|
||||
filledIn = true;
|
||||
}
|
||||
|
||||
if (pField) {
|
||||
cip.setValueWithChange(pField, cip.credentials[combination.loginId].password);
|
||||
pField.data('unchanged', true);
|
||||
_loginId = combination.loginId;
|
||||
filledIn = true;
|
||||
}
|
||||
|
||||
|
|
@ -1602,9 +1634,9 @@ cip.fillIn = function(combination, onlyPassword, suppressWarnings) {
|
|||
|
||||
if (!filledIn) {
|
||||
if (!suppressWarnings) {
|
||||
const message = 'Error #102\nCannot find fields to fill in.';
|
||||
const message = 'Error:\nCannot find fields to fill in.';
|
||||
browser.runtime.sendMessage({
|
||||
action: 'alert',
|
||||
action: 'show_notification',
|
||||
args: [message]
|
||||
});
|
||||
}
|
||||
|
|
@ -1631,7 +1663,7 @@ cip.fillIn = function(combination, onlyPassword, suppressWarnings) {
|
|||
}
|
||||
}
|
||||
|
||||
// for the correct alert message: 0 = no logins, X > 1 = too many logins
|
||||
// for the correct notification message: 0 = no logins, X > 1 = too many logins
|
||||
if (countPasswords === 0) {
|
||||
countPasswords = cip.credentials.length;
|
||||
}
|
||||
|
|
@ -1656,19 +1688,17 @@ cip.fillIn = function(combination, onlyPassword, suppressWarnings) {
|
|||
// user has to select correct credentials by himself
|
||||
if (countPasswords > 1) {
|
||||
if (!suppressWarnings) {
|
||||
const message = 'Error #105\nMore than one login was found in KeePassXC!\n' +
|
||||
'Press the KeePassXC-Browser icon for more options.';
|
||||
browser.runtime.sendMessage({
|
||||
action: 'alert',
|
||||
args: [message]
|
||||
});
|
||||
const $target = onlyPassword ? pField : uField;
|
||||
cipAutocomplete.init($target);
|
||||
$target.focus();
|
||||
jQuery($target).autocomplete('search', jQuery($target).val());
|
||||
}
|
||||
}
|
||||
else if (countPasswords < 1) {
|
||||
if (!suppressWarnings) {
|
||||
const message = 'Error #103\nNo credentials for given username found.';
|
||||
const message = 'Error:\nNo credentials for given username found.';
|
||||
browser.runtime.sendMessage({
|
||||
action: 'alert',
|
||||
action: 'show_notification',
|
||||
args: [message]
|
||||
});
|
||||
}
|
||||
|
|
@ -1676,12 +1706,10 @@ cip.fillIn = function(combination, onlyPassword, suppressWarnings) {
|
|||
}
|
||||
else {
|
||||
if (!suppressWarnings) {
|
||||
const message = 'Error #104\nMore than one login was found in KeePassXC!\n' +
|
||||
'Press the KeePassXC-Browser icon for more options.';
|
||||
browser.runtime.sendMessage({
|
||||
action: 'alert',
|
||||
args: [message]
|
||||
});
|
||||
const $target = onlyPassword ? pField : uField;
|
||||
cipAutocomplete.init($target);
|
||||
$target.focus();
|
||||
jQuery($target).autocomplete('search', jQuery($target).val());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1717,7 +1745,11 @@ cip.contextMenuRememberCredentials = function() {
|
|||
}
|
||||
|
||||
if (!cip.rememberCredentials(usernameValue, passwordValue)) {
|
||||
alert('Could not detect changed credentials.');
|
||||
const message = 'Error:\nCould not detect changed credentials.';
|
||||
browser.runtime.sendMessage({
|
||||
action: 'show_notification',
|
||||
args: [message]
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -1762,7 +1794,7 @@ cip.rememberCredentials = function(usernameValue, passwordValue) {
|
|||
|
||||
let url = jQuery(this)[0].action;
|
||||
if (!url) {
|
||||
url = document.location.href;
|
||||
url = cip.settings.saveDomainOnly ? document.location.origin : document.location.href;
|
||||
if (url.indexOf('?') > 0) {
|
||||
url = url.substring(0, url.indexOf('?'));
|
||||
if (url.length < document.location.origin.length) {
|
||||
|
|
@ -1782,6 +1814,25 @@ cip.rememberCredentials = function(usernameValue, passwordValue) {
|
|||
return false;
|
||||
};
|
||||
|
||||
cip.ignoreSite = function(sites) {
|
||||
if (!sites || sites.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const site = sites[0];
|
||||
if (!cip.settings['ignoredSites']) {
|
||||
cip.settings['ignoredSites'] = {};
|
||||
}
|
||||
|
||||
cip.settings['ignoredSites'][site] = {
|
||||
url: site
|
||||
};
|
||||
|
||||
browser.runtime.sendMessage({
|
||||
action: 'save_settings',
|
||||
args: [cip.settings]
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
var cipEvents = {};
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"manifest_version": 2,
|
||||
"name": "KeePassXC-Browser",
|
||||
"version": "1.0.1",
|
||||
"version_name": "1.0.1",
|
||||
"version": "1.1.0",
|
||||
"version_name": "1.1.0",
|
||||
"description": "KeePassXC integration for modern web browsers",
|
||||
"author": "KeePassXC Team",
|
||||
"icons": {
|
||||
|
|
@ -72,8 +72,8 @@
|
|||
"fill-password": {
|
||||
"description": "Insert a password",
|
||||
"suggested_key": {
|
||||
"default": "Alt+Shift+P",
|
||||
"mac": "MacCtrl+Shift+P"
|
||||
"default": "Alt+Shift+I",
|
||||
"mac": "MacCtrl+Shift+I"
|
||||
}
|
||||
},
|
||||
"fill-totp": {
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
<li class="active"><a href="#general-settings">General</a></li>
|
||||
<li><a href="#connected-databases">Connected Databases</a></li>
|
||||
<li><a href="#specified-fields">Specified credential fields</a></li>
|
||||
<li><a href="#ignored-sites">Ignored sites</a></li>
|
||||
<li><a href="#about">About</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
|
@ -29,9 +30,9 @@
|
|||
<h2>General Settings</h2>
|
||||
<hr />
|
||||
<p>
|
||||
If you just want to insert username + password into the fields where your focus is, press <code>Alt + Shift + U</code>.
|
||||
If you just want to insert username + password into the fields where your focus is, press <code><span id="mac-user-shortcut">Ctrl + Shift + U</span><span id="default-user-shortcut">Alt + Shift + U</span></code>.
|
||||
<br />
|
||||
If you only want to insert the password, just press <code>Alt + Shift + P</code>.
|
||||
If you only want to insert the password, just press <code><span id="mac-pass-shortcut">Ctrl + Shift + I</span><span id="default-pass-shortcut">Alt + Shift + I</span></code>.
|
||||
<span id="chrome-only">You can customize these shortcuts on <code>chrome://extensions/configureCommands</code> page</span>
|
||||
</p>
|
||||
<p>
|
||||
|
|
@ -39,7 +40,7 @@
|
|||
<label for="blinkTimeout">Blink Time:</label>
|
||||
<div class="control-group">
|
||||
<div class="input-append">
|
||||
<input type="number" id="blinkTimeout" placeholder="7500" value="7500" />
|
||||
<input type="number" id="blinkTimeout" placeholder="7500" value="7500" min="0"/>
|
||||
<button class="btn btn-sm btn-primary" id="blinkTimeoutButton" type="button"><span class="glyphicon glyphicon-floppy-disk"></span> Save</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -55,7 +56,7 @@
|
|||
<label for="blinkMinTimeout">Redirect Offset:</label>
|
||||
<div class="control-group">
|
||||
<div class="input-append">
|
||||
<input type="number" id="blinkMinTimeout" placeholder="2000" value="2000" />
|
||||
<input type="number" id="blinkMinTimeout" placeholder="2000" value="2000" min="-1"/>
|
||||
<button class="btn btn-sm btn-primary" id="blinkMinTimeoutButton" type="button"><span class="glyphicon glyphicon-floppy-disk"></span> Save</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -73,7 +74,7 @@
|
|||
<label for="allowedRedirect">Redirect Allowance:</label>
|
||||
<div class="control-group">
|
||||
<div class="input-append">
|
||||
<input type="number" id="allowedRedirect" placeholder="1" value="1" />
|
||||
<input type="number" id="allowedRedirect" placeholder="1" value="1" min="1"/>
|
||||
<button class="btn btn-sm btn-primary" id="allowedRedirectButton" type="button"><span class="glyphicon glyphicon-floppy-disk"></span> Save</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -130,7 +131,21 @@
|
|||
<label class="checkbox">
|
||||
<input type="checkbox" name="showNotifications" value="true" /> Show notifications.
|
||||
</label>
|
||||
<span class="help-block">Allow KeePassXC-Browser to show notifications when user interaction is needed from the extension icon.</span>
|
||||
<span class="help-block">Show notifications for errors and when user interaction is required.</span>
|
||||
</div>
|
||||
<div class="checkbox">
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="showLoginNotifications" value="true" /> Show a notification when new credentials can be saved to the database.
|
||||
</label>
|
||||
</div>
|
||||
</p>
|
||||
<hr />
|
||||
<p>
|
||||
<div class="checkbox">
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="saveDomainOnly" value="true" /> Save domain only.
|
||||
</label>
|
||||
<span class="help-block">When saving new credentials save only the domain instead of full URL.</span>
|
||||
</div>
|
||||
</p>
|
||||
<hr />
|
||||
|
|
@ -274,6 +289,52 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Ignored sites -->
|
||||
<div class="tab" id="tab-ignored-sites">
|
||||
<h2>Ignored sites</h2>
|
||||
<hr />
|
||||
<p>
|
||||
Sites in this list are ignored when new credentials are detected.
|
||||
<br />
|
||||
Go to the page with new credentials, click the blinking KeePassXC-Browser icon or the notification and select <em>Never ask for this page</em>.
|
||||
</p>
|
||||
<table class="table table-striped table-bordered table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Page URL</th>
|
||||
<th>Delete</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="empty">
|
||||
<td colspan="2">No ignored sites found.</td>
|
||||
</tr>
|
||||
<tr class="clone">
|
||||
<td></td>
|
||||
<td><button class="btn delete btn-danger btn"><span class="glyphicon glyphicon-remove-sign"></span> Remove</button></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div id="dialogDeleteIgnoredSite" class="modal fade" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3 id="myModalLabel">Remove site?</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>Do you really want to remove the specified site from the ignore list?</p>
|
||||
<p class="help-block">KeePassXC-Browser will detect new credentials the next time you visit this page.</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn" data-dismiss="modal" aria-hidden="true">Cancel</button>
|
||||
<button class="btn yes btn-primary">Yes, remove now</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- About -->
|
||||
<div class="tab" id="tab-about">
|
||||
<h2>About</h2>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,15 @@
|
|||
'use strict';
|
||||
|
||||
if (jQuery) {
|
||||
var $ = jQuery.noConflict(true);
|
||||
}
|
||||
|
||||
const defaultSettings = {
|
||||
blinkTimeout: 7500,
|
||||
redirectOffset: -1,
|
||||
redirectAllowance: 1
|
||||
};
|
||||
|
||||
$(function() {
|
||||
browser.runtime.sendMessage({ action: 'load_settings' }).then((settings) => {
|
||||
options.settings = settings;
|
||||
|
|
@ -11,6 +19,7 @@ $(function() {
|
|||
options.initGeneralSettings();
|
||||
options.initConnectedDatabases();
|
||||
options.initSpecifiedCredentialFields();
|
||||
options.initIgnoredSites();
|
||||
options.initAbout();
|
||||
});
|
||||
});
|
||||
|
|
@ -111,7 +120,7 @@ options.initGeneralSettings = function() {
|
|||
|
||||
$('#blinkTimeoutButton').click(function(){
|
||||
const blinkTimeout = $.trim($('#blinkTimeout').val());
|
||||
const blinkTimeoutval = Number(blinkTimeout);
|
||||
const blinkTimeoutval = blinkTimeout !== '' ? Number(blinkTimeout) : defaultSettings.blinkTimeout;
|
||||
|
||||
options.settings['blinkTimeout'] = String(blinkTimeoutval);
|
||||
options.saveSetting('blinkTimeout');
|
||||
|
|
@ -119,7 +128,7 @@ options.initGeneralSettings = function() {
|
|||
|
||||
$('#blinkMinTimeoutButton').click(function(){
|
||||
const blinkMinTimeout = $.trim($('#blinkMinTimeout').val());
|
||||
const blinkMinTimeoutval = Number(blinkMinTimeout);
|
||||
const blinkMinTimeoutval = blinkMinTimeout !== '' ? Number(blinkMinTimeout) : defaultSettings.redirectOffset;
|
||||
|
||||
options.settings['blinkMinTimeout'] = String(blinkMinTimeoutval);
|
||||
options.saveSetting('blinkMinTimeout');
|
||||
|
|
@ -127,7 +136,7 @@ options.initGeneralSettings = function() {
|
|||
|
||||
$('#allowedRedirectButton').click(function(){
|
||||
const allowedRedirect = $.trim($('#allowedRedirect').val());
|
||||
const allowedRedirectval = Number(allowedRedirect);
|
||||
const allowedRedirectval = allowedRedirect !== '' ? Number(allowedRedirect) : defaultSettings.redirectAllowance;
|
||||
|
||||
options.settings['allowedRedirect'] = String(allowedRedirectval);
|
||||
options.saveSetting('allowedRedirect');
|
||||
|
|
@ -167,8 +176,7 @@ options.initConnectedDatabases = function() {
|
|||
|
||||
if ($('#tab-connected-databases table tbody:first tr').length > 2) {
|
||||
$('#tab-connected-databases table tbody:first tr.empty:first').hide();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
$('#tab-connected-databases table tbody:first tr.empty:first').show();
|
||||
}
|
||||
});
|
||||
|
|
@ -195,8 +203,7 @@ options.initConnectedDatabases = function() {
|
|||
|
||||
if ($('#tab-connected-databases table tbody:first tr').length > 2) {
|
||||
$('#tab-connected-databases table tbody:first tr.empty:first').hide();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
$('#tab-connected-databases table tbody:first tr.empty:first').show();
|
||||
}
|
||||
|
||||
|
|
@ -229,8 +236,7 @@ options.initSpecifiedCredentialFields = function() {
|
|||
|
||||
if ($('#tab-specified-fields table tbody:first tr').length > 2) {
|
||||
$('#tab-specified-fields table tbody:first tr.empty:first').hide();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
$('#tab-specified-fields table tbody:first tr.empty:first').show();
|
||||
}
|
||||
});
|
||||
|
|
@ -242,7 +248,7 @@ options.initSpecifiedCredentialFields = function() {
|
|||
const $tr = $trClone.clone(true);
|
||||
$tr.data('url', url);
|
||||
$tr.attr('id', 'tr-scf' + counter);
|
||||
counter += 1;
|
||||
++counter;
|
||||
|
||||
$tr.children('td:first').text(url);
|
||||
$('#tab-specified-fields table tbody:first').append($tr);
|
||||
|
|
@ -250,15 +256,73 @@ options.initSpecifiedCredentialFields = function() {
|
|||
|
||||
if ($('#tab-specified-fields table tbody:first tr').length > 2) {
|
||||
$('#tab-specified-fields table tbody:first tr.empty:first').hide();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
$('#tab-specified-fields table tbody:first tr.empty:first').show();
|
||||
}
|
||||
};
|
||||
|
||||
options.initIgnoredSites = function() {
|
||||
$('#dialogDeleteIgnoredSite').modal({keyboard: true, show: false, backdrop: true});
|
||||
$('#tab-ignored-sites tr.clone:first button.delete:first').click(function(e) {
|
||||
e.preventDefault();
|
||||
$('#dialogDeleteIgnoredSite').data('url', $(this).closest('tr').data('url'));
|
||||
$('#dialogDeleteIgnoredSite').data('tr-id', $(this).closest('tr').attr('id'));
|
||||
$('#dialogDeleteIgnoredSite .modal-body:first strong:first').text($(this).closest('tr').children('td:first').text());
|
||||
$('#dialogDeleteIgnoredSite').modal('show');
|
||||
});
|
||||
|
||||
$('#dialogDeleteIgnoredSite .modal-footer:first button.yes:first').click(function(e) {
|
||||
$('#dialogDeleteIgnoredSite').modal('hide');
|
||||
|
||||
const $url = $('#dialogDeleteIgnoredSite').data('url');
|
||||
const $trId = $('#dialogDeleteIgnoredSite').data('tr-id');
|
||||
$('#tab-ignored-sites #' + $trId).remove();
|
||||
|
||||
delete options.settings['ignoredSites'][$url];
|
||||
options.saveSettings();
|
||||
|
||||
if ($('#tab-ignored-sites table tbody:first tr').length > 2) {
|
||||
$('#tab-ignored-sites table tbody:first tr.empty:first').hide();
|
||||
} else {
|
||||
$('#tab-ignored-sites table tbody:first tr.empty:first').show();
|
||||
}
|
||||
});
|
||||
|
||||
const $trClone = $('#tab-ignored-sites table tr.clone:first').clone(true);
|
||||
$trClone.removeClass('clone');
|
||||
let counter = 1;
|
||||
for (let url in options.settings['ignoredSites']) {
|
||||
const $tr = $trClone.clone(true);
|
||||
$tr.data('url', url);
|
||||
$tr.attr('id', 'tr-scf' + counter);
|
||||
++counter;
|
||||
|
||||
$tr.children('td:first').text(url);
|
||||
$('#tab-ignored-sites table tbody:first').append($tr);
|
||||
}
|
||||
|
||||
if ($('#tab-ignored-sites table tbody:first tr').length > 2) {
|
||||
$('#tab-ignored-sites table tbody:first tr.empty:first').hide();
|
||||
} else {
|
||||
$('#tab-ignored-sites table tbody:first tr.empty:first').show();
|
||||
}
|
||||
};
|
||||
|
||||
options.initAbout = function() {
|
||||
$('#tab-about em.versionCIP').text(browser.runtime.getManifest().version);
|
||||
if (isFirefox()) {
|
||||
$('#chrome-only').remove();
|
||||
}
|
||||
|
||||
if (navigator.platform === 'MacIntel') {
|
||||
$('#default-user-shortcut').hide();
|
||||
$('#default-pass-shortcut').hide();
|
||||
$('#mac-user-shortcut').show();
|
||||
$('#mac-pass-shortcut').show();
|
||||
} else {
|
||||
$('#mac-user-shortcut').hide();
|
||||
$('#mac-pass-shortcut').hide();
|
||||
$('#default-user-shortcut').show();
|
||||
$('#default-pass-shortcut').show();
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
<button id="btn-choose-credential-fields" class="btn btn-sm btn-warning"><span class="glyphicon glyphicon-list-alt"></span> Choose own credential fields for this page</button>
|
||||
<button id="lock-database-button" class="btn btn-danger" title="Lock database"><span class="glyphicon glyphicon-lock"></span></button>
|
||||
|
||||
<div id="update-available" class="alert alert-danger">
|
||||
<div id="update-available" class="alert alert-danger" style="display: none">
|
||||
You use an old version of KeePassXC.
|
||||
<br />
|
||||
<a target="_blank" class="alert-link" href="https://keepassxc.org/download">Please download the latest version from keepassxc.org</a>.
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
'use strict';
|
||||
|
||||
function status_response(r) {
|
||||
$('#initial-state').hide();
|
||||
$('#error-encountered').hide();
|
||||
|
|
@ -6,6 +8,7 @@ function status_response(r) {
|
|||
$('#configured-and-associated').hide();
|
||||
$('#configured-not-associated').hide();
|
||||
$('#lock-database-button').hide();
|
||||
$('#update-available').hide();
|
||||
|
||||
if (!r.keePassXCAvailable) {
|
||||
$('#error-message').html(r.error);
|
||||
|
|
|
|||
|
|
@ -1,12 +1,11 @@
|
|||
'use strict';
|
||||
|
||||
var $ = jQuery.noConflict(true);
|
||||
|
||||
function updateAvailableResponse(available) {
|
||||
if (available) {
|
||||
$('#update-available').show();
|
||||
}
|
||||
else {
|
||||
$('#update-available').hide();
|
||||
}
|
||||
}
|
||||
|
||||
function initSettings() {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
'use strict';
|
||||
|
||||
$(function() {
|
||||
browser.runtime.getBackgroundPage().then((global) => {
|
||||
browser.tabs.query({'active': true, 'currentWindow': true}).then((tabs) => {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
'use strict';
|
||||
|
||||
$(function() {
|
||||
browser.runtime.getBackgroundPage().then((global) => {
|
||||
browser.tabs.query({'active': true, 'currentWindow': true}).then((tabs) => {
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
<button id="btn-new" class="btn btn-sm btn-success"><span class="glyphicon glyphicon-pencil"></span> New</button>
|
||||
<button id="btn-update" class="btn btn-sm btn-warning"><span class="glyphicon glyphicon-refresh"></span> Update</button>
|
||||
<button id="btn-dismiss" class="btn btn-sm btn-danger"><span class="glyphicon glyphicon-remove"></span> Dismiss</button>
|
||||
<button id="btn-ignore" class="btn btn-sm btn-default"><span class="glyphicon glyphicon-remove"></span> Never ask for this page</button>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
'use strict';
|
||||
|
||||
var _tab;
|
||||
|
||||
function _initialize(tab) {
|
||||
|
|
@ -78,6 +80,21 @@ function _initialize(tab) {
|
|||
e.preventDefault();
|
||||
_close();
|
||||
});
|
||||
|
||||
$('#btn-ignore').click(function(e) {
|
||||
browser.windows.getCurrent().then((win) => {
|
||||
browser.tabs.query({ 'active': true, 'currentWindow': true }).then((tabs) => {
|
||||
const tab = tabs[0];
|
||||
browser.runtime.getBackgroundPage().then((global) => {
|
||||
browser.tabs.sendMessage(tab.id, {
|
||||
action: 'ignore-site',
|
||||
args: [_tab.credentials.url]
|
||||
});
|
||||
_close();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function _connected_database(db) {
|
||||
|
|
|
|||
|
|
@ -158,7 +158,14 @@ Unencrypted message:
|
|||
{
|
||||
"action": "get-logins",
|
||||
"url": "<snip>",
|
||||
"submitUrl": optional
|
||||
"submitUrl": optional,
|
||||
"keys": [
|
||||
{
|
||||
"id": <connected_id>,
|
||||
"key": <connected_key>
|
||||
},
|
||||
...
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue