Compare commits

..

No commits in common. "master" and "7.16.7" have entirely different histories.

59 changed files with 496 additions and 752 deletions

View file

@ -37,12 +37,12 @@ jobs:
- name: Build - name: Build
run: | run: |
cd v2rayN cd v2rayN
dotnet publish ./v2rayN/v2rayN.csproj -c Release -r win-x64 -p:SelfContained=true -p:EnableWindowsTargeting=true -o $OutputPath64 dotnet publish ./v2rayN/v2rayN.csproj -c Release -r win-x64 -p:SelfContained=false -p:EnableWindowsTargeting=true -o $OutputPath64
dotnet publish ./v2rayN/v2rayN.csproj -c Release -r win-arm64 -p:SelfContained=true -p:EnableWindowsTargeting=true -o $OutputPathArm64 dotnet publish ./v2rayN/v2rayN.csproj -c Release -r win-arm64 -p:SelfContained=false -p:EnableWindowsTargeting=true -o $OutputPathArm64
dotnet publish ./v2rayN/v2rayN.csproj -c Release -r win-x64 -p:SelfContained=true -p:EnableWindowsTargeting=true -o $OutputPath64Sc dotnet publish ./v2rayN/v2rayN.csproj -c Release -r win-x64 -p:SelfContained=true -p:EnableWindowsTargeting=true -o $OutputPath64Sc
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-x64 -p:SelfContained=true -p:EnableWindowsTargeting=true -p:PublishTrimmed=true -o $OutputPath64 dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-x64 -p:SelfContained=false -p:EnableWindowsTargeting=true -o $OutputPath64
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-arm64 -p:SelfContained=true -p:EnableWindowsTargeting=true -p:PublishTrimmed=true -o $OutputPathArm64 dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-arm64 -p:SelfContained=false -p:EnableWindowsTargeting=true -o $OutputPathArm64
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-x64 -p:SelfContained=true -p:EnableWindowsTargeting=true -p:PublishTrimmed=true -o $OutputPath64Sc dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-x64 -p:SelfContained=true -p:EnableWindowsTargeting=true -p:PublishTrimmed=true -o $OutputPath64Sc
- name: Upload build artifacts - name: Upload build artifacts

View file

@ -1,11 +1,11 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -euo pipefail set -euo pipefail
# ====== Require Red Hat Enterprise Linux/FedoraLinux/RockyLinux/AlmaLinux/CentOS ====== # == Require Red Hat Enterprise Linux/FedoraLinux/RockyLinux/AlmaLinux/CentOS OR Ubuntu/Debian ==
if [[ -r /etc/os-release ]]; then if [[ -r /etc/os-release ]]; then
. /etc/os-release . /etc/os-release
case "$ID" in case "$ID" in
rhel|rocky|almalinux|fedora|centos) rhel|rocky|almalinux|fedora|centos|ubuntu|debian)
echo "[OK] Detected supported system: $NAME $VERSION_ID" echo "[OK] Detected supported system: $NAME $VERSION_ID"
;; ;;
*) *)
@ -30,7 +30,7 @@ echo "[INFO] Detected kernel version: $KERNEL_FULL"
if (( KERNEL_MAJOR < MIN_KERNEL_MAJOR )) || { (( KERNEL_MAJOR == MIN_KERNEL_MAJOR )) && (( KERNEL_MINOR < MIN_KERNEL_MINOR )); }; then if (( KERNEL_MAJOR < MIN_KERNEL_MAJOR )) || { (( KERNEL_MAJOR == MIN_KERNEL_MAJOR )) && (( KERNEL_MINOR < MIN_KERNEL_MINOR )); }; then
echo "[ERROR] Kernel $KERNEL_FULL is too old. Requires Linux >= ${MIN_KERNEL_MAJOR}.${MIN_KERNEL_MINOR}." echo "[ERROR] Kernel $KERNEL_FULL is too old. Requires Linux >= ${MIN_KERNEL_MAJOR}.${MIN_KERNEL_MINOR}."
echo "Please upgrade your system or use a newer container (e.g. Fedora 42+, RHEL 10+)." echo "Please upgrade your system or use a newer container (e.g. Fedora 42+, RHEL 10+, Debian 13+)."
exit 1 exit 1
fi fi
@ -80,6 +80,7 @@ host_arch="$(uname -m)"
install_ok=0 install_ok=0
case "$ID" in case "$ID" in
# ------------------------------ RHEL family (UNCHANGED) ------------------------------
rhel|rocky|almalinux|centos) rhel|rocky|almalinux|centos)
if command -v dnf >/dev/null 2>&1; then if command -v dnf >/dev/null 2>&1; then
sudo dnf -y install dotnet-sdk-8.0 rpm-build rpmdevtools curl unzip tar rsync || \ sudo dnf -y install dotnet-sdk-8.0 rpm-build rpmdevtools curl unzip tar rsync || \
@ -91,7 +92,58 @@ case "$ID" in
install_ok=1 install_ok=1
fi fi
;; ;;
*) # ------------------------------ Ubuntu ----------------------------------------------
ubuntu)
sudo apt-get update
# Ensure 'universe' (Ubuntu) to get 'rpm'
if ! apt-cache policy | grep -q '^500 .*ubuntu.com/ubuntu.* universe'; then
sudo apt-get -y install software-properties-common || true
sudo add-apt-repository -y universe || true
sudo apt-get update
fi
# Base tools + rpm (provides rpmbuild)
sudo apt-get -y install curl unzip tar rsync rpm || true
# Cross-arch binutils so strip matches target arch + objdump for brp scripts
sudo apt-get -y install binutils binutils-x86-64-linux-gnu binutils-aarch64-linux-gnu || true
# rpmbuild presence check
if ! command -v rpmbuild >/dev/null 2>&1; then
echo "[ERROR] 'rpmbuild' not found after installing 'rpm'."
echo " Please ensure the 'rpm' package is available from your repos (universe on Ubuntu)."
exit 1
fi
# .NET SDK 8 (best effort via apt)
if ! command -v dotnet >/dev/null 2>&1; then
sudo apt-get -y install dotnet-sdk-8.0 || true
sudo apt-get -y install dotnet-sdk-8 || true
sudo apt-get -y install dotnet-sdk || true
fi
install_ok=1
;;
# ------------------------------ Debian (KEEP, with local dotnet install) ------------
debian)
sudo apt-get update
# Base tools + rpm (provides rpmbuild on Debian) + objdump/strip
sudo apt-get -y install curl unzip tar rsync rpm binutils || true
# rpmbuild presence check
if ! command -v rpmbuild >/dev/null 2>&1; then
echo "[ERROR] 'rpmbuild' not found after installing 'rpm'."
echo " Please ensure 'rpm' is available from Debian repos."
exit 1
fi
# Try apt for dotnet; fallback to official installer into $HOME/.dotnet
if ! command -v dotnet >/dev/null 2>&1; then
echo "[INFO] 'dotnet' not found. Installing .NET 8 SDK locally to \$HOME/.dotnet ..."
tmp="$(mktemp -d)"; trap '[[ -n "${tmp:-}" ]] && rm -rf "$tmp"' RETURN
curl -fsSL https://dot.net/v1/dotnet-install.sh -o "$tmp/dotnet-install.sh"
bash "$tmp/dotnet-install.sh" --channel 8.0 --install-dir "$HOME/.dotnet"
export PATH="$HOME/.dotnet:$HOME/.dotnet/tools:$PATH"
export DOTNET_ROOT="$HOME/.dotnet"
if ! command -v dotnet >/dev/null 2>&1; then
echo "[ERROR] dotnet installation failed."
exit 1
fi
fi
install_ok=1
;; ;;
esac esac
@ -102,7 +154,7 @@ fi
command -v curl >/dev/null command -v curl >/dev/null
# Root directory # Root directory = the script's location
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR" cd "$SCRIPT_DIR"
@ -112,14 +164,14 @@ if [[ -f .gitmodules ]]; then
git submodule update --init --recursive || true git submodule update --init --recursive || true
fi fi
# Locate project # ===== Locate project ================================================================
PROJECT="v2rayN.Desktop/v2rayN.Desktop.csproj" PROJECT="v2rayN.Desktop/v2rayN.Desktop.csproj"
if [[ ! -f "$PROJECT" ]]; then if [[ ! -f "$PROJECT" ]]; then
PROJECT="$(find . -maxdepth 3 -name 'v2rayN.Desktop.csproj' | head -n1 || true)" PROJECT="$(find . -maxdepth 3 -name 'v2rayN.Desktop.csproj' | head -n1 || true)"
fi fi
[[ -f "$PROJECT" ]] || { echo "v2rayN.Desktop.csproj not found"; exit 1; } [[ -f "$PROJECT" ]] || { echo "v2rayN.Desktop.csproj not found"; exit 1; }
# Resolve GUI version & auto checkout # ===== Resolve GUI version & auto checkout ============================================
VERSION="" VERSION=""
choose_channel() { choose_channel() {
@ -339,6 +391,22 @@ download_singbox() {
install -Dm755 "$bin" "$outdir/sing-box" install -Dm755 "$bin" "$outdir/sing-box"
} }
# ---- NEW: download_mihomo (REQUIRED in --netcore mode) ----
download_mihomo() {
# Download mihomo into outroot/bin/mihomo/mihomo
local outroot="$1"
local url=""
if [[ "$RID_DIR" == "linux-arm64" ]]; then
url="https://raw.githubusercontent.com/2dust/v2rayN-core-bin/refs/heads/master/v2rayN-linux-arm64/bin/mihomo/mihomo"
else
url="https://raw.githubusercontent.com/2dust/v2rayN-core-bin/refs/heads/master/v2rayN-linux-64/bin/mihomo/mihomo"
fi
echo "[+] Download mihomo: $url"
mkdir -p "$outroot/bin/mihomo"
curl -fL "$url" -o "$outroot/bin/mihomo/mihomo"
chmod +x "$outroot/bin/mihomo/mihomo" || true
}
# Move geo files to a unified path: outroot/bin # Move geo files to a unified path: outroot/bin
unify_geo_layout() { unify_geo_layout() {
local outroot="$1" local outroot="$1"
@ -423,7 +491,8 @@ download_v2rayn_bundle() {
fi fi
rm -f "$outroot/v2rayn.zip" 2>/dev/null || true rm -f "$outroot/v2rayn.zip" 2>/dev/null || true
find "$outroot" -type d -name "mihomo" -prune -exec rm -rf {} + 2>/dev/null || true # keep mihomo
# find "$outroot" -type d -name "mihomo" -prune -exec rm -rf {} + 2>/dev/null || true
local nested_dir local nested_dir
nested_dir="$(find "$outroot" -maxdepth 1 -type d -name 'v2rayN-linux-*' | head -n1 || true)" nested_dir="$(find "$outroot" -maxdepth 1 -type d -name 'v2rayN-linux-*' | head -n1 || true)"
@ -534,7 +603,7 @@ build_for_arch() {
fi fi
download_geo_assets "$WORKDIR/$PKGROOT" || echo "[!] Geo rules download failed (skipped)" download_geo_assets "$WORKDIR/$PKGROOT" || echo "[!] Geo rules download failed (skipped)"
# ---- REQUIRED: always fetch mihomo in netcore mode, per-arch ---- # ---- REQUIRED: always fetch mihomo in netcore mode, per-arch ----
# download_mihomo "$WORKDIR/$PKGROOT" || echo "[!] mihomo download failed (skipped)" download_mihomo "$WORKDIR/$PKGROOT" || echo "[!] mihomo download failed (skipped)"
fi fi
# Tarball # Tarball

View file

@ -1,7 +1,7 @@
<Project> <Project>
<PropertyGroup> <PropertyGroup>
<Version>7.17.0</Version> <Version>7.16.7</Version>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>

View file

@ -14,14 +14,14 @@
<PackageVersion Include="Downloader" Version="4.0.3" /> <PackageVersion Include="Downloader" Version="4.0.3" />
<PackageVersion Include="H.NotifyIcon.Wpf" Version="2.4.1" /> <PackageVersion Include="H.NotifyIcon.Wpf" Version="2.4.1" />
<PackageVersion Include="MaterialDesignThemes" Version="5.3.0" /> <PackageVersion Include="MaterialDesignThemes" Version="5.3.0" />
<PackageVersion Include="MessageBox.Avalonia" Version="3.3.1.1" /> <PackageVersion Include="MessageBox.Avalonia" Version="3.3.1" />
<PackageVersion Include="QRCoder" Version="1.7.0" /> <PackageVersion Include="QRCoder" Version="1.7.0" />
<PackageVersion Include="ReactiveUI" Version="22.3.1" /> <PackageVersion Include="ReactiveUI" Version="22.3.1" />
<PackageVersion Include="ReactiveUI.Fody" Version="19.5.41" /> <PackageVersion Include="ReactiveUI.Fody" Version="19.5.41" />
<PackageVersion Include="ReactiveUI.WPF" Version="22.3.1" /> <PackageVersion Include="ReactiveUI.WPF" Version="22.3.1" />
<PackageVersion Include="Semi.Avalonia" Version="11.3.7.2" /> <PackageVersion Include="Semi.Avalonia" Version="11.3.7.1" />
<PackageVersion Include="Semi.Avalonia.AvaloniaEdit" Version="11.2.0.1" /> <PackageVersion Include="Semi.Avalonia.AvaloniaEdit" Version="11.2.0.1" />
<PackageVersion Include="Semi.Avalonia.DataGrid" Version="11.3.7.2" /> <PackageVersion Include="Semi.Avalonia.DataGrid" Version="11.3.7.1" />
<PackageVersion Include="NLog" Version="6.0.7" /> <PackageVersion Include="NLog" Version="6.0.7" />
<PackageVersion Include="sqlite-net-pcl" Version="1.9.172" /> <PackageVersion Include="sqlite-net-pcl" Version="1.9.172" />
<PackageVersion Include="TaskScheduler" Version="2.12.2" /> <PackageVersion Include="TaskScheduler" Version="2.12.2" />

View file

@ -6,17 +6,17 @@ public static class Extension
{ {
public static bool IsNullOrEmpty([NotNullWhen(false)] this string? value) public static bool IsNullOrEmpty([NotNullWhen(false)] this string? value)
{ {
return string.IsNullOrWhiteSpace(value) || string.IsNullOrEmpty(value); return string.IsNullOrEmpty(value) || string.IsNullOrWhiteSpace(value);
}
public static bool IsNullOrWhiteSpace([NotNullWhen(false)] this string? value)
{
return string.IsNullOrWhiteSpace(value);
} }
public static bool IsNotEmpty([NotNullWhen(false)] this string? value) public static bool IsNotEmpty([NotNullWhen(false)] this string? value)
{ {
return !string.IsNullOrWhiteSpace(value); return !string.IsNullOrEmpty(value);
}
public static string? NullIfEmpty(this string? value)
{
return string.IsNullOrWhiteSpace(value) ? null : value;
} }
public static bool BeginWithAny(this string s, IEnumerable<char> chars) public static bool BeginWithAny(this string s, IEnumerable<char> chars)

View file

@ -88,235 +88,232 @@ public class Global
public const string SingboxLocalDNSTag = "local_local"; public const string SingboxLocalDNSTag = "local_local";
public const string SingboxHostsDNSTag = "hosts_dns"; public const string SingboxHostsDNSTag = "hosts_dns";
public const string SingboxFakeDNSTag = "fake_dns"; public const string SingboxFakeDNSTag = "fake_dns";
public const string SingboxEchDNSTag = "ech_dns";
public static readonly List<string> IEProxyProtocols = public static readonly List<string> IEProxyProtocols =
[ [
"{ip}:{http_port}", "{ip}:{http_port}",
"socks={ip}:{socks_port}", "socks={ip}:{socks_port}",
"http={ip}:{http_port};https={ip}:{http_port};ftp={ip}:{http_port};socks={ip}:{socks_port}", "http={ip}:{http_port};https={ip}:{http_port};ftp={ip}:{http_port};socks={ip}:{socks_port}",
"http=http://{ip}:{http_port};https=http://{ip}:{http_port}", "http=http://{ip}:{http_port};https=http://{ip}:{http_port}",
"" ""
]; ];
public static readonly List<string> SubConvertUrls = public static readonly List<string> SubConvertUrls =
[ [
@"https://sub.xeton.dev/sub?url={0}", @"https://sub.xeton.dev/sub?url={0}",
@"https://api.dler.io/sub?url={0}", @"https://api.dler.io/sub?url={0}",
@"http://127.0.0.1:25500/sub?url={0}", @"http://127.0.0.1:25500/sub?url={0}",
"" ""
]; ];
public static readonly List<string> SubConvertConfig = public static readonly List<string> SubConvertConfig =
[ [@"https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online.ini"];
@"https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online.ini"
];
public static readonly List<string> SubConvertTargets = public static readonly List<string> SubConvertTargets =
[ [
"", "",
"mixed", "mixed",
"v2ray", "v2ray",
"clash", "clash",
"ss" "ss"
]; ];
public static readonly List<string> SpeedTestUrls = public static readonly List<string> SpeedTestUrls =
[ [
@"https://cachefly.cachefly.net/50mb.test", @"https://cachefly.cachefly.net/50mb.test",
@"https://speed.cloudflare.com/__down?bytes=10000000", @"https://speed.cloudflare.com/__down?bytes=10000000",
@"https://speed.cloudflare.com/__down?bytes=50000000", @"https://speed.cloudflare.com/__down?bytes=50000000",
@"https://speed.cloudflare.com/__down?bytes=100000000", @"https://speed.cloudflare.com/__down?bytes=100000000",
]; ];
public static readonly List<string> SpeedPingTestUrls = public static readonly List<string> SpeedPingTestUrls =
[ [
@"https://www.google.com/generate_204", @"https://www.google.com/generate_204",
@"https://www.gstatic.com/generate_204", @"https://www.gstatic.com/generate_204",
@"https://www.apple.com/library/test/success.html", @"https://www.apple.com/library/test/success.html",
@"http://www.msftconnecttest.com/connecttest.txt" @"http://www.msftconnecttest.com/connecttest.txt"
]; ];
public static readonly List<string> GeoFilesSources = public static readonly List<string> GeoFilesSources =
[ [
"", "",
@"https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/{0}.dat", @"https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/{0}.dat",
@"https://github.com/Chocolate4U/Iran-v2ray-rules/releases/latest/download/{0}.dat" @"https://github.com/Chocolate4U/Iran-v2ray-rules/releases/latest/download/{0}.dat"
]; ];
public static readonly List<string> SingboxRulesetSources = public static readonly List<string> SingboxRulesetSources =
[ [
"", "",
@"https://raw.githubusercontent.com/runetfreedom/russia-v2ray-rules-dat/release/sing-box/rule-set-{0}/{1}.srs", @"https://raw.githubusercontent.com/runetfreedom/russia-v2ray-rules-dat/release/sing-box/rule-set-{0}/{1}.srs",
@"https://raw.githubusercontent.com/chocolate4u/Iran-sing-box-rules/rule-set/{1}.srs" @"https://raw.githubusercontent.com/chocolate4u/Iran-sing-box-rules/rule-set/{1}.srs"
]; ];
public static readonly List<string> RoutingRulesSources = public static readonly List<string> RoutingRulesSources =
[ [
"", "",
@"https://raw.githubusercontent.com/runetfreedom/russia-v2ray-custom-routing-list/main/v2rayN/template.json", @"https://raw.githubusercontent.com/runetfreedom/russia-v2ray-custom-routing-list/main/v2rayN/template.json",
@"https://raw.githubusercontent.com/Chocolate4U/Iran-v2ray-rules/main/v2rayN/template.json" @"https://raw.githubusercontent.com/Chocolate4U/Iran-v2ray-rules/main/v2rayN/template.json"
]; ];
public static readonly List<string> DNSTemplateSources = public static readonly List<string> DNSTemplateSources =
[ [
"", "",
@"https://raw.githubusercontent.com/runetfreedom/russia-v2ray-custom-routing-list/main/v2rayN/", @"https://raw.githubusercontent.com/runetfreedom/russia-v2ray-custom-routing-list/main/v2rayN/",
@"https://raw.githubusercontent.com/Chocolate4U/Iran-v2ray-rules/main/v2rayN/" @"https://raw.githubusercontent.com/Chocolate4U/Iran-v2ray-rules/main/v2rayN/"
]; ];
public static readonly Dictionary<string, string> UserAgentTexts = new() public static readonly Dictionary<string, string> UserAgentTexts = new()
{ {
{"chrome","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36" }, {"chrome","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36" },
{"firefox","Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0" }, {"firefox","Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0" },
{"safari","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Safari/605.1.15" }, {"safari","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Safari/605.1.15" },
{"edge","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 Edg/91.0.864.70" }, {"edge","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 Edg/91.0.864.70" },
{"none",""} {"none",""}
}; };
public const string Hysteria2ProtocolShare = "hy2://"; public const string Hysteria2ProtocolShare = "hy2://";
public static readonly Dictionary<EConfigType, string> ProtocolShares = new() public static readonly Dictionary<EConfigType, string> ProtocolShares = new()
{ {
{ EConfigType.VMess, "vmess://" }, { EConfigType.VMess, "vmess://" },
{ EConfigType.Shadowsocks, "ss://" }, { EConfigType.Shadowsocks, "ss://" },
{ EConfigType.SOCKS, "socks://" }, { EConfigType.SOCKS, "socks://" },
{ EConfigType.VLESS, "vless://" }, { EConfigType.VLESS, "vless://" },
{ EConfigType.Trojan, "trojan://" }, { EConfigType.Trojan, "trojan://" },
{ EConfigType.Hysteria2, "hysteria2://" }, { EConfigType.Hysteria2, "hysteria2://" },
{ EConfigType.TUIC, "tuic://" }, { EConfigType.TUIC, "tuic://" },
{ EConfigType.WireGuard, "wireguard://" }, { EConfigType.WireGuard, "wireguard://" },
{ EConfigType.Anytls, "anytls://" } { EConfigType.Anytls, "anytls://" }
}; };
public static readonly Dictionary<EConfigType, string> ProtocolTypes = new() public static readonly Dictionary<EConfigType, string> ProtocolTypes = new()
{ {
{ EConfigType.VMess, "vmess" }, { EConfigType.VMess, "vmess" },
{ EConfigType.Shadowsocks, "shadowsocks" }, { EConfigType.Shadowsocks, "shadowsocks" },
{ EConfigType.SOCKS, "socks" }, { EConfigType.SOCKS, "socks" },
{ EConfigType.HTTP, "http" }, { EConfigType.HTTP, "http" },
{ EConfigType.VLESS, "vless" }, { EConfigType.VLESS, "vless" },
{ EConfigType.Trojan, "trojan" }, { EConfigType.Trojan, "trojan" },
{ EConfigType.Hysteria2, "hysteria2" }, { EConfigType.Hysteria2, "hysteria2" },
{ EConfigType.TUIC, "tuic" }, { EConfigType.TUIC, "tuic" },
{ EConfigType.WireGuard, "wireguard" }, { EConfigType.WireGuard, "wireguard" },
{ EConfigType.Anytls, "anytls" } { EConfigType.Anytls, "anytls" }
}; };
public static readonly List<string> VmessSecurities = public static readonly List<string> VmessSecurities =
[ [
"aes-128-gcm", "aes-128-gcm",
"chacha20-poly1305", "chacha20-poly1305",
"auto", "auto",
"none", "none",
"zero" "zero"
]; ];
public static readonly List<string> SsSecurities = public static readonly List<string> SsSecurities =
[ [
"aes-256-gcm", "aes-256-gcm",
"aes-128-gcm", "aes-128-gcm",
"chacha20-poly1305", "chacha20-poly1305",
"chacha20-ietf-poly1305", "chacha20-ietf-poly1305",
"none", "none",
"plain" "plain"
]; ];
public static readonly List<string> SsSecuritiesInXray = public static readonly List<string> SsSecuritiesInXray =
[ [
"aes-256-gcm", "aes-256-gcm",
"aes-128-gcm", "aes-128-gcm",
"chacha20-poly1305", "chacha20-poly1305",
"chacha20-ietf-poly1305", "chacha20-ietf-poly1305",
"xchacha20-poly1305", "xchacha20-poly1305",
"xchacha20-ietf-poly1305", "xchacha20-ietf-poly1305",
"none", "none",
"plain", "plain",
"2022-blake3-aes-128-gcm", "2022-blake3-aes-128-gcm",
"2022-blake3-aes-256-gcm", "2022-blake3-aes-256-gcm",
"2022-blake3-chacha20-poly1305" "2022-blake3-chacha20-poly1305"
]; ];
public static readonly List<string> SsSecuritiesInSingbox = public static readonly List<string> SsSecuritiesInSingbox =
[ [
"aes-256-gcm", "aes-256-gcm",
"aes-192-gcm", "aes-192-gcm",
"aes-128-gcm", "aes-128-gcm",
"chacha20-ietf-poly1305", "chacha20-ietf-poly1305",
"xchacha20-ietf-poly1305", "xchacha20-ietf-poly1305",
"none", "none",
"2022-blake3-aes-128-gcm", "2022-blake3-aes-128-gcm",
"2022-blake3-aes-256-gcm", "2022-blake3-aes-256-gcm",
"2022-blake3-chacha20-poly1305", "2022-blake3-chacha20-poly1305",
"aes-128-ctr", "aes-128-ctr",
"aes-192-ctr", "aes-192-ctr",
"aes-256-ctr", "aes-256-ctr",
"aes-128-cfb", "aes-128-cfb",
"aes-192-cfb", "aes-192-cfb",
"aes-256-cfb", "aes-256-cfb",
"rc4-md5", "rc4-md5",
"chacha20-ietf", "chacha20-ietf",
"xchacha20" "xchacha20"
]; ];
public static readonly List<string> Flows = public static readonly List<string> Flows =
[ [
"", "",
"xtls-rprx-vision", "xtls-rprx-vision",
"xtls-rprx-vision-udp443" "xtls-rprx-vision-udp443"
]; ];
public static readonly List<string> Networks = public static readonly List<string> Networks =
[ [
"tcp", "tcp",
"kcp", "kcp",
"ws", "ws",
"httpupgrade", "httpupgrade",
"xhttp", "xhttp",
"h2", "h2",
"quic", "quic",
"grpc" "grpc"
]; ];
public static readonly List<string> KcpHeaderTypes = public static readonly List<string> KcpHeaderTypes =
[ [
"srtp", "srtp",
"utp", "utp",
"wechat-video", "wechat-video",
"dtls", "dtls",
"wireguard", "wireguard",
"dns" "dns"
]; ];
public static readonly List<string> CoreTypes = public static readonly List<string> CoreTypes =
[ [
"Xray", "Xray",
"sing_box" "sing_box"
]; ];
public static readonly HashSet<EConfigType> XraySupportConfigType = public static readonly HashSet<EConfigType> XraySupportConfigType =
[ [
EConfigType.VMess, EConfigType.VMess,
EConfigType.VLESS, EConfigType.VLESS,
EConfigType.Shadowsocks, EConfigType.Shadowsocks,
EConfigType.Trojan, EConfigType.Trojan,
EConfigType.WireGuard, EConfigType.WireGuard,
EConfigType.SOCKS, EConfigType.SOCKS,
EConfigType.HTTP, EConfigType.HTTP,
]; ];
public static readonly HashSet<EConfigType> SingboxSupportConfigType = public static readonly HashSet<EConfigType> SingboxSupportConfigType =
[ [
EConfigType.VMess, EConfigType.VMess,
EConfigType.VLESS, EConfigType.VLESS,
EConfigType.Shadowsocks, EConfigType.Shadowsocks,
EConfigType.Trojan, EConfigType.Trojan,
EConfigType.Hysteria2, EConfigType.Hysteria2,
EConfigType.TUIC, EConfigType.TUIC,
EConfigType.Anytls, EConfigType.Anytls,
EConfigType.WireGuard, EConfigType.WireGuard,
EConfigType.SOCKS, EConfigType.SOCKS,
EConfigType.HTTP, EConfigType.HTTP,
]; ];
public static readonly HashSet<EConfigType> SingboxOnlyConfigType = SingboxSupportConfigType.Except(XraySupportConfigType).ToHashSet(); public static readonly HashSet<EConfigType> SingboxOnlyConfigType = SingboxSupportConfigType.Except(XraySupportConfigType).ToHashSet();
@ -331,129 +328,129 @@ public class Global
public static readonly List<string> DomainStrategies4Singbox = public static readonly List<string> DomainStrategies4Singbox =
[ [
"ipv4_only", "ipv4_only",
"ipv6_only", "ipv6_only",
"prefer_ipv4", "prefer_ipv4",
"prefer_ipv6", "prefer_ipv6",
"" ""
]; ];
public static readonly List<string> Fingerprints = public static readonly List<string> Fingerprints =
[ [
"chrome", "chrome",
"firefox", "firefox",
"safari", "safari",
"ios", "ios",
"android", "android",
"edge", "edge",
"360", "360",
"qq", "qq",
"random", "random",
"randomized", "randomized",
"" ""
]; ];
public static readonly List<string> UserAgent = public static readonly List<string> UserAgent =
[ [
"chrome", "chrome",
"firefox", "firefox",
"safari", "safari",
"edge", "edge",
"none" "none"
]; ];
public static readonly List<string> XhttpMode = public static readonly List<string> XhttpMode =
[ [
"auto", "auto",
"packet-up", "packet-up",
"stream-up", "stream-up",
"stream-one" "stream-one"
]; ];
public static readonly List<string> AllowInsecure = public static readonly List<string> AllowInsecure =
[ [
"true", "true",
"false", "false",
"" ""
]; ];
public static readonly List<string> DomainStrategy4Freedoms = public static readonly List<string> DomainStrategy4Freedoms =
[ [
"AsIs", "AsIs",
"UseIP", "UseIP",
"UseIPv4", "UseIPv4",
"UseIPv6", "UseIPv6",
"" ""
]; ];
public static readonly List<string> SingboxDomainStrategy4Out = public static readonly List<string> SingboxDomainStrategy4Out =
[ [
"", "",
"ipv4_only", "ipv4_only",
"prefer_ipv4", "prefer_ipv4",
"prefer_ipv6", "prefer_ipv6",
"ipv6_only" "ipv6_only"
]; ];
public static readonly List<string> DomainDirectDNSAddress = public static readonly List<string> DomainDirectDNSAddress =
[ [
"https://dns.alidns.com/dns-query", "https://dns.alidns.com/dns-query",
"https://doh.pub/dns-query", "https://doh.pub/dns-query",
"223.5.5.5", "223.5.5.5",
"119.29.29.29", "119.29.29.29",
"localhost" "localhost"
]; ];
public static readonly List<string> DomainRemoteDNSAddress = public static readonly List<string> DomainRemoteDNSAddress =
[ [
"https://cloudflare-dns.com/dns-query", "https://cloudflare-dns.com/dns-query",
"https://dns.cloudflare.com/dns-query", "https://dns.cloudflare.com/dns-query",
"https://dns.google/dns-query", "https://dns.google/dns-query",
"https://doh.dns.sb/dns-query", "https://doh.dns.sb/dns-query",
"https://doh.opendns.com/dns-query", "https://doh.opendns.com/dns-query",
"https://common.dot.dns.yandex.net", "https://common.dot.dns.yandex.net",
"8.8.8.8", "8.8.8.8",
"1.1.1.1", "1.1.1.1",
"185.222.222.222", "185.222.222.222",
"208.67.222.222", "208.67.222.222",
"77.88.8.8" "77.88.8.8"
]; ];
public static readonly List<string> DomainPureIPDNSAddress = public static readonly List<string> DomainPureIPDNSAddress =
[ [
"223.5.5.5", "223.5.5.5",
"119.29.29.29", "119.29.29.29",
"localhost" "localhost"
]; ];
public static readonly List<string> Languages = public static readonly List<string> Languages =
[ [
"zh-Hans", "zh-Hans",
"zh-Hant", "zh-Hant",
"en", "en",
"fa-Ir", "fa-Ir",
"fr", "fr",
"ru", "ru",
"hu" "hu"
]; ];
public static readonly List<string> Alpns = public static readonly List<string> Alpns =
[ [
"h3", "h3",
"h2", "h2",
"http/1.1", "http/1.1",
"h3,h2", "h3,h2",
"h2,http/1.1", "h2,http/1.1",
"h3,h2,http/1.1", "h3,h2,http/1.1",
"" ""
]; ];
public static readonly List<string> LogLevels = public static readonly List<string> LogLevels =
[ [
"debug", "debug",
"info", "info",
"warning", "warning",
"error", "error",
"none" "none"
]; ];
public static readonly Dictionary<string, string> LogLevelColors = new() public static readonly Dictionary<string, string> LogLevelColors = new()
@ -467,32 +464,32 @@ public class Global
public static readonly List<string> InboundTags = public static readonly List<string> InboundTags =
[ [
"socks", "socks",
"socks2", "socks2",
"socks3" "socks3"
]; ];
public static readonly List<string> RuleProtocols = public static readonly List<string> RuleProtocols =
[ [
"http", "http",
"tls", "tls",
"bittorrent" "bittorrent"
]; ];
public static readonly List<string> RuleNetworks = public static readonly List<string> RuleNetworks =
[ [
"", "",
"tcp", "tcp",
"udp", "udp",
"tcp,udp" "tcp,udp"
]; ];
public static readonly List<string> destOverrideProtocols = public static readonly List<string> destOverrideProtocols =
[ [
"http", "http",
"tls", "tls",
"quic", "quic",
"fakedns", "fakedns",
"fakedns+others" "fakedns+others"
]; ];
public static readonly List<int> TunMtus = public static readonly List<int> TunMtus =
@ -508,83 +505,83 @@ public class Global
public static readonly List<string> TunStacks = public static readonly List<string> TunStacks =
[ [
"gvisor", "gvisor",
"system", "system",
"mixed" "mixed"
]; ];
public static readonly List<string> PresetMsgFilters = public static readonly List<string> PresetMsgFilters =
[ [
"proxy", "proxy",
"direct", "direct",
"block", "block",
"" ""
]; ];
public static readonly List<string> SingboxMuxs = public static readonly List<string> SingboxMuxs =
[ [
"h2mux", "h2mux",
"smux", "smux",
"yamux", "yamux",
"" ""
]; ];
public static readonly List<string> TuicCongestionControls = public static readonly List<string> TuicCongestionControls =
[ [
"cubic", "cubic",
"new_reno", "new_reno",
"bbr" "bbr"
]; ];
public static readonly List<string> allowSelectType = public static readonly List<string> allowSelectType =
[ [
"selector", "selector",
"urltest", "urltest",
"loadbalance", "loadbalance",
"fallback" "fallback"
]; ];
public static readonly List<string> notAllowTestType = public static readonly List<string> notAllowTestType =
[ [
"selector", "selector",
"urltest", "urltest",
"direct", "direct",
"reject", "reject",
"compatible", "compatible",
"pass", "pass",
"loadbalance", "loadbalance",
"fallback" "fallback"
]; ];
public static readonly List<string> proxyVehicleType = public static readonly List<string> proxyVehicleType =
[ [
"file", "file",
"http" "http"
]; ];
public static readonly Dictionary<ECoreType, string> CoreUrls = new() public static readonly Dictionary<ECoreType, string> CoreUrls = new()
{ {
{ ECoreType.v2fly, "v2fly/v2ray-core" }, { ECoreType.v2fly, "v2fly/v2ray-core" },
{ ECoreType.v2fly_v5, "v2fly/v2ray-core" }, { ECoreType.v2fly_v5, "v2fly/v2ray-core" },
{ ECoreType.Xray, "XTLS/Xray-core" }, { ECoreType.Xray, "XTLS/Xray-core" },
{ ECoreType.sing_box, "SagerNet/sing-box" }, { ECoreType.sing_box, "SagerNet/sing-box" },
{ ECoreType.mihomo, "MetaCubeX/mihomo" }, { ECoreType.mihomo, "MetaCubeX/mihomo" },
{ ECoreType.hysteria, "apernet/hysteria" }, { ECoreType.hysteria, "apernet/hysteria" },
{ ECoreType.hysteria2, "apernet/hysteria" }, { ECoreType.hysteria2, "apernet/hysteria" },
{ ECoreType.naiveproxy, "klzgrad/naiveproxy" }, { ECoreType.naiveproxy, "klzgrad/naiveproxy" },
{ ECoreType.tuic, "EAimTY/tuic" }, { ECoreType.tuic, "EAimTY/tuic" },
{ ECoreType.juicity, "juicity/juicity" }, { ECoreType.juicity, "juicity/juicity" },
{ ECoreType.brook, "txthinking/brook" }, { ECoreType.brook, "txthinking/brook" },
{ ECoreType.overtls, "ShadowsocksR-Live/overtls" }, { ECoreType.overtls, "ShadowsocksR-Live/overtls" },
{ ECoreType.shadowquic, "spongebob888/shadowquic" }, { ECoreType.shadowquic, "spongebob888/shadowquic" },
{ ECoreType.mieru, "enfein/mieru" }, { ECoreType.mieru, "enfein/mieru" },
{ ECoreType.v2rayN, "2dust/v2rayN" }, { ECoreType.v2rayN, "2dust/v2rayN" },
}; };
public static readonly List<string> OtherGeoUrls = public static readonly List<string> OtherGeoUrls =
[ [
@"https://raw.githubusercontent.com/Loyalsoldier/geoip/release/geoip-only-cn-private.dat", @"https://raw.githubusercontent.com/Loyalsoldier/geoip/release/geoip-only-cn-private.dat",
@"https://raw.githubusercontent.com/Loyalsoldier/geoip/release/Country.mmdb", @"https://raw.githubusercontent.com/Loyalsoldier/geoip/release/Country.mmdb",
@"https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb" @"https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb"
]; ];
public static readonly List<string> IPAPIUrls = public static readonly List<string> IPAPIUrls =
@ -604,37 +601,29 @@ public class Global
]; ];
public static readonly Dictionary<string, List<string>> PredefinedHosts = new() public static readonly Dictionary<string, List<string>> PredefinedHosts = new()
{ {
{ "dns.google", new List<string> { "8.8.8.8", "8.8.4.4", "2001:4860:4860::8888", "2001:4860:4860::8844" } }, { "dns.google", new List<string> { "8.8.8.8", "8.8.4.4", "2001:4860:4860::8888", "2001:4860:4860::8844" } },
{ "dns.alidns.com", new List<string> { "223.5.5.5", "223.6.6.6", "2400:3200::1", "2400:3200:baba::1" } }, { "dns.alidns.com", new List<string> { "223.5.5.5", "223.6.6.6", "2400:3200::1", "2400:3200:baba::1" } },
{ "one.one.one.one", new List<string> { "1.1.1.1", "1.0.0.1", "2606:4700:4700::1111", "2606:4700:4700::1001" } }, { "one.one.one.one", new List<string> { "1.1.1.1", "1.0.0.1", "2606:4700:4700::1111", "2606:4700:4700::1001" } },
{ "1dot1dot1dot1.cloudflare-dns.com", new List<string> { "1.1.1.1", "1.0.0.1", "2606:4700:4700::1111", "2606:4700:4700::1001" } }, { "1dot1dot1dot1.cloudflare-dns.com", new List<string> { "1.1.1.1", "1.0.0.1", "2606:4700:4700::1111", "2606:4700:4700::1001" } },
{ "cloudflare-dns.com", new List<string> { "104.16.249.249", "104.16.248.249", "2606:4700::6810:f8f9", "2606:4700::6810:f9f9" } }, { "cloudflare-dns.com", new List<string> { "104.16.249.249", "104.16.248.249", "2606:4700::6810:f8f9", "2606:4700::6810:f9f9" } },
{ "dns.cloudflare.com", new List<string> { "104.16.132.229", "104.16.133.229", "2606:4700::6810:84e5", "2606:4700::6810:85e5" } }, { "dns.cloudflare.com", new List<string> { "104.16.132.229", "104.16.133.229", "2606:4700::6810:84e5", "2606:4700::6810:85e5" } },
{ "dot.pub", new List<string> { "1.12.12.12", "120.53.53.53" } }, { "dot.pub", new List<string> { "1.12.12.12", "120.53.53.53" } },
{ "doh.pub", new List<string> { "1.12.12.12", "120.53.53.53" } }, { "doh.pub", new List<string> { "1.12.12.12", "120.53.53.53" } },
{ "dns.quad9.net", new List<string> { "9.9.9.9", "149.112.112.112", "2620:fe::fe", "2620:fe::9" } }, { "dns.quad9.net", new List<string> { "9.9.9.9", "149.112.112.112", "2620:fe::fe", "2620:fe::9" } },
{ "dns.yandex.net", new List<string> { "77.88.8.8", "77.88.8.1", "2a02:6b8::feed:0ff", "2a02:6b8:0:1::feed:0ff" } }, { "dns.yandex.net", new List<string> { "77.88.8.8", "77.88.8.1", "2a02:6b8::feed:0ff", "2a02:6b8:0:1::feed:0ff" } },
{ "dns.sb", new List<string> { "185.222.222.222", "2a09::" } }, { "dns.sb", new List<string> { "185.222.222.222", "2a09::" } },
{ "dns.umbrella.com", new List<string> { "208.67.220.220", "208.67.222.222", "2620:119:35::35", "2620:119:53::53" } }, { "dns.umbrella.com", new List<string> { "208.67.220.220", "208.67.222.222", "2620:119:35::35", "2620:119:53::53" } },
{ "dns.sse.cisco.com", new List<string> { "208.67.220.220", "208.67.222.222", "2620:119:35::35", "2620:119:53::53" } }, { "dns.sse.cisco.com", new List<string> { "208.67.220.220", "208.67.222.222", "2620:119:35::35", "2620:119:53::53" } },
{ "engage.cloudflareclient.com", new List<string> { "162.159.192.1", "2606:4700:d0::a29f:c001" } } { "engage.cloudflareclient.com", new List<string> { "162.159.192.1", "2606:4700:d0::a29f:c001" } }
}; };
public static readonly List<string> ExpectedIPs = public static readonly List<string> ExpectedIPs =
[ [
"geoip:cn", "geoip:cn",
"geoip:ir", "geoip:ir",
"geoip:ru", "geoip:ru",
"" ""
];
public static readonly List<string> EchForceQuerys =
[
"none",
"half",
"full",
""
]; ];
#endregion const #endregion const

View file

@ -253,8 +253,6 @@ public static class ConfigHandler
item.Extra = profileItem.Extra; item.Extra = profileItem.Extra;
item.MuxEnabled = profileItem.MuxEnabled; item.MuxEnabled = profileItem.MuxEnabled;
item.Cert = profileItem.Cert; item.Cert = profileItem.Cert;
item.EchConfigList = profileItem.EchConfigList;
item.EchForceQuery = profileItem.EchForceQuery;
} }
var ret = item.ConfigType switch var ret = item.ConfigType switch
@ -1275,7 +1273,7 @@ public static class ConfigHandler
} }
else if (node.ConfigType == EConfigType.Custom && node.PreSocksPort > 0) else if (node.ConfigType == EConfigType.Custom && node.PreSocksPort > 0)
{ {
var preCoreType = AppManager.Instance.RunningCoreType = config.TunModeItem.EnableTun ? ECoreType.sing_box : ECoreType.Xray; var preCoreType = config.RunningCoreType = config.TunModeItem.EnableTun ? ECoreType.sing_box : ECoreType.Xray;
itemSocks = new ProfileItem() itemSocks = new ProfileItem()
{ {
CoreType = preCoreType, CoreType = preCoreType,

View file

@ -70,10 +70,6 @@ public class BaseFmt
} }
ToUriQueryAllowInsecure(item, ref dicQuery); ToUriQueryAllowInsecure(item, ref dicQuery);
} }
if (item.EchConfigList.IsNotEmpty())
{
dicQuery.Add("ech", Utils.UrlEncode(item.EchConfigList));
}
dicQuery.Add("type", item.Network.IsNotEmpty() ? item.Network : nameof(ETransport.tcp)); dicQuery.Add("type", item.Network.IsNotEmpty() ? item.Network : nameof(ETransport.tcp));
@ -213,7 +209,6 @@ public class BaseFmt
item.ShortId = GetQueryDecoded(query, "sid"); item.ShortId = GetQueryDecoded(query, "sid");
item.SpiderX = GetQueryDecoded(query, "spx"); item.SpiderX = GetQueryDecoded(query, "spx");
item.Mldsa65Verify = GetQueryDecoded(query, "pqv"); item.Mldsa65Verify = GetQueryDecoded(query, "pqv");
item.EchConfigList = GetQueryDecoded(query, "ech");
if (_allowInsecureArray.Any(k => GetQueryDecoded(query, k) == "1")) if (_allowInsecureArray.Any(k => GetQueryDecoded(query, k) == "1"))
{ {

View file

@ -193,6 +193,19 @@ public class ActionPrecheckManager
} }
} }
// ws with tls, tls alpn should contain "http/1.1" in xray core
// rfc6455
// https://github.com/XTLS/Xray-core/blob/81f8f398c7b2b845853b1e85087c6122acc6db0b/transport/internet/tls/tls.go#L95-L116
if (item.Network == nameof(ETransport.ws)
&& item.StreamSecurity == Global.StreamSecurity)
{
var alpnList = Utils.String2List(item.Alpn) ?? [];
if (alpnList.Count > 0 && !alpnList.Contains("http/1.1"))
{
errors.Add(ResUI.AlpnMustContainHttp11ForWsTls);
}
}
return errors; return errors;
} }
@ -214,10 +227,9 @@ public class ActionPrecheckManager
return errors; return errors;
} }
var childIds = new List<string>(); var childIds = Utils.String2List(group.ChildItems) ?? [];
var subItems = await ProfileGroupItemManager.GetSubChildProfileItems(group); var subItems = await ProfileGroupItemManager.GetSubChildProfileItems(group);
childIds.AddRange(subItems.Select(p => p.IndexId)); childIds.AddRange(subItems.Select(p => p.IndexId));
childIds.AddRange(Utils.String2List(group.ChildItems));
foreach (var child in childIds) foreach (var child in childIds)
{ {

View file

@ -31,23 +31,6 @@ public sealed class AppManager
public string LinuxSudoPwd { get; set; } public string LinuxSudoPwd { get; set; }
public bool ShowInTaskbar { get; set; }
public ECoreType RunningCoreType { get; set; }
public bool IsRunningCore(ECoreType type)
{
switch (type)
{
case ECoreType.Xray when RunningCoreType is ECoreType.Xray or ECoreType.v2fly or ECoreType.v2fly_v5:
case ECoreType.sing_box when RunningCoreType is ECoreType.sing_box or ECoreType.mihomo:
return true;
default:
return false;
}
}
#endregion Property #endregion Property
#region App #region App

View file

@ -125,7 +125,7 @@ public sealed class CoreInfoManager
new CoreInfo new CoreInfo
{ {
CoreType = ECoreType.mihomo, CoreType = ECoreType.mihomo,
CoreExes = GetMihomoCoreExes(), CoreExes = ["mihomo-windows-amd64-v1", "mihomo-windows-amd64-compatible", "mihomo-windows-amd64", "mihomo-linux-amd64", "clash", "mihomo"],
Arguments = "-f {0}" + PortableMode(), Arguments = "-f {0}" + PortableMode(),
Url = GetCoreUrl(ECoreType.mihomo), Url = GetCoreUrl(ECoreType.mihomo),
ReleaseApiUrl = urlMihomo.Replace(Global.GithubUrl, Global.GithubApiUrl), ReleaseApiUrl = urlMihomo.Replace(Global.GithubUrl, Global.GithubApiUrl),
@ -248,34 +248,4 @@ public sealed class CoreInfoManager
{ {
return $"{Global.GithubUrl}/{Global.CoreUrls[eCoreType]}/releases"; return $"{Global.GithubUrl}/{Global.CoreUrls[eCoreType]}/releases";
} }
private static List<string>? GetMihomoCoreExes()
{
var names = new List<string>();
if (Utils.IsWindows())
{
names.Add("mihomo-windows-amd64-v1");
names.Add("mihomo-windows-amd64-compatible");
names.Add("mihomo-windows-amd64");
names.Add("mihomo-windows-arm64");
}
else if (Utils.IsLinux())
{
names.Add("mihomo-linux-amd64-v1");
names.Add("mihomo-linux-amd64");
names.Add("mihomo-linux-arm64");
}
else if (Utils.IsMacOS())
{
names.Add("mihomo-darwin-amd64-v1");
names.Add("mihomo-darwin-amd64");
names.Add("mihomo-darwin-arm64");
}
names.Add("clash");
names.Add("mihomo");
return names;
}
} }

View file

@ -167,7 +167,7 @@ public class CoreManager
private async Task CoreStart(ProfileItem node) private async Task CoreStart(ProfileItem node)
{ {
var coreType = AppManager.Instance.RunningCoreType = AppManager.Instance.GetCoreType(node, node.ConfigType); var coreType = _config.RunningCoreType = AppManager.Instance.GetCoreType(node, node.ConfigType);
var coreInfo = CoreInfoManager.Instance.GetCoreInfo(coreType); var coreInfo = CoreInfoManager.Instance.GetCoreInfo(coreType);
var displayLog = node.ConfigType != EConfigType.Custom || node.DisplayLog; var displayLog = node.ConfigType != EConfigType.Custom || node.DisplayLog;

View file

@ -230,10 +230,9 @@ public class ProfileGroupItemManager
{ {
return (new List<ProfileItem>(), profileGroupItem); return (new List<ProfileItem>(), profileGroupItem);
} }
var items = await GetChildProfileItems(profileGroupItem);
var items = new List<ProfileItem>(); var subItems = await GetSubChildProfileItems(profileGroupItem);
items.AddRange(await GetSubChildProfileItems(profileGroupItem)); items.AddRange(subItems);
items.AddRange(await GetChildProfileItems(profileGroupItem));
return (items, profileGroupItem); return (items, profileGroupItem);
} }
@ -317,72 +316,5 @@ public class ProfileGroupItemManager
return childAddresses; return childAddresses;
} }
public static async Task<HashSet<string>> GetAllChildEchQuerySni(string indexId)
{
// include grand children
var childAddresses = new HashSet<string>();
if (!Instance.TryGet(indexId, out var groupItem) || groupItem == null)
{
return childAddresses;
}
if (groupItem.SubChildItems.IsNotEmpty())
{
var subItems = await GetSubChildProfileItems(groupItem);
foreach (var childNode in subItems)
{
if (childNode.EchConfigList.IsNullOrEmpty())
{
continue;
}
if (childNode.StreamSecurity == Global.StreamSecurity
&& childNode.EchConfigList?.Contains("://") == true)
{
var idx = childNode.EchConfigList.IndexOf('+');
childAddresses.Add(idx > 0 ? childNode.EchConfigList[..idx] : childNode.Sni);
}
else
{
childAddresses.Add(childNode.Sni);
}
}
}
var childIds = Utils.String2List(groupItem.ChildItems) ?? [];
foreach (var childId in childIds)
{
var childNode = await AppManager.Instance.GetProfileItem(childId);
if (childNode == null)
{
continue;
}
if (!childNode.IsComplex() && !childNode.EchConfigList.IsNullOrEmpty())
{
if (childNode.StreamSecurity == Global.StreamSecurity
&& childNode.EchConfigList?.Contains("://") == true)
{
var idx = childNode.EchConfigList.IndexOf('+');
childAddresses.Add(idx > 0 ? childNode.EchConfigList[..idx] : childNode.Sni);
}
else
{
childAddresses.Add(childNode.Sni);
}
}
else if (childNode.ConfigType.IsGroupType())
{
var subAddresses = await GetAllChildDomainAddresses(childNode.IndexId);
foreach (var addr in subAddresses)
{
childAddresses.Add(addr);
}
}
}
return childAddresses;
}
#endregion Helper #endregion Helper
} }

View file

@ -8,6 +8,21 @@ public class Config
public string IndexId { get; set; } public string IndexId { get; set; }
public string SubIndexId { get; set; } public string SubIndexId { get; set; }
public ECoreType RunningCoreType { get; set; }
public bool IsRunningCore(ECoreType type)
{
switch (type)
{
case ECoreType.Xray when RunningCoreType is ECoreType.Xray or ECoreType.v2fly or ECoreType.v2fly_v5:
case ECoreType.sing_box when RunningCoreType is ECoreType.sing_box or ECoreType.mihomo:
return true;
default:
return false;
}
}
#endregion property #endregion property
#region other entities #region other entities

View file

@ -99,7 +99,8 @@ public class UIItem
public bool EnableDragDropSort { get; set; } public bool EnableDragDropSort { get; set; }
public bool DoubleClick2Activate { get; set; } public bool DoubleClick2Activate { get; set; }
public bool AutoHideStartup { get; set; } public bool AutoHideStartup { get; set; }
public bool Hide2TrayWhenClose { get; set; } public bool Hide2TrayWhenClose { get; set; }
public bool ShowInTaskbar { get; set; }
public bool MacOSShowInDock { get; set; } public bool MacOSShowInDock { get; set; }
public List<ColumnItem> MainColumnItem { get; set; } public List<ColumnItem> MainColumnItem { get; set; }
public List<WindowSizeItem> WindowSizeItem { get; set; } public List<WindowSizeItem> WindowSizeItem { get; set; }

View file

@ -161,6 +161,4 @@ public class ProfileItem : ReactiveObject
public string Extra { get; set; } public string Extra { get; set; }
public bool? MuxEnabled { get; set; } public bool? MuxEnabled { get; set; }
public string Cert { get; set; } public string Cert { get; set; }
public string EchConfigList { get; set; }
public string EchForceQuery { get; set; }
} }

View file

@ -182,14 +182,6 @@ public class Tls4Sbox
public string? fragment_fallback_delay { get; set; } public string? fragment_fallback_delay { get; set; }
public bool? record_fragment { get; set; } public bool? record_fragment { get; set; }
public List<string>? certificate { get; set; } public List<string>? certificate { get; set; }
public Ech4Sbox? ech { get; set; }
}
public class Ech4Sbox
{
public bool enabled { get; set; }
public List<string>? config { get; set; }
public string? query_server_name { get; set; }
} }
public class Multiplex4Sbox public class Multiplex4Sbox

View file

@ -356,8 +356,6 @@ public class TlsSettings4Ray
public string? mldsa65Verify { get; set; } public string? mldsa65Verify { get; set; }
public List<CertificateSettings4Ray>? certificates { get; set; } public List<CertificateSettings4Ray>? certificates { get; set; }
public bool? disableSystemRoot { get; set; } public bool? disableSystemRoot { get; set; }
public string? echConfigList { get; set; }
public string? echForceQuery { get; set; }
} }
public class CertificateSettings4Ray public class CertificateSettings4Ray

View file

@ -78,6 +78,15 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 ALPN must contain &apos;http/1.1&apos; when using WebSocket with TLS. 的本地化字符串。
/// </summary>
public static string AlpnMustContainHttp11ForWsTls {
get {
return ResourceManager.GetString("AlpnMustContainHttp11ForWsTls", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Export share link to clipboard successfully 的本地化字符串。 /// 查找类似 Export share link to clipboard successfully 的本地化字符串。
/// </summary> /// </summary>
@ -2790,24 +2799,6 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 EchConfigList 的本地化字符串。
/// </summary>
public static string TbEchConfigList {
get {
return ResourceManager.GetString("TbEchConfigList", resourceCulture);
}
}
/// <summary>
/// 查找类似 EchForceQuery 的本地化字符串。
/// </summary>
public static string TbEchForceQuery {
get {
return ResourceManager.GetString("TbEchForceQuery", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Edit 的本地化字符串。 /// 查找类似 Edit 的本地化字符串。
/// </summary> /// </summary>

View file

@ -1641,10 +1641,7 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="menuServerList2" xml:space="preserve"> <data name="menuServerList2" xml:space="preserve">
<value>Configuration Item 2, Select and add from self-built</value> <value>Configuration Item 2, Select and add from self-built</value>
</data> </data>
<data name="TbEchConfigList" xml:space="preserve"> <data name="AlpnMustContainHttp11ForWsTls" xml:space="preserve">
<value>EchConfigList</value> <value>ALPN must contain 'http/1.1' when using WebSocket with TLS.</value>
</data>
<data name="TbEchForceQuery" xml:space="preserve">
<value>EchForceQuery</value>
</data> </data>
</root> </root>

View file

@ -1638,10 +1638,7 @@ Si un certificat auto-signé est utilisé ou si le système contient une CA non
<data name="menuServerList2" xml:space="preserve"> <data name="menuServerList2" xml:space="preserve">
<value>Élément de config 2 : choisir et ajouter depuis self-hosted</value> <value>Élément de config 2 : choisir et ajouter depuis self-hosted</value>
</data> </data>
<data name="TbEchConfigList" xml:space="preserve"> <data name="AlpnMustContainHttp11ForWsTls" xml:space="preserve">
<value>EchConfigList</value> <value>Avec WebSocket et TLS, lALPN doit inclure http/1.1.</value>
</data> </data>
<data name="TbEchForceQuery" xml:space="preserve"> </root>
<value>EchForceQuery</value>
</data>
</root>

View file

@ -1641,10 +1641,7 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="menuServerList2" xml:space="preserve"> <data name="menuServerList2" xml:space="preserve">
<value>Configuration Item 2, Select and add from self-built</value> <value>Configuration Item 2, Select and add from self-built</value>
</data> </data>
<data name="TbEchConfigList" xml:space="preserve"> <data name="AlpnMustContainHttp11ForWsTls" xml:space="preserve">
<value>EchConfigList</value> <value>ALPN must contain 'http/1.1' when using WebSocket with TLS.</value>
</data>
<data name="TbEchForceQuery" xml:space="preserve">
<value>EchForceQuery</value>
</data> </data>
</root> </root>

View file

@ -1641,10 +1641,7 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="menuServerList2" xml:space="preserve"> <data name="menuServerList2" xml:space="preserve">
<value>Configuration Item 2, Select and add from self-built</value> <value>Configuration Item 2, Select and add from self-built</value>
</data> </data>
<data name="TbEchConfigList" xml:space="preserve"> <data name="AlpnMustContainHttp11ForWsTls" xml:space="preserve">
<value>EchConfigList</value> <value>ALPN must contain 'http/1.1' when using WebSocket with TLS.</value>
</data>
<data name="TbEchForceQuery" xml:space="preserve">
<value>EchForceQuery</value>
</data> </data>
</root> </root>

View file

@ -1641,10 +1641,7 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="menuServerList2" xml:space="preserve"> <data name="menuServerList2" xml:space="preserve">
<value>Configuration Item 2, Select and add from self-built</value> <value>Configuration Item 2, Select and add from self-built</value>
</data> </data>
<data name="TbEchConfigList" xml:space="preserve"> <data name="AlpnMustContainHttp11ForWsTls" xml:space="preserve">
<value>EchConfigList</value> <value>ALPN must contain 'http/1.1' when using WebSocket with TLS.</value>
</data>
<data name="TbEchForceQuery" xml:space="preserve">
<value>EchForceQuery</value>
</data> </data>
</root> </root>

View file

@ -1638,10 +1638,7 @@
<data name="menuServerList2" xml:space="preserve"> <data name="menuServerList2" xml:space="preserve">
<value>子配置项二,从自建中选择添加</value> <value>子配置项二,从自建中选择添加</value>
</data> </data>
<data name="TbEchConfigList" xml:space="preserve"> <data name="AlpnMustContainHttp11ForWsTls" xml:space="preserve">
<value>EchConfigList</value> <value>使用 WebSocket+TLS 时ALPN 必须包含 'http/1.1'。</value>
</data>
<data name="TbEchForceQuery" xml:space="preserve">
<value>EchForceQuery</value>
</data> </data>
</root> </root>

View file

@ -1638,10 +1638,7 @@
<data name="menuServerList2" xml:space="preserve"> <data name="menuServerList2" xml:space="preserve">
<value>子配置項二,從自建中選擇新增</value> <value>子配置項二,從自建中選擇新增</value>
</data> </data>
<data name="TbEchConfigList" xml:space="preserve"> <data name="AlpnMustContainHttp11ForWsTls" xml:space="preserve">
<value>EchConfigList</value> <value>ALPN must contain 'http/1.1' when using WebSocket with TLS.</value>
</data>
<data name="TbEchForceQuery" xml:space="preserve">
<value>EchForceQuery</value>
</data> </data>
</root> </root>

View file

@ -371,7 +371,7 @@ public partial class CoreConfigSingboxService(Config config)
await GenRouting(singboxConfig); await GenRouting(singboxConfig);
await GenExperimental(singboxConfig); await GenExperimental(singboxConfig);
await GenDns(parentNode, singboxConfig); await GenDns(null, singboxConfig);
await ConvertGeo2Ruleset(singboxConfig); await ConvertGeo2Ruleset(singboxConfig);
ret.Success = true; ret.Success = true;
@ -428,7 +428,7 @@ public partial class CoreConfigSingboxService(Config config)
await GenRouting(singboxConfig); await GenRouting(singboxConfig);
await GenExperimental(singboxConfig); await GenExperimental(singboxConfig);
await GenDns(parentNode, singboxConfig); await GenDns(null, singboxConfig);
await ConvertGeo2Ruleset(singboxConfig); await ConvertGeo2Ruleset(singboxConfig);
ret.Success = true; ret.Success = true;

View file

@ -13,8 +13,8 @@ public partial class CoreConfigSingboxService
} }
var simpleDNSItem = _config.SimpleDNSItem; var simpleDNSItem = _config.SimpleDNSItem;
await GenDnsServers(node, singboxConfig, simpleDNSItem); await GenDnsServers(singboxConfig, simpleDNSItem);
await GenDnsRules(node, singboxConfig, simpleDNSItem); await GenDnsRules(singboxConfig, simpleDNSItem);
singboxConfig.dns ??= new Dns4Sbox(); singboxConfig.dns ??= new Dns4Sbox();
singboxConfig.dns.independent_cache = true; singboxConfig.dns.independent_cache = true;
@ -52,7 +52,7 @@ public partial class CoreConfigSingboxService
return 0; return 0;
} }
private async Task<int> GenDnsServers(ProfileItem? node, SingboxConfig singboxConfig, SimpleDNSItem simpleDNSItem) private async Task<int> GenDnsServers(SingboxConfig singboxConfig, SimpleDNSItem simpleDNSItem)
{ {
var finalDns = await GenDnsDomains(singboxConfig, simpleDNSItem); var finalDns = await GenDnsDomains(singboxConfig, simpleDNSItem);
@ -133,29 +133,6 @@ public partial class CoreConfigSingboxService
singboxConfig.dns.servers.Add(fakeip); singboxConfig.dns.servers.Add(fakeip);
} }
// ech
var (_, dnsServer) = ParseEchParam(node?.EchConfigList);
if (dnsServer is not null)
{
dnsServer.tag = Global.SingboxEchDNSTag;
if (dnsServer.server is not null
&& hostsDns.predefined.ContainsKey(dnsServer.server))
{
dnsServer.domain_resolver = Global.SingboxHostsDNSTag;
}
else
{
dnsServer.domain_resolver = Global.SingboxLocalDNSTag;
}
singboxConfig.dns.servers.Add(dnsServer);
}
else if (node?.ConfigType.IsGroupType() == true)
{
var echDnsObject = JsonUtils.DeepCopy(directDns);
echDnsObject.tag = Global.SingboxEchDNSTag;
singboxConfig.dns.servers.Add(echDnsObject);
}
return await Task.FromResult(0); return await Task.FromResult(0);
} }
@ -169,7 +146,7 @@ public partial class CoreConfigSingboxService
return await Task.FromResult(finalDns); return await Task.FromResult(finalDns);
} }
private async Task<int> GenDnsRules(ProfileItem? node, SingboxConfig singboxConfig, SimpleDNSItem simpleDNSItem) private async Task<int> GenDnsRules(SingboxConfig singboxConfig, SimpleDNSItem simpleDNSItem)
{ {
singboxConfig.dns ??= new Dns4Sbox(); singboxConfig.dns ??= new Dns4Sbox();
singboxConfig.dns.rules ??= new List<Rule4Sbox>(); singboxConfig.dns.rules ??= new List<Rule4Sbox>();
@ -180,42 +157,17 @@ public partial class CoreConfigSingboxService
new Rule4Sbox new Rule4Sbox
{ {
server = Global.SingboxRemoteDNSTag, server = Global.SingboxRemoteDNSTag,
strategy = simpleDNSItem.SingboxStrategy4Proxy.NullIfEmpty(), strategy = simpleDNSItem.SingboxStrategy4Proxy.IsNullOrEmpty() ? null : simpleDNSItem.SingboxStrategy4Proxy,
clash_mode = ERuleMode.Global.ToString() clash_mode = ERuleMode.Global.ToString()
}, },
new Rule4Sbox new Rule4Sbox
{ {
server = Global.SingboxDirectDNSTag, server = Global.SingboxDirectDNSTag,
strategy = simpleDNSItem.SingboxStrategy4Direct.NullIfEmpty(), strategy = simpleDNSItem.SingboxStrategy4Direct.IsNullOrEmpty() ? null : simpleDNSItem.SingboxStrategy4Direct,
clash_mode = ERuleMode.Direct.ToString() clash_mode = ERuleMode.Direct.ToString()
} }
}); });
var (ech, _) = ParseEchParam(node?.EchConfigList);
if (ech is not null)
{
var echDomain = ech.query_server_name ?? node?.Sni;
singboxConfig.dns.rules.Add(new()
{
query_type = new List<int> { 64, 65 },
server = Global.SingboxEchDNSTag,
domain = echDomain is not null ? new List<string> { echDomain } : null,
});
}
else if (node?.ConfigType.IsGroupType() == true)
{
var queryServerNames = (await ProfileGroupItemManager.GetAllChildEchQuerySni(node.IndexId)).ToList();
if (queryServerNames.Count > 0)
{
singboxConfig.dns.rules.Add(new()
{
query_type = new List<int> { 64, 65 },
server = Global.SingboxEchDNSTag,
domain = queryServerNames,
});
}
}
if (simpleDNSItem.BlockBindingQuery == true) if (simpleDNSItem.BlockBindingQuery == true)
{ {
singboxConfig.dns.rules.Add(new() singboxConfig.dns.rules.Add(new()

View file

@ -10,7 +10,7 @@ public partial class CoreConfigSingboxService
singboxConfig.inbounds = []; singboxConfig.inbounds = [];
if (!_config.TunModeItem.EnableTun if (!_config.TunModeItem.EnableTun
|| (_config.TunModeItem.EnableTun && _config.TunModeItem.EnableExInbound && AppManager.Instance.RunningCoreType == ECoreType.sing_box)) || (_config.TunModeItem.EnableTun && _config.TunModeItem.EnableExInbound && _config.RunningCoreType == ECoreType.sing_box))
{ {
var inbound = new Inbound4Sbox() var inbound = new Inbound4Sbox()
{ {

View file

@ -334,11 +334,6 @@ public partial class CoreConfigSingboxService
}; };
tls.insecure = false; tls.insecure = false;
} }
var (ech, _) = ParseEchParam(node.EchConfigList);
if (ech is not null)
{
tls.ech = ech;
}
outbound.tls = tls; outbound.tls = tls;
} }
catch (Exception ex) catch (Exception ex)
@ -359,7 +354,7 @@ public partial class CoreConfigSingboxService
case nameof(ETransport.h2): case nameof(ETransport.h2):
transport.type = nameof(ETransport.http); transport.type = nameof(ETransport.http);
transport.host = node.RequestHost.IsNullOrEmpty() ? null : Utils.String2List(node.RequestHost); transport.host = node.RequestHost.IsNullOrEmpty() ? null : Utils.String2List(node.RequestHost);
transport.path = node.Path.NullIfEmpty(); transport.path = node.Path.IsNullOrEmpty() ? null : node.Path;
break; break;
case nameof(ETransport.tcp): //http case nameof(ETransport.tcp): //http
@ -367,7 +362,7 @@ public partial class CoreConfigSingboxService
{ {
transport.type = nameof(ETransport.http); transport.type = nameof(ETransport.http);
transport.host = node.RequestHost.IsNullOrEmpty() ? null : Utils.String2List(node.RequestHost); transport.host = node.RequestHost.IsNullOrEmpty() ? null : Utils.String2List(node.RequestHost);
transport.path = node.Path.NullIfEmpty(); transport.path = node.Path.IsNullOrEmpty() ? null : node.Path;
} }
break; break;
@ -401,7 +396,7 @@ public partial class CoreConfigSingboxService
} }
} }
transport.path = wsPath.NullIfEmpty(); transport.path = wsPath.IsNullOrEmpty() ? null : wsPath;
if (node.RequestHost.IsNotEmpty()) if (node.RequestHost.IsNotEmpty())
{ {
transport.headers = new() transport.headers = new()
@ -413,8 +408,8 @@ public partial class CoreConfigSingboxService
case nameof(ETransport.httpupgrade): case nameof(ETransport.httpupgrade):
transport.type = nameof(ETransport.httpupgrade); transport.type = nameof(ETransport.httpupgrade);
transport.path = node.Path.NullIfEmpty(); transport.path = node.Path.IsNullOrEmpty() ? null : node.Path;
transport.host = node.RequestHost.NullIfEmpty(); transport.host = node.RequestHost.IsNullOrEmpty() ? null : node.RequestHost;
break; break;
@ -909,31 +904,4 @@ public partial class CoreConfigSingboxService
} }
return await Task.FromResult(0); return await Task.FromResult(0);
} }
private (Ech4Sbox? ech, Server4Sbox? dnsServer) ParseEchParam(string? echConfig)
{
if (echConfig.IsNullOrEmpty())
{
return (null, null);
}
if (!echConfig.Contains("://"))
{
return (new Ech4Sbox()
{
enabled = true,
config = [$"-----BEGIN ECH CONFIGS-----\n" +
$"{echConfig}\n" +
$"-----END ECH CONFIGS-----"],
}, null);
}
var idx = echConfig.IndexOf('+');
// NOTE: query_server_name, since sing-box 1.13.0
//var queryServerName = idx > 0 ? echConfig[..idx] : null;
var echDnsServer = idx > 0 ? echConfig[(idx + 1)..] : echConfig;
return (new Ech4Sbox()
{
enabled = true,
query_server_name = null,
}, ParseDnsAddress(echDnsServer));
}
} }

View file

@ -113,7 +113,7 @@ public partial class CoreConfigSingboxService
clash_mode = ERuleMode.Global.ToString() clash_mode = ERuleMode.Global.ToString()
}); });
var domainStrategy = _config.RoutingBasicItem.DomainStrategy4Singbox.NullIfEmpty(); var domainStrategy = _config.RoutingBasicItem.DomainStrategy4Singbox.IsNullOrEmpty() ? null : _config.RoutingBasicItem.DomainStrategy4Singbox;
var defaultRouting = await ConfigHandler.GetDefaultRouting(_config); var defaultRouting = await ConfigHandler.GetDefaultRouting(_config);
if (defaultRouting.DomainStrategy4Singbox.IsNotEmpty()) if (defaultRouting.DomainStrategy4Singbox.IsNotEmpty())
{ {

View file

@ -197,7 +197,7 @@ public partial class CoreConfigV2rayService
if (item.OutboundTag == Global.DirectTag) if (item.OutboundTag == Global.DirectTag)
{ {
if (normalizedDomain.StartsWith("geosite:") || normalizedDomain.StartsWith("ext:")) if (normalizedDomain.StartsWith("geosite:"))
{ {
(regionNames.Contains(normalizedDomain) ? expectedDomainList : directGeositeList).Add(normalizedDomain); (regionNames.Contains(normalizedDomain) ? expectedDomainList : directGeositeList).Add(normalizedDomain);
} }
@ -208,7 +208,7 @@ public partial class CoreConfigV2rayService
} }
else if (item.OutboundTag != Global.BlockTag) else if (item.OutboundTag != Global.BlockTag)
{ {
if (normalizedDomain.StartsWith("geosite:") || normalizedDomain.StartsWith("ext:")) if (normalizedDomain.StartsWith("geosite:"))
{ {
proxyGeositeList.Add(normalizedDomain); proxyGeositeList.Add(normalizedDomain);
} }

View file

@ -272,9 +272,7 @@ public partial class CoreConfigV2rayService
{ {
allowInsecure = Utils.ToBool(node.AllowInsecure.IsNullOrEmpty() ? _config.CoreBasicItem.DefAllowInsecure.ToString().ToLower() : node.AllowInsecure), allowInsecure = Utils.ToBool(node.AllowInsecure.IsNullOrEmpty() ? _config.CoreBasicItem.DefAllowInsecure.ToString().ToLower() : node.AllowInsecure),
alpn = node.GetAlpn(), alpn = node.GetAlpn(),
fingerprint = node.Fingerprint.IsNullOrEmpty() ? _config.CoreBasicItem.DefFingerprint : node.Fingerprint, fingerprint = node.Fingerprint.IsNullOrEmpty() ? _config.CoreBasicItem.DefFingerprint : node.Fingerprint
echConfigList = node.EchConfigList.NullIfEmpty(),
echForceQuery = node.EchForceQuery.NullIfEmpty()
}; };
if (sni.IsNotEmpty()) if (sni.IsNotEmpty())
{ {
@ -342,7 +340,7 @@ public partial class CoreConfigV2rayService
kcpSettings.header = new Header4Ray kcpSettings.header = new Header4Ray
{ {
type = node.HeaderType, type = node.HeaderType,
domain = host.NullIfEmpty() domain = host.IsNullOrEmpty() ? null : host
}; };
if (path.IsNotEmpty()) if (path.IsNotEmpty())
{ {
@ -452,7 +450,7 @@ public partial class CoreConfigV2rayService
case nameof(ETransport.grpc): case nameof(ETransport.grpc):
GrpcSettings4Ray grpcSettings = new() GrpcSettings4Ray grpcSettings = new()
{ {
authority = host.NullIfEmpty(), authority = host.IsNullOrEmpty() ? null : host,
serviceName = path, serviceName = path,
multiMode = node.HeaderType == Global.GrpcMultiMode, multiMode = node.HeaderType == Global.GrpcMultiMode,
idle_timeout = _config.GrpcItem.IdleTimeout, idle_timeout = _config.GrpcItem.IdleTimeout,
@ -566,7 +564,7 @@ public partial class CoreConfigV2rayService
var fragmentOutbound = new Outbounds4Ray var fragmentOutbound = new Outbounds4Ray
{ {
protocol = "freedom", protocol = "freedom",
tag = $"frag-{Global.ProxyTag}", tag = $"{Global.ProxyTag}3",
settings = new() settings = new()
{ {
fragment = new() fragment = new()

View file

@ -198,7 +198,6 @@ public class SpeedtestService(Config config, Func<SpeedTestResult, Task> updateF
{ {
if (!it.AllowTest) if (!it.AllowTest)
{ {
await UpdateFunc(it.IndexId, ResUI.SpeedtestingSkip);
continue; continue;
} }

View file

@ -61,7 +61,7 @@ public class StatisticsSingboxService
await Task.Delay(1000); await Task.Delay(1000);
try try
{ {
if (!AppManager.Instance.IsRunningCore(ECoreType.sing_box)) if (!_config.IsRunningCore(ECoreType.sing_box))
{ {
continue; continue;
} }

View file

@ -30,7 +30,7 @@ public class StatisticsXrayService
await Task.Delay(1000); await Task.Delay(1000);
try try
{ {
if (AppManager.Instance.RunningCoreType != ECoreType.Xray) if (_config.RunningCoreType != ECoreType.Xray)
{ {
continue; continue;
} }

View file

@ -291,6 +291,13 @@ public class UpdateService(Config config, Func<bool, string, Task> updateFunc)
return url; return url;
} }
//Check for standalone windows .Net version
if (File.Exists(Path.Combine(Utils.GetBaseDirectory(), "wpfgfx_cor3.dll"))
&& File.Exists(Path.Combine(Utils.GetBaseDirectory(), "D3DCompiler_47_cor3.dll")))
{
return url?.Replace(".zip", "-SelfContained.zip");
}
//Check for avalonia desktop windows version //Check for avalonia desktop windows version
if (File.Exists(Path.Combine(Utils.GetBaseDirectory(), "libHarfBuzzSharp.dll"))) if (File.Exists(Path.Combine(Utils.GetBaseDirectory(), "libHarfBuzzSharp.dll")))
{ {

View file

@ -128,7 +128,7 @@ public class ClashConnectionsViewModel : MyReactiveObject
{ {
await Task.Delay(1000 * 5); await Task.Delay(1000 * 5);
numOfExecuted++; numOfExecuted++;
if (!(AutoRefresh && AppManager.Instance.ShowInTaskbar && AppManager.Instance.IsRunningCore(ECoreType.sing_box))) if (!(AutoRefresh && _config.UiItem.ShowInTaskbar && _config.IsRunningCore(ECoreType.sing_box)))
{ {
continue; continue;
} }

View file

@ -437,7 +437,7 @@ public class ClashProxiesViewModel : MyReactiveObject
{ {
await Task.Delay(1000 * 60); await Task.Delay(1000 * 60);
numOfExecuted++; numOfExecuted++;
if (!(AutoRefresh && AppManager.Instance.ShowInTaskbar && AppManager.Instance.IsRunningCore(ECoreType.sing_box))) if (!(AutoRefresh && _config.UiItem.ShowInTaskbar && _config.IsRunningCore(ECoreType.sing_box)))
{ {
continue; continue;
} }

View file

@ -253,7 +253,7 @@ public class MainWindowViewModel : MyReactiveObject
private async Task Init() private async Task Init()
{ {
AppManager.Instance.ShowInTaskbar = true; _config.UiItem.ShowInTaskbar = true;
//await ConfigHandler.InitBuiltinRouting(_config); //await ConfigHandler.InitBuiltinRouting(_config);
await ConfigHandler.InitBuiltinDNS(_config); await ConfigHandler.InitBuiltinDNS(_config);
@ -306,7 +306,7 @@ public class MainWindowViewModel : MyReactiveObject
private async Task UpdateStatisticsHandler(ServerSpeedItem update) private async Task UpdateStatisticsHandler(ServerSpeedItem update)
{ {
if (!AppManager.Instance.ShowInTaskbar) if (!_config.UiItem.ShowInTaskbar)
{ {
return; return;
} }
@ -560,7 +560,7 @@ public class MainWindowViewModel : MyReactiveObject
}); });
AppEvents.TestServerRequested.Publish(); AppEvents.TestServerRequested.Publish();
var showClashUI = AppManager.Instance.IsRunningCore(ECoreType.sing_box); var showClashUI = _config.IsRunningCore(ECoreType.sing_box);
if (showClashUI) if (showClashUI)
{ {
AppEvents.ProxiesReloadRequested.Publish(); AppEvents.ProxiesReloadRequested.Publish();

View file

@ -44,7 +44,7 @@ public class MsgViewModel : MyReactiveObject
EnqueueQueueMsg(msg); EnqueueQueueMsg(msg);
if (!AppManager.Instance.ShowInTaskbar) if (!_config.UiItem.ShowInTaskbar)
{ {
return; return;
} }

View file

@ -56,8 +56,7 @@ public class ProfilesViewModel : MyReactiveObject
public ReactiveCommand<Unit, Unit> MoveUpCmd { get; } public ReactiveCommand<Unit, Unit> MoveUpCmd { get; }
public ReactiveCommand<Unit, Unit> MoveDownCmd { get; } public ReactiveCommand<Unit, Unit> MoveDownCmd { get; }
public ReactiveCommand<Unit, Unit> MoveBottomCmd { get; } public ReactiveCommand<Unit, Unit> MoveBottomCmd { get; }
public ReactiveCommand<SubItem, Unit> MoveToGroupCmd { get; }
//servers ping //servers ping
public ReactiveCommand<Unit, Unit> MixedTestServerCmd { get; } public ReactiveCommand<Unit, Unit> MixedTestServerCmd { get; }
@ -180,10 +179,6 @@ public class ProfilesViewModel : MyReactiveObject
{ {
await MoveServer(EMove.Bottom); await MoveServer(EMove.Bottom);
}, canEditRemove); }, canEditRemove);
MoveToGroupCmd = ReactiveCommand.CreateFromTask<SubItem>(async sub =>
{
SelectedMoveToGroup = sub;
});
//servers ping //servers ping
FastRealPingCmd = ReactiveCommand.CreateFromTask(async () => FastRealPingCmd = ReactiveCommand.CreateFromTask(async () =>

View file

@ -549,7 +549,7 @@ public class StatusBarViewModel : MyReactiveObject
try try
{ {
if (AppManager.Instance.IsRunningCore(ECoreType.sing_box)) if (_config.IsRunningCore(ECoreType.sing_box))
{ {
SpeedProxyDisplay = string.Format(ResUI.SpeedDisplayText, EInboundProtocol.mixed, Utils.HumanFy(update.ProxyUp), Utils.HumanFy(update.ProxyDown)); SpeedProxyDisplay = string.Format(ResUI.SpeedDisplayText, EInboundProtocol.mixed, Utils.HumanFy(update.ProxyUp), Utils.HumanFy(update.ProxyDown));
SpeedDirectDisplay = string.Empty; SpeedDirectDisplay = string.Empty;

View file

@ -713,7 +713,7 @@
Grid.Row="7" Grid.Row="7"
ColumnDefinitions="300,Auto" ColumnDefinitions="300,Auto"
IsVisible="False" IsVisible="False"
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto"> RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto">
<TextBlock <TextBlock
Grid.Row="1" Grid.Row="1"
@ -768,41 +768,15 @@
Width="200" Width="200"
Margin="{StaticResource Margin4}" /> Margin="{StaticResource Margin4}" />
<TextBlock
Grid.Row="5"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbEchConfigList}" />
<TextBox
x:Name="txtEchConfigList"
Grid.Row="5"
Grid.Column="1"
Width="400"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" />
<TextBlock <TextBlock
Grid.Row="6" Grid.Row="5"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbEchForceQuery}" />
<ComboBox
x:Name="cmbEchForceQuery"
Grid.Row="6"
Grid.Column="1"
Width="200"
Margin="{StaticResource Margin4}" />
<TextBlock
Grid.Row="7"
Grid.Column="0" Grid.Column="0"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
VerticalAlignment="Center" VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbCertPinning}" /> Text="{x:Static resx:ResUI.TbCertPinning}" />
<StackPanel <StackPanel
Grid.Row="7" Grid.Row="5"
Grid.Column="1" Grid.Column="1"
VerticalAlignment="Center" VerticalAlignment="Center"
Orientation="Horizontal"> Orientation="Horizontal">

View file

@ -28,7 +28,6 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
cmbFingerprint2.ItemsSource = Global.Fingerprints; cmbFingerprint2.ItemsSource = Global.Fingerprints;
cmbAllowInsecure.ItemsSource = Global.AllowInsecure; cmbAllowInsecure.ItemsSource = Global.AllowInsecure;
cmbAlpn.ItemsSource = Global.Alpns; cmbAlpn.ItemsSource = Global.Alpns;
cmbEchForceQuery.ItemsSource = Global.EchForceQuerys;
var lstStreamSecurity = new List<string>(); var lstStreamSecurity = new List<string>();
lstStreamSecurity.Add(string.Empty); lstStreamSecurity.Add(string.Empty);
@ -188,9 +187,6 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
this.Bind(ViewModel, vm => vm.SelectedSource.Alpn, v => v.cmbAlpn.SelectedValue).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.Alpn, v => v.cmbAlpn.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.CertTip, v => v.labCertPinning.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.CertTip, v => v.labCertPinning.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.Cert, v => v.txtCert.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.Cert, v => v.txtCert.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.EchConfigList, v => v.txtEchConfigList.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.EchForceQuery, v => v.cmbEchForceQuery.SelectedValue).DisposeWith(disposables);
//reality //reality
this.Bind(ViewModel, vm => vm.SelectedSource.Sni, v => v.txtSNI2.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.Sni, v => v.txtSNI2.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.Fingerprint, v => v.cmbFingerprint2.SelectedValue).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.Fingerprint, v => v.cmbFingerprint2.SelectedValue).DisposeWith(disposables);

View file

@ -11,7 +11,7 @@
Title="v2rayN" Title="v2rayN"
Width="1200" Width="1200"
Height="800" Height="800"
MinWidth="600" MinWidth="900"
x:DataType="vms:MainWindowViewModel" x:DataType="vms:MainWindowViewModel"
Icon="/Assets/NotifyIcon1.ico" Icon="/Assets/NotifyIcon1.ico"
ShowInTaskbar="True" ShowInTaskbar="True"

View file

@ -409,8 +409,8 @@ public partial class MainWindow : WindowBase<MainWindowViewModel>
{ {
var bl = blShow ?? var bl = blShow ??
(Utils.IsLinux() (Utils.IsLinux()
? (!AppManager.Instance.ShowInTaskbar ^ (WindowState == WindowState.Minimized)) ? (!_config.UiItem.ShowInTaskbar ^ (WindowState == WindowState.Minimized))
: !AppManager.Instance.ShowInTaskbar); : !_config.UiItem.ShowInTaskbar);
if (bl) if (bl)
{ {
Show(); Show();
@ -436,7 +436,7 @@ public partial class MainWindow : WindowBase<MainWindowViewModel>
Hide(); Hide();
} }
AppManager.Instance.ShowInTaskbar = bl; _config.UiItem.ShowInTaskbar = bl;
} }
protected override void OnLoaded(object? sender, RoutedEventArgs e) protected override void OnLoaded(object? sender, RoutedEventArgs e)

View file

@ -7,7 +7,6 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib" xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib" xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
x:Name="Root"
d:DesignHeight="450" d:DesignHeight="450"
d:DesignWidth="800" d:DesignWidth="800"
x:DataType="vms:ProfilesViewModel" x:DataType="vms:ProfilesViewModel"
@ -142,18 +141,19 @@
InputGesture="Ctrl+T" /> InputGesture="Ctrl+T" />
<MenuItem x:Name="menuSortServerResult" Header="{x:Static resx:ResUI.menuSortServerResult}" /> <MenuItem x:Name="menuSortServerResult" Header="{x:Static resx:ResUI.menuSortServerResult}" />
<Separator /> <Separator />
<MenuItem <MenuItem x:Name="menuMoveToGroup" Header="{x:Static resx:ResUI.menuMoveToGroup}">
x:Name="menuMoveToGroup" <MenuItem>
Header="{x:Static resx:ResUI.menuMoveToGroup}" <MenuItem.Header>
ItemsSource="{Binding DataContext.SubItems, ElementName=Root}"> <DockPanel>
<MenuItem.ItemTemplate> <ComboBox
<DataTemplate> x:Name="cmbMoveToGroup"
<MenuItem Width="200"
Command="{Binding DataContext.MoveToGroupCmd, ElementName=Root}" DisplayMemberBinding="{Binding Remarks}"
CommandParameter="{Binding}" ItemsSource="{Binding SubItems}"
Header="{Binding Remarks}" /> ToolTip.Tip="{x:Static resx:ResUI.menuSubscription}" />
</DataTemplate> </DockPanel>
</MenuItem.ItemTemplate> </MenuItem.Header>
</MenuItem>
</MenuItem> </MenuItem>
<MenuItem Header="{x:Static resx:ResUI.menuMoveTo}"> <MenuItem Header="{x:Static resx:ResUI.menuMoveTo}">
<MenuItem <MenuItem

View file

@ -69,7 +69,7 @@ public partial class ProfilesView : ReactiveUserControl<ProfilesViewModel>
//servers move //servers move
//this.OneWayBind(ViewModel, vm => vm.SubItems, v => v.cmbMoveToGroup.ItemsSource).DisposeWith(disposables); //this.OneWayBind(ViewModel, vm => vm.SubItems, v => v.cmbMoveToGroup.ItemsSource).DisposeWith(disposables);
//this.Bind(ViewModel, vm => vm.SelectedMoveToGroup, v => v.cmbMoveToGroup.SelectedItem).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedMoveToGroup, v => v.cmbMoveToGroup.SelectedItem).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.MoveTopCmd, v => v.menuMoveTop).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.MoveTopCmd, v => v.menuMoveTop).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.MoveUpCmd, v => v.menuMoveUp).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.MoveUpCmd, v => v.menuMoveUp).DisposeWith(disposables);

View file

@ -40,14 +40,6 @@
<DataGrid.KeyBindings> <DataGrid.KeyBindings>
<KeyBinding Command="{Binding SubDeleteCmd}" Gesture="Delete" /> <KeyBinding Command="{Binding SubDeleteCmd}" Gesture="Delete" />
</DataGrid.KeyBindings> </DataGrid.KeyBindings>
<DataGrid.ContextMenu>
<ContextMenu>
<MenuItem x:Name="menuSubAdd2" Header="{x:Static resx:ResUI.menuSubAdd}" />
<MenuItem x:Name="menuSubDelete2" Header="{x:Static resx:ResUI.menuSubDelete}" />
<MenuItem x:Name="menuSubEdit2" Header="{x:Static resx:ResUI.menuSubEdit}" />
<MenuItem x:Name="menuSubShare2" Header="{x:Static resx:ResUI.menuSubShare}" />
</ContextMenu>
</DataGrid.ContextMenu>
<DataGrid.Columns> <DataGrid.Columns>
<DataGridTextColumn <DataGridTextColumn
Width="*" Width="*"

View file

@ -29,11 +29,6 @@ public partial class SubSettingWindow : WindowBase<SubSettingViewModel>
this.BindCommand(ViewModel, vm => vm.SubDeleteCmd, v => v.menuSubDelete).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SubDeleteCmd, v => v.menuSubDelete).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.SubEditCmd, v => v.menuSubEdit).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SubEditCmd, v => v.menuSubEdit).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.SubShareCmd, v => v.menuSubShare).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SubShareCmd, v => v.menuSubShare).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.SubAddCmd, v => v.menuSubAdd2).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.SubDeleteCmd, v => v.menuSubDelete2).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.SubEditCmd, v => v.menuSubEdit2).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.SubShareCmd, v => v.menuSubShare2).DisposeWith(disposables);
}); });
} }

View file

@ -15,7 +15,7 @@
SecondaryColor="Lime" /> SecondaryColor="Lime" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesign2.Defaults.xaml" /> <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesign2.Defaults.xaml" />
</ResourceDictionary.MergedDictionaries> </ResourceDictionary.MergedDictionaries>
<system:Double x:Key="MenuItemHeight">32</system:Double> <system:Double x:Key="MenuItemHeight">26</system:Double>
<system:Double x:Key="StdFontSize">12</system:Double> <system:Double x:Key="StdFontSize">12</system:Double>
<system:Double x:Key="StdFontSize1">13</system:Double> <system:Double x:Key="StdFontSize1">13</system:Double>
<system:Double x:Key="StdFontSize-1">11</system:Double> <system:Double x:Key="StdFontSize-1">11</system:Double>

View file

@ -1,7 +1,6 @@
using MaterialDesignColors; using MaterialDesignColors;
using MaterialDesignColors.ColorManipulation; using MaterialDesignColors.ColorManipulation;
using MaterialDesignThemes.Wpf; using MaterialDesignThemes.Wpf;
using Microsoft.Win32;
namespace v2rayN.ViewModels; namespace v2rayN.ViewModels;
@ -25,7 +24,7 @@ public class ThemeSettingViewModel : MyReactiveObject
{ {
_config = AppManager.Instance.Config; _config = AppManager.Instance.Config;
RegisterSystemColorSet(_config, ModifyTheme); RegisterSystemColorSet(_config, Application.Current.MainWindow, ModifyTheme);
BindingUI(); BindingUI();
RestoreUI(); RestoreUI();
@ -159,15 +158,25 @@ public class ThemeSettingViewModel : MyReactiveObject
_paletteHelper.SetTheme(theme); _paletteHelper.SetTheme(theme);
} }
public static void RegisterSystemColorSet(Config config, Action updateFunc) public void RegisterSystemColorSet(Config config, Window window, Action updateFunc)
{ {
SystemEvents.UserPreferenceChanged += (s, e) => var helper = new WindowInteropHelper(window);
var hwndSource = HwndSource.FromHwnd(helper.EnsureHandle());
hwndSource.AddHook((IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) =>
{ {
if ((e.Category == UserPreferenceCategory.Color || e.Category == UserPreferenceCategory.General) if (config.UiItem.CurrentTheme == nameof(ETheme.FollowSystem))
&& config.UiItem.CurrentTheme == nameof(ETheme.FollowSystem))
{ {
updateFunc?.Invoke(); const int WM_SETTINGCHANGE = 0x001A;
if (msg == WM_SETTINGCHANGE)
{
if (wParam == IntPtr.Zero && Marshal.PtrToStringUni(lParam) == "ImmersiveColorSet")
{
updateFunc?.Invoke();
}
}
} }
};
return IntPtr.Zero;
});
} }
} }

View file

@ -929,8 +929,6 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="300" /> <ColumnDefinition Width="300" />
@ -1005,40 +1003,9 @@
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbEchConfigList}" />
<TextBox
x:Name="txtEchConfigList"
Grid.Row="5"
Grid.Column="1"
Width="400"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left"
Style="{StaticResource DefTextBox}" />
<TextBlock
Grid.Row="6"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbEchForceQuery}" />
<ComboBox
x:Name="cmbEchForceQuery"
Grid.Row="6"
Grid.Column="1"
Width="200"
Margin="{StaticResource Margin4}"
Style="{StaticResource DefComboBox}" />
<TextBlock
Grid.Row="7"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbCertPinning}" /> Text="{x:Static resx:ResUI.TbCertPinning}" />
<StackPanel <StackPanel
Grid.Row="7" Grid.Row="5"
Grid.Column="1" Grid.Column="1"
VerticalAlignment="Center" VerticalAlignment="Center"
Orientation="Horizontal"> Orientation="Horizontal">

View file

@ -23,7 +23,6 @@ public partial class AddServerWindow
cmbFingerprint2.ItemsSource = Global.Fingerprints; cmbFingerprint2.ItemsSource = Global.Fingerprints;
cmbAllowInsecure.ItemsSource = Global.AllowInsecure; cmbAllowInsecure.ItemsSource = Global.AllowInsecure;
cmbAlpn.ItemsSource = Global.Alpns; cmbAlpn.ItemsSource = Global.Alpns;
cmbEchForceQuery.ItemsSource = Global.EchForceQuerys;
var lstStreamSecurity = new List<string>(); var lstStreamSecurity = new List<string>();
lstStreamSecurity.Add(string.Empty); lstStreamSecurity.Add(string.Empty);
@ -183,10 +182,6 @@ public partial class AddServerWindow
this.Bind(ViewModel, vm => vm.SelectedSource.Alpn, v => v.cmbAlpn.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.Alpn, v => v.cmbAlpn.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.CertTip, v => v.labCertPinning.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.CertTip, v => v.labCertPinning.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.Cert, v => v.txtCert.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.Cert, v => v.txtCert.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.Cert, v => v.txtCert.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.EchConfigList, v => v.txtEchConfigList.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.EchForceQuery, v => v.cmbEchForceQuery.Text).DisposeWith(disposables);
//reality //reality
this.Bind(ViewModel, vm => vm.SelectedSource.Sni, v => v.txtSNI2.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.Sni, v => v.txtSNI2.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.Fingerprint, v => v.cmbFingerprint2.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.Fingerprint, v => v.cmbFingerprint2.Text).DisposeWith(disposables);

View file

@ -13,7 +13,7 @@
Title="v2rayN" Title="v2rayN"
Width="1200" Width="1200"
Height="800" Height="800"
MinWidth="800" MinWidth="900"
x:TypeArguments="vms:MainWindowViewModel" x:TypeArguments="vms:MainWindowViewModel"
Icon="/Resources/v2rayN.ico" Icon="/Resources/v2rayN.ico"
ResizeMode="CanResizeWithGrip" ResizeMode="CanResizeWithGrip"

View file

@ -376,7 +376,7 @@ public partial class MainWindow
public void ShowHideWindow(bool? blShow) public void ShowHideWindow(bool? blShow)
{ {
var bl = blShow ?? !AppManager.Instance.ShowInTaskbar; var bl = blShow ?? !_config.UiItem.ShowInTaskbar;
if (bl) if (bl)
{ {
this?.Show(); this?.Show();
@ -391,7 +391,7 @@ public partial class MainWindow
{ {
this?.Hide(); this?.Hide();
} }
AppManager.Instance.ShowInTaskbar = bl; _config.UiItem.ShowInTaskbar = bl;
} }
protected override void OnLoaded(object? sender, RoutedEventArgs e) protected override void OnLoaded(object? sender, RoutedEventArgs e)

View file

@ -93,26 +93,6 @@
HeadersVisibility="Column" HeadersVisibility="Column"
IsReadOnly="True" IsReadOnly="True"
Style="{StaticResource DefDataGrid}"> Style="{StaticResource DefDataGrid}">
<DataGrid.ContextMenu>
<ContextMenu Style="{StaticResource DefContextMenu}">
<MenuItem
x:Name="menuSubAdd2"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuSubAdd}" />
<MenuItem
x:Name="menuSubDelete2"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuSubDelete}" />
<MenuItem
x:Name="menuSubEdit2"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuSubEdit}" />
<MenuItem
x:Name="menuSubShare2"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuSubShare}" />
</ContextMenu>
</DataGrid.ContextMenu>
<DataGrid.Columns> <DataGrid.Columns>
<DataGridTextColumn <DataGridTextColumn
Width="*" Width="*"

View file

@ -25,11 +25,6 @@ public partial class SubSettingWindow
this.BindCommand(ViewModel, vm => vm.SubDeleteCmd, v => v.menuSubDelete).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SubDeleteCmd, v => v.menuSubDelete).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.SubEditCmd, v => v.menuSubEdit).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SubEditCmd, v => v.menuSubEdit).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.SubShareCmd, v => v.menuSubShare).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SubShareCmd, v => v.menuSubShare).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.SubAddCmd, v => v.menuSubAdd2).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.SubDeleteCmd, v => v.menuSubDelete2).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.SubEditCmd, v => v.menuSubEdit2).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.SubShareCmd, v => v.menuSubShare2).DisposeWith(disposables);
}); });
WindowsUtils.SetDarkBorder(this, AppManager.Instance.Config.UiItem.CurrentTheme); WindowsUtils.SetDarkBorder(this, AppManager.Instance.Config.UiItem.CurrentTheme);
} }