diff --git a/client/client.pro b/client/client.pro index dc69962c..9ef13ea6 100644 --- a/client/client.pro +++ b/client/client.pro @@ -74,6 +74,7 @@ HEADERS += \ ui/pages_logic/protocols/OtherProtocolsLogic.h \ ui/pages_logic/protocols/PageProtocolLogicBase.h \ ui/pages_logic/protocols/ShadowSocksLogic.h \ + ui/pages_logic/protocols/WireGuardLogic.h \ ui/property_helper.h \ ui/models/servers_model.h \ ui/uilogic.h \ @@ -136,6 +137,7 @@ SOURCES += \ ui/pages_logic/protocols/PageProtocolLogicBase.cpp \ ui/pages_logic/protocols/ShadowSocksLogic.cpp \ ui/models/servers_model.cpp \ + ui/pages_logic/protocols/WireGuardLogic.cpp \ ui/uilogic.cpp \ ui/qautostart.cpp \ ui/models/sites_model.cpp \ diff --git a/client/protocols/protocols_defs.h b/client/protocols/protocols_defs.h index c158822d..c5f15d5b 100644 --- a/client/protocols/protocols_defs.h +++ b/client/protocols/protocols_defs.h @@ -58,6 +58,12 @@ constexpr char additional_server_config[] = "additional_server_config"; // proto config keys constexpr char last_config[] = "last_config"; + +constexpr char isThirdPartyConfig[] = "isThirdPartyConfig"; + +constexpr char openvpn[] = "openvpn"; +constexpr char wireguard[] = "wireguard"; + } namespace protocols { diff --git a/client/resources.qrc b/client/resources.qrc index a88ba030..0c325062 100644 --- a/client/resources.qrc +++ b/client/resources.qrc @@ -63,6 +63,7 @@ server_scripts/website_tor/run_container.sh ui/qml/main.qml ui/qml/TitleBar.qml + ui/qml/Pages/PageBase.qml ui/qml/Pages/PageAppSetting.qml ui/qml/Pages/PageGeneralSettings.qml ui/qml/Pages/PageNetworkSetting.qml @@ -81,6 +82,28 @@ ui/qml/Pages/PageSites.qml ui/qml/Pages/PageStart.qml ui/qml/Pages/PageVPN.qml + ui/qml/Pages/PageQrDecoder.qml + ui/qml/Pages/PageAbout.qml + ui/qml/Pages/PageQrDecoderIos.qml + ui/qml/Pages/PageViewConfig.qml + ui/qml/Pages/Protocols/PageProtoCloak.qml + ui/qml/Pages/Protocols/PageProtoOpenVPN.qml + ui/qml/Pages/Protocols/PageProtoShadowSocks.qml + ui/qml/Pages/Protocols/PageProtoSftp.qml + ui/qml/Pages/Protocols/PageProtoTorWebSite.qml + ui/qml/Pages/Protocols/PageProtocolBase.qml + ui/qml/Pages/Protocols/PageProtoWireGuard.qml + ui/qml/Pages/InstallSettings/InstallSettingsBase.qml + ui/qml/Pages/InstallSettings/SelectContainer.qml + ui/qml/Pages/Share/PageShareProtoCloak.qml + ui/qml/Pages/Share/PageShareProtocolBase.qml + ui/qml/Pages/Share/PageShareProtoOpenVPN.qml + ui/qml/Pages/Share/PageShareProtoSftp.qml + ui/qml/Pages/Share/PageShareProtoShadowSocks.qml + ui/qml/Pages/Share/PageShareProtoTorWebSite.qml + ui/qml/Pages/Share/PageShareProtoAmnezia.qml + ui/qml/Pages/Share/PageShareProtoWireGuard.qml + ui/qml/Pages/Share/PageShareProtoIkev2.qml ui/qml/Controls/BasicButtonType.qml ui/qml/Controls/BlueButtonType.qml ui/qml/Controls/CheckBoxType.qml @@ -92,57 +115,40 @@ ui/qml/Controls/ShareConnectionButtonType.qml ui/qml/Controls/ShareConnectionContent.qml ui/qml/Controls/TextFieldType.qml - ui/qml/Pages/PageBase.qml - ui/qml/Config/GlobalConfig.qml - ui/qml/Config/qmldir - images/background_connected.png - images/background_connected@2x.png - ui/qml/Pages/Protocols/PageProtoCloak.qml - ui/qml/Pages/Protocols/PageProtoOpenVPN.qml - ui/qml/Pages/Protocols/PageProtoShadowSocks.qml - ui/qml/Controls/BackButton.qml - ui/qml/Pages/InstallSettings/InstallSettingsBase.qml - ui/qml/Controls/Caption.qml - ui/qml/Controls/Logo.qml - ui/qml/Pages/InstallSettings/SelectContainer.qml - ui/qml/Pages/Protocols/PageProtocolBase.qml - images/delete.png + ui/qml/Controls/RichLabelType.qml + ui/qml/Controls/SvgImageType.qml + ui/qml/Controls/FlickableType.qml + ui/qml/Controls/UrlButtonType.qml + ui/qml/Controls/TextAreaType.qml + ui/qml/Controls/ContextMenu.qml ui/qml/Controls/FadeBehavior.qml ui/qml/Controls/VisibleBehavior.qml + ui/qml/Controls/Caption.qml + ui/qml/Controls/Logo.qml + ui/qml/Controls/BackButton.qml + ui/qml/Controls/ShareConnectionButtonCopyType.qml + ui/qml/Controls/SvgButtonType.qml + ui/qml/Config/GlobalConfig.qml + ui/qml/Config/qmldir server_scripts/dns/configure_container.sh server_scripts/dns/Dockerfile server_scripts/dns/run_container.sh server_scripts/sftp/configure_container.sh server_scripts/sftp/Dockerfile server_scripts/sftp/run_container.sh - ui/qml/Pages/Protocols/PageProtoSftp.qml - ui/qml/Pages/Protocols/PageProtoTorWebSite.qml server_scripts/ipsec/configure_container.sh server_scripts/ipsec/Dockerfile server_scripts/ipsec/run_container.sh server_scripts/ipsec/start.sh - ui/qml/Pages/Share/PageShareProtoCloak.qml - ui/qml/Pages/Share/PageShareProtocolBase.qml - ui/qml/Pages/Share/PageShareProtoOpenVPN.qml - ui/qml/Pages/Share/PageShareProtoSftp.qml - ui/qml/Pages/Share/PageShareProtoShadowSocks.qml - ui/qml/Pages/Share/PageShareProtoTorWebSite.qml - ui/qml/Controls/TextAreaType.qml - ui/qml/Controls/ContextMenu.qml - ui/qml/Pages/Share/PageShareProtoAmnezia.qml - ui/qml/Controls/ShareConnectionButtonCopyType.qml - ui/qml/Pages/Share/PageShareProtoWireGuard.qml server_scripts/ipsec/mobileconfig.plist - ui/qml/Pages/Share/PageShareProtoIkev2.qml server_scripts/ipsec/strongswan.profile + images/background_connected.png + images/background_connected@2x.png + images/delete.png images/animation.gif images/connected.png images/disconnected.png - ui/qml/Pages/PageQrDecoder.qml - ui/qml/Pages/PageAbout.qml - ui/qml/Controls/RichLabelType.qml images/svg/gpp_good_black_24dp.svg - ui/qml/Controls/SvgImageType.qml images/svg/gpp_maybe_black_24dp.svg images/svg/close_black_24dp.svg images/svg/delete_black_24dp.svg @@ -156,11 +162,6 @@ images/svg/vpn_key_black_24dp.svg images/svg/control_point_black_24dp.svg images/svg/settings_suggest_black_24dp.svg - ui/qml/Controls/SvgButtonType.qml - ui/qml/Pages/PageQrDecoderIos.qml server_scripts/website_tor/Dockerfile - ui/qml/Pages/PageViewConfig.qml - ui/qml/Controls/FlickableType.qml - ui/qml/Controls/UrlButtonType.qml diff --git a/client/ui/pages_logic/ServerContainersLogic.cpp b/client/ui/pages_logic/ServerContainersLogic.cpp index 27f865b5..4a7d2343 100644 --- a/client/ui/pages_logic/ServerContainersLogic.cpp +++ b/client/ui/pages_logic/ServerContainersLogic.cpp @@ -29,6 +29,7 @@ void ServerContainersLogic::onUpdatePage() ProtocolsModel *p_model = qobject_cast(uiLogic()->protocolsModel()); p_model->setSelectedServerIndex(uiLogic()->selectedServerIndex); + set_isManagedServer(m_settings->haveAuthData(uiLogic()->selectedServerIndex)); emit updatePage(); } diff --git a/client/ui/pages_logic/ServerContainersLogic.h b/client/ui/pages_logic/ServerContainersLogic.h index 3f2a26cd..d0081516 100644 --- a/client/ui/pages_logic/ServerContainersLogic.h +++ b/client/ui/pages_logic/ServerContainersLogic.h @@ -19,6 +19,8 @@ public: Q_INVOKABLE void onPushButtonRemoveClicked(DockerContainer c); Q_INVOKABLE void onPushButtonContinueClicked(DockerContainer c, int port, TransportProto tp); + AUTO_PROPERTY(bool, isManagedServer) + public: explicit ServerContainersLogic(UiLogic *uiLogic, QObject *parent = nullptr); ~ServerContainersLogic() = default; diff --git a/client/ui/pages_logic/ServerSettingsLogic.cpp b/client/ui/pages_logic/ServerSettingsLogic.cpp index 3b123174..22555a91 100644 --- a/client/ui/pages_logic/ServerSettingsLogic.cpp +++ b/client/ui/pages_logic/ServerSettingsLogic.cpp @@ -37,11 +37,17 @@ void ServerSettingsLogic::onUpdatePage() set_pushButtonShareFullVisible(m_settings->haveAuthData(uiLogic()->selectedServerIndex)); const QJsonObject &server = m_settings->server(uiLogic()->selectedServerIndex); const QString &port = server.value(config_key::port).toString(); - set_labelServerText(QString("%1@%2%3%4") - .arg(server.value(config_key::userName).toString()) - .arg(server.value(config_key::hostName).toString()) - .arg(port.isEmpty() ? "" : ":") - .arg(port)); + + const QString &userName = server.value(config_key::userName).toString(); + const QString &hostName = server.value(config_key::hostName).toString(); + QString name = QString("%1%2%3%4%5") + .arg(userName) + .arg(userName.isEmpty() ? "" : "@") + .arg(hostName) + .arg(port.isEmpty() ? "" : ":") + .arg(port); + + set_labelServerText(name); set_lineEditDescriptionText(server.value(config_key::description).toString()); DockerContainer selectedContainer = m_settings->defaultContainer(uiLogic()->selectedServerIndex); diff --git a/client/ui/pages_logic/StartPageLogic.cpp b/client/ui/pages_logic/StartPageLogic.cpp index ee02e582..98fe7c7e 100644 --- a/client/ui/pages_logic/StartPageLogic.cpp +++ b/client/ui/pages_logic/StartPageLogic.cpp @@ -15,6 +15,36 @@ #include "platforms/android/android_controller.h" #endif +namespace { +enum class ConfigTypes { + Amnezia, + OpenVpn, + WireGuard +}; + +ConfigTypes checkConfigFormat(const QString &config) +{ + const QString openVpnConfigPatternCli = "client"; + const QString openVpnConfigPatternProto1 = "proto tcp"; + const QString openVpnConfigPatternProto2 = "proto udp"; + const QString openVpnConfigPatternDriver1 = "dev tun"; + const QString openVpnConfigPatternDriver2 = "dev tap"; + + const QString wireguardConfigPatternSectionInterface = "[Interface]"; + const QString wireguardConfigPatternSectionPeer = "[Peer]"; + + if (config.contains(openVpnConfigPatternCli) && + (config.contains(openVpnConfigPatternProto1) || config.contains(openVpnConfigPatternProto2)) && + (config.contains(openVpnConfigPatternDriver1) || config.contains(openVpnConfigPatternDriver2))) { + return ConfigTypes::OpenVpn; + } else if (config.contains(wireguardConfigPatternSectionInterface) && + config.contains(wireguardConfigPatternSectionPeer)) + return ConfigTypes::WireGuard; + return ConfigTypes::Amnezia; +} + +} + StartPageLogic::StartPageLogic(UiLogic *logic, QObject *parent): PageLogicBase(logic, parent), m_pushButtonConnectEnabled{true}, @@ -135,15 +165,22 @@ void StartPageLogic::onPushButtonImport() void StartPageLogic::onPushButtonImportOpenFile() { - QString fileName = QFileDialog::getOpenFileName(Q_NULLPTR, tr("Open profile"), - QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), tr("*.vpn")); + QString fileName = QFileDialog::getOpenFileName(Q_NULLPTR, tr("Open config file"), + QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), "*.vpn *.ovpn *.conf"); if (fileName.isEmpty()) return; QFile file(fileName); file.open(QIODevice::ReadOnly); QByteArray data = file.readAll(); - importConnectionFromCode(QString(data)); + auto configFormat = checkConfigFormat(QString(data)); + if (configFormat == ConfigTypes::OpenVpn) { + importConnectionFromOpenVpnConfig(QString(data)); + } else if (configFormat == ConfigTypes::WireGuard) { + importConnectionFromWireguardConfig(QString(data)); + } else { + importConnectionFromCode(QString(data)); + } } bool StartPageLogic::importConnection(const QJsonObject &profile) @@ -205,3 +242,90 @@ bool StartPageLogic::importConnectionFromQr(const QByteArray &data) return false; } + +bool StartPageLogic::importConnectionFromOpenVpnConfig(const QString &config) +{ + QJsonObject openVpnConfig; + openVpnConfig[config_key::config] = config; + + QJsonObject lastConfig; + lastConfig[config_key::last_config] = QString(QJsonDocument(openVpnConfig).toJson()); + lastConfig[config_key::isThirdPartyConfig] = true; + + QJsonObject containers; + containers.insert(config_key::container, QJsonValue("amnezia-openvpn")); + containers.insert(config_key::openvpn, QJsonValue(lastConfig)); + + QJsonArray arr; + arr.push_back(containers); + + QString hostName; + const static QRegularExpression hostNameRegExp("remote (.*) [0-9]*"); + QRegularExpressionMatch hostNameMatch = hostNameRegExp.match(config); + if (hostNameMatch.hasMatch()) { + hostName = hostNameMatch.captured(1); + } + + QJsonObject o; + o[config_key::containers] = arr; + o[config_key::defaultContainer] = "amnezia-openvpn"; + o[config_key::description] = m_settings->nextAvailableServerName(); + + + const static QRegularExpression dnsRegExp("dhcp-option DNS (\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b)"); + QRegularExpressionMatchIterator dnsMatch = dnsRegExp.globalMatch(config); + if (dnsMatch.hasNext()) { + o[config_key::dns1] = dnsMatch.next().captured(1); + } + if (dnsMatch.hasNext()) { + o[config_key::dns2] = dnsMatch.next().captured(1); + } + + o[config_key::hostName] = hostName; + + return importConnection(o); +} + +bool StartPageLogic::importConnectionFromWireguardConfig(const QString &config) +{ + QJsonObject lastConfig; + lastConfig[config_key::config] = config; + + const static QRegularExpression hostNameAndPortRegExp("Endpoint = (.*):([0-9]*)"); + QRegularExpressionMatch hostNameAndPortMatch = hostNameAndPortRegExp.match(config); + QString hostName; + QString port; + if (hostNameAndPortMatch.hasMatch()) { + hostName = hostNameAndPortMatch.captured(1); + port = hostNameAndPortMatch.captured(2); + } + + QJsonObject wireguardConfig; + wireguardConfig[config_key::last_config] = QString(QJsonDocument(lastConfig).toJson()); + wireguardConfig[config_key::isThirdPartyConfig] = true; + wireguardConfig[config_key::port] = port; + wireguardConfig[config_key::transport_proto] = "udp"; + + QJsonObject containers; + containers.insert(config_key::container, QJsonValue("amnezia-wireguard")); + containers.insert(config_key::wireguard, QJsonValue(wireguardConfig)); + + QJsonArray arr; + arr.push_back(containers); + + QJsonObject o; + o[config_key::containers] = arr; + o[config_key::defaultContainer] = "amnezia-wireguard"; + o[config_key::description] = m_settings->nextAvailableServerName(); + + const static QRegularExpression dnsRegExp("DNS = (\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b).*(\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b)"); + QRegularExpressionMatch dnsMatch = dnsRegExp.match(config); + if (dnsMatch.hasMatch()) { + o[config_key::dns1] = dnsMatch.captured(1); + o[config_key::dns2] = dnsMatch.captured(2); + } + + o[config_key::hostName] = hostName; + + return importConnection(o); +} diff --git a/client/ui/pages_logic/StartPageLogic.h b/client/ui/pages_logic/StartPageLogic.h index 24bdc53f..d5e72edc 100644 --- a/client/ui/pages_logic/StartPageLogic.h +++ b/client/ui/pages_logic/StartPageLogic.h @@ -32,6 +32,8 @@ public: bool importConnection(const QJsonObject &profile); bool importConnectionFromCode(QString code); bool importConnectionFromQr(const QByteArray &data); + bool importConnectionFromOpenVpnConfig(const QString &config); + bool importConnectionFromWireguardConfig(const QString &config); public: explicit StartPageLogic(UiLogic *uiLogic, QObject *parent = nullptr); diff --git a/client/ui/pages_logic/ViewConfigLogic.cpp b/client/ui/pages_logic/ViewConfigLogic.cpp index 1dfe9abe..9ccd9d3e 100644 --- a/client/ui/pages_logic/ViewConfigLogic.cpp +++ b/client/ui/pages_logic/ViewConfigLogic.cpp @@ -13,6 +13,8 @@ void ViewConfigLogic::onUpdatePage() { set_configText(QJsonDocument(configJson()).toJson()); + auto s = configJson()[config_key::isThirdPartyConfig].toBool(); + m_openVpnLastConfigs = m_openVpnMalStrings = "