Files
amnezia-client/client/core/models/protocols/xrayProtocolConfig.cpp
T
2026-06-17 15:31:11 +03:00

642 lines
26 KiB
C++

#include "xrayProtocolConfig.h"
#include <QJsonDocument>
#include <QJsonArray>
#include "core/utils/protocolEnum.h"
#include "core/protocols/protocolUtils.h"
#include "core/utils/constants/configKeys.h"
#include "core/utils/constants/protocolConstants.h"
using namespace amnezia;
using namespace ProtocolUtils;
namespace amnezia
{
QJsonObject XrayXPaddingConfig::toJson() const
{
QJsonObject obj;
if (!bytesMin.isEmpty()) obj[configKey::xPaddingBytesMin] = bytesMin;
if (!bytesMax.isEmpty()) obj[configKey::xPaddingBytesMax] = bytesMax;
obj[configKey::xPaddingObfsMode] = obfsMode;
if (!key.isEmpty()) obj[configKey::xPaddingKey] = key;
if (!header.isEmpty()) obj[configKey::xPaddingHeader] = header;
if (!placement.isEmpty()) obj[configKey::xPaddingPlacement] = placement;
if (!method.isEmpty()) obj[configKey::xPaddingMethod] = method;
return obj;
}
XrayXPaddingConfig XrayXPaddingConfig::fromJson(const QJsonObject &json)
{
XrayXPaddingConfig c;
c.bytesMin = json.value(configKey::xPaddingBytesMin).toString();
c.bytesMax = json.value(configKey::xPaddingBytesMax).toString();
c.obfsMode = json.value(configKey::xPaddingObfsMode).toBool(true);
c.key = json.value(configKey::xPaddingKey).toString();
c.header = json.value(configKey::xPaddingHeader).toString();
c.placement = json.value(configKey::xPaddingPlacement).toString(protocols::xray::defaultXPaddingPlacement);
c.method = json.value(configKey::xPaddingMethod).toString(protocols::xray::defaultXPaddingMethod);
return c;
}
QJsonObject XrayXmuxConfig::toJson() const
{
QJsonObject obj;
obj[configKey::xmuxEnabled] = enabled;
if (!maxConcurrencyMin.isEmpty()) obj[configKey::xmuxMaxConcurrencyMin] = maxConcurrencyMin;
if (!maxConcurrencyMax.isEmpty()) obj[configKey::xmuxMaxConcurrencyMax] = maxConcurrencyMax;
if (!maxConnectionsMin.isEmpty()) obj[configKey::xmuxMaxConnectionsMin] = maxConnectionsMin;
if (!maxConnectionsMax.isEmpty()) obj[configKey::xmuxMaxConnectionsMax] = maxConnectionsMax;
if (!cMaxReuseTimesMin.isEmpty()) obj[configKey::xmuxCMaxReuseTimesMin] = cMaxReuseTimesMin;
if (!cMaxReuseTimesMax.isEmpty()) obj[configKey::xmuxCMaxReuseTimesMax] = cMaxReuseTimesMax;
if (!hMaxRequestTimesMin.isEmpty()) obj[configKey::xmuxHMaxRequestTimesMin] = hMaxRequestTimesMin;
if (!hMaxRequestTimesMax.isEmpty()) obj[configKey::xmuxHMaxRequestTimesMax] = hMaxRequestTimesMax;
if (!hMaxReusableSecsMin.isEmpty()) obj[configKey::xmuxHMaxReusableSecsMin] = hMaxReusableSecsMin;
if (!hMaxReusableSecsMax.isEmpty()) obj[configKey::xmuxHMaxReusableSecsMax] = hMaxReusableSecsMax;
if (!hKeepAlivePeriod.isEmpty()) obj[configKey::xmuxHKeepAlivePeriod] = hKeepAlivePeriod;
return obj;
}
XrayXmuxConfig XrayXmuxConfig::fromJson(const QJsonObject &json)
{
XrayXmuxConfig c;
c.enabled = json.value(configKey::xmuxEnabled).toBool(true);
c.maxConcurrencyMin = json.value(configKey::xmuxMaxConcurrencyMin).toString("0");
c.maxConcurrencyMax = json.value(configKey::xmuxMaxConcurrencyMax).toString("0");
c.maxConnectionsMin = json.value(configKey::xmuxMaxConnectionsMin).toString("0");
c.maxConnectionsMax = json.value(configKey::xmuxMaxConnectionsMax).toString("0");
c.cMaxReuseTimesMin = json.value(configKey::xmuxCMaxReuseTimesMin).toString("0");
c.cMaxReuseTimesMax = json.value(configKey::xmuxCMaxReuseTimesMax).toString("0");
c.hMaxRequestTimesMin = json.value(configKey::xmuxHMaxRequestTimesMin).toString("0");
c.hMaxRequestTimesMax = json.value(configKey::xmuxHMaxRequestTimesMax).toString("0");
c.hMaxReusableSecsMin = json.value(configKey::xmuxHMaxReusableSecsMin).toString("0");
c.hMaxReusableSecsMax = json.value(configKey::xmuxHMaxReusableSecsMax).toString("0");
c.hKeepAlivePeriod = json.value(configKey::xmuxHKeepAlivePeriod).toString();
return c;
}
QJsonObject XrayXhttpConfig::toJson() const
{
QJsonObject obj;
if (!mode.isEmpty()) obj[configKey::xhttpMode] = mode;
if (!host.isEmpty()) obj[configKey::xhttpHost] = host;
if (!path.isEmpty()) obj[configKey::xhttpPath] = path;
if (!headersTemplate.isEmpty()) obj[configKey::xhttpHeadersTemplate] = headersTemplate;
if (!uplinkMethod.isEmpty()) obj[configKey::xhttpUplinkMethod] = uplinkMethod;
obj[configKey::xhttpDisableGrpc] = disableGrpc;
obj[configKey::xhttpDisableSse] = disableSse;
if (!sessionPlacement.isEmpty()) obj[configKey::xhttpSessionPlacement] = sessionPlacement;
if (!sessionKey.isEmpty()) obj[configKey::xhttpSessionKey] = sessionKey;
if (!seqPlacement.isEmpty()) obj[configKey::xhttpSeqPlacement] = seqPlacement;
if (!seqKey.isEmpty()) obj[configKey::xhttpSeqKey] = seqKey;
if (!uplinkDataPlacement.isEmpty()) obj[configKey::xhttpUplinkDataPlacement] = uplinkDataPlacement;
if (!uplinkDataKey.isEmpty()) obj[configKey::xhttpUplinkDataKey] = uplinkDataKey;
if (!uplinkChunkSize.isEmpty()) obj[configKey::xhttpUplinkChunkSize] = uplinkChunkSize;
if (!scMaxBufferedPosts.isEmpty()) obj[configKey::xhttpScMaxBufferedPosts] = scMaxBufferedPosts;
if (!scMaxEachPostBytesMin.isEmpty()) obj[configKey::xhttpScMaxEachPostBytesMin] = scMaxEachPostBytesMin;
if (!scMaxEachPostBytesMax.isEmpty()) obj[configKey::xhttpScMaxEachPostBytesMax] = scMaxEachPostBytesMax;
if (!scMinPostsIntervalMsMin.isEmpty()) obj[configKey::xhttpScMinPostsIntervalMsMin] = scMinPostsIntervalMsMin;
if (!scMinPostsIntervalMsMax.isEmpty()) obj[configKey::xhttpScMinPostsIntervalMsMax] = scMinPostsIntervalMsMax;
if (!scStreamUpServerSecsMin.isEmpty()) obj[configKey::xhttpScStreamUpServerSecsMin] = scStreamUpServerSecsMin;
if (!scStreamUpServerSecsMax.isEmpty()) obj[configKey::xhttpScStreamUpServerSecsMax] = scStreamUpServerSecsMax;
obj["xPadding"] = xPadding.toJson();
obj["xmux"] = xmux.toJson();
return obj;
}
namespace
{
XrayXhttpConfig clearedXhttpConfig()
{
XrayXhttpConfig c;
c.mode = QString();
c.host = QString();
c.path = QString();
c.headersTemplate = QString();
c.uplinkMethod = QString();
c.disableGrpc = false;
c.disableSse = false;
c.sessionPlacement = QString();
c.sessionKey = QString();
c.seqPlacement = QString();
c.seqKey = QString();
c.uplinkDataPlacement = QString();
c.uplinkDataKey = QString();
c.uplinkChunkSize = QString();
c.scMaxBufferedPosts = QString();
c.scMaxEachPostBytesMin = QString();
c.scMaxEachPostBytesMax = QString();
c.scMinPostsIntervalMsMin = QString();
c.scMinPostsIntervalMsMax = QString();
c.scStreamUpServerSecsMin = QString();
c.scStreamUpServerSecsMax = QString();
return c;
}
} // namespace
XrayXhttpConfig XrayXhttpConfig::fromJson(const QJsonObject &json)
{
if (json.isEmpty()) {
return clearedXhttpConfig();
}
XrayXhttpConfig c = clearedXhttpConfig();
if (json.contains(configKey::xhttpMode)) {
c.mode = json.value(configKey::xhttpMode).toString();
}
if (json.contains(configKey::xhttpHost)) {
c.host = json.value(configKey::xhttpHost).toString();
}
if (json.contains(configKey::xhttpPath)) {
c.path = json.value(configKey::xhttpPath).toString();
}
if (json.contains(configKey::xhttpHeadersTemplate)) {
c.headersTemplate = json.value(configKey::xhttpHeadersTemplate).toString();
}
if (json.contains(configKey::xhttpUplinkMethod)) {
c.uplinkMethod = json.value(configKey::xhttpUplinkMethod).toString();
}
if (json.contains(configKey::xhttpDisableGrpc)) {
c.disableGrpc = json.value(configKey::xhttpDisableGrpc).toBool();
}
if (json.contains(configKey::xhttpDisableSse)) {
c.disableSse = json.value(configKey::xhttpDisableSse).toBool();
}
if (json.contains(configKey::xhttpSessionPlacement)) {
c.sessionPlacement = json.value(configKey::xhttpSessionPlacement).toString();
}
if (json.contains(configKey::xhttpSessionKey)) {
c.sessionKey = json.value(configKey::xhttpSessionKey).toString();
}
if (json.contains(configKey::xhttpSeqPlacement)) {
c.seqPlacement = json.value(configKey::xhttpSeqPlacement).toString();
}
if (json.contains(configKey::xhttpSeqKey)) {
c.seqKey = json.value(configKey::xhttpSeqKey).toString();
}
if (json.contains(configKey::xhttpUplinkDataPlacement)) {
c.uplinkDataPlacement = json.value(configKey::xhttpUplinkDataPlacement).toString();
}
if (json.contains(configKey::xhttpUplinkDataKey)) {
c.uplinkDataKey = json.value(configKey::xhttpUplinkDataKey).toString();
}
if (json.contains(configKey::xhttpUplinkChunkSize)) {
c.uplinkChunkSize = json.value(configKey::xhttpUplinkChunkSize).toString();
}
if (json.contains(configKey::xhttpScMaxBufferedPosts)) {
c.scMaxBufferedPosts = json.value(configKey::xhttpScMaxBufferedPosts).toString();
}
if (json.contains(configKey::xhttpScMaxEachPostBytesMin)) {
c.scMaxEachPostBytesMin = json.value(configKey::xhttpScMaxEachPostBytesMin).toString();
}
if (json.contains(configKey::xhttpScMaxEachPostBytesMax)) {
c.scMaxEachPostBytesMax = json.value(configKey::xhttpScMaxEachPostBytesMax).toString();
}
if (json.contains(configKey::xhttpScMinPostsIntervalMsMin)) {
c.scMinPostsIntervalMsMin = json.value(configKey::xhttpScMinPostsIntervalMsMin).toString();
}
if (json.contains(configKey::xhttpScMinPostsIntervalMsMax)) {
c.scMinPostsIntervalMsMax = json.value(configKey::xhttpScMinPostsIntervalMsMax).toString();
}
if (json.contains(configKey::xhttpScStreamUpServerSecsMin)) {
c.scStreamUpServerSecsMin = json.value(configKey::xhttpScStreamUpServerSecsMin).toString();
}
if (json.contains(configKey::xhttpScStreamUpServerSecsMax)) {
c.scStreamUpServerSecsMax = json.value(configKey::xhttpScStreamUpServerSecsMax).toString();
}
if (json.contains(QLatin1String("xPadding"))) {
c.xPadding = XrayXPaddingConfig::fromJson(json.value(QLatin1String("xPadding")).toObject());
}
if (json.contains(QLatin1String("xmux"))) {
c.xmux = XrayXmuxConfig::fromJson(json.value(QLatin1String("xmux")).toObject());
}
return c;
}
QJsonObject XrayMkcpConfig::toJson() const
{
QJsonObject obj;
if (!tti.isEmpty()) obj[configKey::mkcpTti] = tti;
if (!uplinkCapacity.isEmpty()) obj[configKey::mkcpUplinkCapacity] = uplinkCapacity;
if (!downlinkCapacity.isEmpty()) obj[configKey::mkcpDownlinkCapacity] = downlinkCapacity;
if (!readBufferSize.isEmpty()) obj[configKey::mkcpReadBufferSize] = readBufferSize;
if (!writeBufferSize.isEmpty()) obj[configKey::mkcpWriteBufferSize] = writeBufferSize;
obj[configKey::mkcpCongestion] = congestion;
return obj;
}
XrayMkcpConfig XrayMkcpConfig::fromJson(const QJsonObject &json)
{
XrayMkcpConfig c;
if (json.isEmpty()) {
return c;
}
if (json.contains(configKey::mkcpTti)) {
c.tti = json.value(configKey::mkcpTti).toString();
}
if (json.contains(configKey::mkcpUplinkCapacity)) {
c.uplinkCapacity = json.value(configKey::mkcpUplinkCapacity).toString();
}
if (json.contains(configKey::mkcpDownlinkCapacity)) {
c.downlinkCapacity = json.value(configKey::mkcpDownlinkCapacity).toString();
}
if (json.contains(configKey::mkcpReadBufferSize)) {
c.readBufferSize = json.value(configKey::mkcpReadBufferSize).toString();
}
if (json.contains(configKey::mkcpWriteBufferSize)) {
c.writeBufferSize = json.value(configKey::mkcpWriteBufferSize).toString();
}
if (json.contains(configKey::mkcpCongestion)) {
c.congestion = json.value(configKey::mkcpCongestion).toBool();
}
return c;
}
QJsonObject XrayServerConfig::toJson() const
{
QJsonObject obj;
// Existing fields
if (!port.isEmpty()) {
obj[configKey::port] = port;
}
if (!transportProto.isEmpty()) {
obj[configKey::transportProto] = transportProto;
}
if (!subnetAddress.isEmpty()) {
obj[configKey::subnetAddress] = subnetAddress;
}
if (!site.isEmpty()) {
obj[configKey::site] = site;
}
if (isThirdPartyConfig) {
obj[configKey::isThirdPartyConfig] = isThirdPartyConfig;
}
// New: Security
if (!security.isEmpty()) {
obj[configKey::xraySecurity] = security;
}
if (!flow.isEmpty()) {
obj[configKey::xrayFlow] = flow;
}
if (!fingerprint.isEmpty()) {
obj[configKey::xrayFingerprint] = fingerprint;
}
if (!sni.isEmpty()) {
obj[configKey::xraySni] = sni;
}
if (!alpn.isEmpty()) {
obj[configKey::xrayAlpn] = alpn;
}
// New: Transport
if (!transport.isEmpty()) {
obj[configKey::xrayTransport] = transport;
}
const QJsonObject xhttpObj = xhttp.toJson();
if (!xhttpObj.isEmpty()) {
obj[QStringLiteral("xhttp")] = xhttpObj;
}
const QJsonObject mkcpObj = mkcp.toJson();
if (!mkcpObj.isEmpty()) {
obj[QStringLiteral("mkcp")] = mkcpObj;
}
return obj;
}
XrayServerConfig XrayServerConfig::fromJson(const QJsonObject &json)
{
XrayServerConfig c;
// Existing fields
c.port = json.value(configKey::port).toString();
c.transportProto = json.value(configKey::transportProto).toString();
c.subnetAddress = json.value(configKey::subnetAddress).toString();
c.site = json.value(configKey::site).toString();
c.isThirdPartyConfig = json.value(configKey::isThirdPartyConfig).toBool(false);
if (json.contains(configKey::xraySecurity)) {
c.security = json.value(configKey::xraySecurity).toString();
}
if (json.contains(configKey::xrayFlow)) {
c.flow = json.value(configKey::xrayFlow).toString();
}
if (json.contains(configKey::xrayFingerprint)) {
c.fingerprint = json.value(configKey::xrayFingerprint).toString();
if (c.fingerprint.contains(QLatin1String("Mozilla/5.0"), Qt::CaseInsensitive)) {
c.fingerprint = QString::fromLatin1(protocols::xray::defaultFingerprint);
}
}
if (json.contains(configKey::xraySni)) {
c.sni = json.value(configKey::xraySni).toString();
}
if (json.contains(configKey::xrayAlpn)) {
c.alpn = json.value(configKey::xrayAlpn).toString();
}
if (json.contains(configKey::xrayTransport)) {
c.transport = json.value(configKey::xrayTransport).toString();
}
if (json.contains(QLatin1String("xhttp"))) {
const QJsonObject xhttpJson = json.value(QLatin1String("xhttp")).toObject();
if (!xhttpJson.isEmpty()) {
c.xhttp = XrayXhttpConfig::fromJson(xhttpJson);
}
}
if (json.contains(QLatin1String("mkcp"))) {
const QJsonObject mkcpJson = json.value(QLatin1String("mkcp")).toObject();
if (!mkcpJson.isEmpty()) {
c.mkcp = XrayMkcpConfig::fromJson(mkcpJson);
}
}
return c;
}
bool XrayServerConfig::hasEqualServerSettings(const XrayServerConfig &other) const
{
return port == other.port
&& transportProto == other.transportProto
&& subnetAddress == other.subnetAddress
&& site == other.site
&& security == other.security
&& flow == other.flow
&& transport == other.transport
&& fingerprint == other.fingerprint
&& sni == other.sni
&& alpn == other.alpn
&& xhttp.toJson() == other.xhttp.toJson()
&& mkcp.toJson() == other.mkcp.toJson();
}
QJsonObject XrayClientConfig::toJson() const
{
QJsonObject obj;
if (!nativeConfig.isEmpty()) obj[configKey::config] = nativeConfig;
if (!localPort.isEmpty()) obj[configKey::localPort] = localPort;
if (!id.isEmpty()) obj[configKey::clientId] = id;
return obj;
}
XrayClientConfig XrayClientConfig::fromJson(const QJsonObject &json)
{
XrayClientConfig c;
c.nativeConfig = json.value(configKey::config).toString();
c.localPort = json.value(configKey::localPort).toString();
c.id = json.value(configKey::clientId).toString();
if (c.id.isEmpty() && !c.nativeConfig.isEmpty()) {
QJsonDocument doc = QJsonDocument::fromJson(c.nativeConfig.toUtf8());
if (!doc.isNull() && doc.isObject()) {
QJsonObject configObj = doc.object();
if (configObj.contains(protocols::xray::outbounds)) {
QJsonArray outbounds = configObj.value(protocols::xray::outbounds).toArray();
if (!outbounds.isEmpty()) {
QJsonObject outbound = outbounds[0].toObject();
if (outbound.contains(protocols::xray::settings)) {
QJsonObject settings = outbound[protocols::xray::settings].toObject();
if (settings.contains(protocols::xray::vnext)) {
QJsonArray vnext = settings[protocols::xray::vnext].toArray();
if (!vnext.isEmpty()) {
QJsonObject vnextObj = vnext[0].toObject();
if (vnextObj.contains(protocols::xray::users)) {
QJsonArray users = vnextObj[protocols::xray::users].toArray();
if (!users.isEmpty()) {
QJsonObject user = users[0].toObject();
if (user.contains(protocols::xray::id)) {
c.id = user[protocols::xray::id].toString();
}
}
}
}
}
}
}
}
}
}
return c;
}
QJsonObject XrayProtocolConfig::toJson() const
{
QJsonObject obj = serverConfig.toJson();
if (clientConfig.has_value()) {
QJsonDocument doc = QJsonDocument::fromJson(clientConfig->nativeConfig.toUtf8());
if (!doc.isNull() && doc.isObject() && doc.object().contains(protocols::xray::outbounds)
&& !doc.object().contains(configKey::config)) {
obj[configKey::lastConfig] = clientConfig->nativeConfig;
} else {
QJsonObject clientJson = clientConfig->toJson();
obj[configKey::lastConfig] = QString::fromUtf8(QJsonDocument(clientJson).toJson(QJsonDocument::Compact));
}
}
return obj;
}
XrayProtocolConfig XrayProtocolConfig::fromJson(const QJsonObject &json)
{
XrayProtocolConfig c;
c.serverConfig = XrayServerConfig::fromJson(json);
QString lastConfigStr = json.value(configKey::lastConfig).toString();
if (!lastConfigStr.isEmpty()) {
QJsonDocument doc = QJsonDocument::fromJson(lastConfigStr.toUtf8());
if (doc.isObject()) {
QJsonObject parsed = doc.object();
if (parsed.contains(protocols::xray::outbounds) && !parsed.contains(configKey::config)) {
XrayClientConfig clientCfg;
clientCfg.nativeConfig = lastConfigStr;
if (parsed.contains(protocols::xray::inbounds)) {
QJsonArray inbounds = parsed.value(protocols::xray::inbounds).toArray();
if (!inbounds.isEmpty()) {
QJsonObject inbound = inbounds[0].toObject();
if (inbound.contains(protocols::xray::port)) {
clientCfg.localPort = QString::number(inbound.value(protocols::xray::port).toInt());
}
}
}
c.clientConfig = clientCfg;
} else {
c.clientConfig = XrayClientConfig::fromJson(parsed);
}
}
}
c.needsClientHydration =
c.hasClientConfig()
&& (!json.contains(configKey::xrayTransport) || c.serverConfig.isThirdPartyConfig);
if (c.needsClientHydration) {
c.hydrateServerConfigFromClientNative();
}
return c;
}
bool XrayProtocolConfig::hydrateServerConfigFromClientNative()
{
if (!clientConfig.has_value() || clientConfig->nativeConfig.isEmpty()) {
return false;
}
QJsonDocument doc = QJsonDocument::fromJson(clientConfig->nativeConfig.toUtf8());
if (doc.isNull() || !doc.isObject()) {
return false;
}
const QJsonObject root = doc.object();
const QJsonArray outbounds = root.value(protocols::xray::outbounds).toArray();
if (outbounds.isEmpty()) {
return false;
}
const QJsonObject outbound = outbounds[0].toObject();
const QJsonObject streamSettings = outbound.value(protocols::xray::streamSettings).toObject();
if (streamSettings.isEmpty()) {
return false;
}
XrayServerConfig &srv = serverConfig;
const QJsonObject settings = outbound.value(protocols::xray::settings).toObject();
const QJsonArray vnext = settings.value(protocols::xray::vnext).toArray();
if (!vnext.isEmpty()) {
const QJsonObject vnextEntry = vnext[0].toObject();
if (vnextEntry.contains(protocols::xray::port)) {
srv.port = QString::number(vnextEntry.value(protocols::xray::port).toInt());
}
const QJsonArray users = vnextEntry.value(protocols::xray::users).toArray();
if (!users.isEmpty()) {
srv.flow = users[0].toObject().value(protocols::xray::flow).toString();
}
}
const QString networkVal = streamSettings.value(protocols::xray::network).toString(QStringLiteral("tcp"));
if (networkVal == QLatin1String("xhttp")) {
srv.transport = QStringLiteral("xhttp");
} else if (networkVal == QLatin1String("kcp")) {
srv.transport = QStringLiteral("mkcp");
} else {
srv.transport = QStringLiteral("raw");
}
if (streamSettings.contains(protocols::xray::security)) {
srv.security = streamSettings.value(protocols::xray::security).toString();
}
if (srv.security == QLatin1String("reality")) {
const QJsonObject rs = streamSettings.value(protocols::xray::realitySettings).toObject();
srv.sni = rs.value(protocols::xray::serverName).toString();
srv.site = srv.sni.isEmpty() ? srv.site : srv.sni;
const QString fp = rs.value(protocols::xray::fingerprint).toString();
if (!fp.isEmpty()) {
srv.fingerprint = fp.contains(QLatin1String("Mozilla/5.0"), Qt::CaseInsensitive)
? QString::fromLatin1(protocols::xray::defaultFingerprint)
: fp;
}
}
if (srv.security == QLatin1String("tls")) {
const QJsonObject tls = streamSettings.value(QStringLiteral("tlsSettings")).toObject();
srv.sni = tls.value(protocols::xray::serverName).toString();
const QString fp = tls.value(protocols::xray::fingerprint).toString();
if (!fp.isEmpty()) {
srv.fingerprint = fp;
}
QStringList alpnList;
for (const QJsonValue &v : tls.value(QStringLiteral("alpn")).toArray()) {
alpnList << v.toString();
}
if (!alpnList.isEmpty()) {
srv.alpn = alpnList.join(QLatin1Char(','));
}
}
if (srv.transport == QLatin1String("xhttp")) {
const QJsonObject xhttpObj = streamSettings.value(QStringLiteral("xhttpSettings")).toObject();
QJsonObject xhttpJson;
const QString mode = xhttpObj.value(QStringLiteral("mode")).toString();
if (!mode.isEmpty()) {
if (mode == QLatin1String("auto")) {
xhttpJson[configKey::xhttpMode] = QStringLiteral("Auto");
} else if (mode == QLatin1String("packet-up")) {
xhttpJson[configKey::xhttpMode] = QStringLiteral("Packet-up");
} else if (mode == QLatin1String("stream-up")) {
xhttpJson[configKey::xhttpMode] = QStringLiteral("Stream-up");
} else if (mode == QLatin1String("stream-one")) {
xhttpJson[configKey::xhttpMode] = QStringLiteral("Stream-one");
} else {
xhttpJson[configKey::xhttpMode] = mode;
}
}
if (xhttpObj.contains(QStringLiteral("host"))) {
xhttpJson[configKey::xhttpHost] = xhttpObj.value(QStringLiteral("host")).toString();
}
if (xhttpObj.contains(QStringLiteral("path"))) {
xhttpJson[configKey::xhttpPath] = xhttpObj.value(QStringLiteral("path")).toString();
}
if (xhttpObj.contains(QStringLiteral("uplinkHTTPMethod"))) {
xhttpJson[configKey::xhttpUplinkMethod] = xhttpObj.value(QStringLiteral("uplinkHTTPMethod")).toString();
}
xhttpJson[configKey::xhttpDisableGrpc] = xhttpObj.value(QStringLiteral("noGRPCHeader")).toBool(true);
xhttpJson[configKey::xhttpDisableSse] = xhttpObj.value(QStringLiteral("noSSEHeader")).toBool(true);
srv.xhttp = XrayXhttpConfig::fromJson(xhttpJson);
}
if (srv.transport == QLatin1String("mkcp")) {
const QJsonObject kcpObj = streamSettings.value(QStringLiteral("kcpSettings")).toObject();
XrayMkcpConfig mk;
if (kcpObj.contains(QStringLiteral("tti"))) {
mk.tti = QString::number(kcpObj.value(QStringLiteral("tti")).toInt());
}
if (kcpObj.contains(QStringLiteral("uplinkCapacity"))) {
mk.uplinkCapacity = QString::number(kcpObj.value(QStringLiteral("uplinkCapacity")).toInt());
}
if (kcpObj.contains(QStringLiteral("downlinkCapacity"))) {
mk.downlinkCapacity = QString::number(kcpObj.value(QStringLiteral("downlinkCapacity")).toInt());
}
if (kcpObj.contains(QStringLiteral("readBufferSize"))) {
mk.readBufferSize = QString::number(kcpObj.value(QStringLiteral("readBufferSize")).toInt());
}
if (kcpObj.contains(QStringLiteral("writeBufferSize"))) {
mk.writeBufferSize = QString::number(kcpObj.value(QStringLiteral("writeBufferSize")).toInt());
}
if (kcpObj.contains(QStringLiteral("congestion"))) {
mk.congestion = kcpObj.value(QStringLiteral("congestion")).toBool(true);
}
srv.mkcp = mk;
}
needsClientHydration = false;
return true;
}
bool XrayProtocolConfig::hasClientConfig() const
{
return clientConfig.has_value();
}
void XrayProtocolConfig::setClientConfig(const XrayClientConfig &config)
{
clientConfig = config;
}
void XrayProtocolConfig::clearClientConfig()
{
clientConfig.reset();
}
} // namespace amnezia