mirror of
https://github.com/MatsuriDayo/nekoray.git
synced 2025-12-17 20:44:38 +03:00
feat: add ducksoft link for VMess
This commit is contained in:
@@ -1,4 +1,3 @@
|
|||||||
#include "QUICBean.hpp"
|
|
||||||
#include "db/ProxyEntity.hpp"
|
#include "db/ProxyEntity.hpp"
|
||||||
#include "fmt/includes.h"
|
#include "fmt/includes.h"
|
||||||
|
|
||||||
@@ -99,22 +98,69 @@ namespace NekoGui_fmt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
QString VMessBean::ToShareLink() {
|
QString VMessBean::ToShareLink() {
|
||||||
QJsonObject N{
|
if (NekoGui::dataStore->old_share_link_format) {
|
||||||
{"v", "2"},
|
// v2rayN format
|
||||||
{"ps", name},
|
QJsonObject N{
|
||||||
{"add", serverAddress},
|
{"v", "2"},
|
||||||
{"port", Int2String(serverPort)},
|
{"ps", name},
|
||||||
{"id", uuid},
|
{"add", serverAddress},
|
||||||
{"aid", Int2String(aid)},
|
{"port", Int2String(serverPort)},
|
||||||
{"net", stream->network},
|
{"id", uuid},
|
||||||
{"host", stream->host},
|
{"aid", Int2String(aid)},
|
||||||
{"path", stream->path},
|
{"net", stream->network},
|
||||||
{"type", stream->header_type},
|
{"host", stream->host},
|
||||||
{"scy", security},
|
{"path", stream->path},
|
||||||
{"tls", stream->security == "tls" ? "tls" : ""},
|
{"type", stream->header_type},
|
||||||
{"sni", stream->sni},
|
{"scy", security},
|
||||||
};
|
{"tls", stream->security == "tls" ? "tls" : ""},
|
||||||
return "vmess://" + QJsonObject2QString(N, true).toUtf8().toBase64();
|
{"sni", stream->sni},
|
||||||
|
};
|
||||||
|
return "vmess://" + QJsonObject2QString(N, true).toUtf8().toBase64();
|
||||||
|
} else {
|
||||||
|
// ducksoft format
|
||||||
|
QUrl url;
|
||||||
|
QUrlQuery query;
|
||||||
|
url.setScheme("vmess");
|
||||||
|
url.setUserName(uuid);
|
||||||
|
url.setHost(serverAddress);
|
||||||
|
url.setPort(serverPort);
|
||||||
|
if (!name.isEmpty()) url.setFragment(name);
|
||||||
|
|
||||||
|
query.addQueryItem("encryption", security);
|
||||||
|
|
||||||
|
// security
|
||||||
|
auto security = stream->security;
|
||||||
|
if (security == "tls" && !stream->reality_pbk.trimmed().isEmpty()) security = "reality";
|
||||||
|
query.addQueryItem("security", security);
|
||||||
|
|
||||||
|
if (!stream->sni.isEmpty()) query.addQueryItem("sni", stream->sni);
|
||||||
|
if (stream->allow_insecure) query.addQueryItem("allowInsecure", "1");
|
||||||
|
if (!stream->utlsFingerprint.isEmpty()) query.addQueryItem("fp", stream->utlsFingerprint);
|
||||||
|
|
||||||
|
if (security == "reality") {
|
||||||
|
query.addQueryItem("pbk", stream->reality_pbk);
|
||||||
|
if (!stream->reality_sid.isEmpty()) query.addQueryItem("sid", stream->reality_sid);
|
||||||
|
if (!stream->reality_spx.isEmpty()) query.addQueryItem("spx", stream->reality_spx);
|
||||||
|
}
|
||||||
|
|
||||||
|
// type
|
||||||
|
query.addQueryItem("type", stream->network);
|
||||||
|
|
||||||
|
if (stream->network == "ws" || stream->network == "http") {
|
||||||
|
if (!stream->path.isEmpty()) query.addQueryItem("path", stream->path);
|
||||||
|
if (!stream->host.isEmpty()) query.addQueryItem("host", stream->host);
|
||||||
|
} else if (stream->network == "grpc") {
|
||||||
|
if (!stream->path.isEmpty()) query.addQueryItem("serviceName", stream->path);
|
||||||
|
} else if (stream->network == "tcp") {
|
||||||
|
if (stream->header_type == "http") {
|
||||||
|
query.addQueryItem("headerType", "http");
|
||||||
|
query.addQueryItem("host", stream->host);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
url.setQuery(query);
|
||||||
|
return url.toString(QUrl::FullyEncoded);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString NaiveBean::ToShareLink() {
|
QString NaiveBean::ToShareLink() {
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
#include "QUICBean.hpp"
|
|
||||||
#include "db/ProxyEntity.hpp"
|
#include "db/ProxyEntity.hpp"
|
||||||
#include "fmt/includes.h"
|
#include "fmt/includes.h"
|
||||||
|
|
||||||
@@ -153,9 +152,52 @@ namespace NekoGui_fmt {
|
|||||||
stream->security = objN["tls"].toString();
|
stream->security = objN["tls"].toString();
|
||||||
// TODO quic & kcp
|
// TODO quic & kcp
|
||||||
return true;
|
return true;
|
||||||
|
} else {
|
||||||
|
// https://github.com/XTLS/Xray-core/discussions/716
|
||||||
|
auto url = QUrl(link);
|
||||||
|
if (!url.isValid()) return false;
|
||||||
|
auto query = GetQuery(url);
|
||||||
|
|
||||||
|
name = url.fragment(QUrl::FullyDecoded);
|
||||||
|
serverAddress = url.host();
|
||||||
|
serverPort = url.port();
|
||||||
|
uuid = url.userName();
|
||||||
|
if (serverPort == -1) serverPort = 443;
|
||||||
|
|
||||||
|
aid = 0; // “此分享标准仅针对 VMess AEAD 和 VLESS。”
|
||||||
|
security = GetQueryValue(query, "encryption", "auto");
|
||||||
|
|
||||||
|
// security
|
||||||
|
stream->network = GetQueryValue(query, "type", "tcp");
|
||||||
|
stream->security = GetQueryValue(query, "security", "tls").replace("reality", "tls");
|
||||||
|
auto sni1 = GetQueryValue(query, "sni");
|
||||||
|
auto sni2 = GetQueryValue(query, "peer");
|
||||||
|
if (!sni1.isEmpty()) stream->sni = sni1;
|
||||||
|
if (!sni2.isEmpty()) stream->sni = sni2;
|
||||||
|
if (!query.queryItemValue("allowInsecure").isEmpty()) stream->allow_insecure = true;
|
||||||
|
stream->reality_pbk = GetQueryValue(query, "pbk", "");
|
||||||
|
stream->reality_sid = GetQueryValue(query, "sid", "");
|
||||||
|
stream->reality_spx = GetQueryValue(query, "spx", "");
|
||||||
|
stream->utlsFingerprint = GetQueryValue(query, "fp", "");
|
||||||
|
|
||||||
|
// type
|
||||||
|
if (stream->network == "ws") {
|
||||||
|
stream->path = GetQueryValue(query, "path", "");
|
||||||
|
stream->host = GetQueryValue(query, "host", "");
|
||||||
|
} else if (stream->network == "http") {
|
||||||
|
stream->path = GetQueryValue(query, "path", "");
|
||||||
|
stream->host = GetQueryValue(query, "host", "").replace("|", ",");
|
||||||
|
} else if (stream->network == "grpc") {
|
||||||
|
stream->path = GetQueryValue(query, "serviceName", "");
|
||||||
|
} else if (stream->network == "tcp") {
|
||||||
|
if (GetQueryValue(query, "headerType") == "http") {
|
||||||
|
stream->header_type = "http";
|
||||||
|
stream->host = GetQueryValue(query, "host", "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return !(uuid.isEmpty() || serverAddress.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Std Format
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -97,6 +97,7 @@ namespace NekoGui {
|
|||||||
QString test_download_url = "http://cachefly.cachefly.net/10mb.test";
|
QString test_download_url = "http://cachefly.cachefly.net/10mb.test";
|
||||||
int test_download_timeout = 30;
|
int test_download_timeout = 30;
|
||||||
int test_concurrent = 5;
|
int test_concurrent = 5;
|
||||||
|
bool old_share_link_format = true;
|
||||||
int traffic_loop_interval = 1000;
|
int traffic_loop_interval = 1000;
|
||||||
bool connection_statistics = false;
|
bool connection_statistics = false;
|
||||||
int current_group = 0; // group id
|
int current_group = 0; // group id
|
||||||
|
|||||||
@@ -163,6 +163,14 @@
|
|||||||
<source>Advanced system proxy settings. Please select a format.</source>
|
<source>Advanced system proxy settings. Please select a format.</source>
|
||||||
<translation>高级系统代理设置。请选择一种格式。</translation>
|
<translation>高级系统代理设置。请选择一种格式。</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Old Share Link Format</source>
|
||||||
|
<translation>旧分享链接格式</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Share VMess Link with v2rayN Format</source>
|
||||||
|
<translation>用 v2rayN 的格式分享 VMess 链接</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Clear servers before updating subscription</source>
|
<source>Clear servers before updating subscription</source>
|
||||||
<translation>更新订阅前清除服务器</translation>
|
<translation>更新订阅前清除服务器</translation>
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ DialogBasicSettings::DialogBasicSettings(QWidget *parent)
|
|||||||
D_LOAD_INT(test_download_timeout)
|
D_LOAD_INT(test_download_timeout)
|
||||||
D_LOAD_STRING(test_latency_url)
|
D_LOAD_STRING(test_latency_url)
|
||||||
D_LOAD_STRING(test_download_url)
|
D_LOAD_STRING(test_download_url)
|
||||||
|
D_LOAD_BOOL(old_share_link_format)
|
||||||
|
|
||||||
connect(ui->custom_inbound_edit, &QPushButton::clicked, this, [=] {
|
connect(ui->custom_inbound_edit, &QPushButton::clicked, this, [=] {
|
||||||
C_EDIT_JSON_ALLOW_EMPTY(custom_inbound)
|
C_EDIT_JSON_ALLOW_EMPTY(custom_inbound)
|
||||||
@@ -272,6 +273,7 @@ void DialogBasicSettings::accept() {
|
|||||||
D_SAVE_INT(test_download_timeout)
|
D_SAVE_INT(test_download_timeout)
|
||||||
D_SAVE_STRING(test_latency_url)
|
D_SAVE_STRING(test_latency_url)
|
||||||
D_SAVE_STRING(test_download_url)
|
D_SAVE_STRING(test_download_url)
|
||||||
|
D_SAVE_BOOL(old_share_link_format)
|
||||||
|
|
||||||
// Style
|
// Style
|
||||||
|
|
||||||
|
|||||||
@@ -213,6 +213,16 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="old_share_link_format">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Share VMess Link with v2rayN Format</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Old Share Link Format</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="sys_proxy_format">
|
<widget class="QPushButton" name="sys_proxy_format">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
|||||||
Reference in New Issue
Block a user