diff --git a/CMakeLists.txt b/CMakeLists.txt index d8b67a6..8e8d094 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -135,6 +135,7 @@ set(PROJECT_SOURCES main/NekoRay.cpp main/NekoRay_Utils.cpp main/QJS.cpp + main/HTTPRequestHelper.cpp 3rdparty/base64.cpp 3rdparty/qrcodegen.cpp @@ -142,7 +143,6 @@ set(PROJECT_SOURCES qv2ray/v2/ui/LogHighlighter.cpp qv2ray/v2/ui/QvAutoCompleteTextEdit.cpp - qv2ray/v2/utils/HTTPRequestHelper.cpp qv2ray/v2/components/proxy/QvProxyConfigurator.cpp qv2ray/v2/ui/widgets/common/QJsonModel.cpp qv2ray/v2/ui/widgets/editors/w_JsonEditor.cpp @@ -174,7 +174,7 @@ set(PROJECT_SOURCES sys/AutoRun.cpp ui/ThemeManager.cpp - ui/TrayIcon.cpp + ui/Icon.cpp ui/mainwindow_grpc.cpp ui/mainwindow.cpp diff --git a/db/ConfigBuilder.cpp b/db/ConfigBuilder.cpp index 4e7debf..dd33f2a 100644 --- a/db/ConfigBuilder.cpp +++ b/db/ConfigBuilder.cpp @@ -100,34 +100,28 @@ namespace NekoRay { } } -#define DOMAIN_USER_RULE \ - for (const auto &line: SplitLines(dataStore->routing->proxy_domain)) { \ - if (line.startsWith("#")) continue; \ - if (dataStore->dns_routing) status->domainListDNSRemote += line; \ - status->domainListRemote += line; \ - } \ - for (const auto &line: SplitLines(dataStore->routing->direct_domain)) { \ - if (line.startsWith("#")) continue; \ - if (dataStore->dns_routing) status->domainListDNSDirect += line; \ - status->domainListDirect += line; \ - } \ - for (const auto &line: SplitLines(dataStore->routing->block_domain)) { \ - if (line.startsWith("#")) continue; \ - status->domainListBlock += line; \ +#define DOMAIN_USER_RULE \ + for (const auto &line: SplitLinesSkipSharp(dataStore->routing->proxy_domain)) { \ + if (dataStore->dns_routing) status->domainListDNSRemote += line; \ + status->domainListRemote += line; \ + } \ + for (const auto &line: SplitLinesSkipSharp(dataStore->routing->direct_domain)) { \ + if (dataStore->dns_routing) status->domainListDNSDirect += line; \ + status->domainListDirect += line; \ + } \ + for (const auto &line: SplitLinesSkipSharp(dataStore->routing->block_domain)) { \ + status->domainListBlock += line; \ } -#define IP_USER_RULE \ - for (const auto &line: SplitLines(dataStore->routing->block_ip)) { \ - if (line.startsWith("#")) continue; \ - status->ipListBlock += line; \ - } \ - for (const auto &line: SplitLines(dataStore->routing->proxy_ip)) { \ - if (line.startsWith("#")) continue; \ - status->ipListRemote += line; \ - } \ - for (const auto &line: SplitLines(dataStore->routing->direct_ip)) { \ - if (line.startsWith("#")) continue; \ - status->ipListDirect += line; \ +#define IP_USER_RULE \ + for (const auto &line: SplitLinesSkipSharp(dataStore->routing->block_ip)) { \ + status->ipListBlock += line; \ + } \ + for (const auto &line: SplitLinesSkipSharp(dataStore->routing->proxy_ip)) { \ + status->ipListRemote += line; \ + } \ + for (const auto &line: SplitLinesSkipSharp(dataStore->routing->direct_ip)) { \ + status->ipListDirect += line; \ } // V2Ray @@ -147,32 +141,49 @@ namespace NekoRay { }; // socks-in - if (InRange(dataStore->inbound_socks_port, 1, 65535) && !status->forTest) { - QJsonObject socksInbound; - socksInbound["tag"] = "socks-in"; - socksInbound["protocol"] = "socks"; - socksInbound["listen"] = dataStore->inbound_address; - socksInbound["port"] = dataStore->inbound_socks_port; - socksInbound["settings"] = QJsonObject{ - {"auth", "noauth"}, - {"udp", true}, - }; + if (IsValidPort(dataStore->inbound_socks_port) && !status->forTest) { + QJsonObject inboundObj; + inboundObj["tag"] = "socks-in"; + inboundObj["protocol"] = "socks"; + inboundObj["listen"] = dataStore->inbound_address; + inboundObj["port"] = dataStore->inbound_socks_port; + QJsonObject socksSettings = {{"udp", true}}; if (dataStore->fake_dns || dataStore->sniffing_mode != SniffingMode::DISABLE) { - socksInbound["sniffing"] = sniffing; + inboundObj["sniffing"] = sniffing; } - status->inbounds += socksInbound; + if (dataStore->inbound_auth->NeedAuth()) { + socksSettings["auth"] = "password"; + socksSettings["accounts"] = QJsonArray{ + QJsonObject{ + {"user", dataStore->inbound_auth->username}, + {"pass", dataStore->inbound_auth->password}, + }, + }; + } + inboundObj["settings"] = socksSettings; + status->inbounds += inboundObj; } // http-in - if (InRange(dataStore->inbound_http_port, 1, 65535) && !status->forTest) { - QJsonObject socksInbound; - socksInbound["tag"] = "http-in"; - socksInbound["protocol"] = "http"; - socksInbound["listen"] = dataStore->inbound_address; - socksInbound["port"] = dataStore->inbound_http_port; + if (IsValidPort(dataStore->inbound_http_port) && !status->forTest) { + QJsonObject inboundObj; + inboundObj["tag"] = "http-in"; + inboundObj["protocol"] = "http"; + inboundObj["listen"] = dataStore->inbound_address; + inboundObj["port"] = dataStore->inbound_http_port; if (dataStore->sniffing_mode != SniffingMode::DISABLE) { - socksInbound["sniffing"] = sniffing; + inboundObj["sniffing"] = sniffing; } - status->inbounds += socksInbound; + if (dataStore->inbound_auth->NeedAuth()) { + inboundObj["settings"] = QJsonObject{ + {"accounts", QJsonArray{ + QJsonObject{ + {"user", dataStore->inbound_auth->username}, + {"pass", dataStore->inbound_auth->password}, + }, + }}, + }; + } + status->inbounds += inboundObj; } // Outbounds @@ -431,12 +442,12 @@ namespace NekoRay { if (thisExternalStat > 0) { if (ent->type == "custom") { auto bean = ent->CustomBean(); - if (InRange(bean->mapping_port, 1, 65535)) { + if (IsValidPort(bean->mapping_port)) { ext_mapping_port = bean->mapping_port; } else { ext_mapping_port = MkPort(); } - if (InRange(bean->socks_port, 1, 65535)) { + if (IsValidPort(bean->socks_port)) { ext_socks_port = bean->socks_port; } else { ext_socks_port = MkPort(); @@ -617,17 +628,25 @@ namespace NekoRay { // Inbounds // mixed-in - if (InRange(dataStore->inbound_socks_port, 1, 65535) && !status->forTest) { - QJsonObject socksInbound; - socksInbound["tag"] = "mixed-in"; - socksInbound["type"] = "mixed"; - socksInbound["listen"] = dataStore->inbound_address; - socksInbound["listen_port"] = dataStore->inbound_socks_port; + if (IsValidPort(dataStore->inbound_socks_port) && !status->forTest) { + QJsonObject inboundObj; + inboundObj["tag"] = "mixed-in"; + inboundObj["type"] = "mixed"; + inboundObj["listen"] = dataStore->inbound_address; + inboundObj["listen_port"] = dataStore->inbound_socks_port; if (dataStore->sniffing_mode != SniffingMode::DISABLE) { - socksInbound["sniff"] = true; - socksInbound["sniff_override_destination"] = dataStore->sniffing_mode == SniffingMode::FOR_DESTINATION; + inboundObj["sniff"] = true; + inboundObj["sniff_override_destination"] = dataStore->sniffing_mode == SniffingMode::FOR_DESTINATION; } - status->inbounds += socksInbound; + if (dataStore->inbound_auth->NeedAuth()) { + inboundObj["users"] = QJsonArray{ + QJsonObject{ + {"username", dataStore->inbound_auth->username}, + {"password", dataStore->inbound_auth->password}, + }, + }; + } + status->inbounds += inboundObj; } // Outbounds @@ -839,26 +858,32 @@ namespace NekoRay { } QString WriteVPNSingBoxConfig() { - // + // user rule QString process_name_rule = dataStore->vpn_bypass_process.trimmed(); if (!process_name_rule.isEmpty()) { - auto arr = SplitLines(process_name_rule); + auto arr = SplitLinesSkipSharp(process_name_rule); QJsonObject rule{{"outbound", "direct"}, {"process_name", QList2QJsonArray(arr)}}; process_name_rule = "," + QJsonObject2QString(rule, false); } QString cidr_rule = dataStore->vpn_bypass_cidr.trimmed(); if (!cidr_rule.isEmpty()) { - auto arr = SplitLines(cidr_rule); + auto arr = SplitLinesSkipSharp(cidr_rule); QJsonObject rule{{"outbound", "direct"}, {"ip_cidr", QList2QJsonArray(arr)}}; cidr_rule = "," + QJsonObject2QString(rule, false); } - // + // tun name auto tun_name = "nekoray-tun"; #ifdef Q_OS_MACOS tun_name = "utun9"; #endif + // auth + QString socks_user_pass; + if (dataStore->inbound_auth->NeedAuth()) { + socks_user_pass = R"( "username": "%1", "password": "%2", )"; + socks_user_pass = socks_user_pass.arg(dataStore->inbound_auth->username, dataStore->inbound_auth->password); + } // gen config auto configFn = ":/neko/vpn/sing-box-vpn.json"; if (QFile::exists("vpn/sing-box-vpn.json")) configFn = "vpn/sing-box-vpn.json"; @@ -870,6 +895,7 @@ namespace NekoRay { .replace("%CIDR_RULE%", cidr_rule) .replace("%TUN_NAME%", tun_name) .replace("%STRICT_ROUTE%", dataStore->vpn_strict_route ? "true" : "false") + .replace("%SOCKS_USER_PASS%", socks_user_pass) .replace("%PORT%", Int2String(dataStore->inbound_socks_port)); // hook.js auto source = qjs::ReadHookJS(); @@ -891,11 +917,13 @@ namespace NekoRay { } QString WriteVPNLinuxScript(const QString &protectPath, const QString &configPath) { +#ifdef Q_OS_WIN + return {}; +#endif // gen script auto scriptFn = ":/neko/vpn/vpn-run-root.sh"; if (QFile::exists("vpn/vpn-run-root.sh")) scriptFn = "vpn/vpn-run-root.sh"; auto script = ReadFileText(scriptFn) - .replace("$PORT", Int2String(dataStore->inbound_socks_port)) .replace("./nekobox_core", QApplication::applicationDirPath() + "/nekobox_core") .replace("$PROTECT_LISTEN_PATH", protectPath) .replace("$CONFIG_PATH", configPath) diff --git a/qv2ray/v2/utils/HTTPRequestHelper.cpp b/main/HTTPRequestHelper.cpp similarity index 91% rename from qv2ray/v2/utils/HTTPRequestHelper.cpp rename to main/HTTPRequestHelper.cpp index 79b84fa..a85fc3f 100644 --- a/qv2ray/v2/utils/HTTPRequestHelper.cpp +++ b/main/HTTPRequestHelper.cpp @@ -7,9 +7,7 @@ #include "main/NekoRay.hpp" -#include "qv2ray/wrapper.hpp" - -namespace Qv2ray::common::network { +namespace NekoRay::network { NekoHTTPResponse NetworkRequestHelper::HttpGet(const QUrl &url) { QNetworkRequest request; @@ -22,13 +20,16 @@ namespace Qv2ray::common::network { p.setType(IS_NEKO_BOX ? QNetworkProxy::HttpProxy : QNetworkProxy::Socks5Proxy); p.setHostName("127.0.0.1"); p.setPort(NekoRay::dataStore->inbound_socks_port); + if (dataStore->inbound_auth->NeedAuth()) { + p.setUser(dataStore->inbound_auth->username); + p.setPassword(dataStore->inbound_auth->password); + } accessManager.setProxy(p); if (NekoRay::dataStore->started_id < 0) { return NekoHTTPResponse{QObject::tr("Request with proxy but no profile started.")}; } } if (accessManager.proxy().type() == QNetworkProxy::Socks5Proxy) { - DEBUG("Adding HostNameLookupCapability to proxy."); auto cap = accessManager.proxy().capabilities(); accessManager.proxy().setCapabilities(cap | QNetworkProxy::HostNameLookupCapability); } @@ -69,4 +70,4 @@ namespace Qv2ray::common::network { return ""; } -} // namespace Qv2ray::common::network +} // namespace NekoRay::network diff --git a/qv2ray/v2/utils/HTTPRequestHelper.hpp b/main/HTTPRequestHelper.hpp similarity index 85% rename from qv2ray/v2/utils/HTTPRequestHelper.hpp rename to main/HTTPRequestHelper.hpp index bac6962..439978e 100644 --- a/qv2ray/v2/utils/HTTPRequestHelper.hpp +++ b/main/HTTPRequestHelper.hpp @@ -6,7 +6,7 @@ #include #include -namespace Qv2ray::common::network { +namespace NekoRay::network { struct NekoHTTPResponse { QString error; QByteArray data; @@ -26,6 +26,6 @@ namespace Qv2ray::common::network { static QString GetHeader(const QList> &header, const QString &name); }; -} // namespace Qv2ray::common::network +} // namespace NekoRay::network -using namespace Qv2ray::common::network; +using namespace NekoRay::network; diff --git a/main/NekoRay.cpp b/main/NekoRay.cpp index 40a98d9..89f207d 100644 --- a/main/NekoRay.cpp +++ b/main/NekoRay.cpp @@ -17,6 +17,7 @@ namespace NekoRay { 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_agent", &user_agent, itemType::string)); _add(new configItem("test_url", &test_url, itemType::string)); @@ -112,12 +113,12 @@ namespace NekoRay { QString Routing::DisplayRouting() const { return QString("[Proxy] %1\n[Proxy] %2\n[Direct] %3\n[Direct] %4\n[Block] %5\n[Block] %6") - .arg(SplitLines(proxy_domain).join(",")) - .arg(SplitLines(proxy_ip).join(",")) - .arg(SplitLines(direct_domain).join(",")) - .arg(SplitLines(direct_ip).join(",")) - .arg(SplitLines(block_domain).join(",")) - .arg(SplitLines(block_ip).join(",")); + .arg(SplitLinesSkipSharp(proxy_domain).join(",")) + .arg(SplitLinesSkipSharp(proxy_ip).join(",")) + .arg(SplitLinesSkipSharp(direct_domain).join(",")) + .arg(SplitLinesSkipSharp(direct_ip).join(",")) + .arg(SplitLinesSkipSharp(block_domain).join(",")) + .arg(SplitLinesSkipSharp(block_ip).join(",")); } QStringList Routing::List() { @@ -163,6 +164,15 @@ namespace NekoRay { 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(); + } + // 添加关联 void JsonStore::_add(configItem *item) { _map.insert(item->name, QSharedPointer(item)); diff --git a/main/NekoRay_DataStore.hpp b/main/NekoRay_DataStore.hpp index 3ef13bc..4bb6144 100644 --- a/main/NekoRay_DataStore.hpp +++ b/main/NekoRay_DataStore.hpp @@ -34,6 +34,16 @@ namespace NekoRay { 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 @@ -98,6 +108,7 @@ namespace NekoRay { QString inbound_address = "127.0.0.1"; int inbound_socks_port = 2080; // or Mixed int inbound_http_port = -2081; + InboundAuthorization *inbound_auth = new InboundAuthorization; QString custom_inbound = "{\"inbounds\": []}"; // DNS diff --git a/main/NekoRay_Utils.cpp b/main/NekoRay_Utils.cpp index 4fcb08e..4397fb1 100644 --- a/main/NekoRay_Utils.cpp +++ b/main/NekoRay_Utils.cpp @@ -25,6 +25,16 @@ QStringList SplitLines(const QString &_string) { #endif } +QStringList SplitLinesSkipSharp(const QString &_string) { + auto lines = SplitLines(_string); + QStringList newLines; + for (const auto &line: lines) { + if (line.trimmed().startsWith("#")) continue; + newLines << line; + } + return newLines; +} + QString DecodeB64IfValid(const QString &input, QByteArray::Base64Options options) { Qt515Base64::Base64Options newOptions = Qt515Base64::Base64Option::AbortOnBase64DecodingErrors; if (options.testFlag(QByteArray::Base64UrlEncoding)) newOptions |= Qt515Base64::Base64Option::Base64UrlEncoding; @@ -134,6 +144,28 @@ int MkPort() { return port; } +QString ReadableSize(const qint64 &size) { + double sizeAsDouble = size; + static QStringList measures; + if (measures.isEmpty()) + measures << "B" + << "KiB" + << "MiB" + << "GiB" + << "TiB" + << "PiB" + << "EiB" + << "ZiB" + << "YiB"; + QStringListIterator it(measures); + QString measure(it.next()); + while (sizeAsDouble >= 1024.0 && it.hasNext()) { + measure = it.next(); + sizeAsDouble /= 1024.0; + } + return QString::fromLatin1("%1 %2").arg(sizeAsDouble, 0, 'f', 2).arg(measure); +} + bool IsIpAddress(const QString &str) { auto address = QHostAddress(str); if (address.protocol() == QAbstractSocket::IPv4Protocol || address.protocol() == QAbstractSocket::IPv6Protocol) diff --git a/main/NekoRay_Utils.hpp b/main/NekoRay_Utils.hpp index 98f054c..fb6b0c4 100644 --- a/main/NekoRay_Utils.hpp +++ b/main/NekoRay_Utils.hpp @@ -43,6 +43,8 @@ QString QStringList2Command(const QStringList &list); QStringList SplitLines(const QString &_string); +QStringList SplitLinesSkipSharp(const QString &_string); + // Base64 QString DecodeB64IfValid(const QString &input, QByteArray::Base64Options options = QByteArray::Base64Option::Base64Encoding); @@ -120,32 +122,16 @@ int MkPort(); QString DisplayTime(long long time, int formatType = 0); -inline QString ReadableSize(const qint64 &size) { - double sizeAsDouble = size; - static QStringList measures; - if (measures.isEmpty()) - measures << "B" - << "KiB" - << "MiB" - << "GiB" - << "TiB" - << "PiB" - << "EiB" - << "ZiB" - << "YiB"; - QStringListIterator it(measures); - QString measure(it.next()); - while (sizeAsDouble >= 1024.0 && it.hasNext()) { - measure = it.next(); - sizeAsDouble /= 1024.0; - } - return QString::fromLatin1("%1 %2").arg(sizeAsDouble, 0, 'f', 2).arg(measure); -} +QString ReadableSize(const qint64 &size); inline bool InRange(unsigned x, unsigned low, unsigned high) { return (low <= x && x <= high); } +inline bool IsValidPort(int port) { + return InRange(port, 1, 65535); +} + // UI QWidget *GetMessageBoxParent(); diff --git a/res/icon/material/lock-open-outline.svg b/res/icon/material/lock-open-outline.svg new file mode 100644 index 0000000..4e0291d --- /dev/null +++ b/res/icon/material/lock-open-outline.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/res/icon/material/lock-outline.svg b/res/icon/material/lock-outline.svg new file mode 100644 index 0000000..4dee801 --- /dev/null +++ b/res/icon/material/lock-outline.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/res/neko.qrc b/res/neko.qrc index 64d3cae..1b52064 100644 --- a/res/neko.qrc +++ b/res/neko.qrc @@ -6,6 +6,8 @@ icon/network-server.svg icon/dialog-question.svg icon/system-software-update.svg + icon/material/lock-open-outline.svg + icon/material/lock-outline.svg public/nekobox.png diff --git a/res/vpn/sing-box-vpn.json b/res/vpn/sing-box-vpn.json index 6949957..6679c27 100644 --- a/res/vpn/sing-box-vpn.json +++ b/res/vpn/sing-box-vpn.json @@ -27,6 +27,7 @@ "type": "socks", "tag": "nekoray-socks", "udp_fragment": true, + %SOCKS_USER_PASS% "server": "127.0.0.1", "server_port": %PORT% }, diff --git a/res/vpn/vpn-run-root.sh b/res/vpn/vpn-run-root.sh index e7fa50e..d36d322 100755 --- a/res/vpn/vpn-run-root.sh +++ b/res/vpn/vpn-run-root.sh @@ -11,7 +11,6 @@ if [ "$(uname)" == "Darwin" ]; then IS_MACOS=1 fi -[ -z $PORT ] && echo "Please set env PORT" && exit [ -z $TABLE_FWMARK ] && echo "Please set env TABLE_FWMARK" && exit command -v pkill >/dev/null 2>&1 || exit diff --git a/sub/GroupUpdater.cpp b/sub/GroupUpdater.cpp index d618b30..00f18ea 100644 --- a/sub/GroupUpdater.cpp +++ b/sub/GroupUpdater.cpp @@ -1,10 +1,9 @@ -#include "qv2ray/v2/utils/HTTPRequestHelper.hpp" - #include "db/Database.hpp" #include "db/ProfileFilter.hpp" #include "fmt/includes.h" #include "fmt/Preset.hpp" #include "main/QJS.hpp" +#include "main/HTTPRequestHelper.hpp" #include "GroupUpdater.hpp" diff --git a/translations/fa_IR.ts b/translations/fa_IR.ts index 4d64f03..c4e56f5 100644 --- a/translations/fa_IR.ts +++ b/translations/fa_IR.ts @@ -217,6 +217,18 @@ Max log lines + + Inbound Auth + + + + Username + نام کاربری + + + Password + + DialogEditGroup diff --git a/translations/zh_CN.ts b/translations/zh_CN.ts index 56bf7da..0b0f460 100644 --- a/translations/zh_CN.ts +++ b/translations/zh_CN.ts @@ -215,6 +215,18 @@ Max log lines 日志最大行数限制 + + Inbound Auth + 入站认证设置 + + + Username + 用户名 + + + Password + 密码 + DialogEditGroup diff --git a/ui/TrayIcon.cpp b/ui/Icon.cpp similarity index 85% rename from ui/TrayIcon.cpp rename to ui/Icon.cpp index d0ef1bf..d2338df 100644 --- a/ui/TrayIcon.cpp +++ b/ui/Icon.cpp @@ -1,10 +1,10 @@ -#include "TrayIcon.hpp" +#include "Icon.hpp" #include "main/NekoRay.hpp" #include -QIcon TrayIcon::GetIcon(TrayIcon::TrayIconStatus status) { +QIcon Icon::GetTrayIcon(Icon::TrayIconStatus status) { QPixmap pixmap; // software embedded icon @@ -46,3 +46,8 @@ QIcon TrayIcon::GetIcon(TrayIcon::TrayIconStatus status) { return pixmap; } + +QIcon Icon::GetMaterialIcon(const QString &name) { + QPixmap pixmap(":/icon/material/" + name + ".svg"); + return pixmap; +} diff --git a/ui/TrayIcon.hpp b/ui/Icon.hpp similarity index 50% rename from ui/TrayIcon.hpp rename to ui/Icon.hpp index d55236e..9ceae93 100644 --- a/ui/TrayIcon.hpp +++ b/ui/Icon.hpp @@ -2,7 +2,7 @@ #include -namespace TrayIcon { +namespace Icon { enum TrayIconStatus { NONE, @@ -11,6 +11,8 @@ namespace TrayIcon { VPN, }; - QIcon GetIcon(TrayIconStatus status); + QIcon GetTrayIcon(TrayIconStatus status); -} // namespace TrayIcon + QIcon GetMaterialIcon(const QString &name); + +} // namespace Icon diff --git a/ui/dialog_basic_settings.cpp b/ui/dialog_basic_settings.cpp index 36941c7..b31565d 100644 --- a/ui/dialog_basic_settings.cpp +++ b/ui/dialog_basic_settings.cpp @@ -4,6 +4,7 @@ #include "qv2ray/v2/ui/widgets/editors/w_JsonEditor.hpp" #include "fmt/Preset.hpp" #include "ui/ThemeManager.hpp" +#include "ui/Icon.hpp" #include "main/GuiUtils.hpp" #include "main/NekoRay.hpp" @@ -66,6 +67,8 @@ DialogBasicSettings::DialogBasicSettings(QWidget *parent) ui->log_level->addItems({"debug", "info", "warning", "none"}); } + refresh_auth(); + ui->socks_ip->setText(NekoRay::dataStore->inbound_address); ui->log_level->setCurrentText(NekoRay::dataStore->log_level); CACHE.custom_inbound = NekoRay::dataStore->custom_inbound; @@ -298,6 +301,17 @@ void DialogBasicSettings::accept() { QDialog::accept(); } +// slots + +void DialogBasicSettings::refresh_auth() { + ui->inbound_auth->setText({}); + if (NekoRay::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"; @@ -319,3 +333,37 @@ 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(NekoRay::dataStore->inbound_auth->username); + pass->setText(NekoRay::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, [=] { + NekoRay::dataStore->inbound_auth->username = user->text(); + NekoRay::dataStore->inbound_auth->password = pass->text(); + NekoRay::dataStore->Save(); + w->accept(); + }); + connect(box, &QDialogButtonBox::rejected, w, &QDialog::reject); + layout->addWidget(box, 2, 1); + // + w->exec(); + w->deleteLater(); + refresh_auth(); +} diff --git a/ui/dialog_basic_settings.h b/ui/dialog_basic_settings.h index 71a1440..8af3f84 100644 --- a/ui/dialog_basic_settings.h +++ b/ui/dialog_basic_settings.h @@ -31,7 +31,11 @@ private: private slots: + void refresh_auth(); + void on_set_custom_icon_clicked(); + + void on_inbound_auth_clicked(); }; #endif // DIALOG_BASIC_SETTINGS_H diff --git a/ui/dialog_basic_settings.ui b/ui/dialog_basic_settings.ui index 8ca0c68..88bb0ea 100644 --- a/ui/dialog_basic_settings.ui +++ b/ui/dialog_basic_settings.ui @@ -45,6 +45,13 @@ + + + + Auth + + + @@ -199,6 +206,13 @@ + + + + Qt::Vertical + + + diff --git a/ui/mainwindow.cpp b/ui/mainwindow.cpp index e5bfd49..6516834 100644 --- a/ui/mainwindow.cpp +++ b/ui/mainwindow.cpp @@ -8,7 +8,7 @@ #include "sys/AutoRun.hpp" #include "ui/ThemeManager.hpp" -#include "ui/TrayIcon.hpp" +#include "ui/Icon.hpp" #include "ui/edit/dialog_edit_profile.h" #include "ui/dialog_basic_settings.h" #include "ui/dialog_manage_groups.h" @@ -223,7 +223,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi // Setup Tray tray = new QSystemTrayIcon(this); // 初始化托盘对象tray - tray->setIcon(TrayIcon::GetIcon(TrayIcon::NONE)); + tray->setIcon(Icon::GetTrayIcon(Icon::NONE)); tray->setContextMenu(ui->menu_program); // 创建托盘菜单 tray->show(); // 让托盘图标显示在系统托盘上 connect(tray, &QSystemTrayIcon::activated, this, [=](QSystemTrayIcon::ActivationReason reason) { @@ -587,8 +587,7 @@ void MainWindow::neko_set_spmode(int mode, bool save) { if (mode == NekoRay::SystemProxyMode::SYSTEM_PROXY) { #if defined(Q_OS_WIN) || defined(Q_OS_MACOS) - if (mode == NekoRay::SystemProxyMode::SYSTEM_PROXY && !IS_NEKO_BOX && - !InRange(NekoRay::dataStore->inbound_http_port, 1, 65535)) { + if (mode == NekoRay::SystemProxyMode::SYSTEM_PROXY && !IS_NEKO_BOX && !IsValidPort(NekoRay::dataStore->inbound_http_port)) { auto btn = QMessageBox::warning(this, software_name, tr("Http inbound is not enabled, can't set system proxy."), "OK", tr("Settings"), "", 0, 0); @@ -646,7 +645,7 @@ void MainWindow::refresh_status(const QString &traffic_update) { } // auto display_http = tr("None"); - if (InRange(NekoRay::dataStore->inbound_http_port, 1, 65535)) { + if (IsValidPort(NekoRay::dataStore->inbound_http_port)) { display_http = DisplayAddress(NekoRay::dataStore->inbound_address, NekoRay::dataStore->inbound_http_port); } auto display_socks = DisplayAddress(NekoRay::dataStore->inbound_address, NekoRay::dataStore->inbound_socks_port); @@ -676,21 +675,23 @@ void MainWindow::refresh_status(const QString &traffic_update) { return tt.join(isTray ? "\n" : " "); }; - auto icon_status_new = TrayIcon::NONE; + auto icon_status_new = Icon::NONE; if (NekoRay::dataStore->running_spmode == NekoRay::SystemProxyMode::SYSTEM_PROXY) { - icon_status_new = TrayIcon::SYSTEM_PROXY; + icon_status_new = Icon::SYSTEM_PROXY; } else if (NekoRay::dataStore->running_spmode == NekoRay::SystemProxyMode::VPN) { - icon_status_new = TrayIcon::VPN; + icon_status_new = Icon::VPN; } else if (!running.isNull()) { - icon_status_new = TrayIcon::RUNNING; + icon_status_new = Icon::RUNNING; } + // refresh title & window icon setWindowTitle(make_title(false)); - if (icon_status_new != icon_status) QApplication::setWindowIcon(TrayIcon::GetIcon(TrayIcon::NONE)); + if (icon_status_new != icon_status) QApplication::setWindowIcon(Icon::GetTrayIcon(Icon::NONE)); + // refresh tray if (tray != nullptr) { tray->setToolTip(make_title(true)); - if (icon_status_new != icon_status) tray->setIcon(TrayIcon::GetIcon(icon_status_new)); + if (icon_status_new != icon_status) tray->setIcon(Icon::GetTrayIcon(icon_status_new)); } icon_status = icon_status_new; @@ -1310,7 +1311,7 @@ void MainWindow::show_log_impl(const QString &log) { } } -#define ADD_TO_CURRENT_ROUTE(a, b) NekoRay::dataStore->routing->a = (SplitLines(NekoRay::dataStore->routing->a) << b).join("\n"); +#define ADD_TO_CURRENT_ROUTE(a, b) NekoRay::dataStore->routing->a = (SplitLines(NekoRay::dataStore->routing->a) << (b)).join("\n"); void MainWindow::on_masterLogBrowser_customContextMenuRequested(const QPoint &pos) { QMenu *menu = ui->masterLogBrowser->createStandardContextMenu();