mirror of
https://github.com/MatsuriDayo/nekoray.git
synced 2025-12-18 04:54:38 +03:00
feat: inbound authorization
This commit is contained in:
@@ -135,6 +135,7 @@ set(PROJECT_SOURCES
|
|||||||
main/NekoRay.cpp
|
main/NekoRay.cpp
|
||||||
main/NekoRay_Utils.cpp
|
main/NekoRay_Utils.cpp
|
||||||
main/QJS.cpp
|
main/QJS.cpp
|
||||||
|
main/HTTPRequestHelper.cpp
|
||||||
|
|
||||||
3rdparty/base64.cpp
|
3rdparty/base64.cpp
|
||||||
3rdparty/qrcodegen.cpp
|
3rdparty/qrcodegen.cpp
|
||||||
@@ -142,7 +143,6 @@ set(PROJECT_SOURCES
|
|||||||
|
|
||||||
qv2ray/v2/ui/LogHighlighter.cpp
|
qv2ray/v2/ui/LogHighlighter.cpp
|
||||||
qv2ray/v2/ui/QvAutoCompleteTextEdit.cpp
|
qv2ray/v2/ui/QvAutoCompleteTextEdit.cpp
|
||||||
qv2ray/v2/utils/HTTPRequestHelper.cpp
|
|
||||||
qv2ray/v2/components/proxy/QvProxyConfigurator.cpp
|
qv2ray/v2/components/proxy/QvProxyConfigurator.cpp
|
||||||
qv2ray/v2/ui/widgets/common/QJsonModel.cpp
|
qv2ray/v2/ui/widgets/common/QJsonModel.cpp
|
||||||
qv2ray/v2/ui/widgets/editors/w_JsonEditor.cpp
|
qv2ray/v2/ui/widgets/editors/w_JsonEditor.cpp
|
||||||
@@ -174,7 +174,7 @@ set(PROJECT_SOURCES
|
|||||||
sys/AutoRun.cpp
|
sys/AutoRun.cpp
|
||||||
|
|
||||||
ui/ThemeManager.cpp
|
ui/ThemeManager.cpp
|
||||||
ui/TrayIcon.cpp
|
ui/Icon.cpp
|
||||||
|
|
||||||
ui/mainwindow_grpc.cpp
|
ui/mainwindow_grpc.cpp
|
||||||
ui/mainwindow.cpp
|
ui/mainwindow.cpp
|
||||||
|
|||||||
@@ -101,32 +101,26 @@ namespace NekoRay {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define DOMAIN_USER_RULE \
|
#define DOMAIN_USER_RULE \
|
||||||
for (const auto &line: SplitLines(dataStore->routing->proxy_domain)) { \
|
for (const auto &line: SplitLinesSkipSharp(dataStore->routing->proxy_domain)) { \
|
||||||
if (line.startsWith("#")) continue; \
|
|
||||||
if (dataStore->dns_routing) status->domainListDNSRemote += line; \
|
if (dataStore->dns_routing) status->domainListDNSRemote += line; \
|
||||||
status->domainListRemote += line; \
|
status->domainListRemote += line; \
|
||||||
} \
|
} \
|
||||||
for (const auto &line: SplitLines(dataStore->routing->direct_domain)) { \
|
for (const auto &line: SplitLinesSkipSharp(dataStore->routing->direct_domain)) { \
|
||||||
if (line.startsWith("#")) continue; \
|
|
||||||
if (dataStore->dns_routing) status->domainListDNSDirect += line; \
|
if (dataStore->dns_routing) status->domainListDNSDirect += line; \
|
||||||
status->domainListDirect += line; \
|
status->domainListDirect += line; \
|
||||||
} \
|
} \
|
||||||
for (const auto &line: SplitLines(dataStore->routing->block_domain)) { \
|
for (const auto &line: SplitLinesSkipSharp(dataStore->routing->block_domain)) { \
|
||||||
if (line.startsWith("#")) continue; \
|
|
||||||
status->domainListBlock += line; \
|
status->domainListBlock += line; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define IP_USER_RULE \
|
#define IP_USER_RULE \
|
||||||
for (const auto &line: SplitLines(dataStore->routing->block_ip)) { \
|
for (const auto &line: SplitLinesSkipSharp(dataStore->routing->block_ip)) { \
|
||||||
if (line.startsWith("#")) continue; \
|
|
||||||
status->ipListBlock += line; \
|
status->ipListBlock += line; \
|
||||||
} \
|
} \
|
||||||
for (const auto &line: SplitLines(dataStore->routing->proxy_ip)) { \
|
for (const auto &line: SplitLinesSkipSharp(dataStore->routing->proxy_ip)) { \
|
||||||
if (line.startsWith("#")) continue; \
|
|
||||||
status->ipListRemote += line; \
|
status->ipListRemote += line; \
|
||||||
} \
|
} \
|
||||||
for (const auto &line: SplitLines(dataStore->routing->direct_ip)) { \
|
for (const auto &line: SplitLinesSkipSharp(dataStore->routing->direct_ip)) { \
|
||||||
if (line.startsWith("#")) continue; \
|
|
||||||
status->ipListDirect += line; \
|
status->ipListDirect += line; \
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,32 +141,49 @@ namespace NekoRay {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// socks-in
|
// socks-in
|
||||||
if (InRange(dataStore->inbound_socks_port, 1, 65535) && !status->forTest) {
|
if (IsValidPort(dataStore->inbound_socks_port) && !status->forTest) {
|
||||||
QJsonObject socksInbound;
|
QJsonObject inboundObj;
|
||||||
socksInbound["tag"] = "socks-in";
|
inboundObj["tag"] = "socks-in";
|
||||||
socksInbound["protocol"] = "socks";
|
inboundObj["protocol"] = "socks";
|
||||||
socksInbound["listen"] = dataStore->inbound_address;
|
inboundObj["listen"] = dataStore->inbound_address;
|
||||||
socksInbound["port"] = dataStore->inbound_socks_port;
|
inboundObj["port"] = dataStore->inbound_socks_port;
|
||||||
socksInbound["settings"] = QJsonObject{
|
QJsonObject socksSettings = {{"udp", true}};
|
||||||
{"auth", "noauth"},
|
|
||||||
{"udp", true},
|
|
||||||
};
|
|
||||||
if (dataStore->fake_dns || dataStore->sniffing_mode != SniffingMode::DISABLE) {
|
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
|
// http-in
|
||||||
if (InRange(dataStore->inbound_http_port, 1, 65535) && !status->forTest) {
|
if (IsValidPort(dataStore->inbound_http_port) && !status->forTest) {
|
||||||
QJsonObject socksInbound;
|
QJsonObject inboundObj;
|
||||||
socksInbound["tag"] = "http-in";
|
inboundObj["tag"] = "http-in";
|
||||||
socksInbound["protocol"] = "http";
|
inboundObj["protocol"] = "http";
|
||||||
socksInbound["listen"] = dataStore->inbound_address;
|
inboundObj["listen"] = dataStore->inbound_address;
|
||||||
socksInbound["port"] = dataStore->inbound_http_port;
|
inboundObj["port"] = dataStore->inbound_http_port;
|
||||||
if (dataStore->sniffing_mode != SniffingMode::DISABLE) {
|
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
|
// Outbounds
|
||||||
@@ -431,12 +442,12 @@ namespace NekoRay {
|
|||||||
if (thisExternalStat > 0) {
|
if (thisExternalStat > 0) {
|
||||||
if (ent->type == "custom") {
|
if (ent->type == "custom") {
|
||||||
auto bean = ent->CustomBean();
|
auto bean = ent->CustomBean();
|
||||||
if (InRange(bean->mapping_port, 1, 65535)) {
|
if (IsValidPort(bean->mapping_port)) {
|
||||||
ext_mapping_port = bean->mapping_port;
|
ext_mapping_port = bean->mapping_port;
|
||||||
} else {
|
} else {
|
||||||
ext_mapping_port = MkPort();
|
ext_mapping_port = MkPort();
|
||||||
}
|
}
|
||||||
if (InRange(bean->socks_port, 1, 65535)) {
|
if (IsValidPort(bean->socks_port)) {
|
||||||
ext_socks_port = bean->socks_port;
|
ext_socks_port = bean->socks_port;
|
||||||
} else {
|
} else {
|
||||||
ext_socks_port = MkPort();
|
ext_socks_port = MkPort();
|
||||||
@@ -617,17 +628,25 @@ namespace NekoRay {
|
|||||||
// Inbounds
|
// Inbounds
|
||||||
|
|
||||||
// mixed-in
|
// mixed-in
|
||||||
if (InRange(dataStore->inbound_socks_port, 1, 65535) && !status->forTest) {
|
if (IsValidPort(dataStore->inbound_socks_port) && !status->forTest) {
|
||||||
QJsonObject socksInbound;
|
QJsonObject inboundObj;
|
||||||
socksInbound["tag"] = "mixed-in";
|
inboundObj["tag"] = "mixed-in";
|
||||||
socksInbound["type"] = "mixed";
|
inboundObj["type"] = "mixed";
|
||||||
socksInbound["listen"] = dataStore->inbound_address;
|
inboundObj["listen"] = dataStore->inbound_address;
|
||||||
socksInbound["listen_port"] = dataStore->inbound_socks_port;
|
inboundObj["listen_port"] = dataStore->inbound_socks_port;
|
||||||
if (dataStore->sniffing_mode != SniffingMode::DISABLE) {
|
if (dataStore->sniffing_mode != SniffingMode::DISABLE) {
|
||||||
socksInbound["sniff"] = true;
|
inboundObj["sniff"] = true;
|
||||||
socksInbound["sniff_override_destination"] = dataStore->sniffing_mode == SniffingMode::FOR_DESTINATION;
|
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
|
// Outbounds
|
||||||
@@ -839,26 +858,32 @@ namespace NekoRay {
|
|||||||
}
|
}
|
||||||
|
|
||||||
QString WriteVPNSingBoxConfig() {
|
QString WriteVPNSingBoxConfig() {
|
||||||
//
|
// user rule
|
||||||
QString process_name_rule = dataStore->vpn_bypass_process.trimmed();
|
QString process_name_rule = dataStore->vpn_bypass_process.trimmed();
|
||||||
if (!process_name_rule.isEmpty()) {
|
if (!process_name_rule.isEmpty()) {
|
||||||
auto arr = SplitLines(process_name_rule);
|
auto arr = SplitLinesSkipSharp(process_name_rule);
|
||||||
QJsonObject rule{{"outbound", "direct"},
|
QJsonObject rule{{"outbound", "direct"},
|
||||||
{"process_name", QList2QJsonArray(arr)}};
|
{"process_name", QList2QJsonArray(arr)}};
|
||||||
process_name_rule = "," + QJsonObject2QString(rule, false);
|
process_name_rule = "," + QJsonObject2QString(rule, false);
|
||||||
}
|
}
|
||||||
QString cidr_rule = dataStore->vpn_bypass_cidr.trimmed();
|
QString cidr_rule = dataStore->vpn_bypass_cidr.trimmed();
|
||||||
if (!cidr_rule.isEmpty()) {
|
if (!cidr_rule.isEmpty()) {
|
||||||
auto arr = SplitLines(cidr_rule);
|
auto arr = SplitLinesSkipSharp(cidr_rule);
|
||||||
QJsonObject rule{{"outbound", "direct"},
|
QJsonObject rule{{"outbound", "direct"},
|
||||||
{"ip_cidr", QList2QJsonArray(arr)}};
|
{"ip_cidr", QList2QJsonArray(arr)}};
|
||||||
cidr_rule = "," + QJsonObject2QString(rule, false);
|
cidr_rule = "," + QJsonObject2QString(rule, false);
|
||||||
}
|
}
|
||||||
//
|
// tun name
|
||||||
auto tun_name = "nekoray-tun";
|
auto tun_name = "nekoray-tun";
|
||||||
#ifdef Q_OS_MACOS
|
#ifdef Q_OS_MACOS
|
||||||
tun_name = "utun9";
|
tun_name = "utun9";
|
||||||
#endif
|
#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
|
// gen config
|
||||||
auto configFn = ":/neko/vpn/sing-box-vpn.json";
|
auto configFn = ":/neko/vpn/sing-box-vpn.json";
|
||||||
if (QFile::exists("vpn/sing-box-vpn.json")) configFn = "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("%CIDR_RULE%", cidr_rule)
|
||||||
.replace("%TUN_NAME%", tun_name)
|
.replace("%TUN_NAME%", tun_name)
|
||||||
.replace("%STRICT_ROUTE%", dataStore->vpn_strict_route ? "true" : "false")
|
.replace("%STRICT_ROUTE%", dataStore->vpn_strict_route ? "true" : "false")
|
||||||
|
.replace("%SOCKS_USER_PASS%", socks_user_pass)
|
||||||
.replace("%PORT%", Int2String(dataStore->inbound_socks_port));
|
.replace("%PORT%", Int2String(dataStore->inbound_socks_port));
|
||||||
// hook.js
|
// hook.js
|
||||||
auto source = qjs::ReadHookJS();
|
auto source = qjs::ReadHookJS();
|
||||||
@@ -891,11 +917,13 @@ namespace NekoRay {
|
|||||||
}
|
}
|
||||||
|
|
||||||
QString WriteVPNLinuxScript(const QString &protectPath, const QString &configPath) {
|
QString WriteVPNLinuxScript(const QString &protectPath, const QString &configPath) {
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
return {};
|
||||||
|
#endif
|
||||||
// gen script
|
// gen script
|
||||||
auto scriptFn = ":/neko/vpn/vpn-run-root.sh";
|
auto scriptFn = ":/neko/vpn/vpn-run-root.sh";
|
||||||
if (QFile::exists("vpn/vpn-run-root.sh")) scriptFn = "vpn/vpn-run-root.sh";
|
if (QFile::exists("vpn/vpn-run-root.sh")) scriptFn = "vpn/vpn-run-root.sh";
|
||||||
auto script = ReadFileText(scriptFn)
|
auto script = ReadFileText(scriptFn)
|
||||||
.replace("$PORT", Int2String(dataStore->inbound_socks_port))
|
|
||||||
.replace("./nekobox_core", QApplication::applicationDirPath() + "/nekobox_core")
|
.replace("./nekobox_core", QApplication::applicationDirPath() + "/nekobox_core")
|
||||||
.replace("$PROTECT_LISTEN_PATH", protectPath)
|
.replace("$PROTECT_LISTEN_PATH", protectPath)
|
||||||
.replace("$CONFIG_PATH", configPath)
|
.replace("$CONFIG_PATH", configPath)
|
||||||
|
|||||||
@@ -7,9 +7,7 @@
|
|||||||
|
|
||||||
#include "main/NekoRay.hpp"
|
#include "main/NekoRay.hpp"
|
||||||
|
|
||||||
#include "qv2ray/wrapper.hpp"
|
namespace NekoRay::network {
|
||||||
|
|
||||||
namespace Qv2ray::common::network {
|
|
||||||
|
|
||||||
NekoHTTPResponse NetworkRequestHelper::HttpGet(const QUrl &url) {
|
NekoHTTPResponse NetworkRequestHelper::HttpGet(const QUrl &url) {
|
||||||
QNetworkRequest request;
|
QNetworkRequest request;
|
||||||
@@ -22,13 +20,16 @@ namespace Qv2ray::common::network {
|
|||||||
p.setType(IS_NEKO_BOX ? QNetworkProxy::HttpProxy : QNetworkProxy::Socks5Proxy);
|
p.setType(IS_NEKO_BOX ? QNetworkProxy::HttpProxy : QNetworkProxy::Socks5Proxy);
|
||||||
p.setHostName("127.0.0.1");
|
p.setHostName("127.0.0.1");
|
||||||
p.setPort(NekoRay::dataStore->inbound_socks_port);
|
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);
|
accessManager.setProxy(p);
|
||||||
if (NekoRay::dataStore->started_id < 0) {
|
if (NekoRay::dataStore->started_id < 0) {
|
||||||
return NekoHTTPResponse{QObject::tr("Request with proxy but no profile started.")};
|
return NekoHTTPResponse{QObject::tr("Request with proxy but no profile started.")};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (accessManager.proxy().type() == QNetworkProxy::Socks5Proxy) {
|
if (accessManager.proxy().type() == QNetworkProxy::Socks5Proxy) {
|
||||||
DEBUG("Adding HostNameLookupCapability to proxy.");
|
|
||||||
auto cap = accessManager.proxy().capabilities();
|
auto cap = accessManager.proxy().capabilities();
|
||||||
accessManager.proxy().setCapabilities(cap | QNetworkProxy::HostNameLookupCapability);
|
accessManager.proxy().setCapabilities(cap | QNetworkProxy::HostNameLookupCapability);
|
||||||
}
|
}
|
||||||
@@ -69,4 +70,4 @@ namespace Qv2ray::common::network {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Qv2ray::common::network
|
} // namespace NekoRay::network
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
namespace Qv2ray::common::network {
|
namespace NekoRay::network {
|
||||||
struct NekoHTTPResponse {
|
struct NekoHTTPResponse {
|
||||||
QString error;
|
QString error;
|
||||||
QByteArray data;
|
QByteArray data;
|
||||||
@@ -26,6 +26,6 @@ namespace Qv2ray::common::network {
|
|||||||
|
|
||||||
static QString GetHeader(const QList<QPair<QByteArray, QByteArray>> &header, const QString &name);
|
static QString GetHeader(const QList<QPair<QByteArray, QByteArray>> &header, const QString &name);
|
||||||
};
|
};
|
||||||
} // namespace Qv2ray::common::network
|
} // namespace NekoRay::network
|
||||||
|
|
||||||
using namespace Qv2ray::common::network;
|
using namespace NekoRay::network;
|
||||||
@@ -17,6 +17,7 @@ namespace NekoRay {
|
|||||||
|
|
||||||
DataStore::DataStore() : JsonStore() {
|
DataStore::DataStore() : JsonStore() {
|
||||||
_add(new configItem("extraCore", dynamic_cast<JsonStore *>(extraCore), itemType::jsonStore));
|
_add(new configItem("extraCore", dynamic_cast<JsonStore *>(extraCore), itemType::jsonStore));
|
||||||
|
_add(new configItem("inbound_auth", dynamic_cast<JsonStore *>(inbound_auth), itemType::jsonStore));
|
||||||
|
|
||||||
_add(new configItem("user_agent", &user_agent, itemType::string));
|
_add(new configItem("user_agent", &user_agent, itemType::string));
|
||||||
_add(new configItem("test_url", &test_url, itemType::string));
|
_add(new configItem("test_url", &test_url, itemType::string));
|
||||||
@@ -112,12 +113,12 @@ namespace NekoRay {
|
|||||||
|
|
||||||
QString Routing::DisplayRouting() const {
|
QString Routing::DisplayRouting() const {
|
||||||
return QString("[Proxy] %1\n[Proxy] %2\n[Direct] %3\n[Direct] %4\n[Block] %5\n[Block] %6")
|
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(SplitLinesSkipSharp(proxy_domain).join(","))
|
||||||
.arg(SplitLines(proxy_ip).join(","))
|
.arg(SplitLinesSkipSharp(proxy_ip).join(","))
|
||||||
.arg(SplitLines(direct_domain).join(","))
|
.arg(SplitLinesSkipSharp(direct_domain).join(","))
|
||||||
.arg(SplitLines(direct_ip).join(","))
|
.arg(SplitLinesSkipSharp(direct_ip).join(","))
|
||||||
.arg(SplitLines(block_domain).join(","))
|
.arg(SplitLinesSkipSharp(block_domain).join(","))
|
||||||
.arg(SplitLines(block_ip).join(","));
|
.arg(SplitLinesSkipSharp(block_ip).join(","));
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList Routing::List() {
|
QStringList Routing::List() {
|
||||||
@@ -163,6 +164,15 @@ namespace NekoRay {
|
|||||||
core_map = QJsonObject2QString(obj, true);
|
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) {
|
void JsonStore::_add(configItem *item) {
|
||||||
_map.insert(item->name, QSharedPointer<configItem>(item));
|
_map.insert(item->name, QSharedPointer<configItem>(item));
|
||||||
|
|||||||
@@ -34,6 +34,16 @@ namespace NekoRay {
|
|||||||
void Delete(const QString &id);
|
void Delete(const QString &id);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class InboundAuthorization : public JsonStore {
|
||||||
|
public:
|
||||||
|
QString username;
|
||||||
|
QString password;
|
||||||
|
|
||||||
|
InboundAuthorization();
|
||||||
|
|
||||||
|
[[nodiscard]] bool NeedAuth() const;
|
||||||
|
};
|
||||||
|
|
||||||
class DataStore : public JsonStore {
|
class DataStore : public JsonStore {
|
||||||
public:
|
public:
|
||||||
// Running
|
// Running
|
||||||
@@ -98,6 +108,7 @@ namespace NekoRay {
|
|||||||
QString inbound_address = "127.0.0.1";
|
QString inbound_address = "127.0.0.1";
|
||||||
int inbound_socks_port = 2080; // or Mixed
|
int inbound_socks_port = 2080; // or Mixed
|
||||||
int inbound_http_port = -2081;
|
int inbound_http_port = -2081;
|
||||||
|
InboundAuthorization *inbound_auth = new InboundAuthorization;
|
||||||
QString custom_inbound = "{\"inbounds\": []}";
|
QString custom_inbound = "{\"inbounds\": []}";
|
||||||
|
|
||||||
// DNS
|
// DNS
|
||||||
|
|||||||
@@ -25,6 +25,16 @@ QStringList SplitLines(const QString &_string) {
|
|||||||
#endif
|
#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) {
|
QString DecodeB64IfValid(const QString &input, QByteArray::Base64Options options) {
|
||||||
Qt515Base64::Base64Options newOptions = Qt515Base64::Base64Option::AbortOnBase64DecodingErrors;
|
Qt515Base64::Base64Options newOptions = Qt515Base64::Base64Option::AbortOnBase64DecodingErrors;
|
||||||
if (options.testFlag(QByteArray::Base64UrlEncoding)) newOptions |= Qt515Base64::Base64Option::Base64UrlEncoding;
|
if (options.testFlag(QByteArray::Base64UrlEncoding)) newOptions |= Qt515Base64::Base64Option::Base64UrlEncoding;
|
||||||
@@ -134,6 +144,28 @@ int MkPort() {
|
|||||||
return port;
|
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) {
|
bool IsIpAddress(const QString &str) {
|
||||||
auto address = QHostAddress(str);
|
auto address = QHostAddress(str);
|
||||||
if (address.protocol() == QAbstractSocket::IPv4Protocol || address.protocol() == QAbstractSocket::IPv6Protocol)
|
if (address.protocol() == QAbstractSocket::IPv4Protocol || address.protocol() == QAbstractSocket::IPv6Protocol)
|
||||||
|
|||||||
@@ -43,6 +43,8 @@ QString QStringList2Command(const QStringList &list);
|
|||||||
|
|
||||||
QStringList SplitLines(const QString &_string);
|
QStringList SplitLines(const QString &_string);
|
||||||
|
|
||||||
|
QStringList SplitLinesSkipSharp(const QString &_string);
|
||||||
|
|
||||||
// Base64
|
// Base64
|
||||||
|
|
||||||
QString DecodeB64IfValid(const QString &input, QByteArray::Base64Options options = QByteArray::Base64Option::Base64Encoding);
|
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);
|
QString DisplayTime(long long time, int formatType = 0);
|
||||||
|
|
||||||
inline QString ReadableSize(const qint64 &size) {
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool InRange(unsigned x, unsigned low, unsigned high) {
|
inline bool InRange(unsigned x, unsigned low, unsigned high) {
|
||||||
return (low <= x && x <= high);
|
return (low <= x && x <= high);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool IsValidPort(int port) {
|
||||||
|
return InRange(port, 1, 65535);
|
||||||
|
}
|
||||||
|
|
||||||
// UI
|
// UI
|
||||||
|
|
||||||
QWidget *GetMessageBoxParent();
|
QWidget *GetMessageBoxParent();
|
||||||
|
|||||||
1
res/icon/material/lock-open-outline.svg
Normal file
1
res/icon/material/lock-open-outline.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M18,20V10H6V20H18M18,8A2,2 0 0,1 20,10V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V10A2,2 0 0,1 6,8H15V6A3,3 0 0,0 12,3A3,3 0 0,0 9,6H7A5,5 0 0,1 12,1A5,5 0 0,1 17,6V8H18M12,17A2,2 0 0,1 10,15A2,2 0 0,1 12,13A2,2 0 0,1 14,15A2,2 0 0,1 12,17Z" /></svg>
|
||||||
|
After Width: | Height: | Size: 317 B |
1
res/icon/material/lock-outline.svg
Normal file
1
res/icon/material/lock-outline.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12,17C10.89,17 10,16.1 10,15C10,13.89 10.89,13 12,13A2,2 0 0,1 14,15A2,2 0 0,1 12,17M18,20V10H6V20H18M18,8A2,2 0 0,1 20,10V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V10C4,8.89 4.89,8 6,8H7V6A5,5 0 0,1 12,1A5,5 0 0,1 17,6V8H18M12,3A3,3 0 0,0 9,6V8H15V6A3,3 0 0,0 12,3Z" /></svg>
|
||||||
|
After Width: | Height: | Size: 345 B |
@@ -6,6 +6,8 @@
|
|||||||
<file alias="icon/b-network-server.svg">icon/network-server.svg</file>
|
<file alias="icon/b-network-server.svg">icon/network-server.svg</file>
|
||||||
<file alias="icon/b-dialog-question.svg">icon/dialog-question.svg</file>
|
<file alias="icon/b-dialog-question.svg">icon/dialog-question.svg</file>
|
||||||
<file alias="icon/b-system-software-update.svg">icon/system-software-update.svg</file>
|
<file alias="icon/b-system-software-update.svg">icon/system-software-update.svg</file>
|
||||||
|
<file>icon/material/lock-open-outline.svg</file>
|
||||||
|
<file>icon/material/lock-outline.svg</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
<qresource prefix="/neko">
|
<qresource prefix="/neko">
|
||||||
<file alias="nekobox.png">public/nekobox.png</file>
|
<file alias="nekobox.png">public/nekobox.png</file>
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
"type": "socks",
|
"type": "socks",
|
||||||
"tag": "nekoray-socks",
|
"tag": "nekoray-socks",
|
||||||
"udp_fragment": true,
|
"udp_fragment": true,
|
||||||
|
%SOCKS_USER_PASS%
|
||||||
"server": "127.0.0.1",
|
"server": "127.0.0.1",
|
||||||
"server_port": %PORT%
|
"server_port": %PORT%
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ if [ "$(uname)" == "Darwin" ]; then
|
|||||||
IS_MACOS=1
|
IS_MACOS=1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
[ -z $PORT ] && echo "Please set env PORT" && exit
|
|
||||||
[ -z $TABLE_FWMARK ] && echo "Please set env TABLE_FWMARK" && exit
|
[ -z $TABLE_FWMARK ] && echo "Please set env TABLE_FWMARK" && exit
|
||||||
command -v pkill >/dev/null 2>&1 || exit
|
command -v pkill >/dev/null 2>&1 || exit
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
#include "qv2ray/v2/utils/HTTPRequestHelper.hpp"
|
|
||||||
|
|
||||||
#include "db/Database.hpp"
|
#include "db/Database.hpp"
|
||||||
#include "db/ProfileFilter.hpp"
|
#include "db/ProfileFilter.hpp"
|
||||||
#include "fmt/includes.h"
|
#include "fmt/includes.h"
|
||||||
#include "fmt/Preset.hpp"
|
#include "fmt/Preset.hpp"
|
||||||
#include "main/QJS.hpp"
|
#include "main/QJS.hpp"
|
||||||
|
#include "main/HTTPRequestHelper.hpp"
|
||||||
|
|
||||||
#include "GroupUpdater.hpp"
|
#include "GroupUpdater.hpp"
|
||||||
|
|
||||||
|
|||||||
@@ -217,6 +217,18 @@
|
|||||||
<source>Max log lines</source>
|
<source>Max log lines</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Inbound Auth</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Username</source>
|
||||||
|
<translation type="unfinished">نام کاربری</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Password</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>DialogEditGroup</name>
|
<name>DialogEditGroup</name>
|
||||||
|
|||||||
@@ -215,6 +215,18 @@
|
|||||||
<source>Max log lines</source>
|
<source>Max log lines</source>
|
||||||
<translation>日志最大行数限制</translation>
|
<translation>日志最大行数限制</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Inbound Auth</source>
|
||||||
|
<translation>入站认证设置</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Username</source>
|
||||||
|
<translation>用户名</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Password</source>
|
||||||
|
<translation>密码</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>DialogEditGroup</name>
|
<name>DialogEditGroup</name>
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
#include "TrayIcon.hpp"
|
#include "Icon.hpp"
|
||||||
|
|
||||||
#include "main/NekoRay.hpp"
|
#include "main/NekoRay.hpp"
|
||||||
|
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
|
|
||||||
QIcon TrayIcon::GetIcon(TrayIcon::TrayIconStatus status) {
|
QIcon Icon::GetTrayIcon(Icon::TrayIconStatus status) {
|
||||||
QPixmap pixmap;
|
QPixmap pixmap;
|
||||||
|
|
||||||
// software embedded icon
|
// software embedded icon
|
||||||
@@ -46,3 +46,8 @@ QIcon TrayIcon::GetIcon(TrayIcon::TrayIconStatus status) {
|
|||||||
|
|
||||||
return pixmap;
|
return pixmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QIcon Icon::GetMaterialIcon(const QString &name) {
|
||||||
|
QPixmap pixmap(":/icon/material/" + name + ".svg");
|
||||||
|
return pixmap;
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include <QIcon>
|
#include <QIcon>
|
||||||
|
|
||||||
namespace TrayIcon {
|
namespace Icon {
|
||||||
|
|
||||||
enum TrayIconStatus {
|
enum TrayIconStatus {
|
||||||
NONE,
|
NONE,
|
||||||
@@ -11,6 +11,8 @@ namespace TrayIcon {
|
|||||||
VPN,
|
VPN,
|
||||||
};
|
};
|
||||||
|
|
||||||
QIcon GetIcon(TrayIconStatus status);
|
QIcon GetTrayIcon(TrayIconStatus status);
|
||||||
|
|
||||||
} // namespace TrayIcon
|
QIcon GetMaterialIcon(const QString &name);
|
||||||
|
|
||||||
|
} // namespace Icon
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "qv2ray/v2/ui/widgets/editors/w_JsonEditor.hpp"
|
#include "qv2ray/v2/ui/widgets/editors/w_JsonEditor.hpp"
|
||||||
#include "fmt/Preset.hpp"
|
#include "fmt/Preset.hpp"
|
||||||
#include "ui/ThemeManager.hpp"
|
#include "ui/ThemeManager.hpp"
|
||||||
|
#include "ui/Icon.hpp"
|
||||||
#include "main/GuiUtils.hpp"
|
#include "main/GuiUtils.hpp"
|
||||||
#include "main/NekoRay.hpp"
|
#include "main/NekoRay.hpp"
|
||||||
|
|
||||||
@@ -66,6 +67,8 @@ DialogBasicSettings::DialogBasicSettings(QWidget *parent)
|
|||||||
ui->log_level->addItems({"debug", "info", "warning", "none"});
|
ui->log_level->addItems({"debug", "info", "warning", "none"});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
refresh_auth();
|
||||||
|
|
||||||
ui->socks_ip->setText(NekoRay::dataStore->inbound_address);
|
ui->socks_ip->setText(NekoRay::dataStore->inbound_address);
|
||||||
ui->log_level->setCurrentText(NekoRay::dataStore->log_level);
|
ui->log_level->setCurrentText(NekoRay::dataStore->log_level);
|
||||||
CACHE.custom_inbound = NekoRay::dataStore->custom_inbound;
|
CACHE.custom_inbound = NekoRay::dataStore->custom_inbound;
|
||||||
@@ -298,6 +301,17 @@ void DialogBasicSettings::accept() {
|
|||||||
QDialog::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() {
|
void DialogBasicSettings::on_set_custom_icon_clicked() {
|
||||||
auto title = ui->set_custom_icon->text();
|
auto title = ui->set_custom_icon->text();
|
||||||
QString user_icon_path = "./" + software_name.toLower() + ".png";
|
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");
|
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();
|
||||||
|
}
|
||||||
|
|||||||
@@ -31,7 +31,11 @@ private:
|
|||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
|
void refresh_auth();
|
||||||
|
|
||||||
void on_set_custom_icon_clicked();
|
void on_set_custom_icon_clicked();
|
||||||
|
|
||||||
|
void on_inbound_auth_clicked();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // DIALOG_BASIC_SETTINGS_H
|
#endif // DIALOG_BASIC_SETTINGS_H
|
||||||
|
|||||||
@@ -45,6 +45,13 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="QLineEdit" name="socks_ip"/>
|
<widget class="QLineEdit" name="socks_ip"/>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="inbound_auth">
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">Auth</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@@ -199,6 +206,13 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="Line" name="sys_proxy_format_vline">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="sys_proxy_format">
|
<widget class="QPushButton" name="sys_proxy_format">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
#include "sys/AutoRun.hpp"
|
#include "sys/AutoRun.hpp"
|
||||||
|
|
||||||
#include "ui/ThemeManager.hpp"
|
#include "ui/ThemeManager.hpp"
|
||||||
#include "ui/TrayIcon.hpp"
|
#include "ui/Icon.hpp"
|
||||||
#include "ui/edit/dialog_edit_profile.h"
|
#include "ui/edit/dialog_edit_profile.h"
|
||||||
#include "ui/dialog_basic_settings.h"
|
#include "ui/dialog_basic_settings.h"
|
||||||
#include "ui/dialog_manage_groups.h"
|
#include "ui/dialog_manage_groups.h"
|
||||||
@@ -223,7 +223,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
|
|||||||
|
|
||||||
// Setup Tray
|
// Setup Tray
|
||||||
tray = new QSystemTrayIcon(this); // 初始化托盘对象tray
|
tray = new QSystemTrayIcon(this); // 初始化托盘对象tray
|
||||||
tray->setIcon(TrayIcon::GetIcon(TrayIcon::NONE));
|
tray->setIcon(Icon::GetTrayIcon(Icon::NONE));
|
||||||
tray->setContextMenu(ui->menu_program); // 创建托盘菜单
|
tray->setContextMenu(ui->menu_program); // 创建托盘菜单
|
||||||
tray->show(); // 让托盘图标显示在系统托盘上
|
tray->show(); // 让托盘图标显示在系统托盘上
|
||||||
connect(tray, &QSystemTrayIcon::activated, this, [=](QSystemTrayIcon::ActivationReason reason) {
|
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 (mode == NekoRay::SystemProxyMode::SYSTEM_PROXY) {
|
||||||
#if defined(Q_OS_WIN) || defined(Q_OS_MACOS)
|
#if defined(Q_OS_WIN) || defined(Q_OS_MACOS)
|
||||||
if (mode == NekoRay::SystemProxyMode::SYSTEM_PROXY && !IS_NEKO_BOX &&
|
if (mode == NekoRay::SystemProxyMode::SYSTEM_PROXY && !IS_NEKO_BOX && !IsValidPort(NekoRay::dataStore->inbound_http_port)) {
|
||||||
!InRange(NekoRay::dataStore->inbound_http_port, 1, 65535)) {
|
|
||||||
auto btn = QMessageBox::warning(this, software_name,
|
auto btn = QMessageBox::warning(this, software_name,
|
||||||
tr("Http inbound is not enabled, can't set system proxy."),
|
tr("Http inbound is not enabled, can't set system proxy."),
|
||||||
"OK", tr("Settings"), "", 0, 0);
|
"OK", tr("Settings"), "", 0, 0);
|
||||||
@@ -646,7 +645,7 @@ void MainWindow::refresh_status(const QString &traffic_update) {
|
|||||||
}
|
}
|
||||||
//
|
//
|
||||||
auto display_http = tr("None");
|
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);
|
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);
|
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" : " ");
|
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) {
|
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) {
|
} else if (NekoRay::dataStore->running_spmode == NekoRay::SystemProxyMode::VPN) {
|
||||||
icon_status_new = TrayIcon::VPN;
|
icon_status_new = Icon::VPN;
|
||||||
} else if (!running.isNull()) {
|
} else if (!running.isNull()) {
|
||||||
icon_status_new = TrayIcon::RUNNING;
|
icon_status_new = Icon::RUNNING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// refresh title & window icon
|
||||||
setWindowTitle(make_title(false));
|
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) {
|
if (tray != nullptr) {
|
||||||
tray->setToolTip(make_title(true));
|
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;
|
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) {
|
void MainWindow::on_masterLogBrowser_customContextMenuRequested(const QPoint &pos) {
|
||||||
QMenu *menu = ui->masterLogBrowser->createStandardContextMenu();
|
QMenu *menu = ui->masterLogBrowser->createStandardContextMenu();
|
||||||
|
|||||||
Reference in New Issue
Block a user