diff --git a/CMakeLists.txt b/CMakeLists.txt index a986520b..ccd078ad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -267,6 +267,7 @@ include(cmake/libcurl.cmake) include(cmake/libsemver.cmake) include(cmake/protobuf.cmake) include(cmake/backend.cmake) +include(3rdparty/QJsonStruct/QJsonStruct.cmake) # ================================================================================== # Qv2ray Base, Qt Libraries, Qv2ray GUI Libraries, libThreads diff --git a/cmake/translations.cmake b/cmake/translations.cmake index c690415e..fc792256 100644 --- a/cmake/translations.cmake +++ b/cmake/translations.cmake @@ -16,9 +16,7 @@ if(CMAKE_BUILD_TYPE MATCHES "^[Dd][Ee][Bb][Uu][Gg]$" OR NOT DEFINED CMAKE_BUILD_ add_custom_target(lupdate COMMENT "Generating Translation Sources" COMMAND lupdate - ${QV2RAY_BASE_SOURCES} - ${QV2RAY_UI_SOURCES} - ${QVPLUGIN_INTERFACE_HEADERS} + ${CMAKE_SOURCE_DIR}/src -ts translations/en_US.ts -locations none -no-obsolete diff --git a/makespec/BUILDVERSION b/makespec/BUILDVERSION index f1700f94..3a9a0e4c 100644 --- a/makespec/BUILDVERSION +++ b/makespec/BUILDVERSION @@ -1 +1 @@ -6096 +6097 diff --git a/src/base/JsonHelpers.hpp b/src/base/JsonHelpers.hpp index daa84db5..c9c62bbd 100644 --- a/src/base/JsonHelpers.hpp +++ b/src/base/JsonHelpers.hpp @@ -10,10 +10,3 @@ // Add key value pair into JSON named 'root' #define JADDEx(field) root.insert(#field, field); #define JADD(...) FOR_EACH(JADDEx, __VA_ARGS__) - -#define JAUTOREMOVE(jObj, key) \ - { \ - if ((jObj[key].isArray() && jObj[key].toArray().isEmpty()) || (jObj[key].isObject() && jObj[key].toObject().isEmpty()) || \ - (jObj[key].isString() && jObj[key].toString().isEmpty())) \ - jObj.remove(key); \ - } diff --git a/src/base/models/CoreObjectModels.hpp b/src/base/models/CoreObjectModels.hpp index 1a711d1f..d60f9298 100644 --- a/src/base/models/CoreObjectModels.hpp +++ b/src/base/models/CoreObjectModels.hpp @@ -37,6 +37,7 @@ namespace Qv2ray::base::objects } void loadJson(const QJsonValue &___json_object_) { + DNSServerObject ___qjsonstruct_default_check; // Hack to convert simple DNS settings to complex format. if (___json_object_.isString()) { @@ -55,6 +56,7 @@ namespace Qv2ray::base::objects [[nodiscard]] const QJsonObject toJson() const { QJsonObject ___json_object_; + DNSServerObject ___qjsonstruct_default_check; FOREACH_CALL_FUNC(___SERIALIZE_TO_JSON_EXTRACT_B_F, F(QV2RAY_DNS_IS_COMPLEX_DNS, address, port, domains, expectIPs)); return ___json_object_; } @@ -79,7 +81,7 @@ namespace Qv2ray::base::objects { QString user; QString pass; - AccountObject(){}; + JSONSTRUCT_COMPARE(AccountObject, user, pass) JSONSTRUCT_REGISTER(AccountObject, F(user, pass)) }; // @@ -90,19 +92,27 @@ namespace Qv2ray::base::objects QString QV2RAY_RULE_TAG = "New Rule"; // QString type = "field"; - QList domain; - QList ip; - QString port = "1-65535"; - QString network; - QList source; - QList user; QList inboundTag; - QList protocol; - QString attrs; QString outboundTag; QString balancerTag; - JSONSTRUCT_REGISTER(RuleObject, F(QV2RAY_RULE_ENABLED, QV2RAY_RULE_TAG, type, domain, ip, port, network, source, user, inboundTag, protocol, - attrs, outboundTag, balancerTag)) + // Addresses + QList source; + QList domain; + QList ip; + // Ports + QString sourcePort; + QString port; + // + QString network; + QList protocol; + QString attrs; + JSONSTRUCT_COMPARE(RuleObject, type, outboundTag, balancerTag, // + QV2RAY_RULE_ENABLED, QV2RAY_RULE_TAG, // + domain, ip, port, sourcePort, network, source, inboundTag, protocol, attrs) + JSONSTRUCT_REGISTER(RuleObject, // + A(type, outboundTag, balancerTag), // + A(QV2RAY_RULE_ENABLED, QV2RAY_RULE_TAG), // + F(domain, ip, port, sourcePort, network, source, inboundTag, protocol, attrs)) }; // // @@ -110,6 +120,7 @@ namespace Qv2ray::base::objects { QString tag; QList selector; + JSONSTRUCT_COMPARE(BalancerObject, tag, selector) JSONSTRUCT_REGISTER(BalancerObject, F(tag, selector)) }; // @@ -120,8 +131,21 @@ namespace Qv2ray::base::objects { QString version = "1.1"; QString method = "GET"; - QList path; + QList path = { "/" }; QMap> headers; + HTTPRequestObject() + { + headers = { + { "Host", { "www.baidu.com", "www.bing.com" } }, + { "User-Agent", + { "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36", + "Mozilla/5.0 (iPhone; CPU iPhone OS 10_0_2 like Mac OS X) AppleWebKit/601.1 (KHTML, like Gecko) CriOS/53.0.2785.109 Mobile/14A456 Safari/601.1.46" } }, + { "Accept-Encoding", { "gzip, deflate" } }, + { "Connection", { "keep-alive" } }, + { "Pragma", { "no-cache" } } + }; + } + JSONSTRUCT_COMPARE(HTTPRequestObject, version, method, path, headers) JSONSTRUCT_REGISTER(HTTPRequestObject, F(version, method, path, headers)) }; // @@ -132,6 +156,14 @@ namespace Qv2ray::base::objects QString status = "200"; QString reason = "OK"; QMap> headers; + HTTPResponseObject() + { + headers = { { "Content-Type", { "application/octet-stream", "video/mpeg" } }, // + { "Transfer-Encoding", { "chunked" } }, // + { "Connection", { "keep-alive" } }, // + { "Pragma", { "no-cache" } } }; + } + JSONSTRUCT_COMPARE(HTTPResponseObject, version, status, reason, headers) JSONSTRUCT_REGISTER(HTTPResponseObject, F(version, status, reason, headers)) }; // @@ -141,6 +173,7 @@ namespace Qv2ray::base::objects QString type = "none"; HTTPRequestObject request; HTTPResponseObject response; + JSONSTRUCT_COMPARE(TCPHeader_Internal, type, request, response) JSONSTRUCT_REGISTER(TCPHeader_Internal, F(type, request, response)) }; // @@ -148,6 +181,7 @@ namespace Qv2ray::base::objects struct ObfsHeaderObject { QString type = "none"; + JSONSTRUCT_COMPARE(ObfsHeaderObject, type) JSONSTRUCT_REGISTER(ObfsHeaderObject, F(type)) }; // @@ -155,7 +189,7 @@ namespace Qv2ray::base::objects struct TCPObject { TCPHeader_Internal header; - TCPObject(){}; + JSONSTRUCT_COMPARE(TCPObject, header) JSONSTRUCT_REGISTER(TCPObject, F(header)) }; // @@ -172,6 +206,7 @@ namespace Qv2ray::base::objects QString seed; ObfsHeaderObject header; KCPObject(){}; + JSONSTRUCT_COMPARE(KCPObject, mtu, tti, uplinkCapacity, downlinkCapacity, congestion, readBufferSize, writeBufferSize, seed, header) JSONSTRUCT_REGISTER(KCPObject, F(mtu, tti, uplinkCapacity, downlinkCapacity, congestion, readBufferSize, writeBufferSize, header, seed)) }; // @@ -180,6 +215,7 @@ namespace Qv2ray::base::objects { QString path = "/"; QMap headers; + JSONSTRUCT_COMPARE(WebSocketObject, path, headers) JSONSTRUCT_REGISTER(WebSocketObject, F(path, headers)) }; // @@ -188,6 +224,7 @@ namespace Qv2ray::base::objects { QList host; QString path = "/"; + JSONSTRUCT_COMPARE(HttpObject, host, path) JSONSTRUCT_REGISTER(HttpObject, F(host, path)) }; // @@ -195,6 +232,7 @@ namespace Qv2ray::base::objects struct DomainSocketObject { QString path = "/"; + JSONSTRUCT_COMPARE(DomainSocketObject, path) JSONSTRUCT_REGISTER(DomainSocketObject, F(path)) }; // @@ -204,7 +242,7 @@ namespace Qv2ray::base::objects QString security; QString key; ObfsHeaderObject header; - QuicObject(){}; + JSONSTRUCT_COMPARE(QuicObject, security, key, header) JSONSTRUCT_REGISTER(QuicObject, F(security, key, header)) }; // @@ -214,6 +252,7 @@ namespace Qv2ray::base::objects int mark = 255; bool tcpFastOpen = false; QString tproxy = "off"; + JSONSTRUCT_COMPARE(SockoptObject, mark, tcpFastOpen, tproxy) JSONSTRUCT_REGISTER(SockoptObject, F(mark, tcpFastOpen, tproxy)) }; // @@ -225,6 +264,7 @@ namespace Qv2ray::base::objects QString keyFile; QList certificate; QList key; + JSONSTRUCT_COMPARE(CertificateObject, usage, certificateFile, keyFile, certificate, key) JSONSTRUCT_REGISTER(CertificateObject, F(usage, certificateFile, keyFile, certificate, key)) }; // @@ -233,13 +273,12 @@ namespace Qv2ray::base::objects { QString serverName; bool allowInsecure = false; - bool allowInsecureCiphers = false; bool disableSessionResumption = true; bool disableSystemRoot = false; QList alpn = { "http/1.1" }; QList certificates; - JSONSTRUCT_REGISTER(TLSObject, - F(serverName, allowInsecure, allowInsecureCiphers, disableSessionResumption, alpn, certificates, disableSystemRoot)) + JSONSTRUCT_COMPARE(TLSObject, serverName, allowInsecure, disableSessionResumption, disableSystemRoot, alpn, certificates) + JSONSTRUCT_REGISTER(TLSObject, F(serverName, allowInsecure, disableSessionResumption, disableSystemRoot, alpn, certificates)) }; // // @@ -247,13 +286,12 @@ namespace Qv2ray::base::objects { QString serverName; bool allowInsecure = false; - bool allowInsecureCiphers = false; bool disableSessionResumption = true; bool disableSystemRoot = false; QList alpn = { "http/1.1" }; QList certificates; - JSONSTRUCT_REGISTER(XTLSObject, - F(serverName, allowInsecure, allowInsecureCiphers, disableSessionResumption, alpn, certificates, disableSystemRoot)) + JSONSTRUCT_COMPARE(XTLSObject, serverName, allowInsecure, disableSessionResumption, disableSystemRoot, alpn, certificates) + JSONSTRUCT_REGISTER(XTLSObject, F(serverName, allowInsecure, disableSessionResumption, disableSystemRoot, alpn, certificates)) }; } // namespace transfer // @@ -271,8 +309,12 @@ namespace Qv2ray::base::objects transfer::HttpObject httpSettings; transfer::DomainSocketObject dsSettings; transfer::QuicObject quicSettings; - JSONSTRUCT_REGISTER(StreamSettingsObject, F(network, security, sockopt, tcpSettings, tlsSettings, xtlsSettings, kcpSettings, wsSettings, - httpSettings, dsSettings, quicSettings)) + JSONSTRUCT_COMPARE(StreamSettingsObject, // + network, security, sockopt, // + tcpSettings, tlsSettings, xtlsSettings, kcpSettings, wsSettings, httpSettings, dsSettings, quicSettings) + JSONSTRUCT_REGISTER(StreamSettingsObject, // + F(network, security, sockopt), + F(tcpSettings, tlsSettings, xtlsSettings, kcpSettings, wsSettings, httpSettings, dsSettings, quicSettings)) }; // // Some protocols from: https://v2ray.com/chapter_02/02_protocols.html @@ -289,12 +331,14 @@ namespace Qv2ray::base::objects int alterId = VMESS_USER_ALTERID_DEFAULT; QString security = "auto"; int level = 0; + JSONSTRUCT_COMPARE(UserObject, id, alterId, security, level) JSONSTRUCT_REGISTER(UserObject, F(id, alterId, security, level)) }; QString address; - int port = 0; + int port; QList users; + JSONSTRUCT_COMPARE(VMessServerObject, address, port, users) JSONSTRUCT_REGISTER(VMessServerObject, F(address, port, users)) }; // @@ -305,6 +349,7 @@ namespace Qv2ray::base::objects QString method = "aes-256-cfb"; QString password; int port; + JSONSTRUCT_COMPARE(ShadowSocksServerObject, address, method, password) JSONSTRUCT_REGISTER(ShadowSocksServerObject, F(address, port, method, password)) }; } // namespace protocol diff --git a/src/base/models/QvComplexConfigModels.hpp b/src/base/models/QvComplexConfigModels.hpp index 0ba46fef..8148c79b 100644 --- a/src/base/models/QvComplexConfigModels.hpp +++ b/src/base/models/QvComplexConfigModels.hpp @@ -79,7 +79,7 @@ namespace Qv2ray::base::objects::complex meta.realOutbound = out; return meta; } - explicit OutboundObjectMeta() : metaType(METAOUTBOUND_ORIGINAL){}; + OutboundObjectMeta() : metaType(METAOUTBOUND_ORIGINAL){}; JSONSTRUCT_REGISTER(OutboundObjectMeta, F(metaType, displayName, connectionId, outboundTags, chainPortAllocation)) }; diff --git a/src/base/models/QvConfigIdentifier.hpp b/src/base/models/QvConfigIdentifier.hpp index 119584ae..ca26cb7d 100644 --- a/src/base/models/QvConfigIdentifier.hpp +++ b/src/base/models/QvConfigIdentifier.hpp @@ -113,6 +113,11 @@ namespace Qv2ray::base bool overrideForwardProxyConfig = false; config::QvConfig_ForwardProxy forwardProxyConfig; // + JSONSTRUCT_COMPARE(GroupRoutingConfig, // + overrideDNS, dnsConfig, // + overrideRoute, routeConfig, // + overrideConnectionConfig, connectionConfig, // + overrideForwardProxyConfig, forwardProxyConfig) JSONSTRUCT_REGISTER(GroupRoutingConfig, // F(overrideRoute, routeConfig), // F(overrideDNS, dnsConfig), // @@ -135,8 +140,10 @@ namespace Qv2ray::base QList ExcludeKeywords; SubscriptionFilterRelation IncludeRelation = RELATION_OR; SubscriptionFilterRelation ExcludeRelation = RELATION_AND; - JSONSTRUCT_REGISTER(SubscriptionConfigObject, - F(updateInterval, address, type, IncludeRelation, ExcludeRelation, IncludeKeywords, ExcludeKeywords)) + JSONSTRUCT_COMPARE(SubscriptionConfigObject, address, type, updateInterval, // + IncludeKeywords, ExcludeKeywords, IncludeRelation, ExcludeRelation) + JSONSTRUCT_REGISTER(SubscriptionConfigObject, F(updateInterval, address, type), + F(IncludeRelation, ExcludeRelation, IncludeKeywords, ExcludeKeywords)) }; struct GroupObject : __Qv2rayConfigObjectBase @@ -146,6 +153,7 @@ namespace Qv2ray::base GroupRoutingId routeConfigId; SubscriptionConfigObject subscriptionOption; GroupObject() : __Qv2rayConfigObjectBase(){}; + JSONSTRUCT_COMPARE(GroupObject, isSubscription, connections, routeConfigId, subscriptionOption) JSONSTRUCT_REGISTER(GroupObject, F(connections, isSubscription, routeConfigId, subscriptionOption), B(__Qv2rayConfigObjectBase)) }; @@ -197,6 +205,10 @@ namespace Qv2ray::base { return JsonStructHelper::Serialize(entries); } + friend bool operator==(const ConnectionStatsObject &left, const ConnectionStatsObject &right) + { + return left.toJson() == right.toJson(); + } void loadJson(const QJsonValue &d) { JsonStructHelper::Deserialize(entries, d); @@ -218,6 +230,7 @@ namespace Qv2ray::base ConnectionStatsObject stats; // int __qvConnectionRefCount = 0; + JSONSTRUCT_COMPARE(ConnectionObject, lastConnected, latency, importSource, stats, displayName, creationDate, lastUpdatedDate) JSONSTRUCT_REGISTER(ConnectionObject, F(lastConnected, latency, importSource, stats), B(__Qv2rayConfigObjectBase)) }; diff --git a/src/base/models/QvCoreSettings.hpp b/src/base/models/QvCoreSettings.hpp index 1ce1a1ed..9fed7909 100644 --- a/src/base/models/QvCoreSettings.hpp +++ b/src/base/models/QvCoreSettings.hpp @@ -1,5 +1,5 @@ #pragma once -#include "3rdparty/QJsonStruct/QJsonStruct.hpp" +#include "QJsonStruct.hpp" #include "base/models/CoreObjectModels.hpp" namespace Qv2ray::base::config { @@ -11,28 +11,19 @@ namespace Qv2ray::base::config QList block; QList proxy; QvRouteConfig_Impl(){}; - friend bool operator==(const QvRouteConfig_Impl &left, const QvRouteConfig_Impl &right) - { - return left.direct == right.direct && left.block == right.block && left.proxy == right.proxy; - } QvRouteConfig_Impl(const QList &_direct, const QList &_block, const QList &_proxy) - : direct(_direct), // - block(_block), // - proxy(_proxy){}; + : direct(_direct), block(_block), proxy(_proxy){}; + JSONSTRUCT_COMPARE(QvRouteConfig_Impl, direct, block, proxy) JSONSTRUCT_REGISTER(QvRouteConfig_Impl, F(proxy, block, direct)) }; + QString domainStrategy; QvRouteConfig_Impl domains; QvRouteConfig_Impl ips; - friend bool operator==(const QvConfig_Route &left, const QvConfig_Route &right) - { - return left.domainStrategy == right.domainStrategy && left.domains == right.domains && left.ips == right.ips; - } QvConfig_Route(){}; QvConfig_Route(const QvRouteConfig_Impl &_domains, const QvRouteConfig_Impl &_ips, const QString &ds) - : domainStrategy(ds), // - domains(_domains), // - ips(_ips){}; + : domainStrategy(ds), domains(_domains), ips(_ips){}; + JSONSTRUCT_COMPARE(QvConfig_Route, domainStrategy, domains, ips) JSONSTRUCT_REGISTER(QvConfig_Route, F(domainStrategy, domains, ips)) }; @@ -41,6 +32,7 @@ namespace Qv2ray::base::config struct QvConfig_Outbounds { int mark = 255; + JSONSTRUCT_COMPARE(QvConfig_Outbounds, mark) JSONSTRUCT_REGISTER(QvConfig_Outbounds, F(mark)) }; @@ -53,6 +45,7 @@ namespace Qv2ray::base::config bool useAuth = false; QString username; QString password; + JSONSTRUCT_COMPARE(QvConfig_ForwardProxy, enableForwardProxy, type, serverAddress, port, useAuth, username, password) JSONSTRUCT_REGISTER(QvConfig_ForwardProxy, F(enableForwardProxy, type, serverAddress, port, useAuth, username, password)) }; @@ -66,22 +59,27 @@ namespace Qv2ray::base::config bool withLocalDNS = true; bool dnsIntercept = false; bool fakeDNS = false; + JSONSTRUCT_COMPARE(QvConfig_Connection, enableProxy, // + bypassCN, bypassBT, bypassLAN, // + v2rayFreedomDNS, withLocalDNS, dnsIntercept, fakeDNS) JSONSTRUCT_REGISTER(QvConfig_Connection, F(bypassCN, bypassBT, bypassLAN, enableProxy, v2rayFreedomDNS, withLocalDNS, dnsIntercept, fakeDNS)) }; struct QvConfig_SystemProxy { bool setSystemProxy = true; + JSONSTRUCT_COMPARE(QvConfig_SystemProxy, setSystemProxy) JSONSTRUCT_REGISTER(QvConfig_SystemProxy, F(setSystemProxy)) }; struct __Qv2rayConfig_ProtocolInboundBase { - int port; + int port = 0; bool useAuth = false; bool sniffing = false; objects::AccountObject account; - __Qv2rayConfig_ProtocolInboundBase(int _port = 0) : port(_port){}; + __Qv2rayConfig_ProtocolInboundBase(){}; + JSONSTRUCT_COMPARE(__Qv2rayConfig_ProtocolInboundBase, port, useAuth, sniffing) JSONSTRUCT_REGISTER(__Qv2rayConfig_ProtocolInboundBase, F(port, useAuth, sniffing, account)) }; @@ -89,13 +87,19 @@ namespace Qv2ray::base::config { bool enableUDP = true; QString localIP = "127.0.0.1"; - QvConfig_SocksInbound() : __Qv2rayConfig_ProtocolInboundBase(1089){}; + QvConfig_SocksInbound() : __Qv2rayConfig_ProtocolInboundBase() + { + port = 1089; + } JSONSTRUCT_REGISTER(QvConfig_SocksInbound, B(__Qv2rayConfig_ProtocolInboundBase), F(enableUDP, localIP)) }; struct QvConfig_HttpInbound : __Qv2rayConfig_ProtocolInboundBase { - QvConfig_HttpInbound() : __Qv2rayConfig_ProtocolInboundBase(8889){}; + QvConfig_HttpInbound() : __Qv2rayConfig_ProtocolInboundBase() + { + port = 8889; + } JSONSTRUCT_REGISTER(QvConfig_HttpInbound, B(__Qv2rayConfig_ProtocolInboundBase)) }; @@ -108,6 +112,7 @@ namespace Qv2ray::base::config bool hasUDP = true; bool sniffing = true; QString mode = "tproxy"; + JSONSTRUCT_COMPARE(QvConfig_TProxy, tProxyIP, tProxyV6IP, port, hasTCP, hasUDP, sniffing, mode) JSONSTRUCT_REGISTER(QvConfig_TProxy, F(tProxyIP, tProxyV6IP, port, hasTCP, hasUDP, sniffing, mode)) }; @@ -122,6 +127,8 @@ namespace Qv2ray::base::config QvConfig_HttpInbound httpSettings; QvConfig_SocksInbound socksSettings; QvConfig_SystemProxy systemProxySettings; + JSONSTRUCT_COMPARE(QvConfig_Inbounds, listenip, useSocks, useHTTP, useTPROXY, tProxySettings, httpSettings, socksSettings, + systemProxySettings) JSONSTRUCT_REGISTER(QvConfig_Inbounds, // F(listenip, useSocks, useHTTP, useTPROXY), // F(tProxySettings, httpSettings, socksSettings, systemProxySettings)) diff --git a/src/base/models/QvSafeType.hpp b/src/base/models/QvSafeType.hpp index 76addc5b..8a37d566 100644 --- a/src/base/models/QvSafeType.hpp +++ b/src/base/models/QvSafeType.hpp @@ -42,12 +42,14 @@ namespace Qv2ray::base::safetype { T1 value1; T2 value2; - JSONSTRUCT_REGISTER(___qvpair_t, F(value1, value2)) - private: - typedef QvPair ___qvpair_t; + friend bool operator==(const QvPair &one, const QvPair &another) + { + return another.value1 == one.value1 && another.value2 == one.value2; + } + JSONSTRUCT_REGISTER(___qvpair_t, F(value1, value2)) private : typedef QvPair ___qvpair_t; }; - template::value>::type> + template>> struct QvEnumMap : QMap { // WARN: Changing this will break all existing JSON. diff --git a/src/base/models/QvSettingsObject.hpp b/src/base/models/QvSettingsObject.hpp index 0a66b52f..43160d6d 100644 --- a/src/base/models/QvSettingsObject.hpp +++ b/src/base/models/QvSettingsObject.hpp @@ -23,6 +23,10 @@ namespace Qv2ray::base::config this->width = w; this->style = s; }; + friend bool operator==(const QvGraphPenConfig &one, const QvGraphPenConfig &another) + { + return one.R == another.R && one.G == another.G && one.B == another.B && one.width == another.width && one.style == another.style; + } JSONSTRUCT_REGISTER(QvGraphPenConfig, F(R, G, B, width, style)) }; @@ -31,6 +35,7 @@ namespace Qv2ray::base::config bool useOutboundStats = true; bool hasDirectStats = true; safetype::QvEnumMap> colorConfig; + JSONSTRUCT_COMPARE(Qv2rayConfig_Graph, useOutboundStats, hasDirectStats, colorConfig) JSONSTRUCT_REGISTER(Qv2rayConfig_Graph, F(useOutboundStats, hasDirectStats, colorConfig)) }; @@ -46,6 +51,8 @@ namespace Qv2ray::base::config int maximumLogLines = 500; int maxJumpListCount = 20; bool useOldShareLinkFormat = false; + JSONSTRUCT_COMPARE(Qv2rayConfig_UI, theme, language, quietMode, graphConfig, useDarkTheme, useDarkTrayIcon, maximumLogLines, maxJumpListCount, + recentConnections, useOldShareLinkFormat) JSONSTRUCT_REGISTER(Qv2rayConfig_UI, F(theme, language, quietMode, graphConfig, useDarkTheme, useDarkTrayIcon, maximumLogLines, maxJumpListCount, recentConnections, useOldShareLinkFormat)) }; @@ -55,6 +62,7 @@ namespace Qv2ray::base::config QMap pluginStates; bool v2rayIntegration = true; int portAllocationStart = 15000; + JSONSTRUCT_COMPARE(Qv2rayConfig_Plugin, pluginStates, v2rayIntegration, portAllocationStart) JSONSTRUCT_REGISTER(Qv2rayConfig_Plugin, F(pluginStates, v2rayIntegration, portAllocationStart)) }; @@ -93,6 +101,10 @@ namespace Qv2ray::base::config #undef _VARNAME_VCOREPATH_ #undef _VARNAME_VASSETSPATH_ + JSONSTRUCT_COMPARE(Qv2rayConfig_Kernel, enableAPI, statsPort, // + v2CorePath_linux, v2AssetsPath_linux, // + v2CorePath_macx, v2AssetsPath_macx, // + v2CorePath_win, v2AssetsPath_win) JSONSTRUCT_REGISTER(Qv2rayConfig_Kernel, // F(enableAPI, statsPort), // F(v2CorePath_linux, v2AssetsPath_linux), // @@ -109,6 +121,7 @@ namespace Qv2ray::base::config }; UpdateChannel updateChannel = CHANNEL_STABLE; QString ignoredVersion; + JSONSTRUCT_COMPARE(Qv2rayConfig_Update, updateChannel, ignoredVersion) JSONSTRUCT_REGISTER(Qv2rayConfig_Update, F(ignoredVersion, updateChannel)) }; @@ -119,7 +132,10 @@ namespace Qv2ray::base::config bool testLatencyPeriodcally = false; bool disableSystemRoot = false; bool testLatencyOnConnected = false; - JSONSTRUCT_REGISTER(Qv2rayConfig_Advanced, F(setAllowInsecure, setSessionResumption, testLatencyPeriodcally, disableSystemRoot, testLatencyOnConnected)) + JSONSTRUCT_COMPARE(Qv2rayConfig_Advanced, setAllowInsecure, setSessionResumption, testLatencyPeriodcally, disableSystemRoot, + testLatencyOnConnected) + JSONSTRUCT_REGISTER(Qv2rayConfig_Advanced, + F(setAllowInsecure, setSessionResumption, testLatencyPeriodcally, disableSystemRoot, testLatencyOnConnected)) }; enum Qv2rayLatencyTestingMethod @@ -145,6 +161,7 @@ namespace Qv2ray::base::config QString type = "http"; int port = 8000; QString userAgent = "Qv2ray/$VERSION WebRequestHelper"; + JSONSTRUCT_COMPARE(Qv2rayConfig_Network, latencyTestingMethod, latencyRealPingTestURL, proxyType, type, address, port, userAgent) JSONSTRUCT_REGISTER(Qv2rayConfig_Network, F(latencyTestingMethod, latencyRealPingTestURL, proxyType, type, address, port, userAgent)) }; @@ -183,9 +200,11 @@ namespace Qv2ray::base::config #else Q_DISABLE_COPY_MOVE(Qv2rayConfigObject); #endif + JSONSTRUCT_COMPARE(Qv2rayConfigObject, config_version, logLevel, autoStartId, lastConnectedId, autoStartBehavior, uiConfig, pluginConfig, + kernelConfig, updateConfig, networkConfig, inboundConfig, outboundConfig, advancedConfig, defaultRouteConfig) JSONSTRUCT_REGISTER_NOCOPYMOVE(Qv2rayConfigObject, // - F(config_version, autoStartId, lastConnectedId, autoStartBehavior, logLevel), // - F(uiConfig, advancedConfig, pluginConfig, updateConfig, kernelConfig, networkConfig), // - F(inboundConfig, outboundConfig, defaultRouteConfig)) + A(config_version, autoStartId, lastConnectedId, autoStartBehavior, logLevel), // + A(uiConfig, advancedConfig, pluginConfig, updateConfig, kernelConfig, networkConfig), // + A(inboundConfig, outboundConfig, defaultRouteConfig)) }; } // namespace Qv2ray::base::config diff --git a/src/core/connection/generation/routing.cpp b/src/core/connection/generation/routing.cpp index 38be89f8..3623a314 100644 --- a/src/core/connection/generation/routing.cpp +++ b/src/core/connection/generation/routing.cpp @@ -14,9 +14,9 @@ namespace Qv2ray::core::connection::generation::routing if (withLocalhost) servers.push_front("localhost"); root["servers"] = servers; - JAUTOREMOVE(root, "clientIp"); - JAUTOREMOVE(root, "hosts"); - JAUTOREMOVE(root, "tag"); + // JAUTOREMOVE(root, "clientIp"); + // JAUTOREMOVE(root, "hosts"); + // JAUTOREMOVE(root, "tag"); return root; } diff --git a/src/core/handler/ConfigHandler.cpp b/src/core/handler/ConfigHandler.cpp index 85bbb44c..8b6d3be5 100644 --- a/src/core/handler/ConfigHandler.cpp +++ b/src/core/handler/ConfigHandler.cpp @@ -97,8 +97,6 @@ namespace Qv2ray::core::handler groupObject[key.toString()] = groups[key].toJson(); } StringToFile(JsonToString(groupObject), QV2RAY_CONFIG_DIR + "groups.json"); - RouteManager->SaveRoutes(); - SaveGlobalSettings(); } void QvConfigHandler::timerEvent(QTimerEvent *event) @@ -341,7 +339,6 @@ namespace Qv2ray::core::handler void QvConfigHandler::StopConnection() // const ConnectionId &id { kernelHandler->StopConnection(); - SaveConnectionConfig(); } void QvConfigHandler::p_OnKernelCrashed(const ConnectionGroupPair &id, const QString &errMessage) diff --git a/src/plugins/common/CommonTypes.hpp b/src/plugins/common/CommonTypes.hpp index 1bd42be0..a7c77a64 100644 --- a/src/plugins/common/CommonTypes.hpp +++ b/src/plugins/common/CommonTypes.hpp @@ -1,5 +1,5 @@ #pragma once -#include "3rdparty/QJsonStruct/QJsonStruct.hpp" +#include "QJsonStruct.hpp" // GUI TOOLS #define RED(obj) \ @@ -16,6 +16,7 @@ struct HTTPSOCKSUserObject QString user; QString pass; int level = 0; + JSONSTRUCT_COMPARE(HTTPSOCKSUserObject, user, pass, level) JSONSTRUCT_REGISTER(HTTPSOCKSUserObject, F(user, pass, level)) }; // @@ -25,6 +26,7 @@ struct SocksServerObject QString address = "0.0.0.0"; int port = 0; QList users; + JSONSTRUCT_COMPARE(SocksServerObject, address, port, users) JSONSTRUCT_REGISTER(SocksServerObject, F(address, port, users)) }; @@ -35,6 +37,7 @@ struct HttpServerObject QString address = "0.0.0.0"; int port = 0; QList users; + JSONSTRUCT_COMPARE(HttpServerObject, address, port, users) JSONSTRUCT_REGISTER(HttpServerObject, F(address, port, users)) }; @@ -46,6 +49,7 @@ struct ShadowSocksServerObject QString method = "aes-256-cfb"; QString password; int port = 0; + JSONSTRUCT_COMPARE(ShadowSocksServerObject, address, method, password) JSONSTRUCT_REGISTER(ShadowSocksServerObject, F(address, port, method, password)) }; @@ -58,12 +62,14 @@ struct VLESSServerObject QString id; QString encryption = "none"; QString flow; - JSONSTRUCT_REGISTER(UserObject, F(id, encryption, flow)) + JSONSTRUCT_COMPARE(UserObject, id, encryption, flow) + JSONSTRUCT_REGISTER(UserObject, A(encryption), F(id, flow)) }; QString address; int port = 0; QList users; + JSONSTRUCT_COMPARE(VLESSServerObject, address, port, users) JSONSTRUCT_REGISTER(VLESSServerObject, F(address, port, users)) }; @@ -78,11 +84,13 @@ struct VMessServerObject int alterId = VMESS_USER_ALTERID_DEFAULT; QString security = "auto"; int level = 0; + JSONSTRUCT_COMPARE(UserObject, id, alterId, security, level) JSONSTRUCT_REGISTER(UserObject, F(id, alterId, security, level)) }; QString address; int port = 0; QList users; + JSONSTRUCT_COMPARE(VMessServerObject, address, port, users) JSONSTRUCT_REGISTER(VMessServerObject, F(address, port, users)) }; diff --git a/src/plugins/protocols/QvPlugin-BuiltinProtocolSupport.cmake b/src/plugins/protocols/QvPlugin-BuiltinProtocolSupport.cmake index e7962def..f5d0ef5d 100644 --- a/src/plugins/protocols/QvPlugin-BuiltinProtocolSupport.cmake +++ b/src/plugins/protocols/QvPlugin-BuiltinProtocolSupport.cmake @@ -29,6 +29,7 @@ ADD_SOURCE(inbound socksin) set(BUILTIN_PROTOCOL_PLUGIN_SOURCES ${PLUGIN_UI_SOURCE} + ${CMAKE_CURRENT_LIST_DIR}/../common/CommonTypes.hpp ${CMAKE_CURRENT_LIST_DIR}/BuiltinProtocolPlugin.hpp ${CMAKE_CURRENT_LIST_DIR}/BuiltinProtocolPlugin.cpp ${CMAKE_CURRENT_LIST_DIR}/core/OutboundHandler.cpp diff --git a/src/plugins/protocols/ui/outbound/blackhole.cpp b/src/plugins/protocols/ui/outbound/blackhole.cpp index c05daaf2..81aba608 100644 --- a/src/plugins/protocols/ui/outbound/blackhole.cpp +++ b/src/plugins/protocols/ui/outbound/blackhole.cpp @@ -20,7 +20,10 @@ void BlackholeOutboundEditor::changeEvent(QEvent *e) void BlackholeOutboundEditor::SetContent(const QJsonObject &_content) { this->content = _content; - PLUGIN_EDITOR_LOADING_SCOPE({ responseTypeCB->setCurrentText(content["response"].toObject()["response"].toString()); }) + PLUGIN_EDITOR_LOADING_SCOPE({ + if (content.contains("response") && content["response"].toObject().contains("type")) + responseTypeCB->setCurrentText(content["response"].toObject()["type"].toString()); + }) } void BlackholeOutboundEditor::on_responseTypeCB_currentTextChanged(const QString &arg1) diff --git a/src/ui/widgets/editors/w_OutboundEditor.cpp b/src/ui/widgets/editors/w_OutboundEditor.cpp index b7946432..e0059e46 100644 --- a/src/ui/widgets/editors/w_OutboundEditor.cpp +++ b/src/ui/widgets/editors/w_OutboundEditor.cpp @@ -114,7 +114,7 @@ void OutboundEditor::reloadGUI() tag = originalConfig["tag"].toString(); tagTxt->setText(tag); outboundType = originalConfig["protocol"].toString("vmess"); - muxConfig = originalConfig["mux"].toObject(); + muxConfig = originalConfig.contains("mux") ? originalConfig["mux"].toObject() : QJsonObject{}; useForwardProxy = originalConfig[QV2RAY_USE_FPROXY_KEY].toBool(false); streamSettingsWidget->SetStreamObject(StreamSettingsObject::fromJson(originalConfig["streamSettings"].toObject())); // diff --git a/src/ui/widgets/editors/w_RoutesEditor.cpp b/src/ui/widgets/editors/w_RoutesEditor.cpp index e40fd199..8ae79bfa 100644 --- a/src/ui/widgets/editors/w_RoutesEditor.cpp +++ b/src/ui/widgets/editors/w_RoutesEditor.cpp @@ -239,8 +239,6 @@ CONFIGROOT RouteEditor::OpenEditor() { const auto &ruleObject = rules[ruleTag]; auto ruleJson = ruleObject.toJson(); - JAUTOREMOVE(ruleJson, "network"); - JAUTOREMOVE(ruleJson, "port"); if (ruleJson["outboundTag"].toString().isEmpty()) ruleJson.remove("outboundTag"); else diff --git a/src/ui/widgets/node/widgets/RuleWidget.cpp b/src/ui/widgets/node/widgets/RuleWidget.cpp index 26ee6180..907b114d 100644 --- a/src/ui/widgets/node/widgets/RuleWidget.cpp +++ b/src/ui/widgets/node/widgets/RuleWidget.cpp @@ -64,7 +64,7 @@ void QvNodeRuleWidget::setValue(std::shared_ptr _ruleptr) routePortTxt->setText(rule.port); // // Users - const auto users = rule.user.join(NEWLINE); + const auto sourcePorts = rule.sourcePort; // // Incoming Sources const auto sources = rule.source.join(NEWLINE); @@ -115,11 +115,6 @@ void QvNodeRuleWidget::on_routePortTxt_textEdited(const QString &arg1) LOADINGCHECK rule.port = arg1; } -void QvNodeRuleWidget::on_routeUserTxt_textEdited(const QString &arg1) -{ - LOADINGCHECK - rule.user = SplitLines(arg1); -} void QvNodeRuleWidget::on_netUDPRB_clicked() { diff --git a/src/ui/widgets/node/widgets/RuleWidget.hpp b/src/ui/widgets/node/widgets/RuleWidget.hpp index e5c7e308..c4008ec3 100644 --- a/src/ui/widgets/node/widgets/RuleWidget.hpp +++ b/src/ui/widgets/node/widgets/RuleWidget.hpp @@ -27,7 +27,6 @@ class QvNodeRuleWidget void on_hostList_textChanged(); void on_ipList_textChanged(); void on_routePortTxt_textEdited(const QString &arg1); - void on_routeUserTxt_textEdited(const QString &arg1); void on_netUDPRB_clicked(); void on_netTCPRB_clicked(); void on_sourceIPList_textChanged(); diff --git a/src/ui/widgets/widgets/StreamSettingsWidget.cpp b/src/ui/widgets/widgets/StreamSettingsWidget.cpp index ede022d9..747a6edb 100644 --- a/src/ui/widgets/widgets/StreamSettingsWidget.cpp +++ b/src/ui/widgets/widgets/StreamSettingsWidget.cpp @@ -153,25 +153,13 @@ void StreamSettingsWidget::on_wsHeadersTxt_textChanged() void StreamSettingsWidget::on_tcpRequestDefBtn_clicked() { tcpRequestTxt->clear(); - tcpRequestTxt->setPlainText("{\"version\":\"1.1\",\"method\":\"GET\",\"path\":[\"/\"],\"headers\":" - "{\"Host\":[\"www.baidu.com\",\"www.bing.com\"],\"User-Agent\":" - "[\"Mozilla/5.0 (Windows NT 10.0; WOW64) " - "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36\"," - "\"Mozilla/5.0 (iPhone; CPU iPhone OS 10_0_2 like Mac OS X) " - "AppleWebKit/601.1 (KHTML, like Gecko) CriOS/53.0.2785.109 Mobile/14A456 " - "Safari/601.1.46\"],\"Accept-Encoding\":[\"gzip, deflate\"]," - "\"Connection\":[\"keep-alive\"],\"Pragma\":\"no-cache\"}}"); + tcpRequestTxt->setPlainText(JsonToString(transfer::HTTPRequestObject().toJson()["headers"].toObject())); } void StreamSettingsWidget::on_tcpRespDefBtn_clicked() { tcpRespTxt->clear(); - tcpRespTxt->setPlainText("{\"version\":\"1.1\",\"status\":\"200\",\"" - "reason\":\"OK\",\"headers\":{\"Content-Typ" - "e\":[\"application/octet-stream\",\"video/" - "mpeg\"],\"Transfer-Encoding\":[\"chunked\"" - "],\"Connection\":[\"keep-alive\"],\"Pragma" - "\":\"no-cache\"}}"); + tcpRespTxt->setPlainText(JsonToString(transfer::HTTPResponseObject().toJson()["headers"].toObject())); } void StreamSettingsWidget::on_soMarkSpinBox_valueChanged(int arg1) diff --git a/test/src/core/connection/TestParseVmess.cpp b/test/src/core/connection/TestParseVmess.cpp index 82312697..a60c559f 100644 --- a/test/src/core/connection/TestParseVmess.cpp +++ b/test/src/core/connection/TestParseVmess.cpp @@ -35,15 +35,13 @@ SCENARIO("Test Parse VMess V2 url", "[ParseVMessV2]") const auto portParsed = QJsonIO::GetValue(result, "outbounds", 0, "settings", "vnext", 0, "port").toInt(); const auto idParsed = QJsonIO::GetValue(result, "outbounds", 0, "settings", "vnext", 0, "users", 0, "id").toString(); const auto alterIdParsed = QJsonIO::GetValue(result, "outbounds", 0, "settings", "vnext", 0, "users", 0, "alterId").toInt(); - const auto typeParsed = QJsonIO::GetValue(result, "outbounds", 0, "streamSettings", "tcpSettings", "header", "type").toString(); REQUIRE(commentParsed.toStdString() == comment.toStdString()); REQUIRE(addressParsed.toStdString() == address.toStdString()); REQUIRE(portParsed == port); REQUIRE(idParsed.toStdString() == uuid.toStdString()); REQUIRE(alterIdParsed == alterId); - REQUIRE(networkParsed.toStdString() == network.toStdString()); - REQUIRE(typeParsed.toStdString() == "none"); + REQUIRE(networkParsed.toStdString() == ""); } } } @@ -88,8 +86,6 @@ SCENARIO("Test Parse VMess V1 url", "[ParseVMessV1]") REQUIRE(idParsed.toStdString() == uuid.toStdString()); REQUIRE(alterIdParsed == alterId); REQUIRE(networkParsed.toStdString() == network.toStdString()); - REQUIRE(typeParsed.toStdString() == "none"); - REQUIRE(tlsParsed.toStdString() == "none"); } } } diff --git a/translations/en_US.ts b/translations/en_US.ts index 3517a070..033204f0 100644 --- a/translations/en_US.ts +++ b/translations/en_US.ts @@ -2256,6 +2256,14 @@ Output: Please upgrade firstly up to Qv2ray v2.0/v2.1 and try again. + + Qv2ray has encountered an uncaught exception: + + + + Please report a bug via Github with the file located here: + + Qv2ray::Qv2rayWidgetApplication @@ -3271,4 +3279,339 @@ Maybe you have downloaded the wrong core? + + dokodemodoorInEditor + + Form + + + + Address + + + + Optional when using "Follow Redirect" + + + + Port + + + + Network + + + + TCP + + + + UDP + + + + Timeout + + + + Follow Redirect + + + + Enabled + + + + + httpInEditor + + Form + + + + Allow Transparent + + + + Timeout + + + + s + + + + Users + + + + Username + + + + Password + + + + + PluginInboundEditor + + Form + + + + + socksInEditor + + Form + + + + UDP + + + + Enabled + + + + UDP Local IP + + + + 127.0.0.1 + + + + Auth + + + + Users + + + + Username + + + + Password + + + + + blackholeOutEditor + + Form + + + + Response + + + + Type + + + + + dnsOutEditor + + Form + + + + Network + + + + TCP + + + + UDP + + + + Original + + + + Address + + + + Port + + + + + freedomOutEditor + + Form + + + + Domain Strategy + + + + Redirect + + + + :0 + + + + + httpOutEditor + + Form + + + + Username + + + + Password + + + + + PluginOutboundEditor + + Form + + + + + shadowsocksOutEditor + + Form + + + + Password + + + + Encryption Method + + + + + socksOutEditor + + Form + + + + Username + + + + Password + + + + + vlessOutEditor + + Form + + + + UUID + + + + Encryption + + + + Flow + + + + <h3>Notes for <code>udp443</code> Methods</h3> + +<p>Some applications like Google Chrome would attempt to use QUIC protocol instead of TLS, which, won't benefit from XTLS at all. What's worse, QUIC over TCP will cause potential congestion control problem, downgrading your experience.</p> + +<p>Non-<code>udp443</code> methods block UDP 443 outbound traffic to workaround this situation. If you do want to let it go, use at your own peril.</p> + + + + + vmessOutEditor + + Form + + + + UUID + + + + Alter ID + + + + Security + + + + + PluginSettingsWidget + + Form + + + + + MainWindowForm.ui + + Qv2ray + + + + + HTTPInboundEditor + + Removing a user + + + + You haven't selected a user yet. + + + + Add a user + + + + This user exists already. + + + + + SocksInboundEditor + + Removing a user + + + + You haven't selected a user yet. + + + + Add a user + + + + This user exists already. + + +