From 6ecc18d9853073031f7e0ab02c07932a1ec136fd Mon Sep 17 00:00:00 2001 From: Gary Wang Date: Sun, 13 Nov 2022 15:13:28 +0000 Subject: [PATCH] Add proxy config with Socks5 and HTTP proxy support Resolve https://invent.kde.org/network/neochat/-/issues/547 This patch attempts to add proxy config support to NeoChat so people could set a HTTP or Socks5 proxy for anonymity or privacy/censorship-circumvention reason. Currently this will only allows setting proxy type, host and port (which should be usable for most of the cases). Settings in that page needs to be applied by clicking the Apply button so the proxy setting won't accidentally get changed. Proxy is disabled (use System Default option) by default. --- .gitignore | 1 + src/CMakeLists.txt | 1 + src/controller.cpp | 29 ++++++++ src/controller.h | 2 + src/neochatconfig.kcfg | 25 +++++++ src/qml/Settings/NetworkProxyPage.qml | 97 +++++++++++++++++++++++++++ src/qml/Settings/SettingsPage.qml | 7 +- src/res.qrc | 1 + 8 files changed, 162 insertions(+), 1 deletion(-) create mode 100644 src/qml/Settings/NetworkProxyPage.qml diff --git a/.gitignore b/.gitignore index e89a2150b..5fb34c4c6 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ compile_commands.json .cache/ .vscode/ kate.project.ctags.* +*.user diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ac5cb3ac4..7a02f9046 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -140,6 +140,7 @@ if(ANDROID) "edit-copy" "gtk-quit" "compass" + "computer" "network-connect" "list-remove-user" "org.kde.neochat" diff --git a/src/controller.cpp b/src/controller.cpp index d77ea32f9..7c4e0bbb5 100644 --- a/src/controller.cpp +++ b/src/controller.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -65,6 +66,8 @@ Controller::Controller(QObject *parent) Connection::setRoomType(); Connection::setUserType(); + setApplicationProxy(); + #ifndef Q_OS_ANDROID if (NeoChatConfig::self()->systemTray()) { m_trayIcon = new TrayIcon(this); @@ -784,3 +787,29 @@ void Controller::forceRefreshTextDocument(QQuickTextDocument *textDocument, QQui // HACK: Workaround bug QTBUG 93281 connect(textDocument->textDocument(), SIGNAL(imagesLoaded()), item, SLOT(updateWholeDocument())); } + +void Controller::setApplicationProxy() +{ + NeoChatConfig *cfg = NeoChatConfig::self(); + QNetworkProxy proxy; + + // type match to ProxyType from neochatconfig.kcfg + switch (cfg->proxyType()) { + case 1: // HTTP + proxy.setType(QNetworkProxy::HttpProxy); + proxy.setHostName(cfg->proxyHost()); + proxy.setPort(cfg->proxyPort()); + break; + case 2: // SOCKS 5 + proxy.setType(QNetworkProxy::Socks5Proxy); + proxy.setHostName(cfg->proxyHost()); + proxy.setPort(cfg->proxyPort()); + break; + case 0: // System Default + default: + // do nothing + break; + } + + QNetworkProxy::setApplicationProxy(proxy); +} diff --git a/src/controller.h b/src/controller.h index c3069f2aa..9364788fe 100644 --- a/src/controller.h +++ b/src/controller.h @@ -99,6 +99,8 @@ public: Q_INVOKABLE void forceRefreshTextDocument(QQuickTextDocument *textDocument, QQuickItem *item); + Q_INVOKABLE void setApplicationProxy(); + private: explicit Controller(QObject *parent = nullptr); diff --git a/src/neochatconfig.kcfg b/src/neochatconfig.kcfg index 4c7e923eb..3743e3cc9 100644 --- a/src/neochatconfig.kcfg +++ b/src/neochatconfig.kcfg @@ -98,5 +98,30 @@ true + + + + + + + + + + + + + + System + + + + + 127.0.0.1 + + + + 1080 + + diff --git a/src/qml/Settings/NetworkProxyPage.qml b/src/qml/Settings/NetworkProxyPage.qml new file mode 100644 index 000000000..dd9169b11 --- /dev/null +++ b/src/qml/Settings/NetworkProxyPage.qml @@ -0,0 +1,97 @@ +// SPDX-FileCopyrightText: 2022 Gary Wang +// SPDX-License-Identifier: GPL-2.0-or-later OR LicenseRef-KDE-Accepted-LGPL + +import QtQuick 2.15 +import QtQuick.Controls 2.15 as QQC2 +import QtQuick.Layouts 1.15 + +import org.kde.kirigami 2.15 as Kirigami + +import org.kde.neochat 1.0 + +Kirigami.ScrollablePage { + title: i18nc("@title:window", "General") + property int currentType + property bool proxyConfigChanged: false + + ColumnLayout { + Kirigami.FormLayout { + Layout.fillWidth: true + + QQC2.RadioButton { + Kirigami.FormData.label: i18n("Network Proxy") + text: i18n("System Default") + checked: currentType === 0 + enabled: !Config.isProxyTypeImmutable + onToggled: { + currentType = 0 + } + } + QQC2.RadioButton { + text: i18n("HTTP") + checked: currentType === 1 + enabled: !Config.isProxyTypeImmutable + onToggled: { + currentType = 1 + } + } + QQC2.RadioButton { + text: i18n("Socks5") + checked: currentType === 2 + enabled: !Config.isProxyTypeImmutable + onToggled: { + currentType = 2 + } + } + QQC2.TextField { + id: hostField + Kirigami.FormData.label: i18n("Proxy Host") + text: Config.proxyHost + inputMethodHints: Qt.ImhUrlCharactersOnly + onEditingFinished: { + proxyConfigChanged = true + } + } + QQC2.SpinBox { + id: portField + Kirigami.FormData.label: i18n("Proxy Port") + value: Config.proxyPort + from: 0 + to: 65536 + validator: IntValidator {bottom: from; top: to} + textFromValue: function(value, locale) { + return value // it will add a thousands separator if we don't do this, not sure why + } + onValueChanged: { + proxyConfigChanged = true + } + } + } + } + + footer: QQC2.ToolBar { + height: visible ? implicitHeight : 0 + contentItem: RowLayout { + Item { + Layout.fillWidth: true + } + + QQC2.Button { + text: i18n("Apply") + enabled: currentType !== Config.proxyType || proxyConfigChanged + onClicked: { + Config.proxyType = currentType + Config.proxyHost = hostField.text + Config.proxyPort = portField.value + Config.save() + proxyConfigChanged = false + Controller.setApplicationProxy() + } + } + } + } + + Component.onCompleted: { + currentType = Config.proxyType + } +} diff --git a/src/qml/Settings/SettingsPage.qml b/src/qml/Settings/SettingsPage.qml index 0313d2c31..9a97d8ae3 100644 --- a/src/qml/Settings/SettingsPage.qml +++ b/src/qml/Settings/SettingsPage.qml @@ -34,8 +34,13 @@ Kirigami.CategorizedSettings { page: Qt.resolvedUrl("SonnetConfigPage.qml") }, Kirigami.SettingAction { - text: i18n("Devices") + text: i18n("Network Proxy") iconName: "network-connect" + page: Qt.resolvedUrl("NetworkProxyPage.qml") + }, + Kirigami.SettingAction { + text: i18n("Devices") + iconName: "computer" page: Qt.resolvedUrl("DevicesPage.qml") }, Kirigami.SettingAction { diff --git a/src/res.qrc b/src/res.qrc index f57e4a56a..c43f5b415 100644 --- a/src/res.qrc +++ b/src/res.qrc @@ -83,5 +83,6 @@ qml/Settings/DevicesPage.qml qml/Settings/About.qml qml/Settings/SonnetConfigPage.qml + qml/Settings/NetworkProxyPage.qml