diff --git a/client/configurators/v2ray_configurator.cpp b/client/configurators/v2ray_configurator.cpp index 0c26cd78..361182a6 100644 --- a/client/configurators/v2ray_configurator.cpp +++ b/client/configurators/v2ray_configurator.cpp @@ -21,20 +21,24 @@ QString V2RayConfigurator::genV2RayConfig(const ServerCredentials &credentials, { ErrorCode e = ErrorCode::NoError; - QString v2rayVmessClientUuid = m_serverController->getTextFileFromContainer(container, credentials, + QString v2RayVmessClientUuid = m_serverController->getTextFileFromContainer(container, credentials, amnezia::protocols::v2ray::v2rayKeyPath, &e); - v2rayVmessClientUuid.replace("\n", ""); + if (v2RayVmessClientUuid.isEmpty()) { + e = ErrorCode::V2RayKeyMissing; + return ""; + } + + v2RayVmessClientUuid.replace("\n", ""); if (e) { if (errorCode) *errorCode = e; return ""; } - QString v2RayClientConfig = m_serverController->replaceVars(amnezia::scriptData(ProtocolScriptType::v2ray_client_template, container), m_serverController->genVarsForScript(credentials, container, containerConfig)); - v2RayClientConfig.replace("$V2RAY_VMESS_CLIENT_UUID", v2rayVmessClientUuid); + v2RayClientConfig.replace("$V2RAY_VMESS_CLIENT_UUID", v2RayVmessClientUuid); v2RayClientConfig = m_serverController->replaceVars(v2RayClientConfig, m_serverController->genVarsForScript(credentials, container, containerConfig)); diff --git a/client/core/defs.h b/client/core/defs.h index fb0066cc..5a0f215b 100644 --- a/client/core/defs.h +++ b/client/core/defs.h @@ -67,7 +67,9 @@ enum ErrorCode OpenSslFailed, OpenVpnExecutableCrashed, ShadowSocksExecutableCrashed, - CloakExecutableCrashed + CloakExecutableCrashed, + V2RayExecutableCrashed, + V2RayKeyMissing }; } // namespace amnezia diff --git a/client/core/errorstrings.cpp b/client/core/errorstrings.cpp index 653e6a97..b660b4a4 100644 --- a/client/core/errorstrings.cpp +++ b/client/core/errorstrings.cpp @@ -42,9 +42,12 @@ 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"); + // V2Ray errors + case (V2RayExecutableMissing): return QObject::tr("V2Ray (v2ray) executable missing"); + case (V2RayKeyMissing): return QObject::tr("V2Ray key missing"); + // VPN errors case (OpenVpnAdaptersInUseError): return QObject::tr("Can't connect: another VPN connection is active"); case (OpenVpnTapAdapterError): return QObject::tr("Can't setup OpenVPN TAP network adapter"); diff --git a/client/protocols/v2rayprotocol.cpp b/client/protocols/v2rayprotocol.cpp index a004c8f4..1cbaa986 100644 --- a/client/protocols/v2rayprotocol.cpp +++ b/client/protocols/v2rayprotocol.cpp @@ -32,7 +32,7 @@ ErrorCode V2RayProtocol::start() QStringList args = QStringList() << "-c" << m_v2RayConfigFile.fileName(); - qDebug().noquote() << "ShadowSocksVpnProtocol::start()" + qDebug().noquote() << "V2RayProtocol::start()" << v2RayExecPath() << args.join(" "); m_v2RayProcess.setProcessChannelMode(QProcess::MergedChannels); @@ -41,14 +41,14 @@ ErrorCode V2RayProtocol::start() m_v2RayProcess.setArguments(args); connect(&m_v2RayProcess, &QProcess::readyReadStandardOutput, this, [this](){ - qDebug().noquote() << "v2ray:" << m_v2RayProcess.readAllStandardOutput(); + 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 + emit protocolError(amnezia::ErrorCode::V2RayExecutableCrashed); stop(); } if (exitCode != 0 ) { @@ -64,8 +64,7 @@ ErrorCode V2RayProtocol::start() setConnectionState(VpnConnectionState::Connecting); return OpenVpnProtocol::start(); - } - else return ErrorCode::ShadowSocksExecutableMissing; + } else return ErrorCode::V2RayExecutableMissing; #else return ErrorCode::NotImplementedError; #endif diff --git a/client/server_scripts/openvpn_v2ray_vmess/template.ovpn b/client/server_scripts/openvpn_v2ray_vmess/template.ovpn index fdbda078..efd4228c 100644 --- a/client/server_scripts/openvpn_v2ray_vmess/template.ovpn +++ b/client/server_scripts/openvpn_v2ray_vmess/template.ovpn @@ -19,7 +19,6 @@ dhcp-option DNS $PRIMARY_DNS dhcp-option DNS $SECONDARY_DNS block-outside-dns -# TODO test next 3 lines for (feature/v2ray-container) socks-proxy 127.0.0.1 $V2RAY_SOCKS_LOCAL_PORT route $REMOTE_HOST 255.255.255.255 net_gateway remote 127.0.0.1 $OPENVPN_PORT diff --git a/client/ui/pages_logic/protocols/ShadowSocksLogic.cpp b/client/ui/pages_logic/protocols/ShadowSocksLogic.cpp index 94a8ee04..c6f22c44 100644 --- a/client/ui/pages_logic/protocols/ShadowSocksLogic.cpp +++ b/client/ui/pages_logic/protocols/ShadowSocksLogic.cpp @@ -104,15 +104,16 @@ void ShadowSocksLogic::onPushButtonSaveClicked() progressBarFunc.setTextVisibleFunc(true); progressBarFunc.setTextFunc(QString("Configuring...")); - ErrorCode e = uiLogic()->pageLogic()->doInstallAction([this, containerConfig, &newContainerConfig](){ + + auto installAction = [this, containerConfig, &newContainerConfig](){ return m_serverController->updateContainer(m_settings->serverCredentials(uiLogic()->selectedServerIndex), uiLogic()->selectedDockerContainer, containerConfig, newContainerConfig); - }, - pageFunc, progressBarFunc, - saveButtonFunc, waitInfoFunc, - busyInfoFuncy, cancelButtonFunc); + }; + ErrorCode e = uiLogic()->pageLogic()->doInstallAction(installAction, pageFunc, progressBarFunc, + saveButtonFunc, waitInfoFunc, + busyInfoFuncy, cancelButtonFunc); if (!e) { m_settings->setContainerConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer, newContainerConfig); diff --git a/client/ui/pages_logic/protocols/V2RayLogic.cpp b/client/ui/pages_logic/protocols/V2RayLogic.cpp index 9a3c6848..148a9773 100644 --- a/client/ui/pages_logic/protocols/V2RayLogic.cpp +++ b/client/ui/pages_logic/protocols/V2RayLogic.cpp @@ -11,7 +11,6 @@ using namespace PageEnumNS; V2RayLogic::V2RayLogic(UiLogic *logic, QObject *parent): PageProtocolLogicBase(logic, parent), - m_comboBoxCipherText{"chacha20-poly1305"}, m_lineEditPortText{}, m_pushButtonSaveVisible{false}, m_progressBarResetVisible{false}, @@ -24,36 +23,31 @@ V2RayLogic::V2RayLogic(UiLogic *logic, QObject *parent): } -void V2RayLogic::updateProtocolPage(const QJsonObject &ssConfig, DockerContainer container, bool haveAuthData) +void V2RayLogic::updateProtocolPage(const QJsonObject &v2RayConfig, 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(v2RayConfig.value(config_key::port). + toString(protocols::v2ray::defaultServerPort)); - set_lineEditPortText(ssConfig.value(config_key::port). - toString(protocols::shadowsocks::defaultPort)); - - set_lineEditPortEnabled(container == DockerContainer::ShadowSocks); + set_lineEditPortEnabled(container == DockerContainer::V2Ray); } 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 protocolConfig = m_settings->protocolConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer, Proto::V2Ray); QJsonObject containerConfig = m_settings->containerConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer); QJsonObject newContainerConfig = containerConfig; - newContainerConfig.insert(ProtocolProps::protoToString(Proto::ShadowSocks), protocolConfig); + newContainerConfig.insert(ProtocolProps::protoToString(Proto::V2Ray), protocolConfig); ServerConfiguringProgressLogic::PageFunc pageFunc; pageFunc.setEnabledFunc = [this] (bool enabled) -> void { set_pageEnabled(enabled); @@ -104,13 +98,15 @@ void V2RayLogic::onPushButtonSaveClicked() progressBarFunc.setTextVisibleFunc(true); progressBarFunc.setTextFunc(QString("Configuring...")); - ErrorCode e = uiLogic()->pageLogic()->doInstallAction([this, containerConfig, &newContainerConfig](){ + + auto installAction = [this, containerConfig, &newContainerConfig]() { return m_serverController->updateContainer(m_settings->serverCredentials(uiLogic()->selectedServerIndex), uiLogic()->selectedDockerContainer, containerConfig, newContainerConfig); - }, - pageFunc, progressBarFunc, + }; + + ErrorCode e = uiLogic()->pageLogic()->doInstallAction(installAction, pageFunc, progressBarFunc, saveButtonFunc, waitInfoFunc, busyInfoFuncy, cancelButtonFunc); diff --git a/client/ui/pages_logic/protocols/V2RayLogic.h b/client/ui/pages_logic/protocols/V2RayLogic.h index efc29572..1bde8878 100644 --- a/client/ui/pages_logic/protocols/V2RayLogic.h +++ b/client/ui/pages_logic/protocols/V2RayLogic.h @@ -9,21 +9,22 @@ 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(QString, lineEditPortText) + AUTO_PROPERTY(bool, labelInfoVisible) AUTO_PROPERTY(QString, labelInfoText) + AUTO_PROPERTY(int, progressBarResetValue) AUTO_PROPERTY(int, progressBarResetMaximium) + AUTO_PROPERTY(bool, progressBarResetVisible) AUTO_PROPERTY(bool, progressBarTextVisible) AUTO_PROPERTY(QString, progressBarText) AUTO_PROPERTY(bool, labelServerBusyVisible) AUTO_PROPERTY(QString, labelServerBusyText) + AUTO_PROPERTY(bool, pushButtonSaveVisible) AUTO_PROPERTY(bool, pushButtonCancelVisible) public: @@ -34,7 +35,7 @@ public: explicit V2RayLogic(UiLogic *uiLogic, QObject *parent = nullptr); ~V2RayLogic() = default; - void updateProtocolPage(const QJsonObject &ssConfig, DockerContainer container, bool haveAuthData) override; + void updateProtocolPage(const QJsonObject &v2rayConfig, DockerContainer container, bool haveAuthData) override; QJsonObject getProtocolConfigFromPage(QJsonObject oldConfig) override; private: diff --git a/client/ui/qml/Pages/Protocols/PageProtoV2Ray.qml b/client/ui/qml/Pages/Protocols/PageProtoV2Ray.qml index 5560aee7..6d6816be 100644 --- a/client/ui/qml/Pages/Protocols/PageProtoV2Ray.qml +++ b/client/ui/qml/Pages/Protocols/PageProtoV2Ray.qml @@ -1,5 +1,138 @@ import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import ProtocolEnum 1.0 +import "../" +import "../../Controls" +import "../../Config" -Item { +PageProtocolBase { + id: root + protocol: ProtocolEnum.V2Ray + logic: UiLogic.protocolLogic(protocol) + BackButton { + id: back + enabled: !logic.pushButtonCancelVisible + } + + Caption { + id: caption + text: qsTr("V2Ray Settings") + } + + ColumnLayout { + id: content + enabled: logic.pageEnabled + anchors.top: caption.bottom + anchors.left: root.left + anchors.right: root.right + anchors.bottom: pb_save.top + anchors.margins: 20 + anchors.topMargin: 10 + + RowLayout { + Layout.fillWidth: true + + LabelType { + Layout.preferredWidth: 0.3 * root.width - 10 + height: 31 + text: qsTr("Port") + } + + TextFieldType { + Layout.fillWidth: true + height: 31 + text: logic.lineEditPortText + onEditingFinished: { + logic.lineEditPortText = text + } + enabled: logic.lineEditPortEnabled + } + } + + Item { + Layout.fillHeight: true + } + + LabelType { + horizontalAlignment: Text.AlignHCenter + Layout.maximumWidth: parent.width + Layout.fillWidth: true + visible: logic.labelServerBusyVisible + text: logic.labelServerBusyText + } + + LabelType { + horizontalAlignment: Text.AlignHCenter + Layout.maximumWidth: parent.width + Layout.fillWidth: true + visible: logic.labelInfoVisible + text: logic.labelInfoText + } + } + + ProgressBar { + id: progressBar_reset + anchors.fill: pb_save + from: 0 + to: logic.progressBarResetMaximium + value: logic.progressBarResetValue + visible: logic.progressBarResetVisible + background: Rectangle { + implicitWidth: parent.width + implicitHeight: parent.height + color: "#100A44" + radius: 4 + } + + contentItem: Item { + implicitWidth: parent.width + implicitHeight: parent.height + Rectangle { + width: progressBar_reset.visualPosition * parent.width + height: parent.height + radius: 4 + color: Qt.rgba(255, 255, 255, 0.15); + } + } + LabelType { + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + text: logic.progressBarText + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Lato" + font.styleName: "normal" + font.pixelSize: 16 + color: "#D4D4D4" + visible: logic.progressBarTextVisible + } + } + + BlueButtonType { + id: pb_save + enabled: logic.pageEnabled + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: root.bottom + anchors.bottomMargin: 20 + width: root.width - 60 + height: 40 + text: qsTr("Save and restart VPN") + visible: logic.pushButtonSaveVisible + onClicked: { + logic.onPushButtonSaveClicked() + } + } + + BlueButtonType { + anchors.fill: pb_save + text: qsTr("Cancel") + visible: logic.pushButtonCancelVisible + enabled: logic.pushButtonCancelVisible + onClicked: { + logic.onPushButtonCancelClicked() + } + } }