fixed changes

This commit is contained in:
dranik
2026-04-30 16:53:17 +03:00
parent 28709072bf
commit 4b1a0c0788
5 changed files with 113 additions and 74 deletions

View File

@@ -1,29 +1,28 @@
#include "xrayConfigurator.h" #include "xrayConfigurator.h"
#include "logger.h"
#include <QFile> #include <QFile>
#include <QJsonArray>
#include <QJsonDocument> #include <QJsonDocument>
#include <QJsonObject> #include <QJsonObject>
#include <QJsonArray>
#include <QUuid> #include <QUuid>
#include "logger.h"
#include "core/models/containerConfig.h"
#include "core/models/protocolConfig.h"
#include "core/models/protocols/xrayProtocolConfig.h"
#include "core/protocols/protocolUtils.h"
#include "core/utils/constants/configKeys.h"
#include "core/utils/constants/protocolConstants.h"
#include "core/utils/containerEnum.h" #include "core/utils/containerEnum.h"
#include "core/utils/containers/containerUtils.h" #include "core/utils/containers/containerUtils.h"
#include "core/utils/protocolEnum.h" #include "core/utils/protocolEnum.h"
#include "core/utils/selfhosted/scriptsRegistry.h"
#include "core/utils/selfhosted/sshSession.h" #include "core/utils/selfhosted/sshSession.h"
#include "core/utils/selfhosted/scriptsRegistry.h"
#include "core/utils/protocolEnum.h"
#include "core/protocols/protocolUtils.h"
#include "core/utils/constants/configKeys.h"
#include "core/utils/constants/protocolConstants.h"
#include "core/models/containerConfig.h"
#include "core/models/protocols/xrayProtocolConfig.h"
namespace namespace {
{
Logger logger("XrayConfigurator"); Logger logger("XrayConfigurator");
QString normalizeXhttpMode(const QString &m)
{ QString normalizeXhttpMode(const QString &m) {
const QString t = m.trimmed(); const QString t = m.trimmed();
if (t.isEmpty() || t.compare(QLatin1String("Auto"), Qt::CaseInsensitive) == 0) { if (t.isEmpty() || t.compare(QLatin1String("Auto"), Qt::CaseInsensitive) == 0) {
return QStringLiteral("auto"); return QStringLiteral("auto");
@@ -416,9 +415,9 @@ QJsonObject XrayConfigurator::buildStreamSettings(const XrayServerConfig &srv, c
} }
ProtocolConfig XrayConfigurator::createConfig(const ServerCredentials &credentials, DockerContainer container, ProtocolConfig XrayConfigurator::createConfig(const ServerCredentials &credentials, DockerContainer container,
const ContainerConfig &containerConfig, const ContainerConfig &containerConfig,
const DnsSettings &dnsSettings, const DnsSettings &dnsSettings,
ErrorCode &errorCode) ErrorCode &errorCode)
{ {
const XrayServerConfig *serverConfig = nullptr; const XrayServerConfig *serverConfig = nullptr;
if (const auto *xrayCfg = containerConfig.protocolConfig.as<XrayProtocolConfig>()) { if (const auto *xrayCfg = containerConfig.protocolConfig.as<XrayProtocolConfig>()) {
@@ -428,7 +427,7 @@ ProtocolConfig XrayConfigurator::createConfig(const ServerCredentials &credentia
if (!serverConfig) { if (!serverConfig) {
logger.error() << "No XrayProtocolConfig found"; logger.error() << "No XrayProtocolConfig found";
errorCode = ErrorCode::InternalError; errorCode = ErrorCode::InternalError;
return XrayProtocolConfig {}; return XrayProtocolConfig{};
} }
const XrayServerConfig &srv = *serverConfig; const XrayServerConfig &srv = *serverConfig;
@@ -436,7 +435,10 @@ ProtocolConfig XrayConfigurator::createConfig(const ServerCredentials &credentia
QString xrayClientId = prepareServerConfig(credentials, container, containerConfig, dnsSettings, errorCode); QString xrayClientId = prepareServerConfig(credentials, container, containerConfig, dnsSettings, errorCode);
if (errorCode != ErrorCode::NoError || xrayClientId.isEmpty()) { if (errorCode != ErrorCode::NoError || xrayClientId.isEmpty()) {
logger.error() << "Failed to prepare server config"; logger.error() << "Failed to prepare server config";
return XrayProtocolConfig {}; if (errorCode == ErrorCode::NoError) {
errorCode = ErrorCode::InternalError;
}
return XrayProtocolConfig{};
} }
// Fetch server keys (Reality only) // Fetch server keys (Reality only)
@@ -448,7 +450,10 @@ ProtocolConfig XrayConfigurator::createConfig(const ServerCredentials &credentia
amnezia::protocols::xray::PublicKeyPath, errorCode); amnezia::protocols::xray::PublicKeyPath, errorCode);
if (errorCode != ErrorCode::NoError || xrayPublicKey.isEmpty()) { if (errorCode != ErrorCode::NoError || xrayPublicKey.isEmpty()) {
logger.error() << "Failed to get public key"; logger.error() << "Failed to get public key";
return XrayProtocolConfig {}; if (errorCode == ErrorCode::NoError) {
errorCode = ErrorCode::InternalError;
}
return XrayProtocolConfig{};
} }
xrayPublicKey.replace("\n", ""); xrayPublicKey.replace("\n", "");
@@ -456,7 +461,10 @@ ProtocolConfig XrayConfigurator::createConfig(const ServerCredentials &credentia
amnezia::protocols::xray::shortidPath, errorCode); amnezia::protocols::xray::shortidPath, errorCode);
if (errorCode != ErrorCode::NoError || xrayShortId.isEmpty()) { if (errorCode != ErrorCode::NoError || xrayShortId.isEmpty()) {
logger.error() << "Failed to get short ID"; logger.error() << "Failed to get short ID";
return XrayProtocolConfig {}; if (errorCode == ErrorCode::NoError) {
errorCode = ErrorCode::InternalError;
}
return XrayProtocolConfig{};
} }
xrayShortId.replace("\n", ""); xrayShortId.replace("\n", "");
} }
@@ -522,4 +530,4 @@ ProtocolConfig XrayConfigurator::createConfig(const ServerCredentials &credentia
protocolConfig.setClientConfig(clientConfig); protocolConfig.setClientConfig(clientConfig);
return protocolConfig; return protocolConfig;
} }

View File

@@ -170,23 +170,46 @@ QJsonObject XrayServerConfig::toJson() const
QJsonObject obj; QJsonObject obj;
// Existing fields // Existing fields
if (!port.isEmpty()) obj[configKey::port] = port; if (!port.isEmpty()) {
if (!transportProto.isEmpty()) obj[configKey::transportProto] = transportProto; obj[configKey::port] = port;
if (!subnetAddress.isEmpty()) obj[configKey::subnetAddress] = subnetAddress; }
if (!site.isEmpty()) obj[configKey::site] = site; if (!transportProto.isEmpty()) {
if (isThirdPartyConfig) obj[configKey::isThirdPartyConfig] = isThirdPartyConfig; obj[configKey::transportProto] = transportProto;
}
if (!subnetAddress.isEmpty()) {
obj[configKey::subnetAddress] = subnetAddress;
}
if (!site.isEmpty()) {
obj[configKey::site] = site;
}
if (isThirdPartyConfig) {
obj[configKey::isThirdPartyConfig] = isThirdPartyConfig;
}
// New: Security // New: Security
if (!security.isEmpty()) obj[configKey::xraySecurity] = security; if (!security.isEmpty()) {
if (!flow.isEmpty()) obj[configKey::xrayFlow] = flow; obj[configKey::xraySecurity] = security;
if (!fingerprint.isEmpty()) obj[configKey::xrayFingerprint] = fingerprint; }
if (!sni.isEmpty()) obj[configKey::xraySni] = sni; if (!flow.isEmpty()) {
if (!alpn.isEmpty()) obj[configKey::xrayAlpn] = alpn; obj[configKey::xrayFlow] = flow;
}
if (!fingerprint.isEmpty()) {
obj[configKey::xrayFingerprint] = fingerprint;
}
if (!sni.isEmpty()) {
obj[configKey::xraySni] = sni;
}
if (!alpn.isEmpty()) {
obj[configKey::xrayAlpn] = alpn;
}
// New: Transport // New: Transport
if (!transport.isEmpty()) obj[configKey::xrayTransport] = transport; if (!transport.isEmpty()) {
obj[configKey::xrayTransport] = transport;
}
obj["xhttp"] = xhttp.toJson(); obj["xhttp"] = xhttp.toJson();
obj["mkcp"] = mkcp.toJson(); obj["mkcp"] = mkcp.toJson();
return obj; return obj;
} }
@@ -196,39 +219,39 @@ XrayServerConfig XrayServerConfig::fromJson(const QJsonObject &json)
XrayServerConfig c; XrayServerConfig c;
// Existing fields // Existing fields
c.port = json.value(configKey::port).toString(); c.port = json.value(configKey::port).toString();
c.transportProto = json.value(configKey::transportProto).toString(); c.transportProto = json.value(configKey::transportProto).toString();
c.subnetAddress = json.value(configKey::subnetAddress).toString(); c.subnetAddress = json.value(configKey::subnetAddress).toString();
c.site = json.value(configKey::site).toString(); c.site = json.value(configKey::site).toString();
c.isThirdPartyConfig = json.value(configKey::isThirdPartyConfig).toBool(false); c.isThirdPartyConfig = json.value(configKey::isThirdPartyConfig).toBool(false);
// New: Security // New: Security
c.security = json.value(configKey::xraySecurity).toString(protocols::xray::defaultSecurity); c.security = json.value(configKey::xraySecurity).toString(protocols::xray::defaultSecurity);
c.flow = json.value(configKey::xrayFlow).toString(protocols::xray::defaultFlow); c.flow = json.value(configKey::xrayFlow).toString(protocols::xray::defaultFlow);
c.fingerprint = json.value(configKey::xrayFingerprint).toString(protocols::xray::defaultFingerprint); c.fingerprint = json.value(configKey::xrayFingerprint).toString(protocols::xray::defaultFingerprint);
if (c.fingerprint.contains(QLatin1String("Mozilla/5.0"), Qt::CaseInsensitive)) { if (c.fingerprint.contains(QLatin1String("Mozilla/5.0"), Qt::CaseInsensitive)) {
c.fingerprint = QString::fromLatin1(protocols::xray::defaultFingerprint); c.fingerprint = QString::fromLatin1(protocols::xray::defaultFingerprint);
} }
c.sni = json.value(configKey::xraySni).toString(protocols::xray::defaultSni); c.sni = json.value(configKey::xraySni).toString(protocols::xray::defaultSni);
c.alpn = json.value(configKey::xrayAlpn).toString(protocols::xray::defaultAlpn); c.alpn = json.value(configKey::xrayAlpn).toString(protocols::xray::defaultAlpn);
// New: Transport // New: Transport
c.transport = json.value(configKey::xrayTransport).toString(protocols::xray::defaultTransport); c.transport = json.value(configKey::xrayTransport).toString(protocols::xray::defaultTransport);
c.xhttp = XrayXhttpConfig::fromJson(json.value("xhttp").toObject()); c.xhttp = XrayXhttpConfig::fromJson(json.value("xhttp").toObject());
c.mkcp = XrayMkcpConfig::fromJson(json.value("mkcp").toObject()); c.mkcp = XrayMkcpConfig::fromJson(json.value("mkcp").toObject());
return c; return c;
} }
bool XrayServerConfig::hasEqualServerSettings(const XrayServerConfig &other) const bool XrayServerConfig::hasEqualServerSettings(const XrayServerConfig &other) const
{ {
return port == other.port return port == other.port
&& site == other.site && site == other.site
&& security == other.security && security == other.security
&& flow == other.flow && flow == other.flow
&& transport == other.transport && transport == other.transport
&& fingerprint == other.fingerprint && fingerprint == other.fingerprint
&& sni == other.sni; && sni == other.sni;
} }
QJsonObject XrayClientConfig::toJson() const QJsonObject XrayClientConfig::toJson() const

View File

@@ -93,26 +93,26 @@ struct XrayMkcpConfig {
// ── Server config (settings editable by user) ───────────────────────────────── // ── Server config (settings editable by user) ─────────────────────────────────
struct XrayServerConfig { struct XrayServerConfig {
// Existing fields
QString port; QString port;
QString transportProto; QString transportProto;
QString subnetAddress; QString subnetAddress;
QString site; QString site;
bool isThirdPartyConfig = false; bool isThirdPartyConfig = false;
// New: Security // New: Security
QString security = protocols::xray::defaultSecurity; QString security = protocols::xray::defaultSecurity;
QString flow = protocols::xray::defaultFlow; QString flow = protocols::xray::defaultFlow;
QString fingerprint = protocols::xray::defaultFingerprint; QString fingerprint = protocols::xray::defaultFingerprint;
QString sni = protocols::xray::defaultSni; QString sni = protocols::xray::defaultSni;
QString alpn = protocols::xray::defaultAlpn; QString alpn = protocols::xray::defaultAlpn;
// New: Transport // New: Transport
QString transport = protocols::xray::defaultTransport; QString transport = protocols::xray::defaultTransport;
XrayXhttpConfig xhttp; XrayXhttpConfig xhttp;
XrayMkcpConfig mkcp; XrayMkcpConfig mkcp;
QJsonObject toJson() const; QJsonObject toJson() const;
static XrayServerConfig fromJson(const QJsonObject &json); static XrayServerConfig fromJson(const QJsonObject &json);
bool hasEqualServerSettings(const XrayServerConfig &other) const; bool hasEqualServerSettings(const XrayServerConfig &other) const;
@@ -130,7 +130,7 @@ struct XrayClientConfig {
// ── Top-level protocol config ────────────────────────────────────────────────── // ── Top-level protocol config ──────────────────────────────────────────────────
struct XrayProtocolConfig { struct XrayProtocolConfig {
XrayServerConfig serverConfig; XrayServerConfig serverConfig;
std::optional<XrayClientConfig> clientConfig; std::optional<XrayClientConfig> clientConfig;
QJsonObject toJson() const; QJsonObject toJson() const;

View File

@@ -167,8 +167,7 @@ bool XrayConfigModel::setData(const QModelIndex& index, const QVariant& value, i
QVariant XrayConfigModel::data(const QModelIndex& index, int role) const QVariant XrayConfigModel::data(const QModelIndex& index, int role) const
{ {
if (!index.isValid() || index.row() < 0 || index.row() >= rowCount()) if (!index.isValid() || index.row() < 0 || index.row() >= rowCount()) {
{
return QVariant(); return QVariant();
} }
@@ -252,14 +251,18 @@ QVariant XrayConfigModel::data(const QModelIndex& index, int role) const
return QVariant(); return QVariant();
} }
void XrayConfigModel::updateModel(amnezia::DockerContainer container, void XrayConfigModel::updateModel(amnezia::DockerContainer container, const amnezia::XrayProtocolConfig& protocolConfig)
const amnezia::XrayProtocolConfig& protocolConfig)
{ {
beginResetModel(); beginResetModel();
m_container = container; m_container = container;
m_protocolConfig = protocolConfig; m_protocolConfig = protocolConfig;
applyDefaultsToServerConfig(m_protocolConfig.serverConfig); applyDefaultsToServerConfig(m_protocolConfig.serverConfig);
m_originalProtocolConfig = m_protocolConfig; m_originalProtocolConfig = m_protocolConfig;
endResetModel(); endResetModel();
} }
@@ -269,6 +272,11 @@ void XrayConfigModel::applyDefaultsToServerConfig(amnezia::XrayServerConfig &con
config.port = protocols::xray::defaultPort; config.port = protocols::xray::defaultPort;
} }
if (config.transportProto.isEmpty()) {
config.transportProto = ProtocolUtils::transportProtoToString(
ProtocolUtils::defaultTransportProto(amnezia::Proto::Xray), amnezia::Proto::Xray);
}
if (config.site.isEmpty()) { if (config.site.isEmpty()) {
config.site = protocols::xray::defaultSite; config.site = protocols::xray::defaultSite;
} }

View File

@@ -46,7 +46,7 @@ PageType {
delegate: ColumnLayout { delegate: ColumnLayout {
width: listView.width width: listView.width
property alias focusItemId: portTextField.textField property alias focusItemId: textFieldWithHeaderType.textField
spacing: 0 spacing: 0
@@ -87,7 +87,7 @@ PageType {
} }
TextFieldWithHeaderType { TextFieldWithHeaderType {
id: portTextField id: textFieldWithHeaderType
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 32 Layout.topMargin: 32
Layout.leftMargin: 16 Layout.leftMargin: 16
@@ -112,7 +112,7 @@ PageType {
descriptionText: transport descriptionText: transport
rightImageSource: "qrc:/images/controls/chevron-right.svg" rightImageSource: "qrc:/images/controls/chevron-right.svg"
enabled: listView.enabled enabled: listView.enabled
clickedFunction: function () { clickedFunction: function() {
PageController.goToPage(PageEnum.PageProtocolXrayTransportSettings) PageController.goToPage(PageEnum.PageProtocolXrayTransportSettings)
} }
} }
@@ -126,7 +126,7 @@ PageType {
descriptionText: security descriptionText: security
rightImageSource: "qrc:/images/controls/chevron-right.svg" rightImageSource: "qrc:/images/controls/chevron-right.svg"
enabled: listView.enabled enabled: listView.enabled
clickedFunction: function () { clickedFunction: function() {
PageController.goToPage(PageEnum.PageProtocolXraySecuritySettings) PageController.goToPage(PageEnum.PageProtocolXraySecuritySettings)
} }
} }
@@ -140,7 +140,7 @@ PageType {
descriptionText: flow descriptionText: flow
rightImageSource: "qrc:/images/controls/chevron-right.svg" rightImageSource: "qrc:/images/controls/chevron-right.svg"
enabled: listView.enabled enabled: listView.enabled
clickedFunction: function () { clickedFunction: function() {
PageController.goToPage(PageEnum.PageProtocolXrayFlowSettings) PageController.goToPage(PageEnum.PageProtocolXrayFlowSettings)
} }
} }
@@ -158,15 +158,15 @@ PageType {
Layout.bottomMargin: 8 Layout.bottomMargin: 8
Layout.leftMargin: 16 Layout.leftMargin: 16
Layout.rightMargin: 16 Layout.rightMargin: 16
enabled: portTextField.errorText === "" enabled: textFieldWithHeaderType.errorText === ""
text: qsTr("Save") text: qsTr("Save")
onClicked: function () { onClicked: function() {
forceActiveFocus() forceActiveFocus()
var headerText = qsTr("Save settings?") var headerText = qsTr("Save settings?")
var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.") var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.")
var yesButtonText = qsTr("Continue") var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel") var noButtonText = qsTr("Cancel")
var yesButtonFunction = function () { var yesButtonFunction = function() {
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ServersUiController.processedContainerIndex) { if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ServersUiController.processedContainerIndex) {
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection")) PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
return return
@@ -174,7 +174,7 @@ PageType {
PageController.goToPage(PageEnum.PageSetupWizardInstalling) PageController.goToPage(PageEnum.PageSetupWizardInstalling)
InstallController.updateContainer(ServersUiController.processedIndex, ServersUiController.processedContainerIndex, ProtocolEnum.Xray) InstallController.updateContainer(ServersUiController.processedIndex, ServersUiController.processedContainerIndex, ProtocolEnum.Xray)
} }
var noButtonFunction = function () { var noButtonFunction = function() {
if (!GC.isMobile()) saveButton.forceActiveFocus() if (!GC.isMobile()) saveButton.forceActiveFocus()
} }
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
@@ -188,12 +188,12 @@ PageType {
text: qsTr("Reset settings") text: qsTr("Reset settings")
textColor: AmneziaStyle.color.vibrantRed textColor: AmneziaStyle.color.vibrantRed
visible: listView.enabled visible: listView.enabled
clickedFunction: function () { clickedFunction: function() {
var yesButtonFunction = function () { var yesButtonFunction = function() {
XrayConfigModel.resetToDefaults() XrayConfigModel.resetToDefaults()
} }
showQuestionDrawer(qsTr("Reset settings?"), qsTr("All XRay settings will be restored to defaults."), showQuestionDrawer(qsTr("Reset settings?"), qsTr("All XRay settings will be restored to defaults."),
qsTr("Reset"), qsTr("Cancel"), yesButtonFunction, function () { qsTr("Reset"), qsTr("Cancel"), yesButtonFunction, function() {
}) })
} }
} }