diff --git a/3rdparty/qv2ray/v2/components/proxy/QvProxyConfigurator.cpp b/3rdparty/qv2ray/v2/components/proxy/QvProxyConfigurator.cpp deleted file mode 100644 index 693c5ca..0000000 --- a/3rdparty/qv2ray/v2/components/proxy/QvProxyConfigurator.cpp +++ /dev/null @@ -1,440 +0,0 @@ -#include "QvProxyConfigurator.hpp" - -#ifdef Q_OS_WIN -// -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#include -// -#include -#include -#include -#include -#endif - -#include -#include - -#include "3rdparty/fix_old_qt.h" -#include "3rdparty/qv2ray/wrapper.hpp" -#include "fmt/Preset.hpp" -#include "main/NekoGui.hpp" - -#define QV_MODULE_NAME "SystemProxy" - -#define QSTRN(num) QString::number(num) - -namespace Qv2ray::components::proxy { - - using ProcessArgument = QPair; -#ifdef Q_OS_MACOS - QStringList macOSgetNetworkServices() { - QProcess p; - p.setProgram("/usr/sbin/networksetup"); - p.setArguments(QStringList{"-listallnetworkservices"}); - p.start(); - p.waitForStarted(); - p.waitForFinished(); - LOG(p.errorString()); - auto str = p.readAllStandardOutput(); - auto lines = SplitLines(str); - QStringList result; - - // Start from 1 since first line is unneeded. - for (auto i = 1; i < lines.count(); i++) { - // * means disabled. - if (!lines[i].contains("*")) { - result << lines[i]; - } - } - - LOG("Found " + QSTRN(result.size()) + " network services: " + result.join(";")); - return result; - } -#endif -#ifdef Q_OS_WIN -#define NO_CONST(expr) const_cast(expr) - // static auto DEFAULT_CONNECTION_NAME = - // NO_CONST(L"DefaultConnectionSettings"); - /// - /// INTERNAL FUNCTION - bool __QueryProxyOptions() { - INTERNET_PER_CONN_OPTION_LIST List; - INTERNET_PER_CONN_OPTION Option[5]; - // - unsigned long nSize = sizeof(INTERNET_PER_CONN_OPTION_LIST); - Option[0].dwOption = INTERNET_PER_CONN_AUTOCONFIG_URL; - Option[1].dwOption = INTERNET_PER_CONN_AUTODISCOVERY_FLAGS; - Option[2].dwOption = INTERNET_PER_CONN_FLAGS; - Option[3].dwOption = INTERNET_PER_CONN_PROXY_BYPASS; - Option[4].dwOption = INTERNET_PER_CONN_PROXY_SERVER; - // - List.dwSize = sizeof(INTERNET_PER_CONN_OPTION_LIST); - List.pszConnection = nullptr; // NO_CONST(DEFAULT_CONNECTION_NAME); - List.dwOptionCount = 5; - List.dwOptionError = 0; - List.pOptions = Option; - - if (!InternetQueryOption(nullptr, INTERNET_OPTION_PER_CONNECTION_OPTION, &List, &nSize)) { - LOG("InternetQueryOption failed, GLE=" + QSTRN(GetLastError())); - } - - LOG("System default proxy info:"); - - if (Option[0].Value.pszValue != nullptr) { - LOG(QString::fromWCharArray(Option[0].Value.pszValue)); - } - - if ((Option[2].Value.dwValue & PROXY_TYPE_AUTO_PROXY_URL) == PROXY_TYPE_AUTO_PROXY_URL) { - LOG("PROXY_TYPE_AUTO_PROXY_URL"); - } - - if ((Option[2].Value.dwValue & PROXY_TYPE_AUTO_DETECT) == PROXY_TYPE_AUTO_DETECT) { - LOG("PROXY_TYPE_AUTO_DETECT"); - } - - if ((Option[2].Value.dwValue & PROXY_TYPE_DIRECT) == PROXY_TYPE_DIRECT) { - LOG("PROXY_TYPE_DIRECT"); - } - - if ((Option[2].Value.dwValue & PROXY_TYPE_PROXY) == PROXY_TYPE_PROXY) { - LOG("PROXY_TYPE_PROXY"); - } - - if (!InternetQueryOption(nullptr, INTERNET_OPTION_PER_CONNECTION_OPTION, &List, &nSize)) { - LOG("InternetQueryOption failed,GLE=" + QSTRN(GetLastError())); - } - - if (Option[4].Value.pszValue != nullptr) { - LOG(QString::fromStdWString(Option[4].Value.pszValue)); - } - - INTERNET_VERSION_INFO Version; - nSize = sizeof(INTERNET_VERSION_INFO); - InternetQueryOption(nullptr, INTERNET_OPTION_VERSION, &Version, &nSize); - - if (Option[0].Value.pszValue != nullptr) { - GlobalFree(Option[0].Value.pszValue); - } - - if (Option[3].Value.pszValue != nullptr) { - GlobalFree(Option[3].Value.pszValue); - } - - if (Option[4].Value.pszValue != nullptr) { - GlobalFree(Option[4].Value.pszValue); - } - - return false; - } - bool __SetProxyOptions(LPWSTR proxy_full_addr, bool isPAC) { - INTERNET_PER_CONN_OPTION_LIST list; - DWORD dwBufSize = sizeof(list); - // Fill the list structure. - list.dwSize = sizeof(list); - // NULL == LAN, otherwise connectoid name. - list.pszConnection = nullptr; - - if (nullptr == proxy_full_addr) { - LOG("Clearing system proxy"); - // - list.dwOptionCount = 1; - list.pOptions = new INTERNET_PER_CONN_OPTION[1]; - - // Ensure that the memory was allocated. - if (nullptr == list.pOptions) { - // Return if the memory wasn't allocated. - return false; - } - - // Set flags. - list.pOptions[0].dwOption = INTERNET_PER_CONN_FLAGS; - list.pOptions[0].Value.dwValue = PROXY_TYPE_DIRECT; - } else if (isPAC) { - LOG("Setting system proxy for PAC"); - // - list.dwOptionCount = 2; - list.pOptions = new INTERNET_PER_CONN_OPTION[2]; - - if (nullptr == list.pOptions) { - return false; - } - - // Set flags. - list.pOptions[0].dwOption = INTERNET_PER_CONN_FLAGS; - list.pOptions[0].Value.dwValue = PROXY_TYPE_DIRECT | PROXY_TYPE_AUTO_PROXY_URL; - // Set proxy name. - list.pOptions[1].dwOption = INTERNET_PER_CONN_AUTOCONFIG_URL; - list.pOptions[1].Value.pszValue = proxy_full_addr; - } else { - LOG("Setting system proxy for Global Proxy"); - // - list.dwOptionCount = 2; - list.pOptions = new INTERNET_PER_CONN_OPTION[2]; - - if (nullptr == list.pOptions) { - return false; - } - - // Set flags. - list.pOptions[0].dwOption = INTERNET_PER_CONN_FLAGS; - list.pOptions[0].Value.dwValue = PROXY_TYPE_DIRECT | PROXY_TYPE_PROXY; - // Set proxy name. - list.pOptions[1].dwOption = INTERNET_PER_CONN_PROXY_SERVER; - list.pOptions[1].Value.pszValue = proxy_full_addr; - // Set proxy override. - // list.pOptions[2].dwOption = INTERNET_PER_CONN_PROXY_BYPASS; - // auto localhost = L"localhost"; - // list.pOptions[2].Value.pszValue = NO_CONST(localhost); - } - - // Set proxy for LAN. - if (!InternetSetOption(nullptr, INTERNET_OPTION_PER_CONNECTION_OPTION, &list, dwBufSize)) { - LOG("InternetSetOption failed for LAN, GLE=" + QSTRN(GetLastError())); - } - - RASENTRYNAME entry; - entry.dwSize = sizeof(entry); - std::vector entries; - DWORD size = sizeof(entry), count; - LPRASENTRYNAME entryAddr = &entry; - auto ret = RasEnumEntries(nullptr, nullptr, entryAddr, &size, &count); - if (ERROR_BUFFER_TOO_SMALL == ret) { - entries.resize(count); - entries[0].dwSize = sizeof(RASENTRYNAME); - entryAddr = entries.data(); - ret = RasEnumEntries(nullptr, nullptr, entryAddr, &size, &count); - } - if (ERROR_SUCCESS != ret) { - LOG("Failed to list entry names"); - return false; - } - - // Set proxy for each connectoid. - for (DWORD i = 0; i < count; ++i) { - list.pszConnection = entryAddr[i].szEntryName; - if (!InternetSetOption(nullptr, INTERNET_OPTION_PER_CONNECTION_OPTION, &list, dwBufSize)) { - LOG("InternetSetOption failed for connectoid " + QString::fromWCharArray(list.pszConnection) + ", GLE=" + QSTRN(GetLastError())); - } - } - - delete[] list.pOptions; - InternetSetOption(nullptr, INTERNET_OPTION_SETTINGS_CHANGED, nullptr, 0); - InternetSetOption(nullptr, INTERNET_OPTION_REFRESH, nullptr, 0); - return true; - } -#endif - - void SetSystemProxy(int httpPort, int socksPort) { - const QString &address = "127.0.0.1"; - bool hasHTTP = (httpPort > 0 && httpPort < 65536); - bool hasSOCKS = (socksPort > 0 && socksPort < 65536); - -#ifdef Q_OS_WIN - if (!hasHTTP) { - LOG("Nothing?"); - return; - } else { - LOG("Qv2ray will set system proxy to use HTTP"); - } -#else - if (!hasHTTP && !hasSOCKS) { - LOG("Nothing?"); - return; - } - - if (hasHTTP) { - LOG("Qv2ray will set system proxy to use HTTP"); - } - - if (hasSOCKS) { - LOG("Qv2ray will set system proxy to use SOCKS"); - } -#endif - -#ifdef Q_OS_WIN - QString str = NekoGui::dataStore->system_proxy_format; - if (str.isEmpty()) str = Preset::Windows::system_proxy_format[0]; - str = str.replace("{ip}", address) - .replace("{http_port}", Int2String(httpPort)) - .replace("{socks_port}", Int2String(socksPort)); - // - LOG("Windows proxy string: " + str); - auto proxyStrW = new WCHAR[str.length() + 1]; - wcscpy(proxyStrW, str.toStdWString().c_str()); - // - __QueryProxyOptions(); - - if (!__SetProxyOptions(proxyStrW, false)) { - LOG("Failed to set proxy."); - } - - __QueryProxyOptions(); -#elif defined(Q_OS_LINUX) - QList actions; - actions << ProcessArgument{"gsettings", {"set", "org.gnome.system.proxy", "mode", "manual"}}; - // - bool isKDE = qEnvironmentVariable("XDG_SESSION_DESKTOP") == "KDE" || - qEnvironmentVariable("XDG_SESSION_DESKTOP") == "plasma"; - const auto configPath = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation); - - // - // Configure HTTP Proxies for HTTP, FTP and HTTPS - if (hasHTTP) { - // iterate over protocols... - for (const auto &protocol: QStringList{"http", "ftp", "https"}) { - // for GNOME: - { - actions << ProcessArgument{"gsettings", - {"set", "org.gnome.system.proxy." + protocol, "host", address}}; - actions << ProcessArgument{"gsettings", - {"set", "org.gnome.system.proxy." + protocol, "port", QSTRN(httpPort)}}; - } - - // for KDE: - if (isKDE) { - actions << ProcessArgument{"kwriteconfig5", - {"--file", configPath + "/kioslaverc", // - "--group", "Proxy Settings", // - "--key", protocol + "Proxy", // - "http://" + address + " " + QSTRN(httpPort)}}; - } - } - } - - // Configure SOCKS5 Proxies - if (hasSOCKS) { - // for GNOME: - { - actions << ProcessArgument{"gsettings", {"set", "org.gnome.system.proxy.socks", "host", address}}; - actions << ProcessArgument{"gsettings", - {"set", "org.gnome.system.proxy.socks", "port", QSTRN(socksPort)}}; - - // for KDE: - if (isKDE) { - actions << ProcessArgument{"kwriteconfig5", - {"--file", configPath + "/kioslaverc", // - "--group", "Proxy Settings", // - "--key", "socksProxy", // - "socks://" + address + " " + QSTRN(socksPort)}}; - } - } - } - // Setting Proxy Mode to Manual - { - // for GNOME: - { - actions << ProcessArgument{"gsettings", {"set", "org.gnome.system.proxy", "mode", "manual"}}; - } - - // for KDE: - if (isKDE) { - actions << ProcessArgument{"kwriteconfig5", - {"--file", configPath + "/kioslaverc", // - "--group", "Proxy Settings", // - "--key", "ProxyType", "1"}}; - } - } - - // Notify kioslaves to reload system proxy configuration. - if (isKDE) { - actions << ProcessArgument{"dbus-send", - {"--type=signal", "/KIO/Scheduler", // - "org.kde.KIO.Scheduler.reparseSlaveConfiguration", // - "string:''"}}; - } - // Execute them all! - // - // note: do not use std::all_of / any_of / none_of, - // because those are short-circuit and cannot guarantee atomicity. - QList results; - for (const auto &action: actions) { - // execute and get the code - const auto returnCode = QProcess::execute(action.first, action.second); - // print out the commands and result codes - DEBUG(QString("[%1] Program: %2, Args: %3").arg(returnCode).arg(action.first).arg(action.second.join(";"))); - // give the code back - results << (returnCode == QProcess::NormalExit); - } - - if (results.count(true) != actions.size()) { - LOG("Something wrong when setting proxies."); - } -#else - - for (const auto &service: macOSgetNetworkServices()) { - LOG("Setting proxy for interface: " + service); - if (hasHTTP) { - QProcess::execute("/usr/sbin/networksetup", {"-setwebproxystate", service, "on"}); - QProcess::execute("/usr/sbin/networksetup", {"-setsecurewebproxystate", service, "on"}); - QProcess::execute("/usr/sbin/networksetup", {"-setwebproxy", service, address, QSTRN(httpPort)}); - QProcess::execute("/usr/sbin/networksetup", {"-setsecurewebproxy", service, address, QSTRN(httpPort)}); - } - - if (hasSOCKS) { - QProcess::execute("/usr/sbin/networksetup", {"-setsocksfirewallproxystate", service, "on"}); - QProcess::execute("/usr/sbin/networksetup", {"-setsocksfirewallproxy", service, address, QSTRN(socksPort)}); - } - } - -#endif - } - - void ClearSystemProxy() { - LOG("Clearing System Proxy"); - -#ifdef Q_OS_WIN - if (!__SetProxyOptions(nullptr, false)) { - LOG("Failed to clear proxy."); - } -#elif defined(Q_OS_LINUX) - QList actions; - const bool isKDE = qEnvironmentVariable("XDG_SESSION_DESKTOP") == "KDE" || - qEnvironmentVariable("XDG_SESSION_DESKTOP") == "plasma"; - const auto configRoot = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation); - - // Setting System Proxy Mode to: None - { - // for GNOME: - { - actions << ProcessArgument{"gsettings", {"set", "org.gnome.system.proxy", "mode", "none"}}; - } - - // for KDE: - if (isKDE) { - actions << ProcessArgument{"kwriteconfig5", - {"--file", configRoot + "/kioslaverc", // - "--group", "Proxy Settings", // - "--key", "ProxyType", "0"}}; - } - } - - // Notify kioslaves to reload system proxy configuration. - if (isKDE) { - actions << ProcessArgument{"dbus-send", - {"--type=signal", "/KIO/Scheduler", // - "org.kde.KIO.Scheduler.reparseSlaveConfiguration", // - "string:''"}}; - } - - // Execute the Actions - for (const auto &action: actions) { - // execute and get the code - const auto returnCode = QProcess::execute(action.first, action.second); - // print out the commands and result codes - DEBUG(QString("[%1] Program: %2, Args: %3").arg(returnCode).arg(action.first).arg(action.second.join(";"))); - } - -#else - for (const auto &service: macOSgetNetworkServices()) { - LOG("Clearing proxy for interface: " + service); - QProcess::execute("/usr/sbin/networksetup", {"-setautoproxystate", service, "off"}); - QProcess::execute("/usr/sbin/networksetup", {"-setwebproxystate", service, "off"}); - QProcess::execute("/usr/sbin/networksetup", {"-setsecurewebproxystate", service, "off"}); - QProcess::execute("/usr/sbin/networksetup", {"-setsocksfirewallproxystate", service, "off"}); - } - -#endif - } -} // namespace Qv2ray::components::proxy diff --git a/3rdparty/qv2ray/v2/components/proxy/QvProxyConfigurator.hpp b/3rdparty/qv2ray/v2/components/proxy/QvProxyConfigurator.hpp deleted file mode 100644 index eaa2c0f..0000000 --- a/3rdparty/qv2ray/v2/components/proxy/QvProxyConfigurator.hpp +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include -#include -#include -// -namespace Qv2ray::components::proxy { - void ClearSystemProxy(); - void SetSystemProxy(int http_port, int socks_port); -} // namespace Qv2ray::components::proxy - -using namespace Qv2ray::components; -using namespace Qv2ray::components::proxy; diff --git a/3rdparty/qv2ray/v3/components/GeositeReader/GeositeReader.cpp b/3rdparty/qv2ray/v3/components/GeositeReader/GeositeReader.cpp deleted file mode 100644 index 562e986..0000000 --- a/3rdparty/qv2ray/v3/components/GeositeReader/GeositeReader.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include "GeositeReader.hpp" - -#include "3rdparty/qv2ray/wrapper.hpp" -#include "picoproto.hpp" - -#include -#include - -namespace Qv2ray::components::GeositeReader { - QMap GeositeEntries; - - QStringList ReadGeoSiteFromFile(const QString &filepath, bool allowCache) { - if (GeositeEntries.contains(filepath) && allowCache) - return GeositeEntries.value(filepath); - - QStringList list; - qInfo() << "Reading geosites from:" << filepath; - QFile f(filepath); - bool opened = f.open(QFile::OpenModeFlag::ReadOnly); - - if (!opened) { - qInfo() << "File cannot be opened:" << filepath; - return list; - } - - const auto content = f.readAll(); - f.close(); - { - picoproto::Message root; - root.ParseFromBytes((unsigned char *) content.data(), content.size()); - - list.reserve(root.GetMessageArray(1).size()); - for (const auto &geosite: root.GetMessageArray(1)) - list << QString::fromStdString(geosite->GetString(1)); - } - - qInfo() << "Loaded" << list.count() << "geosite entries from data file."; - list.sort(); - GeositeEntries[filepath] = list; - return list; - } -} // namespace Qv2ray::components::GeositeReader diff --git a/3rdparty/qv2ray/v3/components/GeositeReader/GeositeReader.hpp b/3rdparty/qv2ray/v3/components/GeositeReader/GeositeReader.hpp deleted file mode 100644 index 8bafd6d..0000000 --- a/3rdparty/qv2ray/v3/components/GeositeReader/GeositeReader.hpp +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include - -namespace Qv2ray::components::GeositeReader { - QStringList ReadGeoSiteFromFile(const QString &filepath, bool allowCache = true); -} // namespace Qv2ray::components::GeositeReader diff --git a/3rdparty/qv2ray/v3/components/GeositeReader/picoproto.cpp b/3rdparty/qv2ray/v3/components/GeositeReader/picoproto.cpp deleted file mode 100644 index 786c1fd..0000000 --- a/3rdparty/qv2ray/v3/components/GeositeReader/picoproto.cpp +++ /dev/null @@ -1,551 +0,0 @@ -/* Copyright 2016 Pete Warden. All Rights Reserved. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - ==============================================================================*/ - -#include "picoproto.hpp" - -namespace picoproto { - - namespace { - - // To keep the dependencies down, here's a local copy of the widespread bit_cast - // operator. This is necessary because in practice weird things can happen if - // you just try to use reinterpret_cast. - template - inline Dest bit_cast(const Source &source) { - static_assert(sizeof(Dest) == sizeof(Source), "Sizes do not match"); - Dest dest; - memcpy(&dest, &source, sizeof(dest)); - return dest; - } - - // These are defined in: - // https://developers.google.com/protocol-buffers/docs/encoding - enum WireType { - WIRETYPE_VARINT = 0, - WIRETYPE_64BIT = 1, - WIRETYPE_LENGTH_DELIMITED = 2, - WIRETYPE_GROUP_START = 3, - WIRETYPE_GROUP_END = 4, - WIRETYPE_32BIT = 5, - }; - - // Pull bytes from the stream, updating the state. - bool ConsumeBytes(uint8_t **current, size_t how_many, size_t *remaining) { - if (how_many > *remaining) { - PP_LOG(ERROR) << "ReadBytes overrun!"; - return false; - } - *current += how_many; - *remaining -= how_many; - return true; - } - - // Grabs a particular type from the byte stream. - template - T ReadFromBytes(uint8_t **current, size_t *remaining) { - PP_CHECK(ConsumeBytes(current, sizeof(T), remaining)); - const T result = *(bit_cast(*current - sizeof(T))); - return result; - } - - uint64_t ReadVarInt(uint8_t **current, size_t *remaining) { - uint64_t result = 0; - bool keep_going; - int shift = 0; - do { - const uint8_t next_number = ReadFromBytes(current, remaining); - keep_going = (next_number >= 128); - result += (uint64_t) (next_number & 0x7f) << shift; - shift += 7; - } while (keep_going); - return result; - } - - void ReadWireTypeAndFieldNumber(uint8_t **current, size_t *remaining, uint8_t *wire_type, uint32_t *field_number) { - uint64_t wire_type_and_field_number = ReadVarInt(current, remaining); - *wire_type = wire_type_and_field_number & 0x07; - *field_number = wire_type_and_field_number >> 3; - } - - } // namespace - - std::string FieldTypeDebugString(enum FieldType type) { - switch (type) { - case FIELD_UNSET: - return "UNSET"; - break; - case FIELD_UINT32: - return "UINT32"; - break; - case FIELD_UINT64: - return "UINT64"; - break; - case FIELD_BYTES: - return "BYTES"; - break; - default: - return "Unknown field type"; - break; - } - return "Should never get here"; - } - - Field::Field(FieldType type, bool owns_data) : type(type), owns_data(owns_data) { - cached_messages = nullptr; - switch (type) { - case FIELD_UINT32: { - value.v_uint32 = new std::vector(); - } break; - case FIELD_UINT64: { - value.v_uint64 = new std::vector(); - } break; - case FIELD_BYTES: { - value.v_bytes = new std::vector>(); - cached_messages = new std::vector(); - } break; - default: { - PP_LOG(ERROR) << "Bad field type when constructing field: " << type; - } break; - } - } - - Field::Field(const Field &other) : type(other.type), owns_data(other.owns_data) { - switch (type) { - case FIELD_UINT32: { - value.v_uint32 = new std::vector(*other.value.v_uint32); - } break; - case FIELD_UINT64: { - value.v_uint64 = new std::vector(*other.value.v_uint64); - } break; - case FIELD_BYTES: { - if (owns_data) { - value.v_bytes = new std::vector>(); - for (std::pair data_info: *other.value.v_bytes) { - uint8_t *new_data = new uint8_t[data_info.second]; - std::copy_n(data_info.first, data_info.second, new_data); - value.v_bytes->push_back({new_data, data_info.second}); - } - } else { - value.v_bytes = new std::vector>(*other.value.v_bytes); - } - cached_messages = new std::vector(); - cached_messages->reserve(other.cached_messages->size()); - for (Message *other_cached_message: *other.cached_messages) { - Message *cached_message; - if (other_cached_message) { - cached_message = new Message(*other_cached_message); - } else { - cached_message = nullptr; - } - cached_messages->push_back(cached_message); - } - } break; - default: { - PP_LOG(ERROR) << "Bad field type when constructing field: " << type; - } break; - } - } - - Field::~Field() { - switch (type) { - case FIELD_UINT32: - delete value.v_uint32; - break; - case FIELD_UINT64: - delete value.v_uint64; - break; - case FIELD_BYTES: { - if (owns_data) - for (std::pair data_info: *value.v_bytes) - delete[] data_info.first; - delete value.v_bytes; - - for (Message *cached_message: *cached_messages) - if (cached_message) - delete cached_message; - delete cached_messages; - break; - } - default: - PP_LOG(ERROR) << "Bad field type when destroying field: " << type; - break; - } - } - - Message::Message() : Message(true){}; - - Message::Message(bool copy_arrays) : copy_arrays(copy_arrays){}; - - Message::Message(const Message &other) : field_map(other.field_map), fields(other.fields), copy_arrays(other.copy_arrays){}; - - Message::~Message(){}; - - bool Message::ParseFromBytes(uint8_t *bytes, size_t bytes_size) { - uint8_t *current = bytes; - size_t remaining = bytes_size; - while (remaining > 0) { - uint8_t wire_type; - uint32_t field_number; - ReadWireTypeAndFieldNumber(¤t, &remaining, &wire_type, &field_number); - switch (wire_type) { - case WIRETYPE_VARINT: { - Field *field = AddField(field_number, FIELD_UINT64); - const uint64_t varint = ReadVarInt(¤t, &remaining); - field->value.v_uint64->push_back(varint); - break; - } - case WIRETYPE_64BIT: { - Field *field = AddField(field_number, FIELD_UINT64); - const uint64_t value = ReadFromBytes(¤t, &remaining); - field->value.v_uint64->push_back(value); - break; - } - case WIRETYPE_LENGTH_DELIMITED: { - Field *field = AddField(field_number, FIELD_BYTES); - const uint64_t size = ReadVarInt(¤t, &remaining); - uint8_t *data; - if (copy_arrays) { - data = new uint8_t[size]; - std::copy_n(current, size, data); - field->owns_data = true; - } else { - data = current; - field->owns_data = false; - } - field->value.v_bytes->push_back({data, size}); - field->cached_messages->push_back(nullptr); - current += size; - remaining -= size; - break; - } - case WIRETYPE_GROUP_START: { - PP_LOG(INFO) << field_number << ": GROUPSTART" << std::endl; - PP_LOG(ERROR) << "Unhandled wire type encountered"; - break; - } - case WIRETYPE_GROUP_END: { - PP_LOG(INFO) << field_number << ": GROUPEND" << std::endl; - PP_LOG(ERROR) << "Unhandled wire type encountered"; - break; - } - case WIRETYPE_32BIT: { - Field *field = AddField(field_number, FIELD_UINT32); - const uint32_t value = ReadFromBytes(¤t, &remaining); - field->value.v_uint32->push_back(value); - break; - } - default: { - PP_LOG(ERROR) << "Unknown wire type encountered: " << static_cast(wire_type) << " at offset" << (bytes_size - remaining); - return false; - break; - } - } - } - return true; - } - - Field *Message::AddField(int32_t number, enum FieldType type) { - Field *field = GetField(number); - if (!field) { - fields.push_back(Field(type, copy_arrays)); - field = &fields.back(); - field_map.insert({number, fields.size() - 1}); - } - return field; - } - - Field *Message::GetField(int32_t number) { - if (field_map.count(number) == 0) - return nullptr; - return &(fields[field_map[number]]); - } - - Field *Message::GetFieldAndCheckType(int32_t number, enum FieldType type) { - Field *field = GetField(number); - PP_CHECK(field) << "No field for " << number; - PP_CHECK(field->type == type) << "For field " << number << " wanted type " << FieldTypeDebugString(type) << " but found " << FieldTypeDebugString(field->type); - return field; - } - - int32_t Message::GetInt32(int32_t number) { - Field *field = GetFieldAndCheckType(number, FIELD_UINT32); - uint32_t first_value = (*(field->value.v_uint32))[0]; - int32_t zig_zag_decoded = static_cast((first_value >> 1) ^ (-(first_value & 1))); - return zig_zag_decoded; - } - - int64_t Message::GetInt64(int32_t number) { - Field *field = GetFieldAndCheckType(number, FIELD_UINT64); - uint64_t first_value = (*(field->value.v_uint64))[0]; - int64_t zig_zag_decoded = static_cast((first_value >> 1) ^ (-(first_value & 1))); - return zig_zag_decoded; - } - - uint32_t Message::GetUInt32(int32_t number) { - Field *field = GetFieldAndCheckType(number, FIELD_UINT32); - uint32_t first_value = (*(field->value.v_uint32))[0]; - return first_value; - } - - uint64_t Message::GetUInt64(int32_t number) { - Field *field = GetFieldAndCheckType(number, FIELD_UINT64); - uint64_t first_value = (*(field->value.v_uint64))[0]; - return first_value; - } - - int64_t Message::GetInt(int32_t number) { - Field *field = GetField(number); - PP_CHECK(field) << "No field for " << number; - PP_CHECK((field->type == FIELD_UINT32) || (field->type == FIELD_UINT64)) - << "For field " << number << " wanted integer type but found " << FieldTypeDebugString(field->type); - switch (field->type) { - case FIELD_UINT32: - return GetInt32(number); - break; - case FIELD_UINT64: - return GetInt64(number); - break; - default: { - // Should never get here. - } break; - } - // Should never get here. - return 0; - } - - bool Message::GetBool(int32_t number) { - return (GetInt(number) != 0); - } - - float Message::GetFloat(int32_t number) { - uint32_t int_value = GetUInt32(number); - float float_value = *(bit_cast(&int_value)); - return float_value; - } - - double Message::GetDouble(int32_t number) { - uint64_t int_value = GetUInt64(number); - return *(bit_cast(&int_value)); - } - - std::pair Message::GetBytes(int32_t number) { - Field *field = GetFieldAndCheckType(number, FIELD_BYTES); - std::pair first_value = (*(field->value.v_bytes))[0]; - return first_value; - } - - std::string Message::GetString(int32_t number) { - Field *field = GetFieldAndCheckType(number, FIELD_BYTES); - std::pair first_value = (*(field->value.v_bytes))[0]; - std::string result(first_value.first, first_value.first + first_value.second); - return result; - } - - Message *Message::GetMessage(int32_t number) { - Field *field = GetFieldAndCheckType(number, FIELD_BYTES); - Message *cached_message = field->cached_messages->at(0); - if (!cached_message) { - std::pair first_value = (*(field->value.v_bytes))[0]; - cached_message = new Message(copy_arrays); - cached_message->ParseFromBytes(first_value.first, first_value.second); - field->cached_messages->at(0) = cached_message; - } - return cached_message; - } - - std::vector Message::GetInt32Array(int32_t number) { - std::vector raw_array = GetUInt64Array(number); - std::vector result; - result.reserve(raw_array.size()); - for (uint64_t raw_value: raw_array) { - int32_t zig_zag_decoded = static_cast((raw_value >> 1) ^ (-(raw_value & 1))); - result.push_back(zig_zag_decoded); - } - return result; - } - - std::vector Message::GetInt64Array(int32_t number) { - std::vector raw_array = GetUInt64Array(number); - std::vector result; - result.reserve(raw_array.size()); - for (uint64_t raw_value: raw_array) { - int64_t zig_zag_decoded = static_cast((raw_value >> 1) ^ (-(raw_value & 1))); - result.push_back(zig_zag_decoded); - } - return result; - } - - std::vector Message::GetUInt32Array(int32_t number) { - std::vector raw_array = GetUInt64Array(number); - std::vector result; - result.reserve(raw_array.size()); - for (uint64_t raw_value: raw_array) { - result.push_back(static_cast(raw_value)); - } - return result; - } - - std::vector Message::GetUInt64Array(int32_t number) { - std::vector result; - Field *field = GetField(number); - if (!field) { - return result; - } - if (field->type == FIELD_UINT64) { - result.reserve(field->value.v_uint64->size()); - for (uint64_t value: *field->value.v_uint64) { - result.push_back(static_cast(value)); - } - } else if (field->type == FIELD_UINT32) { - result.reserve(field->value.v_uint32->size()); - for (uint32_t value: *field->value.v_uint32) { - result.push_back(static_cast(value)); - } - } else if (field->type == FIELD_BYTES) { - for (std::pair data_info: *field->value.v_bytes) { - uint8_t *current = data_info.first; - size_t remaining = data_info.second; - while (remaining > 0) { - const uint64_t varint = ReadVarInt(¤t, &remaining); - result.push_back(static_cast(varint)); - } - } - } else { - PP_LOG(ERROR) << "Expected field type UINT32, UINT64, or BYTES but got " << FieldTypeDebugString(field->type); - } - return result; - } - - std::vector Message::GetBoolArray(int32_t number) { - std::vector raw_array = GetUInt64Array(number); - std::vector result; - result.reserve(raw_array.size()); - for (uint64_t raw_value: raw_array) { - result.push_back(raw_value != 0); - } - return result; - } - - std::vector Message::GetFloatArray(int32_t number) { - std::vector result; - Field *field = GetField(number); - if (!field) { - return result; - } - if (field->type == FIELD_UINT32) { - result.reserve(field->value.v_uint32->size()); - for (uint32_t value: *field->value.v_uint32) { - result.push_back(bit_cast(value)); - } - } else if (field->type == FIELD_BYTES) { - for (std::pair data_info: *field->value.v_bytes) { - uint8_t *current = data_info.first; - size_t remaining = data_info.second; - while (remaining > 0) { - const uint64_t varint = ReadVarInt(¤t, &remaining); - const uint32_t varint32 = static_cast(varint & 0xffffffff); - result.push_back(bit_cast(varint32)); - } - } - } else { - PP_LOG(ERROR) << "Expected field type UINT32 or BYTES but got " << FieldTypeDebugString(field->type); - } - return result; - } - - std::vector Message::GetDoubleArray(int32_t number) { - std::vector result; - Field *field = GetField(number); - if (!field) { - return result; - } - if (field->type == FIELD_UINT64) { - result.reserve(field->value.v_uint64->size()); - for (uint64_t value: *field->value.v_uint64) { - result.push_back(bit_cast(value)); - } - } else if (field->type == FIELD_BYTES) { - for (std::pair data_info: *field->value.v_bytes) { - uint8_t *current = data_info.first; - size_t remaining = data_info.second; - while (remaining > 0) { - const uint64_t varint = ReadVarInt(¤t, &remaining); - result.push_back(bit_cast(varint)); - } - } - } else { - PP_LOG(ERROR) << "Expected field type UINT64 or BYTES but got " << FieldTypeDebugString(field->type); - } - return result; - } - - std::vector> Message::GetByteArray(int32_t number) { - std::vector> result; - Field *field = GetField(number); - if (!field) { - return result; - } - if (field->type == FIELD_BYTES) { - result.reserve(field->value.v_bytes->size()); - for (std::pair data_info: *field->value.v_bytes) { - result.push_back(data_info); - } - } else { - PP_LOG(ERROR) << "Expected field type BYTES but got " << FieldTypeDebugString(field->type); - } - return result; - } - - std::vector Message::GetStringArray(int32_t number) { - std::vector result; - Field *field = GetField(number); - if (!field) - return result; - if (field->type == FIELD_BYTES) { - result.reserve(field->value.v_bytes->size()); - for (std::pair data_info: *field->value.v_bytes) { - result.push_back(std::string(data_info.first, data_info.first + data_info.second)); - } - } else { - PP_LOG(ERROR) << "Expected field type BYTES but got " << FieldTypeDebugString(field->type); - } - return result; - } - - std::vector Message::GetMessageArray(int32_t number) { - std::vector result; - Field *field = GetField(number); - if (!field) - return result; - - if (field->type == FIELD_BYTES) { - result.reserve(field->value.v_bytes->size()); - for (size_t i = 0; i < field->value.v_bytes->size(); ++i) { - Message *cached_message = field->cached_messages->at(i); - if (!cached_message) { - std::pair value = field->value.v_bytes->at(i); - cached_message = new Message(copy_arrays); - cached_message->ParseFromBytes(value.first, value.second); - field->cached_messages->at(i) = cached_message; - } - result.push_back(cached_message); - } - } else { - PP_LOG(ERROR) << "Expected field type BYTES but got " << FieldTypeDebugString(field->type); - } - return result; - } - -} // namespace picoproto diff --git a/3rdparty/qv2ray/v3/components/GeositeReader/picoproto.hpp b/3rdparty/qv2ray/v3/components/GeositeReader/picoproto.hpp deleted file mode 100644 index 76a1b6e..0000000 --- a/3rdparty/qv2ray/v3/components/GeositeReader/picoproto.hpp +++ /dev/null @@ -1,208 +0,0 @@ -/* Copyright 2016 Pete Warden. All Rights Reserved. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - ==============================================================================*/ - -/* - See the README for full details, but this module lets you read in protobuf - encoded files with a minimal code footprint. - - It doesn't create classes for each kind of message it encounters, it just has a - single Message interface that lets you access the members of the protobuf as a - key/value store. This loses a lot of the convenience of type-checked classes, - but it does mean that very little code is needed to access data from files. - - As a simple example, if you had read a `bytes_size` long file into `bytes` that - contained a TensorFlow GraphDef proto: - - Message graph_def; - graph_def.ParseFromBytes(bytes, bytes_size); - - You can then access the different fields of the GraphDef using the field - numbers assigned in the .proto file: - - std::vector nodes = graph_def.GetMessageArray(1); - - One big difference between this minimal approach and normal protobufs is that - the calling code has to already know the field number and type of any members - it's trying to access. Here I know that the `node` field is number 1, and that - it should contain a repeated list of NodeDefs. Since they are not primitive - types like numbers or strings, they are accessed as an array of Messages. - - Here are the design goals of this module: - - Keep the code size tiny (single-digit kilobytes on most platforms). - - Minimize memory usage (for example allow in-place references to byte data). - - Provide a simple, readable implementation that can be ported easily. - - Deserialize all saved protobuf files into a usable representation. - - No dependencies other than the standard C++ library. - - No build-time support (e.g. protoc) required. - - Here's what it's explicitly not offering: - - Providing a readable and transparent way of accessing serialized data. - - Saving out data to protobuf format. - -*/ - -#ifndef INCLUDE_PICOPROTO_H -#define INCLUDE_PICOPROTO_H - -#include -#include -#include -#include -#include -#include -#include -#include - -// To keep dependencies minimal, some bare-bones macros to make logging easier. -#define PP_LOG(X) PP_LOG_##X -#define PP_LOG_INFO std::cerr << __FILE__ << ":" << __LINE__ << " - INFO: " -#define PP_LOG_WARN std::cerr << __FILE__ << ":" << __LINE__ << " - WARN: " -#define PP_LOG_ERROR std::cerr << __FILE__ << ":" << __LINE__ << " - ERROR: " -#define PP_CHECK(X) \ - if (!(X)) \ - PP_LOG(ERROR) << "PP_CHECK(" << #X << ") failed. " - -namespace picoproto { - - // These roughly correspond to the wire types used to save data in protobuf - // files. The best reference to understand the full format is: - // https://developers.google.com/protocol-buffers/docs/encoding - // Because we don't know the bit-depth of VarInts, they're always stored as - // uint64 values, which is why there's no specific type for them. - enum FieldType { - FIELD_UNSET, - FIELD_UINT32, - FIELD_UINT64, - FIELD_BYTES, - }; - - // Gives a readable name for the field type for logging purposes. - std::string FieldTypeDebugString(enum FieldType type); - - // Forward declare the main message class, since fields can contain them. - class Message; - - // Fields are the building blocks of messages. They contain the values for each - // data member, and handle all the allocation and deallocation of storage. - // It's unlikely you'll want to access this class directly, since you'll - // normally want to use Message below to pull typed values. - class Field { - public: - // You need to specify the type of a Field on creation, so that the right - // storage can be set up for the values. You also need to indicate whether the - // underlying memory will be around for the lifetime of the message (in which - // case no copies are needed) or whether the class should make copies and take - // ownership in case the data goes away. - Field(FieldType type, bool owns_data); - Field(const Field &other); - ~Field(); - - enum FieldType type; - // I know, this isn't very OOP, but the simplicity of keeping track of a type - // and deciding how to initialize and access the data based on that persuaded - // me this was the best approach. The `value` member contains whatever data - // the field should be holding. - union { - std::vector *v_uint32; - std::vector *v_uint64; - std::vector> *v_bytes; - } value; - // One of the drawbacks of not requiring .proto files ahead of time is that I - // don't know if a length-delimited field contains raw bytes, strings, or - // sub-messages. The only time we know that a field should be interpreted as a - // message is when client code requests it in that form. Because parsing can - // be costly, here we cache the results of any such calls for subsequent - // accesses. - std::vector *cached_messages; - // If this is set, then the object will allocate its own storage for - // length-delimited values, and copy from the input stream. If you know the - // underlying data will be around for the lifetime of the message, you can - // save memory and copies by leaving this as false. - bool owns_data; - }; - - // The main interface for loading and accessing serialized protobuf data. - class Message { - public: - // If you're not sure about the lifetime of any binary data you're reading - // from, just call this default constructor. - Message(); - // In the case when you're sure the lifetime of the byte stream you'll be - // decoding is longer than the lifetime of the message, you can set - // copy_arrays to false. This is especially useful if you have a memory - // mapped file to read from containing large binary blobs, since you'll skip - // a lot of copying and extra allocation. - Message(bool copy_arrays); - Message(const Message &other); - ~Message(); - - // Populates fields with all of the data from this stream of bytes. - // You can call this repeatedly with new messages, and the results will be - // merged together. - bool ParseFromBytes(uint8_t *binary, size_t binary_size); - - // These are the accessor functions if you're expecting exactly one value in a - // field. As discussed above, the burden is on the client code to know the - // field number and type of each member it's trying to access, and so pick the - // correct accessor function. - // If the field isn't present, this will raise an error, so if it's optional - // you should use the array accessors below. - int32_t GetInt32(int32_t number); - int64_t GetInt64(int32_t number); - uint32_t GetUInt32(int32_t number); - uint64_t GetUInt64(int32_t number); - int64_t GetInt(int32_t number); - bool GetBool(int32_t number); - float GetFloat(int32_t number); - double GetDouble(int32_t number); - std::pair GetBytes(int32_t number); - std::string GetString(int32_t number); - Message *GetMessage(int32_t number); - - // If you're not sure if a value will be present, or if it is repeated, you - // should call these array functions. If no such field has been seen, then the - // result will be an empty vector, otherwise you'll get back one or more - // entries. - std::vector GetInt32Array(int32_t number); - std::vector GetInt64Array(int32_t number); - std::vector GetUInt32Array(int32_t number); - std::vector GetUInt64Array(int32_t number); - std::vector GetBoolArray(int32_t number); - std::vector GetFloatArray(int32_t number); - std::vector GetDoubleArray(int32_t number); - std::vector> GetByteArray(int32_t number); - std::vector GetStringArray(int32_t number); - std::vector GetMessageArray(int32_t number); - - // It's unlikely you'll want to access fields directly, but here's an escape - // hatch in case you do have to manipulate them more directly. - Field *GetField(int32_t number); - - private: - // Inserts a new field, updating all the internal data structures. - Field *AddField(int32_t number, enum FieldType type); - - Field *GetFieldAndCheckType(int32_t number, enum FieldType type); - - // Maps from a field number to an index in the `fields` vector. - std::map field_map; - // The core list of fields that have been parsed. - std::vector fields; - bool copy_arrays; - }; - -} // namespace picoproto - -#endif // INCLUDE_PICOPROTO_H diff --git a/CMakeLists.txt b/CMakeLists.txt index 410698e..1c3d01f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -92,15 +92,11 @@ set(PROJECT_SOURCES 3rdparty/qv2ray/v2/ui/LogHighlighter.cpp 3rdparty/qv2ray/v2/ui/QvAutoCompleteTextEdit.cpp - 3rdparty/qv2ray/v2/components/proxy/QvProxyConfigurator.cpp 3rdparty/qv2ray/v2/ui/widgets/common/QJsonModel.cpp 3rdparty/qv2ray/v2/ui/widgets/editors/w_JsonEditor.cpp 3rdparty/qv2ray/v2/ui/widgets/editors/w_JsonEditor.hpp 3rdparty/qv2ray/v2/ui/widgets/editors/w_JsonEditor.ui - 3rdparty/qv2ray/v3/components/GeositeReader/GeositeReader.cpp - 3rdparty/qv2ray/v3/components/GeositeReader/picoproto.cpp - rpc/gRPC.cpp db/Database.cpp diff --git a/db/ConfigBuilder.cpp b/db/ConfigBuilder.cpp index b5508fd..07a89e7 100644 --- a/db/ConfigBuilder.cpp +++ b/db/ConfigBuilder.cpp @@ -453,14 +453,6 @@ namespace NekoGui { inboundObj["sniff"] = true; inboundObj["sniff_override_destination"] = dataStore->routing->sniffing_mode == SniffingMode::FOR_DESTINATION; } - if (dataStore->inbound_auth->NeedAuth()) { - inboundObj["users"] = QJsonArray{ - QJsonObject{ - {"username", dataStore->inbound_auth->username}, - {"password", dataStore->inbound_auth->password}, - }, - }; - } inboundObj["domain_strategy"] = dataStore->routing->domain_strategy; status->inbounds += inboundObj; } diff --git a/fmt/Bean2Link.cpp b/fmt/Bean2Link.cpp index 7dccb34..e792a6c 100644 --- a/fmt/Bean2Link.cpp +++ b/fmt/Bean2Link.cpp @@ -121,80 +121,59 @@ namespace NekoGui_fmt { } QString VMessBean::ToShareLink() { - if (NekoGui::dataStore->old_share_link_format) { - // v2rayN format - QJsonObject N{ - {"v", "2"}, - {"ps", name}, - {"add", serverAddress}, - {"port", Int2String(serverPort)}, - {"id", uuid}, - {"aid", Int2String(aid)}, - {"net", stream->network}, - {"host", stream->host}, - {"path", stream->path}, - {"type", stream->header_type}, - {"scy", security}, - {"tls", stream->security == "tls" ? "tls" : ""}, - {"sni", stream->sni}, - }; - return "vmess://" + QJsonObject2QString(N, true).toUtf8().toBase64(); + QUrl url; + QUrlQuery query; + url.setScheme("vmess"); + url.setUserName(uuid); + url.setHost(serverAddress); + url.setPort(serverPort); + if (!name.isEmpty()) url.setFragment(name); + + query.addQueryItem("encryption", security); + + // security + auto security = stream->security; + if (security == "tls" && !stream->reality_pbk.trimmed().isEmpty()) security = "reality"; + query.addQueryItem("security", security); + + if (!stream->sni.isEmpty()) query.addQueryItem("sni", stream->sni); + if (stream->allow_insecure) query.addQueryItem("allowInsecure", "1"); + if (stream->utlsFingerprint.isEmpty()) { + query.addQueryItem("fp", NekoGui::dataStore->utlsFingerprint); } else { - // ducksoft format - QUrl url; - QUrlQuery query; - url.setScheme("vmess"); - url.setUserName(uuid); - url.setHost(serverAddress); - url.setPort(serverPort); - if (!name.isEmpty()) url.setFragment(name); - - query.addQueryItem("encryption", security); - - // security - auto security = stream->security; - if (security == "tls" && !stream->reality_pbk.trimmed().isEmpty()) security = "reality"; - query.addQueryItem("security", security); - - if (!stream->sni.isEmpty()) query.addQueryItem("sni", stream->sni); - if (stream->allow_insecure) query.addQueryItem("allowInsecure", "1"); - if (stream->utlsFingerprint.isEmpty()) { - query.addQueryItem("fp", NekoGui::dataStore->utlsFingerprint); - } else { - query.addQueryItem("fp", stream->utlsFingerprint); - } - - if (security == "reality") { - query.addQueryItem("pbk", stream->reality_pbk); - if (!stream->reality_sid.isEmpty()) query.addQueryItem("sid", stream->reality_sid); - if (!stream->reality_spx.isEmpty()) query.addQueryItem("spx", stream->reality_spx); - } - - // type - query.addQueryItem("type", stream->network); - - if (stream->network == "ws" || stream->network == "http" || stream->network == "httpupgrade") { - if (!stream->path.isEmpty()) query.addQueryItem("path", stream->path); - if (!stream->host.isEmpty()) query.addQueryItem("host", stream->host); - } else if (stream->network == "grpc") { - if (!stream->path.isEmpty()) query.addQueryItem("serviceName", stream->path); - } else if (stream->network == "tcp") { - if (stream->header_type == "http") { - query.addQueryItem("headerType", "http"); - query.addQueryItem("host", stream->host); - } - } - - // mux - if (mux_state == 1) { - query.addQueryItem("mux", "true"); - } else if (mux_state == 2) { - query.addQueryItem("mux", "false"); - } - - url.setQuery(query); - return url.toString(QUrl::FullyEncoded); + query.addQueryItem("fp", stream->utlsFingerprint); } + + if (security == "reality") { + query.addQueryItem("pbk", stream->reality_pbk); + if (!stream->reality_sid.isEmpty()) query.addQueryItem("sid", stream->reality_sid); + if (!stream->reality_spx.isEmpty()) query.addQueryItem("spx", stream->reality_spx); + } + + // type + query.addQueryItem("type", stream->network); + + if (stream->network == "ws" || stream->network == "http" || stream->network == "httpupgrade") { + if (!stream->path.isEmpty()) query.addQueryItem("path", stream->path); + if (!stream->host.isEmpty()) query.addQueryItem("host", stream->host); + } else if (stream->network == "grpc") { + if (!stream->path.isEmpty()) query.addQueryItem("serviceName", stream->path); + } else if (stream->network == "tcp") { + if (stream->header_type == "http") { + query.addQueryItem("headerType", "http"); + query.addQueryItem("host", stream->host); + } + } + + // mux + if (mux_state == 1) { + query.addQueryItem("mux", "true"); + } else if (mux_state == 2) { + query.addQueryItem("mux", "false"); + } + + url.setQuery(query); + return url.toString(QUrl::FullyEncoded); } QString NaiveBean::ToShareLink() { diff --git a/main/HTTPRequestHelper.cpp b/main/HTTPRequestHelper.cpp index 2df78cd..ee16842 100644 --- a/main/HTTPRequestHelper.cpp +++ b/main/HTTPRequestHelper.cpp @@ -3,6 +3,11 @@ #include #include #include +#include +#include +#include +#include +#include #include "cpr/cpr.h" #include "main/NekoGui.hpp" @@ -11,14 +16,10 @@ namespace NekoGui_network { NekoHTTPResponse NetworkRequestHelper::HttpGet(const QString &url) { cpr::Session session; - if (NekoGui::dataStore->sub_use_proxy) { + if (NekoGui::dataStore->sub_use_proxy || NekoGui::dataStore->spmode_system_proxy) { session.SetProxies({{"http", "127.0.0.1:" + QString(Int2String(NekoGui::dataStore->inbound_socks_port)).toStdString()}, {"https", "127.0.0.1:" + QString(Int2String(NekoGui::dataStore->inbound_socks_port)).toStdString()}}); - if (NekoGui::dataStore->inbound_auth->NeedAuth()) { - session.SetProxyAuth(cpr::ProxyAuthentication{{"http", - cpr::EncodedAuthentication{NekoGui::dataStore->inbound_auth->username.toStdString(), NekoGui::dataStore->inbound_auth->password.toStdString()}}}); - } - if (NekoGui::dataStore->started_id < 0) { + if (NekoGui::dataStore->started_id < 0 && NekoGui::dataStore->sub_use_proxy) { return NekoHTTPResponse{QObject::tr("Request with proxy but no profile started.")}; } } @@ -46,4 +47,59 @@ namespace NekoGui_network { return ""; } + QString NetworkRequestHelper::GetLatestDownloadURL(const QString &url, const QString &assetName, bool* success) { + cpr::Session session; + session.SetUrl(cpr::Url{url.toStdString()}); + session.SetTimeout(3000); + if (NekoGui::dataStore->spmode_system_proxy) { + session.SetProxies({{"http", "127.0.0.1:" + QString(Int2String(NekoGui::dataStore->inbound_socks_port)).toStdString()}, + {"https", "127.0.0.1:" + QString(Int2String(NekoGui::dataStore->inbound_socks_port)).toStdString()}}); + } + cpr::Response r = session.Get(); + if (r.status_code != 200) { + *success = false; + return {r.status_line.c_str()}; + } + auto respObj = QString2QJsonObject(QString(r.text.c_str())); + auto assets = respObj["assets"].toArray(); + for (const auto &asset: assets) { + auto assetObj = asset.toObject(); + if (assetObj["name"] == assetName) { + *success = true; + return assetObj["browser_download_url"].toString(); + } + } + + *success = false; + return "not found"; + } + + QString NetworkRequestHelper::DownloadGeoAsset(const QString &url, const QString &fileName) { + cpr::Session session; + session.SetUrl(cpr::Url{url.toStdString()}); + session.SetTimeout(3000); + if (NekoGui::dataStore->spmode_system_proxy) { + session.SetProxies({{"http", "127.0.0.1:" + QString(Int2String(NekoGui::dataStore->inbound_socks_port)).toStdString()}, + {"https", "127.0.0.1:" + QString(Int2String(NekoGui::dataStore->inbound_socks_port)).toStdString()}}); + } + auto filePath = qApp->applicationDirPath()+ "/" + fileName; + std::ofstream fout; + fout.open(QString(filePath + ".1").toStdString(), std::ios::trunc | std::ios::out | std::ios::binary); + auto r = session.Download(fout); + fout.close(); + auto tmpFile = QFile(filePath + ".1"); + if (r.status_code != 200) { + tmpFile.remove(); + if (r.status_code == 0) { + return "Please check the URL and your network Connectivity"; + } + return r.status_line.c_str(); + } + QFile(filePath).remove(); + if (!tmpFile.rename(filePath)) { + return tmpFile.errorString(); + } + return ""; + } + } // namespace NekoGui_network diff --git a/main/HTTPRequestHelper.hpp b/main/HTTPRequestHelper.hpp index 56a940b..e721b9c 100644 --- a/main/HTTPRequestHelper.hpp +++ b/main/HTTPRequestHelper.hpp @@ -25,6 +25,10 @@ namespace NekoGui_network { static NekoHTTPResponse HttpGet(const QString &url); static QString GetHeader(const QList> &header, const QString &name); + + static QString GetLatestDownloadURL(const QString &url, const QString &assetName, bool* success); + + static QString DownloadGeoAsset(const QString &url, const QString &fileName); }; } // namespace NekoGui_network diff --git a/main/NekoGui.cpp b/main/NekoGui.cpp index 56d969d..d70a469 100644 --- a/main/NekoGui.cpp +++ b/main/NekoGui.cpp @@ -240,16 +240,12 @@ namespace NekoGui { DataStore::DataStore() : JsonStore() { _add(new configItem("extraCore", dynamic_cast(extraCore), itemType::jsonStore)); - _add(new configItem("inbound_auth", dynamic_cast(inbound_auth), itemType::jsonStore)); _add(new configItem("user_agent2", &user_agent, itemType::string)); _add(new configItem("test_url", &test_latency_url, itemType::string)); - _add(new configItem("test_url_dl", &test_download_url, itemType::string)); - _add(new configItem("test_dl_timeout", &test_download_timeout, itemType::integer)); _add(new configItem("current_group", ¤t_group, itemType::integer)); _add(new configItem("inbound_address", &inbound_address, itemType::string)); _add(new configItem("inbound_socks_port", &inbound_socks_port, itemType::integer)); - _add(new configItem("inbound_http_port", &inbound_http_port, itemType::integer)); _add(new configItem("log_level", &log_level, itemType::string)); _add(new configItem("mux_protocol", &mux_protocol, itemType::string)); _add(new configItem("mux_concurrency", &mux_concurrency, itemType::integer)); @@ -260,7 +256,6 @@ namespace NekoGui { _add(new configItem("theme", &theme, itemType::string)); _add(new configItem("custom_inbound", &custom_inbound, itemType::string)); _add(new configItem("custom_route", &custom_route_global, itemType::string)); - _add(new configItem("v2ray_asset_dir", &v2ray_asset_dir, itemType::string)); _add(new configItem("sub_use_proxy", &sub_use_proxy, itemType::boolean)); _add(new configItem("remember_id", &remember_id, itemType::integer)); _add(new configItem("remember_enable", &remember_enable, itemType::boolean)); @@ -281,8 +276,6 @@ namespace NekoGui { _add(new configItem("vpn_ipv6", &vpn_ipv6, itemType::boolean)); _add(new configItem("vpn_hide_console", &vpn_hide_console, itemType::boolean)); _add(new configItem("vpn_strict_route", &vpn_strict_route, itemType::boolean)); - _add(new configItem("check_include_pre", &check_include_pre, itemType::boolean)); - _add(new configItem("sp_format", &system_proxy_format, itemType::string)); _add(new configItem("sub_clear", &sub_clear, itemType::boolean)); _add(new configItem("sub_insecure", &sub_insecure, itemType::boolean)); _add(new configItem("sub_auto_update", &sub_auto_update, itemType::integer)); @@ -300,6 +293,8 @@ namespace NekoGui { _add(new configItem("ntp_server_address", &ntp_server_address, itemType::string)); _add(new configItem("ntp_server_port", &ntp_server_port, itemType::integer)); _add(new configItem("ntp_interval", &ntp_interval, itemType::string)); + _add(new configItem("geoip_download_url", &geoip_download_url, itemType::string)); + _add(new configItem("geosite_download_url", &geosite_download_url, itemType::string)); } void DataStore::UpdateStartedId(int id) { @@ -373,25 +368,12 @@ namespace NekoGui { core_map = QJsonObject2QString(obj, true); } - InboundAuthorization::InboundAuthorization() : JsonStore() { - _add(new configItem("user", &this->username, itemType::string)); - _add(new configItem("pass", &this->password, itemType::string)); - } - - bool InboundAuthorization::NeedAuth() const { - return !username.trimmed().isEmpty() && !password.trimmed().isEmpty(); - } - // System Utils QString FindCoreAsset(const QString &name) { - QStringList search{NekoGui::dataStore->v2ray_asset_dir}; - search << QApplication::applicationDirPath(); + QStringList search{QApplication::applicationDirPath()}; search << "/usr/share/sing-geoip"; search << "/usr/share/sing-geosite"; - search << "/usr/share/xray"; - search << "/usr/local/share/xray"; - search << "/opt/xray"; search << "/usr/share/v2ray"; search << "/usr/local/share/v2ray"; search << "/opt/v2ray"; diff --git a/main/NekoGui_DataStore.hpp b/main/NekoGui_DataStore.hpp index 9335005..ab31867 100644 --- a/main/NekoGui_DataStore.hpp +++ b/main/NekoGui_DataStore.hpp @@ -39,16 +39,6 @@ namespace NekoGui { void Delete(const QString &id); }; - class InboundAuthorization : public JsonStore { - public: - QString username; - QString password; - - InboundAuthorization(); - - [[nodiscard]] bool NeedAuth() const; - }; - class DataStore : public JsonStore { public: // Running @@ -84,10 +74,7 @@ namespace NekoGui { // Misc QString log_level = "warning"; QString test_latency_url = "http://cp.cloudflare.com/"; - QString test_download_url = "http://cachefly.cachefly.net/10mb.test"; - int test_download_timeout = 30; int test_concurrent = 5; - bool old_share_link_format = true; int traffic_loop_interval = 1000; bool disable_traffic_stats = false; int current_group = 0; // group id @@ -96,11 +83,8 @@ namespace NekoGui { int mux_concurrency = 8; bool mux_default_on = false; QString theme = "0"; - QString v2ray_asset_dir = ""; int language = 0; QString mw_size = ""; - bool check_include_pre = true; - QString system_proxy_format = ""; QStringList log_ignore = {}; bool start_minimal = false; int max_log_line = 200; @@ -113,6 +97,10 @@ namespace NekoGui { bool sub_insecure = false; int sub_auto_update = -30; + // Assets + QString geoip_download_url = ""; + QString geosite_download_url = ""; + // Security bool skip_cert = false; QString utlsFingerprint = ""; @@ -124,9 +112,7 @@ namespace NekoGui { // Socks & HTTP Inbound QString inbound_address = "127.0.0.1"; - int inbound_socks_port = 2080; // or Mixed - int inbound_http_port = 2081; - InboundAuthorization *inbound_auth = new InboundAuthorization; + int inbound_socks_port = 2080; // Mixed, actually QString custom_inbound = "{\"inbounds\": []}"; // Routing diff --git a/ui/dialog_basic_settings.cpp b/ui/dialog_basic_settings.cpp index 27990e3..6f94498 100644 --- a/ui/dialog_basic_settings.cpp +++ b/ui/dialog_basic_settings.cpp @@ -7,6 +7,7 @@ #include "ui/Icon.hpp" #include "main/GuiUtils.hpp" #include "main/NekoGui.hpp" +#include "main/HTTPRequestHelper.hpp" #include #include @@ -58,48 +59,25 @@ DialogBasicSettings::DialogBasicSettings(QWidget *parent) ADD_ASTERISK(this); // Common - - ui->groupBox_http->hide(); ui->inbound_socks_port_l->setText(ui->inbound_socks_port_l->text().replace("Socks", "Mixed (SOCKS+HTTP)")); ui->log_level->addItems(QString("trace debug info warn error fatal panic").split(" ")); ui->mux_protocol->addItems({"h2mux", "smux", "yamux"}); ui->disable_stats->setChecked(NekoGui::dataStore->disable_traffic_stats); - refresh_auth(); - D_LOAD_STRING(inbound_address) D_LOAD_COMBO_STRING(log_level) CACHE.custom_inbound = NekoGui::dataStore->custom_inbound; D_LOAD_INT(inbound_socks_port) - D_LOAD_INT_ENABLE(inbound_http_port, http_enable) D_LOAD_INT(test_concurrent) - D_LOAD_INT(test_download_timeout) D_LOAD_STRING(test_latency_url) - D_LOAD_STRING(test_download_url) - D_LOAD_BOOL(old_share_link_format) connect(ui->custom_inbound_edit, &QPushButton::clicked, this, [=] { C_EDIT_JSON_ALLOW_EMPTY(custom_inbound) }); -#ifdef Q_OS_WIN - connect(ui->sys_proxy_format, &QPushButton::clicked, this, [=] { - bool ok; - auto str = QInputDialog::getItem(this, ui->sys_proxy_format->text() + " (Windows)", - tr("Advanced system proxy settings. Please select a format."), - Preset::Windows::system_proxy_format, - Preset::Windows::system_proxy_format.indexOf(NekoGui::dataStore->system_proxy_format), - false, &ok); - if (ok) NekoGui::dataStore->system_proxy_format = str; - }); -#else - ui->sys_proxy_format->hide(); -#endif - // Style ui->connection_statistics_box->setDisabled(true); // - D_LOAD_BOOL(check_include_pre) D_LOAD_BOOL(start_minimal) D_LOAD_INT(max_log_line) // @@ -149,9 +127,47 @@ DialogBasicSettings::DialogBasicSettings(QWidget *parent) D_LOAD_INT_ENABLE(sub_auto_update, sub_auto_update_enable) // Core - ui->groupBox_core->setTitle(software_core_name); - ui->core_v2ray_asset->setText(NekoGui::dataStore->v2ray_asset_dir); + + // Assets + ui->geoip_url->setText(NekoGui::dataStore->geoip_download_url); + ui->geosite_url->setText(NekoGui::dataStore->geosite_download_url); + connect(ui->geoip_auto_btn, &QPushButton::clicked, this, [=](){ + bool success; + auto resp = NetworkRequestHelper::GetLatestDownloadURL("https://api.github.com/repos/SagerNet/sing-geoip/releases/latest", "geoip.db", &success); + if (!success) { + runOnUiThread([=](){ + MessageBoxWarning("Error", resp); + }); + return; + } + ui->geoip_url->setText(resp); + }); + connect(ui->geosite_auto_btn, &QPushButton::clicked, this, [=](){ + bool success; + auto resp = NetworkRequestHelper::GetLatestDownloadURL("https://api.github.com/repos/SagerNet/sing-geosite/releases/latest", "geosite.db", &success); + if (!success) { + runOnUiThread([=](){ + MessageBoxWarning("Error", resp); + }); + return; + } + ui->geosite_url->setText(resp); + }); + connect(ui->download_geo_btn, &QPushButton::clicked, this, [=]() { + MW_dialog_message(Dialog_DialogBasicSettings, "DownloadAssets;"+ui->geoip_url->text()+";"+ui->geosite_url->text()); + }); + connect(ui->remove_srs_btn, &QPushButton::clicked, this, [=](){ + auto rsDir = QDir(RULE_SETS_DIR); + auto entries = rsDir.entryList(QDir::Files); + for (const auto &item: entries) { + if (!QFile(RULE_SETS_DIR + "/" + item).remove()) { + MW_show_log("Failed to remove " + item + ", stop the core then try again"); + } + } + MW_show_log("Removed all rule-set files"); + }); + // CACHE.extraCore = QString2QJsonObject(NekoGui::dataStore->extraCore->core_map); if (!CACHE.extraCore.contains("naive")) CACHE.extraCore.insert("naive", ""); @@ -164,16 +180,6 @@ DialogBasicSettings::DialogBasicSettings(QWidget *parent) extra_core_layout->addWidget(new ExtraCoreWidget(&CACHE.extraCore, s)); } // - connect(ui->core_v2ray_asset, &QLineEdit::textChanged, this, [=] { - CACHE.needRestart = true; - }); - connect(ui->core_v2ray_asset_pick, &QPushButton::clicked, this, [=] { - auto fn = QFileDialog::getExistingDirectory(this, tr("Select"), QDir::currentPath(), - QFileDialog::Option::ShowDirsOnly | QFileDialog::Option::ReadOnly); - if (!fn.isEmpty()) { - ui->core_v2ray_asset->setText(fn); - } - }); connect(ui->extra_core_add, &QPushButton::clicked, this, [=] { bool ok; auto s = QInputDialog::getText(nullptr, tr("Add"), @@ -241,17 +247,12 @@ void DialogBasicSettings::accept() { D_SAVE_COMBO_STRING(log_level) NekoGui::dataStore->custom_inbound = CACHE.custom_inbound; D_SAVE_INT(inbound_socks_port) - D_SAVE_INT_ENABLE(inbound_http_port, http_enable) D_SAVE_INT(test_concurrent) - D_SAVE_INT(test_download_timeout) D_SAVE_STRING(test_latency_url) - D_SAVE_STRING(test_download_url) - D_SAVE_BOOL(old_share_link_format) // Style NekoGui::dataStore->language = ui->language->currentIndex(); - D_SAVE_BOOL(check_include_pre) D_SAVE_BOOL(start_minimal) D_SAVE_INT(max_log_line) @@ -288,11 +289,13 @@ void DialogBasicSettings::accept() { D_SAVE_INT_ENABLE(sub_auto_update, sub_auto_update_enable) // Core - - NekoGui::dataStore->v2ray_asset_dir = ui->core_v2ray_asset->text(); NekoGui::dataStore->extraCore->core_map = QJsonObject2QString(CACHE.extraCore, true); NekoGui::dataStore->disable_traffic_stats = ui->disable_stats->isChecked(); + // Assets + NekoGui::dataStore->geoip_download_url = ui->geoip_url->text(); + NekoGui::dataStore->geosite_download_url = ui->geosite_url->text(); + // Mux D_SAVE_INT(mux_concurrency) D_SAVE_COMBO_STRING(mux_protocol) @@ -316,17 +319,6 @@ void DialogBasicSettings::accept() { QDialog::accept(); } -// slots - -void DialogBasicSettings::refresh_auth() { - ui->inbound_auth->setText({}); - if (NekoGui::dataStore->inbound_auth->NeedAuth()) { - ui->inbound_auth->setIcon(Icon::GetMaterialIcon("lock-outline")); - } else { - ui->inbound_auth->setIcon(Icon::GetMaterialIcon("lock-open-outline")); - } -} - void DialogBasicSettings::on_set_custom_icon_clicked() { auto title = ui->set_custom_icon->text(); QString user_icon_path = "./" + software_name.toLower() + ".png"; @@ -350,40 +342,6 @@ void DialogBasicSettings::on_set_custom_icon_clicked() { MW_dialog_message(Dialog_DialogBasicSettings, "UpdateIcon"); } -void DialogBasicSettings::on_inbound_auth_clicked() { - auto w = new QDialog(this); - w->setWindowTitle(tr("Inbound Auth")); - auto layout = new QGridLayout; - w->setLayout(layout); - // - auto user_l = new QLabel(tr("Username")); - auto pass_l = new QLabel(tr("Password")); - auto user = new MyLineEdit; - auto pass = new MyLineEdit; - user->setText(NekoGui::dataStore->inbound_auth->username); - pass->setText(NekoGui::dataStore->inbound_auth->password); - // - layout->addWidget(user_l, 0, 0); - layout->addWidget(user, 0, 1); - layout->addWidget(pass_l, 1, 0); - layout->addWidget(pass, 1, 1); - auto box = new QDialogButtonBox; - box->setOrientation(Qt::Horizontal); - box->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Ok); - connect(box, &QDialogButtonBox::accepted, w, [=] { - NekoGui::dataStore->inbound_auth->username = user->text(); - NekoGui::dataStore->inbound_auth->password = pass->text(); - MW_dialog_message(Dialog_DialogBasicSettings, "UpdateDataStore"); - w->accept(); - }); - connect(box, &QDialogButtonBox::rejected, w, &QDialog::reject); - layout->addWidget(box, 2, 1); - // - w->exec(); - w->deleteLater(); - refresh_auth(); -} - void DialogBasicSettings::on_core_settings_clicked() { auto w = new QDialog(this); w->setWindowTitle(software_core_name + " Core Options"); @@ -449,5 +407,4 @@ void DialogBasicSettings::on_core_settings_clicked() { ADD_ASTERISK(w) w->exec(); w->deleteLater(); - refresh_auth(); } diff --git a/ui/dialog_basic_settings.h b/ui/dialog_basic_settings.h index 3a7ff19..c022d7b 100644 --- a/ui/dialog_basic_settings.h +++ b/ui/dialog_basic_settings.h @@ -31,12 +31,8 @@ private: private slots: - void refresh_auth(); - void on_set_custom_icon_clicked(); - void on_inbound_auth_clicked(); - void on_core_settings_clicked(); }; diff --git a/ui/dialog_basic_settings.ui b/ui/dialog_basic_settings.ui index e8279ff..b2f41ad 100644 --- a/ui/dialog_basic_settings.ui +++ b/ui/dialog_basic_settings.ui @@ -30,7 +30,7 @@ - + @@ -61,47 +61,16 @@ - - - - - - - - - - - - - - Custom Inbound - - - - - - - Edit - - - - - - - - - - - Socks Listen Port + Listen Port @@ -118,30 +87,24 @@ + + + + - - + + - + - HTTP Listen Port + Custom Inbound - - - - 0 - 0 - - - - - - + - Enable + Edit @@ -176,69 +139,6 @@ - - - - - - - Download Test URL - - - - - - - - - - Timeout (s) - - - - - - - - - - - - - - - - Include Pre-release when checking update - - - - - - - Qt::Orientation::Vertical - - - - - - - Share VMess Link with v2rayN Format - - - Old Share Link Format - - - - - - - System proxy format - - - - - - @@ -587,39 +487,7 @@ - - - - Asset Location - - - - - - - - Default: dir of "nekoray" - - - - - - - Select - - - - - - - - - Loglevel - - - - @@ -649,14 +517,21 @@ - + Multiplex (mux) - + + + + Loglevel + + + + @@ -781,6 +656,93 @@ + + + Assets + + + + + + Geo Assets and Rule-sets + + + + + + <html><head/><body><p>Remove the currently generated rule-sets so that they can be regenerated</p></body></html> + + + Remove Generated Rule-sets + + + + + + + + + + + + GeoIP URL + + + + + + + + + + <html><head/><body><p>Sets the URL to the latest sing-geoip release URL</p></body></html> + + + Use Sing-Geoip + + + + + + + + + + + GeoSite URL + + + + + + + + + + <html><head/><body><p>Sets the URL to the latest sing-geosite release URL</p></body></html> + + + Use Sing-Geosite + + + + + + + + + Download and Replace Geo files + + + + + + + + + + + Extra Core @@ -799,8 +761,8 @@ 0 0 - 686 - 377 + 680 + 355 diff --git a/ui/dialog_manage_routes.cpp b/ui/dialog_manage_routes.cpp index 4358aff..5205035 100644 --- a/ui/dialog_manage_routes.cpp +++ b/ui/dialog_manage_routes.cpp @@ -3,7 +3,6 @@ #include "db/Database.hpp" #include "3rdparty/qv2ray/v2/ui/widgets/editors/w_JsonEditor.hpp" -#include "3rdparty/qv2ray/v3/components/GeositeReader/GeositeReader.hpp" #include "main/GuiUtils.hpp" #include "fmt/Preset.hpp" diff --git a/ui/mainwindow.cpp b/ui/mainwindow.cpp index ac16e05..1f1bc3d 100644 --- a/ui/mainwindow.cpp +++ b/ui/mainwindow.cpp @@ -44,6 +44,7 @@ #include #include #include +#include
void UI_InitMainWindow() { mainwindow = new MainWindow; @@ -531,6 +532,12 @@ void MainWindow::dialog_message_impl(const QString &sender, const QString &info) on_menu_exit_triggered(); } } + if (info.contains("DownloadAssets")) { + auto splitted = info.split(";"); + runOnNewThread([=](){ + DownloadAssets(splitted[1], splitted[2]); + }); + } // if (info == "RestartProgram") { this->exit_reason = 2; @@ -803,13 +810,8 @@ void MainWindow::refresh_status(const QString &traffic_update) { ui->label_running->setText(txt); } // - auto display_http = tr("None"); - if (IsValidPort(NekoGui::dataStore->inbound_http_port)) { - display_http = DisplayAddress(NekoGui::dataStore->inbound_address, NekoGui::dataStore->inbound_http_port); - } auto display_socks = DisplayAddress(NekoGui::dataStore->inbound_address, NekoGui::dataStore->inbound_socks_port); - auto inbound_txt = QString("Socks: %1\nHTTP: %2").arg(display_socks, display_http); - inbound_txt = QString("Mixed: %1").arg(display_socks); + auto inbound_txt = QString("Mixed: %1").arg(display_socks); ui->label_inbound->setText(inbound_txt); // ui->checkBox_VPN->setChecked(NekoGui::dataStore->spmode_vpn); @@ -1673,3 +1675,35 @@ bool MainWindow::StopVPNProcess(bool unconditional) { } return true; } + +void MainWindow::DownloadAssets(const QString &geoipUrl, const QString &geositeUrl) { + if (!mu_download_assets.tryLock()) { + runOnUiThread([=](){ + MessageBoxWarning("Cannot start", "Last download request has not finished yet"); + }); + return; + } + MW_show_log("Start downloading..."); + QString errors; + if (!geoipUrl.isEmpty()) { + auto resp = NetworkRequestHelper::DownloadGeoAsset(geoipUrl, "geoip.db"); + if (!resp.isEmpty()) { + MW_show_log(QString("Failed to download geoip: %1").arg(resp)); + errors += "geoip: " + resp; + } + } + if (!geositeUrl.isEmpty()) { + auto resp = NetworkRequestHelper::DownloadGeoAsset(geositeUrl, "geosite.db"); + if (!resp.isEmpty()) { + MW_show_log(QString("Failed to download geosite: %1").arg(resp)); + errors += "\ngeosite: " + resp; + } + } + mu_download_assets.unlock(); + if (!errors.isEmpty()) { + runOnUiThread([=](){ + MessageBoxWarning("Failed to download geo assets", errors); + }); + } + MW_show_log("Geo Asset update completed!"); +} \ No newline at end of file diff --git a/ui/mainwindow.h b/ui/mainwindow.h index 300de8e..deb05a2 100644 --- a/ui/mainwindow.h +++ b/ui/mainwindow.h @@ -68,6 +68,8 @@ public: bool StopVPNProcess(bool unconditional = false); + void DownloadAssets(const QString &geoipUrl, const QString &geositeUrl); + signals: void profile_selected(int id); @@ -159,6 +161,8 @@ private: QMutex mu_exit; QSemaphore sem_stopped; int exit_reason = 0; + // + QMutex mu_download_assets; QList> get_now_selected_list(); diff --git a/ui/mainwindow_grpc.cpp b/ui/mainwindow_grpc.cpp index b746b3a..fbff6cd 100644 --- a/ui/mainwindow_grpc.cpp +++ b/ui/mainwindow_grpc.cpp @@ -491,7 +491,6 @@ void MainWindow::CheckUpdate() { bool ok; libcore::UpdateReq request; request.set_action(libcore::UpdateAction::Check); - request.set_check_pre_release(NekoGui::dataStore->check_include_pre); auto response = NekoGui_rpc::defaultClient->Update(&ok, request); if (!ok) return;