From 4407e2801b5ea204af2360ef5b921195951419f5 Mon Sep 17 00:00:00 2001 From: aiamnezia Date: Mon, 17 Feb 2025 21:35:08 +0400 Subject: [PATCH] feature: Add Kill Switch settings page with strict mode option --- client/resources.qrc | 1 + client/settings.cpp | 10 ++ client/settings.h | 4 + client/ui/controllers/pageController.h | 1 + client/ui/controllers/settingsController.cpp | 12 +++ client/ui/controllers/settingsController.h | 7 ++ client/ui/qml/Controls2/HeaderType.qml | 15 +++ .../ui/qml/Pages2/PageSettingsConnection.qml | 25 ++--- .../ui/qml/Pages2/PageSettingsKillSwitch.qml | 98 +++++++++++++++++++ 9 files changed, 155 insertions(+), 18 deletions(-) create mode 100644 client/ui/qml/Pages2/PageSettingsKillSwitch.qml diff --git a/client/resources.qrc b/client/resources.qrc index 38f0e79a..dc19cd15 100644 --- a/client/resources.qrc +++ b/client/resources.qrc @@ -197,6 +197,7 @@ ui/qml/Pages2/PageSettingsBackup.qml ui/qml/Pages2/PageSettingsConnection.qml ui/qml/Pages2/PageSettingsDns.qml + ui/qml/Pages2/PageSettingsKillSwitch.qml ui/qml/Pages2/PageSettingsLogging.qml ui/qml/Pages2/PageSettingsServerData.qml ui/qml/Pages2/PageSettingsServerInfo.qml diff --git a/client/settings.cpp b/client/settings.cpp index 7a572a13..c5679844 100644 --- a/client/settings.cpp +++ b/client/settings.cpp @@ -443,6 +443,16 @@ void Settings::setKillSwitchEnabled(bool enabled) setValue("Conf/killSwitchEnabled", enabled); } +bool Settings::isStrictKillSwitchEnabled() const +{ + return value("Conf/strictKillSwitchEnabled", false).toBool(); +} + +void Settings::setStrictKillSwitchEnabled(bool enabled) +{ + setValue("Conf/strictKillSwitchEnabled", enabled); +} + QString Settings::getInstallationUuid(const bool needCreate) { auto uuid = value("Conf/installationUuid", "").toString(); diff --git a/client/settings.h b/client/settings.h index f41f4d29..7f6d487e 100644 --- a/client/settings.h +++ b/client/settings.h @@ -213,6 +213,10 @@ public: bool isKillSwitchEnabled() const; void setKillSwitchEnabled(bool enabled); + + bool isStrictKillSwitchEnabled() const; + void setStrictKillSwitchEnabled(bool enabled); + QString getInstallationUuid(const bool needCreate); void resetGatewayEndpoint(); diff --git a/client/ui/controllers/pageController.h b/client/ui/controllers/pageController.h index ffbdd3a1..0894e5aa 100644 --- a/client/ui/controllers/pageController.h +++ b/client/ui/controllers/pageController.h @@ -31,6 +31,7 @@ namespace PageLoader PageSettingsLogging, PageSettingsSplitTunneling, PageSettingsAppSplitTunneling, + PageSettingsKillSwitch, PageServiceSftpSettings, PageServiceTorWebsiteSettings, diff --git a/client/ui/controllers/settingsController.cpp b/client/ui/controllers/settingsController.cpp index 6d777bd8..877d4a6e 100644 --- a/client/ui/controllers/settingsController.cpp +++ b/client/ui/controllers/settingsController.cpp @@ -245,6 +245,18 @@ bool SettingsController::isKillSwitchEnabled() void SettingsController::toggleKillSwitch(bool enable) { m_settings->setKillSwitchEnabled(enable); + emit killSwitchEnabledChanged(); +} + +bool SettingsController::isStrictKillSwitchEnabled() +{ + return m_settings->isStrictKillSwitchEnabled(); +} + +void SettingsController::toggleStrictKillSwitch(bool enable) +{ + m_settings->setStrictKillSwitchEnabled(enable); + emit strictKillSwitchEnabledChanged(); } bool SettingsController::isNotificationPermissionGranted() diff --git a/client/ui/controllers/settingsController.h b/client/ui/controllers/settingsController.h index efc18a7d..83d824a8 100644 --- a/client/ui/controllers/settingsController.h +++ b/client/ui/controllers/settingsController.h @@ -24,6 +24,8 @@ public: Q_PROPERTY(QString secondaryDns READ getSecondaryDns WRITE setSecondaryDns NOTIFY secondaryDnsChanged) Q_PROPERTY(bool isLoggingEnabled READ isLoggingEnabled WRITE toggleLogging NOTIFY loggingStateChanged) Q_PROPERTY(bool isNotificationPermissionGranted READ isNotificationPermissionGranted NOTIFY onNotificationStateChanged) + Q_PROPERTY(bool isKillSwitchEnabled READ isKillSwitchEnabled WRITE toggleKillSwitch NOTIFY killSwitchEnabledChanged) + Q_PROPERTY(bool strictKillSwitchEnabled READ isStrictKillSwitchEnabled WRITE toggleStrictKillSwitch NOTIFY strictKillSwitchEnabledChanged) Q_PROPERTY(bool isDevModeEnabled READ isDevModeEnabled NOTIFY devModeEnabled) Q_PROPERTY(QString gatewayEndpoint READ getGatewayEndpoint WRITE setGatewayEndpoint NOTIFY gatewayEndpointChanged) @@ -73,6 +75,9 @@ public slots: bool isKillSwitchEnabled(); void toggleKillSwitch(bool enable); + bool isStrictKillSwitchEnabled(); + void toggleStrictKillSwitch(bool enable); + bool isNotificationPermissionGranted(); void requestNotificationPermission(); @@ -93,6 +98,8 @@ signals: void primaryDnsChanged(); void secondaryDnsChanged(); void loggingStateChanged(); + void killSwitchEnabledChanged(); + void strictKillSwitchEnabledChanged(); void restoreBackupFinished(); void changeSettingsFinished(const QString &finishedMessage); diff --git a/client/ui/qml/Controls2/HeaderType.qml b/client/ui/qml/Controls2/HeaderType.qml index 1366148d..54f1386d 100644 --- a/client/ui/qml/Controls2/HeaderType.qml +++ b/client/ui/qml/Controls2/HeaderType.qml @@ -10,8 +10,11 @@ Item { property string actionButtonImage property var actionButtonFunction + property var switcherFunction + property bool showSwitcher: false property alias actionButton: headerActionButton + property alias switcher: headerSwitcher property string headerText property int headerTextMaximumLineCount: 2 @@ -56,6 +59,18 @@ Item { } } } + + SwitcherType { + id: headerSwitcher + Layout.alignment: Qt.AlignRight + visible: root.showSwitcher + + onToggled: { + if (switcherFunction && typeof switcherFunction === "function") { + switcherFunction(checked) + } + } + } } ParagraphTextType { diff --git a/client/ui/qml/Pages2/PageSettingsConnection.qml b/client/ui/qml/Pages2/PageSettingsConnection.qml index d3743b96..fe57d1c4 100644 --- a/client/ui/qml/Pages2/PageSettingsConnection.qml +++ b/client/ui/qml/Pages2/PageSettingsConnection.qml @@ -94,9 +94,7 @@ PageType { } } - DividerType { - visible: root.isAppSplitTinnelingEnabled - } + DividerType {} LabelWithButtonType { id: splitTunnelingButton2 @@ -119,29 +117,20 @@ PageType { visible: root.isAppSplitTinnelingEnabled } - SwitcherType { - id: killSwitchSwitcher + LabelWithButtonType { + id: killSwitchButton visible: !GC.isMobile() Layout.fillWidth: true - Layout.margins: 16 text: qsTr("KillSwitch") - descriptionText: qsTr("Disables your internet if your encrypted VPN connection drops out for any reason.") + descriptionText: qsTr("Blocks network connections without VPN") + rightImageSource: "qrc:/images/controls/chevron-right.svg" parentFlickable: fl - checked: SettingsController.isKillSwitchEnabled() - checkable: !ConnectionController.isConnected - onCheckedChanged: { - if (checked !== SettingsController.isKillSwitchEnabled()) { - SettingsController.toggleKillSwitch(checked) - } - } - onClicked: { - if (!checkable) { - PageController.showNotificationMessage(qsTr("Cannot change killSwitch settings during active connection")) - } + clickedFunction: function() { + PageController.goToPage(PageEnum.PageSettingsKillSwitch) } } diff --git a/client/ui/qml/Pages2/PageSettingsKillSwitch.qml b/client/ui/qml/Pages2/PageSettingsKillSwitch.qml new file mode 100644 index 00000000..62f8dd71 --- /dev/null +++ b/client/ui/qml/Pages2/PageSettingsKillSwitch.qml @@ -0,0 +1,98 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import PageEnum 1.0 +import Style 1.0 + +import "./" +import "../Controls2" +import "../Config" + +PageType { + id: root + + BackButtonType { + id: backButton + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.topMargin: 20 + } + + FlickableType { + id: fl + anchors.top: backButton.bottom + anchors.bottom: parent.bottom + contentHeight: content.height + + ColumnLayout { + id: content + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + + HeaderType { + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: qsTr("Kill Switch") + descriptionText: qsTr("Enable to ensure network traffic goes through a secure VPN tunnel, preventing accidental exposure of your IP and DNS queries if the connection drops") + + showSwitcher: true + switcher { + checked: SettingsController.isKillSwitchEnabled + enabled: !ConnectionController.isConnected + } + switcherFunction: function(checked) { + if (!ConnectionController.isConnected) { + SettingsController.isKillSwitchEnabled = checked + } else { + PageController.showNotificationMessage(qsTr("Cannot change killSwitch settings during active connection")) + switcher.checked = SettingsController.isKillSwitchEnabled + } + } + } + + VerticalRadioButton { + id: softKillSwitch + Layout.fillWidth: true + Layout.topMargin: 32 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + enabled: SettingsController.isKillSwitchEnabled && !ConnectionController.isConnected + checked: !SettingsController.strictKillSwitchEnabled + + text: qsTr("Soft Kill Switch") + descriptionText: qsTr("Internet connection is blocked if VPN connection drops accidentally") + + onClicked: { + SettingsController.strictKillSwitchEnabled = false + } + } + + DividerType {} + + VerticalRadioButton { + id: strictKillSwitch + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + enabled: SettingsController.isKillSwitchEnabled && !ConnectionController.isConnected + checked: SettingsController.strictKillSwitchEnabled + + text: qsTr("Strict Kill Switch") + descriptionText: qsTr("Internet connection is blocked even if VPN was turned off manually or not started") + + onClicked: { + SettingsController.strictKillSwitchEnabled = true + } + } + + DividerType {} + } + } +} \ No newline at end of file