remove naive and extra core support

This commit is contained in:
Nova 2024-12-07 00:36:38 +03:30
parent bf8de2e9e9
commit 3688295d66
No known key found for this signature in database
GPG Key ID: 389787EC83F5D73A
32 changed files with 38 additions and 1104 deletions

View File

@ -1,22 +0,0 @@
#pragma once
#include <QString>
inline QString cleanVT100String(const QString &in) {
QString out;
bool in_033 = false;
for (auto &&chr: in) {
if (chr == '\033') {
in_033 = true;
continue;
}
if (in_033) {
if (chr == 'm') {
in_033 = false;
}
continue;
}
out += chr;
}
return out;
}

11
3rdparty/fix_old_qt.h vendored
View File

@ -1,11 +0,0 @@
#pragma once
#include <QString>
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
inline QString qEnvironmentVariable(const char *varName) {
return qgetenv(varName);
}
#endif

View File

@ -100,7 +100,6 @@ set(PROJECT_SOURCES
src/configs/proxy/AbstractBean.cpp
src/configs/proxy/Bean2CoreObj_box.cpp
src/configs/proxy/Bean2External.cpp
src/configs/proxy/Bean2Link.cpp
src/configs/proxy/Link2Bean.cpp
include/configs/proxy/ChainBean.hpp # translate
@ -108,7 +107,8 @@ set(PROJECT_SOURCES
include/configs/sub/GroupUpdater.hpp
src/configs/sub/GroupUpdater.cpp
src/sys/ExternalProcess.cpp
include/sys/Process.hpp
src/sys/Process.cpp
src/sys/AutoRun.cpp
include/ui/setting/ThemeManager.hpp
@ -143,10 +143,6 @@ set(PROJECT_SOURCES
src/ui/profile/edit_trojan_vless.cpp
include/ui/profile/edit_trojan_vless.ui
include/ui/profile/edit_naive.h
src/ui/profile/edit_naive.cpp
include/ui/profile/edit_naive.ui
include/ui/profile/edit_quic.h
src/ui/profile/edit_quic.cpp
include/ui/profile/edit_quic.ui
@ -209,7 +205,7 @@ set(PROJECT_SOURCES
src/sys/macos/MacOS.cpp
src/sys/AutoRun.cpp
src/sys/ExternalProcess.cpp
src/sys/Process.cpp
include/ui/mainwindow_interface.h
)

View File

@ -2,7 +2,7 @@
#ifndef NKR_NO_GRPC
#include "go/grpc_server/gen/libcore.pb.h"
#include "core/grpc_server/gen/libcore.pb.h"
#include <QString>
namespace QtGrpc {

View File

@ -1,7 +1,7 @@
#pragma once
#include "include/dataStore/ProxyEntity.hpp"
#include "include/sys/ExternalProcess.hpp"
#include "include/sys/Process.hpp"
namespace NekoGui {
class BuildConfigResult {
@ -12,8 +12,6 @@ namespace NekoGui {
QList<std::shared_ptr<NekoGui_traffic::TrafficData>> outboundStats; // all, but not including "bypass" "block"
std::shared_ptr<NekoGui_traffic::TrafficData> outboundStat; // main
QStringList ignoreConnTag;
std::list<std::shared_ptr<NekoGui_fmt::ExternalBuildResult>> extRs;
};
class BuildTestConfigResult {

View File

@ -12,18 +12,6 @@ namespace NekoGui_fmt {
QString error;
};
struct ExternalBuildResult {
public:
QString program;
QStringList env;
QStringList arguments;
//
QString tag;
//
QString error;
QString config_export;
};
class AbstractBean : public JsonStore {
public:
int version;
@ -62,12 +50,8 @@ namespace NekoGui_fmt {
//
virtual int NeedExternal(bool isFirstProfile) { return 0; };
virtual CoreObjOutboundBuildResult BuildCoreObjSingBox() { return {}; };
virtual ExternalBuildResult BuildExternal(int mapping_port, int socks_port, int external_stat) { return {}; };
virtual QString ToShareLink() { return {}; };
};

View File

@ -31,7 +31,7 @@ namespace NekoGui_fmt {
return core;
};
QString DisplayCoreType() override { return NeedExternal(true) == 0 ? software_core_name : core; };
QString DisplayCoreType() override { return software_core_name; };
QString DisplayAddress() override {
if (core == "internal") {
@ -43,10 +43,6 @@ namespace NekoGui_fmt {
return AbstractBean::DisplayAddress();
};
int NeedExternal(bool isFirstProfile) override;
ExternalBuildResult BuildExternal(int mapping_port, int socks_port, int external_stat) override;
CoreObjOutboundBuildResult BuildCoreObjSingBox() override;
};
} // namespace NekoGui_fmt

View File

@ -1,41 +0,0 @@
#pragma once
#include "AbstractBean.hpp"
namespace NekoGui_fmt {
class NaiveBean : public AbstractBean {
public:
QString username = "";
QString password = "";
QString protocol = "https";
QString extra_headers = "";
QString sni = "";
QString certificate = "";
int insecure_concurrency = 0;
bool disable_log = false;
NaiveBean() : AbstractBean(0) {
_add(new configItem("username", &username, itemType::string));
_add(new configItem("password", &password, itemType::string));
_add(new configItem("protocol", &protocol, itemType::string));
_add(new configItem("extra_headers", &extra_headers, itemType::string));
_add(new configItem("sni", &sni, itemType::string));
_add(new configItem("certificate", &certificate, itemType::string));
_add(new configItem("insecure_concurrency", &insecure_concurrency, itemType::integer));
_add(new configItem("disable_log", &disable_log, itemType::boolean));
};
QString DisplayCoreType() override { return "Naive"; };
QString DisplayType() override { return "Naive"; };
int NeedExternal(bool isFirstProfile) override;
ExternalBuildResult BuildExternal(int mapping_port, int socks_port, int external_stat) override;
bool TryParseLink(const QString &link);
QString ToShareLink() override;
};
} // namespace NekoGui_fmt

View File

@ -97,9 +97,7 @@ namespace NekoGui_fmt {
}
QString DisplayCoreType() override {
if (NeedExternal(true) == 0) {
return software_core_name;
} else if (proxy_type == proxy_TUIC) {
if (proxy_type == proxy_TUIC) {
return "tuic";
} else if (proxy_type == proxy_Hysteria) {
return "hysteria";
@ -118,10 +116,6 @@ namespace NekoGui_fmt {
}
};
int NeedExternal(bool isFirstProfile) override;
ExternalBuildResult BuildExternal(int mapping_port, int socks_port, int external_stat) override;
CoreObjOutboundBuildResult BuildCoreObjSingBox() override;
bool TryParseLink(const QString &link);

View File

@ -5,7 +5,6 @@
#include "ChainBean.hpp"
#include "VMessBean.hpp"
#include "TrojanVLESSBean.hpp"
#include "NaiveBean.hpp"
#include "QUICBean.hpp"
#include "WireguardBean.h"
#include "SSHBean.h"

View File

@ -19,8 +19,6 @@ inline std::function<void()> MF_release_runguard;
class QWidget;
inline QWidget *mainwindow;
inline std::function<void(QString)> MW_show_log;
inline std::function<void(QString, QString)> MW_show_log_ext;
inline std::function<void(QString)> MW_show_log_ext_vt100;
inline std::function<void(QString, QString)> MW_dialog_message;
// Dispatchers

View File

@ -4,36 +4,25 @@
#include <QProcess>
namespace NekoGui_sys {
class ExternalProcess : public QProcess {
class CoreProcess : public QProcess
{
public:
QString tag;
QString program;
QStringList arguments;
QStringList env;
bool managed = true; // MW_dialog_message
ExternalProcess();
~ExternalProcess();
CoreProcess();
~CoreProcess();
// start & kill is one time
virtual void Start();
void Start();
void Kill();
protected:
bool started = false;
bool killed = false;
bool crashed = false;
};
class CoreProcess : public ExternalProcess {
public:
CoreProcess(const QString &core_path, const QStringList &args);
void Start() override;
void Restart();
int start_profile_when_core_is_up = -1;
@ -42,10 +31,12 @@ namespace NekoGui_sys {
bool show_stderr = false;
bool failed_to_start = false;
bool restarting = false;
};
// 手动管理
inline std::list<std::shared_ptr<ExternalProcess>> running_ext;
protected:
bool started = false;
bool killed = false;
bool crashed = false;
};
inline QAtomicInt logCounter;
} // namespace NekoGui_sys

View File

@ -1,41 +0,0 @@
#pragma once
#include <QWidget>
#include "profile_editor.h"
#include "ui_edit_naive.h"
QT_BEGIN_NAMESPACE
namespace Ui {
class EditNaive;
}
QT_END_NAMESPACE
class EditNaive : public QWidget, public ProfileEditor {
Q_OBJECT
public:
explicit EditNaive(QWidget *parent = nullptr);
~EditNaive() override;
void onStart(std::shared_ptr<NekoGui::ProxyEntity> _ent) override;
bool onEnd() override;
QList<QPair<QPushButton *, QString>> get_editor_cached() override;
private:
Ui::EditNaive *ui;
std::shared_ptr<NekoGui::ProxyEntity> ent;
struct {
QString certificate;
QString extra_headers;
} CACHE;
private slots:
void on_certificate_clicked();
void on_extra_headers_clicked();
};

View File

@ -1,131 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>EditNaive</class>
<widget class="QWidget" name="EditNaive">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>525</width>
<height>304</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">EditNaive</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Username</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="MyLineEdit" name="username"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Password</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="MyLineEdit" name="password"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Protocol</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="protocol">
<item>
<property name="text">
<string notr="true">https</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">quic</string>
</property>
</item>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Extra headers</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QPushButton" name="extra_headers">
<property name="text">
<string notr="true">PushButton</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>SNI</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="MyLineEdit" name="sni"/>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Certificate</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QPushButton" name="certificate">
<property name="text">
<string notr="true">PushButton</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Insecure concurrency</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="MyLineEdit" name="insecure_concurrency"/>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Disable logs</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QCheckBox" name="disable_log">
<property name="text">
<string>Turn on this option if your connection is lost after a while</string>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>MyLineEdit</class>
<extends>QLineEdit</extends>
<header>include/ui/utils/MyLineEdit.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@ -25,7 +25,6 @@ private:
Ui::DialogBasicSettings *ui;
struct {
QJsonObject extraCore;
QString custom_inbound;
bool needRestart = false;
} CACHE;

View File

@ -756,61 +756,6 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_6">
<attribute name="title">
<string>Extra Core</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<widget class="QScrollArea" name="extra_core_box_scrollArea">
<property name="frameShape">
<enum>QFrame::Shape::NoFrame</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="extra_core_box_scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>700</width>
<height>402</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QWidget" name="horizontalWidget_4" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_8">
<item>
<widget class="QPushButton" name="extra_core_add">
<property name="text">
<string>Add</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="extra_core_del">
<property name="text">
<string>Delete</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_5">
<attribute name="title">
<string>Security</string>

View File

@ -11,17 +11,6 @@
#define BOX_UNDERLYING_DNS_EXPORT dataStore->core_box_underlying_dns.isEmpty() ? (status->forExport ? "local" : "underlying://0.0.0.0") : dataStore->core_box_underlying_dns
namespace NekoGui {
QStringList getAutoBypassExternalProcessPaths(const std::shared_ptr<BuildConfigResult> &result) {
QStringList paths;
for (const auto &extR: result->extRs) {
auto path = extR->program;
if (path.trimmed().isEmpty()) continue;
paths << path.replace("\\", "/");
}
return paths;
}
QString genTunName() {
auto tun_name = "nekoray-tun";
#ifdef Q_OS_MACOS
@ -281,83 +270,12 @@ namespace NekoGui {
status->result->outboundStat = ent->traffic_data;
}
// chain rules: this
auto ext_mapping_port = 0;
auto ext_socks_port = 0;
auto thisExternalStat = ent->bean->NeedExternal(isFirstProfile);
if (thisExternalStat < 0) {
status->result->error = "This configuration cannot be set automatically, please try another.";
return {};
}
// determine port
if (thisExternalStat > 0) {
if (ent->type == "custom") {
auto bean = ent->CustomBean();
if (IsValidPort(bean->mapping_port)) {
ext_mapping_port = bean->mapping_port;
} else {
ext_mapping_port = MkPort();
}
if (IsValidPort(bean->socks_port)) {
ext_socks_port = bean->socks_port;
} else {
ext_socks_port = MkPort();
}
} else {
ext_mapping_port = MkPort();
ext_socks_port = MkPort();
}
}
if (thisExternalStat == 2) dataStore->need_keep_vpn_off = true;
if (thisExternalStat == 1) {
// mapping
status->inbounds += QJsonObject{
{"type", "direct"},
{"tag", tagOut + "-mapping"},
{"listen", "127.0.0.1"},
{"listen_port", ext_mapping_port},
{"override_address", ent->bean->serverAddress},
{"override_port", ent->bean->serverPort},
};
// no chain rule and not outbound, so need to set to direct
if (isFirstProfile) {
status->routingRules += QJsonObject{
{"inbound", QJsonArray{tagOut + "-mapping"}},
{"outbound", "direct"},
};
}
}
// Outbound
QJsonObject outbound;
if (thisExternalStat > 0) {
auto extR = ent->bean->BuildExternal(ext_mapping_port, ext_socks_port, thisExternalStat);
if (extR.program.isEmpty()) {
status->result->error = QObject::tr("Core not found: %1").arg(ent->bean->DisplayCoreType());
return {};
}
if (!extR.error.isEmpty()) { // rejected
status->result->error = extR.error;
return {};
}
extR.tag = ent->bean->DisplayType();
status->result->extRs.emplace_back(std::make_shared<NekoGui_fmt::ExternalBuildResult>(extR));
BuildOutbound(ent, status, outbound, tagOut);
// SOCKS OUTBOUND
outbound["type"] = "socks";
outbound["server"] = "127.0.0.1";
outbound["server_port"] = ext_socks_port;
// outbound misc
outbound["tag"] = tagOut;
ent->traffic_data->id = ent->id;
ent->traffic_data->tag = tagOut.toStdString();
status->result->outboundStats += ent->traffic_data;
} else {
BuildOutbound(ent, status, outbound, tagOut);
}
// apply custom outbound settings
MergeJson(QString2QJsonObject(ent->bean->custom_outbound), outbound);
@ -377,7 +295,6 @@ namespace NekoGui {
status->outbounds += outbound;
pastTag = tagOut;
pastExternalStat = thisExternalStat;
index++;
}

View File

@ -52,7 +52,6 @@ namespace NekoGui_fmt {
bool noResolve = false;
if (dynamic_cast<ChainBean *>(this) != nullptr) noResolve = true;
if (dynamic_cast<CustomBean *>(this) != nullptr) noResolve = true;
if (dynamic_cast<NaiveBean *>(this) != nullptr) noResolve = true;
if (IsIpAddress(serverAddress)) noResolve = true;
if (noResolve) {
onFinished();

View File

@ -1,336 +0,0 @@
#include "include/dataStore/ProxyEntity.hpp"
#include "include/configs/proxy/includes.h"
#include <QFile>
#include <QDir>
#include <QFileInfo>
#include <QUrl>
#define WriteTempFile(fn, data) \
QDir dir; \
if (!dir.exists("temp")) dir.mkdir("temp"); \
QFile f(QString("temp/") + fn); \
bool ok = f.open(QIODevice::WriteOnly | QIODevice::Truncate); \
if (ok) { \
f.write(data); \
} else { \
result.error = f.errorString(); \
} \
f.close(); \
auto TempFile = QFileInfo(f).absoluteFilePath();
namespace NekoGui_fmt {
// -1: Cannot use this config
// 0: Internal
// 1: Mapping External
// 2: Direct External
int NaiveBean::NeedExternal(bool isFirstProfile) {
if (isFirstProfile) {
if (NekoGui::dataStore->spmode_vpn) {
return 1;
}
return 2;
}
return 1;
}
int QUICBean::NeedExternal(bool isFirstProfile) {
auto hysteriaCore = [=] {
if (isFirstProfile) {
if (NekoGui::dataStore->spmode_vpn && hyProtocol != hysteria_protocol_facktcp) {
return 1;
}
return 2;
} else {
if (hyProtocol == hysteria_protocol_facktcp) {
return -1;
}
}
return 1;
};
auto hysteria2Core = [=] {
if (isFirstProfile) {
if (NekoGui::dataStore->spmode_vpn) {
return 1;
}
return 2;
}
return 1;
};
auto tuicCore = [=] {
if (isFirstProfile) {
if (NekoGui::dataStore->spmode_vpn) {
return 1;
}
return 2;
}
return 1;
};
if (IS_NEKO_BOX) {
if (!forceExternal && (proxy_type == proxy_TUIC || hyProtocol == hysteria_protocol_udp)) {
// sing-box support
return 0;
} else {
// hysteria core support
return hysteriaCore();
}
} else if (proxy_type == proxy_TUIC) {
return tuicCore();
} else if (proxy_type == proxy_Hysteria2) {
return hysteria2Core();
} else {
return hysteriaCore();
}
}
int CustomBean::NeedExternal(bool isFirstProfile) {
if (core == "internal" || core == "internal-full") return 0;
return 1;
}
ExternalBuildResult NaiveBean::BuildExternal(int mapping_port, int socks_port, int external_stat) {
ExternalBuildResult result{NekoGui::dataStore->extraCore->Get("naive")};
auto is_direct = external_stat == 2;
auto domain_address = sni.isEmpty() ? serverAddress : sni;
auto connect_address = is_direct ? serverAddress : "127.0.0.1";
auto connect_port = is_direct ? serverPort : mapping_port;
domain_address = WrapIPV6Host(domain_address);
connect_address = WrapIPV6Host(connect_address);
auto proxy_url = QUrl();
proxy_url.setScheme(protocol);
proxy_url.setUserName(username);
proxy_url.setPassword(password);
proxy_url.setPort(connect_port);
proxy_url.setHost(domain_address);
if (!disable_log) result.arguments += "--log";
result.arguments += "--listen=socks://127.0.0.1:" + Int2String(socks_port);
result.arguments += "--proxy=" + proxy_url.toString(QUrl::FullyEncoded);
if (domain_address != connect_address)
result.arguments += "--host-resolver-rules=MAP " + domain_address + " " + connect_address;
if (insecure_concurrency > 0) result.arguments += "--insecure-concurrency=" + Int2String(insecure_concurrency);
if (!extra_headers.trimmed().isEmpty()) result.arguments += "--extra-headers=" + extra_headers;
if (!certificate.trimmed().isEmpty()) {
WriteTempFile("naive_" + GetRandomString(10) + ".crt", certificate.toUtf8());
result.env += "SSL_CERT_FILE=" + TempFile;
}
auto config_export = QStringList{result.program};
config_export += result.arguments;
result.config_export = QStringList2Command(config_export);
return result;
}
ExternalBuildResult QUICBean::BuildExternal(int mapping_port, int socks_port, int external_stat) {
if (proxy_type == proxy_TUIC) {
ExternalBuildResult result{NekoGui::dataStore->extraCore->Get("tuic")};
QJsonObject relay;
relay["uuid"] = uuid;
relay["password"] = password;
relay["udp_relay_mode"] = udpRelayMode;
relay["congestion_control"] = congestionControl;
relay["zero_rtt_handshake"] = zeroRttHandshake;
relay["disable_sni"] = disableSni;
if (!heartbeat.trimmed().isEmpty()) relay["heartbeat"] = heartbeat;
if (!alpn.trimmed().isEmpty()) relay["alpn"] = QListStr2QJsonArray(alpn.split(","));
if (!caText.trimmed().isEmpty()) {
WriteTempFile("tuic_" + GetRandomString(10) + ".crt", caText.toUtf8());
QJsonArray certificate;
certificate.append(TempFile);
relay["certificates"] = certificate;
}
// The most confused part of TUIC......
if (serverAddress == sni) {
relay["server"] = serverAddress + ":" + Int2String(serverPort);
} else {
relay["server"] = sni + ":" + Int2String(serverPort);
relay["ip"] = serverAddress;
}
QJsonObject local{
{"server", "127.0.0.1:" + Int2String(socks_port)},
};
QJsonObject config{
{"relay", relay},
{"local", local},
};
//
result.config_export = QJsonObject2QString(config, false);
WriteTempFile("tuic_" + GetRandomString(10) + ".json", result.config_export.toUtf8());
result.arguments = QStringList{"-c", TempFile};
return result;
} else if (proxy_type == proxy_Hysteria2) {
ExternalBuildResult result{NekoGui::dataStore->extraCore->Get("hysteria2")};
QJsonObject config;
auto server = WrapIPV6Host(serverAddress) + ":" + Int2String(serverPort);;
QJsonObject transport;
transport["type"] = "udp";
config["transport"] = transport;
config["server"] = server;
config["socks5"] = QJsonObject{
{"listen", "127.0.0.1:" + Int2String(socks_port)},
{"disableUDP", false},
};
config["auth"] = password;
QJsonObject bandwidth;
if (uploadMbps > 0) bandwidth["up"] = Int2String(uploadMbps) + " mbps";
if (downloadMbps > 0) bandwidth["down"] = Int2String(downloadMbps) + " mbps";
config["bandwidth"] = bandwidth;
QJsonObject quic;
if (streamReceiveWindow > 0) quic["initStreamReceiveWindow"] = streamReceiveWindow;
if (connectionReceiveWindow > 0) quic["initConnReceiveWindow"] = connectionReceiveWindow;
if (disableMtuDiscovery) quic["disablePathMTUDiscovery"] = true;
config["quic"] = quic;
config["fastOpen"] = true;
config["lazy"] = true;
if (!obfsPassword.isEmpty()) {
QJsonObject obfs;
obfs["type"] = "salamander";
obfs["salamander"] = QJsonObject{
{"password", obfsPassword},
};
config["obfs"] = obfs;
}
QJsonObject tls;
auto sniGen = sni;
if (sni.isEmpty() && !IsIpAddress(serverAddress)) sniGen = serverAddress;
tls["sni"] = sniGen;
if (allowInsecure) tls["insecure"] = true;
if (!caText.trimmed().isEmpty()) {
WriteTempFile("hysteria2_" + GetRandomString(10) + ".crt", caText.toUtf8());
QJsonArray certificate;
certificate.append(TempFile);
tls["certificates"] = certificate;
}
config["tls"] = tls;
result.config_export = QJsonObject2QString(config, false);
WriteTempFile("hysteria2_" + GetRandomString(10) + ".json", result.config_export.toUtf8());
result.arguments = QStringList{"-c", TempFile};
return result;
} else { // Hysteria
ExternalBuildResult result{NekoGui::dataStore->extraCore->Get("hysteria")};
QJsonObject config;
// determine server format
auto is_direct = external_stat == 2;
auto sniGen = sni;
if (sni.isEmpty() && !IsIpAddress(serverAddress)) sniGen = serverAddress;
auto server = WrapIPV6Host(serverAddress) + ":" + Int2String(serverPort);
config["server"] = is_direct ? server : "127.0.0.1:" + Int2String(mapping_port);
// listen
config["socks5"] = QJsonObject{
{"listen", "127.0.0.1:" + Int2String(socks_port)},
};
// misc
config["retry"] = 5;
config["fast_open"] = true;
config["lazy_start"] = true;
config["obfs"] = obfsPassword;
config["up_mbps"] = uploadMbps;
config["down_mbps"] = downloadMbps;
if (authPayloadType == hysteria_auth_base64) config["auth"] = authPayload;
if (authPayloadType == hysteria_auth_string) config["auth_str"] = authPayload;
if (hyProtocol == hysteria_protocol_facktcp) config["protocol"] = "faketcp";
if (hyProtocol == hysteria_protocol_wechat_video) config["protocol"] = "wechat-video";
if (!sniGen.isEmpty()) config["server_name"] = sniGen;
if (!alpn.isEmpty()) config["alpn"] = alpn;
if (!caText.trimmed().isEmpty()) {
WriteTempFile("hysteria_" + GetRandomString(10) + ".crt", caText.toUtf8());
config["ca"] = TempFile;
}
if (allowInsecure) config["insecure"] = true;
if (streamReceiveWindow > 0) config["recv_window_conn"] = streamReceiveWindow;
if (connectionReceiveWindow > 0) config["recv_window"] = connectionReceiveWindow;
if (disableMtuDiscovery) config["disable_mtu_discovery"] = true;
//
result.config_export = QJsonObject2QString(config, false);
WriteTempFile("hysteria_" + GetRandomString(10) + ".json", result.config_export.toUtf8());
result.arguments = QStringList{"--no-check", "-c", TempFile};
return result;
}
}
ExternalBuildResult CustomBean::BuildExternal(int mapping_port, int socks_port, int external_stat) {
ExternalBuildResult result{NekoGui::dataStore->extraCore->Get(core)};
result.arguments = command; // TODO split?
for (int i = 0; i < result.arguments.length(); i++) {
auto arg = result.arguments[i];
arg = arg.replace("%mapping_port%", Int2String(mapping_port));
arg = arg.replace("%socks_port%", Int2String(socks_port));
arg = arg.replace("%server_addr%", serverAddress);
arg = arg.replace("%server_port%", Int2String(serverPort));
result.arguments[i] = arg;
}
if (!config_simple.trimmed().isEmpty()) {
auto config = config_simple;
config = config.replace("%mapping_port%", Int2String(mapping_port));
config = config.replace("%socks_port%", Int2String(socks_port));
config = config.replace("%server_addr%", serverAddress);
config = config.replace("%server_port%", Int2String(serverPort));
// suffix
QString suffix;
if (!config_suffix.isEmpty()) {
suffix = "." + config_suffix;
} else if (!QString2QJsonObject(config).isEmpty()) {
// trojan-go: unsupported config format: xxx.tmp. use .yaml or .json instead.
suffix = ".json";
}
// write config
WriteTempFile("custom_" + GetRandomString(10) + suffix, config.toUtf8());
for (int i = 0; i < result.arguments.count(); i++) {
result.arguments[i] = result.arguments[i].replace("%config%", TempFile);
}
result.config_export = config;
}
return result;
}
} // namespace NekoGui_fmt

View File

@ -177,17 +177,6 @@ namespace NekoGui_fmt {
return url.toString(QUrl::FullyEncoded);
}
QString NaiveBean::ToShareLink() {
QUrl url;
url.setScheme("naive+" + protocol);
url.setUserName(username);
url.setPassword(password);
url.setHost(serverAddress);
url.setPort(serverPort);
if (!name.isEmpty()) url.setFragment(name);
return url.toString(QUrl::FullyEncoded);
}
QString QUICBean::ToShareLink() {
QUrl url;
if (proxy_type == proxy_Hysteria) {

View File

@ -258,22 +258,6 @@ namespace NekoGui_fmt {
return false;
}
bool NaiveBean::TryParseLink(const QString &link) {
auto url = QUrl(link);
if (!url.isValid()) return false;
protocol = url.scheme().replace("naive+", "");
if (protocol != "https" && protocol != "quic") return false;
name = url.fragment(QUrl::FullyDecoded);
serverAddress = url.host();
serverPort = url.port();
username = url.userName();
password = url.password();
return !(username.isEmpty() || password.isEmpty() || serverAddress.isEmpty());
}
bool QUICBean::TryParseLink(const QString &link) {
auto url = QUrl(link);
auto query = QUrlQuery(url.query());

View File

@ -172,14 +172,6 @@ namespace NekoGui_sub {
if (!ok) return;
}
// Naive
if (str.startsWith("naive+")) {
needFix = false;
ent = NekoGui::ProfileManager::NewProxyEntity("naive");
auto ok = ent->NaiveBean()->TryParseLink(str);
if (!ok) return;
}
// Hysteria1
if (str.startsWith("hysteria://")) {
needFix = false;

View File

@ -215,8 +215,6 @@ namespace NekoGui {
bean = new NekoGui_fmt::TrojanVLESSBean(NekoGui_fmt::TrojanVLESSBean::proxy_Trojan);
} else if (type == "vless") {
bean = new NekoGui_fmt::TrojanVLESSBean(NekoGui_fmt::TrojanVLESSBean::proxy_VLESS);
} else if (type == "naive") {
bean = new NekoGui_fmt::NaiveBean();
} else if (type == "hysteria") {
bean = new NekoGui_fmt::QUICBean(NekoGui_fmt::QUICBean::proxy_Hysteria);
} else if (type == "hysteria2") {

View File

@ -23,11 +23,7 @@
#endif
QStringList SplitLines(const QString &_string) {
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
return _string.split(QRegularExpression("[\r\n]"), Qt::SplitBehaviorFlags::SkipEmptyParts);
#else
return _string.split(QRegularExpression("[\r\n]"), QString::SkipEmptyParts);
#endif
}
QStringList SplitLinesSkipSharp(const QString &_string, int maxLine) {

View File

@ -3,7 +3,6 @@
#include <QApplication>
#include <QDir>
#include "3rdparty/fix_old_qt.h"
#include "include/global/NekoGui.hpp"
// macOS headers (possibly OBJ-c)

View File

@ -1,4 +1,4 @@
#include "include/sys/ExternalProcess.hpp"
#include "include/sys/Process.hpp"
#include "include/global/NekoGui.hpp"
#include <QTimer>
@ -8,61 +8,20 @@
namespace NekoGui_sys {
ExternalProcess::ExternalProcess() : QProcess() {
// qDebug() << "[Debug] ExternalProcess()" << this << running_ext;
CoreProcess::CoreProcess() : QProcess() {
this->env = QProcessEnvironment::systemEnvironment().toStringList();
}
ExternalProcess::~ExternalProcess() {
// qDebug() << "[Debug] ~ExternalProcess()" << this << running_ext;
CoreProcess::~CoreProcess() {
}
void ExternalProcess::Start() {
if (started) return;
started = true;
if (managed) {
connect(this, &QProcess::readyReadStandardOutput, this, [&]() {
auto log = readAllStandardOutput();
if (logCounter.fetchAndAddRelaxed(log.count("\n")) > NekoGui::dataStore->max_log_line) return;
MW_show_log_ext_vt100(log);
});
connect(this, &QProcess::readyReadStandardError, this, [&]() {
MW_show_log_ext_vt100(readAllStandardError().trimmed());
});
connect(this, &QProcess::errorOccurred, this, [&](QProcess::ProcessError error) {
if (!killed) {
crashed = true;
MW_show_log_ext(tag, "errorOccurred:" + errorString());
MW_dialog_message("ExternalProcess", "Crashed");
}
});
connect(this, &QProcess::stateChanged, this, [&](QProcess::ProcessState state) {
if (state == QProcess::NotRunning) {
if (killed) { // 用户命令退出
MW_show_log_ext(tag, "External core stopped");
} else if (!crashed) { // 异常退出
crashed = true;
MW_show_log_ext(tag, "[Error] Program exited accidentally: " + errorString());
Kill();
MW_dialog_message("ExternalProcess", "Crashed");
}
}
});
MW_show_log_ext(tag, "External core starting: " + env.join(" ") + " " + program + " " + arguments.join(" "));
}
QProcess::setEnvironment(env);
QProcess::start(program, arguments);
}
void ExternalProcess::Kill() {
void CoreProcess::Kill() {
if (killed) return;
killed = true;
if (!crashed) {
QProcess::kill();
QProcess::waitForFinished(500);
kill();
waitForFinished(500);
}
}
@ -70,10 +29,9 @@ namespace NekoGui_sys {
QElapsedTimer coreRestartTimer;
CoreProcess::CoreProcess(const QString &core_path, const QStringList &args) : ExternalProcess() {
ExternalProcess::managed = false;
ExternalProcess::program = core_path;
ExternalProcess::arguments = args;
CoreProcess::CoreProcess(const QString &core_path, const QStringList &args) : QProcess() {
program = core_path;
arguments = args;
connect(this, &QProcess::readyReadStandardOutput, this, [&]() {
auto log = readAllStandardOutput();
@ -87,7 +45,7 @@ namespace NekoGui_sys {
}
} else if (log.contains("failed to serve")) {
// The core failed to start
QProcess::kill();
kill();
}
}
if (logCounter.fetchAndAddRelaxed(log.count("\n")) > NekoGui::dataStore->max_log_line) return;
@ -141,15 +99,19 @@ namespace NekoGui_sys {
void CoreProcess::Start() {
show_stderr = false;
ExternalProcess::Start();
if (started) return;
started = true;
setEnvironment(env);
start(program, arguments);
write((NekoGui::dataStore->core_token + "\n").toUtf8());
}
void CoreProcess::Restart() {
restarting = true;
QProcess::kill();
QProcess::waitForFinished(500);
ExternalProcess::started = false;
kill();
waitForFinished(500);
started = false;
Start();
restarting = false;
}

View File

@ -3,7 +3,7 @@
#include "include/dataStore/ProfileFilter.hpp"
#include "include/configs/configBuilder.hpp"
#include "include/configs/sub/GroupUpdater.hpp"
#include "include/sys/ExternalProcess.hpp"
#include "include/sys/Process.hpp"
#include "include/sys/AutoRun.hpp"
#include "include/ui/setting/ThemeManager.hpp"
@ -16,7 +16,6 @@
#include "include/ui/setting/dialog_hotkey.h"
#include "3rdparty/qrcodegen.hpp"
#include "3rdparty/VT100Parser.hpp"
#include "3rdparty/qv2ray/v2/ui/LogHighlighter.hpp"
#include "3rdparty/ZxingQtReader.hpp"
#include "include/ui/group/dialog_edit_group.h"
@ -154,12 +153,6 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
MW_show_log = [=](const QString &log) {
runOnUiThread([=] { show_log_impl(log); });
};
MW_show_log_ext = [=](const QString &tag, const QString &log) {
runOnUiThread([=] { show_log_impl("[" + tag + "] " + log); });
};
MW_show_log_ext_vt100 = [=](const QString &log) {
runOnUiThread([=] { show_log_impl(cleanVT100String(log)); });
};
// table UI
ui->proxyListTable->callback_save_order = [=] {

View File

@ -12,24 +12,6 @@
#include <QDesktopServices>
#include <QMessageBox>
// ext core
std::list<std::shared_ptr<NekoGui_sys::ExternalProcess>> CreateExtCFromExtR(const std::list<std::shared_ptr<NekoGui_fmt::ExternalBuildResult>> &extRs, bool start) {
// plz run and start in same thread
std::list<std::shared_ptr<NekoGui_sys::ExternalProcess>> l;
for (const auto &extR: extRs) {
std::shared_ptr<NekoGui_sys::ExternalProcess> extC(new NekoGui_sys::ExternalProcess());
extC->tag = extR->tag;
extC->program = extR->program;
extC->arguments = extR->arguments;
extC->env = extR->env;
l.emplace_back(extC);
//
if (start) extC->Start();
}
return l;
}
// grpc
using namespace NekoGui_rpc;
@ -52,9 +34,6 @@ void MainWindow::RunSpeedTest(const QString& config, bool useDefault, const QStr
return;
}
std::list<std::shared_ptr<NekoGui_sys::ExternalProcess>> extCs;
QSemaphore extSem;
libcore::TestReq req;
for (const auto &item: outboundTags) {
req.add_outbound_tags(item.toStdString());
@ -67,18 +46,6 @@ void MainWindow::RunSpeedTest(const QString& config, bool useDefault, const QStr
bool rpcOK;
auto result = defaultClient->Test(&rpcOK, req);
//
if (!extCs.empty()) {
runOnUiThread(
[&] {
for (const auto &extC: extCs) {
extC->Kill();
}
extSem.release();
},
DS_cores);
extSem.acquire();
}
//
if (!rpcOK) return;
for (const auto &res: result.results()) {
@ -313,13 +280,6 @@ void MainWindow::neko_start(int _id) {
NekoGui::dataStore->ignoreConnTag = result->ignoreConnTag;
NekoGui_traffic::trafficLooper->loop_enabled = true;
runOnUiThread(
[=] {
auto extCs = CreateExtCFromExtR(result->extRs, true);
NekoGui_sys::running_ext.splice(NekoGui_sys::running_ext.end(), extCs);
},
DS_cores);
NekoGui::dataStore->UpdateStartedId(ent->id);
running = ent;
@ -417,16 +377,6 @@ void MainWindow::neko_stop(bool crash, bool sem, bool manual) {
return;
}
runOnUiThread(
[=] {
while (!NekoGui_sys::running_ext.empty()) {
auto extC = NekoGui_sys::running_ext.front();
extC->Kill();
NekoGui_sys::running_ext.pop_front();
}
},
DS_cores);
auto neko_stop_stage2 = [=] {
if (!crash) {
bool rpcOK;

View File

@ -5,7 +5,6 @@
#include "include/ui/profile/edit_chain.h"
#include "include/ui/profile/edit_vmess.h"
#include "include/ui/profile/edit_trojan_vless.h"
#include "include/ui/profile/edit_naive.h"
#include "include/ui/profile/edit_quic.h"
#include "include/ui/profile/edit_wireguard.h"
#include "include/ui/profile/edit_ssh.h"
@ -156,7 +155,6 @@ DialogEditProfile::DialogEditProfile(const QString &_type, int profileOrGroupId,
LOAD_TYPE("trojan")
LOAD_TYPE("vmess")
LOAD_TYPE("vless")
LOAD_TYPE("naive")
LOAD_TYPE("hysteria")
LOAD_TYPE("hysteria2")
LOAD_TYPE("tuic")
@ -164,7 +162,6 @@ DialogEditProfile::DialogEditProfile(const QString &_type, int profileOrGroupId,
LOAD_TYPE("ssh")
ui->type->addItem(tr("Custom (%1 outbound)").arg(software_core_name), "internal");
ui->type->addItem(tr("Custom (%1 config)").arg(software_core_name), "internal-full");
ui->type->addItem(tr("Custom (Extra Core)"), "custom");
LOAD_TYPE("chain")
// type changed
@ -213,10 +210,6 @@ void DialogEditProfile::typeSelected(const QString &newType) {
auto _innerWidget = new EditTrojanVLESS(this);
innerWidget = _innerWidget;
innerEditor = _innerWidget;
} else if (type == "naive") {
auto _innerWidget = new EditNaive(this);
innerWidget = _innerWidget;
innerEditor = _innerWidget;
} else if (type == "hysteria" || type == "hysteria2" || type == "tuic") {
auto _innerWidget = new EditQUIC(this);
innerWidget = _innerWidget;
@ -229,7 +222,7 @@ void DialogEditProfile::typeSelected(const QString &newType) {
auto _innerWidget = new EditSSH(this);
innerWidget = _innerWidget;
innerEditor = _innerWidget;
} else if (type == "custom" || type == "internal" || type == "internal-full") {
} else if (type == "internal" || type == "internal-full") {
auto _innerWidget = new EditCustom(this);
innerWidget = _innerWidget;
innerEditor = _innerWidget;

View File

@ -114,16 +114,6 @@ void EditCustom::onStart(std::shared_ptr<NekoGui::ProxyEntity> _ent) {
MessageBoxInfo(software_name, result->error);
return;
}
for (const auto &extR: result->extRs) {
auto command = QStringList{extR->program};
command += extR->arguments;
auto btn = QMessageBox::information(this, tr("Preview config"),
QString("Command: %1\n\n%2").arg(QStringList2Command(command), extR->config_export),
"OK", "Copy", "", 0, 0);
if (btn == 1) {
QApplication::clipboard()->setText(extR->config_export);
}
}
});
}

View File

@ -1,67 +0,0 @@
#include "include/ui/profile/edit_naive.h"
#include "include/configs/proxy/NaiveBean.hpp"
#include <QInputDialog>
EditNaive::EditNaive(QWidget *parent) : QWidget(parent), ui(new Ui::EditNaive) {
ui->setupUi(this);
}
EditNaive::~EditNaive() {
delete ui;
}
void EditNaive::onStart(std::shared_ptr<NekoGui::ProxyEntity> _ent) {
this->ent = _ent;
auto bean = this->ent->NaiveBean();
P_LOAD_STRING(username);
P_LOAD_STRING(password);
P_LOAD_COMBO_STRING(protocol);
P_C_LOAD_STRING(extra_headers);
P_LOAD_STRING(sni);
P_C_LOAD_STRING(certificate);
P_LOAD_INT(insecure_concurrency);
P_LOAD_BOOL(disable_log);
}
bool EditNaive::onEnd() {
auto bean = this->ent->NaiveBean();
P_SAVE_STRING(username);
P_SAVE_STRING(password);
P_SAVE_COMBO_STRING(protocol);
P_C_SAVE_STRING(extra_headers);
P_SAVE_STRING(sni);
P_C_SAVE_STRING(certificate);
P_SAVE_INT(insecure_concurrency);
P_SAVE_BOOL(disable_log);
return true;
}
QList<QPair<QPushButton *, QString>> EditNaive::get_editor_cached() {
return {
{ui->certificate, CACHE.certificate},
{ui->extra_headers, CACHE.extra_headers},
};
}
void EditNaive::on_certificate_clicked() {
bool ok;
auto txt = QInputDialog::getMultiLineText(this, tr("Certificate"), "", CACHE.certificate, &ok);
if (ok) {
CACHE.certificate = txt;
editor_cache_updated();
}
}
void EditNaive::on_extra_headers_clicked() {
bool ok;
auto txt = QInputDialog::getMultiLineText(this, tr("Extra headers"), "", CACHE.extra_headers, &ok);
if (ok) {
CACHE.extra_headers = txt;
editor_cache_updated();
}
}

View File

@ -15,44 +15,6 @@
#include <QTimer>
#include <qfontdatabase.h>
class ExtraCoreWidget : public QWidget {
public:
QString coreName;
QLabel *label_name;
MyLineEdit *lineEdit_path;
QPushButton *pushButton_pick;
explicit ExtraCoreWidget(QJsonObject *extraCore, const QString &coreName_,
QWidget *parent = nullptr)
: QWidget(parent) {
coreName = coreName_;
label_name = new QLabel;
label_name->setText(coreName);
lineEdit_path = new MyLineEdit;
lineEdit_path->setText(extraCore->value(coreName).toString());
pushButton_pick = new QPushButton;
pushButton_pick->setText(QObject::tr("Select"));
auto layout = new QHBoxLayout;
layout->addWidget(label_name);
layout->addWidget(lineEdit_path);
layout->addWidget(pushButton_pick);
setLayout(layout);
setContentsMargins(0, 0, 0, 0);
//
connect(pushButton_pick, &QPushButton::clicked, this, [=] {
auto fn = QFileDialog::getOpenFileName(this, QObject::tr("Select"), QDir::currentPath(),
"", nullptr, QFileDialog::Option::ReadOnly);
if (!fn.isEmpty()) {
lineEdit_path->setText(fn);
}
});
connect(lineEdit_path, &QLineEdit::textChanged, this, [=](const QString &newTxt) {
extraCore->insert(coreName, newTxt);
});
}
};
DialogBasicSettings::DialogBasicSettings(QWidget *parent)
: QDialog(parent), ui(new Ui::DialogBasicSettings) {
ui->setupUi(this);
@ -169,46 +131,6 @@ DialogBasicSettings::DialogBasicSettings(QWidget *parent)
MW_show_log("Removed all rule-set files");
});
//
CACHE.extraCore = QString2QJsonObject(NekoGui::dataStore->extraCore->core_map);
if (!CACHE.extraCore.contains("naive")) CACHE.extraCore.insert("naive", "");
if (!CACHE.extraCore.contains("hysteria")) CACHE.extraCore.insert("hysteria", "");
if (!CACHE.extraCore.contains("hysteria2")) CACHE.extraCore.insert("hysteria2", "");
if (!CACHE.extraCore.contains("tuic")) CACHE.extraCore.insert("tuic", "");
//
auto extra_core_layout = ui->extra_core_box_scrollAreaWidgetContents->layout();
for (const auto &s: CACHE.extraCore.keys()) {
extra_core_layout->addWidget(new ExtraCoreWidget(&CACHE.extraCore, s));
}
//
connect(ui->extra_core_add, &QPushButton::clicked, this, [=] {
bool ok;
auto s = QInputDialog::getText(nullptr, tr("Add"),
tr("Please input the core name."),
QLineEdit::Normal, "", &ok)
.trimmed();
if (s.isEmpty() || !ok) return;
if (CACHE.extraCore.contains(s)) return;
extra_core_layout->addWidget(new ExtraCoreWidget(&CACHE.extraCore, s));
CACHE.extraCore.insert(s, "");
});
connect(ui->extra_core_del, &QPushButton::clicked, this, [=] {
bool ok;
auto s = QInputDialog::getItem(nullptr, tr("Delete"),
tr("Please select the core name."),
CACHE.extraCore.keys(), 0, false, &ok);
if (s.isEmpty() || !ok) return;
for (int i = 0; i < extra_core_layout->count(); i++) {
auto item = extra_core_layout->itemAt(i);
auto ecw = dynamic_cast<ExtraCoreWidget *>(item->widget());
if (ecw != nullptr && ecw->coreName == s) {
ecw->deleteLater();
CACHE.extraCore.remove(s);
return;
}
}
});
// Mux
D_LOAD_INT(mux_concurrency)
D_LOAD_COMBO_STRING(mux_protocol)
@ -290,7 +212,6 @@ void DialogBasicSettings::accept() {
D_SAVE_INT_ENABLE(sub_auto_update, sub_auto_update_enable)
// Core
NekoGui::dataStore->extraCore->core_map = QJsonObject2QString(CACHE.extraCore, true);
NekoGui::dataStore->disable_traffic_stats = ui->disable_stats->isChecked();
// Assets