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
625b1a74c0
24 changed files with 392 additions and 363 deletions
|
|
@ -1,3 +1,12 @@
|
|||
0.3.0 (2017-09-18)
|
||||
=========================
|
||||
- Added Mozilla's browser-polyfill for making WebExtension compatibility easier
|
||||
- Merged changes from the latest passifox (credits to smorks/keepasshttp-connector)
|
||||
- HTTP auth works with all browsers (credits to smorks/keepasshttp-connector)
|
||||
- Fixed showing credentials from previous logins in the popup (credits to smorks/keepasshttp-connector)
|
||||
- Automatic detection of div's with forms that are non-hidden by user interaction
|
||||
- Verified the source code via JSHint
|
||||
|
||||
0.2.9 (2017-08-27)
|
||||
=========================
|
||||
- Code cleaning, global functions moved to global.js
|
||||
|
|
|
|||
39
README.md
39
README.md
|
|
@ -2,7 +2,7 @@
|
|||
Chrome extension for [KeePassXC](https://keepassxc.org/) with Native Messaging.
|
||||
|
||||
This is a heavily forked version of [pfn](https://github.com/pfn)'s [chromeIPass](https://github.com/pfn/passifox).
|
||||
Some changes merged also from [projectgus'](https://github.com/projectgus/passifox) fork.
|
||||
Some changes merged also from [smorks'](https://github.com/smorks/keepasshttp-connector) KeePassHttp-Connector fork.
|
||||
For testing purposes, please use following unofficial KeePassXC [release's](https://github.com/varjolintu/keepassxc/releases).
|
||||
|
||||
Get the extension for [Firefox](https://addons.mozilla.org/en-US/firefox/addon/keepassxc-browser/) or [Chrome/Chromium](https://chrome.google.com/webstore/detail/keepassxc-browser/iopaggbpplllidnfmcghoonnokmjoicf).
|
||||
|
|
@ -269,41 +269,10 @@ You should have received a copy of the GNU General Public License
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
```
|
||||
|
||||
The following quick method to determine which browser is used with API calls by [David Rousset](https://github.com/davrous):
|
||||
```javascript
|
||||
window.browser = (function () {
|
||||
return window.msBrowser ||
|
||||
window.browser ||
|
||||
window.chrome;
|
||||
})();
|
||||
```
|
||||
|
||||
```
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2016 David Rousset
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
```
|
||||
|
||||
## Donations
|
||||
|
||||
Feel free to support this project:
|
||||
- Donate via [PayPal](https://paypal.me/varjolintu)
|
||||
- Donate via Bitcoin: 1LHbD69CcmpLW5hjUXs2MGJhw3GxwqLdw3
|
||||
- Donate via Bitcoin: 1LHbD69CcmpLW5hjUXs2MGJhw3GxwqLdw3
|
||||
|
||||
Also consider donating to [KeePassXC](https://flattr.com/submit/auto?fid=x7yqz0&url=https%3A%2F%2Fkeepassxc.org) and passifox teams [(1)](https://github.com/smorks/passifox),[(2)](https://github.com/projectgus/passifox),[(3)](https://github.com/pfn/passifox). They are doing great job.
|
||||
|
|
@ -27,7 +27,7 @@ browserAction.show = function(callback, tab) {
|
|||
popup: 'popups/' + data.popup
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
browserAction.update = function(interval) {
|
||||
if (!page.tabs[page.currentTabId] || page.tabs[page.currentTabId].stack.length === 0) {
|
||||
|
|
@ -79,14 +79,14 @@ browserAction.update = function(interval) {
|
|||
path: '/icons/19x19/' + browserAction.generateIconName(null, data.intervalIcon.icons[data.intervalIcon.index])
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
browserAction.showDefault = function(callback, tab) {
|
||||
let stackData = {
|
||||
level: 1,
|
||||
iconType: 'normal',
|
||||
popup: 'popup.html'
|
||||
}
|
||||
};
|
||||
keepass.isConfigured((response) => {
|
||||
if (!response || keepass.isDatabaseClosed || !keepass.isKeePassXCAvailable || page.tabs[tab.id].errorMessage) {
|
||||
stackData.iconType = 'cross';
|
||||
|
|
@ -100,7 +100,7 @@ browserAction.showDefault = function(callback, tab) {
|
|||
browserAction.stackUnshift(stackData, tab.id);
|
||||
browserAction.show(null, tab);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
browserAction.stackAdd = function(callback, tab, icon, popup, level, push, visibleForMilliSeconds, visibleForPageUpdates, redirectOffset, dontShow) {
|
||||
const id = tab.id || page.currentTabId;
|
||||
|
|
@ -112,7 +112,7 @@ browserAction.stackAdd = function(callback, tab, icon, popup, level, push, visib
|
|||
let stackData = {
|
||||
level: level,
|
||||
icon: icon
|
||||
}
|
||||
};
|
||||
|
||||
if (popup) {
|
||||
stackData.popup = popup;
|
||||
|
|
@ -140,8 +140,7 @@ browserAction.stackAdd = function(callback, tab, icon, popup, level, push, visib
|
|||
if (!dontShow) {
|
||||
browserAction.show(null, {'id': id});
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
browserAction.removeLevelFromStack = function(callback, tab, level, type, dontShow) {
|
||||
if (!page.tabs[tab.id]) {
|
||||
|
|
@ -172,7 +171,7 @@ browserAction.removeLevelFromStack = function(callback, tab, level, type, dontSh
|
|||
if (!dontShow) {
|
||||
browserAction.show(callback, tab);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
browserAction.stackPop = function(tabId) {
|
||||
const id = tabId || page.currentTabId;
|
||||
|
|
@ -242,7 +241,7 @@ browserAction.setRememberPopup = function(tabId, username, password, url, userna
|
|||
},
|
||||
icon: 'icon_remember_red_background_19x19.png',
|
||||
popup: 'popup_remember.html'
|
||||
}
|
||||
};
|
||||
|
||||
browserAction.stackPush(stackData, id);
|
||||
|
||||
|
|
@ -255,7 +254,7 @@ browserAction.setRememberPopup = function(tabId, username, password, url, userna
|
|||
};
|
||||
|
||||
browserAction.show(null, {'id': id});
|
||||
}
|
||||
};
|
||||
|
||||
function getValueOrDefault(settings, key, defaultVal, min) {
|
||||
try {
|
||||
|
|
@ -280,4 +279,4 @@ browserAction.generateIconName = function(iconType, icon) {
|
|||
name += '_19x19.png';
|
||||
|
||||
return name;
|
||||
}
|
||||
};
|
||||
|
|
@ -16,7 +16,7 @@ event.onMessage = function(request, sender, callback) {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get interesting information about the given tab.
|
||||
|
|
@ -41,7 +41,7 @@ event.invoke = function(handler, callback, senderTabId, args, secondTime) {
|
|||
// remove information from no longer existing tabs
|
||||
page.removePageInformationFromNotExistingTabs();
|
||||
|
||||
browser.tabs.get(senderTabId, (tab) => {
|
||||
browser.tabs.get(senderTabId).then((tab) => {
|
||||
if (!tab) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -73,13 +73,12 @@ event.invoke = function(handler, callback, senderTabId, args, secondTime) {
|
|||
console.log('undefined handler for tab ' + tab.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
event.onShowAlert = function(callback, tab, message) {
|
||||
if (page.settings.supressAlerts) { console.log(message); }
|
||||
else { alert(message); }
|
||||
}
|
||||
};
|
||||
|
||||
event.showStatus = function(configured, tab, callback) {
|
||||
let keyId = null;
|
||||
|
|
@ -98,11 +97,11 @@ event.showStatus = function(configured, tab, callback) {
|
|||
associated: keepass.isAssociated(),
|
||||
error: errorMessage ? errorMessage : null
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
event.onLoadSettings = function(callback, tab) {
|
||||
page.settings = (typeof(localStorage.settings) === 'undefined') ? {} : JSON.parse(localStorage.settings);
|
||||
}
|
||||
};
|
||||
|
||||
event.onLoadKeyRing = function(callback, tab) {
|
||||
keepass.keyRing = (typeof(localStorage.keyRing) === 'undefined') ? {} : JSON.parse(localStorage.keyRing);
|
||||
|
|
@ -112,17 +111,17 @@ event.onLoadKeyRing = function(callback, tab) {
|
|||
hash: null
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
event.onGetSettings = function(callback, tab) {
|
||||
event.onLoadSettings();
|
||||
callback({ data: page.settings });
|
||||
}
|
||||
};
|
||||
|
||||
event.onSaveSettings = function(callback, tab, settings) {
|
||||
localStorage.settings = JSON.stringify(settings);
|
||||
event.onLoadSettings();
|
||||
}
|
||||
};
|
||||
|
||||
event.onGetStatus = function(callback, tab) {
|
||||
keepass.testAssociation((response) => {
|
||||
|
|
@ -130,7 +129,7 @@ event.onGetStatus = function(callback, tab) {
|
|||
event.showStatus(configured, tab, callback);
|
||||
});
|
||||
}, tab);
|
||||
}
|
||||
};
|
||||
|
||||
event.onReconnect = function(callback, tab) {
|
||||
keepass.connectToNative();
|
||||
|
|
@ -150,24 +149,24 @@ event.onReconnect = function(callback, tab) {
|
|||
}, null);
|
||||
});
|
||||
}, 2000);
|
||||
}
|
||||
};
|
||||
|
||||
event.onPopStack = function(callback, tab) {
|
||||
browserAction.stackPop(tab.id);
|
||||
browserAction.show(null, tab);
|
||||
}
|
||||
};
|
||||
|
||||
event.onGetTabInformation = function(callback, tab) {
|
||||
const id = tab.id || page.currentTabId;
|
||||
callback(page.tabs[id]);
|
||||
}
|
||||
};
|
||||
|
||||
event.onGetConnectedDatabase = function(callback, tab) {
|
||||
callback({
|
||||
count: Object.keys(keepass.keyRing).length,
|
||||
identifier: (keepass.keyRing[keepass.associated.hash]) ? keepass.keyRing[keepass.associated.hash].id : null
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
event.onGetKeePassXCVersions = function(callback, tab) {
|
||||
if (keepass.currentKeePassXC.version === 0) {
|
||||
|
|
@ -176,57 +175,62 @@ event.onGetKeePassXCVersions = function(callback, tab) {
|
|||
}, tab);
|
||||
}
|
||||
callback({current: keepass.currentKeePassXC.version, latest: keepass.latestKeePassXC.version});
|
||||
}
|
||||
};
|
||||
|
||||
event.onCheckUpdateKeePassXC = function(callback, tab) {
|
||||
keepass.checkForNewKeePassXCVersion();
|
||||
callback({current: keepass.currentKeePassXC.version, latest: keepass.latestKeePassXC.version});
|
||||
}
|
||||
};
|
||||
|
||||
event.onUpdateAvailableKeePassXC = function(callback, tab) {
|
||||
callback(keepass.keePassXCUpdateAvailable());
|
||||
}
|
||||
};
|
||||
|
||||
event.onRemoveCredentialsFromTabInformation = function(callback, tab) {
|
||||
const id = tab.id || page.currentTabId;
|
||||
page.clearCredentials(id);
|
||||
}
|
||||
};
|
||||
|
||||
event.onSetRememberPopup = function(callback, tab, username, password, url, usernameExists, credentialsList) {
|
||||
browserAction.setRememberPopup(tab.id, username, password, url, usernameExists, credentialsList);
|
||||
}
|
||||
};
|
||||
|
||||
event.onLoginPopup = function(callback, tab, logins) {
|
||||
let stackData = {
|
||||
level: 1,
|
||||
iconType: 'questionmark',
|
||||
popup: 'popup_login.html'
|
||||
}
|
||||
};
|
||||
browserAction.stackUnshift(stackData, tab.id);
|
||||
page.tabs[tab.id].loginList = logins;
|
||||
browserAction.show(null, tab);
|
||||
}
|
||||
};
|
||||
|
||||
event.onHTTPAuthPopup = function(callback, tab, data) {
|
||||
let stackData = {
|
||||
level: 1,
|
||||
iconType: 'questionmark',
|
||||
popup: 'popup_httpauth.html'
|
||||
}
|
||||
};
|
||||
browserAction.stackUnshift(stackData, tab.id);
|
||||
page.tabs[tab.id].loginList = data;
|
||||
browserAction.show(null, tab);
|
||||
}
|
||||
};
|
||||
|
||||
event.onMultipleFieldsPopup = function(callback, tab) {
|
||||
let stackData = {
|
||||
level: 1,
|
||||
iconType: 'normal',
|
||||
popup: 'popup_multiple-fields.html'
|
||||
}
|
||||
};
|
||||
browserAction.stackUnshift(stackData, tab.id);
|
||||
browserAction.show(null, tab);
|
||||
}
|
||||
};
|
||||
|
||||
event.pageClearLogins = function(callback, tab) {
|
||||
page.clearLogins(tab.id);
|
||||
callback();
|
||||
};
|
||||
|
||||
|
||||
// all methods named in this object have to be declared BEFORE this!
|
||||
|
|
@ -242,6 +246,7 @@ event.messageHandlers = {
|
|||
'get_tab_information': event.onGetTabInformation,
|
||||
'load_keyring': event.onLoadKeyRing,
|
||||
'load_settings': event.onLoadSettings,
|
||||
'page_clear_logins': event.pageClearLogins,
|
||||
'pop_stack': event.onPopStack,
|
||||
'popup_login': event.onLoginPopup,
|
||||
'popup_multiple-fields': event.onMultipleFieldsPopup,
|
||||
|
|
|
|||
|
|
@ -1,65 +1,62 @@
|
|||
var httpAuth = httpAuth || {};
|
||||
|
||||
httpAuth.requests = [];
|
||||
httpAuth.pendingCallbacks = [];
|
||||
httpAuth.requestId = '';
|
||||
httpAuth.tabId = 0;
|
||||
httpAuth.url = null;
|
||||
httpAuth.isProxy = false;
|
||||
httpAuth.proxyUrl = null;
|
||||
httpAuth.resolve = null;
|
||||
httpAuth.reject = null;
|
||||
|
||||
httpAuth.handleRequest = function (details, callback) {
|
||||
if (httpAuth.requestId == details.requestId || !page.tabs[details.tabId]) {
|
||||
callback({});
|
||||
httpAuth.requestCompleted = function(details) {
|
||||
let index = httpAuth.requests.indexOf(details.requestId);
|
||||
if (index > -1) {
|
||||
httpAuth.requests.splice(index, 1);
|
||||
}
|
||||
else {
|
||||
httpAuth.requestId = details.requestId;
|
||||
httpAuth.pendingCallbacks.push(callback);
|
||||
httpAuth.processPendingCallbacks(details);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
httpAuth.processPendingCallbacks = function(details) {
|
||||
httpAuth.callback = httpAuth.pendingCallbacks.pop();
|
||||
httpAuth.tabId = details.tabId;
|
||||
httpAuth.url = details.url;
|
||||
httpAuth.isProxy = details.isProxy;
|
||||
httpAuth.handleRequestPromise = function(details) {
|
||||
return new Promise((resolve, reject) => {
|
||||
httpAuth.processPendingCallbacks(details, resolve, reject);
|
||||
});
|
||||
};
|
||||
|
||||
if (details.challenger){
|
||||
httpAuth.proxyUrl = details.challenger.host;
|
||||
httpAuth.handleRequestCallback = function(details, callback) {
|
||||
httpAuth.processPendingCallbacks(details, callback, callback);
|
||||
};
|
||||
|
||||
httpAuth.processPendingCallbacks = function(details, resolve, reject) {
|
||||
if (httpAuth.requests.indexOf(details.requestId) >= 0 || !page.tabs[details.tabId]) {
|
||||
reject({});
|
||||
}
|
||||
|
||||
// WORKAROUND: second parameter should be tab, but is an own object with tab-id
|
||||
// but in background.js only tab.id is used. To get tabs we could use
|
||||
// chrome.tabs.get(tabId, callback) <-- but what should callback be?
|
||||
httpAuth.requests.push(details.requestId);
|
||||
|
||||
const url = (httpAuth.isProxy && httpAuth.proxyUrl) ? httpAuth.proxyUrl : httpAuth.url;
|
||||
if (details.challenger) {
|
||||
details.proxyUrl = details.challenger.host;
|
||||
}
|
||||
|
||||
keepass.retrieveCredentials(httpAuth.loginOrShowCredentials, { 'id' : details.tabId }, url, url, true);
|
||||
}
|
||||
details.searchUrl = (details.isProxy && details.proxyUrl) ? details.proxyUrl : details.url;
|
||||
|
||||
httpAuth.loginOrShowCredentials = function(logins) {
|
||||
keepass.retrieveCredentials((logins) => {
|
||||
httpAuth.loginOrShowCredentials(logins, details, resolve, reject);
|
||||
}, { "id": details.tabId }, details.searchUrl, details.searchUrl, true);
|
||||
};
|
||||
|
||||
httpAuth.loginOrShowCredentials = function(logins, details, resolve, reject) {
|
||||
// at least one login found --> use first to login
|
||||
if (logins.length > 0) {
|
||||
const url = (httpAuth.isProxy && httpAuth.proxyUrl) ? httpAuth.proxyUrl : httpAuth.url;
|
||||
event.onHTTPAuthPopup(null, {'id': httpAuth.tabId}, {'logins': logins, 'url': url});
|
||||
event.onHTTPAuthPopup(null, { "id": details.tabId }, { "logins": logins, "url": details.searchUrl });
|
||||
//generate popup-list for HTTP Auth usernames + descriptions
|
||||
|
||||
if (page.settings.autoFillAndSend) {
|
||||
httpAuth.callback({
|
||||
resolve({
|
||||
authCredentials: {
|
||||
username: logins[0].login,
|
||||
password: logins[0].password
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
httpAuth.callback({});
|
||||
} else {
|
||||
reject({});
|
||||
}
|
||||
}
|
||||
// no logins found
|
||||
else {
|
||||
httpAuth.callback({});
|
||||
reject({});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -7,12 +7,6 @@ keepass.changePublicKeys(null, (pkRes) => {
|
|||
keepass.getDatabaseHash((gdRes) => {}, null);
|
||||
});
|
||||
|
||||
// Set initial tab-ID
|
||||
browser.tabs.query({"active": true, "currentWindow": true}, (tabs) => {
|
||||
if (tabs.length === 0)
|
||||
return; // For example: only the background devtools or a popup are opened
|
||||
page.currentTabId = tabs[0].id;
|
||||
});
|
||||
|
||||
// Milliseconds for intervall (e.g. to update browserAction)
|
||||
let _interval = 250;
|
||||
|
|
@ -55,8 +49,7 @@ browser.tabs.onActivated.addListener((activeInfo) => {
|
|||
page.clearCredentials(page.currentTabId, true);
|
||||
browserAction.removeRememberPopup(null, {'id': page.currentTabId}, true);
|
||||
|
||||
browser.tabs.get(activeInfo.tabId, (info) => {
|
||||
//console.log(info.id + ': ' + info.url);
|
||||
browser.tabs.get(activeInfo.tabId).then((info) => {
|
||||
if (info && info.id) {
|
||||
page.currentTabId = info.id;
|
||||
if (info.status === 'complete') {
|
||||
|
|
@ -79,9 +72,20 @@ browser.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
|
|||
});
|
||||
|
||||
// Retrieve Credentials and try auto-login for HTTPAuth requests
|
||||
browser.webRequest.onAuthRequired.addListener(httpAuth.handleRequest,
|
||||
{ urls: ['<all_urls>'] }, ['asyncBlocking']
|
||||
);
|
||||
if (browser.webRequest.onAuthRequired) {
|
||||
let handleReq = httpAuth.handleRequestPromise;
|
||||
let reqType = 'blocking';
|
||||
let opts = { urls: ['<all_urls>'] };
|
||||
|
||||
if (!isFirefox) {
|
||||
handleReq = httpAuth.handleRequestCallback;
|
||||
reqType = 'asyncBlocking';
|
||||
}
|
||||
|
||||
browser.webRequest.onAuthRequired.addListener(handleReq, opts, [reqType]);
|
||||
browser.webRequest.onCompleted.addListener(httpAuth.requestCompleted, opts);
|
||||
browser.webRequest.onErrorOccurred.addListener(httpAuth.requestCompleted, opts);
|
||||
}
|
||||
|
||||
browser.runtime.onMessage.addListener(event.onMessage);
|
||||
|
||||
|
|
@ -90,7 +94,7 @@ const contextMenuItems = [
|
|||
{title: 'Fill &Pass Only', action: 'fill_pass_only'},
|
||||
{title: 'Show Password &Generator Icons', action: 'activate_password_generator'},
|
||||
{title: '&Save credentials', action: 'remember_credentials'}
|
||||
]
|
||||
];
|
||||
|
||||
// Create context menu items
|
||||
for (const item of contextMenuItems) {
|
||||
|
|
@ -100,7 +104,7 @@ for (const item of contextMenuItems) {
|
|||
onclick: (info, tab) => {
|
||||
browser.tabs.sendMessage(tab.id, {
|
||||
action: item.action
|
||||
});
|
||||
}).catch((e) => {console.log(e);});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -108,7 +112,7 @@ for (const item of contextMenuItems) {
|
|||
// Listen for keyboard shortcuts specified by user
|
||||
browser.commands.onCommand.addListener((command) => {
|
||||
if (command === 'fill-username-password') {
|
||||
browser.tabs.query({ active: true, currentWindow: true }, (tabs) => {
|
||||
browser.tabs.query({ active: true, currentWindow: true }).then((tabs) => {
|
||||
if (tabs.length) {
|
||||
browser.tabs.sendMessage(tabs[0].id, { action: 'fill_user_pass' });
|
||||
}
|
||||
|
|
@ -116,7 +120,7 @@ browser.commands.onCommand.addListener((command) => {
|
|||
}
|
||||
|
||||
if (command === 'fill-password') {
|
||||
browser.tabs.query({ active: true, currentWindow: true }, (tabs) => {
|
||||
browser.tabs.query({ active: true, currentWindow: true }).then((tabs) => {
|
||||
if (tabs.length) {
|
||||
browser.tabs.sendMessage(tabs[0].id, { action: 'fill_pass_only' });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ var keepass = {};
|
|||
keepass.associated = {'value': false, 'hash': null};
|
||||
keepass.keyPair = {publicKey: null, secretKey: null};
|
||||
keepass.serverPublicKey = '';
|
||||
keepass.clientID = '';
|
||||
keepass.isConnected = false;
|
||||
keepass.isDatabaseClosed = false;
|
||||
keepass.isKeePassXCAvailable = false;
|
||||
|
|
@ -66,7 +67,7 @@ const kpErrors = {
|
|||
|
||||
keepass.addCredentials = function(callback, tab, username, password, url) {
|
||||
keepass.updateCredentials(callback, tab, null, username, password, url);
|
||||
}
|
||||
};
|
||||
|
||||
keepass.updateCredentials = function(callback, tab, entryId, username, password, url) {
|
||||
page.debug('keepass.updateCredentials(callback, {1}, {2}, {3}, [password], {4})', tab.id, entryId, username, url);
|
||||
|
|
@ -76,9 +77,7 @@ keepass.updateCredentials = function(callback, tab, entryId, username, password,
|
|||
if (!response)
|
||||
{
|
||||
browserAction.showDefault(null, tab);
|
||||
if (forceCallback) {
|
||||
callback([]);
|
||||
}
|
||||
callback([]);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -102,7 +101,8 @@ keepass.updateCredentials = function(callback, tab, entryId, username, password,
|
|||
const request = {
|
||||
action: kpAction,
|
||||
message: keepass.encrypt(messageData, nonce),
|
||||
nonce: keepass.b64e(nonce)
|
||||
nonce: keepass.b64e(nonce),
|
||||
clientID: keepass.clientID
|
||||
};
|
||||
console.log(request);
|
||||
|
||||
|
|
@ -124,7 +124,7 @@ keepass.updateCredentials = function(callback, tab, entryId, username, password,
|
|||
});
|
||||
keepass.nativePort.postMessage(request);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
keepass.retrieveCredentials = function (callback, tab, url, submiturl, forceCallback, triggerUnlock) {
|
||||
page.debug('keepass.retrieveCredentials(callback, {1}, {2}, {3}, {4})', tab.id, url, submiturl, forceCallback);
|
||||
|
|
@ -164,7 +164,8 @@ keepass.retrieveCredentials = function (callback, tab, url, submiturl, forceCall
|
|||
const request = {
|
||||
action: kpAction,
|
||||
message: keepass.encrypt(messageData, nonce),
|
||||
nonce: keepass.b64e(nonce)
|
||||
nonce: keepass.b64e(nonce),
|
||||
clientID: keepass.clientID
|
||||
};
|
||||
|
||||
keepass.callbackOnId(keepass.nativePort.onMessage, kpAction, (response) => {
|
||||
|
|
@ -199,7 +200,7 @@ keepass.retrieveCredentials = function (callback, tab, url, submiturl, forceCall
|
|||
});
|
||||
keepass.nativePort.postMessage(request);
|
||||
}, tab);
|
||||
}
|
||||
};
|
||||
|
||||
// Redirects the callback to a listener (handleReply())
|
||||
keepass.callbackOnId = function (ev, id, callback) {
|
||||
|
|
@ -209,11 +210,11 @@ keepass.callbackOnId = function (ev, id, callback) {
|
|||
ev.removeListener(handler);
|
||||
callback(msg);
|
||||
}
|
||||
}
|
||||
};
|
||||
return handler;
|
||||
})(ev, id, callback);
|
||||
ev.addListener(listener);
|
||||
}
|
||||
};
|
||||
|
||||
keepass.generatePassword = function (callback, tab, forceCallback) {
|
||||
if (!keepass.isConnected) {
|
||||
|
|
@ -242,7 +243,8 @@ keepass.generatePassword = function (callback, tab, forceCallback) {
|
|||
|
||||
const request = {
|
||||
action: kpAction,
|
||||
nonce: keepass.b64e(nonce)
|
||||
nonce: keepass.b64e(nonce),
|
||||
clientID: keepass.clientID
|
||||
};
|
||||
|
||||
keepass.callbackOnId(keepass.nativePort.onMessage, kpAction, (response) => {
|
||||
|
|
@ -254,7 +256,6 @@ keepass.generatePassword = function (callback, tab, forceCallback) {
|
|||
keepass.setcurrentKeePassXCVersion(parsed.version);
|
||||
|
||||
if (keepass.verifyResponse(parsed, response.nonce)) {
|
||||
const rIv = response.nonce;
|
||||
if (parsed.entries) {
|
||||
passwords = parsed.entries;
|
||||
keepass.updateLastUsed(keepass.databaseHash);
|
||||
|
|
@ -275,7 +276,7 @@ keepass.generatePassword = function (callback, tab, forceCallback) {
|
|||
});
|
||||
keepass.nativePort.postMessage(request);
|
||||
}, tab);
|
||||
}
|
||||
};
|
||||
|
||||
keepass.associate = function(callback, tab) {
|
||||
if (keepass.isAssociated()) {
|
||||
|
|
@ -303,7 +304,8 @@ keepass.associate = function(callback, tab) {
|
|||
const request = {
|
||||
action: kpAction,
|
||||
message: keepass.encrypt(messageData, nonce),
|
||||
nonce: keepass.b64e(nonce)
|
||||
nonce: keepass.b64e(nonce),
|
||||
clientID: keepass.clientID
|
||||
};
|
||||
|
||||
keepass.callbackOnId(keepass.nativePort.onMessage, kpAction, (response) => {
|
||||
|
|
@ -333,7 +335,7 @@ keepass.associate = function(callback, tab) {
|
|||
});
|
||||
keepass.nativePort.postMessage(request);
|
||||
}, tab);
|
||||
}
|
||||
};
|
||||
|
||||
keepass.testAssociation = function (callback, tab, triggerUnlock) {
|
||||
if (tab && page.tabs[tab.id]) {
|
||||
|
|
@ -358,7 +360,7 @@ keepass.testAssociation = function (callback, tab, triggerUnlock) {
|
|||
|
||||
if (!keepass.serverPublicKey) {
|
||||
if (tab && page.tabs[tab.id]) {
|
||||
handleError(tab, kpErrors.PUBLIC_KEY_NOT_FOUND);
|
||||
keepass.handleError(tab, kpErrors.PUBLIC_KEY_NOT_FOUND);
|
||||
}
|
||||
callback(false);
|
||||
return false;
|
||||
|
|
@ -368,7 +370,7 @@ keepass.testAssociation = function (callback, tab, triggerUnlock) {
|
|||
const nonce = nacl.randomBytes(keepass.keySize);
|
||||
const {dbid, dbkey} = keepass.getCryptoKey();
|
||||
|
||||
if (dbkey === null || dbid === null) {
|
||||
if (dbkey === null || dbid === null) {
|
||||
if (tab && page.tabs[tab.id]) {
|
||||
keepass.handleError(tab, kpErrors.NO_SAVED_DATABASES_FOUND);
|
||||
}
|
||||
|
|
@ -385,7 +387,8 @@ keepass.testAssociation = function (callback, tab, triggerUnlock) {
|
|||
const request = {
|
||||
action: kpAction,
|
||||
message: keepass.encrypt(messageData, nonce),
|
||||
nonce: keepass.b64e(nonce)
|
||||
nonce: keepass.b64e(nonce),
|
||||
clientID: keepass.clientID
|
||||
};
|
||||
|
||||
keepass.callbackOnId(keepass.nativePort.onMessage, kpAction, (response) => {
|
||||
|
|
@ -395,7 +398,6 @@ keepass.testAssociation = function (callback, tab, triggerUnlock) {
|
|||
const message = nacl.util.encodeUTF8(res);
|
||||
const parsed = JSON.parse(message);
|
||||
keepass.setcurrentKeePassXCVersion(parsed.version);
|
||||
const id = parsed.id;
|
||||
keepass.isEncryptionKeyUnrecognized = false;
|
||||
|
||||
if (!keepass.verifyResponse(parsed, response.nonce)) {
|
||||
|
|
@ -423,7 +425,7 @@ keepass.testAssociation = function (callback, tab, triggerUnlock) {
|
|||
});
|
||||
keepass.nativePort.postMessage(request);
|
||||
}, tab, triggerUnlock);
|
||||
}
|
||||
};
|
||||
|
||||
keepass.getDatabaseHash = function (callback, tab, triggerUnlock) {
|
||||
if (!keepass.isConnected) {
|
||||
|
|
@ -453,7 +455,8 @@ keepass.getDatabaseHash = function (callback, tab, triggerUnlock) {
|
|||
const request = {
|
||||
action: kpAction,
|
||||
message: encrypted,
|
||||
nonce: keepass.b64e(nonce)
|
||||
nonce: keepass.b64e(nonce),
|
||||
clientID: keepass.clientID
|
||||
};
|
||||
|
||||
keepass.callbackOnId(keepass.nativePort.onMessage, kpAction, (response) => {
|
||||
|
|
@ -493,7 +496,7 @@ keepass.getDatabaseHash = function (callback, tab, triggerUnlock) {
|
|||
}
|
||||
});
|
||||
keepass.nativePort.postMessage(request);
|
||||
}
|
||||
};
|
||||
|
||||
keepass.changePublicKeys = function(tab, callback) {
|
||||
if (!keepass.isConnected) {
|
||||
|
|
@ -504,14 +507,16 @@ keepass.changePublicKeys = function(tab, callback) {
|
|||
const kpAction = kpActions.CHANGE_PUBLIC_KEYS;
|
||||
const key = keepass.b64e(keepass.keyPair.publicKey);
|
||||
let nonce = nacl.randomBytes(keepass.keySize);
|
||||
nonce = keepass.b64e(nonce)
|
||||
nonce = keepass.b64e(nonce);
|
||||
keepass.clientID = keepass.b64e(nacl.randomBytes(keepass.keySize));
|
||||
|
||||
const message = {
|
||||
action: kpAction,
|
||||
publicKey: key,
|
||||
proxyPort: (page.settings.port ? page.settings.port : 19700),
|
||||
nonce: nonce
|
||||
}
|
||||
nonce: nonce,
|
||||
clientID: keepass.clientID
|
||||
};
|
||||
|
||||
keepass.callbackOnId(keepass.nativePort.onMessage, kpAction, (response) => {
|
||||
keepass.setcurrentKeePassXCVersion(response.version);
|
||||
|
|
@ -529,12 +534,12 @@ keepass.changePublicKeys = function(tab, callback) {
|
|||
callback(true);
|
||||
});
|
||||
keepass.nativePort.postMessage(message);
|
||||
}
|
||||
};
|
||||
|
||||
keepass.generateNewKeyPair = function() {
|
||||
keepass.keyPair = nacl.box.keyPair();
|
||||
//console.log(keepass.b64e(keepass.keyPair.publicKey) + ' ' + keepass.b64e(keepass.keyPair.secretKey));
|
||||
}
|
||||
};
|
||||
|
||||
keepass.isConfigured = function(callback) {
|
||||
if (typeof(keepass.databaseHash) === 'undefined') {
|
||||
|
|
@ -545,11 +550,11 @@ keepass.isConfigured = function(callback) {
|
|||
else {
|
||||
callback(keepass.databaseHash in keepass.keyRing);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
keepass.isAssociated = function() {
|
||||
return (keepass.associated.value && keepass.associated.hash && keepass.associated.hash === keepass.databaseHash);
|
||||
}
|
||||
};
|
||||
|
||||
keepass.convertKeyToKeyRing = function() {
|
||||
if (keepass.keyId in localStorage && keepass.keyBody in localStorage && !('keyRing' in localStorage)) {
|
||||
|
|
@ -567,7 +572,7 @@ keepass.convertKeyToKeyRing = function() {
|
|||
delete localStorage[keepass.keyId];
|
||||
delete localStorage[keepass.keyBody];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
keepass.saveKey = function(hash, id, key) {
|
||||
if (!(hash in keepass.keyRing)) {
|
||||
|
|
@ -577,7 +582,7 @@ keepass.saveKey = function(hash, id, key) {
|
|||
hash: hash,
|
||||
created: new Date(),
|
||||
lastUsed: new Date()
|
||||
}
|
||||
};
|
||||
}
|
||||
else {
|
||||
keepass.keyRing[hash].id = id;
|
||||
|
|
@ -585,19 +590,19 @@ keepass.saveKey = function(hash, id, key) {
|
|||
keepass.keyRing[hash].hash = hash;
|
||||
}
|
||||
localStorage.keyRing = JSON.stringify(keepass.keyRing);
|
||||
}
|
||||
};
|
||||
|
||||
keepass.updateLastUsed = function(hash) {
|
||||
if ((hash in keepass.keyRing)) {
|
||||
keepass.keyRing[hash].lastUsed = new Date();
|
||||
localStorage.keyRing = JSON.stringify(keepass.keyRing);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
keepass.deleteKey = function(hash) {
|
||||
delete keepass.keyRing[hash];
|
||||
localStorage.keyRing = JSON.stringify(keepass.keyRing);
|
||||
}
|
||||
};
|
||||
|
||||
keepass.setcurrentKeePassXCVersion = function(version) {
|
||||
if (version) {
|
||||
|
|
@ -606,7 +611,7 @@ keepass.setcurrentKeePassXCVersion = function(version) {
|
|||
versionParsed: Number(version.replace(/\./g, ''))
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
keepass.keePassXCUpdateAvailable = function() {
|
||||
if (page.settings.checkUpdateKeePassXC && page.settings.checkUpdateKeePassXC > 0) {
|
||||
|
|
@ -618,7 +623,7 @@ keepass.keePassXCUpdateAvailable = function() {
|
|||
}
|
||||
|
||||
return (keepass.currentKeePassXC.versionParsed > 0 && keepass.currentKeePassXC.versionParsed < keepass.latestKeePassXC.versionParsed);
|
||||
}
|
||||
};
|
||||
|
||||
keepass.checkForNewKeePassXCVersion = function() {
|
||||
let xhr = new XMLHttpRequest();
|
||||
|
|
@ -641,7 +646,7 @@ keepass.checkForNewKeePassXCVersion = function() {
|
|||
|
||||
xhr.onerror = function(e) {
|
||||
console.log('checkForNewKeePassXCVersion error:' + e);
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
xhr.open('GET', keepass.latestVersionUrl, true);
|
||||
|
|
@ -651,17 +656,17 @@ keepass.checkForNewKeePassXCVersion = function() {
|
|||
console.log(ex);
|
||||
}
|
||||
keepass.latestKeePassXC.lastChecked = new Date();
|
||||
}
|
||||
};
|
||||
|
||||
keepass.connectToNative = function() {
|
||||
if (!keepass.isConnected) {
|
||||
keepass.nativeConnect();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
keepass.onNativeMessage = function (response) {
|
||||
//console.log('Received message: ' + JSON.stringify(response));
|
||||
}
|
||||
};
|
||||
|
||||
function onDisconnected() {
|
||||
keepass.nativePort = null;
|
||||
|
|
@ -674,12 +679,12 @@ function onDisconnected() {
|
|||
}
|
||||
|
||||
keepass.nativeConnect = function() {
|
||||
console.log('Connecting to native messaging host ' + keepass.nativeHostName)
|
||||
console.log('Connecting to native messaging host ' + keepass.nativeHostName);
|
||||
keepass.nativePort = browser.runtime.connectNative(keepass.nativeHostName);
|
||||
keepass.nativePort.onMessage.addListener(keepass.onNativeMessage);
|
||||
keepass.nativePort.onDisconnect.addListener(onDisconnected);
|
||||
keepass.isConnected = true;
|
||||
}
|
||||
};
|
||||
|
||||
keepass.verifyKeyResponse = function(response, key, nonce) {
|
||||
if (!response.success || !response.publicKey) {
|
||||
|
|
@ -699,8 +704,7 @@ keepass.verifyKeyResponse = function(response, key, nonce) {
|
|||
}
|
||||
|
||||
return reply;
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
keepass.verifyResponse = function(response, nonce, id) {
|
||||
keepass.associated.value = response.success;
|
||||
|
|
@ -723,8 +727,7 @@ keepass.verifyResponse = function(response, nonce, id) {
|
|||
keepass.associated.hash = (keepass.associated.value) ? keepass.databaseHash : null;
|
||||
|
||||
return keepass.isAssociated();
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
keepass.handleError = function(tab, errorCode, errorMessage = '') {
|
||||
if (errorMessage.length === 0) {
|
||||
|
|
@ -734,15 +737,15 @@ keepass.handleError = function(tab, errorCode, errorMessage = '') {
|
|||
if (tab && page.tabs[tab.id]) {
|
||||
page.tabs[tab.id].errorMessage = errorMessage;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
keepass.b64e = function(d) {
|
||||
return nacl.util.encodeBase64(d);
|
||||
}
|
||||
};
|
||||
|
||||
keepass.b64d = function(d) {
|
||||
return nacl.util.decodeBase64(d);
|
||||
}
|
||||
};
|
||||
|
||||
keepass.getCryptoKey = function() {
|
||||
let dbkey = null;
|
||||
|
|
@ -758,11 +761,11 @@ keepass.getCryptoKey = function() {
|
|||
}
|
||||
|
||||
return {dbid, dbkey};
|
||||
}
|
||||
};
|
||||
|
||||
keepass.setCryptoKey = function(id, key) {
|
||||
keepass.saveKey(keepass.databaseHash, id, key);
|
||||
}
|
||||
};
|
||||
|
||||
keepass.encrypt = function(input, nonce) {
|
||||
const messageData = nacl.util.decodeUTF8(JSON.stringify(input));
|
||||
|
|
@ -774,11 +777,11 @@ keepass.encrypt = function(input, nonce) {
|
|||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
keepass.decrypt = function(input, nonce, toStr) {
|
||||
const m = keepass.b64d(input);
|
||||
const n = keepass.b64d(nonce);
|
||||
const res = nacl.box.open(m, n, keepass.serverPublicKey, keepass.keyPair.secretKey);
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ const defaultSettings = {
|
|||
autoFillSingleEntry: false,
|
||||
autoRetrieveCredentials: true,
|
||||
proxyPort: '19700'
|
||||
}
|
||||
};
|
||||
|
||||
var page = {};
|
||||
page.tabs = {};
|
||||
|
|
@ -39,26 +39,35 @@ page.initSettings = function() {
|
|||
page.settings.port = defaultSettings.proxyPort;
|
||||
}
|
||||
localStorage.settings = JSON.stringify(page.settings);
|
||||
}
|
||||
};
|
||||
|
||||
page.initOpenedTabs = function() {
|
||||
browser.tabs.query({}, (tabs) => {
|
||||
browser.tabs.query({}).then((tabs) => {
|
||||
for (const i of tabs) {
|
||||
page.createTabEntry(i.id);
|
||||
}
|
||||
|
||||
// set initial tab-ID
|
||||
browser.tabs.query({ "active": true, "currentWindow": true }).then((tabs) => {
|
||||
if (tabs.length === 0) {
|
||||
return; // For example: only the background devtools or a popup are opened
|
||||
}
|
||||
page.currentTabId = tabs[0].id;
|
||||
browserAction.show(null, tabs[0]);
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
page.isValidProtocol = function(url) {
|
||||
let protocol = url.substring(0, url.indexOf(':'));
|
||||
protocol = protocol.toLowerCase();
|
||||
return !(url.indexOf('.') === -1 || (protocol !== 'http' && protocol !== 'https' && protocol !== 'ftp' && protocol !== 'sftp'));
|
||||
}
|
||||
};
|
||||
|
||||
page.switchTab = function(callback, tab) {
|
||||
browserAction.showDefault(null, tab);
|
||||
browser.tabs.sendMessage(tab.id, {action: 'activated_tab'});
|
||||
}
|
||||
browser.tabs.sendMessage(tab.id, {action: 'activated_tab'}).catch((e) => {console.log(e);});
|
||||
};
|
||||
|
||||
page.clearCredentials = function(tabId, complete) {
|
||||
if (!page.tabs[tabId]) {
|
||||
|
|
@ -69,22 +78,25 @@ page.clearCredentials = function(tabId, complete) {
|
|||
delete page.tabs[tabId].credentials;
|
||||
|
||||
if (complete) {
|
||||
page.tabs[tabId].loginList = [];
|
||||
page.clearLogins(tabId);
|
||||
|
||||
browser.tabs.sendMessage(tabId, {
|
||||
action: 'clear_credentials'
|
||||
});
|
||||
}).catch((e) => {console.log(e);});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
page.clearLogins = function(tabId) {
|
||||
page.tabs[tabId].loginList = [];
|
||||
};
|
||||
|
||||
page.createTabEntry = function(tabId) {
|
||||
//console.log('page.createTabEntry('+tabId+')');
|
||||
page.tabs[tabId] = {
|
||||
'stack': [],
|
||||
'errorMessage': null,
|
||||
'loginList': {}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
page.removePageInformationFromNotExistingTabs = function() {
|
||||
let rand = Math.floor(Math.random()*1001);
|
||||
|
|
@ -117,12 +129,9 @@ page.debugConsole = function() {
|
|||
|
||||
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
|
||||
;
|
||||
return typeof args[number] !== 'undefined' ? (typeof args[number] === 'object' ? JSON.stringify(args[number]) : args[number]) : match;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
page.debugDummy = function() {};
|
||||
|
||||
|
|
|
|||
9
keepassxc-browser/browser-polyfill.min.js
vendored
Normal file
9
keepassxc-browser/browser-polyfill.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -1,6 +1,4 @@
|
|||
var isFirefox = false;
|
||||
if (typeof browser !== 'undefined') {
|
||||
if (!(/Chrome/.test(navigator.userAgent) && /Google/.test(navigator.vendor))) {
|
||||
isFirefox = true;
|
||||
}
|
||||
|
||||
window.browser = (function () { return window.msBrowser || window.browser || window.chrome; })();
|
||||
}
|
||||
|
|
@ -53,7 +53,7 @@ browser.runtime.onMessage.addListener(function(req, sender, callback) {
|
|||
else if (req.action === 'redetect_fields') {
|
||||
browser.runtime.sendMessage({
|
||||
action: 'get_settings',
|
||||
}, (response) => {
|
||||
}).then((response) => {
|
||||
cip.settings = response.data;
|
||||
cip.initCredentialFields(true);
|
||||
});
|
||||
|
|
@ -94,17 +94,17 @@ cipAutocomplete.init = function(field) {
|
|||
.click(cipAutocomplete.onClick)
|
||||
.blur(cipAutocomplete.onBlur)
|
||||
.focus(cipAutocomplete.onFocus);
|
||||
}
|
||||
};
|
||||
|
||||
cipAutocomplete.onClick = function() {
|
||||
jQuery(this).autocomplete('search', jQuery(this).val());
|
||||
}
|
||||
};
|
||||
|
||||
cipAutocomplete.onOpen = function(event, ui) {
|
||||
// NOT BEAUTIFUL!
|
||||
// modifies ALL ui-autocomplete menus of class .cip-ui-menu
|
||||
jQuery('ul.ui-autocomplete.ui-menu').css('z-index', 2147483636);
|
||||
}
|
||||
};
|
||||
|
||||
cipAutocomplete.onSource = function (request, callback) {
|
||||
const matches = jQuery.map(cipAutocomplete.elements, (tag) => {
|
||||
|
|
@ -113,7 +113,7 @@ cipAutocomplete.onSource = function (request, callback) {
|
|||
}
|
||||
});
|
||||
callback(matches);
|
||||
}
|
||||
};
|
||||
|
||||
cipAutocomplete.onSelect = function (e, ui) {
|
||||
e.preventDefault();
|
||||
|
|
@ -123,7 +123,7 @@ cipAutocomplete.onSelect = function (e, ui) {
|
|||
combination.loginId = ui.item.loginId;
|
||||
cip.fillInCredentials(combination, true, false);
|
||||
jQuery(this).data('fetched', true);
|
||||
}
|
||||
};
|
||||
|
||||
cipAutocomplete.onBlur = function() {
|
||||
if (jQuery(this).data('fetched') === true) {
|
||||
|
|
@ -136,7 +136,7 @@ cipAutocomplete.onBlur = function() {
|
|||
cip.fillInCredentials(fields, true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
cipAutocomplete.onFocus = function() {
|
||||
cip.u = jQuery(this);
|
||||
|
|
@ -144,7 +144,7 @@ cipAutocomplete.onFocus = function() {
|
|||
if (jQuery(this).val() === '') {
|
||||
jQuery(this).autocomplete('search', '');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
|
@ -162,7 +162,7 @@ cipPassword.init = function() {
|
|||
window.setInterval(function() {
|
||||
cipPassword.checkObservedElements();
|
||||
}, 400);
|
||||
}
|
||||
};
|
||||
|
||||
cipPassword.initField = function(field, inputs, pos) {
|
||||
if (!field || field.length !== 1) {
|
||||
|
|
@ -190,7 +190,7 @@ cipPassword.initField = function(field, inputs, pos) {
|
|||
}
|
||||
|
||||
field.data('cip-genpw-next-field-exists', $found);
|
||||
}
|
||||
};
|
||||
|
||||
cipPassword.createDialog = function() {
|
||||
if ('passwordCreateDialog' in _called) {
|
||||
|
|
@ -254,7 +254,7 @@ cipPassword.createDialog = function() {
|
|||
e.preventDefault();
|
||||
browser.runtime.sendMessage({
|
||||
action: 'generate_password'
|
||||
}, cipPassword.callbackGeneratedPassword);
|
||||
}).then(cipPassword.callbackGeneratedPassword);
|
||||
}
|
||||
},
|
||||
'Copy':
|
||||
|
|
@ -276,7 +276,7 @@ cipPassword.createDialog = function() {
|
|||
const fieldId = jQuery('#cip-genpw-dialog:first').data('cip-genpw-field-id');
|
||||
const field = jQuery('input[data-cip-id=\''+fieldId+'\']:first');
|
||||
if (field.length === 1) {
|
||||
const $password = jQuery('input#cip-genpw-textfield-password:first').val();
|
||||
let $password = jQuery('input#cip-genpw-textfield-password:first').val();
|
||||
|
||||
if (field.attr('maxlength')) {
|
||||
if ($password.length > field.attr('maxlength')) {
|
||||
|
|
@ -313,7 +313,7 @@ cipPassword.createDialog = function() {
|
|||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
cipPassword.createIcon = function(field) {
|
||||
const $className = (isFirefox ? 'key-moz' : 'key');
|
||||
|
|
@ -359,12 +359,12 @@ cipPassword.createIcon = function(field) {
|
|||
|
||||
cipPassword.observedIcons.push($icon);
|
||||
jQuery('body').append($icon);
|
||||
}
|
||||
};
|
||||
|
||||
cipPassword.setIconPosition = function($icon, $field) {
|
||||
$icon.css('top', $field.offset().top + $icon.data('offset') + 1)
|
||||
.css('left', $field.offset().left + $field.outerWidth() - $icon.data('size') - $icon.data('offset'))
|
||||
}
|
||||
.css('left', $field.offset().left + $field.outerWidth() - $icon.data('size') - $icon.data('offset'));
|
||||
};
|
||||
|
||||
cipPassword.copyPasswordToClipboard = function(e) {
|
||||
if (e) {
|
||||
|
|
@ -372,7 +372,7 @@ cipPassword.copyPasswordToClipboard = function(e) {
|
|||
}
|
||||
|
||||
const input = jQuery("input#cip-genpw-textfield-password");
|
||||
input.select()
|
||||
input.select();
|
||||
try {
|
||||
const success = document.execCommand('copy');
|
||||
if (success) {
|
||||
|
|
@ -384,13 +384,13 @@ cipPassword.copyPasswordToClipboard = function(e) {
|
|||
catch (err) {
|
||||
console.log('Could not copy password to clipboard: ' + err);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
cipPassword.callbackPasswordCopied = function(bool) {
|
||||
if (bool) {
|
||||
jQuery('#cip-genpw-btn-clipboard').addClass('btn-success');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
cipPassword.callbackGeneratedPassword = function(entries) {
|
||||
if (entries && entries.length >= 1) {
|
||||
|
|
@ -414,13 +414,13 @@ cipPassword.callbackGeneratedPassword = function(entries) {
|
|||
jQuery('button#cip-genpw-btn-fillin').hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
cipPassword.onRequestPassword = function() {
|
||||
browser.runtime.sendMessage({
|
||||
action: 'generate_password'
|
||||
}, cipPassword.callbackGeneratedPassword);
|
||||
}
|
||||
}).then(cipPassword.callbackGeneratedPassword);
|
||||
};
|
||||
|
||||
cipPassword.checkObservedElements = function() {
|
||||
if (cipPassword.observingLock) {
|
||||
|
|
@ -451,7 +451,7 @@ cipPassword.checkObservedElements = function() {
|
|||
}
|
||||
});
|
||||
cipPassword.observingLock = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
|
@ -466,7 +466,7 @@ cipForm.init = function(form, credentialFields) {
|
|||
cipForm.setInputFields(form, credentialFields);
|
||||
form.submit(cipForm.onSubmit);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
cipForm.destroy = function(form, credentialFields) {
|
||||
if (form === false && credentialFields) {
|
||||
|
|
@ -479,12 +479,12 @@ cipForm.destroy = function(form, credentialFields) {
|
|||
if (form && jQuery(form).length > 0) {
|
||||
jQuery(form).unbind('submit', cipForm.onSubmit);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
cipForm.setInputFields = function(form, credentialFields) {
|
||||
form.data('cipUsername', credentialFields.username);
|
||||
form.data('cipPassword', credentialFields.password);
|
||||
}
|
||||
};
|
||||
|
||||
cipForm.onSubmit = function() {
|
||||
const usernameId = jQuery(this).data('cipUsername');
|
||||
|
|
@ -535,7 +535,7 @@ cipDefine.init = function () {
|
|||
cipDefine.resetSelection();
|
||||
cipDefine.prepareStep1();
|
||||
cipDefine.markAllUsernameFields($chooser);
|
||||
}
|
||||
};
|
||||
|
||||
cipDefine.initDescription = function() {
|
||||
const $description = jQuery('div#b2c-cipDefine-description');
|
||||
|
|
@ -586,7 +586,6 @@ cipDefine.initDescription = function() {
|
|||
cipDefine.selection.username = cipFields.prepareId(cipDefine.selection.username);
|
||||
}
|
||||
|
||||
const passwordId = jQuery('div#b2c-cipDefine-fields').data('password');
|
||||
if (cipDefine.selection.password) {
|
||||
cipDefine.selection.password = cipFields.prepareId(cipDefine.selection.password);
|
||||
}
|
||||
|
|
@ -645,7 +644,7 @@ cipDefine.initDescription = function() {
|
|||
}
|
||||
|
||||
jQuery('div#b2c-cipDefine-description').draggable();
|
||||
}
|
||||
};
|
||||
|
||||
cipDefine.resetSelection = function() {
|
||||
cipDefine.selection = {
|
||||
|
|
@ -653,7 +652,7 @@ cipDefine.resetSelection = function() {
|
|||
password: null,
|
||||
fields: {}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
cipDefine.isFieldSelected = function($cipId) {
|
||||
return (
|
||||
|
|
@ -661,7 +660,7 @@ cipDefine.isFieldSelected = function($cipId) {
|
|||
$cipId === cipDefine.selection.password ||
|
||||
$cipId in cipDefine.selection.fields
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
cipDefine.markAllUsernameFields = function($chooser) {
|
||||
cipDefine.eventFieldClick = function(e) {
|
||||
|
|
@ -671,7 +670,7 @@ cipDefine.markAllUsernameFields = function($chooser) {
|
|||
cipDefine.markAllPasswordFields(jQuery('#b2c-cipDefine-fields'));
|
||||
};
|
||||
cipDefine.markFields($chooser, cipFields.inputQueryPattern);
|
||||
}
|
||||
};
|
||||
|
||||
cipDefine.markAllPasswordFields = function($chooser) {
|
||||
cipDefine.eventFieldClick = function(e) {
|
||||
|
|
@ -681,7 +680,7 @@ cipDefine.markAllPasswordFields = function($chooser) {
|
|||
cipDefine.markAllStringFields(jQuery('#b2c-cipDefine-fields'));
|
||||
};
|
||||
cipDefine.markFields($chooser, 'input[type=\'password\']');
|
||||
}
|
||||
};
|
||||
|
||||
cipDefine.markAllStringFields = function($chooser) {
|
||||
cipDefine.eventFieldClick = function(e) {
|
||||
|
|
@ -691,7 +690,7 @@ cipDefine.markAllStringFields = function($chooser) {
|
|||
jQuery('button#b2c-btn-confirm:first').addClass('b2c-btn-primary').attr('disabled', false);
|
||||
};
|
||||
cipDefine.markFields($chooser, cipFields.inputQueryPattern + ', select');
|
||||
}
|
||||
};
|
||||
|
||||
cipDefine.markFields = function ($chooser, $pattern) {
|
||||
//var $found = false;
|
||||
|
|
@ -721,7 +720,7 @@ cipDefine.markFields = function ($chooser, $pattern) {
|
|||
jQuery('button#b2c-btn-skip').click();
|
||||
}
|
||||
*/
|
||||
}
|
||||
};
|
||||
|
||||
cipDefine.prepareStep1 = function() {
|
||||
jQuery('div#b2c-help').text('').css('margin-bottom', 0);
|
||||
|
|
@ -732,7 +731,7 @@ cipDefine.prepareStep1 = function() {
|
|||
jQuery('button#b2c-btn-skip:first').data('step', '1').show();
|
||||
jQuery('button#b2c-btn-confirm:first').hide();
|
||||
jQuery('button#b2c-btn-again:first').hide();
|
||||
}
|
||||
};
|
||||
|
||||
cipDefine.prepareStep2 = function() {
|
||||
jQuery('div#b2c-help').text('').css('margin-bottom', 0);
|
||||
|
|
@ -740,7 +739,7 @@ cipDefine.prepareStep2 = function() {
|
|||
jQuery('div:first', jQuery('div#b2c-cipDefine-description')).text('2. Now choose a password field');
|
||||
jQuery('button#b2c-btn-skip:first').data('step', '2');
|
||||
jQuery('button#b2c-btn-again:first').show();
|
||||
}
|
||||
};
|
||||
|
||||
cipDefine.prepareStep3 = function() {
|
||||
/* skip step if no entry was found
|
||||
|
|
@ -760,11 +759,11 @@ cipDefine.prepareStep3 = function() {
|
|||
jQuery('button#b2c-btn-confirm:first').show();
|
||||
jQuery('button#b2c-btn-skip:first').data('step', '3').hide();
|
||||
jQuery('div:first', jQuery('div#b2c-cipDefine-description')).text('3. Confirm selection');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
var cipFields = {}
|
||||
var cipFields = {};
|
||||
|
||||
cipFields.inputQueryPattern = 'input[type=\'text\'], input[type=\'email\'], input[type=\'password\'], input[type=\'tel\'], input[type=\'number\'], input:not([type])';
|
||||
// unique number as new IDs for input fields
|
||||
|
|
@ -789,11 +788,11 @@ cipFields.setUniqueId = function(field) {
|
|||
cipFields.uniqueNumber += 1;
|
||||
field.attr('data-cip-id', 'jQuery'+String(cipFields.uniqueNumber));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
cipFields.prepareId = function(id) {
|
||||
return id.replace(/[:#.,\[\]\(\)' "]/g, function(m) { return '\\'+m });
|
||||
}
|
||||
return id.replace(/[:#.,\[\]\(\)' "]/g, function(m) { return '\\'+m; });
|
||||
};
|
||||
|
||||
cipFields.getAllFields = function() {
|
||||
let fields = [];
|
||||
|
|
@ -807,7 +806,18 @@ cipFields.getAllFields = function() {
|
|||
});
|
||||
|
||||
return fields;
|
||||
}
|
||||
};
|
||||
|
||||
cipFields.getHiddenFieldCount = function() {
|
||||
let count = 0;
|
||||
jQuery(cipFields.inputQueryPattern).each(function() {
|
||||
if (jQuery(this).is(':hidden')) {
|
||||
count++;
|
||||
}
|
||||
});
|
||||
|
||||
return count;
|
||||
};
|
||||
|
||||
cipFields.prepareVisibleFieldsWithID = function($pattern) {
|
||||
jQuery($pattern).each(function() {
|
||||
|
|
@ -815,7 +825,7 @@ cipFields.prepareVisibleFieldsWithID = function($pattern) {
|
|||
cipFields.setUniqueId(jQuery(this));
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
cipFields.getAllCombinations = function(inputs) {
|
||||
let fields = [];
|
||||
|
|
@ -843,7 +853,7 @@ cipFields.getAllCombinations = function(inputs) {
|
|||
}
|
||||
|
||||
return fields;
|
||||
}
|
||||
};
|
||||
|
||||
cipFields.getCombination = function(givenType, fieldId) {
|
||||
if (cipFields.combinations.length === 0) {
|
||||
|
|
@ -908,7 +918,7 @@ cipFields.getCombination = function(givenType, fieldId) {
|
|||
combination.isNew = true;
|
||||
}
|
||||
return combination;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* return the username field or null if it not exists
|
||||
|
|
@ -969,7 +979,7 @@ cipFields.getUsernameField = function(passwordId, checkDisabled) {
|
|||
|
||||
cipFields.setUniqueId(usernameField);
|
||||
return usernameField;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* return the password field or null if it not exists
|
||||
|
|
@ -1026,7 +1036,7 @@ cipFields.getPasswordField = function(usernameId, checkDisabled) {
|
|||
cipFields.setUniqueId(passwordField);
|
||||
|
||||
return passwordField;
|
||||
}
|
||||
};
|
||||
|
||||
cipFields.prepareCombinations = function(combinations) {
|
||||
for (const c of combinations) {
|
||||
|
|
@ -1049,7 +1059,7 @@ cipFields.prepareCombinations = function(combinations) {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
cipFields.useDefinedCredentialFields = function() {
|
||||
if (cip.settings['defined-credential-fields'] && cip.settings['defined-credential-fields'][document.location.origin]) {
|
||||
|
|
@ -1077,37 +1087,47 @@ cipFields.useDefinedCredentialFields = function() {
|
|||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
var cip = {};
|
||||
|
||||
// settings of keepassxc-browser
|
||||
cip.settings = {};
|
||||
// username field which will be set on focus
|
||||
cip.u = null;
|
||||
// password field which will be set on focus
|
||||
cip.p = null;
|
||||
// document.location
|
||||
cip.url = null;
|
||||
// request-url of the form in which the field is located
|
||||
cip.submitUrl = null;
|
||||
// received credentials from KeePassXC
|
||||
cip.credentials = [];
|
||||
|
||||
jQuery(function() {
|
||||
cip.init();
|
||||
cip.detectNewActiveFields();
|
||||
});
|
||||
|
||||
cip.init = function() {
|
||||
browser.runtime.sendMessage({
|
||||
action: 'get_settings',
|
||||
}, (response) => {
|
||||
}).then((response) => {
|
||||
cip.settings = response.data;
|
||||
cip.initCredentialFields();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
cip.detectNewActiveFields = function() {
|
||||
const hiddenFields = cipFields.getHiddenFieldCount();
|
||||
|
||||
// If hidden fields aren't detected, setInterval is being looped in each frame of the page
|
||||
//if (hiddenFields > 0) {
|
||||
const divDetect = setInterval(function() {
|
||||
const fields = cipFields.getAllFields();
|
||||
console.log(fields.length);
|
||||
if (fields.length > 1) {
|
||||
cip.initCredentialFields(true);
|
||||
clearInterval(divDetect);
|
||||
}
|
||||
}, 1000);
|
||||
//}
|
||||
};
|
||||
|
||||
cip.initCredentialFields = function(forceCall) {
|
||||
if (_called.initCredentialFields && !forceCall) {
|
||||
|
|
@ -1115,33 +1135,35 @@ cip.initCredentialFields = function(forceCall) {
|
|||
}
|
||||
_called.initCredentialFields = true;
|
||||
|
||||
const inputs = cipFields.getAllFields();
|
||||
cipFields.prepareVisibleFieldsWithID('select');
|
||||
cip.initPasswordGenerator(inputs);
|
||||
browser.runtime.sendMessage({ 'action': 'page_clear_logins' }).then(() => {
|
||||
const inputs = cipFields.getAllFields();
|
||||
cipFields.prepareVisibleFieldsWithID('select');
|
||||
cip.initPasswordGenerator(inputs);
|
||||
|
||||
if (!cipFields.useDefinedCredentialFields()) {
|
||||
// get all combinations of username + password fields
|
||||
cipFields.combinations = cipFields.getAllCombinations(inputs);
|
||||
}
|
||||
cipFields.prepareCombinations(cipFields.combinations);
|
||||
if (!cipFields.useDefinedCredentialFields()) {
|
||||
// get all combinations of username + password fields
|
||||
cipFields.combinations = cipFields.getAllCombinations(inputs);
|
||||
}
|
||||
cipFields.prepareCombinations(cipFields.combinations);
|
||||
|
||||
if (cipFields.combinations.length === 0) {
|
||||
browser.runtime.sendMessage({
|
||||
action: 'show_default_browseraction'
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (cipFields.combinations.length === 0) {
|
||||
browser.runtime.sendMessage({
|
||||
action: 'show_default_browseraction'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
cip.url = document.location.origin;
|
||||
cip.submitUrl = cip.getFormActionUrl(cipFields.combinations[0]);
|
||||
cip.url = document.location.origin;
|
||||
cip.submitUrl = cip.getFormActionUrl(cipFields.combinations[0]);
|
||||
|
||||
if (cip.settings.autoRetrieveCredentials) {
|
||||
browser.runtime.sendMessage({
|
||||
action: 'retrieve_credentials',
|
||||
args: [ cip.url, cip.submitUrl ]
|
||||
}, cip.retrieveCredentialsCallback);
|
||||
}
|
||||
} // end function init
|
||||
if (cip.settings.autoRetrieveCredentials) {
|
||||
browser.runtime.sendMessage({
|
||||
action: 'retrieve_credentials',
|
||||
args: [ cip.url, cip.submitUrl ]
|
||||
}).then(cip.retrieveCredentialsCallback);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
cip.initPasswordGenerator = function(inputs) {
|
||||
if (cip.settings.usePasswordGenerator) {
|
||||
|
|
@ -1153,16 +1175,16 @@ cip.initPasswordGenerator = function(inputs) {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
cip.receiveCredentialsIfNecessary = function () {
|
||||
if (cip.credentials.length === 0) {
|
||||
browser.runtime.sendMessage({
|
||||
action: 'retrieve_credentials',
|
||||
args: [ cip.url, cip.submitUrl ]
|
||||
}, cip.retrieveCredentialsCallback);
|
||||
}).then(cip.retrieveCredentialsCallback);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
cip.retrieveCredentialsCallback = function (credentials, dontAutoFillIn) {
|
||||
if (cipFields.combinations.length > 0) {
|
||||
|
|
@ -1174,7 +1196,7 @@ cip.retrieveCredentialsCallback = function (credentials, dontAutoFillIn) {
|
|||
cip.credentials = credentials;
|
||||
cip.prepareFieldsForCredentials(!Boolean(dontAutoFillIn));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
cip.prepareFieldsForCredentials = function(autoFillInForSingle) {
|
||||
// only one login for this site
|
||||
|
|
@ -1211,7 +1233,7 @@ cip.prepareFieldsForCredentials = function(autoFillInForSingle) {
|
|||
else if (cip.credentials.length > 1 || (cip.credentials.length > 0 && (!cip.settings.autoFillSingleEntry || !autoFillInForSingle))) {
|
||||
cip.preparePageForMultipleCredentials(cip.credentials);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
cip.preparePageForMultipleCredentials = function(credentials) {
|
||||
// add usernames + descriptions to autocomplete-list and popup-list
|
||||
|
|
@ -1243,7 +1265,7 @@ cip.preparePageForMultipleCredentials = function(credentials) {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
cip.getFormActionUrl = function(combination) {
|
||||
const field = _f(combination.password) || _f(combination.username);
|
||||
|
|
@ -1264,7 +1286,7 @@ cip.getFormActionUrl = function(combination) {
|
|||
}
|
||||
|
||||
return action;
|
||||
}
|
||||
};
|
||||
|
||||
cip.fillInCredentials = function(combination, onlyPassword, suppressWarnings) {
|
||||
const action = cip.getFormActionUrl(combination);
|
||||
|
|
@ -1301,12 +1323,12 @@ cip.fillInCredentials = function(combination, onlyPassword, suppressWarnings) {
|
|||
browser.runtime.sendMessage({
|
||||
action: 'retrieve_credentials',
|
||||
args: [ cip.url, cip.submitUrl, false, true ]
|
||||
}, (credentials) => {
|
||||
}).then((credentials) => {
|
||||
cip.retrieveCredentialsCallback(credentials, true);
|
||||
cip.fillIn(combination, onlyPassword, suppressWarnings);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
cip.fillInFromActiveElement = function(suppressWarnings) {
|
||||
const el = document.activeElement;
|
||||
|
|
@ -1329,7 +1351,7 @@ cip.fillInFromActiveElement = function(suppressWarnings) {
|
|||
delete combination.loginId;
|
||||
|
||||
cip.fillInCredentials(combination, false, suppressWarnings);
|
||||
}
|
||||
};
|
||||
|
||||
cip.fillInFromActiveElementPassOnly = function(suppressWarnings) {
|
||||
const el = document.activeElement;
|
||||
|
|
@ -1362,7 +1384,7 @@ cip.fillInFromActiveElementPassOnly = function(suppressWarnings) {
|
|||
delete combination.loginId;
|
||||
|
||||
cip.fillInCredentials(combination, true, suppressWarnings);
|
||||
}
|
||||
};
|
||||
|
||||
cip.setValue = function(field, value) {
|
||||
if (field.is('select')) {
|
||||
|
|
@ -1378,7 +1400,7 @@ cip.setValue = function(field, value) {
|
|||
cip.setValueWithChange(field, value);
|
||||
field.trigger('input');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
cip.fillInStringFields = function(fields, StringFields, filledInFields) {
|
||||
let $filledIn = false;
|
||||
|
|
@ -1397,7 +1419,7 @@ cip.fillInStringFields = function(fields, StringFields, filledInFields) {
|
|||
}
|
||||
|
||||
return $filledIn;
|
||||
}
|
||||
};
|
||||
|
||||
cip.setValueWithChange = function(field, value) {
|
||||
|
||||
|
|
@ -1414,7 +1436,7 @@ cip.setValueWithChange = function(field, value) {
|
|||
field.val(value);
|
||||
field[0].dispatchEvent(new Event('input', {'bubbles': true}));
|
||||
field[0].dispatchEvent(new Event('change', {'bubbles': true}));
|
||||
}
|
||||
};
|
||||
|
||||
cip.fillIn = function(combination, onlyPassword, suppressWarnings) {
|
||||
// no credentials available
|
||||
|
|
@ -1565,7 +1587,7 @@ cip.fillIn = function(combination, onlyPassword, suppressWarnings) {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
cip.contextMenuRememberCredentials = function() {
|
||||
const el = document.activeElement;
|
||||
|
|
@ -1680,7 +1702,7 @@ cipEvents.clearCredentials = function() {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
cipEvents.triggerActivatedTab = function() {
|
||||
// doesn't run a second time because of _called.initCredentialFields set to true
|
||||
|
|
@ -1692,6 +1714,6 @@ cipEvents.triggerActivatedTab = function() {
|
|||
browser.runtime.sendMessage({
|
||||
action: 'retrieve_credentials',
|
||||
args: [ cip.url, cip.submitUrl ]
|
||||
}, cip.retrieveCredentialsCallback);
|
||||
}).then(cip.retrieveCredentialsCallback);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"manifest_version": 2,
|
||||
"name": "keepassxc-browser",
|
||||
"version": "0.2.9",
|
||||
"version": "0.3.0",
|
||||
"description": "KeePassXC integration for modern web browsers",
|
||||
"author": "Sami Vänttinen",
|
||||
"icons": {
|
||||
|
|
@ -24,6 +24,7 @@
|
|||
},
|
||||
"background": {
|
||||
"scripts": [
|
||||
"browser-polyfill.min.js",
|
||||
"global.js",
|
||||
"background/nacl.min.js",
|
||||
"background/nacl-util.min.js",
|
||||
|
|
@ -38,10 +39,10 @@
|
|||
"content_scripts": [
|
||||
{
|
||||
"matches": [
|
||||
"http://*/*",
|
||||
"https://*/*"
|
||||
"<all_urls>"
|
||||
],
|
||||
"js": [
|
||||
"browser-polyfill.min.js",
|
||||
"global.js",
|
||||
"jquery-3.2.1.min.js",
|
||||
"jquery-ui.min.js",
|
||||
|
|
@ -75,9 +76,11 @@
|
|||
"icons/key.png"
|
||||
],
|
||||
"permissions": [
|
||||
"activeTab",
|
||||
"contextMenus",
|
||||
"clipboardWrite",
|
||||
"nativeMessaging",
|
||||
"storage",
|
||||
"tabs",
|
||||
"webRequest",
|
||||
"webRequestBlocking",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
<meta charset="UTF-8">
|
||||
<link rel="stylesheet" href="bootstrap.min.css" />
|
||||
<link rel="stylesheet" href="options.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.2.1.min.js"></script>
|
||||
<script type="text/javascript" src="bootstrap.min.js"></script>
|
||||
|
|
@ -307,7 +308,7 @@
|
|||
</div>
|
||||
<hr>
|
||||
<div class="footer">
|
||||
<p>2010-2017 - Perry Nguyen, Lukas Schulze, Sami Vänttinen</p>
|
||||
<p>2010-2017 - Perry Nguyen, Lukas Schulze, Angus Gratton, Andy Brandt, Sami Vänttinen</p>
|
||||
</div>
|
||||
</div> <!-- /container -->
|
||||
</body>
|
||||
|
|
|
|||
|
|
@ -25,19 +25,33 @@ options.initMenu = function() {
|
|||
});
|
||||
|
||||
$('div.tab:first').show();
|
||||
}
|
||||
};
|
||||
|
||||
options.saveSetting = function(name) {
|
||||
const $id = '#' + name;
|
||||
$($id).closest('.control-group').removeClass('error').addClass('success');
|
||||
setTimeout(() => { $($id).closest('.control-group').removeClass('success') }, 2500);
|
||||
setTimeout(() => { $($id).closest('.control-group').removeClass('success'); }, 2500);
|
||||
|
||||
localStorage.settings = JSON.stringify(options.settings);
|
||||
|
||||
browser.runtime.sendMessage({
|
||||
action: 'load_settings'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
options.saveSettings = function() {
|
||||
localStorage.settings = JSON.stringify(options.settings);
|
||||
browser.runtime.sendMessage({
|
||||
action: 'load_settings'
|
||||
});
|
||||
};
|
||||
|
||||
options.saveKeyRing = function() {
|
||||
localStorage.keyRing = JSON.stringify(options.keyRing);
|
||||
browser.runtime.sendMessage({
|
||||
action: 'load_keyring'
|
||||
});
|
||||
};
|
||||
|
||||
options.initGeneralSettings = function() {
|
||||
$('#tab-general-settings input[type=checkbox]').each(function() {
|
||||
|
|
@ -46,38 +60,30 @@ options.initGeneralSettings = function() {
|
|||
|
||||
$('#tab-general-settings input[type=checkbox]').change(function() {
|
||||
options.settings[$(this).attr('name')] = $(this).is(':checked');
|
||||
localStorage.settings = JSON.stringify(options.settings);
|
||||
|
||||
browser.runtime.sendMessage({
|
||||
action: 'load_settings'
|
||||
});
|
||||
options.saveSettings();
|
||||
});
|
||||
|
||||
$('#tab-general-settings input[type=radio]').each(function() {
|
||||
if($(this).val() === options.settings[$(this).attr('name')]) {
|
||||
if ($(this).val() === options.settings[$(this).attr('name')]) {
|
||||
$(this).attr('checked', options.settings[$(this).attr('name')]);
|
||||
}
|
||||
});
|
||||
|
||||
$('#tab-general-settings input[type=radio]').change(function() {
|
||||
options.settings[$(this).attr('name')] = $(this).val();
|
||||
localStorage.settings = JSON.stringify(options.settings);
|
||||
|
||||
browser.runtime.sendMessage({
|
||||
action: 'load_settings'
|
||||
});
|
||||
options.saveSettings();
|
||||
});
|
||||
|
||||
browser.runtime.sendMessage({
|
||||
action: 'get_keepassxc_versions'
|
||||
}, options.showKeePassXCVersions);
|
||||
}).then(options.showKeePassXCVersions);
|
||||
|
||||
$('#tab-general-settings button.checkUpdateKeePassXC:first').click(function(e) {
|
||||
e.preventDefault();
|
||||
$(this).attr('disabled', true);
|
||||
browser.runtime.sendMessage({
|
||||
action: 'check_update_keepassxc'
|
||||
}, options.showKeePassXCVersions);
|
||||
}).then(options.showKeePassXCVersions);
|
||||
});
|
||||
|
||||
$('#port').val(options.settings['port']);
|
||||
|
|
@ -134,7 +140,7 @@ options.showKeePassXCVersions = function(response) {
|
|||
$('#tab-general-settings .kphVersion:first em.latestVersion:first').text(response.latest);
|
||||
$('#tab-about em.versionKPH').text(response.current);
|
||||
$('#tab-general-settings button.checkUpdateKeePassXC:first').attr('disabled', false);
|
||||
}
|
||||
};
|
||||
|
||||
options.initConnectedDatabases = function() {
|
||||
$('#dialogDeleteConnectedDatabase').modal({keyboard: true, show: false, backdrop: true});
|
||||
|
|
@ -152,11 +158,7 @@ options.initConnectedDatabases = function() {
|
|||
$('#tab-connected-databases #tr-cd-' + $hash).remove();
|
||||
|
||||
delete options.keyRing[$hash];
|
||||
localStorage.keyRing = JSON.stringify(options.keyRing);
|
||||
|
||||
browser.runtime.sendMessage({
|
||||
action: 'load_keyring'
|
||||
});
|
||||
options.saveKeyRing();
|
||||
|
||||
if ($('#tab-connected-databases table tbody:first tr').length > 2) {
|
||||
$('#tab-connected-databases table tbody:first tr.empty:first').hide();
|
||||
|
|
@ -198,7 +200,7 @@ options.initConnectedDatabases = function() {
|
|||
action: 'associate'
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
options.initSpecifiedCredentialFields = function() {
|
||||
$('#dialogDeleteSpecifiedCredentialFields').modal({keyboard: true, show: false, backdrop: true});
|
||||
|
|
@ -218,13 +220,9 @@ options.initSpecifiedCredentialFields = function() {
|
|||
$('#tab-specified-fields #' + $trId).remove();
|
||||
|
||||
delete options.settings['defined-credential-fields'][$url];
|
||||
localStorage.settings = JSON.stringify(options.settings);
|
||||
options.saveSettings();
|
||||
|
||||
browser.runtime.sendMessage({
|
||||
action: 'load_settings'
|
||||
});
|
||||
|
||||
if($('#tab-specified-fields table tbody:first tr').length > 2) {
|
||||
if ($('#tab-specified-fields table tbody:first tr').length > 2) {
|
||||
$('#tab-specified-fields table tbody:first tr.empty:first').hide();
|
||||
}
|
||||
else {
|
||||
|
|
@ -235,7 +233,7 @@ options.initSpecifiedCredentialFields = function() {
|
|||
const $trClone = $('#tab-specified-fields table tr.clone:first').clone(true);
|
||||
$trClone.removeClass('clone');
|
||||
let counter = 1;
|
||||
for(let url in options.settings['defined-credential-fields']) {
|
||||
for (let url in options.settings['defined-credential-fields']) {
|
||||
const $tr = $trClone.clone(true);
|
||||
$tr.data('url', url);
|
||||
$tr.attr('id', 'tr-scf' + counter);
|
||||
|
|
@ -245,17 +243,17 @@ options.initSpecifiedCredentialFields = function() {
|
|||
$('#tab-specified-fields table tbody:first').append($tr);
|
||||
}
|
||||
|
||||
if($('#tab-specified-fields table tbody:first tr').length > 2) {
|
||||
if ($('#tab-specified-fields table tbody:first tr').length > 2) {
|
||||
$('#tab-specified-fields table tbody:first tr.empty:first').hide();
|
||||
}
|
||||
else {
|
||||
$('#tab-specified-fields table tbody:first tr.empty:first').show();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
options.initAbout = function() {
|
||||
$('#tab-about em.versionCIP').text(browser.runtime.getManifest().version);
|
||||
if (isFirefox) {
|
||||
$('#chrome-only').remove();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
<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.2.1.min.js"></script>
|
||||
<script type="text/javascript" src="../options/bootstrap.min.js" /></script>
|
||||
|
|
|
|||
|
|
@ -53,18 +53,17 @@ $(function() {
|
|||
$('#reload-status-button').click(function() {
|
||||
browser.runtime.sendMessage({
|
||||
action: 'reconnect'
|
||||
}, status_response);
|
||||
}).then(status_response);
|
||||
});
|
||||
|
||||
$('#reopen-database-button').click(function() {
|
||||
browser.runtime.sendMessage({
|
||||
action: 'get_status'
|
||||
}, status_response);
|
||||
close();
|
||||
}).then(status_response);
|
||||
});
|
||||
|
||||
$('#redetect-fields-button').click(function() {
|
||||
browser.tabs.query({"active": true, "currentWindow": true}, (tabs) => {
|
||||
browser.tabs.query({"active": true, "currentWindow": true}).then(function(tabs) {
|
||||
if (tabs.length === 0)
|
||||
return; // For example: only the background devtools or a popup are opened
|
||||
let tab = tabs[0];
|
||||
|
|
@ -76,6 +75,6 @@ $(function() {
|
|||
});
|
||||
|
||||
browser.runtime.sendMessage({
|
||||
action: 'get_status'
|
||||
}, status_response);
|
||||
});
|
||||
action: "get_status"
|
||||
}).then(status_response);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
var $ = jQuery.noConflict(true);
|
||||
var _settings = typeof(localStorage.settings) ==='undefined' ? {} : JSON.parse(localStorage.settings);
|
||||
|
||||
function updateAvailableResponse(available) {
|
||||
if (available) {
|
||||
|
|
@ -12,12 +11,11 @@ function updateAvailableResponse(available) {
|
|||
|
||||
function initSettings() {
|
||||
$ ('#settings #btn-options').click(function() {
|
||||
browser.runtime.openOptionsPage();
|
||||
close();
|
||||
browser.runtime.openOptionsPage().then(close());
|
||||
});
|
||||
|
||||
$ ('#settings #btn-choose-credential-fields').click(function() {
|
||||
browser.runtime.getBackgroundPage((global) => {
|
||||
browser.runtime.getBackgroundPage().then((global) => {
|
||||
browser.tabs.sendMessage(global.page.currentTabId, {
|
||||
action: 'choose_credential_fields'
|
||||
});
|
||||
|
|
@ -32,5 +30,5 @@ $(function() {
|
|||
|
||||
browser.runtime.sendMessage({
|
||||
action: 'update_available_keepassxc'
|
||||
}, updateAvailableResponse);
|
||||
}).then(updateAvailableResponse);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
<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.2.1.min.js"></script>
|
||||
<script type="text/javascript" src="../options/bootstrap.min.js" /></script>
|
||||
|
|
@ -12,8 +13,8 @@
|
|||
</head>
|
||||
<body>
|
||||
<div id="settings" class="settings">
|
||||
<button id="btn-options" class="btn btn-sm btn-warning">Settings</button>
|
||||
<button id="btn-choose-credential-fields" class="btn btn-sm">Choose own credential fields for this page</button>
|
||||
<button id="btn-options" class="btn btn-sm btn-success">Settings</button>
|
||||
<button id="btn-choose-credential-fields" class="btn btn-sm btn-default">Choose own credential fields for this page</button>
|
||||
|
||||
<div id="update-available">
|
||||
You use an old version of KeePassXC.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
$(function() {
|
||||
browser.runtime.getBackgroundPage(function(global) {
|
||||
browser.tabs.query({"active": true, "currentWindow": true}, (tab) => {
|
||||
browser.runtime.getBackgroundPage().then((global) => {
|
||||
browser.tabs.query({"active": true, "currentWindow": true}).then((tab) => {
|
||||
const data = global.page.tabs[tab.id].loginList;
|
||||
let ul = document.getElementById('login-list');
|
||||
for (let i = 0; i < data.logins.length; i++) {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
<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.2.1.min.js"></script>
|
||||
<script type="text/javascript" src="../options/bootstrap.min.js" /></script>
|
||||
|
|
@ -12,8 +13,8 @@
|
|||
</head>
|
||||
<body>
|
||||
<div id="settings" class="settings">
|
||||
<button id="btn-options" class="btn btn-sm btn-warning">Settings</button>
|
||||
<button id="btn-choose-credential-fields" class="btn btn-sm">Choose own credential fields for this page</button>
|
||||
<button id="btn-options" class="btn btn-sm btn-success">Settings</button>
|
||||
<button id="btn-choose-credential-fields" class="btn btn-sm btn-default">Choose own credential fields for this page</button>
|
||||
|
||||
<div id="update-available">
|
||||
You use an old version of KeePassXC.
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
$(function() {
|
||||
browser.runtime.getBackgroundPage(function(global) {
|
||||
browser.tabs.query({"active": true, "currentWindow": true}, (tabs) => {
|
||||
if (tabs.length === 0)
|
||||
browser.runtime.getBackgroundPage().then((global) => {
|
||||
browser.tabs.query({"active": true, "currentWindow": true}).then((tabs) => {
|
||||
if (tabs.length === 0) {
|
||||
return; // For example: only the background devtools or a popup are opened
|
||||
}
|
||||
const tab = tabs[0];
|
||||
|
||||
const logins = global.page.tabs[tab.id].loginList;
|
||||
|
|
@ -14,7 +15,7 @@ $(function() {
|
|||
li.appendChild(a);
|
||||
a.setAttribute('id', '' + i);
|
||||
a.addEventListener('click', (e) => {
|
||||
var id = e.target.id;
|
||||
const id = e.target.id;
|
||||
browser.tabs.sendMessage(tab.id, {
|
||||
action: 'fill_user_pass_with_specific_login',
|
||||
id: id
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
<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.2.1.min.js"></script>
|
||||
<script type="text/javascript" src="../options/bootstrap.min.js" /></script>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
<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.2.1.min.js"></script>
|
||||
<script type="text/javascript" src="../options/bootstrap.min.js" /></script>
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ function _initialize(tab) {
|
|||
browser.runtime.sendMessage({
|
||||
action: 'add_credentials',
|
||||
args: [_tab.credentials.username, _tab.credentials.password, _tab.credentials.url]
|
||||
}, _verifyResult);
|
||||
}).then(_verifyResult);
|
||||
});
|
||||
|
||||
$('#btn-update').click(function(e) {
|
||||
|
|
@ -34,7 +34,7 @@ function _initialize(tab) {
|
|||
browser.runtime.sendMessage({
|
||||
action: 'update_credentials',
|
||||
args: [_tab.credentials.list[0].uuid, _tab.credentials.username, _tab.credentials.password, _tab.credentials.url]
|
||||
}, _verifyResult);
|
||||
}).then(_verifyResult);
|
||||
}
|
||||
else {
|
||||
$('.credentials:first .username-new:first strong:first').text(_tab.credentials.username);
|
||||
|
|
@ -59,7 +59,7 @@ function _initialize(tab) {
|
|||
browser.runtime.sendMessage({
|
||||
action: 'update_credentials',
|
||||
args: [_tab.credentials.list[$(this).data('entryId')].uuid, _tab.credentials.username, _tab.credentials.password, _tab.credentials.url]
|
||||
}, _verifyResult);
|
||||
}).then(_verifyResult);
|
||||
});
|
||||
|
||||
if (_tab.credentials.usernameExists && _tab.credentials.username === _tab.credentials.list[i].login) {
|
||||
|
|
@ -116,9 +116,9 @@ $(function() {
|
|||
|
||||
browser.runtime.sendMessage({
|
||||
action: 'get_tab_information'
|
||||
}, _initialize);
|
||||
}).then(_initialize);
|
||||
|
||||
browser.runtime.sendMessage({
|
||||
action: 'get_connected_database'
|
||||
}, _connected_database);
|
||||
}).then(_connected_database);
|
||||
});
|
||||
Loading…
Reference in a new issue