mirror of
https://github.com/Mahdi-zarei/nekoray.git
synced 2025-12-19 05:30:06 +08:00
Implement new classes
This commit is contained in:
parent
8b9753627a
commit
3e9a5aa5c3
@ -227,6 +227,13 @@ set(PROJECT_SOURCES
|
||||
include/configs/common/multiplex.h
|
||||
include/configs/common/transport.h
|
||||
include/configs/common/Outbound.h
|
||||
|
||||
# common impl
|
||||
src/configs/common/DialFields.cpp
|
||||
src/configs/common/TLS.cpp
|
||||
src/configs/common/multiplex.cpp
|
||||
src/configs/common/transport.cpp
|
||||
src/configs/common/Outbound.cpp
|
||||
include/configs/outbounds/socks.h
|
||||
include/configs/outbounds/http.h
|
||||
include/configs/outbounds/shadowsocks.h
|
||||
@ -238,6 +245,24 @@ set(PROJECT_SOURCES
|
||||
include/configs/outbounds/hysteria2.h
|
||||
include/configs/outbounds/anyTLS.h
|
||||
include/configs/outbounds/ssh.h
|
||||
|
||||
# outbounds impl
|
||||
src/configs/outbounds/anyTLS.cpp
|
||||
src/configs/outbounds/http.cpp
|
||||
src/configs/outbounds/hysteria.cpp
|
||||
src/configs/outbounds/hysteria2.cpp
|
||||
src/configs/outbounds/shadowsocks.cpp
|
||||
src/configs/outbounds/socks.cpp
|
||||
src/configs/outbounds/ssh.cpp
|
||||
src/configs/outbounds/tailscale.cpp
|
||||
src/configs/outbounds/trojan.cpp
|
||||
src/configs/outbounds/tuic.cpp
|
||||
src/configs/outbounds/vless.cpp
|
||||
src/configs/outbounds/vmess.cpp
|
||||
src/configs/outbounds/wireguard.cpp
|
||||
include/configs/generate.h
|
||||
include/configs/common/utils.h
|
||||
src/configs/common/utils.cpp
|
||||
)
|
||||
|
||||
if (NOT APPLE AND Qt6_VERSION VERSION_GREATER_EQUAL 6.9.0)
|
||||
|
||||
@ -1,7 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <QJsonObject>
|
||||
#include <QString>
|
||||
#include <include/global/Utils.hpp>
|
||||
|
||||
#include "generate.h"
|
||||
#include "common/Outbound.h"
|
||||
#include "include/global/ConfigItem.hpp"
|
||||
|
||||
namespace Configs
|
||||
@ -9,30 +12,44 @@ namespace Configs
|
||||
class baseConfig : public JsonStore
|
||||
{
|
||||
public:
|
||||
virtual bool ParseFromLink(QString link);
|
||||
virtual bool ParseFromLink(const QString& link);
|
||||
|
||||
virtual bool ParseFromJson(QJsonObject object);
|
||||
virtual bool ParseFromJson(const QJsonObject& object);
|
||||
|
||||
virtual QString ExportToLink();
|
||||
|
||||
virtual QJsonObject ExportToJson();
|
||||
|
||||
virtual QJsonObject Build();
|
||||
virtual BuildResult Build();
|
||||
};
|
||||
|
||||
class outboundMeta
|
||||
class outbound : public baseConfig
|
||||
{
|
||||
public:
|
||||
std::shared_ptr<OutboundCommons> commons = std::make_shared<OutboundCommons>();
|
||||
|
||||
void ResolveDomainToIP(const std::function<void()> &onFinished);
|
||||
|
||||
virtual QString DisplayAddress();
|
||||
virtual QString DisplayAddress()
|
||||
{
|
||||
return ::DisplayAddress(commons->server, commons->server_port);
|
||||
}
|
||||
|
||||
virtual QString DisplayName();
|
||||
QString DisplayName()
|
||||
{
|
||||
if (commons->name.isEmpty()) {
|
||||
return DisplayAddress();
|
||||
}
|
||||
return commons->name;
|
||||
}
|
||||
|
||||
virtual QString DisplayType() { return {}; };
|
||||
|
||||
virtual QString DisplayTypeAndName();
|
||||
QString DisplayTypeAndName()
|
||||
{
|
||||
return QString("[%1] %2").arg(DisplayType(), DisplayName());
|
||||
}
|
||||
|
||||
virtual bool IsEndpoint() { return false; };
|
||||
static bool IsEndpoint() { return false; };
|
||||
};
|
||||
}
|
||||
|
||||
@ -20,5 +20,12 @@ namespace Configs
|
||||
_add(new configItem("tcp_multi_path", &tcp_multi_path, itemType::boolean));
|
||||
_add(new configItem("udp_fragment", &udp_fragment, itemType::boolean));
|
||||
}
|
||||
|
||||
// baseConfig overrides
|
||||
bool ParseFromLink(const QString& link) override;
|
||||
bool ParseFromJson(const QJsonObject& object) override;
|
||||
QString ExportToLink() override;
|
||||
QJsonObject ExportToJson() override;
|
||||
BuildResult Build() override;
|
||||
};
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#include "DialFields.h"
|
||||
#include "include/configs/baseConfig.h"
|
||||
|
||||
namespace Configs
|
||||
@ -6,21 +7,25 @@ namespace Configs
|
||||
class OutboundCommons : public baseConfig
|
||||
{
|
||||
public:
|
||||
QString type;
|
||||
virtual ~OutboundCommons() = default;
|
||||
QString name;
|
||||
int id = -1;
|
||||
QString server;
|
||||
int server_port = 0;
|
||||
std::shared_ptr<DialFields> dialFields = std::make_shared<DialFields>();
|
||||
|
||||
OutboundCommons()
|
||||
{
|
||||
_add(new configItem("type", &type, string));
|
||||
_add(new configItem("name", &name, string));
|
||||
_add(new configItem("id", &id, integer));
|
||||
_add(new configItem("server", &server, string));
|
||||
_add(new configItem("server_port", &server_port, integer));
|
||||
_add(new configItem("dial_fields", dynamic_cast<JsonStore *>(dialFields.get()), jsonStore));
|
||||
}
|
||||
|
||||
// baseConfig overrides
|
||||
bool ParseFromLink(const QString& link) override;
|
||||
bool ParseFromJson(const QJsonObject& object) override;
|
||||
QString ExportToLink() override;
|
||||
QJsonObject ExportToJson() override;
|
||||
BuildResult Build() override;
|
||||
};
|
||||
}
|
||||
|
||||
@ -17,6 +17,13 @@ namespace Configs
|
||||
_add(new configItem("enabled", &enabled, boolean));
|
||||
_add(new configItem("fingerprint", &fingerPrint, string));
|
||||
}
|
||||
|
||||
// baseConfig overrides
|
||||
bool ParseFromLink(const QString& link) override;
|
||||
bool ParseFromJson(const QJsonObject& object) override;
|
||||
QString ExportToLink() override;
|
||||
QJsonObject ExportToJson() override;
|
||||
BuildResult Build() override;
|
||||
};
|
||||
|
||||
class ECH : public baseConfig
|
||||
@ -32,6 +39,13 @@ namespace Configs
|
||||
_add(new configItem("config", &config, stringList));
|
||||
_add(new configItem("config_path", &config_path, string));
|
||||
}
|
||||
|
||||
// baseConfig overrides
|
||||
bool ParseFromLink(const QString& link) override;
|
||||
bool ParseFromJson(const QJsonObject& object) override;
|
||||
QString ExportToLink() override;
|
||||
QJsonObject ExportToJson() override;
|
||||
BuildResult Build() override;
|
||||
};
|
||||
|
||||
class Reality : public baseConfig
|
||||
@ -47,6 +61,13 @@ namespace Configs
|
||||
_add(new configItem("public_key", &public_key, string));
|
||||
_add(new configItem("short_id", &short_id, string));
|
||||
}
|
||||
|
||||
// baseConfig overrides
|
||||
bool ParseFromLink(const QString& link) override;
|
||||
bool ParseFromJson(const QJsonObject& object) override;
|
||||
QString ExportToLink() override;
|
||||
QJsonObject ExportToJson() override;
|
||||
BuildResult Build() override;
|
||||
};
|
||||
|
||||
class TLS : public baseConfig
|
||||
@ -100,5 +121,12 @@ namespace Configs
|
||||
_add(new configItem("utls", dynamic_cast<JsonStore *>(utls.get()), jsonStore));
|
||||
_add(new configItem("reality", dynamic_cast<JsonStore *>(reality.get()), jsonStore));
|
||||
}
|
||||
|
||||
// baseConfig overrides
|
||||
bool ParseFromLink(const QString& link) override;
|
||||
bool ParseFromJson(const QJsonObject& object) override;
|
||||
QString ExportToLink() override;
|
||||
QJsonObject ExportToJson() override;
|
||||
BuildResult Build() override;
|
||||
};
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
|
||||
namespace Configs
|
||||
{
|
||||
inline QStringLists muxProtocols = {"smux", "yamux", "h2mux"};
|
||||
inline QStringList muxProtocols = {"smux", "yamux", "h2mux"};
|
||||
|
||||
class TcpBrutal : public baseConfig
|
||||
{
|
||||
@ -18,12 +18,20 @@ namespace Configs
|
||||
_add(new configItem("up_mbps", &up_mbps, integer));
|
||||
_add(new configItem("down_mbps", &down_mbps, integer));
|
||||
}
|
||||
|
||||
// baseConfig overrides
|
||||
bool ParseFromLink(const QString& link) override;
|
||||
bool ParseFromJson(const QJsonObject& object) override;
|
||||
QString ExportToLink() override;
|
||||
QJsonObject ExportToJson() override;
|
||||
BuildResult Build() override;
|
||||
};
|
||||
|
||||
class Multiplex : public baseConfig
|
||||
{
|
||||
public:
|
||||
bool enabled = false;
|
||||
bool unspecified = false;
|
||||
QString protocol;
|
||||
int max_connections = 0;
|
||||
int min_streams = 0;
|
||||
@ -34,6 +42,7 @@ namespace Configs
|
||||
Multiplex()
|
||||
{
|
||||
_add(new configItem("enabled", &enabled, boolean));
|
||||
_add(new configItem("unspecified", &unspecified, boolean));
|
||||
_add(new configItem("protocol", &protocol, string));
|
||||
_add(new configItem("max_connections", &max_connections, integer));
|
||||
_add(new configItem("min_streams", &min_streams, integer));
|
||||
@ -41,5 +50,12 @@ namespace Configs
|
||||
_add(new configItem("padding", &padding, boolean));
|
||||
_add(new configItem("brutal", dynamic_cast<JsonStore *>(brutal.get()), jsonStore));
|
||||
}
|
||||
|
||||
// baseConfig overrides
|
||||
bool ParseFromLink(const QString& link) override;
|
||||
bool ParseFromJson(const QJsonObject& object) override;
|
||||
QString ExportToLink() override;
|
||||
QJsonObject ExportToJson() override;
|
||||
BuildResult Build() override;
|
||||
};
|
||||
}
|
||||
|
||||
@ -36,5 +36,12 @@ namespace Configs
|
||||
_add(new configItem("early_data_header_name", &early_data_header_name, string));
|
||||
_add(new configItem("service_name", &service_name, string));
|
||||
}
|
||||
|
||||
// baseConfig overrides
|
||||
bool ParseFromLink(const QString& link) override;
|
||||
bool ParseFromJson(const QJsonObject& object) override;
|
||||
QString ExportToLink() override;
|
||||
QJsonObject ExportToJson() override;
|
||||
BuildResult Build() override;
|
||||
};
|
||||
}
|
||||
|
||||
14
include/configs/common/utils.h
Normal file
14
include/configs/common/utils.h
Normal file
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
#include <QJsonObject>
|
||||
#include <QUrlQuery>
|
||||
|
||||
namespace Configs
|
||||
{
|
||||
void mergeUrlQuery(QUrlQuery& baseQuery, const QString& strQuery);
|
||||
|
||||
void mergeJsonObjects(QJsonObject& baseObject, const QJsonObject& obj);
|
||||
|
||||
QStringList jsonObjectToQStringList(const QJsonObject& obj);
|
||||
|
||||
QJsonObject qStringListToJsonObject(const QStringList& list);
|
||||
}
|
||||
10
include/configs/generate.h
Normal file
10
include/configs/generate.h
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
#include <QJsonObject>
|
||||
|
||||
namespace Configs
|
||||
{
|
||||
struct BuildResult {
|
||||
QJsonObject object;
|
||||
QString error;
|
||||
};
|
||||
}
|
||||
@ -5,10 +5,9 @@
|
||||
|
||||
namespace Configs
|
||||
{
|
||||
class anyTLS : public baseConfig, public outboundMeta
|
||||
class anyTLS : public outbound
|
||||
{
|
||||
public:
|
||||
std::shared_ptr<OutboundCommons> commons = std::make_shared<OutboundCommons>();
|
||||
QString password;
|
||||
QString idle_session_check_interval = "30s";
|
||||
QString idle_session_timeout = "30s";
|
||||
@ -24,5 +23,14 @@ namespace Configs
|
||||
_add(new configItem("min_idle_session", &min_idle_session, integer));
|
||||
_add(new configItem("tls", dynamic_cast<JsonStore *>(tls.get()), jsonStore));
|
||||
}
|
||||
|
||||
// baseConfig overrides
|
||||
bool ParseFromLink(const QString& link) override;
|
||||
bool ParseFromJson(const QJsonObject& object) override;
|
||||
QString ExportToLink() override;
|
||||
QJsonObject ExportToJson() override;
|
||||
BuildResult Build() override;
|
||||
|
||||
QString DisplayType() override;
|
||||
};
|
||||
}
|
||||
|
||||
@ -6,10 +6,9 @@
|
||||
|
||||
namespace Configs
|
||||
{
|
||||
class http : public baseConfig, public outboundMeta
|
||||
class http : public outbound
|
||||
{
|
||||
public:
|
||||
std::shared_ptr<OutboundCommons> commons = std::make_shared<OutboundCommons>();
|
||||
QString username;
|
||||
QString password;
|
||||
QString path;
|
||||
@ -25,5 +24,14 @@ namespace Configs
|
||||
_add(new configItem("headers", &headers, stringList));
|
||||
_add(new configItem("tls", dynamic_cast<JsonStore *>(tls.get()), jsonStore));
|
||||
}
|
||||
|
||||
// baseConfig overrides
|
||||
bool ParseFromLink(const QString& link) override;
|
||||
bool ParseFromJson(const QJsonObject& object) override;
|
||||
QString ExportToLink() override;
|
||||
QJsonObject ExportToJson() override;
|
||||
BuildResult Build() override;
|
||||
|
||||
QString DisplayType() override;
|
||||
};
|
||||
}
|
||||
|
||||
@ -5,10 +5,9 @@
|
||||
|
||||
namespace Configs
|
||||
{
|
||||
class hysteria : public baseConfig, public outboundMeta
|
||||
class hysteria : public outbound
|
||||
{
|
||||
public:
|
||||
std::shared_ptr<OutboundCommons> commons = std::make_shared<OutboundCommons>();
|
||||
QStringList server_ports;
|
||||
QString hop_interval;
|
||||
int up_mbps = 0;
|
||||
@ -36,5 +35,14 @@ namespace Configs
|
||||
_add(new configItem("disable_mtu_discovery", &disable_mtu_discovery, boolean));
|
||||
_add(new configItem("tls", dynamic_cast<JsonStore *>(tls.get()), jsonStore));
|
||||
}
|
||||
|
||||
// baseConfig overrides
|
||||
bool ParseFromLink(const QString& link) override;
|
||||
bool ParseFromJson(const QJsonObject& object) override;
|
||||
QString ExportToLink() override;
|
||||
QJsonObject ExportToJson() override;
|
||||
BuildResult Build() override;
|
||||
|
||||
QString DisplayType() override;
|
||||
};
|
||||
}
|
||||
|
||||
@ -5,10 +5,9 @@
|
||||
|
||||
namespace Configs
|
||||
{
|
||||
class hysteria2 : public baseConfig, public outboundMeta
|
||||
class hysteria2 : public outbound
|
||||
{
|
||||
public:
|
||||
std::shared_ptr<OutboundCommons> commons = std::make_shared<OutboundCommons>();
|
||||
QStringList server_ports;
|
||||
QString hop_interval;
|
||||
int up_mbps = 0;
|
||||
@ -30,5 +29,14 @@ namespace Configs
|
||||
_add(new configItem("password", &password, string));
|
||||
_add(new configItem("tls", dynamic_cast<JsonStore *>(tls.get()), jsonStore));
|
||||
}
|
||||
|
||||
// baseConfig overrides
|
||||
bool ParseFromLink(const QString& link) override;
|
||||
bool ParseFromJson(const QJsonObject& object) override;
|
||||
QString ExportToLink() override;
|
||||
QJsonObject ExportToJson() override;
|
||||
BuildResult Build() override;
|
||||
|
||||
QString DisplayType() override;
|
||||
};
|
||||
}
|
||||
|
||||
@ -11,16 +11,15 @@ namespace Configs
|
||||
|
||||
inline QStringList shadowsocksMethods = {"2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305", "none", "aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "rc4-md5", "chacha20-ietf", "xchacha20"};
|
||||
|
||||
class shadowsocks : public baseConfig, public outboundMeta
|
||||
class shadowsocks : public outbound
|
||||
{
|
||||
public:
|
||||
std::shared_ptr<OutboundCommons> commons = std::make_shared<OutboundCommons>();
|
||||
QString method;
|
||||
QString password;
|
||||
QString plugin;
|
||||
QString plugin_opts;
|
||||
bool uot = false;
|
||||
std::shared_ptr<Multiplex> mux = std::make_shared<Multiplex>();
|
||||
std::shared_ptr<Multiplex> multiplex = std::make_shared<Multiplex>();
|
||||
|
||||
shadowsocks()
|
||||
{
|
||||
@ -30,7 +29,16 @@ namespace Configs
|
||||
_add(new configItem("plugin", &plugin, string));
|
||||
_add(new configItem("plugin_opts", &plugin_opts, string));
|
||||
_add(new configItem("uot", &uot, itemType::boolean));
|
||||
_add(new configItem("mux", dynamic_cast<JsonStore *>(mux.get()), jsonStore));
|
||||
_add(new configItem("multiplex", dynamic_cast<JsonStore *>(multiplex.get()), jsonStore));
|
||||
}
|
||||
|
||||
// baseConfig overrides
|
||||
bool ParseFromLink(const QString& link) override;
|
||||
bool ParseFromJson(const QJsonObject& object) override;
|
||||
QString ExportToLink() override;
|
||||
QJsonObject ExportToJson() override;
|
||||
BuildResult Build() override;
|
||||
|
||||
QString DisplayType() override;
|
||||
};
|
||||
}
|
||||
|
||||
@ -5,12 +5,12 @@
|
||||
|
||||
namespace Configs
|
||||
{
|
||||
class socks : public baseConfig, public outboundMeta
|
||||
class socks : public outbound
|
||||
{
|
||||
public:
|
||||
std::shared_ptr<OutboundCommons> commons = std::make_shared<OutboundCommons>();
|
||||
QString username;
|
||||
QString password;
|
||||
int version = 5;
|
||||
bool uot = false;
|
||||
|
||||
socks()
|
||||
@ -18,7 +18,17 @@ namespace Configs
|
||||
_add(new configItem("commons", dynamic_cast<JsonStore *>(commons.get()), jsonStore));
|
||||
_add(new configItem("username", &username, string));
|
||||
_add(new configItem("password", &password, string));
|
||||
_add(new configItem("version", &version, integer));
|
||||
_add(new configItem("uot", &uot, boolean));
|
||||
}
|
||||
|
||||
// baseConfig overrides
|
||||
bool ParseFromLink(const QString& link) override;
|
||||
bool ParseFromJson(const QJsonObject& object) override;
|
||||
QString ExportToLink() override;
|
||||
QJsonObject ExportToJson() override;
|
||||
BuildResult Build() override;
|
||||
|
||||
QString DisplayType() override;
|
||||
};
|
||||
}
|
||||
|
||||
@ -4,10 +4,9 @@
|
||||
|
||||
namespace Configs
|
||||
{
|
||||
class ssh : public baseConfig, public outboundMeta
|
||||
class ssh : public outbound
|
||||
{
|
||||
public:
|
||||
std::shared_ptr<OutboundCommons> commons = std::make_shared<OutboundCommons>();
|
||||
QString user;
|
||||
QString password;
|
||||
QString private_key;
|
||||
@ -29,5 +28,14 @@ namespace Configs
|
||||
_add(new configItem("host_key_algorithms", &host_key_algorithms, stringList));
|
||||
_add(new configItem("client_version", &client_version, string));
|
||||
}
|
||||
|
||||
// baseConfig overrides
|
||||
bool ParseFromLink(const QString& link) override;
|
||||
bool ParseFromJson(const QJsonObject& object) override;
|
||||
QString ExportToLink() override;
|
||||
QJsonObject ExportToJson() override;
|
||||
BuildResult Build() override;
|
||||
|
||||
QString DisplayType() override;
|
||||
};
|
||||
}
|
||||
|
||||
51
include/configs/outbounds/tailscale.h
Normal file
51
include/configs/outbounds/tailscale.h
Normal file
@ -0,0 +1,51 @@
|
||||
#pragma once
|
||||
#include "include/configs/baseConfig.h"
|
||||
#include "include/configs/common/Outbound.h"
|
||||
|
||||
namespace Configs
|
||||
{
|
||||
class tailscale : public outbound
|
||||
{
|
||||
public:
|
||||
QString state_directory = "$HOME/.tailscale";
|
||||
QString auth_key;
|
||||
QString control_url = "https://controlplane.tailscale.com";
|
||||
bool ephemeral = false;
|
||||
QString hostname;
|
||||
bool accept_routes = false;
|
||||
QString exit_node;
|
||||
bool exit_node_allow_lan_access = false;
|
||||
QStringList advertise_routes;
|
||||
bool advertise_exit_node = false;
|
||||
bool globalDNS = false;
|
||||
|
||||
tailscale()
|
||||
{
|
||||
_add(new configItem("commons", dynamic_cast<JsonStore *>(commons.get()), jsonStore));
|
||||
_add(new configItem("state_directory", &state_directory, itemType::string));
|
||||
_add(new configItem("auth_key", &auth_key, itemType::string));
|
||||
_add(new configItem("control_url", &control_url, itemType::string));
|
||||
_add(new configItem("ephemeral", &ephemeral, itemType::boolean));
|
||||
_add(new configItem("hostname", &hostname, itemType::string));
|
||||
_add(new configItem("accept_routes", &accept_routes, itemType::boolean));
|
||||
_add(new configItem("exit_node", &exit_node, itemType::string));
|
||||
_add(new configItem("exit_node_allow_lan_access", &exit_node_allow_lan_access, itemType::boolean));
|
||||
_add(new configItem("advertise_routes", &advertise_routes, itemType::stringList));
|
||||
_add(new configItem("advertise_exit_node", &advertise_exit_node, itemType::boolean));
|
||||
_add(new configItem("globalDNS", &globalDNS, itemType::boolean));
|
||||
}
|
||||
|
||||
// baseConfig overrides
|
||||
bool ParseFromLink(const QString& link) override;
|
||||
bool ParseFromJson(const QJsonObject& object) override;
|
||||
QString ExportToLink() override;
|
||||
QJsonObject ExportToJson() override;
|
||||
BuildResult Build() override;
|
||||
|
||||
QString DisplayAddress() override;
|
||||
QString DisplayType() override;
|
||||
static bool IsEndpoint();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -8,13 +8,12 @@
|
||||
|
||||
namespace Configs
|
||||
{
|
||||
class Trojan : public baseConfig, public outboundMeta
|
||||
class Trojan : public outbound
|
||||
{
|
||||
public:
|
||||
std::shared_ptr<OutboundCommons> commons = std::make_shared<OutboundCommons>();
|
||||
QString password;
|
||||
std::shared_ptr<TLS> tls = std::make_shared<TLS>();
|
||||
std::shared_ptr<Multiplex> mux = std::make_shared<Multiplex>();
|
||||
std::shared_ptr<Multiplex> multiplex = std::make_shared<Multiplex>();
|
||||
std::shared_ptr<Transport> transport = std::make_shared<Transport>();
|
||||
|
||||
Trojan()
|
||||
@ -22,8 +21,17 @@ namespace Configs
|
||||
_add(new configItem("commons", dynamic_cast<JsonStore *>(commons.get()), jsonStore));
|
||||
_add(new configItem("password", &password, string));
|
||||
_add(new configItem("tls", dynamic_cast<JsonStore *>(tls.get()), jsonStore));
|
||||
_add(new configItem("mux", dynamic_cast<JsonStore *>(mux.get()), jsonStore));
|
||||
_add(new configItem("multiplex", dynamic_cast<JsonStore *>(multiplex.get()), jsonStore));
|
||||
_add(new configItem("transport", dynamic_cast<JsonStore *>(transport.get()), jsonStore));
|
||||
}
|
||||
|
||||
// baseConfig overrides
|
||||
bool ParseFromLink(const QString& link) override;
|
||||
bool ParseFromJson(const QJsonObject& object) override;
|
||||
QString ExportToLink() override;
|
||||
QJsonObject ExportToJson() override;
|
||||
BuildResult Build() override;
|
||||
|
||||
QString DisplayType() override;
|
||||
};
|
||||
}
|
||||
|
||||
@ -9,10 +9,9 @@ namespace Configs
|
||||
inline QStringList ccAlgorithms = {"cubic", "new_reno", "bbr"};
|
||||
inline QStringList udpRelayModes = {"", "native", "quic"};
|
||||
|
||||
class tuic : public baseConfig, public outboundMeta
|
||||
class tuic : public outbound
|
||||
{
|
||||
public:
|
||||
std::shared_ptr<OutboundCommons> commons = std::make_shared<OutboundCommons>();
|
||||
QString uuid;
|
||||
QString password;
|
||||
QString congestion_control;
|
||||
@ -34,5 +33,14 @@ namespace Configs
|
||||
_add(new configItem("heartbeat", &heartbeat, string));
|
||||
_add(new configItem("tls", dynamic_cast<JsonStore *>(tls.get()), jsonStore));
|
||||
}
|
||||
|
||||
// baseConfig overrides
|
||||
bool ParseFromLink(const QString& link) override;
|
||||
bool ParseFromJson(const QJsonObject& object) override;
|
||||
QString ExportToLink() override;
|
||||
QJsonObject ExportToJson() override;
|
||||
BuildResult Build() override;
|
||||
|
||||
QString DisplayType() override;
|
||||
};
|
||||
}
|
||||
|
||||
@ -9,15 +9,14 @@ namespace Configs
|
||||
{
|
||||
inline QStringList vlessFlows = {"xtls-rprx-vision"};
|
||||
|
||||
class vless : public baseConfig, public outboundMeta
|
||||
class vless : public outbound
|
||||
{
|
||||
public:
|
||||
std::shared_ptr<OutboundCommons> commons = std::make_shared<OutboundCommons>();
|
||||
QString uuid;
|
||||
QString flow;
|
||||
std::shared_ptr<TLS> tls = std::make_shared<TLS>();
|
||||
QString packet_encoding;
|
||||
std::shared_ptr<Multiplex> mux = std::make_shared<Multiplex>();
|
||||
std::shared_ptr<Multiplex> multiplex = std::make_shared<Multiplex>();
|
||||
std::shared_ptr<Transport> transport = std::make_shared<Transport>();
|
||||
|
||||
vless()
|
||||
@ -27,8 +26,17 @@ namespace Configs
|
||||
_add(new configItem("flow", &flow, string));
|
||||
_add(new configItem("tls", dynamic_cast<JsonStore *>(tls.get()), jsonStore));
|
||||
_add(new configItem("packet_encoding", &packet_encoding, string));
|
||||
_add(new configItem("mux", dynamic_cast<JsonStore *>(mux.get()), jsonStore));
|
||||
_add(new configItem("multiplex", dynamic_cast<JsonStore *>(multiplex.get()), jsonStore));
|
||||
_add(new configItem("transport", dynamic_cast<JsonStore *>(transport.get()), jsonStore));
|
||||
}
|
||||
|
||||
// baseConfig overrides
|
||||
bool ParseFromLink(const QString& link) override;
|
||||
bool ParseFromJson(const QJsonObject& object) override;
|
||||
QString ExportToLink() override;
|
||||
QJsonObject ExportToJson() override;
|
||||
BuildResult Build() override;
|
||||
|
||||
QString DisplayType() override;
|
||||
};
|
||||
}
|
||||
|
||||
@ -12,10 +12,9 @@ namespace Configs
|
||||
inline QStringList vmessSecurity = {"auto", "none", "zero", "aes-128-gcm", "chacha20-poly1305"};
|
||||
inline QStringList vPacketEncoding = {"", "packetaddr", "xudp"};
|
||||
|
||||
class vmess : public baseConfig, public outboundMeta
|
||||
class vmess : public outbound
|
||||
{
|
||||
public:
|
||||
std::shared_ptr<OutboundCommons> commons = std::make_shared<OutboundCommons>();
|
||||
QString uuid;
|
||||
QString security = "auto";
|
||||
int alter_id = 0;
|
||||
@ -24,7 +23,7 @@ namespace Configs
|
||||
std::shared_ptr<TLS> tls = std::make_shared<TLS>();
|
||||
QString packet_encoding;
|
||||
std::shared_ptr<Transport> transport = std::make_shared<Transport>();
|
||||
std::shared_ptr<Multiplex> mux = std::make_shared<Multiplex>();
|
||||
std::shared_ptr<Multiplex> multiplex = std::make_shared<Multiplex>();
|
||||
|
||||
vmess()
|
||||
{
|
||||
@ -37,7 +36,16 @@ namespace Configs
|
||||
_add(new configItem("tls", dynamic_cast<JsonStore *>(tls.get()), jsonStore));
|
||||
_add(new configItem("packet_encoding", &packet_encoding, string));
|
||||
_add(new configItem("transport", dynamic_cast<JsonStore *>(transport.get()), jsonStore));
|
||||
_add(new configItem("mux", dynamic_cast<JsonStore *>(mux.get()), jsonStore));
|
||||
_add(new configItem("multiplex", dynamic_cast<JsonStore *>(multiplex.get()), jsonStore));
|
||||
}
|
||||
|
||||
// baseConfig overrides
|
||||
bool ParseFromLink(const QString& link) override;
|
||||
bool ParseFromJson(const QJsonObject& object) override;
|
||||
QString ExportToLink() override;
|
||||
QJsonObject ExportToJson() override;
|
||||
BuildResult Build() override;
|
||||
|
||||
QString DisplayType() override;
|
||||
};
|
||||
}
|
||||
|
||||
95
include/configs/outbounds/wireguard.h
Normal file
95
include/configs/outbounds/wireguard.h
Normal file
@ -0,0 +1,95 @@
|
||||
#pragma once
|
||||
#include "include/configs/baseConfig.h"
|
||||
#include "include/configs/common/Outbound.h"
|
||||
|
||||
namespace Configs
|
||||
{
|
||||
class Peer : public baseConfig
|
||||
{
|
||||
public:
|
||||
QString address;
|
||||
int port = 0;
|
||||
QString public_key;
|
||||
QString pre_shared_key;
|
||||
QList<int> reserved;
|
||||
int persistent_keepalive = 0;
|
||||
|
||||
Peer()
|
||||
{
|
||||
_add(new configItem("address", &address, string));
|
||||
_add(new configItem("port", &port, integer));
|
||||
_add(new configItem("public_key", &public_key, itemType::string));
|
||||
_add(new configItem("pre_shared_key", &pre_shared_key, itemType::string));
|
||||
_add(new configItem("reserved", &reserved, itemType::integerList));
|
||||
_add(new configItem("persistent_keepalive", &persistent_keepalive, itemType::integer));
|
||||
}
|
||||
|
||||
// baseConfig overrides
|
||||
bool ParseFromLink(const QString& link) override;
|
||||
bool ParseFromJson(const QJsonObject& object) override;
|
||||
QString ExportToLink() override;
|
||||
QJsonObject ExportToJson() override;
|
||||
BuildResult Build() override;
|
||||
};
|
||||
|
||||
class wireguard : public outbound
|
||||
{
|
||||
public:
|
||||
QString private_key;
|
||||
std::shared_ptr<Peer> peer = std::make_shared<Peer>();
|
||||
QStringList address;
|
||||
int mtu = 1420;
|
||||
bool system = false;
|
||||
int worker_count = 0;
|
||||
QString udp_timeout;
|
||||
|
||||
// Amnezia options
|
||||
bool enable_amnezia = false;
|
||||
int junk_packet_count = 0;
|
||||
int junk_packet_min_size = 0;
|
||||
int junk_packet_max_size = 0;
|
||||
int init_packet_junk_size = 0;
|
||||
int response_packet_junk_size = 0;
|
||||
int init_packet_magic_header = 0;
|
||||
int response_packet_magic_header = 0;
|
||||
int underload_packet_magic_header = 0;
|
||||
int transport_packet_magic_header = 0;
|
||||
|
||||
wireguard()
|
||||
{
|
||||
_add(new configItem("commons", dynamic_cast<JsonStore *>(commons.get()), jsonStore));
|
||||
|
||||
_add(new configItem("private_key", &private_key, itemType::string));
|
||||
_add(new configItem("peer", dynamic_cast<JsonStore *>(peer.get()), jsonStore));
|
||||
_add(new configItem("address", &address, itemType::stringList));
|
||||
_add(new configItem("mtu", &mtu, itemType::integer));
|
||||
_add(new configItem("system", &system, itemType::boolean));
|
||||
_add(new configItem("worker_count", &worker_count, itemType::integer));
|
||||
_add(new configItem("udp_timeout", &udp_timeout, itemType::string));
|
||||
|
||||
_add(new configItem("enable_amnezia", &enable_amnezia, itemType::boolean));
|
||||
_add(new configItem("junk_packet_count", &junk_packet_count, itemType::integer));
|
||||
_add(new configItem("junk_packet_min_size", &junk_packet_min_size, itemType::integer));
|
||||
_add(new configItem("junk_packet_max_size", &junk_packet_max_size, itemType::integer));
|
||||
_add(new configItem("init_packet_junk_size", &init_packet_junk_size, itemType::integer));
|
||||
_add(new configItem("response_packet_junk_size", &response_packet_junk_size, itemType::integer));
|
||||
_add(new configItem("init_packet_magic_header", &init_packet_magic_header, itemType::integer));
|
||||
_add(new configItem("response_packet_magic_header", &response_packet_magic_header, itemType::integer));
|
||||
_add(new configItem("underload_packet_magic_header", &underload_packet_magic_header, itemType::integer));
|
||||
_add(new configItem("transport_packet_magic_header", &transport_packet_magic_header, itemType::integer));
|
||||
}
|
||||
|
||||
// baseConfig overrides
|
||||
bool ParseFromLink(const QString& link) override;
|
||||
bool ParseFromJson(const QJsonObject& object) override;
|
||||
QString ExportToLink() override;
|
||||
QJsonObject ExportToJson() override;
|
||||
BuildResult Build() override;
|
||||
|
||||
QString DisplayAddress() override;
|
||||
QString DisplayType() override;
|
||||
static bool IsEndpoint();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
56
src/configs/common/DialFields.cpp
Normal file
56
src/configs/common/DialFields.cpp
Normal file
@ -0,0 +1,56 @@
|
||||
#include "include/configs/common/DialFields.h"
|
||||
|
||||
#include <QUrlQuery>
|
||||
|
||||
namespace Configs {
|
||||
bool DialFields::ParseFromLink(const QString& link)
|
||||
{
|
||||
auto url = QUrl(link);
|
||||
if (!url.isValid()) return false;
|
||||
auto query = QUrlQuery(url.query(QUrl::ComponentFormattingOption::FullyDecoded));
|
||||
|
||||
if (query.hasQueryItem("reuse_addr")) reuse_addr = query.queryItemValue("reuse_addr") == "true";
|
||||
if (query.hasQueryItem("connect_timeout")) connect_timeout = query.queryItemValue("connect_timeout");
|
||||
if (query.hasQueryItem("tcp_fast_open")) tcp_fast_open = query.queryItemValue("tcp_fast_open") == "true";
|
||||
if (query.hasQueryItem("tcp_multi_path")) tcp_multi_path = query.queryItemValue("tcp_multi_path") == "true";
|
||||
if (query.hasQueryItem("udp_fragment")) udp_fragment = query.queryItemValue("udp_fragment") == "true";
|
||||
return true;
|
||||
}
|
||||
bool DialFields::ParseFromJson(const QJsonObject& object)
|
||||
{
|
||||
if (object == nullptr) return false;
|
||||
|
||||
if (object.contains("reuse_addr")) reuse_addr = object["reuse_addr"].toBool();
|
||||
if (object.contains("connect_timeout")) connect_timeout = object["connect_timeout"].toString();
|
||||
if (object.contains("tcp_fast_open")) tcp_fast_open = object["tcp_fast_open"].toBool();
|
||||
if (object.contains("tcp_multi_path")) tcp_multi_path = object["tcp_multi_path"].toBool();
|
||||
if (object.contains("udp_fragment")) udp_fragment = object["udp_fragment"].toBool();
|
||||
return true;
|
||||
}
|
||||
QString DialFields::ExportToLink()
|
||||
{
|
||||
QUrlQuery query;
|
||||
if (reuse_addr) query.addQueryItem("reuse_addr", "true");
|
||||
if (!connect_timeout.isEmpty()) query.addQueryItem("connect_timeout", connect_timeout);
|
||||
if (tcp_fast_open) query.addQueryItem("tcp_fast_open", "true");
|
||||
if (tcp_multi_path) query.addQueryItem("tcp_multi_path", "true");
|
||||
if (udp_fragment) query.addQueryItem("udp_fragment", "true");
|
||||
return query.toString();
|
||||
}
|
||||
QJsonObject DialFields::ExportToJson()
|
||||
{
|
||||
QJsonObject object;
|
||||
if (reuse_addr) object["reuse_addr"] = reuse_addr;
|
||||
if (!connect_timeout.isEmpty()) object["connect_timeout"] = connect_timeout;
|
||||
if (tcp_fast_open) object["tcp_fast_open"] = tcp_fast_open;
|
||||
if (tcp_multi_path) object["tcp_multi_path"] = tcp_multi_path;
|
||||
if (udp_fragment) object["udp_fragment"] = udp_fragment;
|
||||
return object;
|
||||
}
|
||||
BuildResult DialFields::Build()
|
||||
{
|
||||
return {ExportToJson(), ""};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
47
src/configs/common/Outbound.cpp
Normal file
47
src/configs/common/Outbound.cpp
Normal file
@ -0,0 +1,47 @@
|
||||
#include "include/configs/common/Outbound.h"
|
||||
#include "include/configs/common/utils.h"
|
||||
|
||||
namespace Configs {
|
||||
bool OutboundCommons::ParseFromLink(const QString& link)
|
||||
{
|
||||
auto url = QUrl(link);
|
||||
if (!url.isValid()) return false;
|
||||
|
||||
if (url.hasFragment()) name = url.fragment(QUrl::FullyDecoded);
|
||||
server = url.host();
|
||||
server_port = url.port();
|
||||
dialFields->ParseFromLink(link);
|
||||
return true;
|
||||
}
|
||||
bool OutboundCommons::ParseFromJson(const QJsonObject& object)
|
||||
{
|
||||
if (object.isEmpty()) return false;
|
||||
if (object.contains("tag")) name = object["tag"].toString();
|
||||
if (object.contains("server")) server = object["server"].toString();
|
||||
if (object.contains("server_port")) server_port = object["server_port"].toInt();
|
||||
dialFields->ParseFromJson(object);
|
||||
return true;
|
||||
}
|
||||
QString OutboundCommons::ExportToLink()
|
||||
{
|
||||
QUrlQuery query;
|
||||
mergeUrlQuery(query, dialFields->ExportToLink());
|
||||
return query.toString();
|
||||
}
|
||||
QJsonObject OutboundCommons::ExportToJson()
|
||||
{
|
||||
QJsonObject object;
|
||||
if (!name.isEmpty()) object["tag"] = name;
|
||||
if (!server.isEmpty()) object["server"] = server;
|
||||
if (server_port > 0) object["server_port"] = server_port;
|
||||
auto dialFieldsObj = dialFields->ExportToJson();
|
||||
mergeJsonObjects(object, dialFieldsObj);
|
||||
return object;
|
||||
}
|
||||
BuildResult OutboundCommons::Build()
|
||||
{
|
||||
return {ExportToJson(), ""};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
282
src/configs/common/TLS.cpp
Normal file
282
src/configs/common/TLS.cpp
Normal file
@ -0,0 +1,282 @@
|
||||
#include "include/configs/common/TLS.h"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QUrlQuery>
|
||||
#include <include/global/DataStore.hpp>
|
||||
#include <include/global/Utils.hpp>
|
||||
|
||||
#include "include/configs/common/utils.h"
|
||||
|
||||
namespace Configs {
|
||||
bool uTLS::ParseFromLink(const QString& link)
|
||||
{
|
||||
auto url = QUrl(link);
|
||||
if (!url.isValid()) return false;
|
||||
auto query = QUrlQuery(url.query(QUrl::ComponentFormattingOption::FullyDecoded));
|
||||
|
||||
// handle the common format
|
||||
fingerPrint = dataStore->utlsFingerprint;
|
||||
if (query.hasQueryItem("fp")) fingerPrint = query.queryItemValue("fp");
|
||||
if (!fingerPrint.isEmpty()) enabled = true;
|
||||
return true;
|
||||
}
|
||||
bool uTLS::ParseFromJson(const QJsonObject& object)
|
||||
{
|
||||
if (object.isEmpty()) return false;
|
||||
if (object.contains("enabled")) enabled = object["enabled"].toBool();
|
||||
if (object.contains("fingerprint")) fingerPrint = object["fingerprint"].toString();
|
||||
return true;
|
||||
}
|
||||
QString uTLS::ExportToLink()
|
||||
{
|
||||
QUrlQuery query;
|
||||
if (!enabled) return "";
|
||||
if (!fingerPrint.isEmpty()) query.addQueryItem("fp", fingerPrint);
|
||||
return query.toString();
|
||||
}
|
||||
QJsonObject uTLS::ExportToJson()
|
||||
{
|
||||
QJsonObject object;
|
||||
if (!enabled) return object;
|
||||
object["enabled"] = enabled;
|
||||
if (!fingerPrint.isEmpty()) object["fingerprint"] = fingerPrint;
|
||||
return object;
|
||||
}
|
||||
BuildResult uTLS::Build()
|
||||
{
|
||||
return {ExportToJson(), ""};
|
||||
}
|
||||
|
||||
bool ECH::ParseFromLink(const QString& link)
|
||||
{
|
||||
auto url = QUrl(link);
|
||||
if (!url.isValid()) return false;
|
||||
auto query = QUrlQuery(url.query(QUrl::ComponentFormattingOption::FullyDecoded));
|
||||
|
||||
if (query.hasQueryItem("ech_enabled")) enabled = query.queryItemValue("ech_enabled") == "true";
|
||||
if (query.hasQueryItem("ech_config")) config = query.queryItemValue("ech_config").split(",");
|
||||
if (query.hasQueryItem("ech_config_path")) config_path = query.queryItemValue("ech_config_path");
|
||||
return true;
|
||||
}
|
||||
bool ECH::ParseFromJson(const QJsonObject& object)
|
||||
{
|
||||
if (object.isEmpty()) return false;
|
||||
if (object.contains("enabled")) enabled = object["enabled"].toBool();
|
||||
if (object.contains("config")) {
|
||||
config = QJsonArray2QListString(object["config"].toArray());
|
||||
}
|
||||
if (object.contains("config_path")) config_path = object["config_path"].toString();
|
||||
return true;
|
||||
}
|
||||
QString ECH::ExportToLink()
|
||||
{
|
||||
QUrlQuery query;
|
||||
if (!enabled) return "";
|
||||
query.addQueryItem("ech_enabled", "true");
|
||||
if (!config.isEmpty()) query.addQueryItem("ech_config", config.join(","));
|
||||
if (!config_path.isEmpty()) query.addQueryItem("ech_config_path", config_path);
|
||||
return query.toString();
|
||||
}
|
||||
QJsonObject ECH::ExportToJson()
|
||||
{
|
||||
QJsonObject object;
|
||||
if (!enabled) return object;
|
||||
object["enabled"] = enabled;
|
||||
if (!config.isEmpty()) {
|
||||
object["config"] = QListStr2QJsonArray(config);
|
||||
}
|
||||
if (!config_path.isEmpty()) object["config_path"] = config_path;
|
||||
return object;
|
||||
}
|
||||
BuildResult ECH::Build()
|
||||
{
|
||||
return {ExportToJson(), ""};
|
||||
}
|
||||
|
||||
bool Reality::ParseFromLink(const QString& link)
|
||||
{
|
||||
auto url = QUrl(link);
|
||||
if (!url.isValid()) return false;
|
||||
auto query = QUrlQuery(url.query(QUrl::ComponentFormattingOption::FullyDecoded));
|
||||
|
||||
// handle the common format
|
||||
if (query.hasQueryItem("pbk"))
|
||||
{
|
||||
enabled = true;
|
||||
public_key = query.queryItemValue("pbk");
|
||||
short_id = query.queryItemValue("sid");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool Reality::ParseFromJson(const QJsonObject& object)
|
||||
{
|
||||
if (object.isEmpty()) return false;
|
||||
if (object.contains("enabled")) enabled = object["enabled"].toBool();
|
||||
if (object.contains("public_key")) public_key = object["public_key"].toString();
|
||||
if (object.contains("short_id")) short_id = object["short_id"].toString();
|
||||
return true;
|
||||
}
|
||||
QString Reality::ExportToLink()
|
||||
{
|
||||
QUrlQuery query;
|
||||
if (!enabled) return "";
|
||||
query.addQueryItem("pbk", public_key);
|
||||
query.addQueryItem("sid", short_id);
|
||||
return query.toString();
|
||||
}
|
||||
QJsonObject Reality::ExportToJson()
|
||||
{
|
||||
QJsonObject object;
|
||||
if (!enabled) return object;
|
||||
object["enabled"] = enabled;
|
||||
if (!public_key.isEmpty()) object["public_key"] = public_key;
|
||||
if (!short_id.isEmpty()) object["short_id"] = short_id;
|
||||
return object;
|
||||
}
|
||||
BuildResult Reality::Build()
|
||||
{
|
||||
return {ExportToJson(), ""};
|
||||
}
|
||||
|
||||
bool TLS::ParseFromLink(const QString& link)
|
||||
{
|
||||
auto url = QUrl(link);
|
||||
if (!url.isValid()) return false;
|
||||
auto query = QUrlQuery(url.query(QUrl::ComponentFormattingOption::FullyDecoded));
|
||||
|
||||
if (query.hasQueryItem("security")) enabled = query.queryItemValue("security").replace("reality", "tls").replace("none", "") == "tls";
|
||||
if (query.hasQueryItem("disable_sni")) disable_sni = query.queryItemValue("disable_sni").replace("1", "true") == "true";
|
||||
if (query.hasQueryItem("sni")) server_name = query.queryItemValue("sni");
|
||||
if (query.hasQueryItem("peer")) server_name = query.queryItemValue("peer");
|
||||
if (query.hasQueryItem("allowInsecure")) insecure = query.queryItemValue("allowInsecure").replace("1", "true") == "true";
|
||||
if (query.hasQueryItem("allow_insecure")) insecure = query.queryItemValue("allow_insecure").replace("1", "true") == "true";
|
||||
if (query.hasQueryItem("alpn")) alpn = query.queryItemValue("alpn").split(",");
|
||||
if (query.hasQueryItem("tls_min_version")) min_version = query.queryItemValue("tls_min_version");
|
||||
if (query.hasQueryItem("tls_max_version")) max_version = query.queryItemValue("tls_max_version");
|
||||
if (query.hasQueryItem("tls_cipher_suites")) cipher_suites = query.queryItemValue("tls_cipher_suites").split(",");
|
||||
if (query.hasQueryItem("tls_curve_preferences")) curve_preferences = query.queryItemValue("tls_curve_preferences").split(",");
|
||||
if (query.hasQueryItem("tls_certificate")) certificate = query.queryItemValue("tls_certificate");
|
||||
if (query.hasQueryItem("tls_certificate_path")) certificate_path = query.queryItemValue("tls_certificate_path");
|
||||
if (query.hasQueryItem("tls_certificate_public_key_sha256")) certificate_public_key_sha256 = query.queryItemValue("tls_certificate_public_key_sha256").split(",");
|
||||
if (query.hasQueryItem("tls_client_certificate")) client_certificate = query.queryItemValue("tls_client_certificate");
|
||||
if (query.hasQueryItem("tls_client_certificate_path")) client_certificate_path = query.queryItemValue("tls_client_certificate_path");
|
||||
if (query.hasQueryItem("tls_client_key")) client_key = query.queryItemValue("tls_client_key").split(",");
|
||||
if (query.hasQueryItem("tls_client_key_path")) client_key_path = query.queryItemValue("tls_client_key_path");
|
||||
if (query.hasQueryItem("tls_fragment")) fragment = query.queryItemValue("tls_fragment") == "true";
|
||||
if (query.hasQueryItem("tls_fragment_fallback_delay")) fragment_fallback_delay = query.queryItemValue("tls_fragment_fallback_delay");
|
||||
if (query.hasQueryItem("tls_record_fragment")) record_fragment = query.queryItemValue("tls_record_fragment") == "true";
|
||||
ech->ParseFromLink(link);
|
||||
utls->ParseFromLink(link);
|
||||
reality->ParseFromLink(link);
|
||||
return true;
|
||||
}
|
||||
bool TLS::ParseFromJson(const QJsonObject& object)
|
||||
{
|
||||
if (object.isEmpty()) return false;
|
||||
if (object.contains("enabled")) enabled = object["enabled"].toBool();
|
||||
if (object.contains("disable_sni")) disable_sni = object["disable_sni"].toBool();
|
||||
if (object.contains("server_name")) server_name = object["server_name"].toString();
|
||||
if (object.contains("insecure")) insecure = object["insecure"].toBool();
|
||||
if (object.contains("alpn")) {
|
||||
alpn = QJsonArray2QListString(object["alpn"].toArray());
|
||||
}
|
||||
if (object.contains("min_version")) min_version = object["min_version"].toString();
|
||||
if (object.contains("max_version")) max_version = object["max_version"].toString();
|
||||
if (object.contains("cipher_suites")) {
|
||||
cipher_suites = QJsonArray2QListString(object["cipher_suites"].toArray());
|
||||
}
|
||||
if (object.contains("curve_preferences")) {
|
||||
curve_preferences = QJsonArray2QListString(object["curve_preferences"].toArray());
|
||||
}
|
||||
if (object.contains("certificate")) certificate = object["certificate"].toString();
|
||||
if (object.contains("certificate_path")) certificate_path = object["certificate_path"].toString();
|
||||
if (object.contains("certificate_public_key_sha256")) {
|
||||
certificate_public_key_sha256 = QJsonArray2QListString(object["certificate_public_key_sha256"].toArray());
|
||||
}
|
||||
if (object.contains("client_certificate")) client_certificate = object["client_certificate"].toString();
|
||||
if (object.contains("client_certificate_path")) client_certificate_path = object["client_certificate_path"].toString();
|
||||
if (object.contains("client_key")) {
|
||||
client_key = QJsonArray2QListString(object["client_key"].toArray());
|
||||
}
|
||||
if (object.contains("client_key_path")) client_key_path = object["client_key_path"].toString();
|
||||
if (object.contains("fragment")) fragment = object["fragment"].toBool();
|
||||
if (object.contains("fragment_fallback_delay")) fragment_fallback_delay = object["fragment_fallback_delay"].toString();
|
||||
if (object.contains("record_fragment")) record_fragment = object["record_fragment"].toBool();
|
||||
if (object.contains("ech")) ech->ParseFromJson(object["ech"].toObject());
|
||||
if (object.contains("utls")) utls->ParseFromJson(object["utls"].toObject());
|
||||
if (object.contains("reality")) reality->ParseFromJson(object["reality"].toObject());
|
||||
return true;
|
||||
}
|
||||
QString TLS::ExportToLink()
|
||||
{
|
||||
QUrlQuery query;
|
||||
if (!enabled) return "";
|
||||
query.addQueryItem("security", "tls");
|
||||
if (disable_sni) query.addQueryItem("disable_sni", "true");
|
||||
if (!server_name.isEmpty()) query.addQueryItem("sni", server_name);
|
||||
if (insecure) query.addQueryItem("allowInsecure", "true");
|
||||
if (!alpn.isEmpty()) query.addQueryItem("alpn", alpn.join(","));
|
||||
if (!min_version.isEmpty()) query.addQueryItem("tls_min_version", min_version);
|
||||
if (!max_version.isEmpty()) query.addQueryItem("tls_max_version", max_version);
|
||||
if (!cipher_suites.isEmpty()) query.addQueryItem("tls_cipher_suites", cipher_suites.join(","));
|
||||
if (!curve_preferences.isEmpty()) query.addQueryItem("tls_curve_preferences", curve_preferences.join(","));
|
||||
if (!certificate.isEmpty()) query.addQueryItem("tls_certificate", certificate);
|
||||
if (!certificate_path.isEmpty()) query.addQueryItem("tls_certificate_path", certificate_path);
|
||||
if (!certificate_public_key_sha256.isEmpty()) query.addQueryItem("tls_certificate_public_key_sha256", certificate_public_key_sha256.join(","));
|
||||
if (!client_certificate.isEmpty()) query.addQueryItem("tls_client_certificate", client_certificate);
|
||||
if (!client_certificate_path.isEmpty()) query.addQueryItem("tls_client_certificate_path", client_certificate_path);
|
||||
if (!client_key.isEmpty()) query.addQueryItem("tls_client_key", client_key.join(","));
|
||||
if (!client_key_path.isEmpty()) query.addQueryItem("tls_client_key_path", client_key_path);
|
||||
if (fragment) query.addQueryItem("tls_fragment", "true");
|
||||
if (!fragment_fallback_delay.isEmpty()) query.addQueryItem("tls_fragment_fallback_delay", fragment_fallback_delay);
|
||||
if (record_fragment) query.addQueryItem("tls_record_fragment", "true");
|
||||
mergeUrlQuery(query, ech->ExportToLink());
|
||||
mergeUrlQuery(query, utls->ExportToLink());
|
||||
mergeUrlQuery(query, reality->ExportToLink());
|
||||
return query.toString();
|
||||
}
|
||||
QJsonObject TLS::ExportToJson()
|
||||
{
|
||||
QJsonObject object;
|
||||
if (!enabled) return object;
|
||||
object["enabled"] = enabled;
|
||||
if (disable_sni) object["disable_sni"] = disable_sni;
|
||||
if (!server_name.isEmpty()) object["server_name"] = server_name;
|
||||
if (insecure) object["insecure"] = insecure;
|
||||
if (!alpn.isEmpty()) {
|
||||
object["alpn"] = QListStr2QJsonArray(alpn);
|
||||
}
|
||||
if (!min_version.isEmpty()) object["min_version"] = min_version;
|
||||
if (!max_version.isEmpty()) object["max_version"] = max_version;
|
||||
if (!cipher_suites.isEmpty()) {
|
||||
object["cipher_suites"] = QListStr2QJsonArray(cipher_suites);
|
||||
}
|
||||
if (!curve_preferences.isEmpty()) {
|
||||
object["curve_preferences"] = QListStr2QJsonArray(curve_preferences);
|
||||
}
|
||||
if (!certificate.isEmpty()) object["certificate"] = certificate;
|
||||
if (!certificate_path.isEmpty()) object["certificate_path"] = certificate_path;
|
||||
if (!certificate_public_key_sha256.isEmpty()) {
|
||||
object["certificate_public_key_sha256"] = QListStr2QJsonArray(certificate_public_key_sha256);
|
||||
}
|
||||
if (!client_certificate.isEmpty()) object["client_certificate"] = client_certificate;
|
||||
if (!client_certificate_path.isEmpty()) object["client_certificate_path"] = client_certificate_path;
|
||||
if (!client_key.isEmpty()) {
|
||||
object["client_key"] = QListStr2QJsonArray(client_key);
|
||||
}
|
||||
if (!client_key_path.isEmpty()) object["client_key_path"] = client_key_path;
|
||||
if (fragment) object["fragment"] = fragment;
|
||||
if (!fragment_fallback_delay.isEmpty()) object["fragment_fallback_delay"] = fragment_fallback_delay;
|
||||
if (record_fragment) object["record_fragment"] = record_fragment;
|
||||
if (ech->enabled) object["ech"] = ech->ExportToJson();
|
||||
if (utls->enabled) object["utls"] = utls->ExportToJson();
|
||||
if (reality->enabled) object["reality"] = reality->ExportToJson();
|
||||
return object;
|
||||
}
|
||||
BuildResult TLS::Build()
|
||||
{
|
||||
return {ExportToJson(), ""};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
121
src/configs/common/multiplex.cpp
Normal file
121
src/configs/common/multiplex.cpp
Normal file
@ -0,0 +1,121 @@
|
||||
#include "include/configs/common/multiplex.h"
|
||||
|
||||
#include <QUrlQuery>
|
||||
#include <include/global/DataStore.hpp>
|
||||
|
||||
#include "include/configs/common/utils.h"
|
||||
|
||||
namespace Configs {
|
||||
bool TcpBrutal::ParseFromLink(const QString& link)
|
||||
{
|
||||
auto url = QUrl(link);
|
||||
if (!url.isValid()) return false;
|
||||
auto query = QUrlQuery(url.query(QUrl::ComponentFormattingOption::FullyDecoded));
|
||||
|
||||
if (query.hasQueryItem("brutal_enabled")) enabled = query.queryItemValue("brutal_enabled") == "true";
|
||||
if (query.hasQueryItem("brutal_up_mbps")) up_mbps = query.queryItemValue("brutal_up_mbps").toInt();
|
||||
if (query.hasQueryItem("brutal_down_mbps")) down_mbps = query.queryItemValue("brutal_down_mbps").toInt();
|
||||
return true;
|
||||
}
|
||||
bool TcpBrutal::ParseFromJson(const QJsonObject& object)
|
||||
{
|
||||
if (object == nullptr) return false;
|
||||
if (object.contains("enabled")) enabled = object["enabled"].toBool();
|
||||
if (object.contains("up_mbps")) up_mbps = object["up_mbps"].toInt();
|
||||
if (object.contains("down_mbps")) down_mbps = object["down_mbps"].toInt();
|
||||
return true;
|
||||
}
|
||||
QString TcpBrutal::ExportToLink()
|
||||
{
|
||||
QUrlQuery query;
|
||||
if (!enabled) return "";
|
||||
query.addQueryItem("brutal_enabled", "true");
|
||||
if (up_mbps > 0) query.addQueryItem("brutal_up_mbps", QString::number(up_mbps));
|
||||
if (down_mbps > 0) query.addQueryItem("brutal_down_mbps", QString::number(down_mbps));
|
||||
return QUrlQuery(query).toString();
|
||||
}
|
||||
QJsonObject TcpBrutal::ExportToJson()
|
||||
{
|
||||
QJsonObject object;
|
||||
if (!enabled) return object;
|
||||
object["enabled"] = enabled;
|
||||
if (up_mbps > 0) object["up_mbps"] = up_mbps;
|
||||
if (down_mbps > 0) object["down_mbps"] = down_mbps;
|
||||
return object;
|
||||
}
|
||||
BuildResult TcpBrutal::Build()
|
||||
{
|
||||
return {ExportToJson(), ""};
|
||||
}
|
||||
|
||||
bool Multiplex::ParseFromLink(const QString& link)
|
||||
{
|
||||
auto url = QUrl(link);
|
||||
if (!url.isValid()) return false;
|
||||
auto query = QUrlQuery(url.query(QUrl::ComponentFormattingOption::FullyDecoded));
|
||||
|
||||
if (query.hasQueryItem("mux")) enabled = query.queryItemValue("mux") == "true";
|
||||
else unspecified = true;
|
||||
protocol = query.hasQueryItem("mux_protocol") ? query.queryItemValue("mux_protocol") : "smux";
|
||||
if (query.hasQueryItem("mux_max_connections")) max_connections = query.queryItemValue("mux_max_connections").toInt();
|
||||
if (query.hasQueryItem("mux_min_streams")) min_streams = query.queryItemValue("mux_min_streams").toInt();
|
||||
if (query.hasQueryItem("mux_max_streams")) max_streams = query.queryItemValue("mux_max_streams").toInt();
|
||||
if (query.hasQueryItem("mux_padding")) padding = query.queryItemValue("mux_padding") == "true";
|
||||
brutal->ParseFromLink(link);
|
||||
return true;
|
||||
}
|
||||
bool Multiplex::ParseFromJson(const QJsonObject& object)
|
||||
{
|
||||
if (object == nullptr)
|
||||
{
|
||||
unspecified = true;
|
||||
return false;
|
||||
}
|
||||
if (object.contains("enabled")) enabled = object["enabled"].toBool();
|
||||
else unspecified = true;
|
||||
if (object.contains("protocol")) protocol = object["protocol"].toString();
|
||||
if (object.contains("max_connections")) max_connections = object["max_connections"].toInt();
|
||||
if (object.contains("min_streams")) min_streams = object["min_streams"].toInt();
|
||||
if (object.contains("max_streams")) max_streams = object["max_streams"].toInt();
|
||||
if (object.contains("padding")) padding = object["padding"].toBool();
|
||||
if (object.contains("brutal")) brutal->ParseFromJson(object["brutal"].toObject());
|
||||
return true;
|
||||
}
|
||||
QString Multiplex::ExportToLink()
|
||||
{
|
||||
QUrlQuery query;
|
||||
if (!enabled) return "";
|
||||
query.addQueryItem("mux", "true");
|
||||
if (!protocol.isEmpty()) query.addQueryItem("mux_protocol", protocol);
|
||||
if (max_connections > 0) query.addQueryItem("mux_max_connections", QString::number(max_connections));
|
||||
if (min_streams > 0) query.addQueryItem("mux_min_streams", QString::number(min_streams));
|
||||
if (max_streams > 0) query.addQueryItem("mux_max_streams", QString::number(max_streams));
|
||||
if (padding) query.addQueryItem("mux_padding", "true");
|
||||
mergeUrlQuery(query, brutal->ExportToLink());
|
||||
return query.toString();
|
||||
}
|
||||
QJsonObject Multiplex::ExportToJson()
|
||||
{
|
||||
QJsonObject object;
|
||||
if (!enabled) return object;
|
||||
object["enabled"] = enabled;
|
||||
if (!protocol.isEmpty()) object["protocol"] = protocol;
|
||||
if (max_connections > 0) object["max_connections"] = max_connections;
|
||||
if (min_streams > 0) object["min_streams"] = min_streams;
|
||||
if (max_streams > 0) object["max_streams"] = max_streams;
|
||||
if (padding) object["padding"] = padding;
|
||||
if (brutal->enabled) object["brutal"] = brutal->ExportToJson();
|
||||
return object;
|
||||
}
|
||||
BuildResult Multiplex::Build()
|
||||
{
|
||||
auto obj = ExportToJson();
|
||||
if (unspecified && dataStore->mux_default_on) obj["enabled"] = true;
|
||||
if (protocol.isEmpty()) obj["protocol"] = dataStore->mux_protocol;
|
||||
if (max_streams == 0 && max_connections == 0 && min_streams == 0) obj["max_streams"] = dataStore->mux_concurrency;
|
||||
if (dataStore->mux_padding) obj["padding"] = true;
|
||||
return {obj, ""};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
87
src/configs/common/transport.cpp
Normal file
87
src/configs/common/transport.cpp
Normal file
@ -0,0 +1,87 @@
|
||||
#include "include/configs/common/transport.h"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QUrlQuery>
|
||||
#include <include/global/Utils.hpp>
|
||||
|
||||
#include "include/configs/common/utils.h"
|
||||
|
||||
namespace Configs {
|
||||
bool Transport::ParseFromLink(const QString& link)
|
||||
{
|
||||
auto url = QUrl(link);
|
||||
if (!url.isValid()) return false;
|
||||
auto query = QUrlQuery(url.query(QUrl::ComponentFormattingOption::FullyDecoded));
|
||||
|
||||
if (query.hasQueryItem("type"))
|
||||
{
|
||||
type = query.queryItemValue("type");
|
||||
if ((type == "tcp" && query.queryItemValue("headerType") == "http") || type == "h2") type = "http";
|
||||
}
|
||||
if (query.hasQueryItem("host")) host = query.queryItemValue("host");
|
||||
if (query.hasQueryItem("path")) path = query.queryItemValue("path");
|
||||
if (query.hasQueryItem("method")) method = query.queryItemValue("method");
|
||||
if (query.hasQueryItem("headers")) headers = query.queryItemValue("headers").split(",");
|
||||
if (query.hasQueryItem("idle_timeout")) idle_timeout = query.queryItemValue("idle_timeout");
|
||||
if (query.hasQueryItem("ping_timeout")) ping_timeout = query.queryItemValue("ping_timeout");
|
||||
if (query.hasQueryItem("max_early_data")) max_early_data = query.queryItemValue("max_early_data").toInt();
|
||||
if (query.hasQueryItem("early_data_header_name")) early_data_header_name = query.queryItemValue("early_data_header_name");
|
||||
if (query.hasQueryItem("serviceName")) service_name = query.queryItemValue("serviceName");
|
||||
return true;
|
||||
}
|
||||
bool Transport::ParseFromJson(const QJsonObject& object)
|
||||
{
|
||||
if (object.isEmpty()) return false;
|
||||
if (object.contains("type")) type = object["type"].toString();
|
||||
if (object.contains("host")) host = object["host"].toString();
|
||||
if (object.contains("path")) path = object["path"].toString();
|
||||
if (object.contains("method")) method = object["method"].toString();
|
||||
if (object.contains("headers") && object["headers"].isObject()) {
|
||||
headers = jsonObjectToQStringList(object["headers"].toObject());
|
||||
}
|
||||
if (object.contains("idle_timeout")) idle_timeout = object["idle_timeout"].toString();
|
||||
if (object.contains("ping_timeout")) ping_timeout = object["ping_timeout"].toString();
|
||||
if (object.contains("max_early_data")) max_early_data = object["max_early_data"].toInt();
|
||||
if (object.contains("early_data_header_name")) early_data_header_name = object["early_data_header_name"].toString();
|
||||
if (object.contains("service_name")) service_name = object["service_name"].toString();
|
||||
return true;
|
||||
}
|
||||
QString Transport::ExportToLink()
|
||||
{
|
||||
QUrlQuery query;
|
||||
if (!type.isEmpty()) query.addQueryItem("type", type);
|
||||
if (!host.isEmpty()) query.addQueryItem("host", host);
|
||||
if (!path.isEmpty()) query.addQueryItem("path", path);
|
||||
if (!method.isEmpty()) query.addQueryItem("method", method);
|
||||
if (!headers.isEmpty()) query.addQueryItem("headers", headers.join(","));
|
||||
if (!idle_timeout.isEmpty()) query.addQueryItem("idle_timeout", idle_timeout);
|
||||
if (!ping_timeout.isEmpty()) query.addQueryItem("ping_timeout", ping_timeout);
|
||||
if (max_early_data > 0) query.addQueryItem("max_early_data", QString::number(max_early_data));
|
||||
if (!early_data_header_name.isEmpty()) query.addQueryItem("early_data_header_name", early_data_header_name);
|
||||
if (!service_name.isEmpty()) query.addQueryItem("serviceName", service_name);
|
||||
return query.toString();
|
||||
}
|
||||
QJsonObject Transport::ExportToJson()
|
||||
{
|
||||
QJsonObject object;
|
||||
if (!type.isEmpty()) object["type"] = type;
|
||||
if (!host.isEmpty()) object["host"] = host;
|
||||
if (!path.isEmpty()) object["path"] = path;
|
||||
if (!method.isEmpty()) object["method"] = method;
|
||||
if (!headers.isEmpty()) {
|
||||
object["headers"] = qStringListToJsonObject(headers);
|
||||
}
|
||||
if (!idle_timeout.isEmpty()) object["idle_timeout"] = idle_timeout;
|
||||
if (!ping_timeout.isEmpty()) object["ping_timeout"] = ping_timeout;
|
||||
if (max_early_data > 0) object["max_early_data"] = max_early_data;
|
||||
if (!early_data_header_name.isEmpty()) object["early_data_header_name"] = early_data_header_name;
|
||||
if (!service_name.isEmpty()) object["service_name"] = service_name;
|
||||
return object;
|
||||
}
|
||||
BuildResult Transport::Build()
|
||||
{
|
||||
return {ExportToJson(), ""};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
47
src/configs/common/utils.cpp
Normal file
47
src/configs/common/utils.cpp
Normal file
@ -0,0 +1,47 @@
|
||||
#include "include/configs/common/utils.h"
|
||||
|
||||
namespace Configs
|
||||
{
|
||||
void mergeUrlQuery(QUrlQuery& baseQuery, const QString& strQuery)
|
||||
{
|
||||
QUrlQuery query = QUrlQuery(strQuery);
|
||||
for (const auto& item : query.queryItems())
|
||||
{
|
||||
baseQuery.addQueryItem(item.first, item.second);
|
||||
}
|
||||
}
|
||||
|
||||
void mergeJsonObjects(QJsonObject& baseObject, const QJsonObject& obj)
|
||||
{
|
||||
for (const auto& key : obj.keys())
|
||||
{
|
||||
baseObject[key] = obj[key];
|
||||
}
|
||||
}
|
||||
|
||||
QStringList jsonObjectToQStringList(const QJsonObject& obj)
|
||||
{
|
||||
auto result = QStringList();
|
||||
for (const auto& key : obj.keys())
|
||||
{
|
||||
result << key << obj[key].toString();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QJsonObject qStringListToJsonObject(const QStringList& list)
|
||||
{
|
||||
auto result = QJsonObject();
|
||||
if (list.count() %2 != 0)
|
||||
{
|
||||
qDebug() << "QStringList of odd length in qStringListToJsonObject:" << list;
|
||||
return result;
|
||||
}
|
||||
for (int i=0;i<list.size();i+=2)
|
||||
{
|
||||
result[list[i]] = list[i+1];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
85
src/configs/outbounds/anyTLS.cpp
Normal file
85
src/configs/outbounds/anyTLS.cpp
Normal file
@ -0,0 +1,85 @@
|
||||
#include "include/configs/outbounds/anyTLS.h"
|
||||
|
||||
#include <QUrlQuery>
|
||||
#include <include/global/Utils.hpp>
|
||||
|
||||
#include "include/configs/common/utils.h"
|
||||
|
||||
namespace Configs {
|
||||
bool anyTLS::ParseFromLink(const QString& link)
|
||||
{
|
||||
auto url = QUrl(link);
|
||||
if (!url.isValid()) return false;
|
||||
auto query = QUrlQuery(url.query(QUrl::ComponentFormattingOption::FullyDecoded));
|
||||
|
||||
commons->ParseFromLink(link);
|
||||
password = url.userName();
|
||||
|
||||
if (commons->server_port == 0) commons->server_port = 443;
|
||||
|
||||
if (query.hasQueryItem("idle_session_check_interval")) idle_session_check_interval = query.queryItemValue("idle_session_check_interval");
|
||||
if (query.hasQueryItem("idle_session_timeout")) idle_session_timeout = query.queryItemValue("idle_session_timeout");
|
||||
if (query.hasQueryItem("min_idle_session")) min_idle_session = query.queryItemValue("min_idle_session").toInt();
|
||||
|
||||
tls->ParseFromLink(link);
|
||||
tls->enabled = true; // anyTLS always uses tls
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool anyTLS::ParseFromJson(const QJsonObject& object)
|
||||
{
|
||||
if (object.isEmpty() || object["type"].toString() != "anytls") return false;
|
||||
commons->ParseFromJson(object);
|
||||
if (object.contains("password")) password = object["password"].toString();
|
||||
if (object.contains("idle_session_check_interval")) idle_session_check_interval = object["idle_session_check_interval"].toString();
|
||||
if (object.contains("idle_session_timeout")) idle_session_timeout = object["idle_session_timeout"].toString();
|
||||
if (object.contains("min_idle_session")) min_idle_session = object["min_idle_session"].toInt();
|
||||
if (object.contains("tls")) tls->ParseFromJson(object["tls"].toObject());
|
||||
return true;
|
||||
}
|
||||
|
||||
QString anyTLS::ExportToLink()
|
||||
{
|
||||
QUrl url;
|
||||
QUrlQuery query;
|
||||
url.setScheme("anytls");
|
||||
url.setUserName(password);
|
||||
url.setHost(commons->server);
|
||||
url.setPort(commons->server_port);
|
||||
if (!commons->name.isEmpty()) url.setFragment(commons->name);
|
||||
|
||||
if (!idle_session_check_interval.isEmpty()) query.addQueryItem("idle_session_check_interval", idle_session_check_interval);
|
||||
if (!idle_session_timeout.isEmpty()) query.addQueryItem("idle_session_timeout", idle_session_timeout);
|
||||
if (min_idle_session > 0) query.addQueryItem("min_idle_session", QString::number(min_idle_session));
|
||||
|
||||
mergeUrlQuery(query, tls->ExportToLink());
|
||||
mergeUrlQuery(query, commons->ExportToLink());
|
||||
|
||||
if (!query.isEmpty()) url.setQuery(query);
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
QJsonObject anyTLS::ExportToJson()
|
||||
{
|
||||
QJsonObject object;
|
||||
object["type"] = "anytls";
|
||||
mergeJsonObjects(object, commons->ExportToJson());
|
||||
if (!password.isEmpty()) object["password"] = password;
|
||||
if (!idle_session_check_interval.isEmpty()) object["idle_session_check_interval"] = idle_session_check_interval;
|
||||
if (!idle_session_timeout.isEmpty()) object["idle_session_timeout"] = idle_session_timeout;
|
||||
if (min_idle_session > 0) object["min_idle_session"] = min_idle_session;
|
||||
object["tls"] = tls->ExportToJson();
|
||||
return object;
|
||||
}
|
||||
|
||||
BuildResult anyTLS::Build()
|
||||
{
|
||||
return {ExportToJson(), ""};
|
||||
}
|
||||
|
||||
QString anyTLS::DisplayType()
|
||||
{
|
||||
return "AnyTLS";
|
||||
}
|
||||
}
|
||||
79
src/configs/outbounds/http.cpp
Normal file
79
src/configs/outbounds/http.cpp
Normal file
@ -0,0 +1,79 @@
|
||||
#include "include/configs/outbounds/http.h"
|
||||
|
||||
#include <QUrlQuery>
|
||||
#include <include/global/Utils.hpp>
|
||||
|
||||
#include "include/configs/common/utils.h"
|
||||
|
||||
namespace Configs {
|
||||
bool http::ParseFromLink(const QString& link)
|
||||
{
|
||||
auto url = QUrl(link);
|
||||
if (!url.isValid()) return false;
|
||||
auto query = QUrlQuery(url.query(QUrl::ComponentFormattingOption::FullyDecoded));
|
||||
|
||||
commons->ParseFromLink(link);
|
||||
username = url.userName();
|
||||
password = url.password();
|
||||
if (query.hasQueryItem("path")) path = query.queryItemValue("path");
|
||||
if (query.hasQueryItem("headers")) headers = query.queryItemValue("headers").split(",");
|
||||
if (url.scheme() == "https" || query.queryItemValue("security") == "tls")
|
||||
{
|
||||
tls->ParseFromLink(link);
|
||||
tls->enabled = true; // force enable in case scheme is https and no security queryValue is set
|
||||
}
|
||||
if (commons->server_port == 0) commons->server_port = 443;
|
||||
return true;
|
||||
}
|
||||
bool http::ParseFromJson(const QJsonObject& object)
|
||||
{
|
||||
if (object.empty() || object["type"] != "http") return false;
|
||||
commons->ParseFromJson(object);
|
||||
if (object.contains("username")) username = object["username"].toString();
|
||||
if (object.contains("password")) password = object["password"].toString();
|
||||
if (object.contains("path")) path = object["path"].toString();
|
||||
if (object.contains("headers") && object["headers"].isObject()) headers = jsonObjectToQStringList(object["headers"].toObject());
|
||||
if (object.contains("tls")) tls->ParseFromJson(object["tls"].toObject());
|
||||
return true;
|
||||
}
|
||||
QString http::ExportToLink()
|
||||
{
|
||||
QUrl url;
|
||||
QUrlQuery query;
|
||||
url.setScheme(tls->enabled ? "https" : "http");
|
||||
url.setHost(commons->server);
|
||||
url.setPort(commons->server_port);
|
||||
if (!commons->name.isEmpty()) url.setFragment(commons->name);
|
||||
if (!username.isEmpty()) url.setUserName(username);
|
||||
if (!password.isEmpty()) url.setPassword(password);
|
||||
if (!path.isEmpty()) query.addQueryItem("path", path);
|
||||
if (!headers.empty()) query.addQueryItem("headers", headers.join(","));
|
||||
mergeUrlQuery(query, tls->ExportToLink());
|
||||
mergeUrlQuery(query, commons->ExportToLink());
|
||||
if (!query.isEmpty()) url.setQuery(query);
|
||||
return url.toString();
|
||||
}
|
||||
QJsonObject http::ExportToJson()
|
||||
{
|
||||
QJsonObject object;
|
||||
object["type"] = "http";
|
||||
mergeJsonObjects(object, commons->ExportToJson());
|
||||
if (!username.isEmpty()) object["username"] = username;
|
||||
if (!password.isEmpty()) object["password"] = password;
|
||||
if (!path.isEmpty()) object["path"] = path;
|
||||
if (auto headerObj = qStringListToJsonObject(headers); !headerObj.isEmpty()) object["headers"] = headerObj;
|
||||
if (auto tlsObj = tls->ExportToJson(); !tlsObj.isEmpty()) object["tls"] = tlsObj;
|
||||
return object;
|
||||
}
|
||||
BuildResult http::Build()
|
||||
{
|
||||
return {ExportToJson(), ""};
|
||||
}
|
||||
|
||||
QString http::DisplayType()
|
||||
{
|
||||
return "HTTP";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
144
src/configs/outbounds/hysteria.cpp
Normal file
144
src/configs/outbounds/hysteria.cpp
Normal file
@ -0,0 +1,144 @@
|
||||
#include "include/configs/outbounds/hysteria.h"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QUrlQuery>
|
||||
#include <3rdparty/URLParser/url_parser.h>
|
||||
#include <include/global/Utils.hpp>
|
||||
|
||||
#include "include/configs/common/utils.h"
|
||||
|
||||
namespace Configs {
|
||||
bool hysteria::ParseFromLink(const QString& link)
|
||||
{
|
||||
auto url = QUrl(link);
|
||||
if (!url.isValid())
|
||||
{
|
||||
if(!url.errorString().startsWith("Invalid port"))
|
||||
return false;
|
||||
commons->server_port = 0;
|
||||
server_ports = QString::fromStdString(URLParser::Parse((link.split("?")[0] + "/").toStdString()).port).split(",");
|
||||
for (auto & serverPort : server_ports) {
|
||||
serverPort.replace("-", ":");
|
||||
}
|
||||
}
|
||||
auto query = QUrlQuery(url.query(QUrl::ComponentFormattingOption::FullyDecoded));
|
||||
|
||||
commons->ParseFromLink(link);
|
||||
|
||||
if (query.hasQueryItem("upmbps")) up_mbps = query.queryItemValue("upmbps").toInt();
|
||||
if (query.hasQueryItem("downmbps")) down_mbps = query.queryItemValue("downmbps").toInt();
|
||||
if (query.hasQueryItem("obfsParam")) obfs = QUrl::fromPercentEncoding(query.queryItemValue("obfsParam").toUtf8());
|
||||
if (query.hasQueryItem("auth")) auth_str = query.queryItemValue("auth");
|
||||
if (query.hasQueryItem("recv_window_conn")) recv_window_conn = query.queryItemValue("recv_window_conn").toInt();
|
||||
if (query.hasQueryItem("recv_window")) recv_window = query.queryItemValue("recv_window").toInt();
|
||||
if (query.hasQueryItem("disable_mtu_discovery")) disable_mtu_discovery = query.queryItemValue("disable_mtu_discovery") == "true";
|
||||
if (query.hasQueryItem("hop_interval")) hop_interval = query.queryItemValue("hop_interval");
|
||||
if (query.hasQueryItem("mport")) {
|
||||
server_ports = query.queryItemValue("mport").split(",");
|
||||
for (auto & server_port : server_ports) {
|
||||
server_port.replace("-", ":");
|
||||
}
|
||||
}
|
||||
|
||||
tls->ParseFromLink(link);
|
||||
|
||||
if (commons->server_port == 0 && server_ports.isEmpty()) commons->server_port = 443;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hysteria::ParseFromJson(const QJsonObject& object)
|
||||
{
|
||||
if (object.isEmpty() || object["type"].toString() != "hysteria") return false;
|
||||
commons->ParseFromJson(object);
|
||||
if (object.contains("server_ports")) {
|
||||
server_ports = QJsonArray2QListString(object["server_ports"].toArray());
|
||||
}
|
||||
if (object.contains("hop_interval")) hop_interval = object["hop_interval"].toString();
|
||||
if (object.contains("up_mbps")) up_mbps = object["up_mbps"].toInt();
|
||||
if (object.contains("down_mbps")) down_mbps = object["down_mbps"].toInt();
|
||||
if (object.contains("obfs")) obfs = object["obfs"].toString();
|
||||
if (object.contains("auth")) auth = object["auth"].toString();
|
||||
if (object.contains("auth_str")) auth_str = object["auth_str"].toString();
|
||||
if (object.contains("recv_window_conn")) recv_window_conn = object["recv_window_conn"].toInt();
|
||||
if (object.contains("recv_window")) recv_window = object["recv_window"].toInt();
|
||||
if (object.contains("disable_mtu_discovery")) disable_mtu_discovery = object["disable_mtu_discovery"].toBool();
|
||||
if (object.contains("tls")) tls->ParseFromJson(object["tls"].toObject());
|
||||
return true;
|
||||
}
|
||||
|
||||
QString hysteria::ExportToLink()
|
||||
{
|
||||
QUrl url;
|
||||
QUrlQuery query;
|
||||
url.setScheme("hysteria");
|
||||
url.setHost(commons->server);
|
||||
url.setPort(0);
|
||||
|
||||
if (!server_ports.isEmpty()) {
|
||||
QStringList portList;
|
||||
for (const auto& port : server_ports) {
|
||||
QString modified = port;
|
||||
modified.replace(":", "-");
|
||||
portList.append(modified);
|
||||
}
|
||||
url.setPort(0);
|
||||
query.addQueryItem("mport", portList.join(","));
|
||||
} else {
|
||||
url.setPort(commons->server_port);
|
||||
}
|
||||
|
||||
if (!commons->name.isEmpty()) url.setFragment(commons->name);
|
||||
|
||||
if (up_mbps > 0) query.addQueryItem("upmbps", QString::number(up_mbps));
|
||||
if (down_mbps > 0) query.addQueryItem("downmbps", QString::number(down_mbps));
|
||||
if (!obfs.isEmpty()) {
|
||||
query.addQueryItem("obfsParam", QUrl::toPercentEncoding(obfs));
|
||||
}
|
||||
if (!auth_str.isEmpty()) query.addQueryItem("auth", auth_str);
|
||||
if (recv_window_conn > 0) query.addQueryItem("recv_window_conn", QString::number(recv_window_conn));
|
||||
if (recv_window > 0) query.addQueryItem("recv_window", QString::number(recv_window));
|
||||
if (disable_mtu_discovery) query.addQueryItem("disable_mtu_discovery", "true");
|
||||
if (!hop_interval.isEmpty()) query.addQueryItem("hop_interval", hop_interval);
|
||||
|
||||
mergeUrlQuery(query, tls->ExportToLink());
|
||||
mergeUrlQuery(query, commons->ExportToLink());
|
||||
|
||||
if (!query.isEmpty()) url.setQuery(query);
|
||||
|
||||
QString result = url.toString();
|
||||
if (!server_ports.isEmpty()) {
|
||||
result = result.replace(":0?", ":" + query.queryItemValue("mport") + "?");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QJsonObject hysteria::ExportToJson()
|
||||
{
|
||||
QJsonObject object;
|
||||
object["type"] = "hysteria";
|
||||
mergeJsonObjects(object, commons->ExportToJson());
|
||||
if (!server_ports.isEmpty()) object["server_ports"] = QListStr2QJsonArray(server_ports);
|
||||
if (!hop_interval.isEmpty()) object["hop_interval"] = hop_interval;
|
||||
if (up_mbps > 0) object["up_mbps"] = up_mbps;
|
||||
if (down_mbps > 0) object["down_mbps"] = down_mbps;
|
||||
if (!obfs.isEmpty()) object["obfs"] = obfs;
|
||||
if (!auth.isEmpty()) object["auth"] = auth;
|
||||
if (!auth_str.isEmpty()) object["auth_str"] = auth_str;
|
||||
if (recv_window_conn > 0) object["recv_window_conn"] = recv_window_conn;
|
||||
if (recv_window > 0) object["recv_window"] = recv_window;
|
||||
if (disable_mtu_discovery) object["disable_mtu_discovery"] = disable_mtu_discovery;
|
||||
if (tls->enabled) object["tls"] = tls->ExportToJson();
|
||||
return object;
|
||||
}
|
||||
|
||||
BuildResult hysteria::Build()
|
||||
{
|
||||
return {ExportToJson(), ""};
|
||||
}
|
||||
|
||||
QString hysteria::DisplayType()
|
||||
{
|
||||
return "Hysteria";
|
||||
}
|
||||
}
|
||||
146
src/configs/outbounds/hysteria2.cpp
Normal file
146
src/configs/outbounds/hysteria2.cpp
Normal file
@ -0,0 +1,146 @@
|
||||
#include "include/configs/outbounds/hysteria2.h"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QUrlQuery>
|
||||
#include <3rdparty/URLParser/url_parser.h>
|
||||
#include <include/global/Utils.hpp>
|
||||
|
||||
#include "include/configs/common/utils.h"
|
||||
|
||||
namespace Configs {
|
||||
bool hysteria2::ParseFromLink(const QString& link)
|
||||
{
|
||||
auto url = QUrl(link);
|
||||
if (!url.isValid())
|
||||
{
|
||||
if(!url.errorString().startsWith("Invalid port"))
|
||||
return false;
|
||||
commons->server_port = 0;
|
||||
server_ports = QString::fromStdString(URLParser::Parse((link.split("?")[0] + "/").toStdString()).port).split(",");
|
||||
for (auto & serverPort : server_ports) {
|
||||
serverPort.replace("-", ":");
|
||||
}
|
||||
}
|
||||
auto query = QUrlQuery(url.query(QUrl::ComponentFormattingOption::FullyDecoded));
|
||||
|
||||
commons->ParseFromLink(link);
|
||||
|
||||
if (url.password().isEmpty()) {
|
||||
password = url.userName();
|
||||
} else {
|
||||
password = url.userName() + ":" + url.password();
|
||||
}
|
||||
|
||||
if (query.hasQueryItem("obfs-password")) {
|
||||
obfsPassword = QUrl::fromPercentEncoding(query.queryItemValue("obfs-password").toUtf8());
|
||||
}
|
||||
if (query.hasQueryItem("upmbps")) up_mbps = query.queryItemValue("upmbps").toInt();
|
||||
if (query.hasQueryItem("downmbps")) down_mbps = query.queryItemValue("downmbps").toInt();
|
||||
|
||||
if (query.hasQueryItem("mport")) {
|
||||
QStringList ports = query.queryItemValue("mport").split(",");
|
||||
for (auto& port : ports) {
|
||||
port.replace("-", ":");
|
||||
server_ports.append(port);
|
||||
}
|
||||
}
|
||||
if (query.hasQueryItem("hop_interval")) hop_interval = query.queryItemValue("hop_interval");
|
||||
|
||||
tls->ParseFromLink(link);
|
||||
|
||||
if (commons->server_port == 0 && server_ports.isEmpty()) commons->server_port = 443;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hysteria2::ParseFromJson(const QJsonObject& object)
|
||||
{
|
||||
if (object.isEmpty() || object["type"].toString() != "hysteria2") return false;
|
||||
commons->ParseFromJson(object);
|
||||
if (object.contains("server_ports")) {
|
||||
server_ports = QJsonArray2QListString(object["server_ports"].toArray());
|
||||
}
|
||||
if (object.contains("hop_interval")) hop_interval = object["hop_interval"].toString();
|
||||
if (object.contains("up_mbps")) up_mbps = object["up_mbps"].toInt();
|
||||
if (object.contains("down_mbps")) down_mbps = object["down_mbps"].toInt();
|
||||
if (object.contains("obfsType")) obfsType = object["obfsType"].toString();
|
||||
if (object.contains("obfsPassword")) obfsPassword = object["obfsPassword"].toString();
|
||||
if (object.contains("password")) password = object["password"].toString();
|
||||
if (object.contains("tls")) tls->ParseFromJson(object["tls"].toObject());
|
||||
return true;
|
||||
}
|
||||
|
||||
QString hysteria2::ExportToLink()
|
||||
{
|
||||
QUrl url;
|
||||
QUrlQuery query;
|
||||
url.setScheme("hy2");
|
||||
url.setHost(commons->server);
|
||||
|
||||
if (password.contains(":")) {
|
||||
url.setUserName(SubStrBefore(password, ":"));
|
||||
url.setPassword(SubStrAfter(password, ":"));
|
||||
} else {
|
||||
url.setUserName(password);
|
||||
}
|
||||
|
||||
if (!server_ports.isEmpty()) {
|
||||
QStringList portList;
|
||||
for (const auto& port : server_ports) {
|
||||
QString modified = port;
|
||||
modified.replace(":", "-");
|
||||
portList.append(modified);
|
||||
}
|
||||
url.setPort(0);
|
||||
query.addQueryItem("mport", portList.join(","));
|
||||
} else {
|
||||
url.setPort(commons->server_port);
|
||||
}
|
||||
|
||||
if (!commons->name.isEmpty()) url.setFragment(commons->name);
|
||||
|
||||
if (!obfsPassword.isEmpty()) {
|
||||
query.addQueryItem("obfs-password", QUrl::toPercentEncoding(obfsPassword));
|
||||
}
|
||||
if (up_mbps > 0) query.addQueryItem("upmbps", QString::number(up_mbps));
|
||||
if (down_mbps > 0) query.addQueryItem("downmbps", QString::number(down_mbps));
|
||||
if (!hop_interval.isEmpty()) query.addQueryItem("hop_interval", hop_interval);
|
||||
|
||||
mergeUrlQuery(query, tls->ExportToLink());
|
||||
mergeUrlQuery(query, commons->ExportToLink());
|
||||
|
||||
if (!query.isEmpty()) url.setQuery(query);
|
||||
|
||||
QString result = url.toString();
|
||||
if (!server_ports.isEmpty()) {
|
||||
result = result.replace(":0?", ":" + query.queryItemValue("mport") + "?");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QJsonObject hysteria2::ExportToJson()
|
||||
{
|
||||
QJsonObject object;
|
||||
object["type"] = "hysteria2";
|
||||
mergeJsonObjects(object, commons->ExportToJson());
|
||||
if (!server_ports.isEmpty()) object["server_ports"] = QListStr2QJsonArray(server_ports);
|
||||
if (!hop_interval.isEmpty()) object["hop_interval"] = hop_interval;
|
||||
if (up_mbps > 0) object["up_mbps"] = up_mbps;
|
||||
if (down_mbps > 0) object["down_mbps"] = down_mbps;
|
||||
if (!obfsType.isEmpty()) object["obfsType"] = obfsType;
|
||||
if (!obfsPassword.isEmpty()) object["obfsPassword"] = obfsPassword;
|
||||
if (!password.isEmpty()) object["password"] = password;
|
||||
if (tls->enabled) object["tls"] = tls->ExportToJson();
|
||||
return object;
|
||||
}
|
||||
|
||||
BuildResult hysteria2::Build()
|
||||
{
|
||||
return {ExportToJson(), ""};
|
||||
}
|
||||
|
||||
QString hysteria2::DisplayType()
|
||||
{
|
||||
return "Hysteria2";
|
||||
}
|
||||
}
|
||||
122
src/configs/outbounds/shadowsocks.cpp
Normal file
122
src/configs/outbounds/shadowsocks.cpp
Normal file
@ -0,0 +1,122 @@
|
||||
#include "include/configs/outbounds/shadowsocks.h"
|
||||
|
||||
#include <QUrlQuery>
|
||||
#include <include/global/Utils.hpp>
|
||||
|
||||
#include "include/configs/common/utils.h"
|
||||
|
||||
namespace Configs {
|
||||
bool shadowsocks::ParseFromLink(const QString& link)
|
||||
{
|
||||
auto url = QUrl(link);
|
||||
if (!url.isValid()) return false;
|
||||
auto query = QUrlQuery(url.query(QUrl::ComponentFormattingOption::FullyDecoded));
|
||||
|
||||
commons->ParseFromLink(link);
|
||||
|
||||
if (SubStrBefore(link, "#").contains("@")) {
|
||||
// Traditional SS format
|
||||
if (url.password().isEmpty()) {
|
||||
// Traditional format: method:password base64 encoded in username
|
||||
auto method_password = DecodeB64IfValid(url.userName(), QByteArray::Base64Option::Base64UrlEncoding);
|
||||
if (method_password.isEmpty()) return false;
|
||||
method = SubStrBefore(method_password, ":");
|
||||
password = SubStrAfter(method_password, ":");
|
||||
} else {
|
||||
// 2022 format: method in username, password in password
|
||||
method = url.userName();
|
||||
password = url.password();
|
||||
}
|
||||
} else {
|
||||
// v2rayN format: base64 encoded full URL
|
||||
QString linkN = DecodeB64IfValid(SubStrBefore(SubStrAfter(link, "://"), "#"), QByteArray::Base64Option::Base64UrlEncoding);
|
||||
if (linkN.isEmpty()) return false;
|
||||
if (link.contains("#")) linkN += "#" + SubStrAfter(link, "#");
|
||||
url = QUrl("https://" + linkN);
|
||||
if (!url.isValid()) return false;
|
||||
query = QUrlQuery(url.query(QUrl::ComponentFormattingOption::FullyDecoded));
|
||||
commons->ParseFromLink(url.toString());
|
||||
method = url.userName();
|
||||
password = url.password();
|
||||
}
|
||||
|
||||
plugin = query.queryItemValue("plugin").replace("simple-obfs;", "obfs-local;");
|
||||
if (query.hasQueryItem("plugin-opts")) plugin_opts = query.queryItemValue("plugin-opts");
|
||||
if (query.hasQueryItem("uot")) uot = query.queryItemValue("uot") == "true" || query.queryItemValue("uot").toInt() > 0;
|
||||
multiplex->ParseFromLink(link);
|
||||
|
||||
return !(commons->server.isEmpty() || method.isEmpty() || password.isEmpty());
|
||||
}
|
||||
|
||||
bool shadowsocks::ParseFromJson(const QJsonObject& object)
|
||||
{
|
||||
if (object.isEmpty() || object["type"].toString() != "shadowsocks") return false;
|
||||
commons->ParseFromJson(object);
|
||||
if (object.contains("method")) method = object["method"].toString();
|
||||
if (object.contains("password")) password = object["password"].toString();
|
||||
if (object.contains("plugin")) plugin = object["plugin"].toString();
|
||||
if (object.contains("plugin_opts")) plugin_opts = object["plugin_opts"].toString();
|
||||
if (object.contains("uot"))
|
||||
{
|
||||
if (object["uot"].isBool()) uot = object["uot"].toBool();
|
||||
if (object["uot"].isObject()) uot = object["uot"].toObject()["enabled"].toBool();
|
||||
}
|
||||
if (object.contains("multiplex")) multiplex->ParseFromJson(object["multiplex"].toObject());
|
||||
return true;
|
||||
}
|
||||
|
||||
QString shadowsocks::ExportToLink()
|
||||
{
|
||||
QUrl url;
|
||||
QUrlQuery query;
|
||||
url.setScheme("ss");
|
||||
|
||||
if (method.startsWith("2022-")) {
|
||||
// 2022 format: method:password directly
|
||||
url.setUserName(method);
|
||||
url.setPassword(password);
|
||||
} else {
|
||||
// Traditional format: base64 encode method:password
|
||||
auto method_password = method + ":" + password;
|
||||
url.setUserName(method_password.toUtf8().toBase64(QByteArray::Base64Option::Base64UrlEncoding));
|
||||
}
|
||||
|
||||
url.setHost(commons->server);
|
||||
url.setPort(commons->server_port);
|
||||
if (!commons->name.isEmpty()) url.setFragment(commons->name);
|
||||
|
||||
if (!plugin.isEmpty()) query.addQueryItem("plugin", plugin);
|
||||
if (!plugin_opts.isEmpty()) query.addQueryItem("plugin-opts", plugin_opts);
|
||||
if (uot) query.addQueryItem("uot", "true");
|
||||
|
||||
mergeUrlQuery(query, multiplex->ExportToLink());
|
||||
mergeUrlQuery(query, commons->ExportToLink());
|
||||
|
||||
if (!query.isEmpty()) url.setQuery(query);
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
QJsonObject shadowsocks::ExportToJson()
|
||||
{
|
||||
QJsonObject object;
|
||||
object["type"] = "shadowsocks";
|
||||
mergeJsonObjects(object, commons->ExportToJson());
|
||||
if (!method.isEmpty()) object["method"] = method;
|
||||
if (!password.isEmpty()) object["password"] = password;
|
||||
if (!plugin.isEmpty()) object["plugin"] = plugin;
|
||||
if (!plugin_opts.isEmpty()) object["plugin_opts"] = plugin_opts;
|
||||
if (uot) object["uot"] = uot;
|
||||
if (multiplex->enabled) object["multiplex"] = multiplex->ExportToJson();
|
||||
return object;
|
||||
}
|
||||
|
||||
BuildResult shadowsocks::Build()
|
||||
{
|
||||
return {ExportToJson(), ""};
|
||||
}
|
||||
|
||||
QString shadowsocks::DisplayType()
|
||||
{
|
||||
return "Shadowsocks";
|
||||
}
|
||||
}
|
||||
105
src/configs/outbounds/socks.cpp
Normal file
105
src/configs/outbounds/socks.cpp
Normal file
@ -0,0 +1,105 @@
|
||||
#include "include/configs/outbounds/socks.h"
|
||||
|
||||
#include <QUrlQuery>
|
||||
#include <include/global/Utils.hpp>
|
||||
|
||||
#include "include/configs/common/utils.h"
|
||||
|
||||
namespace Configs {
|
||||
bool socks::ParseFromLink(const QString& link)
|
||||
{
|
||||
auto url = QUrl(link);
|
||||
if (!url.isValid()) return false;
|
||||
auto query = QUrlQuery(url.query(QUrl::ComponentFormattingOption::FullyDecoded));
|
||||
|
||||
commons->ParseFromLink(link);
|
||||
if (query.hasQueryItem("version"))
|
||||
{
|
||||
version = query.queryItemValue("version").toInt();
|
||||
} else
|
||||
{
|
||||
if (url.scheme() == "socks4") version = 4;
|
||||
if (url.scheme() == "socks5") version = 5;
|
||||
}
|
||||
|
||||
// Handle v2rayN format (base64 encoded username)
|
||||
if (!url.password().isEmpty() || !url.userName().isEmpty()) {
|
||||
username = url.userName();
|
||||
password = url.password();
|
||||
|
||||
// Check if username is base64 encoded (v2rayN format)
|
||||
if (password.isEmpty() && !username.isEmpty()) {
|
||||
QString decoded = DecodeB64IfValid(username);
|
||||
if (!decoded.isEmpty()) {
|
||||
username = SubStrBefore(decoded, ":");
|
||||
password = SubStrAfter(decoded, ":");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (query.hasQueryItem("uot")) uot = query.queryItemValue("uot") == "true" || query.queryItemValue("uot").toInt() > 0;
|
||||
|
||||
// Default port
|
||||
if (commons->server_port == 0) commons->server_port = 1080;
|
||||
|
||||
return !commons->server.isEmpty();
|
||||
}
|
||||
|
||||
bool socks::ParseFromJson(const QJsonObject& object)
|
||||
{
|
||||
if (object.isEmpty() || object["type"].toString() != "socks") return false;
|
||||
commons->ParseFromJson(object);
|
||||
if (object.contains("username")) username = object["username"].toString();
|
||||
if (object.contains("password")) password = object["password"].toString();
|
||||
if (object.contains("version")) version = object["version"].toInt();
|
||||
if (object.contains("uot")) uot = object["uot"].toBool();
|
||||
return true;
|
||||
}
|
||||
|
||||
QString socks::ExportToLink()
|
||||
{
|
||||
QUrl url;
|
||||
QUrlQuery query;
|
||||
|
||||
// Determine scheme based on SOCKS version (default to socks5)
|
||||
QString scheme = "socks5";
|
||||
if (version == 4) {
|
||||
scheme = "socks4";
|
||||
}
|
||||
url.setScheme(scheme);
|
||||
|
||||
url.setHost(commons->server);
|
||||
url.setPort(commons->server_port);
|
||||
if (!commons->name.isEmpty()) url.setFragment(commons->name);
|
||||
|
||||
if (!username.isEmpty()) url.setUserName(username);
|
||||
if (!password.isEmpty()) url.setPassword(password);
|
||||
if (uot) query.addQueryItem("uot", "1");
|
||||
|
||||
mergeUrlQuery(query, commons->ExportToLink());
|
||||
if (!query.isEmpty()) url.setQuery(query);
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
QJsonObject socks::ExportToJson()
|
||||
{
|
||||
QJsonObject object;
|
||||
object["type"] = "socks";
|
||||
mergeJsonObjects(object, commons->ExportToJson());
|
||||
if (!username.isEmpty()) object["username"] = username;
|
||||
if (!password.isEmpty()) object["password"] = password;
|
||||
if (version == 4) object["version"] = "4";
|
||||
if (uot) object["uot"] = uot;
|
||||
return object;
|
||||
}
|
||||
|
||||
BuildResult socks::Build()
|
||||
{
|
||||
return {ExportToJson(), ""};
|
||||
}
|
||||
|
||||
QString socks::DisplayType()
|
||||
{
|
||||
return "Socks";
|
||||
}
|
||||
}
|
||||
134
src/configs/outbounds/ssh.cpp
Normal file
134
src/configs/outbounds/ssh.cpp
Normal file
@ -0,0 +1,134 @@
|
||||
#include "include/configs/outbounds/ssh.h"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QUrlQuery>
|
||||
#include <include/global/Utils.hpp>
|
||||
|
||||
#include "include/configs/common/utils.h"
|
||||
|
||||
namespace Configs {
|
||||
bool ssh::ParseFromLink(const QString& link)
|
||||
{
|
||||
auto url = QUrl(link);
|
||||
if (!url.isValid()) return false;
|
||||
auto query = QUrlQuery(url.query(QUrl::ComponentFormattingOption::FullyDecoded));
|
||||
|
||||
commons->ParseFromLink(link);
|
||||
|
||||
if (query.hasQueryItem("user")) user = query.queryItemValue("user");
|
||||
if (query.hasQueryItem("password")) password = query.queryItemValue("password");
|
||||
|
||||
QString privateKeyB64 = query.queryItemValue("private_key");
|
||||
if (!privateKeyB64.isEmpty()) {
|
||||
private_key = QByteArray::fromBase64(privateKeyB64.toUtf8(), QByteArray::OmitTrailingEquals);
|
||||
}
|
||||
if (query.hasQueryItem("private_key_path")) private_key_path = query.queryItemValue("private_key_path");
|
||||
if (query.hasQueryItem("private_key_passphrase")) private_key_passphrase = query.queryItemValue("private_key_passphrase");
|
||||
|
||||
QString hostKeysRaw = query.queryItemValue("host_key");
|
||||
if (!hostKeysRaw.isEmpty()) {
|
||||
for (const auto& item : hostKeysRaw.split("-")) {
|
||||
auto b64hostKey = QByteArray::fromBase64(item.toUtf8(), QByteArray::OmitTrailingEquals);
|
||||
if (!b64hostKey.isEmpty()) host_key.append(QString(b64hostKey));
|
||||
}
|
||||
}
|
||||
|
||||
QString hostKeyAlgsRaw = query.queryItemValue("host_key_algorithms");
|
||||
if (!hostKeyAlgsRaw.isEmpty()) {
|
||||
for (const auto& item : hostKeyAlgsRaw.split("-")) {
|
||||
auto b64hostKeyAlg = QByteArray::fromBase64(item.toUtf8(), QByteArray::OmitTrailingEquals);
|
||||
if (!b64hostKeyAlg.isEmpty()) host_key_algorithms.append(QString(b64hostKeyAlg));
|
||||
}
|
||||
}
|
||||
|
||||
if (query.hasQueryItem("client_version")) client_version = query.queryItemValue("client_version");
|
||||
|
||||
return !commons->server.isEmpty();
|
||||
}
|
||||
|
||||
bool ssh::ParseFromJson(const QJsonObject& object)
|
||||
{
|
||||
if (object.isEmpty() || object["type"].toString() != "ssh") return false;
|
||||
commons->ParseFromJson(object);
|
||||
if (object.contains("user")) user = object["user"].toString();
|
||||
if (object.contains("password")) password = object["password"].toString();
|
||||
if (object.contains("private_key")) private_key = object["private_key"].toString();
|
||||
if (object.contains("private_key_path")) private_key_path = object["private_key_path"].toString();
|
||||
if (object.contains("private_key_passphrase")) private_key_passphrase = object["private_key_passphrase"].toString();
|
||||
if (object.contains("host_key")) {
|
||||
host_key = QJsonArray2QListString(object["host_key"].toArray());
|
||||
}
|
||||
if (object.contains("host_key_algorithms")) {
|
||||
host_key_algorithms = QJsonArray2QListString(object["host_key_algorithms"].toArray());
|
||||
}
|
||||
if (object.contains("client_version")) client_version = object["client_version"].toString();
|
||||
return true;
|
||||
}
|
||||
|
||||
QString ssh::ExportToLink()
|
||||
{
|
||||
QUrl url;
|
||||
QUrlQuery query;
|
||||
url.setScheme("ssh");
|
||||
url.setHost(commons->server);
|
||||
url.setPort(commons->server_port);
|
||||
if (!commons->name.isEmpty()) url.setFragment(commons->name);
|
||||
|
||||
if (!user.isEmpty()) query.addQueryItem("user", user);
|
||||
if (!password.isEmpty()) query.addQueryItem("password", password);
|
||||
if (!private_key.isEmpty()) {
|
||||
query.addQueryItem("private_key", private_key.toUtf8().toBase64(QByteArray::OmitTrailingEquals));
|
||||
}
|
||||
if (!private_key_path.isEmpty()) query.addQueryItem("private_key_path", private_key_path);
|
||||
if (!private_key_passphrase.isEmpty()) query.addQueryItem("private_key_passphrase", private_key_passphrase);
|
||||
|
||||
if (!host_key.isEmpty()) {
|
||||
QStringList b64HostKeys;
|
||||
for (const auto& item : host_key) {
|
||||
b64HostKeys.append(item.toUtf8().toBase64(QByteArray::OmitTrailingEquals));
|
||||
}
|
||||
query.addQueryItem("host_key", b64HostKeys.join("-"));
|
||||
}
|
||||
|
||||
if (!host_key_algorithms.isEmpty()) {
|
||||
QStringList b64HostKeyAlgs;
|
||||
for (const auto& item : host_key_algorithms) {
|
||||
b64HostKeyAlgs.append(item.toUtf8().toBase64(QByteArray::OmitTrailingEquals));
|
||||
}
|
||||
query.addQueryItem("host_key_algorithms", b64HostKeyAlgs.join("-"));
|
||||
}
|
||||
|
||||
if (!client_version.isEmpty()) query.addQueryItem("client_version", client_version);
|
||||
|
||||
mergeUrlQuery(query, commons->ExportToLink());
|
||||
|
||||
if (!query.isEmpty()) url.setQuery(query);
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
QJsonObject ssh::ExportToJson()
|
||||
{
|
||||
QJsonObject object;
|
||||
object["type"] = "ssh";
|
||||
mergeJsonObjects(object, commons->ExportToJson());
|
||||
if (!user.isEmpty()) object["user"] = user;
|
||||
if (!password.isEmpty()) object["password"] = password;
|
||||
if (!private_key.isEmpty()) object["private_key"] = private_key;
|
||||
if (!private_key_path.isEmpty()) object["private_key_path"] = private_key_path;
|
||||
if (!private_key_passphrase.isEmpty()) object["private_key_passphrase"] = private_key_passphrase;
|
||||
if (!host_key.isEmpty()) object["host_key"] = QListStr2QJsonArray(host_key);
|
||||
if (!host_key_algorithms.isEmpty()) object["host_key_algorithms"] = QListStr2QJsonArray(host_key_algorithms);
|
||||
if (!client_version.isEmpty()) object["client_version"] = client_version;
|
||||
return object;
|
||||
}
|
||||
|
||||
BuildResult ssh::Build()
|
||||
{
|
||||
return {ExportToJson(), ""};
|
||||
}
|
||||
|
||||
QString ssh::DisplayType()
|
||||
{
|
||||
return "SSH";
|
||||
}
|
||||
}
|
||||
118
src/configs/outbounds/tailscale.cpp
Normal file
118
src/configs/outbounds/tailscale.cpp
Normal file
@ -0,0 +1,118 @@
|
||||
#include "include/configs/outbounds/tailscale.h"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QUrlQuery>
|
||||
#include <include/global/Utils.hpp>
|
||||
|
||||
#include "include/configs/common/utils.h"
|
||||
|
||||
namespace Configs {
|
||||
bool tailscale::ParseFromLink(const QString& link)
|
||||
{
|
||||
auto url = QUrl(link);
|
||||
if (!url.isValid()) return false;
|
||||
auto query = QUrlQuery(url.query(QUrl::ComponentFormattingOption::FullyDecoded));
|
||||
|
||||
commons->ParseFromLink(link);
|
||||
|
||||
if (query.hasQueryItem("state_directory")) state_directory = QUrl::fromPercentEncoding(query.queryItemValue("state_directory").toUtf8());
|
||||
if (query.hasQueryItem("auth_key")) auth_key = QUrl::fromPercentEncoding(query.queryItemValue("auth_key").toUtf8());
|
||||
if (query.hasQueryItem("control_url")) control_url = QUrl::fromPercentEncoding(query.queryItemValue("control_url").toUtf8());
|
||||
if (query.hasQueryItem("ephemeral")) ephemeral = query.queryItemValue("ephemeral") == "true";
|
||||
if (query.hasQueryItem("hostname")) hostname = QUrl::fromPercentEncoding(query.queryItemValue("hostname").toUtf8());
|
||||
if (query.hasQueryItem("accept_routes")) accept_routes = query.queryItemValue("accept_routes") == "true";
|
||||
if (query.hasQueryItem("exit_node")) exit_node = query.queryItemValue("exit_node");
|
||||
if (query.hasQueryItem("exit_node_allow_lan_access")) exit_node_allow_lan_access = query.queryItemValue("exit_node_allow_lan_access") == "true";
|
||||
if (query.hasQueryItem("advertise_routes")) {
|
||||
advertise_routes = QUrl::fromPercentEncoding(query.queryItemValue("advertise_routes").toUtf8()).split(",");
|
||||
}
|
||||
if (query.hasQueryItem("advertise_exit_node")) advertise_exit_node = query.queryItemValue("advertise_exit_node") == "true";
|
||||
if (query.hasQueryItem("globalDNS")) globalDNS = query.queryItemValue("globalDNS") == "true";
|
||||
if (query.hasQueryItem("global_dns")) globalDNS = query.queryItemValue("global_dns") == "true";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tailscale::ParseFromJson(const QJsonObject& object)
|
||||
{
|
||||
if (object.isEmpty() || object["type"].toString() != "tailscale") return false;
|
||||
commons->ParseFromJson(object);
|
||||
if (object.contains("state_directory")) state_directory = object["state_directory"].toString();
|
||||
if (object.contains("auth_key")) auth_key = object["auth_key"].toString();
|
||||
if (object.contains("control_url")) control_url = object["control_url"].toString();
|
||||
if (object.contains("ephemeral")) ephemeral = object["ephemeral"].toBool();
|
||||
if (object.contains("hostname")) hostname = object["hostname"].toString();
|
||||
if (object.contains("accept_routes")) accept_routes = object["accept_routes"].toBool();
|
||||
if (object.contains("exit_node")) exit_node = object["exit_node"].toString();
|
||||
if (object.contains("exit_node_allow_lan_access")) exit_node_allow_lan_access = object["exit_node_allow_lan_access"].toBool();
|
||||
if (object.contains("advertise_routes")) {
|
||||
advertise_routes = QJsonArray2QListString(object["advertise_routes"].toArray());
|
||||
}
|
||||
if (object.contains("advertise_exit_node")) advertise_exit_node = object["advertise_exit_node"].toBool();
|
||||
if (object.contains("globalDNS")) globalDNS = object["globalDNS"].toBool();
|
||||
return true;
|
||||
}
|
||||
|
||||
QString tailscale::ExportToLink()
|
||||
{
|
||||
QUrl url;
|
||||
QUrlQuery query;
|
||||
url.setScheme("ts");
|
||||
url.setHost("tailscale");
|
||||
if (!commons->name.isEmpty()) url.setFragment(commons->name);
|
||||
|
||||
if (!state_directory.isEmpty()) query.addQueryItem("state_directory", QUrl::toPercentEncoding(state_directory));
|
||||
if (!auth_key.isEmpty()) query.addQueryItem("auth_key", QUrl::toPercentEncoding(auth_key));
|
||||
if (!control_url.isEmpty()) query.addQueryItem("control_url", QUrl::toPercentEncoding(control_url));
|
||||
if (ephemeral) query.addQueryItem("ephemeral", "true");
|
||||
if (!hostname.isEmpty()) query.addQueryItem("hostname", QUrl::toPercentEncoding(hostname));
|
||||
if (accept_routes) query.addQueryItem("accept_routes", "true");
|
||||
if (!exit_node.isEmpty()) query.addQueryItem("exit_node", exit_node);
|
||||
if (exit_node_allow_lan_access) query.addQueryItem("exit_node_allow_lan_access", "true");
|
||||
if (!advertise_routes.isEmpty()) query.addQueryItem("advertise_routes", QUrl::toPercentEncoding(advertise_routes.join(",")));
|
||||
if (advertise_exit_node) query.addQueryItem("advertise_exit_node", "true");
|
||||
if (globalDNS) query.addQueryItem("global_dns", "true");
|
||||
|
||||
if (!query.isEmpty()) url.setQuery(query);
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
QJsonObject tailscale::ExportToJson()
|
||||
{
|
||||
QJsonObject object;
|
||||
object["type"] = "tailscale";
|
||||
mergeJsonObjects(object, commons->ExportToJson());
|
||||
if (!state_directory.isEmpty()) object["state_directory"] = state_directory;
|
||||
if (!auth_key.isEmpty()) object["auth_key"] = auth_key;
|
||||
if (!control_url.isEmpty()) object["control_url"] = control_url;
|
||||
if (ephemeral) object["ephemeral"] = ephemeral;
|
||||
if (!hostname.isEmpty()) object["hostname"] = hostname;
|
||||
if (accept_routes) object["accept_routes"] = accept_routes;
|
||||
if (!exit_node.isEmpty()) object["exit_node"] = exit_node;
|
||||
if (exit_node_allow_lan_access) object["exit_node_allow_lan_access"] = exit_node_allow_lan_access;
|
||||
if (!advertise_routes.isEmpty()) object["advertise_routes"] = QListStr2QJsonArray(advertise_routes);
|
||||
if (advertise_exit_node) object["advertise_exit_node"] = advertise_exit_node;
|
||||
if (globalDNS) object["globalDNS"] = globalDNS;
|
||||
return object;
|
||||
}
|
||||
|
||||
BuildResult tailscale::Build()
|
||||
{
|
||||
return {ExportToJson(), ""};
|
||||
}
|
||||
|
||||
QString tailscale::DisplayAddress()
|
||||
{
|
||||
return control_url;
|
||||
}
|
||||
|
||||
QString tailscale::DisplayType()
|
||||
{
|
||||
return "Tailscale";
|
||||
}
|
||||
|
||||
bool tailscale::IsEndpoint()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
68
src/configs/outbounds/trojan.cpp
Normal file
68
src/configs/outbounds/trojan.cpp
Normal file
@ -0,0 +1,68 @@
|
||||
#include "include/configs/outbounds/trojan.h"
|
||||
|
||||
#include <QUrlQuery>
|
||||
#include <include/global/Utils.hpp>
|
||||
|
||||
#include "include/configs/common/utils.h"
|
||||
|
||||
namespace Configs {
|
||||
bool Trojan::ParseFromLink(const QString& link)
|
||||
{
|
||||
auto url = QUrl(link);
|
||||
if (!url.isValid()) return false;
|
||||
|
||||
commons->ParseFromLink(link);
|
||||
password = url.userName();
|
||||
tls->ParseFromLink(link);
|
||||
transport->ParseFromLink(link);
|
||||
multiplex->ParseFromLink(link);
|
||||
return true;
|
||||
}
|
||||
bool Trojan::ParseFromJson(const QJsonObject& object)
|
||||
{
|
||||
if (object.isEmpty() || object["type"].toString() != "trojan") return false;
|
||||
commons->ParseFromJson(object);
|
||||
if (object.contains("password")) password = object["password"].toString();
|
||||
if (object.contains("tls")) tls->ParseFromJson(object["tls"].toObject());
|
||||
if (object.contains("transport")) transport->ParseFromJson(object["transport"].toObject());
|
||||
if (object.contains("multiplex")) multiplex->ParseFromJson(object["multiplex"].toObject());
|
||||
return true;
|
||||
}
|
||||
QString Trojan::ExportToLink()
|
||||
{
|
||||
QUrl url;
|
||||
QUrlQuery query;
|
||||
url.setHost(commons->server);
|
||||
url.setPort(commons->server_port);
|
||||
url.setScheme("trojan");
|
||||
if (!commons->name.isEmpty()) url.setFragment(commons->name);
|
||||
url.setUserName(password);
|
||||
if (tls->enabled) mergeUrlQuery(query, tls->ExportToLink());
|
||||
if (!transport->type.isEmpty()) mergeUrlQuery(query, transport->ExportToLink());
|
||||
if (multiplex->enabled) mergeUrlQuery(query, multiplex->ExportToLink());
|
||||
if (!query.isEmpty()) url.setQuery(query);
|
||||
return url.toString();
|
||||
}
|
||||
QJsonObject Trojan::ExportToJson()
|
||||
{
|
||||
QJsonObject object;
|
||||
object["type"] = "trojan";
|
||||
mergeJsonObjects(object, commons->ExportToJson());
|
||||
if (!password.isEmpty()) object["password"] = password;
|
||||
if (tls->enabled) object["tls"] = tls->ExportToJson();
|
||||
if (!transport->type.isEmpty()) object["transport"] = transport->ExportToJson();
|
||||
if (multiplex->enabled) object["multiplex"] = multiplex->ExportToJson();
|
||||
return object;
|
||||
}
|
||||
BuildResult Trojan::Build()
|
||||
{
|
||||
return {ExportToJson(), ""};
|
||||
}
|
||||
|
||||
QString Trojan::DisplayType()
|
||||
{
|
||||
return "Trojan";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
96
src/configs/outbounds/tuic.cpp
Normal file
96
src/configs/outbounds/tuic.cpp
Normal file
@ -0,0 +1,96 @@
|
||||
#include "include/configs/outbounds/tuic.h"
|
||||
|
||||
#include <QUrlQuery>
|
||||
#include <include/global/Utils.hpp>
|
||||
|
||||
#include "include/configs/common/utils.h"
|
||||
|
||||
namespace Configs {
|
||||
bool tuic::ParseFromLink(const QString& link)
|
||||
{
|
||||
auto url = QUrl(link);
|
||||
if (!url.isValid()) return false;
|
||||
auto query = QUrlQuery(url.query(QUrl::ComponentFormattingOption::FullyDecoded));
|
||||
|
||||
commons->ParseFromLink(link);
|
||||
uuid = url.userName();
|
||||
password = url.password();
|
||||
|
||||
if (query.hasQueryItem("congestion_control")) congestion_control = query.queryItemValue("congestion_control");
|
||||
if (query.hasQueryItem("udp_relay_mode")) udp_relay_mode = query.queryItemValue("udp_relay_mode");
|
||||
if (query.hasQueryItem("udp_over_stream")) udp_over_stream = query.queryItemValue("udp_over_stream") == "true";
|
||||
if (query.hasQueryItem("zero_rtt_handshake")) zero_rtt_handshake = query.queryItemValue("zero_rtt_handshake") == "true";
|
||||
if (query.hasQueryItem("heartbeat")) heartbeat = query.queryItemValue("heartbeat");
|
||||
|
||||
tls->ParseFromLink(link);
|
||||
|
||||
if (commons->server_port == 0) commons->server_port = 443;
|
||||
|
||||
return !(uuid.isEmpty() || password.isEmpty() || commons->server.isEmpty());
|
||||
}
|
||||
|
||||
bool tuic::ParseFromJson(const QJsonObject& object)
|
||||
{
|
||||
if (object.isEmpty() || object["type"].toString() != "tuic") return false;
|
||||
commons->ParseFromJson(object);
|
||||
if (object.contains("uuid")) uuid = object["uuid"].toString();
|
||||
if (object.contains("password")) password = object["password"].toString();
|
||||
if (object.contains("congestion_control")) congestion_control = object["congestion_control"].toString();
|
||||
if (object.contains("udp_relay_mode")) udp_relay_mode = object["udp_relay_mode"].toString();
|
||||
if (object.contains("udp_over_stream")) udp_over_stream = object["udp_over_stream"].toBool();
|
||||
if (object.contains("zero_rtt_handshake")) zero_rtt_handshake = object["zero_rtt_handshake"].toBool();
|
||||
if (object.contains("heartbeat")) heartbeat = object["heartbeat"].toString();
|
||||
if (object.contains("tls")) tls->ParseFromJson(object["tls"].toObject());
|
||||
return true;
|
||||
}
|
||||
|
||||
QString tuic::ExportToLink()
|
||||
{
|
||||
QUrl url;
|
||||
QUrlQuery query;
|
||||
url.setScheme("tuic");
|
||||
url.setUserName(uuid);
|
||||
url.setPassword(password);
|
||||
url.setHost(commons->server);
|
||||
url.setPort(commons->server_port);
|
||||
if (!commons->name.isEmpty()) url.setFragment(commons->name);
|
||||
|
||||
if (!congestion_control.isEmpty()) query.addQueryItem("congestion_control", congestion_control);
|
||||
if (!udp_relay_mode.isEmpty()) query.addQueryItem("udp_relay_mode", udp_relay_mode);
|
||||
if (udp_over_stream) query.addQueryItem("udp_over_stream", "true");
|
||||
if (zero_rtt_handshake) query.addQueryItem("zero_rtt_handshake", "true");
|
||||
if (!heartbeat.isEmpty()) query.addQueryItem("heartbeat", heartbeat);
|
||||
|
||||
mergeUrlQuery(query, tls->ExportToLink());
|
||||
mergeUrlQuery(query, commons->ExportToLink());
|
||||
|
||||
if (!query.isEmpty()) url.setQuery(query);
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
QJsonObject tuic::ExportToJson()
|
||||
{
|
||||
QJsonObject object;
|
||||
object["type"] = "tuic";
|
||||
mergeJsonObjects(object, commons->ExportToJson());
|
||||
if (!uuid.isEmpty()) object["uuid"] = uuid;
|
||||
if (!password.isEmpty()) object["password"] = password;
|
||||
if (!congestion_control.isEmpty()) object["congestion_control"] = congestion_control;
|
||||
if (!udp_relay_mode.isEmpty()) object["udp_relay_mode"] = udp_relay_mode;
|
||||
if (udp_over_stream) object["udp_over_stream"] = udp_over_stream;
|
||||
if (zero_rtt_handshake) object["zero_rtt_handshake"] = zero_rtt_handshake;
|
||||
if (!heartbeat.isEmpty()) object["heartbeat"] = heartbeat;
|
||||
if (tls->enabled) object["tls"] = tls->ExportToJson();
|
||||
return object;
|
||||
}
|
||||
|
||||
BuildResult tuic::Build()
|
||||
{
|
||||
return {ExportToJson(), ""};
|
||||
}
|
||||
|
||||
QString tuic::DisplayType()
|
||||
{
|
||||
return "TUIC";
|
||||
}
|
||||
}
|
||||
93
src/configs/outbounds/vless.cpp
Normal file
93
src/configs/outbounds/vless.cpp
Normal file
@ -0,0 +1,93 @@
|
||||
#include "include/configs/outbounds/vless.h"
|
||||
|
||||
#include <QUrlQuery>
|
||||
#include <include/global/Utils.hpp>
|
||||
|
||||
#include "include/configs/common/utils.h"
|
||||
|
||||
namespace Configs {
|
||||
bool vless::ParseFromLink(const QString& link)
|
||||
{
|
||||
auto url = QUrl(link);
|
||||
if (!url.isValid()) return false;
|
||||
auto query = QUrlQuery(url.query(QUrl::ComponentFormattingOption::FullyDecoded));
|
||||
|
||||
commons->ParseFromLink(link);
|
||||
uuid = url.userName();
|
||||
if (commons->server_port == 0) commons->server_port = 443;
|
||||
|
||||
flow = GetQueryValue(query, "flow", "");
|
||||
|
||||
transport->ParseFromLink(link);
|
||||
|
||||
tls->ParseFromLink(link);
|
||||
if (!tls->server_name.isEmpty()) {
|
||||
tls->enabled = true;
|
||||
}
|
||||
|
||||
packet_encoding = GetQueryValue(query, "packetEncoding", "");
|
||||
multiplex->ParseFromLink(link);
|
||||
|
||||
return !(uuid.isEmpty() || commons->server.isEmpty());
|
||||
}
|
||||
|
||||
bool vless::ParseFromJson(const QJsonObject& object)
|
||||
{
|
||||
if (object.isEmpty() || object["type"].toString() != "vless") return false;
|
||||
commons->ParseFromJson(object);
|
||||
if (object.contains("uuid")) uuid = object["uuid"].toString();
|
||||
if (object.contains("flow")) flow = object["flow"].toString();
|
||||
if (object.contains("packet_encoding")) packet_encoding = object["packet_encoding"].toString();
|
||||
if (object.contains("tls")) tls->ParseFromJson(object["tls"].toObject());
|
||||
if (object.contains("transport")) transport->ParseFromJson(object["transport"].toObject());
|
||||
if (object.contains("multiplex")) multiplex->ParseFromJson(object["multiplex"].toObject());
|
||||
return true;
|
||||
}
|
||||
|
||||
QString vless::ExportToLink()
|
||||
{
|
||||
QUrl url;
|
||||
QUrlQuery query;
|
||||
url.setScheme("vless");
|
||||
url.setUserName(uuid);
|
||||
url.setHost(commons->server);
|
||||
url.setPort(commons->server_port);
|
||||
if (!commons->name.isEmpty()) url.setFragment(commons->name);
|
||||
|
||||
query.addQueryItem("encryption", "none");
|
||||
if (!flow.isEmpty()) query.addQueryItem("flow", flow);
|
||||
|
||||
mergeUrlQuery(query, tls->ExportToLink());
|
||||
mergeUrlQuery(query, transport->ExportToLink());
|
||||
mergeUrlQuery(query, multiplex->ExportToLink());
|
||||
|
||||
if (!packet_encoding.isEmpty()) query.addQueryItem("packetEncoding", packet_encoding);
|
||||
|
||||
if (!query.isEmpty()) url.setQuery(query);
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
QJsonObject vless::ExportToJson()
|
||||
{
|
||||
QJsonObject object;
|
||||
object["type"] = "vless";
|
||||
mergeJsonObjects(object, commons->ExportToJson());
|
||||
if (!uuid.isEmpty()) object["uuid"] = uuid;
|
||||
if (!flow.isEmpty()) object["flow"] = flow;
|
||||
if (!packet_encoding.isEmpty()) object["packet_encoding"] = packet_encoding;
|
||||
if (tls->enabled) object["tls"] = tls->ExportToJson();
|
||||
if (!transport->type.isEmpty()) object["transport"] = transport->ExportToJson();
|
||||
if (multiplex->enabled) object["multiplex"] = multiplex->ExportToJson();
|
||||
return object;
|
||||
}
|
||||
|
||||
BuildResult vless::Build()
|
||||
{
|
||||
return {ExportToJson(), ""};
|
||||
}
|
||||
|
||||
QString vless::DisplayType()
|
||||
{
|
||||
return "VLESS";
|
||||
}
|
||||
}
|
||||
138
src/configs/outbounds/vmess.cpp
Normal file
138
src/configs/outbounds/vmess.cpp
Normal file
@ -0,0 +1,138 @@
|
||||
#include "include/configs/outbounds/vmess.h"
|
||||
|
||||
#include <QUrlQuery>
|
||||
#include <include/global/Utils.hpp>
|
||||
|
||||
#include "include/configs/common/utils.h"
|
||||
|
||||
namespace Configs {
|
||||
bool vmess::ParseFromLink(const QString& link)
|
||||
{
|
||||
// Try V2RayN format first (base64 encoded JSON)
|
||||
QString linkN = DecodeB64IfValid(SubStrAfter(link, "vmess://"));
|
||||
if (!linkN.isEmpty()) {
|
||||
auto objN = QString2QJsonObject(linkN);
|
||||
if (!objN.isEmpty()) {
|
||||
uuid = objN["id"].toString();
|
||||
commons->server = objN["add"].toString();
|
||||
commons->server_port = objN["port"].toVariant().toInt();
|
||||
commons->name = objN["ps"].toString();
|
||||
alter_id = objN["aid"].toVariant().toInt();
|
||||
|
||||
QString net = objN["net"].toString();
|
||||
if (net == "h2") net = "http";
|
||||
transport->type = net;
|
||||
transport->host = objN["host"].toString();
|
||||
transport->path = objN["path"].toString();
|
||||
|
||||
QString scy = objN["scy"].toString();
|
||||
if (!scy.isEmpty()) security = scy;
|
||||
|
||||
QString tlsStr = objN["tls"].toString();
|
||||
if (tlsStr == "tls") {
|
||||
tls->enabled = true;
|
||||
tls->server_name = objN["sni"].toString();
|
||||
}
|
||||
|
||||
return !(uuid.isEmpty() || commons->server.isEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
// Standard VMess URL format
|
||||
auto url = QUrl(link);
|
||||
if (!url.isValid()) return false;
|
||||
auto query = QUrlQuery(url.query(QUrl::ComponentFormattingOption::FullyDecoded));
|
||||
|
||||
commons->ParseFromLink(link);
|
||||
uuid = url.userName();
|
||||
if (commons->server_port == 0) commons->server_port = 443;
|
||||
|
||||
security = GetQueryValue(query, "encryption", "auto");
|
||||
|
||||
transport->ParseFromLink(link);
|
||||
|
||||
tls->ParseFromLink(link);
|
||||
if (!tls->server_name.isEmpty()) {
|
||||
tls->enabled = true;
|
||||
}
|
||||
|
||||
multiplex->ParseFromLink(link);
|
||||
|
||||
if (query.hasQueryItem("alterId")) alter_id = query.queryItemValue("alterId").toInt();
|
||||
if (query.hasQueryItem("globalPadding")) global_padding = query.queryItemValue("globalPadding") == "true";
|
||||
if (query.hasQueryItem("authenticatedLength")) authenticated_length = query.queryItemValue("authenticatedLength") == "true";
|
||||
if (query.hasQueryItem("packetEncoding")) packet_encoding = query.queryItemValue("packetEncoding");
|
||||
|
||||
return !(uuid.isEmpty() || commons->server.isEmpty());
|
||||
}
|
||||
|
||||
bool vmess::ParseFromJson(const QJsonObject& object)
|
||||
{
|
||||
if (object.isEmpty() || object["type"].toString() != "vmess") return false;
|
||||
commons->ParseFromJson(object);
|
||||
if (object.contains("uuid")) uuid = object["uuid"].toString();
|
||||
if (object.contains("security")) security = object["security"].toString();
|
||||
if (object.contains("alter_id")) alter_id = object["alter_id"].toInt();
|
||||
if (object.contains("alter-id")) alter_id = object["alter-id"].toInt();
|
||||
if (object.contains("global_padding")) global_padding = object["global_padding"].toBool();
|
||||
if (object.contains("global-padding")) global_padding = object["global-padding"].toBool();
|
||||
if (object.contains("authenticated_length")) authenticated_length = object["authenticated_length"].toBool();
|
||||
if (object.contains("packet_encoding")) packet_encoding = object["packet_encoding"].toString();
|
||||
if (object.contains("tls")) tls->ParseFromJson(object["tls"].toObject());
|
||||
if (object.contains("transport")) transport->ParseFromJson(object["transport"].toObject());
|
||||
if (object.contains("multiplex")) multiplex->ParseFromJson(object["multiplex"].toObject());
|
||||
return true;
|
||||
}
|
||||
|
||||
QString vmess::ExportToLink()
|
||||
{
|
||||
QUrl url;
|
||||
QUrlQuery query;
|
||||
url.setScheme("vmess");
|
||||
url.setUserName(uuid);
|
||||
url.setHost(commons->server);
|
||||
url.setPort(commons->server_port);
|
||||
if (!commons->name.isEmpty()) url.setFragment(commons->name);
|
||||
|
||||
if (security != "auto") query.addQueryItem("encryption", security);
|
||||
|
||||
mergeUrlQuery(query, tls->ExportToLink());
|
||||
mergeUrlQuery(query, transport->ExportToLink());
|
||||
mergeUrlQuery(query, multiplex->ExportToLink());
|
||||
|
||||
if (alter_id > 0) query.addQueryItem("alterId", QString::number(alter_id));
|
||||
if (global_padding) query.addQueryItem("globalPadding", "true");
|
||||
if (authenticated_length) query.addQueryItem("authenticatedLength", "true");
|
||||
if (!packet_encoding.isEmpty()) query.addQueryItem("packetEncoding", packet_encoding);
|
||||
|
||||
if (!query.isEmpty()) url.setQuery(query);
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
QJsonObject vmess::ExportToJson()
|
||||
{
|
||||
QJsonObject object;
|
||||
object["type"] = "vmess";
|
||||
mergeJsonObjects(object, commons->ExportToJson());
|
||||
if (!uuid.isEmpty()) object["uuid"] = uuid;
|
||||
if (security != "auto") object["security"] = security;
|
||||
if (alter_id > 0) object["alter_id"] = alter_id;
|
||||
if (global_padding) object["global_padding"] = global_padding;
|
||||
if (authenticated_length) object["authenticated_length"] = authenticated_length;
|
||||
if (!packet_encoding.isEmpty()) object["packet_encoding"] = packet_encoding;
|
||||
if (tls->enabled) object["tls"] = tls->ExportToJson();
|
||||
if (!transport->type.isEmpty()) object["transport"] = transport->ExportToJson();
|
||||
if (multiplex->enabled) object["multiplex"] = multiplex->ExportToJson();
|
||||
return object;
|
||||
}
|
||||
|
||||
BuildResult vmess::Build()
|
||||
{
|
||||
return {ExportToJson(), ""};
|
||||
}
|
||||
|
||||
QString vmess::DisplayType()
|
||||
{
|
||||
return "VMess";
|
||||
}
|
||||
}
|
||||
254
src/configs/outbounds/wireguard.cpp
Normal file
254
src/configs/outbounds/wireguard.cpp
Normal file
@ -0,0 +1,254 @@
|
||||
#include "include/configs/outbounds/wireguard.h"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QUrlQuery>
|
||||
#include <include/global/Utils.hpp>
|
||||
|
||||
#include "include/configs/common/utils.h"
|
||||
|
||||
namespace Configs {
|
||||
bool Peer::ParseFromLink(const QString& link)
|
||||
{
|
||||
auto url = QUrl(link);
|
||||
if (!url.isValid()) return false;
|
||||
auto query = QUrlQuery(url.query(QUrl::ComponentFormattingOption::FullyDecoded));
|
||||
|
||||
if (query.hasQueryItem("address")) address = query.queryItemValue("address");
|
||||
if (query.hasQueryItem("port")) port = query.queryItemValue("port").toInt();
|
||||
if (query.hasQueryItem("public_key")) public_key = query.queryItemValue("public_key");
|
||||
if (query.hasQueryItem("peer_public_key")) public_key = query.queryItemValue("peer_public_key");
|
||||
if (query.hasQueryItem("pre_shared_key")) pre_shared_key = query.queryItemValue("pre_shared_key");
|
||||
if (query.hasQueryItem("reserved")) {
|
||||
QString rawReserved = query.queryItemValue("reserved");
|
||||
if (!rawReserved.isEmpty()) {
|
||||
for (const auto& item : rawReserved.split("-")) {
|
||||
int val = item.toInt();
|
||||
if (val > 0) reserved.append(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (query.hasQueryItem("persistent_keepalive")) persistent_keepalive = query.queryItemValue("persistent_keepalive").toInt();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Peer::ParseFromJson(const QJsonObject& object)
|
||||
{
|
||||
if (object.isEmpty()) return false;
|
||||
if (object.contains("address")) address = object["address"].toString();
|
||||
if (object.contains("port")) port = object["port"].toInt();
|
||||
if (object.contains("public_key")) public_key = object["public_key"].toString();
|
||||
if (object.contains("pre_shared_key")) pre_shared_key = object["pre_shared_key"].toString();
|
||||
if (object.contains("reserved")) {
|
||||
reserved = QJsonArray2QListInt(object["reserved"].toArray());
|
||||
}
|
||||
if (object.contains("persistent_keepalive")) persistent_keepalive = object["persistent_keepalive"].toInt();
|
||||
return true;
|
||||
}
|
||||
|
||||
QString Peer::ExportToLink()
|
||||
{
|
||||
QUrlQuery query;
|
||||
if (!address.isEmpty()) query.addQueryItem("address", address);
|
||||
if (port > 0) query.addQueryItem("port", QString::number(port));
|
||||
if (!public_key.isEmpty()) query.addQueryItem("public_key", public_key);
|
||||
if (!pre_shared_key.isEmpty()) query.addQueryItem("pre_shared_key", pre_shared_key);
|
||||
if (!reserved.isEmpty()) {
|
||||
QStringList reservedStr;
|
||||
for (auto val : reserved) {
|
||||
reservedStr.append(QString::number(val));
|
||||
}
|
||||
query.addQueryItem("reserved", reservedStr.join("-"));
|
||||
}
|
||||
if (persistent_keepalive > 0) query.addQueryItem("persistent_keepalive", QString::number(persistent_keepalive));
|
||||
return query.toString();
|
||||
}
|
||||
|
||||
QJsonObject Peer::ExportToJson()
|
||||
{
|
||||
QJsonObject object;
|
||||
if (!address.isEmpty()) object["address"] = address;
|
||||
if (port > 0) object["port"] = port;
|
||||
if (!public_key.isEmpty()) object["public_key"] = public_key;
|
||||
if (!pre_shared_key.isEmpty()) object["pre_shared_key"] = pre_shared_key;
|
||||
if (!reserved.isEmpty()) object["reserved"] = QListInt2QJsonArray(reserved);
|
||||
if (persistent_keepalive > 0) object["persistent_keepalive"] = persistent_keepalive;
|
||||
return object;
|
||||
}
|
||||
|
||||
BuildResult Peer::Build()
|
||||
{
|
||||
return {ExportToJson(), ""};
|
||||
}
|
||||
|
||||
bool wireguard::ParseFromLink(const QString& link)
|
||||
{
|
||||
// Try WireGuard config file format first
|
||||
if (link.contains("[Interface]") && link.contains("[Peer]")) {
|
||||
auto lines = link.split("\n");
|
||||
for (const auto& line : lines) {
|
||||
QString trimmed = line.trimmed();
|
||||
if (trimmed.isEmpty()) continue;
|
||||
if (trimmed == "[Peer]" || trimmed == "[Interface]") {
|
||||
continue;
|
||||
}
|
||||
if (!trimmed.contains("=")) continue;
|
||||
auto eqIdx = trimmed.indexOf("=");
|
||||
QString key = trimmed.left(eqIdx).trimmed();
|
||||
QString value = trimmed.mid(eqIdx + 1).trimmed();
|
||||
|
||||
if (key == "PrivateKey") private_key = value;
|
||||
if (key == "Address") address = value.split(",");
|
||||
if (key == "MTU") mtu = value.toInt();
|
||||
if (key == "PublicKey") peer->public_key = value;
|
||||
if (key == "PresharedKey") peer->pre_shared_key = value;
|
||||
if (key == "PersistentKeepalive") peer->persistent_keepalive = value.toInt();
|
||||
if (key == "Endpoint") {
|
||||
QStringList parts = value.split(":");
|
||||
if (parts.size() >= 2) {
|
||||
peer->address = parts[0].trimmed();
|
||||
peer->port = parts.last().trimmed().toInt();
|
||||
commons->server = peer->address;
|
||||
commons->server_port = peer->port;
|
||||
}
|
||||
}
|
||||
if (key == "S1") enable_amnezia = true, init_packet_junk_size = value.toInt();
|
||||
if (key == "S2") enable_amnezia = true, response_packet_junk_size = value.toInt();
|
||||
if (key == "Jc") enable_amnezia = true, junk_packet_count = value.toInt();
|
||||
if (key == "Jmin") enable_amnezia = true, junk_packet_min_size = value.toInt();
|
||||
if (key == "Jmax") enable_amnezia = true, junk_packet_max_size = value.toInt();
|
||||
if (key == "H1") enable_amnezia = true, init_packet_magic_header = value.toInt();
|
||||
if (key == "H2") enable_amnezia = true, response_packet_magic_header = value.toInt();
|
||||
if (key == "H3") enable_amnezia = true, underload_packet_magic_header = value.toInt();
|
||||
if (key == "H4") enable_amnezia = true, transport_packet_magic_header = value.toInt();
|
||||
}
|
||||
return !private_key.isEmpty() && !peer->public_key.isEmpty();
|
||||
}
|
||||
|
||||
// Standard wg:// URL format
|
||||
auto url = QUrl(link);
|
||||
if (!url.isValid()) return false;
|
||||
auto query = QUrlQuery(url.query(QUrl::ComponentFormattingOption::FullyDecoded));
|
||||
|
||||
commons->ParseFromLink(link);
|
||||
|
||||
if (query.hasQueryItem("private_key")) private_key = query.queryItemValue("private_key");
|
||||
peer->ParseFromLink(link);
|
||||
|
||||
QString rawLocalAddr = query.queryItemValue("local_address");
|
||||
if (!rawLocalAddr.isEmpty()) {
|
||||
address = rawLocalAddr.split("-");
|
||||
}
|
||||
|
||||
if (query.hasQueryItem("mtu")) mtu = query.queryItemValue("mtu").toInt();
|
||||
if (query.hasQueryItem("use_system_interface")) system = query.queryItemValue("use_system_interface") == "true";
|
||||
if (query.hasQueryItem("workers")) worker_count = query.queryItemValue("workers").toInt();
|
||||
if (query.hasQueryItem("udp_timeout")) udp_timeout = query.queryItemValue("udp_timeout");
|
||||
|
||||
enable_amnezia = query.queryItemValue("enable_amnezia") == "true";
|
||||
if (enable_amnezia) {
|
||||
if (query.hasQueryItem("junk_packet_count")) junk_packet_count = query.queryItemValue("junk_packet_count").toInt();
|
||||
if (query.hasQueryItem("junk_packet_min_size")) junk_packet_min_size = query.queryItemValue("junk_packet_min_size").toInt();
|
||||
if (query.hasQueryItem("junk_packet_max_size")) junk_packet_max_size = query.queryItemValue("junk_packet_max_size").toInt();
|
||||
if (query.hasQueryItem("init_packet_junk_size")) init_packet_junk_size = query.queryItemValue("init_packet_junk_size").toInt();
|
||||
if (query.hasQueryItem("response_packet_junk_size")) response_packet_junk_size = query.queryItemValue("response_packet_junk_size").toInt();
|
||||
if (query.hasQueryItem("init_packet_magic_header")) init_packet_magic_header = query.queryItemValue("init_packet_magic_header").toInt();
|
||||
if (query.hasQueryItem("response_packet_magic_header")) response_packet_magic_header = query.queryItemValue("response_packet_magic_header").toInt();
|
||||
if (query.hasQueryItem("underload_packet_magic_header")) underload_packet_magic_header = query.queryItemValue("underload_packet_magic_header").toInt();
|
||||
if (query.hasQueryItem("transport_packet_magic_header")) transport_packet_magic_header = query.queryItemValue("transport_packet_magic_header").toInt();
|
||||
}
|
||||
|
||||
return !(private_key.isEmpty() || peer->public_key.isEmpty() || commons->server.isEmpty());
|
||||
}
|
||||
|
||||
bool wireguard::ParseFromJson(const QJsonObject& object)
|
||||
{
|
||||
if (object.isEmpty() || object["type"].toString() != "wireguard") return false;
|
||||
commons->ParseFromJson(object);
|
||||
if (object.contains("private_key")) private_key = object["private_key"].toString();
|
||||
if (object.contains("peer") && object["peer"].isObject()) peer->ParseFromJson(object["peer"].toObject());
|
||||
if (object.contains("address")) address = QJsonArray2QListString(object["address"].toArray());
|
||||
if (object.contains("mtu")) mtu = object["mtu"].toInt();
|
||||
if (object.contains("system")) system = object["system"].toBool();
|
||||
if (object.contains("worker_count")) worker_count = object["worker_count"].toInt();
|
||||
if (object.contains("udp_timeout")) udp_timeout = object["udp_timeout"].toString();
|
||||
return true;
|
||||
}
|
||||
|
||||
QString wireguard::ExportToLink()
|
||||
{
|
||||
QUrl url;
|
||||
QUrlQuery query;
|
||||
url.setScheme("wg");
|
||||
url.setHost(peer->address);
|
||||
url.setPort(peer->port);
|
||||
if (!commons->name.isEmpty()) url.setFragment(commons->name);
|
||||
|
||||
if (!private_key.isEmpty()) query.addQueryItem("private_key", private_key);
|
||||
|
||||
if (!address.isEmpty()) query.addQueryItem("local_address", address.join("-"));
|
||||
if (mtu > 0 && mtu != 1420) query.addQueryItem("mtu", QString::number(mtu));
|
||||
if (system) query.addQueryItem("use_system_interface", "true");
|
||||
if (worker_count > 0) query.addQueryItem("workers", QString::number(worker_count));
|
||||
if (!udp_timeout.isEmpty()) query.addQueryItem("udp_timeout", udp_timeout);
|
||||
|
||||
if (enable_amnezia) {
|
||||
query.addQueryItem("enable_amnezia", "true");
|
||||
if (junk_packet_count > 0) query.addQueryItem("junk_packet_count", QString::number(junk_packet_count));
|
||||
if (junk_packet_min_size > 0) query.addQueryItem("junk_packet_min_size", QString::number(junk_packet_min_size));
|
||||
if (junk_packet_max_size > 0) query.addQueryItem("junk_packet_max_size", QString::number(junk_packet_max_size));
|
||||
if (init_packet_junk_size > 0) query.addQueryItem("init_packet_junk_size", QString::number(init_packet_junk_size));
|
||||
if (response_packet_junk_size > 0) query.addQueryItem("response_packet_junk_size", QString::number(response_packet_junk_size));
|
||||
if (init_packet_magic_header > 0) query.addQueryItem("init_packet_magic_header", QString::number(init_packet_magic_header));
|
||||
if (response_packet_magic_header > 0) query.addQueryItem("response_packet_magic_header", QString::number(response_packet_magic_header));
|
||||
if (underload_packet_magic_header > 0) query.addQueryItem("underload_packet_magic_header", QString::number(underload_packet_magic_header));
|
||||
if (transport_packet_magic_header > 0) query.addQueryItem("transport_packet_magic_header", QString::number(transport_packet_magic_header));
|
||||
}
|
||||
|
||||
mergeUrlQuery(query, commons->ExportToLink());
|
||||
mergeUrlQuery(query, peer->ExportToLink());
|
||||
|
||||
if (!query.isEmpty()) url.setQuery(query);
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
QJsonObject wireguard::ExportToJson()
|
||||
{
|
||||
QJsonObject object;
|
||||
object["type"] = "wireguard";
|
||||
mergeJsonObjects(object, commons->ExportToJson());
|
||||
if (!private_key.isEmpty()) object["private_key"] = private_key;
|
||||
if (!address.isEmpty()) object["address"] = QListStr2QJsonArray(address);
|
||||
if (mtu > 0) object["mtu"] = mtu;
|
||||
if (system) object["system"] = system;
|
||||
if (worker_count > 0) object["worker_count"] = worker_count;
|
||||
if (!udp_timeout.isEmpty()) object["udp_timeout"] = udp_timeout;
|
||||
|
||||
auto peerObj = peer->ExportToJson();
|
||||
if (!peerObj.isEmpty()) {
|
||||
object["peer"] = QJsonArray({peerObj});
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
BuildResult wireguard::Build()
|
||||
{
|
||||
return {ExportToJson(), ""};
|
||||
}
|
||||
|
||||
QString wireguard::DisplayAddress()
|
||||
{
|
||||
return ::DisplayAddress(peer->address, peer->port > 0);
|
||||
}
|
||||
|
||||
QString wireguard::DisplayType()
|
||||
{
|
||||
return "WireGuard";
|
||||
}
|
||||
|
||||
bool wireguard::IsEndpoint()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -308,8 +308,8 @@ namespace Configs {
|
||||
return false;
|
||||
serverPort = 0;
|
||||
serverPorts = QString::fromStdString(URLParser::Parse((link.split("?")[0] + "/").toStdString()).port).split(",");
|
||||
for (int i=0; i < serverPorts.size(); i++) {
|
||||
serverPorts[i].replace("-", ":");
|
||||
for (auto & serverPort : serverPorts) {
|
||||
serverPort.replace("-", ":");
|
||||
}
|
||||
}
|
||||
auto query = QUrlQuery(url.query());
|
||||
|
||||
Loading…
Reference in New Issue
Block a user