diff --git a/client/configurators/v2ray_configurator.cpp b/client/configurators/v2ray_configurator.cpp index 4294f5ae..dbebe9b6 100644 --- a/client/configurators/v2ray_configurator.cpp +++ b/client/configurators/v2ray_configurator.cpp @@ -1,13 +1,70 @@ #include "v2ray_configurator.h" +#include +#include +#include +#include +#include + +#include "core/servercontroller.h" +#include "containers/containers_defs.h" + V2RayConfigurator::V2RayConfigurator(std::shared_ptr settings, std::shared_ptr serverController, QObject *parent) : ConfiguratorBase(settings, serverController, parent) { } -QString V2RayConfigurator::genCloakConfig(const ServerCredentials &credentials, DockerContainer container, +QString V2RayConfigurator::genV2RayConfig(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode) { - return ""; + ErrorCode e = ErrorCode::NoError; + + QString v2rayVmessClientUuid = m_serverController->getTextFileFromContainer(container, credentials, + amnezia::protocols::v2ray::v2rayKeyPath, &e); + v2rayVmessClientUuid.replace("\n", ""); + + if (e) { + if (errorCode) *errorCode = e; + return ""; + } + + QJsonObject config; + + QJsonObject inboundsSocks; + inboundsSocks.insert("protocol", "socks"); + inboundsSocks.insert("listen", "127.0.0.1"); + inboundsSocks.insert("port", 1080); //todo + QJsonObject socksSettings; + socksSettings.insert("auth", "noauth"); + socksSettings.insert("udp", true); + inboundsSocks.insert("settings", socksSettings); + + QJsonArray inbounds; + inbounds.push_back(inboundsSocks); + config.insert("inbounds", inbounds); + + + QJsonObject outboundsVmess; + outboundsVmess.insert("protocol", "vmess"); + QJsonObject vmessSettings; + QJsonObject vnext; + vnext.insert("address", credentials.hostName); + vnext.insert("port", 10086); //todo + QJsonObject users; + users.insert("id", v2rayVmessClientUuid); + vnext.insert("users", QJsonArray({users})); + vmessSettings.insert("vnext", QJsonArray({vnext})); + outboundsVmess.insert("settings", vmessSettings); + + QJsonArray outbounds; + outbounds.push_back(outboundsVmess); + config.insert("outbounds", outbounds); + + + QString textCfg = m_serverController->replaceVars(QJsonDocument(config).toJson(), + m_serverController->genVarsForScript(credentials, container, containerConfig)); + + // qDebug().noquote() << textCfg; + return textCfg; } diff --git a/client/configurators/v2ray_configurator.h b/client/configurators/v2ray_configurator.h index 48cb7025..5d952525 100644 --- a/client/configurators/v2ray_configurator.h +++ b/client/configurators/v2ray_configurator.h @@ -13,7 +13,7 @@ public: V2RayConfigurator(std::shared_ptr settings, std::shared_ptr serverController, QObject *parent = nullptr); - QString genCloakConfig(const ServerCredentials &credentials, DockerContainer container, + QString genV2RayConfig(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr); }; diff --git a/client/configurators/vpn_configurator.cpp b/client/configurators/vpn_configurator.cpp index 1433eeaa..9421bde6 100644 --- a/client/configurators/vpn_configurator.cpp +++ b/client/configurators/vpn_configurator.cpp @@ -5,6 +5,7 @@ #include "wireguard_configurator.h" #include "ikev2_configurator.h" #include "ssh_configurator.h" +#include "v2ray_configurator.h" #include #include @@ -24,6 +25,7 @@ VpnConfigurator::VpnConfigurator(std::shared_ptr settings, wireguardConfigurator = std::shared_ptr(new WireguardConfigurator(settings, serverController, this)); ikev2Configurator = std::shared_ptr(new Ikev2Configurator(settings, serverController, this)); sshConfigurator = std::shared_ptr(new SshConfigurator(settings, serverController, this)); + v2RayConfigurator = std::shared_ptr(new V2RayConfigurator(settings, serverController, this)); } QString VpnConfigurator::genVpnProtocolConfig(const ServerCredentials &credentials, @@ -45,6 +47,9 @@ QString VpnConfigurator::genVpnProtocolConfig(const ServerCredentials &credentia case Proto::Ikev2: return ikev2Configurator->genIkev2Config(credentials, container, containerConfig, errorCode); + case Proto::V2Ray: + return v2RayConfigurator->genV2RayConfig(credentials, container, containerConfig, errorCode); + default: return ""; } diff --git a/client/configurators/vpn_configurator.h b/client/configurators/vpn_configurator.h index 47bdc1fd..76df407c 100644 --- a/client/configurators/vpn_configurator.h +++ b/client/configurators/vpn_configurator.h @@ -13,6 +13,7 @@ class CloakConfigurator; class WireguardConfigurator; class Ikev2Configurator; class SshConfigurator; +class V2RayConfigurator; // Retrieve connection settings from server class VpnConfigurator : ConfiguratorBase @@ -43,6 +44,7 @@ public: std::shared_ptr wireguardConfigurator; std::shared_ptr ikev2Configurator; std::shared_ptr sshConfigurator; + std::shared_ptr v2RayConfigurator; }; #endif // VPN_CONFIGURATOR_H diff --git a/client/containers/containers_defs.cpp b/client/containers/containers_defs.cpp index 4319dc1c..a2c67638 100644 --- a/client/containers/containers_defs.cpp +++ b/client/containers/containers_defs.cpp @@ -46,7 +46,7 @@ QVector ContainerProps::protocolsForContainer(amnezia::DockerCon return { Proto::Ikev2 /*, Protocol::L2tp */}; case DockerContainer::V2Ray: - return { Proto::V2Ray }; + return { Proto::OpenVpn, Proto::V2Ray }; case DockerContainer::Dns: return { }; diff --git a/client/core/defs.h b/client/core/defs.h index 3f861401..fb0066cc 100644 --- a/client/core/defs.h +++ b/client/core/defs.h @@ -54,6 +54,7 @@ enum ErrorCode ShadowSocksExecutableMissing, CloakExecutableMissing, AmneziaServiceConnectionFailed, + V2RayExecutableMissing, ExecutableMissing, // VPN errors diff --git a/client/core/errorstrings.cpp b/client/core/errorstrings.cpp index 1e7eb395..653e6a97 100644 --- a/client/core/errorstrings.cpp +++ b/client/core/errorstrings.cpp @@ -42,6 +42,7 @@ QString errorString(ErrorCode code){ case (ShadowSocksExecutableMissing): return QObject::tr("ShadowSocks (ss-local) executable missing"); case (CloakExecutableMissing): return QObject::tr("Cloak (ck-client) executable missing"); case (AmneziaServiceConnectionFailed): return QObject::tr("Amnezia helper service error"); + case (V2RayExecutableMissing): return QObject::tr("V2Ray (v2ray) executable missing"); case (OpenSslFailed): return QObject::tr("OpenSSL failed"); // VPN errors diff --git a/client/core/servercontroller.cpp b/client/core/servercontroller.cpp index 375215b7..9d27bd60 100644 --- a/client/core/servercontroller.cpp +++ b/client/core/servercontroller.cpp @@ -667,6 +667,7 @@ ServerController::Vars ServerController::genVarsForScript(const ServerCredential const QJsonObject &ssConfig = config.value(ProtocolProps::protoToString(Proto::ShadowSocks)).toObject(); const QJsonObject &wireguarConfig = config.value(ProtocolProps::protoToString(Proto::WireGuard)).toObject(); const QJsonObject &sftpConfig = config.value(ProtocolProps::protoToString(Proto::Sftp)).toObject(); + const QJsonObject &v2RayConfig = config.value(ProtocolProps::protoToString(Proto::V2Ray)).toObject(); // Vars vars; @@ -718,6 +719,10 @@ ServerController::Vars ServerController::genVarsForScript(const ServerCredential vars.append({{"$WIREGUARD_SERVER_PORT", wireguarConfig.value(config_key::port).toString(protocols::wireguard::defaultPort) }}); + // V2Ray vars + vars.append({{"$V2RAY_SERVER_PORT", v2RayConfig.value(config_key::port).toString(protocols::v2ray::defaultLocalPort) }}); + vars.append({{"$V2RAY_LOCAL_PORT", v2RayConfig.value(config_key::local_port).toString(protocols::v2ray::defaultServerPort) }}); + // IPsec vars vars.append({{"$IPSEC_VPN_L2TP_NET", "192.168.42.0/24"}}); vars.append({{"$IPSEC_VPN_L2TP_POOL", "192.168.42.10-192.168.42.250"}}); diff --git a/client/managementserver.cpp b/client/managementserver.cpp index c8e3b967..ba860941 100644 --- a/client/managementserver.cpp +++ b/client/managementserver.cpp @@ -49,9 +49,9 @@ void ManagementServer::onNewConnection() m_socket = QPointer(m_tcpServer->nextPendingConnection()); if (m_tcpServer) m_tcpServer->close(); - QObject::connect(m_socket.data(), SIGNAL(disconnected()), this, SLOT(onSocketDisconnected())); - QObject::connect(m_socket.data(), SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onSocketError(QAbstractSocket::SocketError))); - QObject::connect(m_socket.data(), SIGNAL(readyRead()), this, SLOT(onReadyRead())); + QObject::connect(m_socket.data(), &QTcpSocket::disconnected, this, &ManagementServer::onSocketDisconnected); + QObject::connect(m_socket.data(), &QTcpSocket::errorOccurred, this, &ManagementServer::onSocketError); + QObject::connect(m_socket.data(), &QTcpSocket::readyRead, this, &ManagementServer::onReadyRead); } void ManagementServer::onSocketError(QAbstractSocket::SocketError socketError) diff --git a/client/protocols/protocols_defs.cpp b/client/protocols/protocols_defs.cpp index 4479c524..e730f53b 100644 --- a/client/protocols/protocols_defs.cpp +++ b/client/protocols/protocols_defs.cpp @@ -116,7 +116,7 @@ int ProtocolProps::defaultPort(Proto p) case Proto::WireGuard : return 51820; case Proto::Ikev2 : return -1; case Proto::L2tp : return -1; - case Proto::V2Ray : return -1; + case Proto::V2Ray : return 10086; case Proto::TorWebSite : return -1; case Proto::Dns : return 53; @@ -181,7 +181,7 @@ bool ProtocolProps::defaultTransportProtoChangeable(Proto p) case Proto::Dns : return false; case Proto::FileShare : return false; case Proto::Sftp : return false; - default: return false; + default: return false; } } diff --git a/client/protocols/protocols_defs.h b/client/protocols/protocols_defs.h index 8df87b51..d25d85d1 100644 --- a/client/protocols/protocols_defs.h +++ b/client/protocols/protocols_defs.h @@ -124,6 +124,12 @@ constexpr char serverPskKeyPath[] = "/opt/amnezia/wireguard/wireguard_psk.key"; } +namespace v2ray { +constexpr char v2rayKeyPath[] = "/opt/amnezia/v2ray/v2ray.key"; +constexpr char defaultLocalPort[] = "1080"; +constexpr char defaultServerPort[] = "10086"; +} + namespace sftp { constexpr char defaultUserName[] = "sftp_user"; diff --git a/client/protocols/v2rayprotocol.cpp b/client/protocols/v2rayprotocol.cpp index 5afc6796..a004c8f4 100644 --- a/client/protocols/v2rayprotocol.cpp +++ b/client/protocols/v2rayprotocol.cpp @@ -1,33 +1,104 @@ #include "v2rayprotocol.h" +#include +#include +#include + #include "utilities.h" -V2RayProtocol::V2RayProtocol(const QJsonObject &configuration, QObject *parent) : VpnProtocol(configuration, parent) +V2RayProtocol::V2RayProtocol(const QJsonObject &configuration, QObject *parent) : OpenVpnProtocol(configuration, parent) { writeV2RayConfiguration(configuration); } V2RayProtocol::~V2RayProtocol() { - + qDebug() << "V2RayProtocol::~V2RayProtocol"; + V2RayProtocol::stop(); + QThread::msleep(200); } ErrorCode V2RayProtocol::start() { +#ifndef Q_OS_IOS + if (!QFileInfo::exists(v2RayExecPath())) { + setLastError(ErrorCode::V2RayExecutableMissing); + return lastError(); + } + + if (Utils::processIsRunning(Utils::executable("v2ray", false))) { + Utils::killProcessByName(Utils::executable("v2ray", false)); + } + + QStringList args = QStringList() << "-c" << m_v2RayConfigFile.fileName(); + + qDebug().noquote() << "ShadowSocksVpnProtocol::start()" + << v2RayExecPath() << args.join(" "); + + m_v2RayProcess.setProcessChannelMode(QProcess::MergedChannels); + + m_v2RayProcess.setProgram(v2RayExecPath()); + m_v2RayProcess.setArguments(args); + + connect(&m_v2RayProcess, &QProcess::readyReadStandardOutput, this, [this](){ + qDebug().noquote() << "v2ray:" << m_v2RayProcess.readAllStandardOutput(); + }); + + connect(&m_v2RayProcess, QOverload::of(&QProcess::finished), this, [this](int exitCode, QProcess::ExitStatus exitStatus) { + qDebug().noquote() << "V2RayProtocol finished, exitCode, exiStatus" << exitCode << exitStatus; + setConnectionState(VpnProtocol::Disconnected); + if (exitStatus != QProcess::NormalExit){ + emit protocolError(amnezia::ErrorCode::ShadowSocksExecutableCrashed); //todo + stop(); + } + if (exitCode != 0 ) { + emit protocolError(amnezia::ErrorCode::InternalError); + stop(); + } + }); + + m_v2RayProcess.start(); + m_v2RayProcess.waitForStarted(); + + if (m_v2RayProcess.state() == QProcess::ProcessState::Running) { + setConnectionState(VpnConnectionState::Connecting); + + return OpenVpnProtocol::start(); + } + else return ErrorCode::ShadowSocksExecutableMissing; +#else + return ErrorCode::NotImplementedError; +#endif return ErrorCode::NoError; } void V2RayProtocol::stop() { + OpenVpnProtocol::stop(); + qDebug() << "V2RayProtocol::stop()"; +#ifndef Q_OS_IOS + m_v2RayProcess.terminate(); +#endif + +#ifdef Q_OS_WIN + Utils::signalCtrl(m_v2RayProcess.processId(), CTRL_C_EVENT); +#endif } void V2RayProtocol::writeV2RayConfiguration(const QJsonObject &configuration) { + m_v2RayConfig = configuration.value(ProtocolProps::key_proto_config_data(Proto::V2Ray)).toObject(); +#ifdef QT_DEBUG + m_v2RayConfigFile.setAutoRemove(false); +#endif + m_v2RayConfigFile.open(); + m_v2RayConfigFile.write(QJsonDocument(m_v2RayConfig).toJson()); + m_v2RayConfigFile.close(); } -const QString V2RayProtocol::v2rayExecPath() const +const QString V2RayProtocol::v2RayExecPath() const { #ifdef Q_OS_WIN return Utils::executable(QString("v2ray/v2ray"), true); diff --git a/client/protocols/v2rayprotocol.h b/client/protocols/v2rayprotocol.h index 6ccb2dc5..9dcc75b2 100644 --- a/client/protocols/v2rayprotocol.h +++ b/client/protocols/v2rayprotocol.h @@ -1,9 +1,12 @@ #ifndef V2RAYPROTOCOL_H #define V2RAYPROTOCOL_H -#include "vpnprotocol.h" +#include "QProcess" +#include "QTemporaryFile" -class V2RayProtocol : public VpnProtocol +#include "openvpnprotocol.h" + +class V2RayProtocol : public OpenVpnProtocol { public: V2RayProtocol(const QJsonObject& configuration, QObject* parent = nullptr); @@ -13,10 +16,15 @@ public: void stop() override; private: - QJsonObject m_shadowSocksConfig; + QJsonObject m_v2RayConfig; + QTemporaryFile m_v2RayConfigFile; +#ifndef Q_OS_IOS + QProcess m_v2RayProcess; +#endif + void writeV2RayConfiguration(const QJsonObject &configuration); - const QString v2rayExecPath() const; + const QString v2RayExecPath() const; }; #endif // V2RAYPROTOCOL_H diff --git a/client/resources.qrc b/client/resources.qrc index 4651f91e..2acc3c22 100644 --- a/client/resources.qrc +++ b/client/resources.qrc @@ -164,5 +164,11 @@ images/svg/settings_suggest_black_24dp.svg server_scripts/website_tor/Dockerfile ui/qml/Controls/PopupWithQuestion.qml + ui/qml/Pages/Protocols/PageProtoV2Ray.qml + server_scripts/openvpn_v2ray_vmess/configure_container.sh + server_scripts/openvpn_v2ray_vmess/Dockerfile + server_scripts/openvpn_v2ray_vmess/run_container.sh + server_scripts/openvpn_v2ray_vmess/start.sh + server_scripts/openvpn_v2ray_vmess/template.ovpn diff --git a/client/server_scripts/build_container.sh b/client/server_scripts/build_container.sh index 2cda240c..5a8b5457 100644 --- a/client/server_scripts/build_container.sh +++ b/client/server_scripts/build_container.sh @@ -1 +1 @@ -sudo docker build -t $CONTAINER_NAME $DOCKERFILE_FOLDER --build-arg SERVER_ARCH=$(uname -m) +sudo docker build --network host -t $CONTAINER_NAME $DOCKERFILE_FOLDER --build-arg SERVER_ARCH=$(uname -m) diff --git a/client/server_scripts/openvpn_v2ray_vmess/configure_container.sh b/client/server_scripts/openvpn_v2ray_vmess/configure_container.sh index f07911e4..3358af7c 100644 --- a/client/server_scripts/openvpn_v2ray_vmess/configure_container.sh +++ b/client/server_scripts/openvpn_v2ray_vmess/configure_container.sh @@ -26,11 +26,15 @@ $OPENVPN_TLS_AUTH $OPENVPN_ADDITIONAL_SERVER_CONFIG EOF -# V2RAY_VMESS_PORT port for v2ray listening, for example 10086. +# V2RAY_SERVER_PORT port for v2ray listening, for example 10086. # V2RAY_VMESS_CLIENT_UUID client's id and secret as UUID. # UUID is 32 hexadecimal digits /([0-9a-f]-?){32}/ (128 bit value). mkdir -p /opt/amnezia/v2ray +cd /opt/amnezia/v2ray +V2RAY_VMESS_CLIENT_UUID="b831381d-6324-4d53-ad4f-8cda48b30811" # $(openssl rand -base64 32 | tr "=" "A" | tr "+" "A" | tr "/" "A") +echo $V2RAY_VMESS_CLIENT_UUID > /opt/amnezia/v2ray/v2ray.key + cat < /opt/amnezia/v2ray/v2ray-server.json < &action); diff --git a/client/ui/pages_logic/protocols/V2RayLogic.cpp b/client/ui/pages_logic/protocols/V2RayLogic.cpp new file mode 100644 index 00000000..9a3c6848 --- /dev/null +++ b/client/ui/pages_logic/protocols/V2RayLogic.cpp @@ -0,0 +1,127 @@ +#include "V2RayLogic.h" + +#include + +#include "core/servercontroller.h" +#include "ui/pages_logic/ServerConfiguringProgressLogic.h" +#include "ui/uilogic.h" + +using namespace amnezia; +using namespace PageEnumNS; + +V2RayLogic::V2RayLogic(UiLogic *logic, QObject *parent): + PageProtocolLogicBase(logic, parent), + m_comboBoxCipherText{"chacha20-poly1305"}, + m_lineEditPortText{}, + m_pushButtonSaveVisible{false}, + m_progressBarResetVisible{false}, + m_lineEditPortEnabled{false}, + m_labelInfoVisible{true}, + m_labelInfoText{}, + m_progressBarResetValue{0}, + m_progressBarResetMaximium{100} +{ + +} + +void V2RayLogic::updateProtocolPage(const QJsonObject &ssConfig, DockerContainer container, bool haveAuthData) +{ + set_pageEnabled(haveAuthData); + set_pushButtonSaveVisible(haveAuthData); + set_progressBarResetVisible(haveAuthData); + + set_comboBoxCipherText(ssConfig.value(config_key::cipher). + toString(protocols::shadowsocks::defaultCipher)); + + set_lineEditPortText(ssConfig.value(config_key::port). + toString(protocols::shadowsocks::defaultPort)); + + set_lineEditPortEnabled(container == DockerContainer::ShadowSocks); +} + +QJsonObject V2RayLogic::getProtocolConfigFromPage(QJsonObject oldConfig) +{ + oldConfig.insert(config_key::cipher, comboBoxCipherText()); + oldConfig.insert(config_key::port, lineEditPortText()); + + return oldConfig; +} + +void V2RayLogic::onPushButtonSaveClicked() +{ + QJsonObject protocolConfig = m_settings->protocolConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer, Proto::ShadowSocks); + + QJsonObject containerConfig = m_settings->containerConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer); + QJsonObject newContainerConfig = containerConfig; + newContainerConfig.insert(ProtocolProps::protoToString(Proto::ShadowSocks), protocolConfig); + ServerConfiguringProgressLogic::PageFunc pageFunc; + pageFunc.setEnabledFunc = [this] (bool enabled) -> void { + set_pageEnabled(enabled); + }; + ServerConfiguringProgressLogic::ButtonFunc saveButtonFunc; + saveButtonFunc.setVisibleFunc = [this] (bool visible) -> void { + set_pushButtonSaveVisible(visible); + }; + ServerConfiguringProgressLogic::LabelFunc waitInfoFunc; + waitInfoFunc.setVisibleFunc = [this] (bool visible) -> void { + set_labelInfoVisible(visible); + }; + waitInfoFunc.setTextFunc = [this] (const QString& text) -> void { + set_labelInfoText(text); + }; + ServerConfiguringProgressLogic::ProgressFunc progressBarFunc; + progressBarFunc.setVisibleFunc = [this] (bool visible) -> void { + set_progressBarResetVisible(visible); + }; + progressBarFunc.setValueFunc = [this] (int value) -> void { + set_progressBarResetValue(value); + }; + progressBarFunc.getValueFunc = [this] (void) -> int { + return progressBarResetValue(); + }; + progressBarFunc.getMaximiumFunc = [this] (void) -> int { + return progressBarResetMaximium(); + }; + progressBarFunc.setTextVisibleFunc = [this] (bool visible) -> void { + set_progressBarTextVisible(visible); + }; + progressBarFunc.setTextFunc = [this] (const QString& text) -> void { + set_progressBarText(text); + }; + + ServerConfiguringProgressLogic::LabelFunc busyInfoFuncy; + busyInfoFuncy.setTextFunc = [this] (const QString& text) -> void { + set_labelServerBusyText(text); + }; + busyInfoFuncy.setVisibleFunc = [this] (bool visible) -> void { + set_labelServerBusyVisible(visible); + }; + + ServerConfiguringProgressLogic::ButtonFunc cancelButtonFunc; + cancelButtonFunc.setVisibleFunc = [this] (bool visible) -> void { + set_pushButtonCancelVisible(visible); + }; + + progressBarFunc.setTextVisibleFunc(true); + progressBarFunc.setTextFunc(QString("Configuring...")); + ErrorCode e = uiLogic()->pageLogic()->doInstallAction([this, containerConfig, &newContainerConfig](){ + return m_serverController->updateContainer(m_settings->serverCredentials(uiLogic()->selectedServerIndex), + uiLogic()->selectedDockerContainer, + containerConfig, + newContainerConfig); + }, + pageFunc, progressBarFunc, + saveButtonFunc, waitInfoFunc, + busyInfoFuncy, cancelButtonFunc); + + if (!e) { + m_settings->setContainerConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer, newContainerConfig); + m_settings->clearLastConnectionConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer); + } + qDebug() << "Protocol saved with code:" << e << "for" << uiLogic()->selectedServerIndex << uiLogic()->selectedDockerContainer; +} + +void V2RayLogic::onPushButtonCancelClicked() +{ + emit uiLogic()->pageLogic()->cancelDoInstallAction(true); +} diff --git a/client/ui/pages_logic/protocols/V2RayLogic.h b/client/ui/pages_logic/protocols/V2RayLogic.h new file mode 100644 index 00000000..efc29572 --- /dev/null +++ b/client/ui/pages_logic/protocols/V2RayLogic.h @@ -0,0 +1,46 @@ +#ifndef V2RAYLOGIC_H +#define V2RAYLOGIC_H + +#include "PageProtocolLogicBase.h" + +class UiLogic; + +class V2RayLogic : public PageProtocolLogicBase +{ + Q_OBJECT + + AUTO_PROPERTY(QString, comboBoxCipherText) + AUTO_PROPERTY(QString, lineEditPortText) + AUTO_PROPERTY(bool, pushButtonSaveVisible) + AUTO_PROPERTY(bool, progressBarResetVisible) + AUTO_PROPERTY(bool, lineEditPortEnabled) + AUTO_PROPERTY(bool, labelInfoVisible) + AUTO_PROPERTY(QString, labelInfoText) + AUTO_PROPERTY(int, progressBarResetValue) + AUTO_PROPERTY(int, progressBarResetMaximium) + AUTO_PROPERTY(bool, progressBarTextVisible) + AUTO_PROPERTY(QString, progressBarText) + + AUTO_PROPERTY(bool, labelServerBusyVisible) + AUTO_PROPERTY(QString, labelServerBusyText) + + AUTO_PROPERTY(bool, pushButtonCancelVisible) + +public: + Q_INVOKABLE void onPushButtonSaveClicked(); + Q_INVOKABLE void onPushButtonCancelClicked(); + +public: + explicit V2RayLogic(UiLogic *uiLogic, QObject *parent = nullptr); + ~V2RayLogic() = default; + + void updateProtocolPage(const QJsonObject &ssConfig, DockerContainer container, bool haveAuthData) override; + QJsonObject getProtocolConfigFromPage(QJsonObject oldConfig) override; + +private: + UiLogic *m_uiLogic; + +}; + + +#endif // V2RAYLOGIC_H diff --git a/client/ui/qml/Pages/Protocols/PageProtoV2Ray.qml b/client/ui/qml/Pages/Protocols/PageProtoV2Ray.qml new file mode 100644 index 00000000..5560aee7 --- /dev/null +++ b/client/ui/qml/Pages/Protocols/PageProtoV2Ray.qml @@ -0,0 +1,5 @@ +import QtQuick + +Item { + +} diff --git a/client/ui/uilogic.cpp b/client/ui/uilogic.cpp index 3d442cab..bf4c45bb 100644 --- a/client/ui/uilogic.cpp +++ b/client/ui/uilogic.cpp @@ -73,6 +73,7 @@ #include "pages_logic/protocols/ShadowSocksLogic.h" #include "pages_logic/protocols/OtherProtocolsLogic.h" #include "pages_logic/protocols/WireGuardLogic.h" +#include "pages_logic/protocols/V2RayLogic.h" using namespace amnezia; using namespace PageEnumNS; @@ -96,6 +97,7 @@ UiLogic::UiLogic(std::shared_ptr settings, std::shared_ptr