Merge pull request #128 from keepassxreboot/no_jquery

No jQuery
This commit is contained in:
Sami Vänttinen 2019-04-10 13:48:27 +03:00 committed by GitHub
commit c852ba226d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
35 changed files with 3060 additions and 2715 deletions

1
.gitignore vendored
View file

@ -9,3 +9,4 @@
.bz
.bz2
.xz
node_modules/*

View file

@ -112,7 +112,7 @@
"description": "Checkbox text below the password generator input field."
},
"passwordGeneratorBits": {
"message": "??? Bits",
"message": "$1 Bits",
"description": "Bits of the generated password."
},
"passwordGeneratorTitle": {
@ -123,6 +123,10 @@
"message": "Generate",
"description": "Generate button text in password generator."
},
"passwordGeneratorTryAgain": {
"message": "Try again",
"description": "Generate button text in password generator when not connected."
},
"passwordGeneratorCopy": {
"message": "Copy",
"description": "Copy button text in password generator."
@ -132,7 +136,15 @@
"description": "Fill and copy button text in password generator."
},
"passwordGeneratorErrorTooLong": {
"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!",
"message": "Error: The generated password is longer than the allowed length!",
"description": "A warning text shown in the password generator."
},
"passwordGeneratorErrorTooLongCut": {
"message": "It has been cut to fit the length.",
"description": "A warning text shown in the password generator."
},
"passwordGeneratorErrorTooLongRemember": {
"message": "Please remember the new password!",
"description": "A warning text shown in the password generator."
},
"passwordGeneratorGenerateText": {
@ -140,7 +152,11 @@
"description": "Password icon title text."
},
"passwordGeneratorError": {
"message": "Cannot receive generated password.<br />Is KeePassXC running?",
"message": "Cannot receive generated password.",
"description": "Password generator error text when KeePassXC is closed."
},
"passwordGeneratorErrorIsRunning": {
"message": "Is KeePassXC running and connected?",
"description": "Password generator error text when KeePassXC is closed."
},
"defineDismiss": {
@ -208,27 +224,31 @@
"description": "Shown when no username is set in the credentials."
},
"credentialsNoLoginsFound": {
"message": "Error:\nNo logins found.",
"message": "Error: No logins found.",
"description": "Shown when no credentials are found for the current page."
},
"credentialsMultipleFound": {
"message": "Error:\nMore than one login was found in KeePassXC!\nPress the KeePassXC-Browser icon for more options.",
"message": "Error: More than one login was found in KeePassXC!",
"description": "Alert message when trying to fill username and/or password when multiple credentials are found."
},
"credentialsMultipleFoundSecondLine": {
"message": "Press the KeePassXC-Browser icon for more options.",
"description": "Alert message when trying to fill username and/or password when multiple credentials are found."
},
"credentialsNoUsernameFound": {
"message": "Error:\nNo credentials for the given username found.",
"message": "Error: No credentials for the given username found.",
"description": "Alert message when no credentials are found for the given username."
},
"fieldsFill": {
"message": "Error:\nCannot find fields to fill in.",
"message": "Error: Cannot find fields to fill in.",
"description": "Alert message when no fields are found to fill in."
},
"fieldsNoPasswordField": {
"message": "Error:\nUnable to find a password field.",
"message": "Error: Unable to find a password field.",
"description": "Message shown when no password fields are found."
},
"rememberNothingChanged": {
"message": "Error:\nCould not detect changed credentials.",
"message": "Error: Could not detect changed credentials.",
"description": "Message shown when trying to save credentials that haven't changed."
},
"popupTitle": {
@ -323,12 +343,12 @@
"message": "Please choose the group you want to add the new credentials.",
"description": "A popup message shown choosing what group user wants to use for new credentials."
},
"popupRememberErrorDefaultGroupNotFound": {
"message": "Error: Specified default group not found. Creating all necessary groups.",
"description": "Error message shown when default group set cannot be found."
"popupRememberInfoDefaultGroupNotFound": {
"message": "Info: Default group created in connected database.",
"description": "Info message shown when default group set cannot be found."
},
"popupRememberErrorCreatingNewGroup": {
"message": "New group(s) cannot be created.",
"message": "Error: New group(s) cannot be created.",
"description": "Error message shown when new groups cannot be created."
},
"popupRememberErrorPasswordNotChanged": {
@ -503,6 +523,10 @@
"message": "Automatically retrieve credentials.",
"description": "Automatically retrieve credentials checkbox text."
},
"optionsCheckboxAutomaticReconnect": {
"message": "Automatically reconnect to KeePassXC.",
"description": "Auto-reconnect checkbox text."
},
"optionsCheckboxAutoFillSingleEntry": {
"message": "Automatically fill in single-credential entries.",
"description": "Automatically fill-in single credential entry checkbox text."
@ -579,6 +603,10 @@
"message": "KeePassXC-Browser will immediately retrieve credentials when a tab is activated.",
"description": "Auto-Retrive Credentials option help text."
},
"optionsAutomaticReconnectHelpText": {
"message": "Reconnects automatically to KeePassXC when it is detected.",
"description": "Auto-reconnect option help text."
},
"optionsAutoFillSingleEntryHelpText": {
"message": "Let KeePassXC-Browser automatically fill in credentials if it receives only a single entry.",
"description": "Auto-Fill Single Entry option help text."
@ -731,6 +759,10 @@
"message": "Go to the page and click on the KeePassXC-Browser icon, then select ",
"description": "Saved custom login fields info text, second part."
},
"optionsCustomFieldsTabHelpTextThird": {
"message": "On this page you can manage saved custom login fields.",
"description": "Saved custom login fields info text, third part."
},
"optionsCustomFieldsRemove": {
"message": "Remove saved custom login fields?",
"description": "Confirmation text when removing saved custom login fields."

View file

@ -193,7 +193,7 @@ browserAction.removeRememberPopup = function(callback, tab, removeImmediately) {
const currentMS = Date.now();
if (removeImmediately || (data.visibleForPageUpdates <= 0 && data.redirectOffset > 0)) {
browserAction.stackPop(tab.id);
browserAction.show(null, { 'id': tab.id });
browserAction.show(null, { 'id': tab.id } );
page.clearCredentials(tab.id);
} else if (!isNaN(data.visibleForPageUpdates) && data.redirectOffset > 0 && currentMS >= data.redirectOffset) {
data.visibleForPageUpdates -= 1;
@ -205,7 +205,7 @@ browserAction.setRememberPopup = function(tabId, username, password, url, userna
browser.storage.local.get({ 'settings': {} }).then(function(item) {
const settings = item.settings;
// Don't show anything if the site is in the ignore
// Don't show anything if the site is in the ignore
if (settings.sitePreferences !== undefined) {
for (const site of settings.sitePreferences) {
if (site.ignore === IGNORE_NORMAL && (site.url === url || siteMatch(site.url, url))) {
@ -233,7 +233,7 @@ browserAction.setRememberPopup = function(tabId, username, password, url, userna
index: 0,
counter: 0,
max: 2,
icons: [ 'icon_remember_red_background_19x19.png', 'icon_remember_red_lock_19x19.png' ]
icons: ['icon_remember_red_background_19x19.png', 'icon_remember_red_lock_19x19.png']
},
icon: 'icon_remember_red_background_19x19.png',
popup: 'popup_remember.html'
@ -271,8 +271,8 @@ browserAction.setRememberPopup = function(tabId, username, password, url, userna
'buttons': buttons
});
browser.notifications.onButtonClicked.addListener((id, index) => {
browser.notifications.clear(id);
browser.notifications.onButtonClicked.addListener((notificationId, index) => {
browser.notifications.clear(notificationId);
if (index === 1) {
browserAction.ignoreSite(url);
}

View file

@ -99,7 +99,7 @@ kpxcEvent.showStatus = function(configured, tab, callback) {
keePassXCAvailable: keepass.isKeePassXCAvailable,
encryptionKeyUnrecognized: keepass.isEncryptionKeyUnrecognized,
associated: keepass.isAssociated(),
error: errorMessage ? errorMessage : null
error: errorMessage || null
});
};
@ -192,16 +192,16 @@ kpxcEvent.onGetConnectedDatabase = function(callback, tab) {
kpxcEvent.onGetKeePassXCVersions = function(callback, tab) {
if (keepass.currentKeePassXC === '') {
keepass.getDatabaseHash((res) => {
callback({'current': keepass.currentKeePassXC, 'latest': keepass.latestKeePassXC.version});
callback({ 'current': keepass.currentKeePassXC, 'latest': keepass.latestKeePassXC.version });
}, tab);
} else {
callback({'current': keepass.currentKeePassXC, 'latest': keepass.latestKeePassXC.version});
callback({ 'current': keepass.currentKeePassXC, 'latest': keepass.latestKeePassXC.version });
}
};
kpxcEvent.onCheckUpdateKeePassXC = function(callback, tab) {
keepass.checkForNewKeePassXCVersion();
callback({current: keepass.currentKeePassXC.version, latest: keepass.latestKeePassXC.version});
callback({ current: keepass.currentKeePassXC.version, latest: keepass.latestKeePassXC.version });
};
kpxcEvent.onUpdateAvailableKeePassXC = function(callback, tab) {
@ -285,6 +285,8 @@ kpxcEvent.messageHandlers = {
'associate': keepass.associate,
'check_update_keepassxc': kpxcEvent.onCheckUpdateKeePassXC,
'create_new_group': keepass.createNewGroup,
'enable_automatic_reconnect': keepass.enableAutomaticReconnect,
'disable_automatic_reconnect': keepass.disableAutomaticReconnect,
'generate_password': keepass.generatePassword,
'get_connected_database': kpxcEvent.onGetConnectedDatabase,
'get_database_groups': keepass.getDatabaseGroups,

View file

@ -20,11 +20,11 @@ httpAuth.init = function() {
browser.webRequest.onErrorOccurred.removeListener(httpAuth.requestCompleted);
}
// only intercept http auth requests if the option is turned on.
// Only intercept http auth requests if the option is turned on.
if (page.settings.autoFillAndSend) {
const opts = { urls: ['<all_urls>'] };
const opts = { urls: [ '<all_urls>' ] };
browser.webRequest.onAuthRequired.addListener(handleReq, opts, [reqType]);
browser.webRequest.onAuthRequired.addListener(handleReq, opts, [ reqType ]);
browser.webRequest.onCompleted.addListener(httpAuth.requestCompleted, opts);
browser.webRequest.onErrorOccurred.addListener(httpAuth.requestCompleted, opts);
}
@ -75,7 +75,7 @@ httpAuth.processPendingCallbacks = async function(details, resolve, reject) {
httpAuth.loginOrShowCredentials = function(logins, details, resolve, reject) {
// At least one login found --> use first to login
if (logins.length > 0 && page.settings.autoFillAndSend) {
if (logins.length > 0 && page.settings.autoFillAndSend) {
if (logins.length === 1) {
resolve({
authCredentials: {

View file

@ -7,6 +7,7 @@ keepass.migrateKeyRing().then(() => {
keepass.connectToNative();
keepass.generateNewKeyPair();
keepass.changePublicKeys(null).then((pkRes) => {
keepass.enableAutomaticReconnect();
keepass.getDatabaseHash((gdRes) => {}, null);
});
});
@ -85,11 +86,11 @@ const contextMenuItems = [
{ title: tr('contextMenuFillPassword'), action: 'fill_password' },
{ title: tr('contextMenuFillTOTP'), action: 'fill_totp' },
{ title: tr('contextMenuShowPasswordGeneratorIcons'), action: 'activate_password_generator' },
{ title: tr('contextMenuSaveCredentials'), action: 'remember_credentials' },
{ title: tr('contextMenuShowPasswordGenerator'), action: 'show_password_generator' }
{ title: tr('contextMenuShowPasswordGenerator'), action: 'show_password_generator' },
{ title: tr('contextMenuSaveCredentials'), action: 'remember_credentials' }
];
const menuContexts = ['editable'];
const menuContexts = [ 'editable' ];
if (isFirefox()) {
menuContexts.push('password');
@ -103,8 +104,8 @@ for (const item of contextMenuItems) {
onclick: (info, tab) => {
browser.tabs.sendMessage(tab.id, {
action: item.action
}).catch((e) => {
console.log(e);
}).catch((err) => {
console.log(err);
});
}
});

View file

@ -1,8 +1,8 @@
'use strict';
const keepass = {};
keepass.associated = {'value': false, 'hash': null};
keepass.keyPair = {publicKey: null, secretKey: null};
keepass.associated = { 'value': false, 'hash': null };
keepass.keyPair = { publicKey: null, secretKey: null };
keepass.serverPublicKey = '';
keepass.clientID = '';
keepass.isConnected = false;
@ -22,6 +22,7 @@ keepass.keyId = 'keepassxc-browser-cryptokey-name';
keepass.keyBody = 'keepassxc-browser-key';
keepass.messageTimeout = 500; // Milliseconds
keepass.nonce = nacl.util.encodeBase64(nacl.randomBytes(keepass.keySize));
keepass.reconnectLoop = null;
const kpActions = {
SET_LOGIN: 'set-login',
@ -80,11 +81,9 @@ const kpErrors = {
}
};
browser.storage.local.get({
'latestKeePassXC': { 'version': '', 'lastChecked': null },
'keyRing': {}}).then((item) => {
keepass.latestKeePassXC = item.latestKeePassXC;
keepass.keyRing = item.keyRing;
browser.storage.local.get({ 'latestKeePassXC': { 'version': '', 'lastChecked': null }, 'keyRing': {} }).then((item) => {
keepass.latestKeePassXC = item.latestKeePassXC;
keepass.keyRing = item.keyRing;
});
keepass.sendNativeMessage = function(request, enableTimeout = false) {
@ -134,7 +133,6 @@ keepass.addCredentials = function(callback, tab, username, password, url, group,
};
keepass.updateCredentials = function(callback, tab, entryId, username, password, url, group, groupUuid) {
page.debug('keepass.updateCredentials(callback, {1}, {2}, {3}, [password], {4})', tab.id, entryId, username, url);
if (tab && page.tabs[tab.id]) {
page.tabs[tab.id].errorMessage = null;
}
@ -199,8 +197,6 @@ keepass.updateCredentials = function(callback, tab, entryId, username, password,
};
keepass.retrieveCredentials = function(callback, tab, url, submiturl, forceCallback, triggerUnlock = false, httpAuth = false) {
page.debug('keepass.retrieveCredentials(callback, {1}, {2}, {3}, {4})', tab.id, url, submiturl, forceCallback);
keepass.testAssociation((response) => {
if (!response) {
browserAction.showDefault(null, tab);
@ -220,12 +216,12 @@ keepass.retrieveCredentials = function(callback, tab, url, submiturl, forceCallb
}
let entries = [];
let keys = [];
const keys = [];
const kpAction = kpActions.GET_LOGINS;
const nonce = keepass.getNonce();
const incrementedNonce = keepass.incrementedNonce(nonce);
const { dbid } = keepass.getCryptoKey();
for (const keyHash in keepass.keyRing) {
keys.push({
id: keepass.keyRing[keyHash].id,
@ -279,7 +275,6 @@ keepass.retrieveCredentials = function(callback, tab, url, submiturl, forceCallb
} else {
console.log('RetrieveCredentials for ' + url + ' rejected');
}
page.debug('keepass.retrieveCredentials() => entries.length = {1}', entries.length);
} else if (response.error && response.errorCode) {
keepass.handleError(tab, response.errorCode, response.error);
callback([]);
@ -291,7 +286,7 @@ keepass.retrieveCredentials = function(callback, tab, url, submiturl, forceCallb
}, tab, false, triggerUnlock);
};
keepass.generatePassword = function(callback, tab, forceCallback) {
keepass.generatePassword = function(callback, tab) {
if (!keepass.isConnected) {
callback([]);
return;
@ -300,9 +295,7 @@ keepass.generatePassword = function(callback, tab, forceCallback) {
keepass.testAssociation((taresponse) => {
if (!taresponse) {
browserAction.showDefault(null, tab);
if (forceCallback) {
callback([]);
}
callback([]);
return;
}
@ -359,7 +352,7 @@ keepass.associate = function(callback, tab) {
return;
}
keepass.getDatabaseHash((res) => {
keepass.getDatabaseHash((hash) => {
if (keepass.isDatabaseClosed || !keepass.isKeePassXCAvailable) {
callback([]);
return;
@ -421,11 +414,22 @@ keepass.associate = function(callback, tab) {
}, tab);
};
keepass.testAssociation = function(callback, tab, enableTimeout = false, triggerUnlock = false) {
keepass.testAssociation = async function(callback, tab, enableTimeout = false, triggerUnlock = false) {
if (tab && page.tabs[tab.id]) {
page.tabs[tab.id].errorMessage = null;
}
if (!keepass.isKeePassXCAvailable && !page.settings.automaticReconnect) {
try {
keepass.connectToNative();
await keepass.reconnect();
} catch (err) {
keepass.handleError(tab, kpErrors.PUBLIC_KEY_NOT_FOUND);
callback(false);
return false;
}
}
keepass.getDatabaseHash((dbHash) => {
if (!dbHash) {
callback(false);
@ -622,8 +626,8 @@ keepass.changePublicKeys = function(tab, enableTimeout = false) {
if (!keepass.verifyKeyResponse(response, key, incrementedNonce)) {
if (tab && page.tabs[tab.id]) {
keepass.handleError(tab, kpErrors.KEY_CHANGE_FAILED);
reject(false);
}
reject(false);
} else {
keepass.isKeePassXCAvailable = true;
console.log('Server public key: ' + nacl.util.encodeBase64(keepass.serverPublicKey));
@ -846,10 +850,10 @@ keepass.migrateKeyRing = function() {
// Change dates to numbers, for compatibilty with Chromium based browsers
if (keyring) {
let num = 0;
for (let keyHash in keyring) {
let key = keyring[keyHash];
['created', 'lastUsed'].forEach((fld) => {
let v = key[fld];
for (const keyHash in keyring) {
const key = keyring[keyHash];
[ 'created', 'lastUsed' ].forEach((fld) => {
const v = key[fld];
if (v instanceof Date && v.valueOf() >= 0) {
key[fld] = v.valueOf();
num++;
@ -1127,25 +1131,32 @@ keepass.decrypt = function(input, nonce) {
};
keepass.enableAutomaticReconnect = function() {
setInterval(() => {
if (!keepass.isKeePassXCAvailable) {
keepass.connectToNative();
keepass.reconnect();
}
}, 1000);
// Disable for Windows if KeePassXC is older than 2.3.4
if (!page.settings.automaticReconnect ||
(navigator.platform.toLowerCase().includes('win') && !keepass.compareVersion('2.3.4', keepass.currentKeePassXC))) {
return;
}
if (keepass.reconnectLoop === null) {
keepass.reconnectLoop = setInterval(() => {
if (!keepass.isKeePassXCAvailable) {
keepass.connectToNative();
keepass.reconnect().catch((e) => {});
}
}, 1000);
}
};
keepass.disableAutomaticReconnect = function() {
clearInterval(keepass.reconnectLoop);
keepass.reconnectLoop = null;
};
keepass.reconnect = function(callback, tab) {
return new Promise((resolve, reject) => {
keepass.generateNewKeyPair();
keepass.changePublicKeys(tab).then((pkRes) => {
// Database hash should be received if the reconnection succeeded
keepass.changePublicKeys(tab, true).then((pkRes) => {
keepass.getDatabaseHash((gdRes) => {
if (!gdRes) {
reject(false);
return;
}
keepass.testAssociation((response) => {
keepass.isConfigured().then((configured) => {
resolve(configured);
@ -1155,6 +1166,8 @@ keepass.reconnect = function(callback, tab) {
});
}, tab);
}, null);
}).catch((e) => {
reject(e);
});
});
};
@ -1178,7 +1191,7 @@ keepass.updateDatabase = function() {
if (tabs.length) {
browser.tabs.sendMessage(tabs[0].id, {
action: 'check_database_hash',
hash: {old: keepass.previousDatabaseHash, new: keepass.databaseHash}
hash: { old: keepass.previousDatabaseHash, new: keepass.databaseHash }
});
keepass.previousDatabaseHash = keepass.databaseHash;
}

View file

@ -10,6 +10,7 @@ const defaultSettings = {
showNotifications: true,
showLoginNotifications: true,
saveDomainOnly: true,
automaticReconnect: true,
defaultGroup: '',
defaultGroupAlwaysAsk: false
};
@ -51,6 +52,9 @@ page.initSettings = function() {
if (!('saveDomainOnly' in page.settings)) {
page.settings.saveDomainOnly = defaultSettings.saveDomainOnly;
}
if (!('automaticReconnect' in page.settings)) {
page.settings.automaticReconnect = defaultSettings.automaticReconnect;
}
if (!('defaultGroup' in page.settings)) {
page.settings.defaultGroup = defaultSettings.defaultGroup;
}
@ -71,13 +75,13 @@ page.initOpenedTabs = function() {
}
// Set initial tab-ID
browser.tabs.query({ 'active': true, 'currentWindow': true }).then((t) => {
if (t.length === 0) {
browser.tabs.query({ 'active': true, 'currentWindow': true }).then((currentTabs) => {
if (currentTabs.length === 0) {
resolve();
return; // For example: only the background devtools or a popup are opened
}
page.currentTabId = t[0].id;
browserAction.show(null, t[0]);
page.currentTabId = currentTabs[0].id;
browserAction.show(null, currentTabs[0]);
resolve();
});
});
@ -147,31 +151,3 @@ page.removePageInformationFromNotExistingTabs = function() {
});
}
};
page.debugConsole = function() {
if (arguments.length > 1) {
console.log(page.sprintf(arguments[0], arguments));
} else {
console.log(arguments[0]);
}
};
page.sprintf = function(input, args) {
return input.replace(/{(\d+)}/g, (match, number) => {
return typeof args[number] !== 'undefined' ? (typeof args[number] === 'object' ? JSON.stringify(args[number]) : args[number]) : match;
});
};
page.debugDummy = function() {};
page.debug = page.debugDummy;
page.setDebug = function(bool) {
if (bool) {
page.debug = page.debugConsole;
return 'Debug mode enabled';
} else {
page.debug = page.debugDummy;
return 'Debug mode disabled';
}
};

View file

@ -0,0 +1,188 @@
'use strict';
var kpxcAutocomplete = {};
kpxcAutocomplete.elements = [];
kpxcAutocomplete.create = function(input, showListInstantly = false) {
let _index = -1;
input.addEventListener('click', function(e) {
if (!e.isTrusted) {
return;
}
if (input.value !== '') {
input.select();
}
showList(input);
});
input.addEventListener('keydown', keyPress);
input.setAttribute('autocomplete', 'off');
if (showListInstantly) {
showList(input);
}
function showList(input) {
closeList();
const div = kpxcUI.createElement('div', 'kpxcAutocomplete-items', { 'id': 'kpxcAutocomplete-list' });
// Element position
const rect = input.getBoundingClientRect();
div.style.top = String((rect.top + document.body.scrollTop) + input.offsetHeight) + 'px';
div.style.left = String((rect.left + document.body.scrollLeft)) + 'px';
div.style.minWidth = String(input.offsetWidth) + 'px';
div.style.zIndex = '2147483646';
document.body.append(div);
for (const c of kpxcAutocomplete.elements) {
const item = document.createElement('div');
item.textContent += c.label;
const itemInput = kpxcUI.createElement('input', '', { 'type': 'hidden', 'value': c.value });
item.append(itemInput);
item.addEventListener('click', function(e) {
if (!e.isTrusted) {
return;
}
// Save index for combination.loginId
const index = Array.prototype.indexOf.call(e.currentTarget.parentElement.childNodes, e.currentTarget);
input.value = this.getElementsByTagName('input')[0].value;
fillPassword(input.value, index);
closeList();
input.focus();
});
// These events prevent the double hover effect if both keyboard and mouse are used
item.addEventListener('mouseover', function(e) {
removeItem(getAllItems());
item.classList.add('kpxcAutocomplete-active');
_index = Array.from(div.childNodes).indexOf(item);
});
item.addEventListener('mouseout', function(e) {
item.classList.remove('kpxcAutocomplete-active');
});
div.appendChild(item);
}
// Activate the first item automatically
const items = getAllItems();
_index = 0;
activateItem(items);
};
function activateItem(item) {
if (!item || item.length === 0) {
return;
}
removeItem(item);
if (_index >= item.length) {
_index = 0;
}
if (_index < 0) {
_index = item.length - 1;
}
if (item[_index] !== undefined) {
item[_index].classList.add('kpxcAutocomplete-active');
}
};
function removeItem(items) {
for (const item of items) {
item.classList.remove('kpxcAutocomplete-active');
}
};
function closeList(elem) {
const items = document.getElementsByClassName('kpxcAutocomplete-items');
for (const item of items) {
if (elem !== item && input) {
item.parentNode.removeChild(item);
}
}
};
function getAllItems() {
const list = document.getElementById('kpxcAutocomplete-list');
if (!list) {
return [];
}
return list.getElementsByTagName('div');
};
/**
* Keyboard shortcuts for autocomplete menu:
* - ArrowDown shows the list or selects item below, or the first item (last is active)
* - ArrowUp selects item above, or the last item (first is active)
* - Enter or Tab selects the item
* - Backspace and Delete shows the list if input field is empty. First item is activated
*/
function keyPress(e) {
if (!e.isTrusted) {
return;
}
const item = getAllItems();
if (e.key === 'ArrowDown') {
// If the list is now shown, show it
if (item.length === 0) {
_index = -1;
showList(input);
} else {
// Activate next item
++_index;
activateItem(item);
}
} else if (e.key === 'ArrowUp') {
--_index;
activateItem(item);
} else if (e.key === 'Enter' || e.key === 'Tab') {
if (input.value === '' && e.key === 'Enter') {
e.preventDefault();
}
if (_index >= 0 && item && item[_index] !== undefined) {
input.value = e.currentTarget.value;
fillPassword(input.value, _index);
closeList();
}
} else if (e.key === 'Escape') {
closeList();
} else if ((e.key === 'Backspace' || e.key === 'Delete') && input.value === '') {
// Show menu when input field has no value and backspace is pressed
_index = -1;
showList(input);
}
};
function fillPassword(value, index) {
const fieldId = input.getAttribute('data-kpxc-id');
kpxcFields.prepareId(fieldId);
const combination = kpxcFields.getCombination('username', fieldId);
combination.loginId = index;
kpxc.fillInCredentials(combination, false, false);
input.setAttribute('fetched', true);
};
// Detect click outside autocomplete
document.addEventListener('click', function(e) {
if (!e.isTrusted) {
return;
}
const list = document.getElementById('kpxcAutocomplete-list');
if (!list) {
return;
}
if (e.target !== input && (e.target.nodeName !== input.nodeName)) {
closeList(e.target);
}
});
};

View file

@ -0,0 +1,382 @@
'use strict';
var kpxcDefine = {};
kpxcDefine.selection = {
username: null,
password: null,
fields: []
};
kpxcDefine.eventFieldClick = null;
kpxcDefine.dialog = null;
kpxcDefine.startPosX = 0;
kpxcDefine.startPosY = 0;
kpxcDefine.diffX = 0;
kpxcDefine.diffY = 0;
kpxcDefine.keyDown = null;
kpxcDefine.init = function() {
const backdrop = kpxcUI.createElement('div', 'kpxcDefine-modal-backdrop', { 'id': 'kpxcDefine-backdrop' });
const chooser = kpxcUI.createElement('div', '', { 'id': 'kpxcDefine-fields' });
const description = kpxcUI.createElement('div', '', { 'id': 'kpxcDefine-description' });
backdrop.append(description);
document.body.append(backdrop);
document.body.append(chooser);
kpxcFields.getAllFields();
kpxcFields.prepareVisibleFieldsWithID('select');
kpxcDefine.initDescription();
kpxcDefine.resetSelection();
kpxcDefine.prepareStep1();
kpxcDefine.markAllUsernameFields('#kpxcDefine-fields');
kpxcDefine.dialog = $('#kpxcDefine-description');;
kpxcDefine.dialog.onmousedown = function(e) {
kpxcDefine.mouseDown(e);
};
document.addEventListener('keydown', kpxcDefine.keyDown);
};
kpxcDefine.close = function() {
$('#kpxcDefine-backdrop').remove();
$('#kpxcDefine-fields').remove();
document.removeEventListener('keydown', kpxcDefine.keyDown);
};
kpxcDefine.mouseDown = function(e) {
kpxcDefine.selected = kpxcDefine.dialog;
kpxcDefine.startPosX = e.clientX;
kpxcDefine.startPosY = e.clientY;
kpxcDefine.diffX = kpxcDefine.startPosX - kpxcDefine.dialog.offsetLeft;
kpxcDefine.diffY = kpxcDefine.startPosY - kpxcDefine.dialog.offsetTop;
return false;
};
kpxcDefine.initDescription = function() {
const description = $('#kpxcDefine-description');
const h1 = kpxcUI.createElement('div', '', { 'id': 'kpxcDefine-chooser-headline' });
const help = kpxcUI.createElement('div', 'kpxcDefine-chooser-help', { 'id': 'kpxcDefine-help' });
// Show keyboard shortcuts help text
const keyboardHelp = kpxcUI.createElement('div', 'kpxcDefine-keyboardHelp', {}, `${tr('optionsKeyboardShortcutsHeader')}:`);
keyboardHelp.style.marginBottom = '5px';
keyboardHelp.appendMultiple(document.createElement('br'), kpxcUI.createElement('kbd', '', {}, 'Escape'), ' ' + tr('defineDismiss'));
keyboardHelp.appendMultiple(document.createElement('br'), kpxcUI.createElement('kbd', '', {}, 'S'), ' ' + tr('defineSkip'));
keyboardHelp.appendMultiple(document.createElement('br'), kpxcUI.createElement('kbd', '', {}, 'A'), ' ' + tr('defineAgain'));
keyboardHelp.appendMultiple(document.createElement('br'), kpxcUI.createElement('kbd', '', {}, 'C'), ' ' + tr('defineConfirm'));
keyboardHelp.appendMultiple(document.createElement('br'), kpxcUI.createElement('kbd', '', {}, 'M'), ' ' + tr('defineMore'));
keyboardHelp.appendMultiple(document.createElement('br'), kpxcUI.createElement('kbd', '', {}, 'D'), ' ' + tr('defineDiscard'));
description.appendMultiple(h1, help, keyboardHelp);
const buttonDismiss = kpxcUI.createElement('button', 'kpxc-button kpxc-red-button', { 'id': 'kpxcDefine-btn-dismiss' }, tr('defineDismiss'));
buttonDismiss.addEventListener('click', kpxcDefine.close);
const buttonSkip = kpxcUI.createElement('button', 'kpxc-button kpxc-orange-button', { 'id': 'kpxcDefine-btn-skip' }, tr('defineSkip'));
buttonSkip.style.marginRight = '5px';
buttonSkip.addEventListener('click', kpxcDefine.skip);
const buttonMore = kpxcUI.createElement('button', 'kpxc-button kpxc-orange-button', { 'id': 'kpxcDefine-btn-more' }, tr('defineMore'));
buttonMore.style.marginRight = '5px';
buttonMore.style.marginLeft = '5px';
buttonMore.addEventListener('click', kpxcDefine.more);
const buttonAgain = kpxcUI.createElement('button', 'kpxc-button kpxc-blue-button', { 'id': 'kpxcDefine-btn-again' }, tr('defineAgain'));
buttonAgain.style.marginRight = '5px';
buttonAgain.addEventListener('click', kpxcDefine.again);
const buttonConfirm = kpxcUI.createElement('button', 'kpxc-button kpxc-green-button', { 'id': 'kpxcDefine-btn-confirm' }, tr('defineConfirm'));
buttonConfirm.style.marginRight = '15px';
buttonConfirm.style.display = 'none';
buttonConfirm.addEventListener('click', kpxcDefine.confirm);
description.appendMultiple(buttonConfirm, buttonSkip, buttonMore, buttonAgain, buttonDismiss);
const location = kpxc.getDocumentLocation();
if (kpxc.settings['defined-custom-fields'] && kpxc.settings['defined-custom-fields'][location]) {
const div = kpxcUI.createElement('div', 'alreadySelected', {});
const defineDiscard = kpxcUI.createElement('p', '', {}, tr('defineAlreadySelected'));
const buttonDiscard = kpxcUI.createElement('button', 'kpxc-button kpxc-red-button', { 'id': 'kpxcDefine-btn-discard' }, tr('defineDiscard'));
buttonDiscard.style.marginTop = '5px';
buttonDiscard.addEventListener('click', kpxcDefine.discard);
div.appendMultiple(defineDiscard, buttonDiscard);
description.append(div);
}
};
kpxcDefine.resetSelection = function() {
kpxcDefine.selection = {
username: null,
password: null,
fields: []
};
const fields = $('#kpxcDefine-fields');
if (fields) {
fields.textContent = '';
}
};
kpxcDefine.isFieldSelected = function(kpxcId) {
if (kpxcId) {
return (
kpxcId === kpxcDefine.selection.username ||
kpxcId === kpxcDefine.selection.password ||
kpxcId in kpxcDefine.selection.fields
);
}
return false;
};
kpxcDefine.markAllUsernameFields = function(chooser) {
kpxcDefine.eventFieldClick = function(e, elem) {
const field = elem || e.currentTarget;
kpxcDefine.selection.username = field.getAttribute('data-kpxc-id');
field.classList.add('kpxcDefine-fixed-username-field');
field.textContent = tr('username');
field.onclick = null;
kpxcDefine.prepareStep2();
kpxcDefine.markAllPasswordFields('#kpxcDefine-fields');
};
kpxcDefine.markFields(chooser, kpxcFields.inputQueryPattern);
};
kpxcDefine.markAllPasswordFields = function(chooser, more) {
kpxcDefine.eventFieldClick = function(e, elem) {
const field = elem || e.currentTarget;
kpxcDefine.selection.password = field.getAttribute('data-kpxc-id');
field.classList.add('kpxcDefine-fixed-password-field');
field.textContent = tr('password');
field.onclick = null;
kpxcDefine.prepareStep3();
kpxcDefine.markAllStringFields('#kpxcDefine-fields');
};
if (more) {
kpxcDefine.markFields(chooser, kpxcFields.inputQueryPattern);
} else {
kpxcDefine.markFields(chooser, 'input[type=\'password\']');
}
};
kpxcDefine.markAllStringFields = function(chooser) {
kpxcDefine.eventFieldClick = function(e, elem) {
const field = elem || e.currentTarget;
const value = field.getAttribute('data-kpxc-id');
kpxcDefine.selection.fields[value] = true;
const count = Object.keys(kpxcDefine.selection.fields).length;
field.classList.add('kpxcDefine-fixed-string-field');
field.textContent = tr('defineStringField') + String(count);
field.onclick = null;
};
kpxcDefine.markFields(chooser, kpxcFields.inputQueryPattern + ', select');
};
kpxcDefine.markFields = function(chooser, pattern) {
let index = 1;
let firstInput = null;
const inputs = document.querySelectorAll(pattern);
for (const i of inputs) {
if (kpxcDefine.isFieldSelected(i.getAttribute('data-kpxc-id'))) {
return true;
}
if (kpxcFields.isVisible(i)) {
const field = kpxcUI.createElement('div', 'kpxcDefine-fixed-field', { 'data-kpxc-id': i.getAttribute('data-kpxc-id') });
const rect = i.getBoundingClientRect();
field.style.top = rect.top + 'px';
field.style.left = rect.left + 'px';
field.style.width = rect.width + 'px';
field.style.height = rect.height + 'px';
field.textContent = String(index);
field.onclick = function(e) {
kpxcDefine.eventFieldClick(e);
};
field.onmouseenter = function() {
field.classList.add('kpxcDefine-fixed-hover-field');
};
field.onmouseleave = function() {
field.classList.remove('kpxcDefine-fixed-hover-field');
};
i.onfocus = function() {
field.classList.add('kpxcDefine-fixed-hover-field');
}
i.onblur = function() {
field.classList.remove('kpxcDefine-fixed-hover-field');
};
const elem = $(chooser);
if (elem) {
elem.append(field);
firstInput = field;
++index;
}
}
}
if (firstInput) {
firstInput.focus();
}
};
kpxcDefine.prepareStep1 = function() {
const help = $('#kpxcDefine-help');
help.style.marginBottom = '10px';
help.textContent = tr('defineKeyboardText');
removeContent('div#kpxcDefine-fixed-field');
$('#kpxcDefine-chooser-headline').textContent = tr('defineChooseUsername');
kpxcDefine.dataStep = 1;
$('#kpxcDefine-btn-skip').style.display = 'inline-block';
$('#kpxcDefine-btn-confirm').style.display = 'none';
$('#kpxcDefine-btn-again').style.display = 'none';
$('#kpxcDefine-btn-more').style.display = 'none';
};
kpxcDefine.prepareStep2 = function() {
const help = $('#kpxcDefine-help');
help.style.marginBottom = '10px';
help.textContent = tr('defineKeyboardText');
removeContent('div.kpxcDefine-fixed-field:not(.kpxcDefine-fixed-username-field)');
$('#kpxcDefine-chooser-headline').textContent = tr('defineChoosePassword');
kpxcDefine.dataStep = 2;
$('#kpxcDefine-btn-again').style.display = 'inline-block';
$('#kpxcDefine-btn-more').style.display = 'inline-block';
};
kpxcDefine.prepareStep3 = function() {
$('#kpxcDefine-help').style.marginBottom = '10px';
$('#kpxcDefine-help').textContent = tr('defineHelpText');
removeContent('div.kpxcDefine-fixed-field:not(.kpxcDefine-fixed-username-field):not(.kpxcDefine-fixed-password-field)');
$('#kpxcDefine-chooser-headline').textContent = tr('defineConfirmSelection');
kpxcDefine.dataStep = 3;
$('#kpxcDefine-btn-skip').style.display = 'none';
$('#kpxcDefine-btn-more').style.display = 'none';
$('#kpxcDefine-btn-again').style.display = 'inline-block';
$('#kpxcDefine-btn-confirm').style.display = 'inline-block';
};
kpxcDefine.skip = function() {
if (kpxcDefine.dataStep === 1) {
kpxcDefine.selection.username = null;
kpxcDefine.prepareStep2();
kpxcDefine.markAllPasswordFields('#kpxcDefine-fields');
} else if (kpxcDefine.dataStep === 2) {
kpxcDefine.selection.password = null;
kpxcDefine.prepareStep3();
kpxcDefine.markAllStringFields('#kpxcDefine-fields');
}
};
kpxcDefine.again = function() {
kpxcDefine.resetSelection();
kpxcDefine.prepareStep1();
kpxcDefine.markAllUsernameFields('#kpxcDefine-fields');
};
kpxcDefine.more = function() {
if (kpxcDefine.dataStep === 2) {
kpxcDefine.prepareStep2();
kpxcDefine.markAllPasswordFields('#kpxcDefine-fields', true);
}
};
kpxcDefine.confirm = function() {
if (kpxcDefine.dataStep !== 3) {
return;
}
if (!kpxc.settings['defined-custom-fields']) {
kpxc.settings['defined-custom-fields'] = {};
}
if (kpxcDefine.selection.username) {
kpxcDefine.selection.username = kpxcFields.prepareId(kpxcDefine.selection.username);
}
if (kpxcDefine.selection.password) {
kpxcDefine.selection.password = kpxcFields.prepareId(kpxcDefine.selection.password);
}
const fieldIds = [];
const fieldKeys = Object.keys(kpxcDefine.selection.fields);
for (const i of fieldKeys) {
fieldIds.push(kpxcFields.prepareId(i));
}
const location = kpxc.getDocumentLocation();
kpxc.settings['defined-custom-fields'][location] = {
username: kpxcDefine.selection.username,
password: kpxcDefine.selection.password,
fields: fieldIds
};
browser.runtime.sendMessage({
action: 'save_settings',
args: [ kpxc.settings ]
});
kpxcDefine.close();
};
kpxcDefine.discard = function() {
const location = kpxc.getDocumentLocation();
delete kpxc.settings['defined-custom-fields'][location];
browser.runtime.sendMessage({
action: 'save_settings',
args: [ kpxc.settings ]
});
browser.runtime.sendMessage({
action: 'load_settings'
});
$('div.alreadySelected').remove();
};
// Handle the keyboard events
kpxcDefine.keyDown = function(e) {
if (e.key === 'Escape') {
kpxcDefine.close();
} else if (e.key === 'Enter') {
e.preventDefault();
} else if (e.keyCode >= 49 && e.keyCode <= 57) {
// Select input field by number
e.preventDefault();
const index = e.keyCode - 48;
const inputFields = document.querySelectorAll('div.kpxcDefine-fixed-field:not(.kpxcDefine-fixed-username-field):not(.kpxcDefine-fixed-password-field)');
if (inputFields.length >= index) {
kpxcDefine.eventFieldClick(e, inputFields[index - 1]);
}
} else if (e.key === 's') {
e.preventDefault();
kpxcDefine.skip();
} else if (e.key === 'a') {
e.preventDefault();
kpxcDefine.again();
} else if (e.key === 'c') {
e.preventDefault();
kpxcDefine.confirm();
} else if (e.key === 'm') {
e.preventDefault();
kpxcDefine.more();
} else if (e.key === 'd') {
e.preventDefault();
kpxcDefine.discard();
}
};
const removeContent = function(pattern) {
const elems = document.querySelectorAll(pattern);
for (const e of elems) {
e.remove();
}
};

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,407 @@
'use strict';
var kpxcPassword = {};
kpxcPassword.created = false;
kpxcPassword.icon = null;
kpxcPassword.inputField = null;
kpxcPassword.selected = null;
kpxcPassword.startPosX = 0;
kpxcPassword.startPosY = 0;
kpxcPassword.diffX = 0;
kpxcPassword.diffY = 0;
kpxcPassword.dialog = null;
kpxcPassword.titleBar = null;
const DOMRectToArray = function(domRect) {
return [ domRect.bottom, domRect.height, domRect.left, domRect.right, domRect.top, domRect.width, domRect.x, domRect.y ];
};
/**
* Detects if the input field appears or disappears -> show/hide the icon
* - boundingClientRect with slightly (< -10) negative values -> hidden
* - intersectionRatio === 0 -> hidden
* - isIntersecting === false -> hidden
* - intersectionRatio > 0 -> shown
* - isIntersecting === true -> shown
*/
kpxcPassword.observer = new IntersectionObserver((entries) => {
for (const entry of entries) {
const rect = DOMRectToArray(entry.boundingClientRect);
if ((entry.intersectionRatio === 0 && !entry.isIntersecting) || (rect.some(x => x < -10))) {
kpxcPassword.icon.style.display = 'none';
} else if (entry.intersectionRatio > 0 && entry.isIntersecting) {
kpxcPassword.icon.style.display = 'block';
// Wait for possible DOM animations
setTimeout(() => {
kpxcPassword.setIconPosition(kpxcPassword.icon, entry.target)
}, 500);
}
}
});
kpxcPassword.init = function() {
if ('initPasswordGenerator' in _called) {
return;
}
_called.initPasswordGenerator = true;
};
kpxcPassword.initField = function(field, inputs, pos) {
if (!field) {
return;
}
// Observer the visibility
kpxcPassword.observer.observe(field);
if (field.getAttribute('kpxc-password-generator')) {
return;
}
field.setAttribute('kpxc-password-generator', true);
kpxcPassword.createIcon(field);
kpxcPassword.inputField = field;
let found = false;
if (inputs) {
for (let i = pos + 1; i < inputs.length; i++) {
if (inputs[i] && inputs[i].getAttribute('type') && inputs[i].getAttribute('type').toLowerCase() === 'password') {
field.setAttribute('kpxc-pwgen-next-field-id', inputs[i].getAttribute('data-kpxc-id'));
field.setAttribute('kpxc-pwgen-next-is-password-field', (i === 0));
found = true;
break;
}
}
}
field.setAttribute('kpxc-pwgen-next-field-exists', found);
};
kpxcPassword.createIcon = function(field) {
const className = (isFirefox() ? 'key-moz' : 'key');
const size = (field.offsetHeight > 28) ? 24 : 16;
let offset = Math.floor((field.offsetHeight - size) / 3);
offset = (offset < 0) ? 0 : offset;
const icon = kpxcUI.createElement('div', 'kpxc kpxc-pwgen-icon ' + className,
{
'title': tr('passwordGeneratorGenerateText'),
'alt': tr('passwordGeneratorIcon'),
'size': size,
'offset': offset,
'kpxc-pwgen-field-id': field.getAttribute('data-kpxc-id')
});
icon.style.zIndex = '9999';
icon.style.width = String(size) + 'px';
icon.style.height = String(size) + 'px';
icon.addEventListener('click', function(e) {
e.preventDefault();
kpxcPassword.showDialog(field, icon);
});
kpxcPassword.setIconPosition(icon, field);
kpxcPassword.icon = icon;
document.body.appendChild(icon);
};
kpxcPassword.setIconPosition = function(icon, field) {
const rect = field.getBoundingClientRect();
const offset = Number(icon.getAttribute('offset'));
const size = Number(icon.getAttribute('size'));
icon.style.top = String((rect.top + document.scrollingElement.scrollTop) + offset + 1) + 'px';
icon.style.left = String((rect.left + document.scrollingElement.scrollLeft) + field.offsetWidth - size - offset) + 'px';
};
kpxcPassword.createDialog = function() {
if (kpxcPassword.created) {
// If database is open again, generate a new password right away
const input = $('.kpxc-pwgen-input');
if (input.style.display === 'none') {
kpxcPassword.generate();
}
return;
}
kpxcPassword.created = true;
const wrapper = kpxcUI.createElement('div', 'kpxc');
const dialog = kpxcUI.createElement('div', 'kpxc kpxc-pwgen-dialog');
const titleBar = kpxcUI.createElement('div', 'kpxc-pwgen-titlebar', {}, tr('passwordGeneratorTitle'));
const closeButton = kpxcUI.createElement('div', 'kpxc-pwgen-close', {}, '×');
closeButton.onclick = function(e) {
kpxcPassword.openDialog();
};
titleBar.append(closeButton);
const passwordRow = kpxcUI.createElement('div', 'kpxc-pwgen-password-row');
const input = kpxcUI.createElement('input', 'kpxc-pwgen-input', { 'placeholder': tr('passwordGeneratorPlaceholder'), 'type': 'text', 'tabindex': '-1' });
const inputLabel = kpxcUI.createElement('label', 'kpxc-pwgen-bits', {}, tr('passwordGeneratorBits', '???'));
passwordRow.appendMultiple(input, inputLabel);
const nextFillRow = kpxcUI.createElement('div', 'kpxc-pwgen-nextfill-row');
const checkbox = kpxcUI.createElement('input', 'kpxc-pwgen-checkbox', { 'id': 'kpxc-pwgen-checkbox', 'type': 'checkbox' });
const checkboxLabel = kpxcUI.createElement('label', 'kpxc-pwgen-checkbox-label', { 'for': 'kpxc-pwgen-checkbox' }, tr('passwordGeneratorLabel'));
nextFillRow.appendMultiple(checkbox, checkboxLabel);
// Buttons
const buttonsRow = kpxcUI.createElement('div', 'kpxc-pwgen-buttons');
const generateButton = kpxcUI.createElement('button', 'kpxc-button kpxc-white-button', { 'id': 'kpxc-pwgen-btn-generate' }, tr('passwordGeneratorGenerate'));
const copyButton = kpxcUI.createElement('button', 'kpxc-button', { 'id': 'kpxc-pwgen-btn-copy' }, tr('passwordGeneratorCopy'));
const fillButton = kpxcUI.createElement('button', 'kpxc-button', { 'id': 'kpxc-pwgen-btn-fill' }, tr('passwordGeneratorFillAndCopy'));
generateButton.onclick = function(e) {
kpxcPassword.generate(e);
};
copyButton.onclick = function(e) {
kpxcPassword.copy(e);
};
fillButton.onclick = function(e) {
kpxcPassword.fill(e);
};
buttonsRow.appendMultiple(generateButton, copyButton, fillButton);
dialog.appendMultiple(titleBar, passwordRow, nextFillRow, buttonsRow);
wrapper.append(dialog);
const icon = $('.kpxc-pwgen-icon');
dialog.style.top = String(icon.offsetTop + icon.offsetHeight) + 'px';
dialog.style.left = icon.style.left;
document.body.append(wrapper);
kpxcPassword.dialog = dialog;
kpxcPassword.titleBar = titleBar;
kpxcPassword.titleBar.onmousedown = function(e) {
kpxcPassword.mouseDown(e);
};
kpxcPassword.generate();
};
kpxcPassword.mouseDown = function(e) {
kpxcPassword.selected = kpxcPassword.titleBar;
kpxcPassword.startPosX = e.clientX;
kpxcPassword.startPosY = e.clientY;
kpxcPassword.diffX = kpxcPassword.startPosX - kpxcPassword.dialog.offsetLeft;
kpxcPassword.diffY = kpxcPassword.startPosY - kpxcPassword.dialog.offsetTop;
return false;
};
kpxcPassword.openDialog = function() {
if (kpxcPassword.dialog.style.display === '' || kpxcPassword.dialog.style.display === 'none') {
kpxcPassword.dialog.style.display = 'block';
} else {
kpxcPassword.dialog.style.display = 'none';
}
};
kpxcPassword.trigger = function() {
kpxcPassword.showDialog(kpxcPassword.inputField, kpxcPassword.icon);
};
kpxcPassword.showDialog = function(field, icon) {
if (!kpxcFields.isVisible(field)) {
document.body.removeChild(icon);
field.removeAttribute('kpxc-password-generator');
return;
}
kpxcPassword.createDialog();
kpxcPassword.openDialog();
// Adjust the dialog location
if (kpxcPassword.dialog) {
kpxcPassword.dialog.style.top = String(icon.offsetTop + icon.offsetHeight) + 'px';
kpxcPassword.dialog.style.left = icon.style.left;
kpxcPassword.dialog.setAttribute('kpxc-pwgen-field-id', field.getAttribute('data-kpxc-id'));
kpxcPassword.dialog.setAttribute('kpxc-pwgen-next-field-id', field.getAttribute('kpxc-pwgen-next-field-id'));
kpxcPassword.dialog.setAttribute('kpxc-pwgen-next-is-password-field', field.getAttribute('kpxc-pwgen-next-is-password-field'));
const fieldExists = Boolean(field.getAttribute('kpxc-pwgen-next-field-exists'));
const checkbox = $('.kpxc-pwgen-checkbox');
if (checkbox) {
checkbox.setAttribute('checked', fieldExists);
if (fieldExists) {
checkbox.removeAttribute('disabled');
} else {
checkbox.setAttribute('disabled', '');
}
}
}
};
kpxcPassword.generate = function(e) {
if (e) {
e.preventDefault();
}
browser.runtime.sendMessage({
action: 'generate_password'
}).then(kpxcPassword.callbackGeneratedPassword).catch((err) => {
console.log(err);
});
};
kpxcPassword.copy = function(e) {
e.preventDefault();
if (kpxcPassword.copyPasswordToClipboard()) {
kpxcPassword.greenButton('#kpxc-pwgen-btn-copy');
kpxcPassword.whiteButton('#kpxc-pwgen-btn-fill');
}
};
kpxcPassword.fill = function(e) {
e.preventDefault();
let field = null;
const inputs = document.querySelectorAll('input[type=\'password\']');
for (const i of inputs) {
if (i.getAttribute('data-kpxc-id')) {
field = i;
break;
}
}
if (field) {
const password = $('.kpxc-pwgen-input');
if (field.getAttribute('maxlength')) {
if (password.value.length > field.getAttribute('maxlength')) {
const message = tr('passwordGeneratorErrorTooLong') + '\r\n' +
tr('passwordGeneratorErrorTooLongCut') + '\r\n' + tr('passwordGeneratorErrorTooLongRemember');
message.style.whiteSpace = 'pre';
browser.runtime.sendMessage({
action: 'show_notification',
args: [ message ]
});
return;
}
}
field.value = password.value;
if ($('.kpxc-pwgen-checkbox').checked) {
if (field.getAttribute('kpxc-pwgen-next-field-id')) {
const nextFieldId = field.getAttribute('kpxc-pwgen-next-field-id');
const nextField = $('input[data-kpxc-id=\'' + nextFieldId + '\']');
if (nextField) {
nextField.value = password.value;
}
}
}
if (kpxcPassword.copyPasswordToClipboard()) {
kpxcPassword.greenButton('#kpxc-pwgen-btn-fill');
kpxcPassword.whiteButton('#kpxc-pwgen-btn-copy');
}
}
};
kpxcPassword.copyPasswordToClipboard = function() {
$('.kpxc-pwgen-input').select();
try {
return document.execCommand('copy');
}
catch (err) {
console.log('Could not copy password to clipboard: ' + err);
}
return false;
};
kpxcPassword.callbackGeneratedPassword = function(entries) {
if (entries && entries.length >= 1) {
const errorMessage = $('#kpxc-pwgen-error');
if (errorMessage) {
kpxcPassword.enableButtons();
$('.kpxc-pwgen-checkbox').parentElement.style.display = 'block';
$('.kpxc-pwgen-bits').style.display = 'block';
const input = $('.kpxc-pwgen-input');
input.style.display = 'block';
errorMessage.remove();
}
kpxcPassword.whiteButton('#kpxc-pwgen-btn-fill');
kpxcPassword.whiteButton('#kpxc-pwgen-btn-copy');
$('.kpxc-pwgen-input').value = entries[0].password;
$('.kpxc-pwgen-bits').textContent = tr('passwordGeneratorBits', (isNaN(entries[0].login) ? '???' : entries[0].login));
} else {
if (document.querySelectorAll('div#kpxc-pwgen-error').length === 0) {
$('.kpxc-pwgen-checkbox').parentElement.style.display = 'none';
$('.kpxc-pwgen-bits').style.display = 'none';
const input = $('.kpxc-pwgen-input');
input.style.display = 'none';
const errorMessage = kpxcUI.createElement('div', '', { 'id': 'kpxc-pwgen-error' },
tr('passwordGeneratorError') + '\r\n' + tr('passwordGeneratorErrorIsRunning'));
errorMessage.style.whiteSpace = 'pre';
input.parentElement.append(errorMessage);
kpxcPassword.disableButtons();
}
}
};
kpxcPassword.onRequestPassword = function() {
browser.runtime.sendMessage({
action: 'generate_password'
}).then(kpxcPassword.callbackGeneratedPassword);
};
kpxcPassword.greenButton = function(button) {
$(button).classList.remove('kpxc-white-button');
$(button).classList.add('kpxc-green-button');
};
kpxcPassword.whiteButton = function(button) {
$(button).classList.remove('kpxc-green-button');
$(button).classList.add('kpxc-white-button');
};
kpxcPassword.enableButtons = function() {
$('#kpxc-pwgen-btn-generate').textContent = tr('passwordGeneratorGenerate');
$('#kpxc-pwgen-btn-copy').style.display = 'inline-block';
$('#kpxc-pwgen-btn-fill').style.display = 'inline-block';
};
kpxcPassword.disableButtons = function() {
$('#kpxc-pwgen-btn-generate').textContent = tr('passwordGeneratorTryAgain');
$('#kpxc-pwgen-btn-copy').style.display = 'none';
$('#kpxc-pwgen-btn-fill').style.display = 'none';
};
// Handle icon position on window resize
window.addEventListener('resize', function(e) {
if (kpxcPassword.inputField && kpxcPassword.icon) {
kpxcPassword.setIconPosition(kpxcPassword.icon, kpxcPassword.inputField);
}
});
// Handle icon position on scroll
window.addEventListener('scroll', function(e) {
if (kpxcPassword.inputField && kpxcPassword.icon) {
kpxcPassword.setIconPosition(kpxcPassword.icon, kpxcPassword.inputField);
}
});
// Closes the dialog when clicked outside of it)
document.onclick = function(e) {
if (kpxcPassword.dialog && kpxcPassword.dialog.style.display === 'block') {
const dialogEndX = kpxcPassword.dialog.offsetLeft + kpxcPassword.dialog.offsetWidth;
const dialogEndY = kpxcPassword.dialog.offsetTop + kpxcPassword.dialog.offsetHeight;
if ((e.clientX < kpxcPassword.dialog.offsetLeft || e.clientX > dialogEndX) ||
(e.clientY < kpxcPassword.dialog.offsetTop || e.clientY > dialogEndY) &&
!e.target.classList.contains('kpxc-pwgen-icon')) {
kpxcPassword.openDialog();
}
}
};

View file

@ -0,0 +1,67 @@
'use strict';
// jQuery style wrapper for querySelector()
var $ = function(elem)
{
return document.querySelector(elem);
};
var kpxcUI = {};
// Wrapper for creating elements
kpxcUI.createElement = function(type, classes, attributes, textContent) {
const element = document.createElement(type);
if (classes) {
const splitted = classes.split(' ');
for (const c of splitted) {
element.classList.add(c);
}
}
if (attributes !== undefined) {
Object.keys(attributes).forEach((key) => {
element.setAttribute(key, attributes[key]);
});
}
if (textContent !== undefined) {
element.textContent = textContent;
}
return element;
};
// Enables dragging
document.onmousemove = function(e) {
if (kpxcPassword.selected === kpxcPassword.titleBar) {
const x_pos = e.clientX - kpxcPassword.diffX;
const y_pos = e.clientY - kpxcPassword.diffY;
if (kpxcPassword.selected !== null) {
kpxcPassword.dialog.style.left = x_pos + 'px';
kpxcPassword.dialog.style.top = y_pos + 'px';
}
}
if (kpxcDefine.selected === kpxcDefine.dialog) {
const x_pos = e.clientX - kpxcDefine.diffX;
const y_pos = e.clientY - kpxcDefine.diffY;
if (kpxcDefine.selected !== null) {
kpxcDefine.dialog.style.left = x_pos + 'px';
kpxcDefine.dialog.style.top = y_pos + 'px';
}
}
};
document.onmouseup = function() {
kpxcPassword.selected = null;
kpxcDefine.selected = null;
};
HTMLDivElement.prototype.appendMultiple = function(...args) {
for (const a of args) {
this.append(a);
}
};

View file

@ -0,0 +1,19 @@
.kpxcAutocomplete-items {
position: absolute !important;
border: 1px solid #d4d4d4;
}
.kpxcAutocomplete-items div {
padding: 5px;
cursor: pointer;
background-color: #fff;
border-bottom: 1px solid #d4d4d4;
width: auto;
color: #000;
font-size: .9em !important;
}
.kpxcAutocomplete-active {
background-color: #6cac4d !important;
color: #ffffff !important;
}

View file

@ -0,0 +1,48 @@
.kpxc-button {
font-size: 12px !important;
font-family: 'Lato', sans-serif !important;
height: 28px !important;
margin: .2em !important;
background-color: #fff;
border: 1px solid #888 !important;
border-radius: 4px !important;
}
.kpxc-white-button {
color: #333 !important;
background-color: #fff !important;
border-color: #ccc !important;
}
.kpxc-red-button {
color: #fff !important;
background-color: #d9534f !important;
border-color: #d43f3a !important;
}
.kpxc-orange-button {
color: #fff !important;
background-color: #f0ad4e !important;
border-color: #eea236 !important;
}
.kpxc-blue-button {
color: #fff !important;
background-color: #337ab7 !important;
border-color: #2e6da4 !important;
}
.kpxc-green-button {
color: #fff !important;
background-color: #5cb85c !important;
border-color: #4cae4c !important;
}
.kpxc-button:hover {
background-color: #eee;
cursor: pointer;
}
.kpxc-button:active {
background-color: #ddd;
}

View file

@ -0,0 +1,110 @@
.kpxcDefine-modal-backdrop {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 2147483645;
}
.kpxcDefine-modal-backdrop:after {
content: '';
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: #000000;
opacity: 0.5;
filter: alpha(opacity=50);
}
#kpxcDefine-fields {
z-index: 2147483646;
}
#kpxcDefine-description {
z-index: 2147483646;
color: #efefef;
border: 2px solid #555555;
padding: 7px 5px;
position: absolute;
top: 100px;
left: 150px;
text-align: left;
cursor: pointer;
background-color: rgba(0,0,0,0.8);
font-size: 15px;
user-select: none;
}
#kpxcDefine-description div:first-of-type {
margin-top: 0;
padding-top: 0;
text-align: left;
color: #efefef;
padding-bottom: 8px;
font-weight: bold;
font-size: 120%;
}
#kpxcDefine-description p {
margin-top: 10px;
padding-top: 10px;
color: #efefef;
border-top: 2px solid #666666;
line-height: 110%;
}
#kpxcDefine-help {
margin-bottom: 3px;
}
.kpxcDefine-keyboardHelp {
font-size: 0.75em;
}
.kpxcDefine-keyboardHelp kbd {
background-color: #eee;
border-radius: 3px;
border: 1px solid #b4b4b4;
color: #333;
display: inline-block;
line-height: 1;
padding: 2px 4px;
white-space: nowrap;
}
.kpxcDefine-fixed-field {
position: absolute;
border: 2px solid #efefef;
color: #fff;
cursor: pointer;
z-index: 2147483646;
text-align: center;
font-weight: bold;
background-color: rgba(239,239,239,0.4);
}
.kpxcDefine-fixed-hover-field {
border: 2px solid orange;
background-color: rgba(255,165,239,0.4);
}
.kpxcDefine-fixed-password-field {
border: 2px solid red;
color: #efefef;
background-color: rgba(255,0,0,0.4);
}
.kpxcDefine-fixed-username-field {
border: 2px solid limegreen;
color: #efefef;
background-color: rgba(50,205,50,0.4);
}
.kpxcDefine-fixed-string-field {
border: 2px solid deepskyblue;
color: #efefef;
background-color: rgba(30,144,255,0.4);
}

View file

@ -0,0 +1,114 @@
.kpxc-pwgen-dialog {
font-family: 'Lato', sans-serif !important;
width: 350px;
min-height: 80px;
background-color: white;
border: 1px solid #ccc;
border-radius: 4px;
box-shadow: 0 4px 6px 0 hsla(0, 0%, 0%, 0.2);
z-index: 2147483645;
padding: .1em .2em .1em .2em;
position: absolute !important;
}
.kpxc-pwgen-titlebar {
font-size: 14px !important;
background-color: #6cac4d;
color: #fff;
padding: .4em .2em .4em .8em;
margin: .2em 0 .2em 0;
position: relative;
cursor: move;
}
.kpxc-pwgen-password-row {
color: #fff;
padding: .4em 1em;
margin: .2em 0 .2em 0;
display: flex;
}
.kpxc-pwgen-nextfill-row {
font-size: 12px !important;
color: #000;
padding: .4em 1em;
margin: .2em 0 .2em 0;
}
.kpxc-pwgen-buttons {
color: #fff;
padding: .4em 1em;
margin: .2em 0 .2em 0;
border-top: 1px solid #ccc;
display: flex;
align-items: center;
justify-content: center;
}
.kpxc-pwgen-bits {
font-size: 12px !important;
font-style: normal !important;
font-weight: normal !important;
text-align: center;
color: #000;
background-color: #eee;
border: 1px solid #ccc;
padding: .4em;
border-radius: 4px;
min-width: 60px;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
border-collapse: separate;
vertical-align: middle;
white-space: nowrap;
}
.kpxc-pwgen-close {
color: #fff;
float: right;
font-size: inherit;
font-weight: bold;
text-align: center;
min-width: 20px;
}
.kpxc-pwgen-close:hover {
background-color: #6cac4d !important;
color: #fff;
cursor: pointer;
}
.kpxc-pwgen-input {
width: 100%;
font-size: 12px !important;
font-weight: normal !important;
}
.kpxc-pwgen-checkbox-label {
font-style: normal !important;
font-weight: normal !important;
}
.kpxc #kpxc-pwgen-error {
color: #000;
font-size: 12px !important;
font-style: normal !important;
font-weight: normal !important;
text-align: center;
width: 100%;
}
.kpxc-pwgen-icon {
position: absolute;
cursor: pointer;
}
.kpxc-pwgen-icon.key {
background: url('chrome-extension://__MSG_@@extension_id__/icons/key.svg') right no-repeat;
background-size: contain;
}
.kpxc-pwgen-icon.key-moz {
background: url('moz-extension://__MSG_@@extension_id__/icons/key.svg') right no-repeat;
background-size: contain;
}

View file

@ -4,15 +4,12 @@ const IGNORE_NOTHING = 'ignoreNothing';
const IGNORE_NORMAL = 'ignoreNormal';
const IGNORE_FULL = 'ignoreFull';
var schemeSegment = '(\\*|http|https|ws|wss|file|ftp)';
var hostSegment = '(\\*|(?:\\*\\.)?(?:[^/*]+))?';
var pathSegment = '(.*)';
const schemeSegment = '(\\*|http|https|ws|wss|file|ftp)';
const hostSegment = '(\\*|(?:\\*\\.)?(?:[^/*]+))?';
const pathSegment = '(.*)';
var isFirefox = function() {
if (!(/Chrome/.test(navigator.userAgent) && /Google/.test(navigator.vendor))) {
return true;
}
return false;
return navigator.userAgent.indexOf('Firefox') !== -1 || navigator.userAgent.indexOf('Gecko/') !== -1;
};
var showNotification = function(message) {
@ -45,12 +42,12 @@ var matchPatternToRegExp = function(pattern) {
let match = matchPatternRegExp.exec(pattern);
if (!match) {
throw new TypeError(pattern + ' is not a valid MatchPattern');
throw new TypeError('"${pattern}" is not a valid MatchPattern');
}
let [, scheme, host, path] = match;
if (!host) {
throw new TypeError(pattern + ' does not have a valid host');
throw new TypeError('"${pattern}" does not have a valid host');
}
let regex = '^';
@ -92,7 +89,6 @@ var siteMatch = function(site, url) {
return url.match(rx);
};
// Checks if URL has only scheme and host without the last / char.
var slashNeededForUrl = function(pattern) {
const matchPattern = new RegExp(`^${schemeSegment}://${hostSegment}$`);
return matchPattern.exec(pattern);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,255 +0,0 @@
.kpxc .ui-autocomplete li.ui-menu-item {
text-align: left !important;
font-size: .9em !important;
font-weight: normal !important;
font-style: normal !important;
font-family: 'Lato',sans-serif !important;
color: #222222 !important;
}
.kpxc .ui-menu {
z-index: 10000;
}
.ui-helper-hidden-accessible {
display: none !important;
}
.kpxc .ui-dialog-titlebar-close {
visibility: hidden !important;
}
.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 {
opacity: 0.0 !important;
}
.kpxc .dialog-form .ui-dialog-content .ui-widget-content {
max-height: 80px !important;
}
.kpxc .ui-dialog-titlebar {
font-family: 'Lato',sans-serif;
background-color: #6cac4d;
color: #fff;
}
.kpxc .ui-dialog .ui-dialog-buttonpane {
text-align: center !important;
}
.kpxc .ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset {
float: none !important;
}
.kpxc .ui-button .ui-button-text .ui-button {
font-size: .10em !important;
}
input.genpw-text {
font-size: .9em !important;
padding: .4em;
border-radius: 4px;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
border-collapse: separate;
width: 100%;
}
.genpw-input-group-addon {
font-size: .9em !important;
background-color: #eee;
border: 1px solid #ccc;
padding: .2em;
border-radius: 4px;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
white-space: nowrap;
vertical-align: middle;
display: table-cell;
border-collapse: separate;
}
.kpxc .genpw-input-group {
position: relative;
display: table;
border-collapse: separate;
width: 100%;
}
.cip-genpw-icon {
position: absolute;
cursor: pointer;
}
.cip-genpw-icon.key {
background: url('chrome-extension://__MSG_@@extension_id__/icons/key.svg') right no-repeat;
background-size: contain;
}
.cip-genpw-icon.key-moz {
background: url('moz-extension://__MSG_@@extension_id__/icons/key.svg') right no-repeat;
background-size: contain;
}
.kpxc .cip-genpw-checkbox {
-webkit-appearance: checkbox !important;
-moz-appearance: checkbox !important;
appearance: checkbox !important;
}
#cip-genpw-btn-fillin {
margin-right: 5px;
}
#cip-genpw-quality {
text-align: center;
}
.b2c-modal-backdrop {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 2147483645;
}
.b2c-modal-backdrop:after {
content: '';
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: #000000;
opacity: 0.5;
filter: alpha(opacity=50);
}
#b2c-cipDefine-fields {
z-index: 2147483646;
}
#b2c-cipDefine-description {
z-index: 2147483646;
color: #efefef;
border: 2px solid #555555;
padding: 7px 5px;
position: absolute;
top: 100px;
left: 150px;
text-align: left;
cursor: pointer;
background-color: rgba(0,0,0,0.8);
font-size: 15px;
}
#b2c-cipDefine-description div:first-of-type {
margin-top: 0;
padding-top: 0;
text-align: left;
color: #efefef;
padding-bottom: 8px;
font-weight: bold;
font-size: 160%;
}
#b2c-cipDefine-description p {
margin-top: 10px;
padding-top: 10px;
color: #efefef;
border-top: 2px solid #666666;
line-height: 110%;
}
#b2c-help {
margin-bottom: 3px;
}
#b2c-keyboardHelp {
font-size: 0.75em;
}
#b2c-keyboardHelp kbd {
background-color: #eee;
border-radius: 3px;
border: 1px solid #b4b4b4;
color: #333;
display: inline-block;
line-height: 1;
padding: 2px 4px;
white-space: nowrap;
}
.b2c-fixed-field {
position: absolute;
border: 2px solid #efefef;
color: #fff;
cursor: pointer;
z-index: 2147483646;
text-align: center;
font-weight: bold;
background-color:rgba(239,239,239,0.4);
}
.b2c-fixed-hover-field {
border: 2px solid orange;
background-color:rgba(255,165,239,0.4);
}
.b2c-fixed-password-field {
border: 2px solid red;
color: #efefef;
background-color:rgba(255,0,0,0.4);
}
.b2c-fixed-username-field {
border: 2px solid limegreen;
color: #efefef;
background-color:rgba(50,205,50,0.4);
}
.b2c-fixed-string-field {
border: 2px solid deepskyblue;
color: #efefef;
background-color:rgba(30,144,255,0.4);
}
.b2c-input-append {
display: inline-block;
margin-bottom: 10px;
white-space: nowrap;
vertical-align: middle;
}
.b2c-input-append input,
.b2c-input-append select,
.b2c-input-append .b2c-uneditable-input,
.b2c-input-append .b2c-dropdown-menu,
.b2c-input-append .b2c-popover {
font-size: 14px;
}
.b2c-input-append input,
.b2c-input-append select,
.b2c-input-append .b2c-uneditable-input {
position: relative;
margin-bottom: 0;
*margin-left: 0;
vertical-align: top;
-webkit-border-radius: 0 4px 4px 0;
-moz-border-radius: 0 4px 4px 0;
border-radius: 0 4px 4px 0;
}
.b2c-input-append input:focus,
.b2c-input-append select:focus,
.b2c-input-append .b2c-b2c-uneditable-input:focus {
z-index: 2;
}

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,8 @@
{
"manifest_version": 2,
"name": "KeePassXC-Browser",
"version": "1.3.2",
"version": "1.3.3",
"version_name": "1.3.3",
"description": "__MSG_extensionDescription__",
"author": "KeePassXC Team",
"icons": {
@ -37,8 +38,8 @@
"background/page.js",
"background/event.js",
"background/init.js"
]
},
]
},
"content_scripts": [
{
"matches": [
@ -50,14 +51,18 @@
],
"js": [
"browser-polyfill.min.js",
"global.js",
"jquery-3.3.1.min.js",
"jquery-ui.min.js",
"keepassxc-browser.js"
"content/autocomplete.js",
"content/define.js",
"content/keepassxc-browser.js",
"content/pwgen.js",
"content/ui.js",
"global.js"
],
"css": [
"jquery-ui.min.css",
"keepassxc-browser.css"
"css/autocomplete.css",
"css/button.css",
"css/define.css",
"css/pwgen.css"
],
"run_at": "document_idle",
"all_frames": true
@ -111,10 +116,10 @@
"https://api.github.com/"
],
"applications": {
"gecko": {
"id": "keepassxc-browser@keepassxc.org",
"strict_min_version": "52.0"
}
},
"default_locale": "en"
"gecko": {
"id": "keepassxc-browser@keepassxc.org",
"strict_min_version": "52.0"
}
},
"default_locale": "en"
}

View file

@ -84,7 +84,7 @@
<span class="help-inline">
<span data-i18n="optionsRedirectAllowanceHelpText"></span>
<br />
<span data-i18n="optionsDefault"></span>1
<span data-i18n="optionsDefault" i18n-placeholder="1"></span>
</span>
</div>
</p>
@ -134,6 +134,15 @@
</div>
</p>
<hr />
<p>
<div class="checkbox">
<label class="checkbox">
<input type="checkbox" name="automaticReconnect" value="true" /><span data-i18n="optionsCheckboxAutomaticReconnect"/>
</label>
<span class="help-block" data-i18n="optionsAutomaticReconnectHelpText"></span>
</div>
</p>
<hr />
<p>
<div class="checkbox">
<label class="checkbox">

View file

@ -94,7 +94,7 @@ options.initGeneralSettings = function() {
$('#tab-general-settings input[type=checkbox]').change(function() {
const name = $(this).attr('name');
options.settings[name] = $(this).is(':checked');
options.saveSettingsPromise().then((x) => {
options.saveSettingsPromise().then((updated) => {
if (name === 'autoFillAndSend') {
browser.runtime.sendMessage({ action: 'init_http_auth' });
} else if (name === 'defaultGroupAlwaysAsk') {
@ -107,6 +107,9 @@ options.initGeneralSettings = function() {
$('#defaultGroupButton').prop('disabled', false);
$('#defaultGroupButtonReset').prop('disabled', false);
}
} else if (name == 'automaticReconnect') {
const message = updated.automaticReconnect ? 'enable_automatic_reconnect' : 'disable_automatic_reconnect';
browser.runtime.sendMessage({ action: message });
}
});
});
@ -330,6 +333,10 @@ options.initCustomCredentialFields = function() {
};
options.initSitePreferences = function() {
if (!options.settings['sitePreferences']) {
options.settings['sitePreferences'] = [];
}
$('#dialogDeleteSite').modal({ keyboard: true, show: false, backdrop: true });
$('#tab-site-preferences tr.clone:first button.delete:first').click(function(e) {
e.preventDefault();

View file

@ -74,8 +74,8 @@ async function updateShortcut(shortcut) {
shortcut: document.querySelector('#' + shortcut).value
});
createBanner('success', shortcut);
} catch (e) {
console.log('Cannot change shortcut: ' + e);
} catch (err) {
console.log('Cannot change shortcut: ' + err);
createBanner('danger', shortcut);
}
}

View file

@ -40,18 +40,18 @@ body {
font-size: 80%;
color: #787878;
}
.small {
margin-top: 3px;
margin-left: 12px;
font-size: 80%;
color: #787878;
}
#list {
padding-left: 0px;
}
#child {
border-top: 0px;
}
.small {
margin-top: 3px;
margin-left: 12px;
font-size: 80%;
color: #787878;
}
#update-available {
padding-top: 10px;
margin-top: 10px;

View file

@ -1,15 +1,17 @@
<!DOCTYPE html>
<html>
<head>
<title data-i18n="popupTitle"></title>
<meta charset="UTF-8">
<link rel="stylesheet" href="popup.css" />
<link rel="stylesheet" href="../options/bootstrap.min.css" />
<script type="text/javascript" src="../browser-polyfill.min.js"></script>
<script type="text/javascript" src="../global.js"></script>
<script type="text/javascript" src="../jquery-3.3.1.min.js"></script>
<script type="text/javascript" src="../options/bootstrap.min.js" /></script>
<script type="text/javascript" src="popup_functions.js" /></script>
<script type="text/javascript" src="popup.js" /></script>
<script src="../browser-polyfill.min.js"></script>
<script src="../global.js"></script>
<script src="../jquery-3.3.1.min.js"></script>
<script src="../options/bootstrap.min.js"></script>
<script src="popup_functions.js"></script>
<script src="popup.js"></script>
<script defer src="../translate.js"></script>
</head>
<body>
<div class="container">
@ -21,7 +23,7 @@
<div id="update-available" class="alert alert-danger">
<span data-i18n="popupUpdateAvailable"></span>
<br />
<a target="_blank" class="alert-link" href="https://keepassxc.org/download"><span data-i18n="popupDownloadNewVersion"/></a>.
<a target="_blank" class="alert-link" href="https://keepassxc.org/download"><span data-i18n="popupDownloadNewVersion"></span></a>.
</div>
</div>
@ -30,18 +32,18 @@
</div>
<div id="not-configured" style="display: none">
<p data-i18n="popupNotConfigured"/>
<p data-i18n="popupNotConfigured"></p>
<div style="text-align: right">
<button id="connect-button" class="btn btn-sm btn-primary"><span class="glyphicon glyphicon-link"></span> <span data-i18n="popupConnectButton"/></button>
</div>
</div>
<div id="need-reconfigure" style="display: none">
<p data-i18n="popupNeedReconfigure"/>
<p data-i18n="popupNeedReconfigure"></p>
<p style="margin-left: 1em">
<code id="need-reconfigure-message"></code>
</p>
<p data-i18n="popupNeedReconfigureMessage"/>
<p data-i18n="popupNeedReconfigureMessage"></p>
<div style="text-align: right">
<button id="reconnect-button" class="btn btn-sm btn-primary"><span class="glyphicon glyphicon-refresh"></span> <span data-i18n="popupReconnectButton"/></button>
</div>
@ -59,7 +61,7 @@
</div>
<div id="error-encountered" style="display: none">
<p data-i18n="popupErrorEncountered"/>
<p data-i18n="popupErrorEncountered"></p>
<p style="margin-left: 1em">
<code id="error-message"></code>
</p>
@ -69,7 +71,7 @@
</div>
<div id="database-not-opened" style="display: none">
<p data-i18n="popupErrorEncountered"/>
<p data-i18n="popupErrorEncountered"></p>
<p style="margin-left: 1em">
<code id="database-error-message"></code>
</p>
@ -78,6 +80,5 @@
</div>
</div>
</div>
<script type="text/javascript" src="../translate.js"></script>
</body>
</html>

View file

@ -1,15 +1,17 @@
<!DOCTYPE html>
<html>
<head>
<title data-i18n="popupTitle"></title>
<meta charset="UTF-8">
<link rel="stylesheet" href="popup.css" />
<link rel="stylesheet" href="../options/bootstrap.min.css" />
<script type="text/javascript" src="../browser-polyfill.min.js"></script>
<script type="text/javascript" src="../global.js"></script>
<script type="text/javascript" src="../jquery-3.3.1.min.js"></script>
<script type="text/javascript" src="../options/bootstrap.min.js" /></script>
<script type="text/javascript" src="popup_functions.js"></script>
<script type="text/javascript" src="popup_httpauth.js"></script>
<script src="../browser-polyfill.min.js"></script>
<script src="../global.js"></script>
<script src="../jquery-3.3.1.min.js"></script>
<script src="../options/bootstrap.min.js"></script>
<script src="popup_functions.js"></script>
<script src="popup_httpauth.js"></script>
<script defer src="../translate.js"></script>
</head>
<body>
<div class="container">
@ -21,7 +23,7 @@
<div id="update-available" class="alert alert-danger">
<span data-i18n="popupUpdateAvailable"></span>
<br />
<a target="_blank" class="alert-link" href="https://keepassxc.org/download"><span data-i18n="popupDownloadNewVersion"/></a>.
<a target="_blank" class="alert-link" href="https://keepassxc.org/download"><span data-i18n="popupDownloadNewVersion"></span></a>.
</div>
</div>
@ -33,6 +35,5 @@
</p>
</div>
</div>
<script type="text/javascript" src="../translate.js"></script>
</body>
</html>

View file

@ -3,7 +3,7 @@
const getLoginData = function() {
return new Promise((resolve, reject) => {
browser.runtime.getBackgroundPage().then((global) => {
browser.tabs.query({ 'active': true, 'currentWindow': true }).then((tabs) => {
browser.tabs.query({'active': true, 'currentWindow': true}).then((tabs) => {
resolve(global.page.tabs[tabs[0].id].loginList);
});
});

View file

@ -1,15 +1,17 @@
<!DOCTYPE html>
<html>
<head>
<title data-i18n="popupTitle"></title>
<meta charset="UTF-8">
<link rel="stylesheet" href="popup.css" />
<link rel="stylesheet" href="../options/bootstrap.min.css" />
<script type="text/javascript" src="../browser-polyfill.min.js"></script>
<script type="text/javascript" src="../global.js"></script>
<script type="text/javascript" src="../jquery-3.3.1.min.js"></script>
<script type="text/javascript" src="../options/bootstrap.min.js" /></script>
<script type="text/javascript" src="popup_functions.js"></script>
<script type="text/javascript" src="popup_login.js"></script>
<script src="../browser-polyfill.min.js"></script>
<script src="../global.js"></script>
<script src="../jquery-3.3.1.min.js"></script>
<script src="../options/bootstrap.min.js"></script>
<script src="popup_functions.js"></script>
<script src="popup_login.js"></script>
<script defer src="../translate.js"></script>
</head>
<body>
<div class="container">
@ -21,7 +23,7 @@
<div id="update-available" class="alert alert-danger">
<span data-i18n="popupUpdateAvailable"></span>
<br />
<a target="_blank" class="alert-link" href="https://keepassxc.org/download"><span data-i18n="popupDownloadNewVersion"/></a>.
<a target="_blank" class="alert-link" href="https://keepassxc.org/download"><span data-i18n="popupDownloadNewVersion"></span></a>.
</div>
</div>
@ -44,6 +46,5 @@
</div>
</div>
</div>
<script type="text/javascript" src="../translate.js"></script>
</body>
</html>

View file

@ -1,14 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<title data-i18n="popupTitle"></title>
<meta charset="UTF-8">
<link rel="stylesheet" href="popup.css" />
<link rel="stylesheet" href="../options/bootstrap.min.css" />
<script type="text/javascript" src="../browser-polyfill.min.js"></script>
<script type="text/javascript" src="../global.js"></script>
<script type="text/javascript" src="../jquery-3.3.1.min.js"></script>
<script type="text/javascript" src="../options/bootstrap.min.js" /></script>
<script type="text/javascript" src="popup_functions.js"></script>
<script src="../browser-polyfill.min.js"></script>
<script src="../global.js"></script>
<script src="../jquery-3.3.1.min.js"></script>
<script src="../options/bootstrap.min.js"></script>
<script src="popup_functions.js"></script>
<script defer src="../translate.js"></script>
</head>
<body>
<div class="container">
@ -20,7 +22,7 @@
<div id="update-available" class="alert alert-danger">
<span data-i18n="popupUpdateAvailable"></span>
<br />
<a target="_blank" class="alert-link" href="https://keepassxc.org/download"><span data-i18n="popupDownloadNewVersion"/></a>.
<a target="_blank" class="alert-link" href="https://keepassxc.org/download"><span data-i18n="popupDownloadNewVersion"></span></a>.
</div>
</div>
@ -31,6 +33,5 @@
</p>
</div>
</div>
<script type="text/javascript" src="../translate.js"></script>
</body>
</html>

View file

@ -1,15 +1,17 @@
<!DOCTYPE html>
<html>
<head>
<title data-i18n="popupTitle"></title>
<meta charset="UTF-8">
<link rel="stylesheet" href="popup.css" />
<link rel="stylesheet" href="../options/bootstrap.min.css" />
<script type="text/javascript" src="../browser-polyfill.min.js"></script>
<script type="text/javascript" src="../global.js"></script>
<script type="text/javascript" src="../jquery-3.3.1.min.js"></script>
<script type="text/javascript" src="../options/bootstrap.min.js" /></script>
<script type="text/javascript" src="popup_functions.js"></script>
<script type="text/javascript" src="popup_remember.js"></script>
<script src="../browser-polyfill.min.js"></script>
<script src="../global.js"></script>
<script src="../jquery-3.3.1.min.js"></script>
<script src="../options/bootstrap.min.js"></script>
<script src="popup_functions.js"></script>
<script src="popup_remember.js"></script>
<script defer src="../translate.js"></script>
</head>
<body>
<div class="buttons">
@ -43,6 +45,5 @@
<p data-i18n="popupRememberChooseGroup"></p>
<ul id="list" class="list-group"></ul>
</div>
<script type="text/javascript" src="../translate.js"></script>
</body>
</html>

View file

@ -50,7 +50,7 @@ function _initialize(tab) {
// Another group name has been specified
const [ gname, guuid ] = getDefaultGroup(result.groups[0].children, result.defaultGroup);
if (gname === '' && guuid === '') {
showNotification(tr('popupRememberErrorDefaultGroupNotFound'));
showNotification(tr('popupRememberInfoDefaultGroupNotFound'));
// Create a new group
browser.runtime.sendMessage({
@ -216,7 +216,7 @@ function _initialize(tab) {
const currentTab = tabs[0];
browser.runtime.getBackgroundPage().then((global) => {
browser.tabs.sendMessage(currentTab.id, {
action: 'ignore-site',
action: 'ignore_site',
args: [ _tab.credentials.url ]
});
_close();

Binary file not shown.

Before

Width:  |  Height:  |  Size: 583 B

After

Width:  |  Height:  |  Size: 673 B