dbhub: Add proxy configuration support

This adds a new dialog, accessible from the Remote tab in the Preferences
Dialog, which allows the user to configure the proxy to use for all
network connections.

The new default is to use the system-wide proxy settings.

See issue #979.
This commit is contained in:
Martin Kleusberg
2019-05-09 15:11:44 +02:00
parent 4cf6cb7c2a
commit 38ece2ea42
10 changed files with 397 additions and 7 deletions

View File

@@ -158,6 +158,7 @@ set(SQLB_MOC_HDR
src/Palette.h
src/CondFormat.h
src/RunSql.h
src/ProxyDialog.h
)
set(SQLB_SRC
@@ -211,6 +212,7 @@ set(SQLB_SRC
src/Palette.cpp
src/CondFormat.cpp
src/RunSql.cpp
src/ProxyDialog.cpp
)
set(SQLB_FORMS
@@ -234,6 +236,7 @@ set(SQLB_FORMS
src/FindReplaceDialog.ui
src/FileExtensionManager.ui
src/CondFormatManager.ui
src/ProxyDialog.ui
)
set(SQLB_RESOURCES

View File

@@ -6,6 +6,7 @@
#include "MainWindow.h"
#include "RemoteDatabase.h"
#include "FileExtensionManager.h"
#include "ProxyDialog.h"
#include <QDir>
#include <QColorDialog>
@@ -16,6 +17,7 @@
PreferencesDialog::PreferencesDialog(QWidget* parent, Tabs tab)
: QDialog(parent),
ui(new Ui::PreferencesDialog),
m_proxyDialog(new ProxyDialog(this)),
m_dbFileExtensions(Settings::getValue("General", "DBFileExtensions").toString().split(";;"))
{
ui->setupUi(this);
@@ -326,6 +328,8 @@ void PreferencesDialog::saveSettings()
Settings::setValue("General", "DBFileExtensions", m_dbFileExtensions.join(";;") );
m_proxyDialog->saveSettings();
accept();
QApplication::restoreOverrideCursor();
@@ -672,3 +676,8 @@ void PreferencesDialog::on_buttonBox_clicked(QAbstractButton* button)
}
}
}
void PreferencesDialog::configureProxy()
{
m_proxyDialog->show();
}

View File

@@ -8,6 +8,8 @@ class QFrame;
class QSslCertificate;
class QAbstractButton;
class ProxyDialog;
namespace Ui {
class PreferencesDialog;
}
@@ -44,12 +46,15 @@ private slots:
void chooseRemoteCloneDirectory();
void updatePreviewFont();
void adjustColorsToStyle(int style);
void configureProxy();
void on_buttonManageFileExtension_clicked();
void on_buttonBox_clicked(QAbstractButton* button);
private:
Ui::PreferencesDialog *ui;
Ui::PreferencesDialog* ui;
ProxyDialog* m_proxyDialog;
QStringList m_dbFileExtensions;

View File

@@ -1788,14 +1788,14 @@ Can be set to 0 for disabling completion.</string>
</item>
<item>
<layout class="QFormLayout" name="formLayout_5">
<item row="0" column="0">
<item row="1" column="0">
<widget class="QLabel" name="label_23">
<property name="text">
<string>Clone databases into</string>
</property>
</widget>
</item>
<item row="0" column="1">
<item row="1" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLineEdit" name="editRemoteCloneDirectory">
@@ -1825,6 +1825,20 @@ Can be set to 0 for disabling completion.</string>
</item>
</layout>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_21">
<property name="text">
<string>Proxy</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QToolButton" name="buttonProxy">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
@@ -2099,6 +2113,22 @@ Can be set to 0 for disabling completion.</string>
</hint>
</hints>
</connection>
<connection>
<sender>buttonProxy</sender>
<signal>clicked()</signal>
<receiver>PreferencesDialog</receiver>
<slot>configureProxy()</slot>
<hints>
<hint type="sourcelabel">
<x>385</x>
<y>591</y>
</hint>
<hint type="destinationlabel">
<x>385</x>
<y>306</y>
</hint>
</hints>
</connection>
</connections>
<slots>
<slot>saveSettings()</slot>
@@ -2110,5 +2140,6 @@ Can be set to 0 for disabling completion.</string>
<slot>addClientCertificate()</slot>
<slot>removeClientCertificate()</slot>
<slot>chooseRemoteCloneDirectory()</slot>
<slot>configureProxy()</slot>
</slots>
</ui>

57
src/ProxyDialog.cpp Normal file
View File

@@ -0,0 +1,57 @@
#include "ProxyDialog.h"
#include "ui_ProxyDialog.h"
#include "Settings.h"
ProxyDialog::ProxyDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::ProxyDialog)
{
ui->setupUi(this);
// Add different proxy types. We use user data strings for addressing them later
ui->comboType->addItem(tr("None"), "none");
ui->comboType->addItem(tr("System settings"), "system");
ui->comboType->addItem(tr("HTTP"), "http");
ui->comboType->addItem(tr("Socks v5"), "socks5");
// Load current settings
ui->comboType->setCurrentIndex(ui->comboType->findData(Settings::getValue("proxy", "type").toString()));
ui->editHost->setText(Settings::getValue("proxy", "host").toString());
ui->spinPort->setValue(Settings::getValue("proxy", "port").toInt());
ui->checkAuthentication->setChecked(Settings::getValue("proxy", "authentication").toBool());
ui->editUser->setText(Settings::getValue("proxy", "user").toString());
ui->editPassword->setText(Settings::getValue("proxy", "password").toString());
}
ProxyDialog::~ProxyDialog()
{
delete ui;
}
void ProxyDialog::proxyTypeChanged(int /*new_index*/)
{
// When selecting the "None" or "System settings" proxy types, disable all the other input fields
bool proxy_configuration = (ui->comboType->currentData() != "none" && ui->comboType->currentData() != "system");
ui->editHost->setEnabled(proxy_configuration);
ui->spinPort->setEnabled(proxy_configuration);
ui->checkAuthentication->setEnabled(proxy_configuration);
ui->editUser->setEnabled(ui->checkAuthentication->isChecked() && proxy_configuration); // Enable user name and password only if the...
ui->editPassword->setEnabled(ui->checkAuthentication->isChecked() && proxy_configuration); // ... Authentication Required checkbox is checked
}
void ProxyDialog::authenticationRequiredChanged(bool required)
{
ui->editUser->setEnabled(required);
ui->editPassword->setEnabled(required);
}
void ProxyDialog::saveSettings() const
{
Settings::setValue("proxy", "type", ui->comboType->currentData());
Settings::setValue("proxy", "host", ui->editHost->text());
Settings::setValue("proxy", "port", ui->spinPort->value());
Settings::setValue("proxy", "authentication", ui->checkAuthentication->isChecked());
Settings::setValue("proxy", "user", ui->editUser->text());
Settings::setValue("proxy", "password", ui->editPassword->text());
}

28
src/ProxyDialog.h Normal file
View File

@@ -0,0 +1,28 @@
#ifndef PROXYDIALOG_H
#define PROXYDIALOG_H
#include <QDialog>
namespace Ui {
class ProxyDialog;
}
class ProxyDialog : public QDialog
{
Q_OBJECT
public:
explicit ProxyDialog(QWidget* parent = nullptr);
~ProxyDialog();
void saveSettings() const;
private slots:
void proxyTypeChanged(int new_index);
void authenticationRequiredChanged(bool required);
private:
Ui::ProxyDialog* ui;
};
#endif

201
src/ProxyDialog.ui Normal file
View File

@@ -0,0 +1,201 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ProxyDialog</class>
<widget class="QDialog" name="ProxyDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>535</width>
<height>231</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Pro&amp;xy Type</string>
</property>
<property name="buddy">
<cstring>comboType</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="comboType"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Host Na&amp;me</string>
</property>
<property name="buddy">
<cstring>editHost</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="editHost"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Port</string>
</property>
<property name="buddy">
<cstring>spinPort</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="spinPort">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>65536</number>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Authentication Re&amp;quired</string>
</property>
<property name="buddy">
<cstring>checkAuthentication</cstring>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="checkAuthentication"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>&amp;User Name</string>
</property>
<property name="buddy">
<cstring>editUser</cstring>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="editUser"/>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Password</string>
</property>
<property name="buddy">
<cstring>editPassword</cstring>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLineEdit" name="editPassword">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>comboType</tabstop>
<tabstop>editHost</tabstop>
<tabstop>spinPort</tabstop>
<tabstop>checkAuthentication</tabstop>
<tabstop>editUser</tabstop>
<tabstop>editPassword</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>ProxyDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>227</x>
<y>210</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>230</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>ProxyDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>295</x>
<y>216</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>230</y>
</hint>
</hints>
</connection>
<connection>
<sender>comboType</sender>
<signal>currentIndexChanged(int)</signal>
<receiver>ProxyDialog</receiver>
<slot>proxyTypeChanged(int)</slot>
<hints>
<hint type="sourcelabel">
<x>343</x>
<y>22</y>
</hint>
<hint type="destinationlabel">
<x>267</x>
<y>115</y>
</hint>
</hints>
</connection>
<connection>
<sender>checkAuthentication</sender>
<signal>toggled(bool)</signal>
<receiver>ProxyDialog</receiver>
<slot>authenticationRequiredChanged(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>343</x>
<y>114</y>
</hint>
<hint type="destinationlabel">
<x>267</x>
<y>115</y>
</hint>
</hints>
</connection>
</connections>
<slots>
<slot>proxyTypeChanged(int)</slot>
<slot>authenticationRequiredChanged(bool)</slot>
</slots>
</ui>

View File

@@ -11,7 +11,9 @@
#include <QStandardPaths>
#include <QUrlQuery>
#include <QtNetwork/QHttpMultiPart>
#include <QtNetwork/QNetworkProxyFactory>
#include <QTimeZone>
#include <QtNetwork/QNetworkProxy>
#include <json.hpp>
#include <iterator>
@@ -90,7 +92,50 @@ void RemoteDatabase::reloadSettings()
m_clientCertFiles.insert({":/user_certs/public.cert.pem", cert});
}
// TODO Add support for proxies here
// Configure proxy to use
{
QString type = Settings::getValue("proxy", "type").toString();
QNetworkProxy proxy;
if(type == "system")
{
// For system settings we have to get the system-wide proxy and use that
// Get list of proxies for accessing dbhub.io via HTTPS and use the first one
auto list = QNetworkProxyFactory::systemProxyForQuery(QNetworkProxyQuery(QUrl("https://db4s.dbhub.io/")));
proxy = list.front();
} else {
// For any other type we have to set up our own proxy configuration
// Retrieve the required settings
QString host = Settings::getValue("proxy", "host").toString();
unsigned short port = static_cast<unsigned short>(Settings::getValue("proxy", "port").toUInt());
bool authentication = Settings::getValue("proxy", "authentication").toBool();
if(type == "http")
proxy.setType(QNetworkProxy::HttpProxy);
else if(type == "socks5")
proxy.setType(QNetworkProxy::Socks5Proxy);
else
proxy.setType(QNetworkProxy::NoProxy);
proxy.setHostName(host);
proxy.setPort(port);
// Only set authentication details when authentication is required
if(authentication)
{
QString user = Settings::getValue("proxy", "user").toString();
QString password = Settings::getValue("proxy", "password").toString();
proxy.setUser(user);
proxy.setPassword(password);
}
}
// Start using the new proxy configuration
QNetworkProxy::setApplicationProxy(proxy);
}
}
void RemoteDatabase::gotEncrypted(QNetworkReply* reply)

View File

@@ -346,6 +346,14 @@ QVariant Settings::getDefaultValue(const std::string& group, const std::string&
#endif
}
// Proxy settings
if(group == "proxy")
{
// Use system settings by default
if(name == "type")
return "system";
}
// Unknown combination of group and name? Return an invalid QVariant!
return QVariant();
}

View File

@@ -74,7 +74,8 @@ HEADERS += \
CondFormat.h \
sql/Query.h \
RunSql.h \
sql/ObjectIdentifier.h
sql/ObjectIdentifier.h \
ProxyDialog.h
SOURCES += \
sqlitedb.cpp \
@@ -125,7 +126,8 @@ SOURCES += \
CondFormat.cpp \
sql/Query.cpp \
RunSql.cpp \
sql/ObjectIdentifier.cpp
sql/ObjectIdentifier.cpp \
ProxyDialog.cpp
RESOURCES += icons/icons.qrc \
translations/flags/flags.qrc \
@@ -153,7 +155,8 @@ FORMS += \
RemotePushDialog.ui \
FindReplaceDialog.ui \
FileExtensionManager.ui \
CondFormatManager.ui
CondFormatManager.ui \
ProxyDialog.ui
TRANSLATIONS += \
translations/sqlb_ar_SA.ts \