lots of changes, will clarify later if works

This commit is contained in:
unknown 2024-04-30 10:59:33 +03:30
parent 773f07169b
commit 971e56937b
24 changed files with 132 additions and 712 deletions

View File

@ -25,25 +25,24 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checking out sources
uses: actions/checkout@v3
uses: actions/checkout@v4.1.4
- name: Go Status
run: git ls-files go | xargs cat | sha1sum > go_status
- name: Cache Common Download
id: cache-common
uses: actions/cache@v3
uses: actions/cache@v4.0.2
with:
path: artifacts.tgz
key: CommonCache-${{ matrix.cross_os }}-${{ matrix.cross_arch }}-${{ hashFiles('libs/*.sh', 'go_status', '*.txt') }}
- name: Install Golang
if: steps.cache-common.outputs.cache-hit != 'true'
uses: actions/setup-go@v3
uses: actions/setup-go@v5.0.0
with:
go-version: ^1.21
go-version: ^1.22
- name: Build golang parts
if: steps.cache-common.outputs.cache-hit != 'true'
shell: bash
run: |
[ ${{ matrix.cross_os }} == public_res ] || ./libs/get_source.sh
[ ${{ matrix.cross_os }} == public_res ] || GOOS=${{ matrix.cross_os }} GOARCH=${{ matrix.cross_arch }} ./libs/build_go.sh
[ ${{ matrix.cross_os }} == public_res ] || exit 0
./libs/build_public_res.sh
@ -51,7 +50,7 @@ jobs:
if: steps.cache-common.outputs.cache-hit != 'true'
run: tar czvf artifacts.tgz ./deployment
- name: Uploading Artifact
uses: actions/upload-artifact@master
uses: actions/upload-artifact@v4.3.3
with:
name: NekoRay-${{ github.sha }}-Common-${{ matrix.cross_os }}-${{ matrix.cross_arch }}
path: artifacts.tgz
@ -72,7 +71,7 @@ jobs:
ACTIONS_ALLOW_UNSECURE_COMMANDS: true
steps:
- name: Checking out sources
uses: actions/checkout@v3
uses: actions/checkout@v4.1.4
with:
submodules: "recursive"
- name: Install MSVC compiler
@ -94,7 +93,7 @@ jobs:
uses: seanmiddleditch/gha-setup-ninja@v3
- name: Cache Download
id: cache-deps
uses: actions/cache@v3
uses: actions/cache@v4.0.2
with:
path: libs/deps
key: DepsCache-${{ matrix.platform }}-${{ matrix.arch }}-${{ hashFiles('libs/build_deps_*.sh') }}-Qt${{ matrix.qt_version }}
@ -141,7 +140,7 @@ jobs:
shell: bash
run: tar czvf artifacts.tgz ./deployment
- name: Uploading Artifact
uses: actions/upload-artifact@master
uses: actions/upload-artifact@v4.3.3
with:
name: NekoRay-${{ github.sha }}-${{ matrix.platform }}-${{ matrix.arch }}-Qt${{ matrix.qt_version }}
path: artifacts.tgz
@ -154,9 +153,9 @@ jobs:
- build-go
steps:
- name: Checking out sources
uses: actions/checkout@v3
uses: actions/checkout@v4.1.4
- name: Download Artifacts
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4.1.7
with:
path: download-artifact
- name: Pack
@ -205,7 +204,7 @@ jobs:
rm -rf public_res
rm -rf *.pdb
- name: Uploading Artifact
uses: actions/upload-artifact@master
uses: actions/upload-artifact@v4.3.3
with:
name: Deployment-${{ github.sha }}
path: deployment

View File

@ -1,18 +0,0 @@
name: AUR CI
on:
push:
branches:
- main
paths-ignore:
- '**.md'
- 'LICENSE'
- '!.github/workflows/**'
jobs:
update:
runs-on: ubuntu-latest
steps:
- uses: chitang233/aur-pkgbuild-builder@main
with:
deploy_key: ${{ secrets.DEPLOY_KEY }}
package_name: 'nekoray-git'

View File

@ -166,7 +166,6 @@ set(PROJECT_SOURCES
db/ConfigBuilder.cpp
fmt/AbstractBean.cpp
fmt/Bean2CoreObj_ray.cpp
fmt/Bean2CoreObj_box.cpp
fmt/Bean2External.cpp
fmt/Bean2Link.cpp

View File

@ -66,11 +66,7 @@ namespace NekoGui {
if (customBean != nullptr && customBean->core == "internal-full") {
result->coreConfig = QString2QJsonObject(customBean->config_simple);
} else {
if (IS_NEKO_BOX) {
BuildConfigSingBox(status);
} else {
BuildConfigV2Ray(status);
}
BuildConfigSingBox(status);
}
// apply custom config
@ -172,254 +168,6 @@ namespace NekoGui {
status->ipListDirect += line; \
}
// V2Ray
void BuildConfigV2Ray(const std::shared_ptr<BuildConfigStatus> &status) {
// Log
auto logObj = QJsonObject{{"loglevel", dataStore->log_level}};
status->result->coreConfig.insert("log", logObj);
// Inbounds
QJsonObject sniffing{
{"destOverride", QJsonArray{"http", "tls", "quic"}},
{"enabled", true},
{"metadataOnly", false},
{"routeOnly", dataStore->routing->sniffing_mode == SniffingMode::FOR_ROUTING},
};
// socks-in
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->routing->sniffing_mode != SniffingMode::DISABLE) {
inboundObj["sniffing"] = sniffing;
}
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 (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->routing->sniffing_mode != SniffingMode::DISABLE) {
inboundObj["sniffing"] = sniffing;
}
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
auto tagProxy = BuildChain(0, status);
if (!status->result->error.isEmpty()) return;
// direct & bypass & block
status->outbounds += QJsonObject{
{"protocol", "freedom"},
{"domainStrategy", dataStore->core_ray_freedom_domainStrategy},
{"tag", "direct"},
};
status->outbounds += QJsonObject{
{"protocol", "freedom"},
{"domainStrategy", dataStore->core_ray_freedom_domainStrategy},
{"tag", "bypass"},
};
status->outbounds += QJsonObject{
{"protocol", "blackhole"},
{"tag", "block"},
};
// DNS out
if (!status->forTest) {
QJsonObject dnsOut;
dnsOut["protocol"] = "dns";
dnsOut["tag"] = "dns-out";
QJsonObject dnsOut_settings;
dnsOut_settings["network"] = "tcp";
dnsOut_settings["port"] = 53;
dnsOut_settings["address"] = "8.8.8.8";
dnsOut_settings["userLevel"] = 1;
dnsOut["settings"] = dnsOut_settings;
dnsOut["proxySettings"] = QJsonObject{{"tag", tagProxy},
{"transportLayer", true}};
status->outbounds += dnsOut;
status->routingRules += QJsonObject{
{"type", "field"},
{"port", "53"},
{"inboundTag", QJsonArray{"socks-in", "http-in"}},
{"outboundTag", "dns-out"},
};
}
// custom inbound
if (!status->forTest) QJSONARRAY_ADD(status->inbounds, QString2QJsonObject(dataStore->custom_inbound)["inbounds"].toArray())
status->result->coreConfig.insert("inbounds", status->inbounds);
status->result->coreConfig.insert("outbounds", status->outbounds);
// user rule
if (!status->forTest) {
DOMAIN_USER_RULE
IP_USER_RULE
}
// final add DNS
QJsonObject dns;
QJsonArray dnsServers;
// Remote or FakeDNS
QJsonObject dnsServerRemote;
dnsServerRemote["address"] = dataStore->routing->remote_dns;
dnsServerRemote["domains"] = QList2QJsonArray<QString>(status->domainListDNSRemote);
dnsServerRemote["queryStrategy"] = dataStore->routing->remote_dns_strategy;
if (!status->forTest) dnsServers += dnsServerRemote;
// Direct
auto directDnsAddress = dataStore->routing->direct_dns;
if (directDnsAddress.contains("://")) {
auto directDnsIp = SubStrBefore(SubStrAfter(directDnsAddress, "://"), "/");
if (IsIpAddress(directDnsIp)) {
status->routingRules.push_front(QJsonObject{
{"type", "field"},
{"ip", QJsonArray{directDnsIp}},
{"outboundTag", "direct"},
});
} else {
status->routingRules.push_front(QJsonObject{
{"type", "field"},
{"domain", QJsonArray{directDnsIp}},
{"outboundTag", "direct"},
});
}
} else if (directDnsAddress != "localhost") {
status->routingRules.push_front(QJsonObject{
{"type", "field"},
{"ip", QJsonArray{directDnsAddress}},
{"outboundTag", "direct"},
});
}
QJsonObject directObj{
{"address", directDnsAddress.replace("https://", "https+local://")},
{"queryStrategy", dataStore->routing->direct_dns_strategy},
{"domains", QList2QJsonArray<QString>(status->domainListDNSDirect)},
};
if (dataStore->routing->dns_final_out == "bypass") {
dnsServers.prepend(directObj);
} else {
dnsServers.append(directObj);
}
dns["disableFallback"] = true;
dns["servers"] = dnsServers;
dns["tag"] = "dns";
if (dataStore->routing->use_dns_object) {
dns = QString2QJsonObject(dataStore->routing->dns_object);
}
status->result->coreConfig.insert("dns", dns);
// Routing
QJsonObject routing;
routing["domainStrategy"] = dataStore->routing->domain_strategy;
if (status->forTest) routing["domainStrategy"] = "AsIs";
// final add user rule (block)
QJsonObject routingRule_tmp;
routingRule_tmp["type"] = "field";
routingRule_tmp["outboundTag"] = "block";
if (!status->ipListBlock.isEmpty()) {
auto tmp = routingRule_tmp;
tmp["ip"] = QList2QJsonArray<QString>(status->ipListBlock);
status->routingRules += tmp;
}
if (!status->domainListBlock.isEmpty()) {
auto tmp = routingRule_tmp;
tmp["domain"] = QList2QJsonArray<QString>(status->domainListBlock);
status->routingRules += tmp;
}
// final add user rule (proxy)
routingRule_tmp["outboundTag"] = "proxy";
if (!status->ipListRemote.isEmpty()) {
auto tmp = routingRule_tmp;
tmp["ip"] = QList2QJsonArray<QString>(status->ipListRemote);
status->routingRules += tmp;
}
if (!status->domainListRemote.isEmpty()) {
auto tmp = routingRule_tmp;
tmp["domain"] = QList2QJsonArray<QString>(status->domainListRemote);
status->routingRules += tmp;
}
// final add user rule (bypass)
routingRule_tmp["outboundTag"] = "bypass";
if (!status->ipListDirect.isEmpty()) {
auto tmp = routingRule_tmp;
tmp["ip"] = QList2QJsonArray<QString>(status->ipListDirect);
status->routingRules += tmp;
}
if (!status->domainListDirect.isEmpty()) {
auto tmp = routingRule_tmp;
tmp["domain"] = QList2QJsonArray<QString>(status->domainListDirect);
status->routingRules += tmp;
}
// def_outbound
if (!status->forTest) status->routingRules += QJsonObject{
{"type", "field"},
{"port", "0-65535"},
{"outboundTag", dataStore->routing->def_outbound},
};
// final add routing rule
auto routingRules = QString2QJsonObject(dataStore->routing->custom)["rules"].toArray();
if (status->forTest) routingRules = {};
if (!status->forTest) QJSONARRAY_ADD(routingRules, QString2QJsonObject(dataStore->custom_route_global)["rules"].toArray())
QJSONARRAY_ADD(routingRules, status->routingRules)
routing["rules"] = routingRules;
status->result->coreConfig.insert("routing", routing);
// Policy & stats
QJsonObject policy;
QJsonObject levels;
QJsonObject level1;
level1["connIdle"] = 30;
levels["1"] = level1;
policy["levels"] = levels;
QJsonObject policySystem;
policySystem["statsOutboundDownlink"] = true;
policySystem["statsOutboundUplink"] = true;
policy["system"] = policySystem;
status->result->coreConfig.insert("policy", policy);
status->result->coreConfig.insert("stats", QJsonObject());
}
QString BuildChainInternal(int chainId, const QList<std::shared_ptr<ProxyEntity>> &ents,
const std::shared_ptr<BuildConfigStatus> &status) {
QString chainTag = "c-" + Int2String(chainId);
@ -472,26 +220,16 @@ namespace NekoGui {
if (IS_NEKO_BOX) {
replaced["detour"] = tagOut;
} else {
replaced["proxySettings"] = QJsonObject{
{"tag", tagOut},
{"transportLayer", true},
};
status->result->error = "Xray is no longer supported";
return {};
}
status->outbounds.removeLast();
status->outbounds += replaced;
} else {
if (IS_NEKO_BOX) {
status->routingRules += QJsonObject{
{"inbound", QJsonArray{pastTag + "-mapping"}},
{"outbound", tagOut},
};
} else {
status->routingRules += QJsonObject{
{"type", "field"},
{"inboundTag", QJsonArray{pastTag + "-mapping"}},
{"outboundTag", tagOut},
};
}
status->routingRules += QJsonObject{
{"inbound", QJsonArray{pastTag + "-mapping"}},
{"outbound", tagOut},
};
}
} else {
// index == 0 means last profile in chain / not chain
@ -530,43 +268,20 @@ namespace NekoGui {
if (thisExternalStat == 2) dataStore->need_keep_vpn_off = true;
if (thisExternalStat == 1) {
// mapping
if (IS_NEKO_BOX) {
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},
};
} else {
status->inbounds += QJsonObject{
{"protocol", "dokodemo-door"},
{"tag", tagOut + "-mapping"},
{"listen", "127.0.0.1"},
{"port", ext_mapping_port},
{"settings", QJsonObject{
// to
{"address", ent->bean->serverAddress},
{"port", ent->bean->serverPort},
{"network", "tcp,udp"},
}},
};
}
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) {
if (IS_NEKO_BOX) {
status->routingRules += QJsonObject{
{"inbound", QJsonArray{tagOut + "-mapping"}},
{"outbound", "direct"},
};
} else {
status->routingRules += QJsonObject{
{"type", "field"},
{"inboundTag", QJsonArray{tagOut + "-mapping"}},
{"outboundTag", "direct"},
};
}
status->routingRules += QJsonObject{
{"inbound", QJsonArray{tagOut + "-mapping"}},
{"outbound", "direct"},
};
}
}
@ -589,23 +304,11 @@ namespace NekoGui {
status->result->extRs.emplace_back(std::make_shared<NekoGui_fmt::ExternalBuildResult>(extR));
// SOCKS OUTBOUND
if (IS_NEKO_BOX) {
outbound["type"] = "socks";
outbound["server"] = "127.0.0.1";
outbound["server_port"] = ext_socks_port;
} else {
outbound["protocol"] = "socks";
QJsonObject settings;
QJsonArray servers;
QJsonObject server;
server["address"] = "127.0.0.1";
server["port"] = ext_socks_port;
servers.push_back(server);
settings["servers"] = servers;
outbound["settings"] = settings;
}
outbound["type"] = "socks";
outbound["server"] = "127.0.0.1";
outbound["server_port"] = ext_socks_port;
} else {
const auto coreR = IS_NEKO_BOX ? ent->bean->BuildCoreObjSingBox() : ent->bean->BuildCoreObjV2Ray();
const auto coreR = ent->bean->BuildCoreObjSingBox();
if (coreR.outbound.isEmpty()) {
status->result->error = "unsupported outbound";
return {};
@ -624,58 +327,41 @@ namespace NekoGui {
status->result->outboundStats += ent->traffic_data;
// mux common
auto needMux = ent->type == "vmess" || ent->type == "trojan" || ent->type == "vless";
auto needMux = ent->type == "vmess" || ent->type == "trojan" || ent->type == "vless" || ent->type == "shadowsocks";
needMux &= dataStore->mux_concurrency > 0;
if (stream != nullptr) {
if (IS_NEKO_BOX) {
if (stream->network == "grpc" || stream->network == "quic" || (stream->network == "http" && stream->security == "tls")) {
needMux = false;
}
} else {
if (stream->network == "grpc" || stream->network == "quic") {
needMux = false;
}
}
if (stream->multiplex_status == 0) {
if (!dataStore->mux_default_on) needMux = false;
} else if (stream->multiplex_status == 1) {
needMux = true;
} else if (stream->multiplex_status == 2) {
if (stream->network == "grpc" || stream->network == "quic" || (stream->network == "http" && stream->security == "tls")) {
needMux = false;
}
}
auto mux_state = ent->bean->mux_state;
if (mux_state == 0) {
if (!dataStore->mux_default_on) needMux = false;
} else if (mux_state == 1) {
needMux = true;
} else if (mux_state == 2) {
needMux = false;
}
if (ent->type == "vless" && outbound["flow"] != "") {
needMux = false;
}
// common
if (IS_NEKO_BOX) {
// apply domain_strategy
outbound["domain_strategy"] = dataStore->routing->outbound_domain_strategy;
// apply mux
if (!muxApplied && needMux) {
auto muxObj = QJsonObject{
{"enabled", true},
{"protocol", dataStore->mux_protocol},
{"padding", dataStore->mux_padding},
{"max_streams", dataStore->mux_concurrency},
};
outbound["multiplex"] = muxObj;
muxApplied = true;
}
} else {
// apply domain_strategy
if (!status->forTest) outbound["domainStrategy"] = dataStore->routing->outbound_domain_strategy;
// apply mux
if (!muxApplied && needMux) {
auto muxObj = QJsonObject{
{"enabled", true},
{"concurrency", dataStore->mux_concurrency},
};
outbound["mux"] = muxObj;
muxApplied = true;
}
// apply domain_strategy
outbound["domain_strategy"] = dataStore->routing->outbound_domain_strategy;
// apply mux
if (!muxApplied && needMux) {
auto muxObj = QJsonObject{
{"enabled", true},
{"protocol", dataStore->mux_protocol},
{"padding", dataStore->mux_padding},
{"max_streams", dataStore->mux_concurrency},
};
outbound["multiplex"] = muxObj;
muxApplied = true;
}
// apply custom outbound settings
@ -735,7 +421,7 @@ namespace NekoGui {
}
// tun-in
if (IS_NEKO_BOX_INTERNAL_TUN && dataStore->spmode_vpn && !status->forTest) {
if (dataStore->spmode_vpn && !status->forTest) {
QJsonObject inboundObj;
inboundObj["tag"] = "tun-in";
inboundObj["type"] = "tun";
@ -885,7 +571,7 @@ namespace NekoGui {
};
// Fakedns
if (dataStore->fake_dns && IS_NEKO_BOX_INTERNAL_TUN && dataStore->spmode_vpn && !status->forTest) {
if (dataStore->fake_dns && dataStore->spmode_vpn && !status->forTest) {
dnsServers += QJsonObject{
{"tag", "dns-fake"},
{"address", "fakeip"},
@ -927,7 +613,7 @@ namespace NekoGui {
}
// fakedns rule
if (dataStore->fake_dns && IS_NEKO_BOX_INTERNAL_TUN && dataStore->spmode_vpn && !status->forTest) {
if (dataStore->fake_dns && dataStore->spmode_vpn && !status->forTest) {
dnsRules += QJsonObject{
{"inbound", "tun-in"},
{"server", "dns-fake"},
@ -970,11 +656,6 @@ namespace NekoGui {
add_rule_route(status->ipListDirect, true, "bypass");
// built-in rules
status->routingRules += QJsonObject{
{"network", "udp"},
{"port", QJsonArray{135, 137, 138, 139, 5353}},
{"outbound", "block"},
};
status->routingRules += QJsonObject{
{"ip_cidr", QJsonArray{"224.0.0.0/3", "ff00::/8"}},
{"outbound", "block"},
@ -985,7 +666,7 @@ namespace NekoGui {
};
// tun user rule
if (IS_NEKO_BOX_INTERNAL_TUN && dataStore->spmode_vpn && !status->forTest) {
if (dataStore->spmode_vpn && !status->forTest) {
auto match_out = dataStore->vpn_rule_white ? "proxy" : "bypass";
QString process_name_rule = dataStore->vpn_rule_process.trimmed();
@ -1025,7 +706,7 @@ namespace NekoGui {
QJSONARRAY_ADD(routingRules, status->routingRules)
auto routeObj = QJsonObject{
{"rules", routingRules},
{"auto_detect_interface", dataStore->spmode_vpn},
{"auto_detect_interface", true},
{
"geoip",
QJsonObject{

View File

@ -46,8 +46,6 @@ namespace NekoGui {
std::shared_ptr<BuildConfigResult> BuildConfig(const std::shared_ptr<ProxyEntity> &ent, bool forTest, bool forExport);
void BuildConfigV2Ray(const std::shared_ptr<BuildConfigStatus> &status);
void BuildConfigSingBox(const std::shared_ptr<BuildConfigStatus> &status);
QString BuildChain(int chainId, const std::shared_ptr<BuildConfigStatus> &status);

View File

@ -34,6 +34,7 @@ namespace NekoGui_fmt {
QString custom_config = "";
QString custom_outbound = "";
int mux_state = 0;
explicit AbstractBean(int version);
@ -59,8 +60,6 @@ namespace NekoGui_fmt {
virtual int NeedExternal(bool isFirstProfile) { return 0; };
virtual CoreObjOutboundBuildResult BuildCoreObjV2Ray() { return {}; };
virtual CoreObjOutboundBuildResult BuildCoreObjSingBox() { return {}; };
virtual ExternalBuildResult BuildExternal(int mapping_port, int socks_port, int external_stat) { return {}; };

View File

@ -200,10 +200,6 @@ namespace NekoGui_fmt {
outbound["up_mbps"] = uploadMbps;
outbound["down_mbps"] = downloadMbps;
if (!hopPort.trimmed().isEmpty()) {
outbound["hop_ports"] = hopPort;
outbound["hop_interval"] = hopInterval;
}
if (authPayloadType == hysteria_auth_base64) outbound["auth"] = authPayload;
if (authPayloadType == hysteria_auth_string) outbound["auth_str"] = authPayload;
} else if (proxy_type == proxy_Hysteria2) {
@ -211,11 +207,7 @@ namespace NekoGui_fmt {
outbound["password"] = password;
outbound["up_mbps"] = uploadMbps;
outbound["down_mbps"] = downloadMbps;
if (!hopPort.trimmed().isEmpty()) {
outbound["hop_ports"] = hopPort;
outbound["hop_interval"] = hopInterval;
}
if (!obfsPassword.isEmpty()) {
outbound["obfs"] = QJsonObject{
{"type", "salamander"},

View File

@ -1,211 +0,0 @@
#include "db/ProxyEntity.hpp"
#include "fmt/includes.h"
#define MAKE_SETTINGS_STREAM_SETTINGS \
outbound["settings"] = settings; \
auto streamSettings = stream->BuildStreamSettingsV2Ray(); \
outbound["streamSettings"] = streamSettings;
namespace NekoGui_fmt {
QJsonObject V2rayStreamSettings::BuildStreamSettingsV2Ray() {
QJsonObject streamSettings{{"network", network}};
if (network == "ws") {
QJsonObject ws;
if (!host.isEmpty()) ws["headers"] = QJsonObject{{"Host", host}};
// ws path & ed
if (!path.isEmpty()) ws["path"] = path;
streamSettings["wsSettings"] = ws;
} else if (network == "http") {
QJsonObject http;
if (!path.isEmpty()) http["path"] = path;
if (!host.isEmpty()) http["host"] = QList2QJsonArray(host.split(","));
streamSettings["httpSettings"] = http;
} else if (network == "grpc") {
QJsonObject grpc;
if (!path.isEmpty()) grpc["serviceName"] = path;
streamSettings["grpcSettings"] = grpc;
} else if (network == "quic") {
QJsonObject quic;
if (!header_type.isEmpty()) quic["header"] = QJsonObject{{"type", header_type}};
if (!path.isEmpty()) quic["key"] = path;
if (!host.isEmpty()) quic["security"] = host;
streamSettings["quicSettings"] = quic;
} else if (network == "tcp" && !header_type.isEmpty()) {
QJsonObject header{{"type", header_type}};
if (header_type == "http") {
header["request"] = QJsonObject{
{"path", QList2QJsonArray(path.split(","))},
{"headers", QJsonObject{{"Host", QList2QJsonArray(host.split(","))}}},
};
}
streamSettings["tcpSettings"] = QJsonObject{{"header", header}};
}
if (security == "tls") {
QJsonObject tls;
if (!utlsFingerprint.isEmpty()) tls["fingerprint"] = utlsFingerprint;
if (!sni.trimmed().isEmpty()) tls["serverName"] = sni;
if (reality_pbk.trimmed().isEmpty()) {
if (allow_insecure || NekoGui::dataStore->skip_cert) tls["allowInsecure"] = true;
if (!alpn.trimmed().isEmpty()) tls["alpn"] = QList2QJsonArray(alpn.split(","));
if (!certificate.trimmed().isEmpty()) {
tls["disableSystemRoot"] = true;
tls["certificates"] = QJsonArray{
QJsonObject{
{"usage", "verify"},
{"certificate", QList2QJsonArray(SplitLines(certificate.trimmed()))},
},
};
}
streamSettings["tlsSettings"] = tls;
streamSettings["security"] = "tls";
} else {
tls["publicKey"] = reality_pbk;
tls["shortId"] = reality_sid;
tls["spiderX"] = reality_spx;
if (utlsFingerprint.isEmpty()) tls["fingerprint"] = "chrome";
streamSettings["realitySettings"] = tls;
streamSettings["security"] = "reality";
}
}
return streamSettings;
}
CoreObjOutboundBuildResult SocksHttpBean::BuildCoreObjV2Ray() {
CoreObjOutboundBuildResult result;
QJsonObject outbound;
outbound["protocol"] = socks_http_type == type_HTTP ? "http" : "socks";
QJsonObject settings;
QJsonArray servers;
QJsonObject server;
server["address"] = serverAddress;
server["port"] = serverPort;
QJsonArray users;
QJsonObject user;
user["user"] = username;
user["pass"] = password;
users.push_back(user);
if (!username.isEmpty() && !password.isEmpty()) server["users"] = users;
servers.push_back(server);
settings["servers"] = servers;
MAKE_SETTINGS_STREAM_SETTINGS
result.outbound = outbound;
return result;
}
CoreObjOutboundBuildResult ShadowSocksBean::BuildCoreObjV2Ray() {
CoreObjOutboundBuildResult result;
QJsonObject outbound{{"protocol", "shadowsocks"}};
QJsonObject settings;
QJsonArray servers;
QJsonObject server;
server["address"] = serverAddress;
server["port"] = serverPort;
server["method"] = method;
server["password"] = password;
if (uot != 0) {
server["uot"] = true;
server["UoTVersion"] = uot;
} else {
server["uot"] = false;
}
servers.push_back(server);
settings["servers"] = servers;
if (!plugin.trimmed().isEmpty()) {
settings["plugin"] = SubStrBefore(plugin, ";");
settings["pluginOpts"] = SubStrAfter(plugin, ";");
}
MAKE_SETTINGS_STREAM_SETTINGS
result.outbound = outbound;
return result;
}
CoreObjOutboundBuildResult VMessBean::BuildCoreObjV2Ray() {
CoreObjOutboundBuildResult result;
QJsonObject outbound{{"protocol", "vmess"}};
QJsonObject settings{
{"vnext", QJsonArray{
QJsonObject{
{"address", serverAddress},
{"port", serverPort},
{"users", QJsonArray{
QJsonObject{
{"id", uuid.trimmed()},
{"alterId", aid},
{"security", security},
}}},
}}}};
MAKE_SETTINGS_STREAM_SETTINGS
result.outbound = outbound;
return result;
}
CoreObjOutboundBuildResult TrojanVLESSBean::BuildCoreObjV2Ray() {
CoreObjOutboundBuildResult result;
QJsonObject outbound{
{"protocol", proxy_type == proxy_VLESS ? "vless" : "trojan"},
};
QJsonObject settings;
if (proxy_type == proxy_VLESS) {
if (flow == "none") {
flow = "";
}
settings = QJsonObject{
{"vnext", QJsonArray{
QJsonObject{
{"address", serverAddress},
{"port", serverPort},
{"users", QJsonArray{
QJsonObject{
{"id", password.trimmed()},
{"encryption", "none"},
{"flow", flow},
}}},
}}}};
} else {
settings = QJsonObject{
{"servers", QJsonArray{
QJsonObject{
{"address", serverAddress},
{"port", serverPort},
{"password", password},
}}}};
}
MAKE_SETTINGS_STREAM_SETTINGS
result.outbound = outbound;
return result;
}
CoreObjOutboundBuildResult CustomBean::BuildCoreObjV2Ray() {
CoreObjOutboundBuildResult result;
if (core == "internal") {
result.outbound = QString2QJsonObject(config_simple);
}
return result;
}
} // namespace NekoGui_fmt

View File

@ -64,6 +64,13 @@ namespace NekoGui_fmt {
}
}
// mux
if (mux_state == 1) {
query.addQueryItem("mux", "true");
} else if (mux_state == 2) {
query.addQueryItem("mux", "false");
}
// protocol
if (proxy_type == proxy_VLESS) {
if (!flow.isEmpty()) {
@ -92,6 +99,20 @@ namespace NekoGui_fmt {
if (!name.isEmpty()) url.setFragment(name);
QUrlQuery q;
if (!plugin.isEmpty()) q.addQueryItem("plugin", plugin);
// mux
if (mux_state == 1) {
q.addQueryItem("mux", "true");
} else if (mux_state == 2) {
q.addQueryItem("mux", "false");
}
// uot
if (uot == 1) {
q.addQueryItem("uot", "1");
} else if (uot == 2) {
q.addQueryItem("uot", "2");
}
if (!q.isEmpty()) url.setQuery(q);
//
auto link = url.toString(QUrl::FullyEncoded);
@ -164,6 +185,13 @@ namespace NekoGui_fmt {
}
}
// mux
if (mux_state == 1) {
query.addQueryItem("mux", "true");
} else if (mux_state == 2) {
query.addQueryItem("mux", "false");
}
url.setQuery(query);
return url.toString(QUrl::FullyEncoded);
}
@ -196,7 +224,6 @@ namespace NekoGui_fmt {
if (authPayloadType == hysteria_auth_string) q.addQueryItem("auth", authPayload);
if (hyProtocol == hysteria_protocol_facktcp) q.addQueryItem("protocol", "faketcp");
if (hyProtocol == hysteria_protocol_wechat_video) q.addQueryItem("protocol", "wechat-video");
if (!hopPort.trimmed().isEmpty()) q.addQueryItem("mport", hopPort);
if (allowInsecure) q.addQueryItem("insecure", "1");
if (!sni.isEmpty()) q.addQueryItem("peer", sni);
if (!alpn.isEmpty()) q.addQueryItem("alpn", alpn);
@ -235,7 +262,6 @@ namespace NekoGui_fmt {
q.addQueryItem("obfs", "salamander");
q.addQueryItem("obfs-password", obfsPassword);
}
if (!hopPort.trimmed().isEmpty()) q.addQueryItem("mport", hopPort);
if (allowInsecure) q.addQueryItem("insecure", "1");
if (!sni.isEmpty()) q.addQueryItem("sni", sni);
if (!q.isEmpty()) url.setQuery(q);

View File

@ -36,11 +36,7 @@ namespace NekoGui_fmt {
QString DisplayAddress() override {
if (core == "internal") {
auto obj = QString2QJsonObject(config_simple);
if (IS_NEKO_BOX) {
return ::DisplayAddress(obj["server"].toString(), obj["server_port"].toInt());
} else {
return {};
}
return ::DisplayAddress(obj["server"].toString(), obj["server_port"].toInt());
} else if (core == "internal-full") {
return {};
}
@ -52,7 +48,5 @@ namespace NekoGui_fmt {
ExternalBuildResult BuildExternal(int mapping_port, int socks_port, int external_stat) override;
CoreObjOutboundBuildResult BuildCoreObjSingBox() override;
CoreObjOutboundBuildResult BuildCoreObjV2Ray() override;
};
} // namespace NekoGui_fmt

View File

@ -100,6 +100,14 @@ namespace NekoGui_fmt {
}
}
// mux
auto mux_str = GetQueryValue(query, "mux", "");
if (mux_str == "true") {
mux_state = 1;
} else if (mux_str == "false") {
mux_state = 2;
}
// protocol
if (proxy_type == proxy_VLESS) {
flow = GetQueryValue(query, "flow", "");
@ -132,6 +140,13 @@ namespace NekoGui_fmt {
auto query = GetQuery(url);
plugin = query.queryItemValue("plugin").replace("simple-obfs;", "obfs-local;");
auto mux_str = GetQueryValue(query, "mux", "");
if (mux_str == "true") {
mux_state = 1;
} else if (mux_str == "false") {
mux_state = 2;
}
} else {
// v2rayN
DECODE_V2RAY_N_1
@ -210,6 +225,14 @@ namespace NekoGui_fmt {
stream->utlsFingerprint = NekoGui::dataStore->utlsFingerprint;
}
// mux
auto mux_str = GetQueryValue(query, "mux", "");
if (mux_str == "true") {
mux_state = 1;
} else if (mux_str == "false") {
mux_state = 2;
}
// type
if (stream->network == "ws") {
stream->path = GetQueryValue(query, "path", "");
@ -263,7 +286,6 @@ namespace NekoGui_fmt {
name = url.fragment(QUrl::FullyDecoded);
serverAddress = url.host();
serverPort = url.port();
hopPort = query.queryItemValue("mport");
obfsPassword = query.queryItemValue("obfsParam");
allowInsecure = QStringList{"1", "true"}.contains(query.queryItemValue("insecure"));
uploadMbps = query.queryItemValue("upmbps").toInt();
@ -308,7 +330,6 @@ namespace NekoGui_fmt {
name = url.fragment(QUrl::FullyDecoded);
serverAddress = url.host();
serverPort = url.port();
hopPort = query.queryItemValue("mport");
obfsPassword = query.queryItemValue("obfs-password");
allowInsecure = QStringList{"1", "true"}.contains(query.queryItemValue("insecure"));

View File

@ -23,8 +23,6 @@ namespace NekoGui_fmt {
QString DisplayType() override { return "Shadowsocks"; };
CoreObjOutboundBuildResult BuildCoreObjV2Ray() override;
CoreObjOutboundBuildResult BuildCoreObjSingBox() override;
bool TryParseLink(const QString &link);

View File

@ -26,8 +26,6 @@ namespace NekoGui_fmt {
QString DisplayType() override { return socks_http_type == type_HTTP ? "HTTP" : "Socks"; };
CoreObjOutboundBuildResult BuildCoreObjV2Ray() override;
CoreObjOutboundBuildResult BuildCoreObjSingBox() override;
bool TryParseLink(const QString &link);

View File

@ -24,8 +24,6 @@ namespace NekoGui_fmt {
QString DisplayType() override { return proxy_type == proxy_VLESS ? "VLESS" : "Trojan"; };
CoreObjOutboundBuildResult BuildCoreObjV2Ray() override;
CoreObjOutboundBuildResult BuildCoreObjSingBox() override;
bool TryParseLink(const QString &link);

View File

@ -26,8 +26,6 @@ namespace NekoGui_fmt {
QString reality_pbk = "";
QString reality_sid = "";
QString reality_spx = "";
// multiplex
int multiplex_status = 0;
V2rayStreamSettings() : JsonStore() {
_add(new configItem("net", &network, itemType::string));
@ -46,11 +44,8 @@ namespace NekoGui_fmt {
_add(new configItem("pbk", &reality_pbk, itemType::string));
_add(new configItem("sid", &reality_sid, itemType::string));
_add(new configItem("spx", &reality_spx, itemType::string));
_add(new configItem("mux_s", &multiplex_status, itemType::integer));
}
QJsonObject BuildStreamSettingsV2Ray();
void BuildStreamSettingsSingBox(QJsonObject *outbound);
};

View File

@ -21,8 +21,6 @@ namespace NekoGui_fmt {
QString DisplayType() override { return "VMess"; };
CoreObjOutboundBuildResult BuildCoreObjV2Ray() override;
CoreObjOutboundBuildResult BuildCoreObjSingBox() override;
bool TryParseLink(const QString &link);

View File

@ -23,15 +23,6 @@ pushd go/cmd/updater
[ "$GOOS" == "linux" ] && mv $DEST/updater $DEST/launcher || true
popd
#### Go: nekoray_core ####
neko_common="github.com/matsuridayo/libneko/neko_common"
pushd ../Xray-core
Version_Xray=$(git log --pretty=format:'%h' -n 1)
popd
pushd go/cmd/nekoray_core
go build -v -o $DEST -trimpath -ldflags "-w -s -X $neko_common.Version_v2ray=$Version_Xray -X $neko_common.Version_neko=$version_standalone"
popd
#### Go: nekobox_core ####
pushd go/cmd/nekobox_core
go build -v -o $DEST -trimpath -ldflags "-w -s -X $neko_common.Version_neko=$version_standalone" -tags "with_clash_api,with_gvisor,with_quic,with_wireguard,with_utls,with_ech"

View File

@ -18,7 +18,6 @@ namespace NekoGui {
namespace CoreType {
enum CoreType {
V2RAY,
SING_BOX,
};
}

View File

@ -8,7 +8,7 @@
// Switch core support
namespace NekoGui {
inline int coreType = CoreType::V2RAY;
inline int coreType = CoreType::SING_BOX;
QString FindCoreAsset(const QString &name);

View File

@ -164,19 +164,13 @@ int main(int argc, char* argv[]) {
if (coreLoaded.isEmpty()) {
NekoGui::coreType = -1;
loadTranslate(QLocale().name());
auto dialogFirstSetup = new DialogFirstSetup;
dialogFirstSetup->exec();
dialogFirstSetup->deleteLater();
if (NekoGui::coreType < 0) {
return 0;
} else {
QDir().mkdir("groups");
QFile file;
file.setFileName("groups/coreType");
file.open(QIODevice::ReadWrite | QIODevice::Truncate);
file.write(Int2String(NekoGui::coreType).toUtf8());
file.close();
}
NekoGui::coreType = NekoGui::CoreType::SING_BOX;
QDir().mkdir("groups");
QFile file;
file.setFileName("groups/coreType");
file.open(QIODevice::ReadWrite | QIODevice::Truncate);
file.write(Int2String(NekoGui::coreType).toUtf8());
file.close();
} else {
NekoGui::coreType = coreLoaded.toInt();
}
@ -200,9 +194,6 @@ int main(int argc, char* argv[]) {
// Load dataStore
switch (NekoGui::coreType) {
case NekoGui::CoreType::V2RAY:
NekoGui::dataStore->fn = "groups/nekoray.json";
break;
case NekoGui::CoreType::SING_BOX:
NekoGui::dataStore->fn = "groups/nekobox.json";
break;

View File

@ -278,7 +278,7 @@ namespace NekoGui_sub {
// sing-mux
auto smux = NodeChild(proxy, {"smux"});
if (Node2Bool(smux["enabled"])) bean->stream->multiplex_status = 1;
if (Node2Bool(smux["enabled"])) bean->mux_state = 1;
} else if (type == "socks" || type == "http") {
auto bean = ent->SocksHTTPBean();
bean->username = Node2QString(proxy["username"]);
@ -313,7 +313,7 @@ namespace NekoGui_sub {
// sing-mux
auto smux = NodeChild(proxy, {"smux"});
if (Node2Bool(smux["enabled"])) bean->stream->multiplex_status = 1;
if (Node2Bool(smux["enabled"])) bean->mux_state = 1;
// opts
auto ws = NodeChild(proxy, {"ws-opts", "ws-opt"});
@ -358,7 +358,7 @@ namespace NekoGui_sub {
// sing-mux
auto smux = NodeChild(proxy, {"smux"});
if (Node2Bool(smux["enabled"])) bean->stream->multiplex_status = 1;
if (Node2Bool(smux["enabled"])) bean->mux_state = 1;
// meta packet encoding
if (Node2Bool(proxy["xudp"])) bean->stream->packet_encoding = "xudp";

View File

@ -218,31 +218,7 @@ DialogBasicSettings::DialogBasicSettings(QWidget *parent)
});
// switch core
ui->switch_core_v2ray->setChecked(!IS_NEKO_BOX);
ui->switch_core_sing_box->setChecked(IS_NEKO_BOX);
auto switch_core_on_click = [=] {
int neko_core_new;
if (sender() == ui->switch_core_sing_box) {
if (IS_NEKO_BOX) return;
neko_core_new = NekoGui::CoreType::SING_BOX;
} else {
if (!IS_NEKO_BOX) return;
neko_core_new = NekoGui::CoreType::V2RAY;
}
QString core_name_new = dynamic_cast<QRadioButton *>(sender())->text();
if (QMessageBox::question(this, tr("Confirmation"),
tr("Switching the core to %1, click \"Yes\" to complete the switch and the program will restart. This feature may be unstable, please do not switch frequently.")
.arg(core_name_new)) == QMessageBox::StandardButton::Yes) {
QFile file;
file.setFileName("groups/coreType");
file.open(QIODevice::ReadWrite | QIODevice::Truncate);
file.write(Int2String(neko_core_new).toUtf8());
file.close();
MW_dialog_message("", "RestartProgram");
}
};
connect(ui->switch_core_v2ray, &QRadioButton::clicked, this, switch_core_on_click);
connect(ui->switch_core_sing_box, &QRadioButton::clicked, this, switch_core_on_click);
// Mux
D_LOAD_INT(mux_concurrency)

View File

@ -13,10 +13,6 @@ DialogFirstSetup::~DialogFirstSetup() {
void DialogFirstSetup::onButtonClicked() {
auto s = sender();
if (s == ui->v2ray) {
NekoGui::coreType = NekoGui::CoreType::V2RAY;
} else if (s == ui->singbox) {
NekoGui::coreType = NekoGui::CoreType::SING_BOX;
}
NekoGui::coreType = NekoGui::CoreType::SING_BOX;
done(0);
}

View File

@ -236,7 +236,7 @@ void DialogEditProfile::typeSelected(const QString &newType) {
ui->ws_early_data_length->setText(Int2String(stream->ws_early_data_length));
ui->reality_pbk->setText(stream->reality_pbk);
ui->reality_sid->setText(stream->reality_sid);
ui->multiplex->setCurrentIndex(stream->multiplex_status);
ui->multiplex->setCurrentIndex(ent->bean->mux_state);
CACHE.certificate = stream->certificate;
} else {
ui->right_all_w->setVisible(false);
@ -371,7 +371,7 @@ bool DialogEditProfile::onEnd() {
stream->ws_early_data_length = ui->ws_early_data_length->text().toInt();
stream->reality_pbk = ui->reality_pbk->text();
stream->reality_sid = ui->reality_sid->text();
stream->multiplex_status = ui->multiplex->currentIndex();
ent->bean->mux_state = ui->multiplex->currentIndex();
stream->certificate = CACHE.certificate;
}
@ -515,7 +515,7 @@ void DialogEditProfile::do_apply_to_group(const std::shared_ptr<NekoGui::Group>
};
if (key == ui->multiplex) {
copyStream(&stream->multiplex_status);
copyStream(&ent->bean->mux_state);
} else if (key == ui->sni) {
copyStream(&stream->sni);
} else if (key == ui->alpn) {