feat: inbound authorization

This commit is contained in:
arm64v8a
2023-01-12 12:51:03 +09:00
parent 10d7d9437a
commit 6a344bc3d5
22 changed files with 288 additions and 119 deletions

View File

@@ -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

View File

@@ -101,32 +101,26 @@ namespace NekoRay {
}
#define DOMAIN_USER_RULE \
for (const auto &line: SplitLines(dataStore->routing->proxy_domain)) { \
if (line.startsWith("#")) continue; \
for (const auto &line: SplitLinesSkipSharp(dataStore->routing->proxy_domain)) { \
if (dataStore->dns_routing) status->domainListDNSRemote += line; \
status->domainListRemote += line; \
} \
for (const auto &line: SplitLines(dataStore->routing->direct_domain)) { \
if (line.startsWith("#")) continue; \
for (const auto &line: SplitLinesSkipSharp(dataStore->routing->direct_domain)) { \
if (dataStore->dns_routing) status->domainListDNSDirect += line; \
status->domainListDirect += line; \
} \
for (const auto &line: SplitLines(dataStore->routing->block_domain)) { \
if (line.startsWith("#")) continue; \
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; \
for (const auto &line: SplitLinesSkipSharp(dataStore->routing->block_ip)) { \
status->ipListBlock += line; \
} \
for (const auto &line: SplitLines(dataStore->routing->proxy_ip)) { \
if (line.startsWith("#")) continue; \
for (const auto &line: SplitLinesSkipSharp(dataStore->routing->proxy_ip)) { \
status->ipListRemote += line; \
} \
for (const auto &line: SplitLines(dataStore->routing->direct_ip)) { \
if (line.startsWith("#")) continue; \
for (const auto &line: SplitLinesSkipSharp(dataStore->routing->direct_ip)) { \
status->ipListDirect += line; \
}
@@ -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)

View File

@@ -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

View File

@@ -6,7 +6,7 @@
#include <QObject>
#include <functional>
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<QPair<QByteArray, QByteArray>> &header, const QString &name);
};
} // namespace Qv2ray::common::network
} // namespace NekoRay::network
using namespace Qv2ray::common::network;
using namespace NekoRay::network;

View File

@@ -17,6 +17,7 @@ namespace NekoRay {
DataStore::DataStore() : 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("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<configItem>(item));

View File

@@ -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

View File

@@ -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)

View File

@@ -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();

View 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

View 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

View File

@@ -6,6 +6,8 @@
<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-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 prefix="/neko">
<file alias="nekobox.png">public/nekobox.png</file>

View File

@@ -27,6 +27,7 @@
"type": "socks",
"tag": "nekoray-socks",
"udp_fragment": true,
%SOCKS_USER_PASS%
"server": "127.0.0.1",
"server_port": %PORT%
},

View File

@@ -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

View File

@@ -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"

View File

@@ -217,6 +217,18 @@
<source>Max log lines</source>
<translation type="unfinished"></translation>
</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>
<name>DialogEditGroup</name>

View File

@@ -215,6 +215,18 @@
<source>Max log lines</source>
<translation></translation>
</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>
<name>DialogEditGroup</name>

View File

@@ -1,10 +1,10 @@
#include "TrayIcon.hpp"
#include "Icon.hpp"
#include "main/NekoRay.hpp"
#include <QPainter>
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;
}

View File

@@ -2,7 +2,7 @@
#include <QIcon>
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

View File

@@ -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();
}

View File

@@ -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

View File

@@ -45,6 +45,13 @@
<item>
<widget class="QLineEdit" name="socks_ip"/>
</item>
<item>
<widget class="QPushButton" name="inbound_auth">
<property name="text">
<string notr="true">Auth</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@@ -199,6 +206,13 @@
</property>
</widget>
</item>
<item>
<widget class="Line" name="sys_proxy_format_vline">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="sys_proxy_format">
<property name="text">

View File

@@ -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();