Merge pull request #1392 from keepassxreboot/feature/browser-settings-rework

Browser integration settings rework and KeePassHTTP deprecation
This commit is contained in:
Janek Bevendorff 2018-01-19 23:31:05 +01:00 committed by GitHub
commit ee3ccf151a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 362 additions and 207 deletions

View File

@ -1,5 +1,5 @@
# Copyright (C) 2010 Felix Geyer <debfx@fobos.de>
# Copyright (C) 2017 KeePassXC Team <team@keepassxc.org> # Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
# Copyright (C) 2010 Felix Geyer <debfx@fobos.de>
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@ -41,10 +41,17 @@ option(WITH_COVERAGE "Use to build with coverage tests (GCC only)." OFF)
option(WITH_APP_BUNDLE "Enable Application Bundle for macOS" ON) option(WITH_APP_BUNDLE "Enable Application Bundle for macOS" ON)
option(WITH_XC_AUTOTYPE "Include Auto-Type." ON) option(WITH_XC_AUTOTYPE "Include Auto-Type." ON)
option(WITH_XC_HTTP "Include KeePassHTTP and Custom Icon Downloads." OFF) option(WITH_XC_NETWORKING "Include networking code (e.g. for downlading website icons)." OFF)
option(WITH_XC_BROWSER "Include browser integration with keepassxc-browser." OFF)
option(WITH_XC_HTTP "Include KeePassHTTP-compatible browser integration (deprecated, implies WITH_NETWORKING)." OFF)
option(WITH_XC_YUBIKEY "Include YubiKey support." OFF) option(WITH_XC_YUBIKEY "Include YubiKey support." OFF)
option(WITH_XC_SSHAGENT "Include SSH agent support." OFF) option(WITH_XC_SSHAGENT "Include SSH agent support." OFF)
option(WITH_XC_BROWSER "Include browser extension support." OFF)
if(WITH_XC_HTTP)
message(WARNING "KeePassHTTP support has been deprecated and will be removed in a future version. Please use WITH_XC_BROWSER instead!\n"
"For enabling / disabling network access code, WITH_XC_HTTP has been replaced by WITH_XC_NETWORKING.")
set(WITH_XC_NETWORKING ON CACHE BOOL "Include networking code (e.g. for downlading website icons)." FORCE)
endif()
# Process ui files automatically from source files # Process ui files automatically from source files
set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOUIC ON)

View File

@ -187,15 +187,21 @@ set(keepassx_SOURCES_MAINEXE
main.cpp main.cpp
) )
add_feature_info(AutoType WITH_XC_AUTOTYPE "Automatic password typing") add_feature_info(Auto-Type WITH_XC_AUTOTYPE "Automatic password typing")
add_feature_info(KeePassHTTP WITH_XC_HTTP "Browser integration compatible with ChromeIPass and PassIFox") add_feature_info(Networking WITH_XC_NETWORKING "Compile KeePassXC with network access code (e.g. for downloading website icons)")
add_feature_info(YubiKey WITH_XC_YUBIKEY "YubiKey HMAC-SHA1 challenge-response") add_feature_info(keepassxc-browser WITH_XC_BROWSER "Browser integration with keepassxc-browser")
add_feature_info(KeePassHTTP WITH_XC_HTTP "Browser integration compatible with ChromeIPass and PassIFox (deprecated, implies Networking)")
add_feature_info(SSHAgent WITH_XC_SSHAGENT "SSH agent integration compatible with KeeAgent") add_feature_info(SSHAgent WITH_XC_SSHAGENT "SSH agent integration compatible with KeeAgent")
add_feature_info(keepassxc-browser WITH_XC_BROWSER "KeePassXC browser support with keepassxc-browser") add_feature_info(YubiKey WITH_XC_YUBIKEY "YubiKey HMAC-SHA1 challenge-response")
add_subdirectory(http)
if(WITH_XC_HTTP) if(WITH_XC_HTTP)
set(keepasshttp_LIB keepasshttp qhttp Qt5::Network) add_subdirectory(http)
set(keepasshttp_LIB keepasshttp)
endif()
if(WITH_XC_NETWORKING)
add_subdirectory(http/qhttp)
set(keepassxcnetwork_LIB qhttp Qt5::Network)
endif() endif()
set(BROWSER_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/browser) set(BROWSER_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/browser)
@ -247,8 +253,9 @@ add_library(keepassx_core STATIC ${keepassx_SOURCES})
set_target_properties(keepassx_core PROPERTIES COMPILE_DEFINITIONS KEEPASSX_BUILDING_CORE) set_target_properties(keepassx_core PROPERTIES COMPILE_DEFINITIONS KEEPASSX_BUILDING_CORE)
target_link_libraries(keepassx_core target_link_libraries(keepassx_core
${keepasshttp_LIB}
${keepassxcbrowser_LIB} ${keepassxcbrowser_LIB}
${keepasshttp_LIB}
${keepassxcnetwork_LIB}
${autotype_LIB} ${autotype_LIB}
${sshagent_LIB} ${sshagent_LIB}
${YUBIKEY_LIBRARIES} ${YUBIKEY_LIBRARIES}

View File

@ -23,6 +23,7 @@
#include "core/FilePath.h" #include "core/FilePath.h"
#include <QMessageBox> #include <QMessageBox>
#include <QFileDialog>
BrowserOptionDialog::BrowserOptionDialog(QWidget* parent) : BrowserOptionDialog::BrowserOptionDialog(QWidget* parent) :
QWidget(parent), QWidget(parent),
@ -32,15 +33,18 @@ BrowserOptionDialog::BrowserOptionDialog(QWidget* parent) :
connect(m_ui->removeSharedEncryptionKeys, SIGNAL(clicked()), this, SIGNAL(removeSharedEncryptionKeys())); connect(m_ui->removeSharedEncryptionKeys, SIGNAL(clicked()), this, SIGNAL(removeSharedEncryptionKeys()));
connect(m_ui->removeStoredPermissions, SIGNAL(clicked()), this, SIGNAL(removeStoredPermissions())); connect(m_ui->removeStoredPermissions, SIGNAL(clicked()), this, SIGNAL(removeStoredPermissions()));
m_ui->warningWidget->showMessage(tr("The following options can be dangerous!\nChange them only if you know what you are doing."), MessageWidget::Warning); m_ui->warningWidget->showMessage(tr("<b>Warning:</b> The following options can be dangerous!"), MessageWidget::Warning);
m_ui->warningWidget->setIcon(FilePath::instance()->icon("status", "dialog-warning"));
m_ui->warningWidget->setCloseButtonVisible(false); m_ui->warningWidget->setCloseButtonVisible(false);
m_ui->warningWidget->setAutoHideTimeout(-1);
m_ui->tabWidget->setEnabled(m_ui->enableBrowserSupport->isChecked()); m_ui->tabWidget->setEnabled(m_ui->enableBrowserSupport->isChecked());
connect(m_ui->enableBrowserSupport, SIGNAL(toggled(bool)), m_ui->tabWidget, SLOT(setEnabled(bool))); connect(m_ui->enableBrowserSupport, SIGNAL(toggled(bool)), m_ui->tabWidget, SLOT(setEnabled(bool)));
m_ui->customProxyLocation->setEnabled(m_ui->useCustomProxy->isChecked()); m_ui->customProxyLocation->setEnabled(m_ui->useCustomProxy->isChecked());
m_ui->customProxyLocationBrowseButton->setEnabled(m_ui->useCustomProxy->isChecked());
connect(m_ui->useCustomProxy, SIGNAL(toggled(bool)), m_ui->customProxyLocation, SLOT(setEnabled(bool))); connect(m_ui->useCustomProxy, SIGNAL(toggled(bool)), m_ui->customProxyLocation, SLOT(setEnabled(bool)));
connect(m_ui->useCustomProxy, SIGNAL(toggled(bool)), m_ui->customProxyLocationBrowseButton, SLOT(setEnabled(bool)));
connect(m_ui->customProxyLocationBrowseButton, SIGNAL(clicked()), this, SLOT(showProxyLocationFileDialog()));
} }
BrowserOptionDialog::~BrowserOptionDialog() BrowserOptionDialog::~BrowserOptionDialog()
@ -57,6 +61,11 @@ void BrowserOptionDialog::loadSettings()
m_ui->unlockDatabase->setChecked(settings.unlockDatabase()); m_ui->unlockDatabase->setChecked(settings.unlockDatabase());
m_ui->matchUrlScheme->setChecked(settings.matchUrlScheme()); m_ui->matchUrlScheme->setChecked(settings.matchUrlScheme());
// hide unimplemented options
// TODO: fix this
m_ui->showNotification->hide();
m_ui->bestMatchOnly->hide();
if (settings.sortByUsername()) { if (settings.sortByUsername()) {
m_ui->sortByUsername->setChecked(true); m_ui->sortByUsername->setChecked(true);
} else { } else {
@ -102,3 +111,16 @@ void BrowserOptionDialog::saveSettings()
settings.setFirefoxSupport(m_ui->firefoxSupport->isChecked()); settings.setFirefoxSupport(m_ui->firefoxSupport->isChecked());
settings.setVivaldiSupport(m_ui->vivaldiSupport->isChecked()); settings.setVivaldiSupport(m_ui->vivaldiSupport->isChecked());
} }
void BrowserOptionDialog::showProxyLocationFileDialog()
{
#ifdef Q_OS_WIN
QString fileTypeFilter(tr("Executable Files (*.exe);;All Files (*.*)"));
#else
QString fileTypeFilter(tr("Executable Files (*.*)"));
#endif
auto proxyLocation = QFileDialog::getOpenFileName(this, tr("Select custom proxy location"),
QFileInfo(QCoreApplication::applicationDirPath()).filePath(),
fileTypeFilter);
m_ui->customProxyLocation->setText(proxyLocation);
}

View File

@ -43,6 +43,9 @@ signals:
void removeSharedEncryptionKeys(); void removeSharedEncryptionKeys();
void removeStoredPermissions(); void removeStoredPermissions();
private slots:
void showProxyLocationFileDialog();
private: private:
QScopedPointer<Ui::BrowserOptionDialog> m_ui; QScopedPointer<Ui::BrowserOptionDialog> m_ui;
}; };

View File

@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>577</width> <width>456</width>
<height>404</height> <height>385</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -32,7 +32,7 @@
<string>This is required for accessing your databases with keepassxc-browser</string> <string>This is required for accessing your databases with keepassxc-browser</string>
</property> </property>
<property name="text"> <property name="text">
<string>Enable KeepassXC browser extension</string> <string>Enable KeepassXC browser integration</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -47,22 +47,93 @@
</attribute> </attribute>
<layout class="QVBoxLayout" name="verticalLayout_2"> <layout class="QVBoxLayout" name="verticalLayout_2">
<item> <item>
<widget class="QCheckBox" name="showNotification"> <widget class="QGroupBox" name="browsersGroupBox">
<property name="text"> <property name="title">
<string>Sh&amp;ow a notification when credentials are requested</string> <string>Enable integration for these browsers:</string>
</property>
<property name="checked">
<bool>true</bool>
</property> </property>
<layout class="QGridLayout" name="gridLayout">
<property name="horizontalSpacing">
<number>40</number>
</property>
<item row="0" column="0">
<widget class="QCheckBox" name="chromeSupport">
<property name="text">
<string>&amp;Google Chrome</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="firefoxSupport">
<property name="text">
<string>&amp;Firefox</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="0" column="2">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>179</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="chromiumSupport">
<property name="text">
<string>&amp;Chromium</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="vivaldiSupport">
<property name="text">
<string>&amp;Vivaldi</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QCheckBox" name="bestMatchOnly"> <spacer name="verticalSpacer_3">
<property name="toolTip"> <property name="orientation">
<string>Only returns the best matches for a specific URL instead of all entries for the whole domain.</string> <enum>Qt::Vertical</enum>
</property> </property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>4</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QCheckBox" name="showNotification">
<property name="text"> <property name="text">
<string>&amp;Return only best-matching entries</string> <string>Show a &amp;notification when credentials are requested</string>
</property>
<property name="checked">
<bool>true</bool>
</property> </property>
</widget> </widget>
</item> </item>
@ -82,117 +153,82 @@
<string>Only entries with the same scheme (http://, https://, ...) are returned.</string> <string>Only entries with the same scheme (http://, https://, ...) are returned.</string>
</property> </property>
<property name="text"> <property name="text">
<string>&amp;Match URL schemes</string> <string>&amp;Match URL scheme (e.g., https://...)</string>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QRadioButton" name="sortByUsername"> <widget class="QCheckBox" name="bestMatchOnly">
<property name="toolTip">
<string>Only returns the best matches for a specific URL instead of all entries for the whole domain.</string>
</property>
<property name="text"> <property name="text">
<string>Sort matching entries by &amp;username</string> <string>&amp;Return only best-matching credentials</string>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QRadioButton" name="sortByTitle"> <widget class="QRadioButton" name="sortByTitle">
<property name="text"> <property name="text">
<string>Sort &amp;matching entries by title</string> <string>Sort &amp;matching credentials by title</string>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QPushButton" name="removeSharedEncryptionKeys"> <widget class="QRadioButton" name="sortByUsername">
<property name="text"> <property name="text">
<string>R&amp;emove all shared encryption keys from active database</string> <string>Sort matching credentials by &amp;username</string>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QPushButton" name="removeStoredPermissions"> <spacer name="verticalSpacer">
<property name="text">
<string>Re&amp;move all stored permissions from entries in active database</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation"> <property name="orientation">
<enum>Qt::Vertical</enum> <enum>Qt::Vertical</enum>
</property> </property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0"> <property name="sizeHint" stdset="0">
<size> <size>
<width>20</width> <width>20</width>
<height>40</height> <height>10</height>
</size> </size>
</property> </property>
</spacer> </spacer>
</item> </item>
</layout>
</widget>
<widget class="QWidget" name="tab_3">
<attribute name="title">
<string>Supported browsers</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QLabel" name="browserLabel1">
<property name="text">
<string>Native messaging requires certain .json files to be installed. Already installed browsers are automatically detected.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="browserLabel2">
<property name="text">
<string>Enable KeePassXC native messaging extension for these browsers:</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="chromeSupport">
<property name="text">
<string>Chrome</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="chromiumSupport">
<property name="text">
<string>Chromium</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="firefoxSupport">
<property name="text">
<string>Firefox</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="vivaldiSupport">
<property name="text">
<string>Vivaldi</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item> <item>
<spacer name="verticalSpacer_3"> <layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QPushButton" name="removeSharedEncryptionKeys">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>&amp;Disconnect all browsers</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="removeStoredPermissions">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Forget all remembered &amp;permissions</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation"> <property name="orientation">
<enum>Qt::Vertical</enum> <enum>Qt::Vertical</enum>
</property> </property>
@ -224,14 +260,14 @@
<item> <item>
<widget class="QCheckBox" name="alwaysAllowAccess"> <widget class="QCheckBox" name="alwaysAllowAccess">
<property name="text"> <property name="text">
<string>Always allow &amp;access to entries</string> <string>Never &amp;ask before accessing credentials</string>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QCheckBox" name="alwaysAllowUpdate"> <widget class="QCheckBox" name="alwaysAllowUpdate">
<property name="text"> <property name="text">
<string>Always allow &amp;updating entries</string> <string>Never ask before &amp;updating credentials</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -241,7 +277,7 @@
<string>Only the selected database has to be connected with a client.</string> <string>Only the selected database has to be connected with a client.</string>
</property> </property>
<property name="text"> <property name="text">
<string>Searc&amp;h in all opened databases for matching entries</string> <string>Searc&amp;h in all opened databases for matching credentials</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -261,7 +297,7 @@
<string>Updates KeePassXC or keepassxc-proxy binary path automatically to native messaging scripts on startup.</string> <string>Updates KeePassXC or keepassxc-proxy binary path automatically to native messaging scripts on startup.</string>
</property> </property>
<property name="text"> <property name="text">
<string>&amp;Update KeePassXC binary path automatically to native messaging scripts on startup</string> <string>Update &amp;native messaging manifest files at startup</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -271,7 +307,7 @@
<string>Support a proxy application between KeePassXC and browser extension.</string> <string>Support a proxy application between KeePassXC and browser extension.</string>
</property> </property>
<property name="text"> <property name="text">
<string>&amp;Enable support for proxy application between KeePassXC and browser extension</string> <string>Use a &amp;proxy application between KeePassXC and browser extension</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -281,19 +317,30 @@
<string>Use a custom proxy location if you installed a proxy manually.</string> <string>Use a custom proxy location if you installed a proxy manually.</string>
</property> </property>
<property name="text"> <property name="text">
<string>&amp;Use a custom proxy location</string> <string>Use a &amp;custom proxy location</string>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QLineEdit" name="customProxyLocation"> <layout class="QHBoxLayout" name="horizontalLayout">
<property name="maxLength"> <item>
<number>999</number> <widget class="QLineEdit" name="customProxyLocation">
</property> <property name="maxLength">
<property name="alignment"> <number>999</number>
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> </property>
</property> <property name="alignment">
</widget> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="customProxyLocationBrowseButton">
<property name="text">
<string>Browse...</string>
</property>
</widget>
</item>
</layout>
</item> </item>
<item> <item>
<spacer name="verticalSpacer_4"> <spacer name="verticalSpacer_4">

View File

@ -34,7 +34,7 @@ public:
static void setShowNotification(bool showNotification); static void setShowNotification(bool showNotification);
static bool bestMatchOnly(); //TODO!! static bool bestMatchOnly(); //TODO!!
static void setBestMatchOnly(bool bestMatchOnly); static void setBestMatchOnly(bool bestMatchOnly);
static bool unlockDatabase(); //TODO!! static bool unlockDatabase();
static void setUnlockDatabase(bool unlockDatabase); static void setUnlockDatabase(bool unlockDatabase);
static bool matchUrlScheme(); static bool matchUrlScheme();
static void setMatchUrlScheme(bool matchUrlScheme); static void setMatchUrlScheme(bool matchUrlScheme);

View File

@ -12,11 +12,12 @@
#define KEEPASSX_PLUGIN_DIR "${PLUGIN_INSTALL_DIR}" #define KEEPASSX_PLUGIN_DIR "${PLUGIN_INSTALL_DIR}"
#define KEEPASSX_DATA_DIR "${DATA_INSTALL_DIR}" #define KEEPASSX_DATA_DIR "${DATA_INSTALL_DIR}"
#cmakedefine WITH_XC_HTTP
#cmakedefine WITH_XC_AUTOTYPE #cmakedefine WITH_XC_AUTOTYPE
#cmakedefine WITH_XC_NETWORKING
#cmakedefine WITH_XC_BROWSER
#cmakedefine WITH_XC_HTTP
#cmakedefine WITH_XC_YUBIKEY #cmakedefine WITH_XC_YUBIKEY
#cmakedefine WITH_XC_SSHAGENT #cmakedefine WITH_XC_SSHAGENT
#cmakedefine WITH_XC_BROWSER
#cmakedefine KEEPASSXC_DIST #cmakedefine KEEPASSXC_DIST
#cmakedefine KEEPASSXC_DIST_TYPE "@KEEPASSXC_DIST_TYPE@" #cmakedefine KEEPASSXC_DIST_TYPE "@KEEPASSXC_DIST_TYPE@"

View File

@ -78,20 +78,20 @@ AboutDialog::AboutDialog(QWidget* parent)
#endif #endif
QString extensions; QString extensions;
#ifdef WITH_XC_HTTP
extensions += "\n- KeePassHTTP";
#endif
#ifdef WITH_XC_AUTOTYPE #ifdef WITH_XC_AUTOTYPE
extensions += "\n- Auto-Type"; extensions += "\n- Auto-Type";
#endif #endif
#ifdef WITH_XC_YUBIKEY #ifdef WITH_XC_BROWSER
extensions += "\n- YubiKey"; extensions += "\n- Browser Integration";
#endif
#ifdef WITH_XC_HTTP
extensions += "\n- Legacy Browser Integration (KeePassHTTP)";
#endif #endif
#ifdef WITH_XC_SSHAGENT #ifdef WITH_XC_SSHAGENT
extensions += "\n- SSH Agent"; extensions += "\n- SSH Agent";
#endif #endif
#ifdef WITH_XC_BROWSER #ifdef WITH_XC_YUBIKEY
extensions += "\n- Native messaging browser extension"; extensions += "\n- YubiKey";
#endif #endif
if (extensions.isEmpty()) if (extensions.isEmpty())

View File

@ -30,7 +30,7 @@
#include "gui/IconModels.h" #include "gui/IconModels.h"
#include "gui/MessageBox.h" #include "gui/MessageBox.h"
#ifdef WITH_XC_HTTP #ifdef WITH_XC_NETWORKING
#include "http/qhttp/qhttpclient.hpp" #include "http/qhttp/qhttpclient.hpp"
#include "http/qhttp/qhttpclientresponse.hpp" #include "http/qhttp/qhttpclientresponse.hpp"
@ -49,11 +49,13 @@ EditWidgetIcons::EditWidgetIcons(QWidget* parent)
, m_database(nullptr) , m_database(nullptr)
, m_defaultIconModel(new DefaultIconModel(this)) , m_defaultIconModel(new DefaultIconModel(this))
, m_customIconModel(new CustomIconModel(this)) , m_customIconModel(new CustomIconModel(this))
#ifdef WITH_XC_HTTP #ifdef WITH_XC_NETWORKING
, m_fallbackToGoogle(true) , m_fallbackToGoogle(true)
, m_redirectCount(0) , m_redirectCount(0)
#endif
#ifdef WITH_XC_HTTP
, m_httpClient(nullptr) , m_httpClient(nullptr)
#endif #endif
{ {
m_ui->setupUi(this); m_ui->setupUi(this);
@ -146,7 +148,7 @@ void EditWidgetIcons::load(const Uuid& currentUuid, Database* database, const Ic
void EditWidgetIcons::setUrl(const QString& url) void EditWidgetIcons::setUrl(const QString& url)
{ {
#ifdef WITH_XC_HTTP #ifdef WITH_XC_NETWORKING
m_url = url; m_url = url;
m_ui->faviconButton->setVisible(!url.isEmpty()); m_ui->faviconButton->setVisible(!url.isEmpty());
resetFaviconDownload(); resetFaviconDownload();
@ -158,14 +160,14 @@ void EditWidgetIcons::setUrl(const QString& url)
void EditWidgetIcons::downloadFavicon() void EditWidgetIcons::downloadFavicon()
{ {
#ifdef WITH_XC_HTTP #ifdef WITH_XC_NETWORKING
QUrl url = QUrl(m_url); QUrl url = QUrl(m_url);
url.setPath("/favicon.ico"); url.setPath("/favicon.ico");
fetchFavicon(url); fetchFavicon(url);
#endif #endif
} }
#ifdef WITH_XC_HTTP #ifdef WITH_XC_NETWORKING
void EditWidgetIcons::fetchFavicon(const QUrl& url) void EditWidgetIcons::fetchFavicon(const QUrl& url)
{ {
if (nullptr == m_httpClient) { if (nullptr == m_httpClient) {

View File

@ -32,7 +32,7 @@ class Database;
class DefaultIconModel; class DefaultIconModel;
class CustomIconModel; class CustomIconModel;
#ifdef WITH_XC_HTTP #ifdef WITH_XC_NETWORKING
namespace qhttp { namespace qhttp {
namespace client { namespace client {
class QHttpClient; class QHttpClient;
@ -73,7 +73,7 @@ signals:
private slots: private slots:
void downloadFavicon(); void downloadFavicon();
#ifdef WITH_XC_HTTP #ifdef WITH_XC_NETWORKING
void fetchFavicon(const QUrl& url); void fetchFavicon(const QUrl& url);
void fetchFaviconFromGoogle(const QString& domain); void fetchFaviconFromGoogle(const QString& domain);
void resetFaviconDownload(bool clearRedirect = true); void resetFaviconDownload(bool clearRedirect = true);
@ -93,7 +93,7 @@ private:
QString m_url; QString m_url;
DefaultIconModel* const m_defaultIconModel; DefaultIconModel* const m_defaultIconModel;
CustomIconModel* const m_customIconModel; CustomIconModel* const m_customIconModel;
#ifdef WITH_XC_HTTP #ifdef WITH_XC_NETWORKING
QUrl m_redirectUrl; QUrl m_redirectUrl;
bool m_fallbackToGoogle; bool m_fallbackToGoogle;
unsigned short m_redirectCount; unsigned short m_redirectCount;

View File

@ -33,6 +33,7 @@
#include <QTimeLine> #include <QTimeLine>
#include <QToolButton> #include <QToolButton>
#include <QStyle> #include <QStyle>
#include <QtGui/QBitmap>
//--------------------------------------------------------------------- //---------------------------------------------------------------------
// KMessageWidgetPrivate // KMessageWidgetPrivate
@ -49,6 +50,7 @@ public:
QToolButton *closeButton; QToolButton *closeButton;
QTimeLine *timeLine; QTimeLine *timeLine;
QIcon icon; QIcon icon;
QPixmap closeButtonPixmap;
KMessageWidget::MessageType messageType; KMessageWidget::MessageType messageType;
bool wordWrap; bool wordWrap;
@ -95,10 +97,11 @@ void KMessageWidgetPrivate::init(KMessageWidget *q_ptr)
closeAction->setIcon(FilePath::instance()->icon("actions", "message-close", false)); closeAction->setIcon(FilePath::instance()->icon("actions", "message-close", false));
QObject::connect(closeAction, SIGNAL(triggered(bool)), q, SLOT(animatedHide())); QObject::connect(closeAction, SIGNAL(triggered(bool)), q, SLOT(animatedHide()));
closeButton = new QToolButton(content); closeButton = new QToolButton(content);
closeButton->setAutoRaise(true); closeButton->setAutoRaise(true);
closeButton->setDefaultAction(closeAction); closeButton->setDefaultAction(closeAction);
closeButtonPixmap = QPixmap(closeButton->icon().pixmap(closeButton->icon().actualSize(QSize(16, 16))));
#ifdef Q_OS_MAC #ifdef Q_OS_MAC
closeButton->setStyleSheet("QToolButton { background: transparent;" closeButton->setStyleSheet("QToolButton { background: transparent;"
"border-radius: 2px; padding: 3px; }" "border-radius: 2px; padding: 3px; }"
@ -256,49 +259,42 @@ KMessageWidget::MessageType KMessageWidget::messageType() const
return d->messageType; return d->messageType;
} }
static QColor darkShade(QColor c)
{
qreal contrast = 0.7; // taken from kcolorscheme for the dark shade
qreal darkAmount;
if (c.lightnessF() < 0.006) { /* too dark */
darkAmount = 0.02 + 0.40 * contrast;
} else if (c.lightnessF() > 0.93) { /* too bright */
darkAmount = -0.06 - 0.60 * contrast;
} else {
darkAmount = (-c.lightnessF()) * (0.55 + contrast * 0.35);
}
qreal v = c.lightnessF() + darkAmount;
v = v > 0.0 ? (v < 1.0 ? v : 1.0) : 0.0;
c.setHsvF(c.hslHueF(), c.hslSaturationF(), v);
return c;
}
void KMessageWidget::setMessageType(KMessageWidget::MessageType type) void KMessageWidget::setMessageType(KMessageWidget::MessageType type)
{ {
d->messageType = type; d->messageType = type;
QColor bg0, bg1, bg2, border, fg; QColor bg0, bg1, bg2, border;
QColor fg = palette().light().color();
switch (type) { switch (type) {
case Positive: case Positive:
bg1.setRgb(0, 110, 40); // values taken from kcolorscheme.cpp (Positive) bg1.setRgb(37, 163, 83);
break; break;
case Information: case Information:
bg1 = palette().highlight().color(); bg1.setRgb(24, 187, 242);
break; break;
case Warning: case Warning:
bg1.setRgb(181, 102, 0); // values taken from kcolorscheme.cpp (Neutral) bg1.setRgb(252, 193, 57);
break; fg = palette().foreground().color();
case Error: break;
bg1.setRgb(191, 3, 3); // values taken from kcolorscheme.cpp (Negative) case Error:
break; bg1.setRgb(198, 69, 21);
break;
} }
// Colors // Colors
fg = palette().light().color(); bg0 = bg1.lighter(105);
bg0 = bg1.lighter(110); bg2 = bg1.darker(105);
bg2 = bg1.darker(110); border = bg1.darker(115);
border = darkShade(bg1);
// Tint close icon
auto closeButtonPixmap = d->closeButtonPixmap;
QPixmap mask(closeButtonPixmap);
QPainter painter;
painter.begin(&closeButtonPixmap);
painter.setRenderHints(QPainter::HighQualityAntialiasing);
painter.setCompositionMode(QPainter::CompositionMode_SourceIn);
painter.fillRect(QRect(0, 0, 16, 16), fg);
painter.end();
d->closeButton->setIcon(closeButtonPixmap);
d->content->setStyleSheet( d->content->setStyleSheet(
QString(QLatin1String(".QFrame {" QString(QLatin1String(".QFrame {"
@ -306,10 +302,10 @@ void KMessageWidget::setMessageType(KMessageWidget::MessageType type)
" stop: 0 %1," " stop: 0 %1,"
" stop: 0.1 %2," " stop: 0.1 %2,"
" stop: 1.0 %3);" " stop: 1.0 %3);"
"border-radius: 5px;" " border-radius: 2px;"
"border: 1px solid %4;" " border: 1px solid %4;"
"margin: %5px;" " margin: %5px;"
"padding: 5px;" " padding: 5px;"
"}" "}"
".QLabel { color: %6; }" ".QLabel { color: %6; }"
)) ))
@ -317,8 +313,9 @@ void KMessageWidget::setMessageType(KMessageWidget::MessageType type)
.arg(bg1.name()) .arg(bg1.name())
.arg(bg2.name()) .arg(bg2.name())
.arg(border.name()) .arg(border.name())
// DefaultFrameWidth returns the size of the external margin + border width. We know our border is 1px, so we subtract this from the frame normal QStyle FrameWidth to get our margin // DefaultFrameWidth returns the size of the external margin + border width. We know our border is 1px,
.arg(style()->pixelMetric(QStyle::PM_DefaultFrameWidth, 0, this) - 1) // so we subtract this from the frame normal QStyle FrameWidth to get our margin
.arg(style()->pixelMetric(QStyle::PM_DefaultFrameWidth, nullptr, this) - 1)
.arg(fg.name()) .arg(fg.name())
); );
} }

View File

@ -77,7 +77,7 @@ public:
QString name() override QString name() override
{ {
return QObject::tr("Browser Integration"); return QObject::tr("Legacy Browser Integration");
} }
QIcon icon() override QIcon icon() override
@ -125,7 +125,7 @@ class BrowserPlugin: public ISettingsPage
QString name() override QString name() override
{ {
return QObject::tr("Browser extension with native messaging"); return QObject::tr("Browser Integration");
} }
QIcon icon() override QIcon icon() override
@ -182,19 +182,22 @@ MainWindow::MainWindow()
m_countDefaultAttributes = m_ui->menuEntryCopyAttribute->actions().size(); m_countDefaultAttributes = m_ui->menuEntryCopyAttribute->actions().size();
restoreGeometry(config()->get("GUI/MainWindowGeometry").toByteArray()); restoreGeometry(config()->get("GUI/MainWindowGeometry").toByteArray());
#ifdef WITH_XC_HTTP #ifdef WITH_XC_BROWSER
m_ui->settingsWidget->addSettingsPage(new BrowserPlugin(m_ui->tabWidget));
#endif
#ifdef WITH_XC_HTTP
m_ui->settingsWidget->addSettingsPage(new HttpPlugin(m_ui->tabWidget)); m_ui->settingsWidget->addSettingsPage(new HttpPlugin(m_ui->tabWidget));
#endif #endif
#ifdef WITH_XC_SSHAGENT #ifdef WITH_XC_SSHAGENT
SSHAgent::init(this); SSHAgent::init(this);
m_ui->settingsWidget->addSettingsPage(new AgentSettingsPage(m_ui->tabWidget)); m_ui->settingsWidget->addSettingsPage(new AgentSettingsPage(m_ui->tabWidget));
#endif #endif
#ifdef WITH_XC_BROWSER
m_ui->settingsWidget->addSettingsPage(new BrowserPlugin(m_ui->tabWidget));
#endif
setWindowIcon(filePath()->applicationIcon()); setWindowIcon(filePath()->applicationIcon());
m_ui->globalMessageWidget->setHidden(true); m_ui->globalMessageWidget->setHidden(true);
connect(m_ui->globalMessageWidget, &MessageWidget::linkActivated, &MessageWidget::openHttpUrl);
connect(m_ui->globalMessageWidget, SIGNAL(showAnimationStarted()), m_ui->globalMessageWidgetContainer, SLOT(show()));
connect(m_ui->globalMessageWidget, SIGNAL(hideAnimationFinished()), m_ui->globalMessageWidgetContainer, SLOT(hide()));
m_clearHistoryAction = new QAction(tr("Clear history"), m_ui->menuFile); m_clearHistoryAction = new QAction(tr("Clear history"), m_ui->menuFile);
m_lastDatabasesActions = new QActionGroup(m_ui->menuRecentDatabases); m_lastDatabasesActions = new QActionGroup(m_ui->menuRecentDatabases);
@ -407,13 +410,32 @@ MainWindow::MainWindow()
m_ui->globalMessageWidget->showMessage( m_ui->globalMessageWidget->showMessage(
tr("Access error for config file %1").arg(config()->getFileName()), MessageWidget::Error); tr("Access error for config file %1").arg(config()->getFileName()), MessageWidget::Error);
} }
#ifdef WITH_XC_HTTP
if (config()->get("Http/Enabled", false).toBool() && config()->get("Http/DeprecationNoticeShown", 0).toInt() < 3) {
// show message after tab widget dismissed all messages
connect(m_ui->tabWidget, SIGNAL(messageDismissGlobal()), this, SLOT(showKeePassHTTPDeprecationNotice()));
}
#endif
} }
MainWindow::~MainWindow() MainWindow::~MainWindow()
{ {
} }
void MainWindow::showKeePassHTTPDeprecationNotice()
{
int warningNum = config()->get("Http/DeprecationNoticeShown", 0).toInt();
displayGlobalMessage(tr("<p>It looks like you are using KeePassHTTP for browser integration. "
"This feature has been deprecated and will be removed in the future.<br>"
"Please switch to KeePassXC-Browser instead! For help with migration, "
"visit our <a class=\"link\" href=\"https://keepassxc.org/docs/keepassxc-browser-migration\">"
"migration guide</a> (warning %1 of 3).</p>").arg(warningNum + 1),
MessageWidget::Warning, true, -1);
config()->set("Http/DeprecationNoticeShown", warningNum + 1);
disconnect(m_ui->tabWidget, SIGNAL(messageDismissGlobal()), this, SLOT(showKeePassHTTPDeprecationNotice()));
}
void MainWindow::appExit() void MainWindow::appExit()
{ {
m_appExitCalled = true; m_appExitCalled = true;

View File

@ -97,6 +97,7 @@ private slots:
void repairDatabase(); void repairDatabase();
void hideTabMessage(); void hideTabMessage();
void handleScreenLock(); void handleScreenLock();
void showKeePassHTTPDeprecationNotice();
private: private:
static void setShortcut(QAction* action, QKeySequence::StandardKey standard, int fallback = 0); static void setShortcut(QAction* action, QKeySequence::StandardKey standard, int fallback = 0);

View File

@ -21,6 +21,9 @@
<bool>true</bool> <bool>true</bool>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin"> <property name="leftMargin">
<number>0</number> <number>0</number>
</property> </property>
@ -34,13 +37,28 @@
<number>0</number> <number>0</number>
</property> </property>
<item> <item>
<widget class="MessageWidget" name="globalMessageWidget" native="true"> <widget class="QWidget" name="globalMessageWidgetContainer" native="true">
<property name="sizePolicy"> <layout class="QVBoxLayout" name="globalMessageWidgetLayout">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <property name="spacing">
<horstretch>0</horstretch> <number>0</number>
<verstretch>0</verstretch> </property>
</sizepolicy> <property name="bottomMargin">
</property> <number>0</number>
</property>
<item>
<widget class="MessageWidget" name="globalMessageWidget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true">MessageWidget {margin: 90px}</string>
</property>
</widget>
</item>
</layout>
</widget> </widget>
</item> </item>
<item> <item>

View File

@ -18,7 +18,9 @@
#include "MessageWidget.h" #include "MessageWidget.h"
#include "QTimer" #include <QTimer>
#include <QDesktopServices>
#include <QUrl>
const int MessageWidget::DefaultAutoHideTimeout = 6000; const int MessageWidget::DefaultAutoHideTimeout = 6000;
const int MessageWidget::DisableAutoHide = -1; const int MessageWidget::DisableAutoHide = -1;
@ -47,6 +49,7 @@ void MessageWidget::showMessage(const QString &text, KMessageWidget::MessageType
{ {
setMessageType(type); setMessageType(type);
setText(text); setText(text);
emit showAnimationStarted();
animatedShow(); animatedShow();
if (autoHideTimeout > 0) { if (autoHideTimeout > 0) {
m_autoHideTimer->start(autoHideTimeout); m_autoHideTimer->start(autoHideTimeout);
@ -68,3 +71,16 @@ void MessageWidget::setAutoHideTimeout(int autoHideTimeout)
m_autoHideTimer->stop(); m_autoHideTimer->stop();
} }
} }
/**
* Open a link using the system's default handler.
* Links that are not HTTP(S) links are ignored.
*
* @param link link URL
*/
void MessageWidget::openHttpUrl(const QString& link)
{
if (link.startsWith("http://") || link.startsWith("https://")) {
QDesktopServices::openUrl(QUrl(link));
}
}

View File

@ -35,11 +35,15 @@ public:
static const int DefaultAutoHideTimeout; static const int DefaultAutoHideTimeout;
static const int DisableAutoHide; static const int DisableAutoHide;
signals:
void showAnimationStarted();
public slots: public slots:
void showMessage(const QString& text, MessageWidget::MessageType type); void showMessage(const QString& text, MessageWidget::MessageType type);
void showMessage(const QString& text, MessageWidget::MessageType type, int autoHideTimeout); void showMessage(const QString& text, MessageWidget::MessageType type, int autoHideTimeout);
void hideMessage(); void hideMessage();
void setAutoHideTimeout(int autoHideTimeout); void setAutoHideTimeout(int autoHideTimeout);
static void openHttpUrl(QString const& url);
private: private:
QTimer* m_autoHideTimer; QTimer* m_autoHideTimer;

View File

@ -82,7 +82,7 @@ SettingsWidget::SettingsWidget(QWidget* parent)
connect(m_secUi->lockDatabaseIdleCheckBox, SIGNAL(toggled(bool)), connect(m_secUi->lockDatabaseIdleCheckBox, SIGNAL(toggled(bool)),
m_secUi->lockDatabaseIdleSpinBox, SLOT(setEnabled(bool))); m_secUi->lockDatabaseIdleSpinBox, SLOT(setEnabled(bool)));
#ifndef WITH_XC_HTTP #ifndef WITH_XC_NETWORKING
m_secUi->privacy->setVisible(false); m_secUi->privacy->setVisible(false);
#endif #endif
} }

View File

@ -1,5 +1,3 @@
add_subdirectory(qhttp)
if(WITH_XC_HTTP) if(WITH_XC_HTTP)
include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})

View File

@ -32,13 +32,20 @@ OptionDialog::OptionDialog(QWidget *parent) :
connect(m_ui->removeSharedEncryptionKeys, SIGNAL(clicked()), this, SIGNAL(removeSharedEncryptionKeys())); connect(m_ui->removeSharedEncryptionKeys, SIGNAL(clicked()), this, SIGNAL(removeSharedEncryptionKeys()));
connect(m_ui->removeStoredPermissions, SIGNAL(clicked()), this, SIGNAL(removeStoredPermissions())); connect(m_ui->removeStoredPermissions, SIGNAL(clicked()), this, SIGNAL(removeStoredPermissions()));
m_ui->warningWidget->showMessage(tr("The following options can be dangerous!\nChange them only if you know what you are doing."), MessageWidget::Warning); m_ui->warningWidget->showMessage(tr("<b>Warning:</b> The following options can be dangerous!"), MessageWidget::Warning);
m_ui->warningWidget->setIcon(FilePath::instance()->icon("status", "dialog-warning"));
m_ui->warningWidget->setCloseButtonVisible(false); m_ui->warningWidget->setCloseButtonVisible(false);
m_ui->warningWidget->setAutoHideTimeout(MessageWidget::DisableAutoHide); m_ui->warningWidget->setAutoHideTimeout(MessageWidget::DisableAutoHide);
m_ui->tabWidget->setEnabled(m_ui->enableHttpServer->isChecked()); m_ui->tabWidget->setEnabled(m_ui->enableHttpServer->isChecked());
connect(m_ui->enableHttpServer, SIGNAL(toggled(bool)), m_ui->tabWidget, SLOT(setEnabled(bool))); connect(m_ui->enableHttpServer, SIGNAL(toggled(bool)), m_ui->tabWidget, SLOT(setEnabled(bool)));
m_ui->deprecationNotice->showMessage(tr("<p>KeePassHTTP has been deprecated and will be removed in the future.<br>"
"Please switch to KeePassXC-Browser instead! For help with migration, visit "
"our <a href=\"https://keepassxc.org/docs/keepassxc-browser-migration\">"
"migration guide</a>.</p>"), MessageWidget::Warning);
m_ui->deprecationNotice->setCloseButtonVisible(false);
m_ui->deprecationNotice->setAutoHideTimeout(-1);
connect(m_ui->deprecationNotice, &MessageWidget::linkActivated, &MessageWidget::openHttpUrl);
} }
OptionDialog::~OptionDialog() OptionDialog::~OptionDialog()

View File

@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>577</width> <width>803</width>
<height>404</height> <height>433</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -36,6 +36,9 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="MessageWidget" name="deprecationNotice" native="true"/>
</item>
<item> <item>
<widget class="QTabWidget" name="tabWidget"> <widget class="QTabWidget" name="tabWidget">
<property name="currentIndex"> <property name="currentIndex">