nekoray_Mahdi-zarei/src/configs/common/TLS.cpp
Nova b2d917679f Add advanced options &&
Fix some bugs
2025-11-21 23:44:08 +03:30

312 lines
15 KiB
C++

#include "include/configs/common/TLS.h"
#include <QJsonArray>
#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
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()
{
auto obj = ExportToJson();
if ((obj.isEmpty() || obj["enabled"].toBool() == false) && !dataStore->utlsFingerprint.isEmpty()) {
obj["enabled"] = true;
obj["fingerprint"] = dataStore->utlsFingerprint;
}
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()
{
QJsonObject object;
if (!public_key.isEmpty() || enabled) {
object["enabled"] = true;
object["public_key"] = public_key;
if (!short_id.isEmpty()) object["short_id"] = short_id;
}
return {object, ""};
}
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", "")
.replace("0", "")
.replace("false", "tls")
.replace("1", "tls")
.replace("true", "tls") == "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").split(",");
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").split(",");
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";
if (!server_name.isEmpty()) enabled = 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")) {
if (object["certificate"].isString()) {
certificate = object["certificate"].toString().split("\n", Qt::SkipEmptyParts);
} else {
certificate = QJsonArray2QListString(object["certificate"].toArray());
}
}
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 = QJsonArray2QListString(object["client_certificate"].toArray());
}
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.join(","));
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.join(","));
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"] = QListStr2QJsonArray(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"] = QListStr2QJsonArray(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()
{
auto obj = ExportToJson();
if (!obj.isEmpty() && obj["enabled"].toBool()) {
if (dataStore->skip_cert) obj["insecure"] = true;
}
return {ExportToJson(), ""};
}
}