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
103e8091e5
18 changed files with 127 additions and 313 deletions
|
|
@ -1,3 +1,9 @@
|
|||
0.4.4 (17-12-2017)
|
||||
=========================
|
||||
- Added support for OTP codes via context menu
|
||||
- Fixed HTTP auth
|
||||
- General content script code cleaning
|
||||
|
||||
0.4.3 (9-12-2017)
|
||||
=========================
|
||||
- Create password generator dialog only when clicking the icon
|
||||
|
|
|
|||
19
README.md
19
README.md
|
|
@ -7,35 +7,34 @@ For testing purposes, please use only the following unofficial KeePassXC [releas
|
|||
|
||||
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).
|
||||
|
||||
The extension is supported with Firefox 55 and newer. If you want to load it as a temporary plugin with Firefox 54 or ESR you can just change the minimum version from the manifest file before loading it.
|
||||
|
||||
Please thee this [wiki page](hhttps://github.com/varjolintu/keepassxc-browser/wiki/Connecting-the-database-with-keepassxc-browser) for instructions how to configure this KeePassXC fork in order to connect the database correctly.
|
||||
|
||||
## How it works
|
||||
There are two methods which you can use keepassxc-browser to connect to KeePassXC:
|
||||
|
||||
1. keepassxc-browser communicates directly with KeePassXC via stdin/stdout. This method launches KeePassXC every time you start the browser and closes when you exit.
|
||||
This can cause unsaved changes not to be saved. If you use this method it's important to enable `Automatically save after every change` from KeePassXC's preferences.
|
||||
|
||||
2. keepassxc-browser communicated with KeePassXC through keepassxc-proxy. The proxy handles listening stdin/stdout
|
||||
1. keepassxc-browser communicated with KeePassXC through keepassxc-proxy. The proxy handles listening stdin/stdout
|
||||
and transfers these messages through Unix domain sockets / named pipes to KeePassXC. This means KeePassXC can be used and started normally without inteference from
|
||||
Native Messaging API. keepassxc-browser starts only the proxy application and there's no risk of shutting down KeePassXC or losing any unsaved changes. You don't need to install keepassxc-proxy separately. It is included in the latest KeePassXC fork. Use it if you want to make your own proxy or improve/extend it. Alternatively you can use
|
||||
[keepassxc-proxy-rust](https://github.com/varjolintu/keepassxc-proxy-rust) as a proxy if you prefer a non-Qt solution. There's also Python and C++ versions available at
|
||||
Native Messaging API. keepassxc-browser starts only the proxy application and there's no risk of shutting down KeePassXC or losing any unsaved changes. You don't need to install keepassxc-proxy separately. It is included in the latest KeePassXC fork. Alternatively you can use
|
||||
[keepassxc-proxy-rust](https://github.com/varjolintu/keepassxc-proxy-rust) as a proxy if you prefer a non-Qt solution. There's also Python and C++ versions available at
|
||||
[keepassxc-proxy](https://github.com/varjolintu/keepassxc-proxy).
|
||||
|
||||
2. keepassxc-browser communicates directly with KeePassXC via stdin/stdout. Using native messaging directly is a more secure as it ensures the traffic between KeePassXC and keepassxc-browser is direct. This method launches KeePassXC every time you start the browser and closes when you exit.
|
||||
This can cause unsaved changes not to be saved. If you use this method it's important to enable `Automatically save after every change` from KeePassXC's preferences. Because this option is not preferred as default it's good to test this feature with your OS and ensure KeePassXC asks to confirm any unsaved changes before exit.
|
||||
|
||||
## Improvements
|
||||
The following improvements and features have been made after the fork. At this point some features are only available with the KeePassXC fork:
|
||||
- Real-time detection of database status (locked/unlocked)
|
||||
- Credentials on a page are cleared or received automatically again if database is locked or changed to another
|
||||
- It is possible to lock the active database from the popup (using the red lock icon)
|
||||
- Input forms are detected even if the login div has been hidden or is created after the page was loaded
|
||||
- It is possible to use the active database from multiple browsers at the same time with [keepassxc-proxy](https://github.com/varjolintu/keepassxc-proxy) application.
|
||||
- It is possible to use the active database from multiple browsers at the same time with keepassxc-proxy option
|
||||
- Deprecated JavaScript functions are removed and everything is asynchronous
|
||||
- Updated Bootstrap to version 3.3.7 and jQuery to version 3.2.1
|
||||
- New buttons, icons and settings page graphics
|
||||
- Redesigned password generator dialog
|
||||
- Password generator supports diceware passphrases and extended ASCII characters
|
||||
- Autocomplete works also when only password fields are visible
|
||||
- Supports TOTP with custom KHP placeholders (`KPH: {TOPT}`)
|
||||
|
||||
## Protocol
|
||||
|
||||
|
|
@ -79,4 +78,4 @@ Feel free to support this project:
|
|||
- Donate via [PayPal](https://paypal.me/varjolintu)
|
||||
- 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/pfn/passifox). They are doing great job.
|
||||
Also consider donating to [KeePassXC](https://flattr.com/submit/auto?fid=x7yqz0&url=https%3A%2F%2Fkeepassxc.org) and [KeePassHttp-Connector](https://github.com/smorks/keepasshttp-connector) teams. They are doing great job.
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
{
|
||||
"name": "com.varjolintu.keepassxc_browser",
|
||||
"description": "KeepassXC integration with Chrome with Native Messaging support",
|
||||
"path" : "keepassxc-proxy.bat",
|
||||
"type": "stdio",
|
||||
"allowed_origins": [
|
||||
"chrome-extension://iopaggbpplllidnfmcghoonnokmjoicf/",
|
||||
"chrome-extension://fhakpkpdnjecjfceboihdjpfmgajebii/",
|
||||
"chrome-extension://jaikbblhommnkeialomogohhdlndpfbi/"
|
||||
]
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
{
|
||||
"name": "com.varjolintu.keepassxc_browser",
|
||||
"description": "KeepassXC integration with Chrome with Native Messaging support",
|
||||
"path" : "%%replace%%",
|
||||
"type": "stdio",
|
||||
"allowed_origins": [
|
||||
"chrome-extension://iopaggbpplllidnfmcghoonnokmjoicf/",
|
||||
"chrome-extension://fhakpkpdnjecjfceboihdjpfmgajebii/",
|
||||
"chrome-extension://jaikbblhommnkeialomogohhdlndpfbi/"
|
||||
]
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
{
|
||||
"name": "com.varjolintu.keepassxc_browser",
|
||||
"description": "KeepassXC integration with Firefox with Native Messaging support",
|
||||
"path" : "keepassxc-proxy.bat",
|
||||
"type": "stdio",
|
||||
"allowed_extensions": [
|
||||
"keepassxc-browser@sami.vanttinen"
|
||||
]
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
{
|
||||
"name": "com.varjolintu.keepassxc_browser",
|
||||
"description": "KeepassXC integration with Firefox with Native Messaging support",
|
||||
"path" : "%%replace%%",
|
||||
"type": "stdio",
|
||||
"allowed_extensions": [
|
||||
"keepassxc-browser@sami.vanttinen"
|
||||
]
|
||||
}
|
||||
34
install.bat
34
install.bat
|
|
@ -1,34 +0,0 @@
|
|||
:: Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
:: Copyright 2017 Sami Vänttinen <sami.vanttinen@protonmail.com>
|
||||
:: Use of this source code is governed by a BSD-style license that can be
|
||||
:: found in the LICENSE file.
|
||||
:: Change HKCU to HKLM if you want to install globally.
|
||||
:: %~dp0 is the directory containing this bat script and ends with a backslash.
|
||||
@echo off
|
||||
echo.
|
||||
echo Select your browser:
|
||||
echo ====================
|
||||
echo 1) Chrome
|
||||
echo 2) Chromium
|
||||
echo 3) Firefox
|
||||
echo 4) Vivaldi
|
||||
set choice=
|
||||
set /p choice=1-4:
|
||||
if '%choice%'=='1' goto chrome
|
||||
if '%choice%'=='2' goto chromium
|
||||
if '%choice%'=='3' goto firefox
|
||||
if '%choice%'=='3' goto vivaldi
|
||||
goto end
|
||||
:chrome
|
||||
REG ADD "HKCU\Software\Google\Chrome\NativeMessagingHosts\com.varjolintu.keepassxc_browser" /ve /t REG_SZ /d "%~dp0com.varjolintu.keepassxc-browser-chrome.win.json" /f
|
||||
goto end
|
||||
:chromium
|
||||
REG ADD "HKCU\Software\Chromium\NativeMessagingHosts\com.varjolintu.keepassxc_browser" /ve /t REG_SZ /d "%~dp0com.varjolintu.keepassxc-browser-chrome.win.json" /f
|
||||
goto end
|
||||
:firefox
|
||||
REG ADD "HKCU\Software\Mozilla\NativeMessagingHosts\com.varjolintu.keepassxc_browser" /ve /t REG_SZ /d "%~dp0com.varjolintu.keepassxc-browser-firefox.win.json" /f
|
||||
goto end
|
||||
:vivaldi
|
||||
REG ADD "HKCU\Software\Vivaldi\NativeMessagingHosts\com.varjolintu.keepassxc_browser" /ve /t REG_SZ /d "%~dp0com.varjolintu.keepassxc-browser-chrome.win.json" /f
|
||||
goto end
|
||||
:end
|
||||
141
install.sh
141
install.sh
|
|
@ -1,141 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# The MIT License (MIT)
|
||||
# Copyright (c) 2016 Danny van Kooten
|
||||
# Modifications (c) 2017 Sami Vänttinen
|
||||
|
||||
# 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.
|
||||
|
||||
set -e
|
||||
|
||||
DIR="$( cd "$( dirname "$0" )" && pwd )"
|
||||
APP_NAME="com.varjolintu.keepassxc_browser"
|
||||
HOST_FILE="$DIR"
|
||||
KEEPASSXC_PATH=""
|
||||
|
||||
# Find target dirs for various browsers & OS'es
|
||||
# https://developer.chrome.com/extensions/nativeMessaging#native-messaging-host-location
|
||||
# https://wiki.mozilla.org/WebExtensions/Native_Messaging
|
||||
if [ $(uname -s) == 'Darwin' ]; then
|
||||
if [ "$(whoami)" == "root" ]; then
|
||||
TARGET_DIR_CHROME="/Library/Google/Chrome/NativeMessagingHosts"
|
||||
TARGET_DIR_CHROMIUM="/Library/Application Support/Chromium/NativeMessagingHosts"
|
||||
TARGET_DIR_FIREFOX="/Library/Application Support/Mozilla/NativeMessagingHosts"
|
||||
TARGET_DIR_VIVALDI="/Library/Application Support/Vivaldi/NativeMessagingHosts"
|
||||
else
|
||||
TARGET_DIR_CHROME="$HOME/Library/Application Support/Google/Chrome/NativeMessagingHosts"
|
||||
TARGET_DIR_CHROMIUM="$HOME/Library/Application Support/Chromium/NativeMessagingHosts"
|
||||
TARGET_DIR_FIREFOX="$HOME/Library/Application Support/Mozilla/NativeMessagingHosts"
|
||||
TARGET_DIR_VIVALDI="$HOME/Library/Application Support/Vivaldi/NativeMessagingHosts"
|
||||
fi
|
||||
else
|
||||
if [ "$(whoami)" == "root" ]; then
|
||||
TARGET_DIR_CHROME="/etc/opt/chrome/native-messaging-hosts"
|
||||
TARGET_DIR_CHROMIUM="/etc/chromium/native-messaging-hosts"
|
||||
TARGET_DIR_FIREFOX="/usr/lib/mozilla/native-messaging-hosts"
|
||||
TARGET_DIR_VIVALDI="/etc/chromium/native-messaging-hosts"
|
||||
else
|
||||
TARGET_DIR_CHROME="$HOME/.config/google-chrome/NativeMessagingHosts"
|
||||
TARGET_DIR_CHROMIUM="$HOME/.config/chromium/NativeMessagingHosts"
|
||||
TARGET_DIR_FIREFOX="$HOME/.mozilla/native-messaging-hosts"
|
||||
TARGET_DIR_VIVALDI="$HOME/.config/vivaldi/NativeMessagingHosts"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -e "$DIR/keepassxc-browser" ]; then
|
||||
echo "Detected development binary"
|
||||
HOST_FILE="$DIR/keepassxc-browser"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Select your browser:"
|
||||
echo "===================="
|
||||
echo "1) Chrome"
|
||||
echo "2) Chromium"
|
||||
echo "3) Firefox"
|
||||
echo "4) Vivaldi"
|
||||
echo -n "1-4: "
|
||||
read BROWSER
|
||||
echo ""
|
||||
|
||||
# Set target dir from user input
|
||||
if [[ "$BROWSER" == "1" ]]; then
|
||||
BROWSER_NAME="Chrome"
|
||||
TARGET_DIR="$TARGET_DIR_CHROME"
|
||||
fi
|
||||
|
||||
if [[ "$BROWSER" == "2" ]]; then
|
||||
BROWSER_NAME="Chromium"
|
||||
TARGET_DIR="$TARGET_DIR_CHROMIUM"
|
||||
fi
|
||||
|
||||
if [[ "$BROWSER" == "3" ]]; then
|
||||
BROWSER_NAME="Firefox"
|
||||
TARGET_DIR="$TARGET_DIR_FIREFOX"
|
||||
fi
|
||||
|
||||
if [[ "$BROWSER" == "4" ]]; then
|
||||
BROWSER_NAME="Vivaldi"
|
||||
TARGET_DIR="$TARGET_DIR_VIVALDI"
|
||||
fi
|
||||
|
||||
# Try to find the KeePassXC binary.
|
||||
if [ $(uname -s) == 'Darwin' ]; then
|
||||
KEEPASSXC_PATH="/Applications/KeePassXC.app"
|
||||
else
|
||||
KEEPASSXC_PATH="$(command -v keepassxc)"
|
||||
if [ -z "$KEEPASSXC_PATH" ] ; then
|
||||
echo ""
|
||||
echo -n "KeePassXC binary not found. Give the location of KeePassXC binary: "
|
||||
read KEEPASSXC_PATH
|
||||
echo ""
|
||||
fi
|
||||
fi
|
||||
echo "KeePassXC binary location set to $KEEPASSXC_PATH"
|
||||
echo "Installing $BROWSER_NAME host config with path $KEEPASSXC_PATH"
|
||||
echo "Press (ENTER) or give a new path to binary if it's not correct: "
|
||||
read NEW_PATH
|
||||
|
||||
if [ "$NEW_PATH" ]; then
|
||||
KEEPASSXC_PATH="$NEW_PATH"
|
||||
echo "New path set to: $KEEPASSXC_PATH"
|
||||
fi
|
||||
|
||||
# Add /Contents/MacOS/KeePassXC to darwin for exact binary path
|
||||
if [ $(uname -s) == 'Darwin' ]; then
|
||||
KEEPASSXC_PATH="$KEEPASSXC_PATH/Contents/MacOS/KeePassXC"
|
||||
fi
|
||||
|
||||
ESCAPED_PATH=${KEEPASSXC_PATH////\\/}
|
||||
|
||||
# Create config dir if not existing
|
||||
mkdir -p "$TARGET_DIR"
|
||||
|
||||
# Copy manifest host config file
|
||||
if [ "$BROWSER" == "1" ] || [ "$BROWSER" == "2" ] || [ "$BROWSER" == "4" ]; then
|
||||
cp "$DIR/com.varjolintu.keepassxc-browser-chrome.json" "$TARGET_DIR/$APP_NAME.json"
|
||||
else
|
||||
cp "$DIR/com.varjolintu.keepassxc-browser-firefox.json" "$TARGET_DIR//$APP_NAME.json"
|
||||
fi
|
||||
|
||||
# Replace path to host
|
||||
if [ $(uname -s) == 'Darwin' ]; then
|
||||
sed -i "" -e "s/%%replace%%/$ESCAPED_PATH/g" "$TARGET_DIR/$APP_NAME.json"
|
||||
else
|
||||
sed -i -e "s/%%replace%%/$ESCAPED_PATH/g" "$TARGET_DIR/$APP_NAME.json"
|
||||
fi
|
||||
|
||||
# Set permissions for the manifest so that all users can read it.
|
||||
chmod o+r "$TARGET_DIR/$APP_NAME.json"
|
||||
|
||||
echo "Native messaging host for $BROWSER_NAME has been installed to $TARGET_DIR."
|
||||
|
|
@ -100,8 +100,8 @@ kpxcEvent.showStatus = function(configured, tab, callback) {
|
|||
};
|
||||
|
||||
kpxcEvent.onLoadSettings = function(callback, tab) {
|
||||
browser.storage.local.get({'settings': {}}).then((item) => {
|
||||
callback(item.settings);
|
||||
page.initSettings().then((settings) => {
|
||||
callback(settings);
|
||||
}, (err) => {
|
||||
console.log('error loading settings: ' + err);
|
||||
});
|
||||
|
|
@ -230,6 +230,11 @@ kpxcEvent.onLoginPopup = function(callback, tab, logins) {
|
|||
browserAction.show(null, tab);
|
||||
};
|
||||
|
||||
kpxcEvent.initHttpAuth = function(callback) {
|
||||
httpAuth.init();
|
||||
callback();
|
||||
}
|
||||
|
||||
kpxcEvent.onHTTPAuthPopup = function(callback, tab, data) {
|
||||
let stackData = {
|
||||
level: 1,
|
||||
|
|
@ -274,6 +279,7 @@ kpxcEvent.messageHandlers = {
|
|||
'get_keepassxc_versions': kpxcEvent.onGetKeePassXCVersions,
|
||||
'get_status': kpxcEvent.onGetStatus,
|
||||
'get_tab_information': kpxcEvent.onGetTabInformation,
|
||||
'init_http_auth': kpxcEvent.initHttpAuth,
|
||||
'load_keyring': kpxcEvent.onLoadKeyRing,
|
||||
'load_settings': kpxcEvent.onLoadSettings,
|
||||
'page_clear_logins': kpxcEvent.pageClearLogins,
|
||||
|
|
|
|||
|
|
@ -3,6 +3,31 @@ const httpAuth = {};
|
|||
httpAuth.requests = [];
|
||||
httpAuth.pendingCallbacks = [];
|
||||
|
||||
httpAuth.init = function() {
|
||||
let handleReq = httpAuth.handleRequestPromise;
|
||||
let reqType = 'blocking';
|
||||
|
||||
if (!isFirefox()) {
|
||||
handleReq = httpAuth.handleRequestCallback;
|
||||
reqType = 'asyncBlocking';
|
||||
}
|
||||
|
||||
if (browser.webRequest.onAuthRequired.hasListener(handleReq)) {
|
||||
browser.webRequest.onAuthRequired.removeListener(handleReq);
|
||||
browser.webRequest.onCompleted.removeListener(httpAuth.requestCompleted);
|
||||
browser.webRequest.onErrorOccurred.removeListener(httpAuth.requestCompleted);
|
||||
}
|
||||
|
||||
// only intercept http auth requests if the option is turned on.
|
||||
if (page.settings.autoFillAndSend) {
|
||||
const opts = { urls: ['<all_urls>'] };
|
||||
|
||||
browser.webRequest.onAuthRequired.addListener(handleReq, opts, [reqType]);
|
||||
browser.webRequest.onCompleted.addListener(httpAuth.requestCompleted, opts);
|
||||
browser.webRequest.onErrorOccurred.addListener(httpAuth.requestCompleted, opts);
|
||||
}
|
||||
};
|
||||
|
||||
httpAuth.requestCompleted = function(details) {
|
||||
let index = httpAuth.requests.indexOf(details.requestId);
|
||||
if (index >= 0) {
|
||||
|
|
@ -41,8 +66,8 @@ httpAuth.processPendingCallbacks = function(details, resolve, reject) {
|
|||
|
||||
httpAuth.loginOrShowCredentials = function(logins, details, resolve, reject) {
|
||||
// at least one login found --> use first to login
|
||||
if (logins.length > 0) {
|
||||
if (logins.length == 1 && page.settings.autoFillAndSend) {
|
||||
if (logins.length > 0 && page.settings.autoFillAndSend) {
|
||||
if (logins.length === 1) {
|
||||
resolve({
|
||||
authCredentials: {
|
||||
username: logins[0].login,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
keepass.migrateKeyRing().then(() => {
|
||||
page.initSettings().then(() => {
|
||||
page.initOpenedTabs().then(() => {
|
||||
httpAuth.init();
|
||||
keepass.connectToNative();
|
||||
keepass.generateNewKeyPair();
|
||||
keepass.changePublicKeys(null).then((pkRes) => {
|
||||
|
|
@ -73,27 +74,12 @@ browser.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
|
|||
}
|
||||
});
|
||||
|
||||
// Retrieve Credentials and try auto-login for HTTPAuth requests
|
||||
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(kpxcEvent.onMessage);
|
||||
|
||||
const contextMenuItems = [
|
||||
{title: 'Fill User + Pass', action: 'fill_user_pass'},
|
||||
{title: 'Fill Pass Only', action: 'fill_pass_only'},
|
||||
{title: 'Fill TOTP', action: 'fill_totp'},
|
||||
{title: 'Show Password Generator Icons', action: 'activate_password_generator'},
|
||||
{title: 'Save credentials', action: 'remember_credentials'}
|
||||
];
|
||||
|
|
|
|||
|
|
@ -131,7 +131,9 @@ keepass.addCredentials = function(callback, tab, 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);
|
||||
page.tabs[tab.id].errorMessage = null;
|
||||
if (tab && page.tabs[tab.id]) {
|
||||
page.tabs[tab.id].errorMessage = null;
|
||||
}
|
||||
|
||||
keepass.testAssociation((response) => {
|
||||
if (!response) {
|
||||
|
|
@ -200,7 +202,9 @@ keepass.retrieveCredentials = function(callback, tab, url, submiturl, forceCallb
|
|||
return;
|
||||
}
|
||||
|
||||
page.tabs[tab.id].errorMessage = null;
|
||||
if (tab && page.tabs[tab.id]) {
|
||||
page.tabs[tab.id].errorMessage = null;
|
||||
}
|
||||
|
||||
if (!keepass.isConnected) {
|
||||
callback([]);
|
||||
|
|
@ -344,7 +348,9 @@ keepass.associate = function(callback, tab) {
|
|||
return;
|
||||
}
|
||||
|
||||
page.tabs[tab.id].errorMessage = null;
|
||||
if (tab && page.tabs[tab.id]) {
|
||||
page.tabs[tab.id].errorMessage = null;
|
||||
}
|
||||
|
||||
const kpAction = kpActions.ASSOCIATE;
|
||||
const key = nacl.util.encodeBase64(keepass.keyPair.publicKey);
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ page.blockedTabs = {};
|
|||
|
||||
page.initSettings = function() {
|
||||
return new Promise((resolve, reject) => {
|
||||
kpxcEvent.onLoadSettings((settings) => {
|
||||
page.settings = settings;
|
||||
browser.storage.local.get({'settings': {}}).then((item) => {
|
||||
page.settings = item.settings;
|
||||
if (!('checkUpdateKeePassXC' in page.settings)) {
|
||||
page.settings.checkUpdateKeePassXC = defaultSettings.checkUpdateKeePassXC;
|
||||
}
|
||||
|
|
@ -35,7 +35,7 @@ page.initSettings = function() {
|
|||
page.settings.autoRetrieveCredentials = defaultSettings.autoRetrieveCredentials;
|
||||
}
|
||||
browser.storage.local.set({'settings': page.settings});
|
||||
resolve();
|
||||
resolve(page.settings);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ browser.runtime.onMessage.addListener(function(req, sender, callback) {
|
|||
combination = cipFields.getCombination('password', cip.p);
|
||||
}
|
||||
|
||||
let list = {};
|
||||
let list = [];
|
||||
if (cip.fillInStringFields(combination.fields, cip.credentials[req.id].stringFields, list)) {
|
||||
cipForm.destroy(false, {'password': list.list[0], 'username': list.list[1]});
|
||||
}
|
||||
|
|
@ -36,7 +36,11 @@ browser.runtime.onMessage.addListener(function(req, sender, callback) {
|
|||
}
|
||||
else if (req.action === 'fill_pass_only') {
|
||||
cip.receiveCredentialsIfNecessary();
|
||||
cip.fillInFromActiveElementPassOnly(false);
|
||||
cip.fillInFromActiveElement(false, true);
|
||||
}
|
||||
else if (req.action === 'fill_totp') {
|
||||
cip.receiveCredentialsIfNecessary();
|
||||
cip.fillInFromActiveElementTOTPOnly(false);
|
||||
}
|
||||
else if (req.action === 'activate_password_generator') {
|
||||
cip.initPasswordGenerator(cipFields.getAllFields());
|
||||
|
|
@ -530,7 +534,7 @@ var cipDefine = {};
|
|||
cipDefine.selection = {
|
||||
username: null,
|
||||
password: null,
|
||||
fields: {}
|
||||
fields: []
|
||||
};
|
||||
cipDefine.eventFieldClick = null;
|
||||
|
||||
|
|
@ -667,7 +671,7 @@ cipDefine.resetSelection = function() {
|
|||
cipDefine.selection = {
|
||||
username: null,
|
||||
password: null,
|
||||
fields: {}
|
||||
fields: []
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -710,10 +714,8 @@ cipDefine.markAllStringFields = function($chooser) {
|
|||
};
|
||||
|
||||
cipDefine.markFields = function ($chooser, $pattern) {
|
||||
//var $found = false;
|
||||
jQuery($pattern).each(function() {
|
||||
if (cipDefine.isFieldSelected(jQuery(this).data('cip-id'))) {
|
||||
//continue
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -727,16 +729,8 @@ cipDefine.markFields = function ($chooser, $pattern) {
|
|||
.click(cipDefine.eventFieldClick)
|
||||
.hover(function() {jQuery(this).addClass('b2c-fixed-hover-field');}, function() {jQuery(this).removeClass('b2c-fixed-hover-field');});
|
||||
$chooser.append($field);
|
||||
//$found = true;
|
||||
}
|
||||
});
|
||||
|
||||
/* skip step if no entry was found
|
||||
if(!$found) {
|
||||
alert('No username field found.\nContinue with choosing a password field.'');
|
||||
jQuery('button#b2c-btn-skip').click();
|
||||
}
|
||||
*/
|
||||
};
|
||||
|
||||
cipDefine.prepareStep1 = function() {
|
||||
|
|
@ -759,14 +753,6 @@ cipDefine.prepareStep2 = function() {
|
|||
};
|
||||
|
||||
cipDefine.prepareStep3 = function() {
|
||||
/* skip step if no entry was found
|
||||
if(!jQuery('div#b2c-cipDefine-fields').data('username') && !jQuery('div#b2c-cipDefine-fields').data('password')) {
|
||||
alert('Neither an username field nor a password field were selected.\nNothing will be changed and chooser will be closed now.'');
|
||||
jQuery('button#b2c-btn-dismiss').click();
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
if (!cipDefine.selection.username && !cipDefine.selection.password) {
|
||||
jQuery('button#b2c-btn-confirm:first').removeClass('b2c-btn-primary').attr('disabled', true);
|
||||
}
|
||||
|
|
@ -1268,7 +1254,7 @@ cip.prepareFieldsForCredentials = function(autoFillInForSingle) {
|
|||
}
|
||||
|
||||
if (combination) {
|
||||
let list = {};
|
||||
let list = [];
|
||||
if (cip.fillInStringFields(combination.fields, cip.credentials[0].stringFields, list)) {
|
||||
cipForm.destroy(false, {'password': list.list[0], 'username': list.list[1]});
|
||||
}
|
||||
|
|
@ -1389,7 +1375,7 @@ cip.fillInCredentials = function(combination, onlyPassword, suppressWarnings) {
|
|||
}
|
||||
};
|
||||
|
||||
cip.fillInFromActiveElement = function(suppressWarnings) {
|
||||
cip.fillInFromActiveElement = function(suppressWarnings, passOnly = false) {
|
||||
const el = document.activeElement;
|
||||
if (el.tagName.toLowerCase() !== 'input') {
|
||||
if (cipFields.combinations.length > 0) {
|
||||
|
|
@ -1407,42 +1393,41 @@ cip.fillInFromActiveElement = function(suppressWarnings) {
|
|||
else {
|
||||
combination = cipFields.getCombination('username', fieldId);
|
||||
}
|
||||
|
||||
if (passOnly) {
|
||||
if (!_f(combination.password)) {
|
||||
const message = 'Unable to find a password field';
|
||||
browser.runtime.sendMessage({
|
||||
action: 'alert',
|
||||
args: [message]
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
delete combination.loginId;
|
||||
|
||||
cip.fillInCredentials(combination, false, suppressWarnings);
|
||||
};
|
||||
|
||||
cip.fillInFromActiveElementPassOnly = function(suppressWarnings) {
|
||||
cip.fillInFromActiveElementTOTPOnly = function(suppressWarnings) {
|
||||
const el = document.activeElement;
|
||||
if (el.tagName.toLowerCase() !== 'input') {
|
||||
if (cipFields.combinations.length > 0) {
|
||||
cip.fillInCredentials(cipFields.combinations[0], false, suppressWarnings);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
cipFields.setUniqueId(jQuery(el));
|
||||
const fieldId = cipFields.prepareId(jQuery(el).attr('data-cip-id'));
|
||||
let combination = null;
|
||||
if (el.type && el.type.toLowerCase() === 'password') {
|
||||
combination = cipFields.getCombination('password', fieldId);
|
||||
}
|
||||
else {
|
||||
combination = cipFields.getCombination('username', fieldId);
|
||||
}
|
||||
|
||||
if (!_f(combination.password)) {
|
||||
const message = 'Unable to find a password field';
|
||||
browser.runtime.sendMessage({
|
||||
action: 'alert',
|
||||
args: [message]
|
||||
});
|
||||
return;
|
||||
|
||||
if (cip.credentials[0]) {
|
||||
const $sf = _fs(fieldId);
|
||||
if (cip.credentials[0].stringFields && cip.credentials[0].stringFields.length > 0) {
|
||||
const sFields = cip.credentials[0].stringFields;
|
||||
for (const s of sFields) {
|
||||
const val = s["KPH: {TOTP}"];
|
||||
if (val) {
|
||||
cip.setValue($sf, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete combination.loginId;
|
||||
|
||||
cip.fillInCredentials(combination, true, suppressWarnings);
|
||||
};
|
||||
|
||||
cip.setValue = function(field, value) {
|
||||
|
|
@ -1469,7 +1454,6 @@ cip.fillInStringFields = function(fields, StringFields, filledInFields) {
|
|||
for (let i = 0; i < fields.length; i++) {
|
||||
const $sf = _fs(fields[i]);
|
||||
if ($sf && StringFields[i]) {
|
||||
//$sf.val(StringFields[i].Value);
|
||||
cip.setValue($sf, StringFields[i].Value);
|
||||
filledInFields.list.push(fields[i]);
|
||||
$filledIn = true;
|
||||
|
|
@ -1525,7 +1509,7 @@ cip.fillIn = function(combination, onlyPassword, suppressWarnings) {
|
|||
filledIn = true;
|
||||
}
|
||||
|
||||
let list = {};
|
||||
let list = [];
|
||||
if (cip.fillInStringFields(combination.fields, cip.credentials[0].stringFields, list)) {
|
||||
cipForm.destroy(false, {'password': list.list[0], 'username': list.list[1]});
|
||||
filledIn = true;
|
||||
|
|
@ -1555,7 +1539,7 @@ cip.fillIn = function(combination, onlyPassword, suppressWarnings) {
|
|||
filledIn = true;
|
||||
}
|
||||
|
||||
let list = {};
|
||||
let list = [];
|
||||
if (cip.fillInStringFields(combination.fields, cip.credentials[combination.loginId].stringFields, list)) {
|
||||
cipForm.destroy(false, {'password': list.list[0], 'username': list.list[1]});
|
||||
filledIn = true;
|
||||
|
|
@ -1608,7 +1592,7 @@ cip.fillIn = function(combination, onlyPassword, suppressWarnings) {
|
|||
pField.data('unchanged', true);
|
||||
}
|
||||
|
||||
let list = {};
|
||||
let list = [];
|
||||
if (cip.fillInStringFields(combination.fields, valStringFields, list)) {
|
||||
cipForm.destroy(false, {'password': list.list[0], 'username': list.list[1]});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"manifest_version": 2,
|
||||
"name": "keepassxc-browser",
|
||||
"version": "0.4.3",
|
||||
"version": "0.4.4",
|
||||
"description": "KeePassXC integration for modern web browsers",
|
||||
"author": "Sami Vänttinen",
|
||||
"icons": {
|
||||
|
|
|
|||
|
|
@ -200,10 +200,10 @@
|
|||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3 class="modal-title" id="myModalLabel">Remove identifier from Chrome?</h3>
|
||||
<h3 class="modal-title" id="myModalLabel">Remove identifier from database list?</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>Do you really want to remove the identifier <span class="bold"></span> from Chrome?</p>
|
||||
<p>Do you really want to remove the identifier <span class="bold"></span> from the database list?</p>
|
||||
<p class="help-block">You can reconnect your database at any time.</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
|
|
|
|||
|
|
@ -30,6 +30,18 @@ options.initMenu = function() {
|
|||
$('div.tab:first').show();
|
||||
};
|
||||
|
||||
options.saveSettingsPromise = function() {
|
||||
return new Promise((resolve, reject) => {
|
||||
browser.storage.local.set({'settings': options.settings}).then((item) => {
|
||||
browser.runtime.sendMessage({
|
||||
action: 'load_settings'
|
||||
}).then((settings) => {
|
||||
resolve(settings);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
options.saveSetting = function(name) {
|
||||
const $id = '#' + name;
|
||||
$($id).closest('.control-group').removeClass('error').addClass('success');
|
||||
|
|
@ -61,8 +73,13 @@ options.initGeneralSettings = function() {
|
|||
});
|
||||
|
||||
$('#tab-general-settings input[type=checkbox]').change(function() {
|
||||
options.settings[$(this).attr('name')] = $(this).is(':checked');
|
||||
options.saveSettings();
|
||||
const name = $(this).attr('name');
|
||||
options.settings[name] = $(this).is(':checked');
|
||||
options.saveSettingsPromise().then((x) => {
|
||||
if (name === 'autoFillAndSend') {
|
||||
browser.runtime.sendMessage({action: 'init_http_auth'});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('#tab-general-settings input[type=radio]').each(function() {
|
||||
|
|
|
|||
|
|
@ -4,16 +4,16 @@ Transmitting messages between KeePassXC and keepassxc-browser is totally rewritt
|
|||
Now the requests are encrypted by [TweetNaCl.js](https://github.com/dchest/tweetnacl-js) box method and does the following:
|
||||
|
||||
1. keepassxc-browser generates a key pair (with public and secret key) and transfers the public key to KeePassXC
|
||||
2. When KeePassXC receives the public key it generates its own key pair and transfers the public key to keepassxc-browser
|
||||
2. When KeePassXC receives the public key it generates its own key pair and transfers the public key to keepassxc-browser. Public key is transferred in plain-text. Secret keys are never transferred or used anywhere except when encrypting/decrypting.
|
||||
3. All messages between the browser extension and KeePassXC are now encrypted.
|
||||
4. When keepassxc-browser sends a message it is encrypted with KeePassXC's public key, a random generated nonce and keepassxc-browser's secret key.
|
||||
5. When KeePassXC sends a message it is encrypted with keepassxc-browser's public key and an incremented nonce.
|
||||
6. Databases are stored based on the current public key used with `associate`. A new key pair for data transfer is generated each time keepassxc-browser is launched.
|
||||
6. Databases are stored based on the current public key used with `associate`. A new key pair for data transfer is generated each time keepassxc-browser is launched. This saved key is not used again, as it's only used for identification.
|
||||
|
||||
Encrypted messages are built with these JSON parameters:
|
||||
- action - `test-associate`, `associate`, `get-logins`, `get-logins-count`, `set-login`...
|
||||
- message - Encrypted message, base64 encoded
|
||||
- nonce - 24 bytes long random data, base64 encoded. This must be the same when responding to a request.
|
||||
- nonce - 24 bytes long random data, base64 encoded. This is incremented to the response.
|
||||
- clientID - 24 bytes long random data, base64 encoded. This is used to identify different browsers if multiple are used with proxy application.
|
||||
|
||||
Currently these messages are implemented:
|
||||
|
|
|
|||
Loading…
Reference in a new issue