mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-11-13 16:13:49 +09:00
Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
11afa5884b | ||
|
|
016fd4b079 | ||
|
|
78e1641ffc | ||
|
|
cfec5da005 |
No files matched your search
@@ -66,6 +66,8 @@ ProtocolConfig AwgConfigurator::createConfig(const ServerCredentials &credential
|
||||
newClientConfig.nativeConfig = awgConfig;
|
||||
newClientConfig.hostName = wgConfig->clientConfig->hostName;
|
||||
newClientConfig.port = wgConfig->clientConfig->port;
|
||||
newClientConfig.cascadeEndpoint = wgConfig->clientConfig->cascadeEndpoint;
|
||||
newClientConfig.cascadePort = wgConfig->clientConfig->cascadePort;
|
||||
newClientConfig.clientIp = wgConfig->clientConfig->clientIp;
|
||||
newClientConfig.clientPrivateKey = wgConfig->clientConfig->clientPrivateKey;
|
||||
newClientConfig.clientPublicKey = wgConfig->clientConfig->clientPublicKey;
|
||||
|
||||
@@ -266,6 +266,11 @@ ProtocolConfig WireguardConfigurator::createConfig(const ServerCredentials &cred
|
||||
clientConfig.nativeConfig = config;
|
||||
clientConfig.hostName = connData.host;
|
||||
clientConfig.port = connData.port.toInt();
|
||||
if (wireguardServerConfig) {
|
||||
clientConfig.setCascade(wireguardServerConfig->cascadeEndpoint, wireguardServerConfig->cascadePort);
|
||||
} else if (awgServerConfig) {
|
||||
clientConfig.setCascade(awgServerConfig->cascadeEndpoint, awgServerConfig->cascadePort);
|
||||
}
|
||||
clientConfig.clientIp = connData.clientIP;
|
||||
clientConfig.clientPrivateKey = connData.clientPrivKey;
|
||||
clientConfig.clientPublicKey = connData.clientPubKey;
|
||||
|
||||
@@ -289,6 +289,15 @@ QJsonObject ConnectionController::createConnectionConfiguration(const QPair<QStr
|
||||
ContainerUtils::isAwgContainer(container) ? protocols::awg::defaultMtu :
|
||||
protocols::wireguard::defaultMtu;
|
||||
}
|
||||
|
||||
const QString cascadeEndpoint = vpnConfigData.value(configKey::cascadeEndpoint).toString();
|
||||
if (!cascadeEndpoint.isEmpty()) {
|
||||
vpnConfigData[configKey::hostName] = cascadeEndpoint;
|
||||
}
|
||||
const QString cascadePort = vpnConfigData.value(configKey::cascadePort).toString();
|
||||
if (!cascadePort.isEmpty()) {
|
||||
vpnConfigData[configKey::port] = cascadePort.toInt();
|
||||
}
|
||||
}
|
||||
|
||||
vpnConfiguration.insert(ProtocolUtils::key_proto_config_data(proto), vpnConfigData);
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#include "installerBase.h"
|
||||
|
||||
#include <QRandomGenerator>
|
||||
#include <iterator>
|
||||
|
||||
#include "core/utils/containerEnum.h"
|
||||
#include "core/utils/containers/containerUtils.h"
|
||||
#include "core/utils/protocolEnum.h"
|
||||
@@ -85,8 +88,10 @@ ContainerConfig InstallerBase::createBaseConfig(DockerContainer container, int p
|
||||
srv.transport = protocols::xray::defaultTransport;
|
||||
srv.security = protocols::xray::defaultSecurity;
|
||||
srv.flow = protocols::xray::defaultFlow;
|
||||
srv.site = protocols::xray::defaultSite;
|
||||
srv.sni = protocols::xray::defaultSni;
|
||||
const int siteIndex =
|
||||
QRandomGenerator::global()->bounded(static_cast<int>(std::size(protocols::xray::defaultSites)));
|
||||
srv.site = protocols::xray::defaultSites[siteIndex];
|
||||
srv.sni = srv.site;
|
||||
srv.alpn = protocols::xray::defaultAlpn;
|
||||
srv.fingerprint = protocols::xray::defaultFingerprint;
|
||||
config.protocolConfig = xrayConfig;
|
||||
|
||||
@@ -72,6 +72,12 @@ QJsonObject AwgServerConfig::toJson() const
|
||||
if (!port.isEmpty()) {
|
||||
obj[configKey::port] = this->port;
|
||||
}
|
||||
if (!cascadeEndpoint.isEmpty()) {
|
||||
obj[configKey::cascadeEndpoint] = cascadeEndpoint;
|
||||
}
|
||||
if (!cascadePort.isEmpty()) {
|
||||
obj[configKey::cascadePort] = cascadePort;
|
||||
}
|
||||
if (!transportProto.isEmpty()) {
|
||||
obj[configKey::transportProto] = transportProto;
|
||||
}
|
||||
@@ -166,6 +172,8 @@ AwgServerConfig AwgServerConfig::fromJson(const QJsonObject& json)
|
||||
AwgServerConfig config;
|
||||
|
||||
config.port = json.value(configKey::port).toString();
|
||||
config.cascadeEndpoint = json.value(configKey::cascadeEndpoint).toString();
|
||||
config.cascadePort = json.value(configKey::cascadePort).toString();
|
||||
config.transportProto = json.value(configKey::transportProto).toString();
|
||||
config.protocolVersion = json.value(configKey::protocolVersion).toString();
|
||||
config.subnetAddress = json.value(configKey::subnetAddress).toString();
|
||||
@@ -218,6 +226,12 @@ QJsonObject AwgClientConfig::toJson() const
|
||||
if (port > 0) {
|
||||
obj[configKey::port] = port;
|
||||
}
|
||||
if (!cascadeEndpoint.isEmpty()) {
|
||||
obj[configKey::cascadeEndpoint] = cascadeEndpoint;
|
||||
}
|
||||
if (!cascadePort.isEmpty()) {
|
||||
obj[configKey::cascadePort] = cascadePort;
|
||||
}
|
||||
if (!clientIp.isEmpty()) {
|
||||
obj[configKey::clientIp] = clientIp;
|
||||
}
|
||||
@@ -333,6 +347,14 @@ QJsonObject AwgClientConfig::toJson() const
|
||||
return obj;
|
||||
}
|
||||
|
||||
void AwgClientConfig::setCascade(const QString &newEndpoint, const QString &newPort)
|
||||
{
|
||||
cascadeEndpoint = newEndpoint;
|
||||
cascadePort = newPort;
|
||||
nativeConfig = replaceWireGuardEndpoint(nativeConfig, newEndpoint.isEmpty() ? hostName : newEndpoint,
|
||||
newPort.isEmpty() ? port : newPort.toInt());
|
||||
}
|
||||
|
||||
AwgClientConfig AwgClientConfig::fromJson(const QJsonObject& json)
|
||||
{
|
||||
AwgClientConfig config;
|
||||
@@ -340,6 +362,8 @@ AwgClientConfig AwgClientConfig::fromJson(const QJsonObject& json)
|
||||
config.nativeConfig = json.value(configKey::config).toString();
|
||||
config.hostName = json.value(configKey::hostName).toString();
|
||||
config.port = json.value(configKey::port).toInt(0);
|
||||
config.cascadeEndpoint = json.value(configKey::cascadeEndpoint).toString();
|
||||
config.cascadePort = json.value(configKey::cascadePort).toString();
|
||||
config.clientIp = json.value(configKey::clientIp).toString();
|
||||
config.clientPrivateKey = json.value(configKey::clientPrivKey).toString();
|
||||
config.clientPublicKey = json.value(configKey::clientPubKey).toString();
|
||||
|
||||
@@ -19,6 +19,8 @@ namespace AwgConstant
|
||||
|
||||
struct AwgServerConfig {
|
||||
QString port;
|
||||
QString cascadeEndpoint;
|
||||
QString cascadePort;
|
||||
QString transportProto;
|
||||
QString protocolVersion;
|
||||
QString subnetAddress;
|
||||
@@ -61,6 +63,8 @@ struct AwgClientConfig {
|
||||
QString nativeConfig;
|
||||
QString hostName;
|
||||
int port;
|
||||
QString cascadeEndpoint;
|
||||
QString cascadePort;
|
||||
QString clientIp;
|
||||
QString clientPrivateKey;
|
||||
QString clientPublicKey;
|
||||
@@ -95,6 +99,9 @@ struct AwgClientConfig {
|
||||
QString maxHandshakeAttempts;
|
||||
QString randomTrailers;
|
||||
QString disableCookies;
|
||||
|
||||
void setCascade(const QString &newEndpoint, const QString &newPort);
|
||||
|
||||
QJsonObject toJson() const;
|
||||
static AwgClientConfig fromJson(const QJsonObject& json);
|
||||
};
|
||||
|
||||
@@ -20,6 +20,12 @@ QJsonObject WireGuardServerConfig::toJson() const
|
||||
if (!port.isEmpty()) {
|
||||
obj[configKey::port] = port;
|
||||
}
|
||||
if (!cascadeEndpoint.isEmpty()) {
|
||||
obj[configKey::cascadeEndpoint] = cascadeEndpoint;
|
||||
}
|
||||
if (!cascadePort.isEmpty()) {
|
||||
obj[configKey::cascadePort] = cascadePort;
|
||||
}
|
||||
if (!transportProto.isEmpty()) {
|
||||
obj[configKey::transportProto] = transportProto;
|
||||
}
|
||||
@@ -45,6 +51,8 @@ WireGuardServerConfig WireGuardServerConfig::fromJson(const QJsonObject& json)
|
||||
WireGuardServerConfig config;
|
||||
|
||||
config.port = json.value(configKey::port).toString();
|
||||
config.cascadeEndpoint = json.value(configKey::cascadeEndpoint).toString();
|
||||
config.cascadePort = json.value(configKey::cascadePort).toString();
|
||||
config.transportProto = json.value(configKey::transportProto).toString();
|
||||
config.subnetAddress = json.value(configKey::subnetAddress).toString();
|
||||
config.subnetMask = json.value(configKey::subnetMask).toString();
|
||||
@@ -73,6 +81,12 @@ QJsonObject WireGuardClientConfig::toJson() const
|
||||
if (port > 0) {
|
||||
obj[configKey::port] = port;
|
||||
}
|
||||
if (!cascadeEndpoint.isEmpty()) {
|
||||
obj[configKey::cascadeEndpoint] = cascadeEndpoint;
|
||||
}
|
||||
if (!cascadePort.isEmpty()) {
|
||||
obj[configKey::cascadePort] = cascadePort;
|
||||
}
|
||||
if (!clientIp.isEmpty()) {
|
||||
obj[configKey::clientIp] = clientIp;
|
||||
}
|
||||
@@ -119,6 +133,14 @@ QJsonObject WireGuardClientConfig::toJson() const
|
||||
return obj;
|
||||
}
|
||||
|
||||
void WireGuardClientConfig::setCascade(const QString &newEndpoint, const QString &newPort)
|
||||
{
|
||||
cascadeEndpoint = newEndpoint;
|
||||
cascadePort = newPort;
|
||||
nativeConfig = replaceWireGuardEndpoint(nativeConfig, newEndpoint.isEmpty() ? hostName : newEndpoint,
|
||||
newPort.isEmpty() ? port : newPort.toInt());
|
||||
}
|
||||
|
||||
WireGuardClientConfig WireGuardClientConfig::fromJson(const QJsonObject& json)
|
||||
{
|
||||
WireGuardClientConfig config;
|
||||
@@ -126,6 +148,8 @@ WireGuardClientConfig WireGuardClientConfig::fromJson(const QJsonObject& json)
|
||||
config.nativeConfig = json.value(configKey::config).toString();
|
||||
config.hostName = json.value(configKey::hostName).toString();
|
||||
config.port = json.value(configKey::port).toInt(0);
|
||||
config.cascadeEndpoint = json.value(configKey::cascadeEndpoint).toString();
|
||||
config.cascadePort = json.value(configKey::cascadePort).toString();
|
||||
config.clientIp = json.value(configKey::clientIp).toString();
|
||||
config.clientPrivateKey = json.value(configKey::clientPrivKey).toString();
|
||||
config.clientPublicKey = json.value(configKey::clientPubKey).toString();
|
||||
|
||||
@@ -12,6 +12,8 @@ namespace amnezia
|
||||
|
||||
struct WireGuardServerConfig {
|
||||
QString port;
|
||||
QString cascadeEndpoint;
|
||||
QString cascadePort;
|
||||
QString transportProto;
|
||||
QString subnetAddress;
|
||||
QString subnetMask;
|
||||
@@ -28,6 +30,8 @@ struct WireGuardClientConfig {
|
||||
QString nativeConfig;
|
||||
QString hostName;
|
||||
int port;
|
||||
QString cascadeEndpoint;
|
||||
QString cascadePort;
|
||||
QString clientIp;
|
||||
QString clientPrivateKey;
|
||||
QString clientPublicKey;
|
||||
@@ -41,6 +45,8 @@ struct WireGuardClientConfig {
|
||||
QMap<QString, QString> awgParams;
|
||||
bool isObfuscationEnabled = false;
|
||||
|
||||
void setCascade(const QString &newEndpoint, const QString &newPort);
|
||||
|
||||
QJsonObject toJson() const;
|
||||
static WireGuardClientConfig fromJson(const QJsonObject& json);
|
||||
};
|
||||
|
||||
@@ -354,9 +354,6 @@ void XrayServerConfig::applyDefaults(bool fillFlowDefault)
|
||||
transportProto = ProtocolUtils::transportProtoToString(ProtocolUtils::defaultTransportProto(Proto::Xray),
|
||||
Proto::Xray);
|
||||
}
|
||||
if (site.isEmpty()) {
|
||||
site = protocols::xray::defaultSite;
|
||||
}
|
||||
if (transport.isEmpty()) {
|
||||
transport = protocols::xray::defaultTransport;
|
||||
}
|
||||
@@ -367,7 +364,7 @@ void XrayServerConfig::applyDefaults(bool fillFlowDefault)
|
||||
flow = protocols::xray::defaultFlow;
|
||||
}
|
||||
if (sni.isEmpty()) {
|
||||
sni = site.isEmpty() ? QString::fromLatin1(protocols::xray::defaultSni) : site;
|
||||
sni = site;
|
||||
}
|
||||
if (alpn.isEmpty()) {
|
||||
alpn = protocols::xray::defaultAlpn;
|
||||
@@ -569,7 +566,7 @@ QJsonObject XrayServerConfig::streamSettingsJson(XrayStreamSide side) const
|
||||
|
||||
if (securityEff == QLatin1String(px::securityTls)) {
|
||||
QJsonObject tlsSettings;
|
||||
tlsSettings[px::serverName] = sni.isEmpty() ? QString::fromLatin1(px::defaultSni) : sni;
|
||||
tlsSettings[px::serverName] = sni;
|
||||
const QString alpnEff = alpn.isEmpty() ? QString::fromLatin1(px::defaultAlpn) : alpn;
|
||||
QJsonArray alpnArray;
|
||||
for (const QString &a : alpnEff.split(QLatin1Char(','))) {
|
||||
@@ -598,7 +595,7 @@ QJsonObject XrayServerConfig::streamSettingsJson(XrayStreamSide side) const
|
||||
if (clientSide && securityEff == QLatin1String(px::securityReality)) {
|
||||
QJsonObject realitySettings;
|
||||
realitySettings[px::fingerprint] = fingerprintEff;
|
||||
realitySettings[px::serverName] = sni.isEmpty() ? QString::fromLatin1(px::defaultSni) : sni;
|
||||
realitySettings[px::serverName] = sni;
|
||||
streamSettings[px::realitySettings] = realitySettings;
|
||||
}
|
||||
|
||||
@@ -1139,11 +1136,10 @@ QJsonObject XrayServerConfig::toServerInboundJson(const XrayServerInboundInputs
|
||||
|
||||
QJsonObject streamSettings = serverStreamSettings();
|
||||
if (xrayEffective::security(*this) == QLatin1String(px::securityReality)) {
|
||||
const QString siteEff = site.isEmpty() ? QString::fromLatin1(px::defaultSite) : site;
|
||||
QJsonObject realitySettings;
|
||||
realitySettings[px::dest] = siteEff + QStringLiteral(":443");
|
||||
realitySettings[px::dest] = site + QStringLiteral(":443");
|
||||
realitySettings[px::privateKey] = inputs.realityPrivateKey;
|
||||
realitySettings[px::serverNames] = QJsonArray { sni.isEmpty() ? siteEff : sni };
|
||||
realitySettings[px::serverNames] = QJsonArray { sni.isEmpty() ? site : sni };
|
||||
realitySettings[px::shortIds] = QJsonArray { inputs.realityShortId };
|
||||
streamSettings[px::realitySettings] = realitySettings;
|
||||
}
|
||||
@@ -1323,10 +1319,9 @@ QJsonObject XrayServerConfig::serverView() const
|
||||
view[px::streamSettings] = serverStreamSettings();
|
||||
|
||||
if (xrayEffective::security(*this) == QLatin1String(px::securityReality)) {
|
||||
const QString siteEff = site.isEmpty() ? QString::fromLatin1(px::defaultSite) : site;
|
||||
QJsonObject reality;
|
||||
reality[px::dest] = siteEff;
|
||||
reality[px::serverName] = sni.isEmpty() ? siteEff : sni;
|
||||
reality[px::dest] = site;
|
||||
reality[px::serverName] = sni.isEmpty() ? site : sni;
|
||||
view[QStringLiteral("reality")] = reality;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "protocolUtils.h"
|
||||
|
||||
#include <QRandomGenerator>
|
||||
#include <QRegularExpression>
|
||||
#include <QJsonObject>
|
||||
#include <QObject>
|
||||
|
||||
@@ -216,3 +217,10 @@ QString ProtocolUtils::key_proto_config_path(Proto p)
|
||||
return protoToString(p) + "_config_path";
|
||||
}
|
||||
|
||||
QString ProtocolUtils::replaceWireGuardEndpoint(QString nativeConfig, const QString &host, int port)
|
||||
{
|
||||
static const QRegularExpression endpointLine(QString(R"(^(\s*%1\s*=\s*).*$)").arg(protocols::wireguard::Endpoint),
|
||||
QRegularExpression::MultilineOption);
|
||||
const QString endpointHost = host.contains(':') ? QString("[%1]").arg(host) : host;
|
||||
return nativeConfig.replace(endpointLine, QString("\\1%1:%2").arg(endpointHost).arg(port));
|
||||
}
|
||||
@@ -39,6 +39,8 @@ namespace amnezia
|
||||
QString key_proto_config_data(Proto p);
|
||||
QString key_proto_config_path(Proto p);
|
||||
|
||||
QString replaceWireGuardEndpoint(QString nativeConfig, const QString &host, int port);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,8 @@ namespace amnezia
|
||||
constexpr QLatin1String password("password");
|
||||
constexpr QLatin1String port("port");
|
||||
constexpr QLatin1String localPort("local_port");
|
||||
constexpr QLatin1String cascadeEndpoint("cascade_endpoint");
|
||||
constexpr QLatin1String cascadePort("cascade_port");
|
||||
|
||||
constexpr QLatin1String dns1("dns1");
|
||||
constexpr QLatin1String dns2("dns2");
|
||||
|
||||
@@ -57,7 +57,22 @@ namespace amnezia
|
||||
constexpr char shortidPath[] = "/opt/amnezia/xray/xray_short_id.key";
|
||||
constexpr char tlsCertPath[] = "/opt/amnezia/xray/tls_cert.pem";
|
||||
constexpr char tlsKeyPath[] = "/opt/amnezia/xray/tls_key.pem";
|
||||
constexpr char defaultSite[] = "www.googletagmanager.com";
|
||||
constexpr const char *defaultSites[] = {
|
||||
"www.microsoft.com",
|
||||
"www.apple.com",
|
||||
"www.icloud.com",
|
||||
"dl.google.com",
|
||||
"www.bing.com",
|
||||
"www.samsung.com",
|
||||
"www.nvidia.com",
|
||||
"www.cisco.com",
|
||||
"www.asus.com",
|
||||
"www.logitech.com",
|
||||
"www.dropbox.com",
|
||||
"www.mozilla.org",
|
||||
"addons.mozilla.org",
|
||||
"www.speedtest.net",
|
||||
};
|
||||
|
||||
constexpr char defaultPort[] = "443";
|
||||
constexpr char defaultLocalProxyPort[] = "10808";
|
||||
@@ -69,8 +84,7 @@ namespace amnezia
|
||||
constexpr char defaultSecurity[] = "reality";
|
||||
constexpr char defaultFlow[] = "xtls-rprx-vision";
|
||||
constexpr char defaultTransport[] = "raw";
|
||||
constexpr char defaultFingerprint[] = "hellochrome_120";
|
||||
constexpr char defaultSni[] = "www.googletagmanager.com";
|
||||
constexpr char defaultFingerprint[] = "firefox";
|
||||
constexpr char defaultAlpn[] = "h2";
|
||||
|
||||
constexpr char defaultXhttpMode[] = "Stream-one";
|
||||
|
||||
@@ -208,7 +208,7 @@ amnezia::ScriptVars amnezia::genXrayVars(const ContainerConfig &containerConfig)
|
||||
if (auto* xrayProtocolConfig = containerConfig.getXrayProtocolConfig()) {
|
||||
const XrayServerConfig& config = xrayProtocolConfig->serverConfig;
|
||||
|
||||
vars.append({ { "$XRAY_SITE_NAME", config.site.isEmpty() ? protocols::xray::defaultSite : config.site } });
|
||||
vars.append({ { "$XRAY_SITE_NAME", config.site } });
|
||||
vars.append({ { "$XRAY_SERVER_PORT", config.port.isEmpty() ? protocols::xray::defaultPort : config.port } });
|
||||
}
|
||||
|
||||
|
||||
@@ -205,10 +205,10 @@ extension PacketTunnelProvider {
|
||||
}
|
||||
}
|
||||
|
||||
func stopXray(completionHandler: @escaping () -> Void) {
|
||||
func stopXray(completionHandler: () -> Void) {
|
||||
Socks5Tunnel.quit()
|
||||
LibXrayStopXray()
|
||||
hevSocksTunnelGroup.notify(queue: .main, execute: completionHandler)
|
||||
completionHandler()
|
||||
}
|
||||
|
||||
func sockCallback(fd: uintptr_t) {
|
||||
@@ -345,13 +345,10 @@ extension PacketTunnelProvider {
|
||||
return
|
||||
}
|
||||
|
||||
hevSocksTunnelGroup.enter()
|
||||
DispatchQueue.global().async { [hevSocksTunnelGroup] in
|
||||
DispatchQueue.global().async {
|
||||
xrayLog(.info, message: "Hev socks started")
|
||||
completionHandler(nil)
|
||||
let result = Socks5Tunnel.run(withConfig: configurationFilePath)
|
||||
xrayLog(.info, message: "Hev socks stopped: \(result)")
|
||||
hevSocksTunnelGroup.leave()
|
||||
Socks5Tunnel.run(withConfig: configurationFilePath)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -69,7 +69,6 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
||||
var protoType: TunnelProtoType?
|
||||
|
||||
var activeIfaceIdx: UInt32 = 0
|
||||
let hevSocksTunnelGroup = DispatchGroup()
|
||||
|
||||
func openVPNPacketFlow() -> OpenVPNAdapterPacketFlow {
|
||||
openVPNPacketFlowAdapter
|
||||
@@ -317,11 +316,10 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
||||
updateActiveInterfaceIndex(for: changePath)
|
||||
reasserting = true
|
||||
xrayLog(.info, message: "Applying network change to xray tunnel")
|
||||
stopXray { [weak self] in
|
||||
self?.startXray { [weak self] error in
|
||||
self?.reasserting = false
|
||||
completion(error)
|
||||
}
|
||||
stopXray { }
|
||||
startXray { [weak self] error in
|
||||
self?.reasserting = false
|
||||
completion(error)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ void TestXrayConfigModel::isValidSni_data()
|
||||
{
|
||||
QTest::addColumn<QString>("sni");
|
||||
QTest::addColumn<bool>("valid");
|
||||
QTest::newRow("empty") << "" << true;
|
||||
QTest::newRow("empty") << "" << false;
|
||||
QTest::newRow("domain") << "www.example.com" << true;
|
||||
QTest::newRow("ipv4") << "203.0.113.10" << true;
|
||||
QTest::newRow("star") << "*" << false;
|
||||
|
||||
@@ -58,6 +58,73 @@ void AwgConfigModel::setPort(const QString &value)
|
||||
emit changed();
|
||||
}
|
||||
|
||||
QString AwgConfigModel::cascadeEndpoint() const
|
||||
{
|
||||
return m_protocolConfig.serverConfig.cascadeEndpoint;
|
||||
}
|
||||
|
||||
void AwgConfigModel::setCascadeEndpoint(const QString &value)
|
||||
{
|
||||
if (m_protocolConfig.serverConfig.cascadeEndpoint == value) {
|
||||
return;
|
||||
}
|
||||
m_protocolConfig.serverConfig.cascadeEndpoint = value;
|
||||
emit changed();
|
||||
}
|
||||
|
||||
QString AwgConfigModel::cascadePort() const
|
||||
{
|
||||
return m_protocolConfig.serverConfig.cascadePort;
|
||||
}
|
||||
|
||||
void AwgConfigModel::setCascadePort(const QString &value)
|
||||
{
|
||||
if (m_protocolConfig.serverConfig.cascadePort == value) {
|
||||
return;
|
||||
}
|
||||
m_protocolConfig.serverConfig.cascadePort = value;
|
||||
emit changed();
|
||||
}
|
||||
|
||||
QString AwgConfigModel::clientHostName() const
|
||||
{
|
||||
return m_protocolConfig.clientConfig->hostName;
|
||||
}
|
||||
|
||||
QString AwgConfigModel::clientPort() const
|
||||
{
|
||||
const int port = m_protocolConfig.clientConfig->port;
|
||||
return port > 0 ? QString::number(port) : QString();
|
||||
}
|
||||
|
||||
QString AwgConfigModel::clientCascadeEndpoint() const
|
||||
{
|
||||
return m_protocolConfig.clientConfig->cascadeEndpoint;
|
||||
}
|
||||
|
||||
void AwgConfigModel::setClientCascadeEndpoint(const QString &value)
|
||||
{
|
||||
if (m_protocolConfig.clientConfig->cascadeEndpoint == value) {
|
||||
return;
|
||||
}
|
||||
m_protocolConfig.clientConfig->setCascade(value, m_protocolConfig.clientConfig->cascadePort);
|
||||
emit changed();
|
||||
}
|
||||
|
||||
QString AwgConfigModel::clientCascadePort() const
|
||||
{
|
||||
return m_protocolConfig.clientConfig->cascadePort;
|
||||
}
|
||||
|
||||
void AwgConfigModel::setClientCascadePort(const QString &value)
|
||||
{
|
||||
if (m_protocolConfig.clientConfig->cascadePort == value) {
|
||||
return;
|
||||
}
|
||||
m_protocolConfig.clientConfig->setCascade(m_protocolConfig.clientConfig->cascadeEndpoint, value);
|
||||
emit changed();
|
||||
}
|
||||
|
||||
QString AwgConfigModel::clientMtu() const
|
||||
{
|
||||
return m_protocolConfig.clientConfig->mtu;
|
||||
@@ -709,8 +776,15 @@ amnezia::AwgProtocolConfig AwgConfigModel::getProtocolConfig()
|
||||
{
|
||||
bool serverSettingsChanged = !m_protocolConfig.serverConfig.hasEqualServerSettings(m_originalProtocolConfig.serverConfig);
|
||||
|
||||
const auto &serverConfig = m_protocolConfig.serverConfig;
|
||||
const auto &originalServerConfig = m_originalProtocolConfig.serverConfig;
|
||||
const bool cascadeChanged = serverConfig.cascadeEndpoint != originalServerConfig.cascadeEndpoint
|
||||
|| serverConfig.cascadePort != originalServerConfig.cascadePort;
|
||||
|
||||
if (serverSettingsChanged) {
|
||||
m_protocolConfig.clearClientConfig();
|
||||
} else if (cascadeChanged) {
|
||||
m_protocolConfig.clientConfig->setCascade(serverConfig.cascadeEndpoint, serverConfig.cascadePort);
|
||||
}
|
||||
|
||||
return m_protocolConfig;
|
||||
|
||||
@@ -14,7 +14,13 @@ class AwgConfigModel : public QObject
|
||||
|
||||
Q_PROPERTY(QString subnetAddress READ subnetAddress WRITE setSubnetAddress NOTIFY changed)
|
||||
Q_PROPERTY(QString port READ port WRITE setPort NOTIFY changed)
|
||||
Q_PROPERTY(QString cascadeEndpoint READ cascadeEndpoint WRITE setCascadeEndpoint NOTIFY changed)
|
||||
Q_PROPERTY(QString cascadePort READ cascadePort WRITE setCascadePort NOTIFY changed)
|
||||
Q_PROPERTY(QString clientMtu READ clientMtu WRITE setClientMtu NOTIFY changed)
|
||||
Q_PROPERTY(QString clientHostName READ clientHostName NOTIFY changed)
|
||||
Q_PROPERTY(QString clientPort READ clientPort NOTIFY changed)
|
||||
Q_PROPERTY(QString clientCascadeEndpoint READ clientCascadeEndpoint WRITE setClientCascadeEndpoint NOTIFY changed)
|
||||
Q_PROPERTY(QString clientCascadePort READ clientCascadePort WRITE setClientCascadePort NOTIFY changed)
|
||||
Q_PROPERTY(QString clientJunkPacketCount READ clientJunkPacketCount WRITE setClientJunkPacketCount NOTIFY changed)
|
||||
Q_PROPERTY(QString clientJunkPacketMinSize READ clientJunkPacketMinSize WRITE setClientJunkPacketMinSize NOTIFY changed)
|
||||
Q_PROPERTY(QString clientJunkPacketMaxSize READ clientJunkPacketMaxSize WRITE setClientJunkPacketMaxSize NOTIFY changed)
|
||||
@@ -69,6 +75,21 @@ public:
|
||||
QString port() const;
|
||||
void setPort(const QString &value);
|
||||
|
||||
QString cascadeEndpoint() const;
|
||||
void setCascadeEndpoint(const QString &value);
|
||||
|
||||
QString cascadePort() const;
|
||||
void setCascadePort(const QString &value);
|
||||
|
||||
QString clientHostName() const;
|
||||
QString clientPort() const;
|
||||
|
||||
QString clientCascadeEndpoint() const;
|
||||
void setClientCascadeEndpoint(const QString &value);
|
||||
|
||||
QString clientCascadePort() const;
|
||||
void setClientCascadePort(const QString &value);
|
||||
|
||||
QString clientMtu() const;
|
||||
void setClientMtu(const QString &value);
|
||||
|
||||
|
||||
@@ -40,6 +40,73 @@ void WireGuardConfigModel::setPort(const QString &value)
|
||||
emit changed();
|
||||
}
|
||||
|
||||
QString WireGuardConfigModel::cascadeEndpoint() const
|
||||
{
|
||||
return m_protocolConfig.serverConfig.cascadeEndpoint;
|
||||
}
|
||||
|
||||
void WireGuardConfigModel::setCascadeEndpoint(const QString &value)
|
||||
{
|
||||
if (m_protocolConfig.serverConfig.cascadeEndpoint == value) {
|
||||
return;
|
||||
}
|
||||
m_protocolConfig.serverConfig.cascadeEndpoint = value;
|
||||
emit changed();
|
||||
}
|
||||
|
||||
QString WireGuardConfigModel::cascadePort() const
|
||||
{
|
||||
return m_protocolConfig.serverConfig.cascadePort;
|
||||
}
|
||||
|
||||
void WireGuardConfigModel::setCascadePort(const QString &value)
|
||||
{
|
||||
if (m_protocolConfig.serverConfig.cascadePort == value) {
|
||||
return;
|
||||
}
|
||||
m_protocolConfig.serverConfig.cascadePort = value;
|
||||
emit changed();
|
||||
}
|
||||
|
||||
QString WireGuardConfigModel::clientHostName() const
|
||||
{
|
||||
return m_protocolConfig.clientConfig->hostName;
|
||||
}
|
||||
|
||||
QString WireGuardConfigModel::clientPort() const
|
||||
{
|
||||
const int port = m_protocolConfig.clientConfig->port;
|
||||
return port > 0 ? QString::number(port) : QString();
|
||||
}
|
||||
|
||||
QString WireGuardConfigModel::clientCascadeEndpoint() const
|
||||
{
|
||||
return m_protocolConfig.clientConfig->cascadeEndpoint;
|
||||
}
|
||||
|
||||
void WireGuardConfigModel::setClientCascadeEndpoint(const QString &value)
|
||||
{
|
||||
if (m_protocolConfig.clientConfig->cascadeEndpoint == value) {
|
||||
return;
|
||||
}
|
||||
m_protocolConfig.clientConfig->setCascade(value, m_protocolConfig.clientConfig->cascadePort);
|
||||
emit changed();
|
||||
}
|
||||
|
||||
QString WireGuardConfigModel::clientCascadePort() const
|
||||
{
|
||||
return m_protocolConfig.clientConfig->cascadePort;
|
||||
}
|
||||
|
||||
void WireGuardConfigModel::setClientCascadePort(const QString &value)
|
||||
{
|
||||
if (m_protocolConfig.clientConfig->cascadePort == value) {
|
||||
return;
|
||||
}
|
||||
m_protocolConfig.clientConfig->setCascade(m_protocolConfig.clientConfig->cascadeEndpoint, value);
|
||||
emit changed();
|
||||
}
|
||||
|
||||
QString WireGuardConfigModel::clientMtu() const
|
||||
{
|
||||
if (m_protocolConfig.clientConfig.has_value()) {
|
||||
@@ -96,8 +163,15 @@ amnezia::WireGuardProtocolConfig WireGuardConfigModel::getProtocolConfig()
|
||||
{
|
||||
bool serverSettingsChanged = !m_protocolConfig.serverConfig.hasEqualServerSettings(m_originalProtocolConfig.serverConfig);
|
||||
|
||||
const auto &serverConfig = m_protocolConfig.serverConfig;
|
||||
const auto &originalServerConfig = m_originalProtocolConfig.serverConfig;
|
||||
const bool cascadeChanged = serverConfig.cascadeEndpoint != originalServerConfig.cascadeEndpoint
|
||||
|| serverConfig.cascadePort != originalServerConfig.cascadePort;
|
||||
|
||||
if (serverSettingsChanged) {
|
||||
m_protocolConfig.clearClientConfig();
|
||||
} else if (cascadeChanged) {
|
||||
m_protocolConfig.clientConfig->setCascade(serverConfig.cascadeEndpoint, serverConfig.cascadePort);
|
||||
}
|
||||
|
||||
return m_protocolConfig;
|
||||
|
||||
@@ -14,7 +14,13 @@ class WireGuardConfigModel : public QObject
|
||||
|
||||
Q_PROPERTY(QString subnetAddress READ subnetAddress WRITE setSubnetAddress NOTIFY changed)
|
||||
Q_PROPERTY(QString port READ port WRITE setPort NOTIFY changed)
|
||||
Q_PROPERTY(QString cascadeEndpoint READ cascadeEndpoint WRITE setCascadeEndpoint NOTIFY changed)
|
||||
Q_PROPERTY(QString cascadePort READ cascadePort WRITE setCascadePort NOTIFY changed)
|
||||
Q_PROPERTY(QString clientMtu READ clientMtu WRITE setClientMtu NOTIFY changed)
|
||||
Q_PROPERTY(QString clientHostName READ clientHostName NOTIFY changed)
|
||||
Q_PROPERTY(QString clientPort READ clientPort NOTIFY changed)
|
||||
Q_PROPERTY(QString clientCascadeEndpoint READ clientCascadeEndpoint WRITE setClientCascadeEndpoint NOTIFY changed)
|
||||
Q_PROPERTY(QString clientCascadePort READ clientCascadePort WRITE setClientCascadePort NOTIFY changed)
|
||||
|
||||
public:
|
||||
explicit WireGuardConfigModel(QObject *parent = nullptr);
|
||||
@@ -25,6 +31,21 @@ public:
|
||||
QString port() const;
|
||||
void setPort(const QString &value);
|
||||
|
||||
QString cascadeEndpoint() const;
|
||||
void setCascadeEndpoint(const QString &value);
|
||||
|
||||
QString cascadePort() const;
|
||||
void setCascadePort(const QString &value);
|
||||
|
||||
QString clientHostName() const;
|
||||
QString clientPort() const;
|
||||
|
||||
QString clientCascadeEndpoint() const;
|
||||
void setClientCascadeEndpoint(const QString &value);
|
||||
|
||||
QString clientCascadePort() const;
|
||||
void setClientCascadePort(const QString &value);
|
||||
|
||||
QString clientMtu() const;
|
||||
void setClientMtu(const QString &value);
|
||||
|
||||
|
||||
@@ -759,7 +759,7 @@ QStringList XrayConfigModel::transportOptions()
|
||||
|
||||
QStringList XrayConfigModel::fingerprintOptions()
|
||||
{
|
||||
return { "hellochrome_120", "chrome", "firefox", "safari", "ios", "android", "edge", "360", "qq", "random" };
|
||||
return { "chrome", "firefox", "safari", "ios", "android", "edge", "360", "qq", "random" };
|
||||
}
|
||||
|
||||
QStringList XrayConfigModel::alpnOptions()
|
||||
@@ -833,11 +833,6 @@ QString XrayConfigModel::portDefault()
|
||||
return QString::fromLatin1(protocols::xray::defaultPort);
|
||||
}
|
||||
|
||||
QString XrayConfigModel::sniDefault()
|
||||
{
|
||||
return QString::fromLatin1(protocols::xray::defaultSni);
|
||||
}
|
||||
|
||||
QString XrayConfigModel::xhttpHostDefault()
|
||||
{
|
||||
return QString::fromLatin1(protocols::xray::defaultXhttpHost);
|
||||
@@ -933,10 +928,7 @@ bool XrayConfigModel::isValidHost(const QString &host)
|
||||
bool XrayConfigModel::isValidSni(const QString &sni)
|
||||
{
|
||||
const QString t = sni.trimmed();
|
||||
if (t.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
if (t.contains(QLatin1Char('*'))) {
|
||||
if (t.isEmpty() || t.contains(QLatin1Char('*'))) {
|
||||
return false;
|
||||
}
|
||||
return isValidSingleHost(t);
|
||||
|
||||
@@ -251,7 +251,6 @@ public:
|
||||
Q_INVOKABLE static QString mkcpDefaultCwndMultiplier();
|
||||
|
||||
Q_INVOKABLE static QString portDefault();
|
||||
Q_INVOKABLE static QString sniDefault();
|
||||
Q_INVOKABLE static QString xhttpHostDefault();
|
||||
Q_INVOKABLE static QString xhttpUplinkChunkSizeDefault();
|
||||
Q_INVOKABLE static QString scMaxEachPostBytesMinDefault();
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
import MtProxyConfig 1.0
|
||||
|
||||
import "../Controls2"
|
||||
import "../Controls2/TextTypes"
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
|
||||
property string endpoint
|
||||
property string port
|
||||
property string endpointPlaceholder
|
||||
property string portPlaceholder
|
||||
property bool warningVisible: false
|
||||
property var scroller: null
|
||||
|
||||
signal endpointEdited(string text)
|
||||
signal portEdited(string text)
|
||||
|
||||
spacing: 12
|
||||
|
||||
H2TextType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 28
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
text: qsTr("Cascade connection")
|
||||
}
|
||||
|
||||
NotificationType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
visible: root.warningVisible
|
||||
|
||||
variant: NotificationType.Warning
|
||||
text: qsTr("Cascade endpoint and port are the address and port of the entry server that forwards traffic to this server. New client configs will connect to them instead of this server's address and port. Existing configs are not changed")
|
||||
}
|
||||
|
||||
TextFieldType {
|
||||
id: endpointTextField
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
headerText: qsTr("Cascade endpoint")
|
||||
textField.placeholderText: root.endpointPlaceholder
|
||||
textField.text: root.endpoint
|
||||
textField.maximumLength: 253
|
||||
textField.validator: PublicHostInputValidator {}
|
||||
|
||||
textField.onTextEdited: root.endpointEdited(textField.text.trim())
|
||||
|
||||
textField.onActiveFocusChanged: {
|
||||
if (textField.activeFocus && root.scroller) {
|
||||
root.scroller.scrollToItem(endpointTextField)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextFieldType {
|
||||
id: portTextField
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
headerText: qsTr("Cascade port")
|
||||
textField.placeholderText: root.portPlaceholder
|
||||
textField.text: root.port
|
||||
textField.maximumLength: 5
|
||||
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
||||
|
||||
textField.onTextEdited: root.portEdited(textField.text)
|
||||
|
||||
textField.onActiveFocusChanged: {
|
||||
if (textField.activeFocus && root.scroller) {
|
||||
root.scroller.scrollToItem(portTextField)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -118,7 +118,6 @@ Item {
|
||||
|
||||
enabled: d.scrolled > 0
|
||||
acceptedButtons: Qt.AllButtons
|
||||
hoverEnabled: true
|
||||
}
|
||||
|
||||
IconButtonType {
|
||||
|
||||
@@ -15,16 +15,6 @@ TabButton {
|
||||
readonly property int maximumHorizontalPadding: root.size === TabButtonType.Large ? 24 : 10
|
||||
|
||||
implicitWidth: implicitContentWidth + 2 * root.maximumHorizontalPadding
|
||||
width: {
|
||||
if (!root.visible) {
|
||||
return 0
|
||||
}
|
||||
const tabBar = root.TabBar.tabBar
|
||||
if (!tabBar || tabBar.visibleTabCount === undefined) {
|
||||
return implicitWidth
|
||||
}
|
||||
return tabBar.availableWidth / Math.max(1, tabBar.visibleTabCount)
|
||||
}
|
||||
implicitHeight: root.size === TabButtonType.Large ? 48 : 36
|
||||
|
||||
horizontalPadding: Math.max(4, Math.min(root.maximumHorizontalPadding, (root.width - implicitContentWidth) / 2))
|
||||
|
||||
@@ -4,17 +4,6 @@ import QtQuick.Controls
|
||||
TabBar {
|
||||
id: root
|
||||
|
||||
readonly property int visibleTabCount: {
|
||||
let visibleCount = 0
|
||||
for (let i = 0; i < root.count; ++i) {
|
||||
const tab = root.itemAt(i)
|
||||
if (tab && tab.visible) {
|
||||
++visibleCount
|
||||
}
|
||||
}
|
||||
return visibleCount
|
||||
}
|
||||
|
||||
spacing: 0
|
||||
background: null
|
||||
}
|
||||
@@ -271,6 +271,20 @@ PageType {
|
||||
}
|
||||
}
|
||||
|
||||
CascadeSettings {
|
||||
Layout.fillWidth: true
|
||||
|
||||
scroller: smartScroll
|
||||
|
||||
endpoint: AwgConfigModel.clientCascadeEndpoint
|
||||
port: AwgConfigModel.clientCascadePort
|
||||
endpointPlaceholder: AwgConfigModel.clientHostName
|
||||
portPlaceholder: AwgConfigModel.clientPort
|
||||
|
||||
onEndpointEdited: (text) => { AwgConfigModel.clientCascadeEndpoint = text }
|
||||
onPortEdited: (text) => { AwgConfigModel.clientCascadePort = text }
|
||||
}
|
||||
|
||||
H2TextType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 28
|
||||
|
||||
@@ -464,6 +464,23 @@ PageType {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CascadeSettings {
|
||||
Layout.fillWidth: true
|
||||
|
||||
enabled: root.isEnabled
|
||||
|
||||
warningVisible: true
|
||||
scroller: smartScroll
|
||||
|
||||
endpoint: AwgConfigModel.cascadeEndpoint
|
||||
port: AwgConfigModel.cascadePort
|
||||
endpointPlaceholder: ServersUiController.serverHostName(ServersUiController.processedServerId)
|
||||
portPlaceholder: AwgConfigModel.port
|
||||
|
||||
onEndpointEdited: (text) => { AwgConfigModel.cascadeEndpoint = text }
|
||||
onPortEdited: (text) => { AwgConfigModel.cascadePort = text }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -60,6 +60,18 @@ PageType {
|
||||
checkEmptyText: true
|
||||
}
|
||||
|
||||
CascadeSettings {
|
||||
Layout.fillWidth: true
|
||||
|
||||
endpoint: WireGuardConfigModel.clientCascadeEndpoint
|
||||
port: WireGuardConfigModel.clientCascadePort
|
||||
endpointPlaceholder: WireGuardConfigModel.clientHostName
|
||||
portPlaceholder: WireGuardConfigModel.clientPort
|
||||
|
||||
onEndpointEdited: (text) => { WireGuardConfigModel.clientCascadeEndpoint = text }
|
||||
onPortEdited: (text) => { WireGuardConfigModel.clientCascadePort = text }
|
||||
}
|
||||
|
||||
H2TextType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 40
|
||||
|
||||
@@ -77,6 +77,20 @@ PageType {
|
||||
|
||||
checkEmptyText: true
|
||||
}
|
||||
|
||||
CascadeSettings {
|
||||
Layout.fillWidth: true
|
||||
|
||||
warningVisible: true
|
||||
|
||||
endpoint: WireGuardConfigModel.cascadeEndpoint
|
||||
port: WireGuardConfigModel.cascadePort
|
||||
endpointPlaceholder: ServersUiController.serverHostName(ServersUiController.processedServerId)
|
||||
portPlaceholder: WireGuardConfigModel.port
|
||||
|
||||
onEndpointEdited: (text) => { WireGuardConfigModel.cascadeEndpoint = text }
|
||||
onPortEdited: (text) => { WireGuardConfigModel.cascadePort = text }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -159,7 +159,6 @@ PageType {
|
||||
id: sniFieldTls
|
||||
Layout.fillWidth: true
|
||||
headerText: qsTr("Server Name (SNI)")
|
||||
placeholderText: XrayConfigModel.sniDefault()
|
||||
textField.text: XrayConfigModel.sni
|
||||
textField.validator: RegularExpressionValidator { regularExpression: /^[A-Za-z0-9._-]*$/ }
|
||||
textField.onTextEdited: XrayConfigModel.sni = textField.text
|
||||
@@ -216,7 +215,6 @@ PageType {
|
||||
id: sniFieldReality
|
||||
Layout.fillWidth: true
|
||||
headerText: qsTr("Server Name (SNI)")
|
||||
placeholderText: XrayConfigModel.sniDefault()
|
||||
textField.text: XrayConfigModel.sni
|
||||
textField.validator: RegularExpressionValidator { regularExpression: /^[A-Za-z0-9._-]*$/ }
|
||||
textField.onTextEdited: XrayConfigModel.sni = textField.text
|
||||
|
||||
@@ -21,13 +21,30 @@ PageType {
|
||||
readonly property int pageSettingsServerServices: 1
|
||||
readonly property int pageSettingsServerData: 2
|
||||
|
||||
readonly property var tabTitles: [qsTr("Protocols"), qsTr("Services"), qsTr("Management")]
|
||||
readonly property var availableTabs: {
|
||||
const tabs = []
|
||||
if (protocolsPage.installedProtocolsCount > 0) {
|
||||
tabs.push(root.pageSettingsServerProtocols)
|
||||
}
|
||||
if (servicesPage.installedServicesCount > 0) {
|
||||
tabs.push(root.pageSettingsServerServices)
|
||||
}
|
||||
tabs.push(root.pageSettingsServerData)
|
||||
return tabs
|
||||
}
|
||||
|
||||
property int currentTab: (ServersUiController.isServerFromApi(ServersUiController.processedServerId)
|
||||
&& !ServersUiController.serverHasInstalledContainers(ServersUiController.processedServerId)) ?
|
||||
root.pageSettingsServerData : root.pageSettingsServerProtocols
|
||||
|
||||
property var processedServer
|
||||
|
||||
Connections {
|
||||
target: PageController
|
||||
|
||||
function onGoToPageSettingsServerServices() {
|
||||
tabBar.setCurrentIndex(root.pageSettingsServerServices)
|
||||
root.currentTab = root.pageSettingsServerServices
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,25 +128,18 @@ PageType {
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
currentIndex: (ServersUiController.isServerFromApi(ServersUiController.processedServerId)
|
||||
&& !ServersUiController.serverHasInstalledContainers(ServersUiController.processedServerId)) ?
|
||||
root.pageSettingsServerData : root.pageSettingsServerProtocols
|
||||
currentIndex: root.availableTabs.indexOf(root.currentTab)
|
||||
|
||||
TabButtonType {
|
||||
id: protocolsTab
|
||||
visible: protocolsPage.installedProtocolsCount > 0
|
||||
text: qsTr("Protocols")
|
||||
}
|
||||
Repeater {
|
||||
model: root.availableTabs
|
||||
|
||||
TabButtonType {
|
||||
id: servicesTab
|
||||
visible: servicesPage.installedServicesCount > 0
|
||||
text: qsTr("Services")
|
||||
}
|
||||
TabButtonType {
|
||||
required property int modelData
|
||||
|
||||
TabButtonType {
|
||||
id: dataTab
|
||||
text: qsTr("Management")
|
||||
text: root.tabTitles[modelData]
|
||||
|
||||
onClicked: root.currentTab = modelData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,7 +150,7 @@ PageType {
|
||||
Layout.fillHeight: true
|
||||
Layout.topMargin: 24
|
||||
|
||||
currentIndex: tabBar.currentIndex
|
||||
currentIndex: root.currentTab
|
||||
|
||||
PageSettingsServerProtocols {
|
||||
id: protocolsPage
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<RCC>
|
||||
<qresource prefix="/ui/qml">
|
||||
<file>Components/CopyableValueRow.qml</file>
|
||||
<file>Components/CascadeSettings.qml</file>
|
||||
<file>Components/ConfigContentSheet.qml</file>
|
||||
<file>Components/QrCodeCard.qml</file>
|
||||
<file>Components/ShareClientInfoSheet.qml</file>
|
||||
|
||||
@@ -9,7 +9,7 @@ import os
|
||||
|
||||
class AwgApple(ConanFile):
|
||||
name = "awg-apple"
|
||||
version = "3.1.5"
|
||||
version = "3.1.4"
|
||||
settings = "os", "arch", "compiler"
|
||||
|
||||
@property
|
||||
@@ -45,7 +45,7 @@ class AwgApple(ConanFile):
|
||||
|
||||
def source(self):
|
||||
get(self, f"https://github.com/amnezia-vpn/amneziawg-apple/archive/refs/tags/v{self.version}.zip",
|
||||
sha256="b3bd3680fa966dae67162c261e1b0a42235a0bd706ec6ea67cc04e707ef3b7a8", strip_root=True
|
||||
sha256="09d7b760d18232fdf121ed2286b2f171b501dc31137e5e7d557c1ee3a99ef772", strip_root=True
|
||||
)
|
||||
|
||||
def generate(self):
|
||||
|
||||
Reference in new issue
Block a user