From f6fa6d656313d0f070c1a7da8fca52e25bc97397 Mon Sep 17 00:00:00 2001 From: Francois Ferrand Date: Wed, 17 Apr 2013 19:19:07 +0200 Subject: [PATCH] KeyPassX/Http settings. --- src/CMakeLists.txt | 4 + src/http/HttpSettings.cpp | 219 +++++++++++++++++++++++++++ src/http/HttpSettings.h | 64 ++++++++ src/http/OptionDialog.cpp | 81 ++++++++++ src/http/OptionDialog.h | 43 ++++++ src/http/OptionDialog.ui | 305 ++++++++++++++++++++++++++++++++++++++ src/http/Service.cpp | 43 +++--- 7 files changed, 737 insertions(+), 22 deletions(-) create mode 100644 src/http/HttpSettings.cpp create mode 100644 src/http/HttpSettings.h create mode 100644 src/http/OptionDialog.cpp create mode 100644 src/http/OptionDialog.h create mode 100644 src/http/OptionDialog.ui diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b0425c3cd..b57ee84d2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -103,6 +103,8 @@ set(keepassx_SOURCES gui/group/GroupView.cpp http/AccessControlDialog.cpp http/EntryConfig.cpp + http/HttpSettings.cpp + http/OptionDialog.cpp http/Protocol.cpp http/Server.cpp http/Service.cpp @@ -170,6 +172,7 @@ set(keepassx_MOC gui/group/GroupView.h http/AccessControlDialog.h http/EntryConfig.h + http/OptionDialog.h http/Protocol.h http/Server.h http/Service.h @@ -201,6 +204,7 @@ set(keepassx_FORMS gui/entry/EditEntryWidgetMain.ui gui/group/EditGroupWidgetMain.ui http/AccessControlDialog.ui + http/OptionDialog.ui ) if(MINGW) diff --git a/src/http/HttpSettings.cpp b/src/http/HttpSettings.cpp new file mode 100644 index 000000000..15cd962bd --- /dev/null +++ b/src/http/HttpSettings.cpp @@ -0,0 +1,219 @@ +/** + *************************************************************************** + * @file HttpSettings.cpp + * + * @brief + * + * Copyright (C) 2013 + * + * @author Francois Ferrand + * @date 4/2013 + *************************************************************************** + */ + +#include "HttpSettings.h" +#include "core/Config.h" + +bool HttpSettings::isEnabled() +{ + return config()->get("Http/Enabled", true).toBool(); +} + +void HttpSettings::setEnabled(bool enabled) +{ + config()->set("Http/Enabled", enabled); +} + +bool HttpSettings::showNotification() +{ + return config()->get("Http/ShowNotification", true).toBool(); +} + +void HttpSettings::setShowNotification(bool showNotification) +{ + config()->set("Http/ShowNotification", showNotification); +} + +bool HttpSettings::bestMatchOnly() +{ + return config()->get("Http/BestMatchOnly", false).toBool(); +} + +void HttpSettings::setBestMatchOnly(bool bestMatchOnly) +{ + config()->set("Http/BestMatchOnly", bestMatchOnly); +} + +bool HttpSettings::unlockDatabase() +{ + return config()->get("Http/UnlockDatabase", true).toBool(); +} + +void HttpSettings::setUnlockDatabase(bool unlockDatabase) +{ + config()->set("Http/UnlockDatabase", unlockDatabase); +} + +bool HttpSettings::matchUrlScheme() +{ + return config()->get("Http/MatchUrlScheme", true).toBool(); +} + +void HttpSettings::setMatchUrlScheme(bool matchUrlScheme) +{ + config()->set("Http/MatchUrlScheme", matchUrlScheme); +} + +bool HttpSettings::sortByUsername() +{ + return config()->get("Http/SortByUsername", false).toBool(); +} + +void HttpSettings::setSortByUsername(bool sortByUsername) +{ + config()->set("Http/SortByUsername", sortByUsername); +} + +bool HttpSettings::sortByTitle() +{ + return !sortByUsername(); +} + +void HttpSettings::setSortByTitle(bool sortByUsertitle) +{ + setSortByUsername(!sortByUsertitle); +} + +bool HttpSettings::alwaysAllowAccess() +{ + return config()->get("Http/AlwaysAllowAccess", false).toBool(); +} + +void HttpSettings::setAlwaysAllowAccess(bool alwaysAllowAccess) +{ + config()->set("Http/AlwaysAllowAccess", alwaysAllowAccess); +} + +bool HttpSettings::alwaysAllowUpdate() +{ + return config()->get("Http/AlwaysAllowUpdate", false).toBool(); +} + +void HttpSettings::setAlwaysAllowUpdate(bool alwaysAllowUpdate) +{ + config()->set("Http/AlwaysAllowAccess", alwaysAllowUpdate); +} + +bool HttpSettings::searchInAllDatabases() +{ + return config()->get("Http/SearchInAllDatabases", false).toBool(); +} + +void HttpSettings::setSearchInAllDatabases(bool searchInAllDatabases) +{ + config()->set("Http/SearchInAllDatabases", searchInAllDatabases); +} + +bool HttpSettings::supportKphFields() +{ + return config()->get("Http/SupportKphFields", true).toBool(); +} + +void HttpSettings::setSupportKphFields(bool supportKphFields) +{ + config()->set("Http/SupportKphFields", supportKphFields); +} + +bool HttpSettings::passwordUseNumbers() +{ + return config()->get("Http/PasswordUseNumbers", true).toBool(); +} + +void HttpSettings::setPasswordUseNumbers(bool useNumbers) +{ + config()->set("Http/PasswordUseNumbers", useNumbers); +} + +bool HttpSettings::passwordUseLowercase() +{ + return config()->get("Http/PasswordUseLowercase", true).toBool(); +} + +void HttpSettings::setPasswordUseLowercase(bool useLowercase) +{ + config()->set("Http/PasswordUseLowercase", useLowercase); +} + +bool HttpSettings::passwordUseUppercase() +{ + return config()->get("Http/PasswordUseUppercase", true).toBool(); +} + +void HttpSettings::setPasswordUseUppercase(bool useUppercase) +{ + config()->set("Http/PasswordUseUppercase", useUppercase); +} + +bool HttpSettings::passwordUseSpecial() +{ + return config()->get("Http/PasswordUseSpecial", false).toBool(); +} + +void HttpSettings::setPasswordUseSpecial(bool useSpecial) +{ + config()->set("Http/PasswordUseSpecial", useSpecial); +} + +bool HttpSettings::passwordEveryGroup() +{ + return config()->get("Http/PasswordEveryGroup", true).toBool(); +} + +void HttpSettings::setPasswordEveryGroup(bool everyGroup) +{ + config()->get("Http/PasswordEveryGroup", everyGroup); +} + +bool HttpSettings::passwordExcludeAlike() +{ + return config()->get("Http/PasswordExcludeAlike", true).toBool(); +} + +void HttpSettings::setPasswordExcludeAlike(bool excludeAlike) +{ + config()->set("Http/PasswordExcludeAlike", excludeAlike); +} + +int HttpSettings::passwordLength() +{ + return config()->get("Http/PasswordLength", 20).toInt(); +} + +void HttpSettings::setPasswordLength(int length) +{ + config()->set("Http/PasswordLength", length); +} + +PasswordGenerator::CharClasses HttpSettings::passwordCharClasses() +{ + PasswordGenerator::CharClasses classes; + if (passwordUseLowercase()) + classes |= PasswordGenerator::LowerLetters; + if (passwordUseUppercase()) + classes |= PasswordGenerator::UpperLetters; + if (passwordUseNumbers()) + classes |= PasswordGenerator::Numbers; + if (passwordUseSpecial()) + classes |= PasswordGenerator::SpecialCharacters; + return classes; +} + +PasswordGenerator::GeneratorFlags HttpSettings::passwordGeneratorFlags() +{ + PasswordGenerator::GeneratorFlags flags; + if (passwordExcludeAlike()) + flags |= PasswordGenerator::ExcludeLookAlike; + if (passwordEveryGroup()) + flags |= PasswordGenerator::CharFromEveryGroup; + return flags; +} diff --git a/src/http/HttpSettings.h b/src/http/HttpSettings.h new file mode 100644 index 000000000..67a998eec --- /dev/null +++ b/src/http/HttpSettings.h @@ -0,0 +1,64 @@ +/** + *************************************************************************** + * @file HttpSettings.h + * + * @brief + * + * Copyright (C) 2013 + * + * @author Francois Ferrand + * @date 4/2013 + *************************************************************************** + */ + +#ifndef HTTPSETTINGS_H +#define HTTPSETTINGS_H + +#include "core/PasswordGenerator.h" + +class HttpSettings +{ +public: + static bool isEnabled(); + static void setEnabled(bool enabled); + + static bool showNotification(); //TODO!! + static void setShowNotification(bool showNotification); + static bool bestMatchOnly(); //TODO!! + static void setBestMatchOnly(bool bestMatchOnly); + static bool unlockDatabase(); //TODO!! + static void setUnlockDatabase(bool unlockDatabase); + static bool matchUrlScheme(); + static void setMatchUrlScheme(bool matchUrlScheme); + static bool sortByUsername(); + static void setSortByUsername(bool sortByUsername = true); + static bool sortByTitle(); + static void setSortByTitle(bool sortByUsertitle = true); + static bool alwaysAllowAccess(); + static void setAlwaysAllowAccess(bool alwaysAllowAccess); + static bool alwaysAllowUpdate(); + static void setAlwaysAllowUpdate(bool alwaysAllowUpdate); + static bool searchInAllDatabases();//TODO!! + static void setSearchInAllDatabases(bool searchInAllDatabases); + static bool supportKphFields(); + static void setSupportKphFields(bool supportKphFields); + + static bool passwordUseNumbers(); + static void setPasswordUseNumbers(bool useNumbers); + static bool passwordUseLowercase(); + static void setPasswordUseLowercase(bool useLowercase); + static bool passwordUseUppercase(); + static void setPasswordUseUppercase(bool useUppercase); + static bool passwordUseSpecial(); + static void setPasswordUseSpecial(bool useSpecial); + static bool passwordEveryGroup(); + static void setPasswordEveryGroup(bool everyGroup); + static bool passwordExcludeAlike(); + static void setPasswordExcludeAlike(bool excludeAlike); + static int passwordLength(); + static void setPasswordLength(int length); + static PasswordGenerator::CharClasses passwordCharClasses(); + static PasswordGenerator::GeneratorFlags passwordGeneratorFlags(); +}; + +#endif // HTTPSETTINGS_H diff --git a/src/http/OptionDialog.cpp b/src/http/OptionDialog.cpp new file mode 100644 index 000000000..29ebeaa1a --- /dev/null +++ b/src/http/OptionDialog.cpp @@ -0,0 +1,81 @@ +/** + *************************************************************************** + * @file OptionDialog.cpp + * + * @brief + * + * Copyright (C) 2013 + * + * @author Francois Ferrand + * @date 4/2013 + *************************************************************************** + */ + +#include "OptionDialog.h" +#include "ui_OptionDialog.h" +#include "HttpSettings.h" + +OptionDialog::OptionDialog(QWidget *parent) : + QWidget(parent), + ui(new Ui::OptionDialog) +{ + ui->setupUi(this); + connect(ui->removeSharedEncryptionKeys, SIGNAL(clicked()), this, SIGNAL(removeSharedEncryptionKeys())); + connect(ui->removeStoredPermissions, SIGNAL(clicked()), this, SIGNAL(removeStoredPermissions())); +} + +OptionDialog::~OptionDialog() +{ + delete ui; +} + +void OptionDialog::loadSettings() +{ + HttpSettings settings; + ui->enableHttpServer->setChecked(settings.isEnabled()); + + ui->showNotification->setChecked(settings.showNotification()); + ui->bestMatchOnly->setChecked(settings.bestMatchOnly()); + ui->unlockDatabase->setChecked(settings.unlockDatabase()); + ui->matchUrlScheme->setChecked(settings.matchUrlScheme()); + if (settings.sortByUsername()) + ui->sortByUsername->setChecked(true); + else + ui->sortByTitle->setChecked(true); + + ui->checkBoxLower->setChecked(settings.passwordUseLowercase()); + ui->checkBoxNumbers->setChecked(settings.passwordUseNumbers()); + ui->checkBoxUpper->setChecked(settings.passwordUseUppercase()); + ui->checkBoxSpecialChars->setChecked(settings.passwordUseSpecial()); + ui->checkBoxEnsureEvery->setChecked(settings.passwordEveryGroup()); + ui->checkBoxExcludeAlike->setChecked(settings.passwordExcludeAlike()); + ui->spinBoxLength->setValue(settings.passwordLength()); + + ui->alwaysAllowAccess->setChecked(settings.alwaysAllowAccess()); + ui->alwaysAllowUpdate->setChecked(settings.alwaysAllowUpdate()); + ui->searchInAllDatabases->setChecked(settings.searchInAllDatabases()); +} + +void OptionDialog::saveSettings() +{ + HttpSettings settings; + settings.setEnabled(ui->enableHttpServer->isChecked()); + + settings.setShowNotification(ui->showNotification->isChecked()); + settings.setBestMatchOnly(ui->bestMatchOnly->isChecked()); + settings.setUnlockDatabase(ui->unlockDatabase->isChecked()); + settings.setMatchUrlScheme(ui->matchUrlScheme->isChecked()); + settings.setSortByUsername(ui->sortByUsername->isChecked()); + + settings.setPasswordUseLowercase(ui->checkBoxLower->isChecked()); + settings.setPasswordUseNumbers(ui->checkBoxNumbers->isChecked()); + settings.setPasswordUseUppercase(ui->checkBoxUpper->isChecked()); + settings.setPasswordUseSpecial(ui->checkBoxSpecialChars->isChecked()); + settings.setPasswordEveryGroup(ui->checkBoxEnsureEvery->isChecked()); + settings.setPasswordExcludeAlike(ui->checkBoxExcludeAlike->isChecked()); + settings.setPasswordLength(ui->spinBoxLength->value()); + + settings.setAlwaysAllowAccess(ui->alwaysAllowAccess->isChecked()); + settings.setAlwaysAllowUpdate(ui->alwaysAllowUpdate->isChecked()); + settings.setSearchInAllDatabases(ui->searchInAllDatabases->isChecked()); +} diff --git a/src/http/OptionDialog.h b/src/http/OptionDialog.h new file mode 100644 index 000000000..e7508d233 --- /dev/null +++ b/src/http/OptionDialog.h @@ -0,0 +1,43 @@ +/** + *************************************************************************** + * @file OptionDialog.h + * + * @brief + * + * Copyright (C) 2013 + * + * @author Francois Ferrand + * @date 4/2013 + *************************************************************************** + */ + +#ifndef OPTIONDIALOG_H +#define OPTIONDIALOG_H + +#include + +namespace Ui { +class OptionDialog; +} + +class OptionDialog : public QWidget +{ + Q_OBJECT + +public: + explicit OptionDialog(QWidget *parent = 0); + ~OptionDialog(); + +public Q_SLOTS: + void loadSettings(); + void saveSettings(); + +Q_SIGNALS: + void removeSharedEncryptionKeys(); + void removeStoredPermissions(); + +private: + Ui::OptionDialog *ui; +}; + +#endif // OPTIONDIALOG_H diff --git a/src/http/OptionDialog.ui b/src/http/OptionDialog.ui new file mode 100644 index 000000000..621b94836 --- /dev/null +++ b/src/http/OptionDialog.ui @@ -0,0 +1,305 @@ + + + OptionDialog + + + + 0 + 0 + 463 + 354 + + + + Dialog + + + + + + Support KeypassHttp protocol +This is required for accessing keypass database from ChromeIPass or PassIfox + + + + + + + QTabWidget::Rounded + + + 0 + + + + General + + + + + + Sh&ow a notification when credentials are requested + + + + + + + &Return only best matching entries for an URL instead +of all entries for the whole domain + + + + + + + Re&quest for unlocking the database if it is locked + + + + + + + &Match URL schemes +Only entries with the same scheme (http://, https://, ftp://, ...) are returned + + + + + + + Sort matching entries by &username + + + + + + + Sort matching entries by &title + + + + + + + R&emove all shared encryption-keys from active database + + + + + + + Re&move all stored permissions from entries in active database + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + Password generator + + + + + + + + + + Lower letters + + + + + + + Numbers + + + + + + + Upper letters + + + + + + + Special characters + + + + + + + + + + + Ensure that the password contains characters from every group + + + + + + + Exclude look-alike characters + + + + + + + + + Length: + + + + + + + 1 + + + 999 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + Advanced + + + + + + + 75 + true + + + + color: rgb(255, 0, 0); + + + Activate the following only, if you know what you are doing! + + + + + + + Always allow &access to entries + + + + + + + Always allow &updating entries + + + + + + + Searc&h in all opened databases for matching entries + + + + + + + Only the selected database has to be connected with a client! + + + 30 + + + + + + + &Return also advanced string fields which start with "KPH: " + + + + + + + Automatic creates or updates are not supported for string fields! + + + 30 + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + diff --git a/src/http/Service.cpp b/src/http/Service.cpp index aa3e93ed8..b13ba3fad 100644 --- a/src/http/Service.cpp +++ b/src/http/Service.cpp @@ -20,6 +20,7 @@ #include "Protocol.h" #include "EntryConfig.h" #include "AccessControlDialog.h" +#include "HttpSettings.h" #include "core/Database.h" #include "core/Entry.h" @@ -28,13 +29,6 @@ #include "core/Uuid.h" #include "core/PasswordGenerator.h" - -Service::Service(DatabaseTabWidget* parent) : - KeepassHttpProtocol::Server(parent), - m_dbTabWidget(parent) -{ -} - static const unsigned char KEEPASSHTTP_UUID_DATA[] = { 0x34, 0x69, 0x7a, 0x40, 0x8a, 0x5b, 0x41, 0xc0, 0x9f, 0x36, 0x89, 0x7d, 0x62, 0x3e, 0xcb, 0x31 @@ -46,6 +40,14 @@ static const char KEEPASSHTTP_GROUP_NAME[] = "KeePassHttp Passwords"; //Group static int KEEPASSHTTP_DEFAULT_ICON = 1; //private const int DEFAULT_NOTIFICATION_TIME = 5000; +Service::Service(DatabaseTabWidget* parent) : + KeepassHttpProtocol::Server(parent), + m_dbTabWidget(parent) +{ + if (HttpSettings::isEnabled()) + start(); +} + Entry* Service::getConfigEntry(bool create) { if (DatabaseWidget * dbWidget = m_dbTabWidget->currentDatabaseWidget()) @@ -85,11 +87,13 @@ bool Service::isDatabaseOpened() const bool Service::openDatabase() { + if (!HttpSettings::unlockDatabase()) + return false; if (DatabaseWidget * dbWidget = m_dbTabWidget->currentDatabaseWidget()) if (dbWidget->currentMode() == DatabaseWidget::LockedMode) { //- show notification - //- open window - //- wait a few seconds for user to unlock... + //- open & focus main window + //- wait a few seconds for user to unlock (unlockedDatabase) } return false; } @@ -206,10 +210,8 @@ Service::Access Service::checkAccess(const Entry *entry, const QString & host, c KeepassHttpProtocol::Entry Service::prepareEntry(const Entry* entry) { - bool returnStringFields = true; //TODO: setting! KeepassHttpProtocol::Entry res(entry->title(), entry->username(), entry->password(), entry->uuid().toHex()); - if (returnStringFields) - { + if (HttpSettings::supportKphFields()) { const EntryAttributes * attr = entry->attributes(); Q_FOREACH (const QString& key, attr->keys()) if (key.startsWith(QLatin1String("KPH: "))) @@ -273,7 +275,7 @@ private: QList Service::findMatchingEntries(const QString& /*id*/, const QString& url, const QString& submitUrl, const QString& realm) { - const bool autoAccept = false; //TODO: setting! + const bool alwaysAllowAccess = HttpSettings::alwaysAllowAccess(); const QString host = QUrl(url).host(); const QString submitHost = QUrl(submitUrl).host(); @@ -286,7 +288,7 @@ QList Service::findMatchingEntries(const QString& /* continue; case Unknown: - if (autoAccept) + if (alwaysAllowAccess) pwEntries.append(entry); else pwEntriesToConfirm.append(entry); @@ -346,8 +348,7 @@ QList Service::findMatchingEntries(const QString& /* priorities.insert(entry, sortPriority(entry, host, submitUrl, baseSubmitURL)); //Sort by priorities - const bool sortByTitle = true; //TODO: setting - qSort(pwEntries.begin(), pwEntries.end(), SortEntries(priorities, sortByTitle ? "Title" : "UserName")); + qSort(pwEntries.begin(), pwEntries.end(), SortEntries(priorities, HttpSettings::sortByTitle() ? "Title" : "UserName")); } //Fill the list @@ -427,8 +428,7 @@ void Service::updateEntry(const QString &id, const QString &uuid, const QString if (Entry * entry = db->resolveEntry(Uuid::fromHex(uuid))) { QString u = entry->username(); if (u != login || entry->password() != password) { - bool autoAllow = false; //TODO: setting to request confirmation/auto-allow - if ( autoAllow + if ( HttpSettings::alwaysAllowUpdate() || QMessageBox::warning(0, tr("KeyPassX/Http: Update Entry"), tr("Do you want to update the information in %1 - %2?").arg(QUrl(url).host()).arg(u), QMessageBox::Yes|QMessageBox::No) == QMessageBox::Yes ) { @@ -444,10 +444,9 @@ void Service::updateEntry(const QString &id, const QString &uuid, const QString QString Service::generatePassword() { PasswordGenerator * pwGenerator = passwordGenerator(); - //TODO: password generator settings - return pwGenerator->generatePassword(20, - PasswordGenerator::LowerLetters | PasswordGenerator::UpperLetters | PasswordGenerator::Numbers, - PasswordGenerator::ExcludeLookAlike | PasswordGenerator::CharFromEveryGroup); + return pwGenerator->generatePassword(HttpSettings::passwordLength(), + HttpSettings::passwordCharClasses(), + HttpSettings::passwordGeneratorFlags()); } void Service::removeSharedEncryptionKeys()