throne: 1.0.13 -> 1.1.1-unstable-2026-03-28

This commit is contained in:
TomaSajt
2026-03-29 17:36:37 +02:00
parent 496ca5d659
commit 5107ccedca
5 changed files with 92 additions and 64 deletions
+6 -5
View File
@@ -23,7 +23,7 @@ in
enable = lib.mkEnableOption "TUN mode of Throne";
setuid = lib.mkEnableOption ''
setting suid bit for throne-core to run as root, which is less
setting suid bit for ThroneCore to run as root, which is less
secure than default setcap method but closer to upstream assumptions.
Enable this if you find the default setcap method configured in
this module doesn't work for you
@@ -36,8 +36,8 @@ in
environment.systemPackages = [ cfg.package ];
security.wrappers.throne-core = lib.mkIf cfg.tunMode.enable {
source = "${cfg.package}/share/throne/Core";
security.wrappers."ThroneCore" = lib.mkIf cfg.tunMode.enable {
source = "${cfg.package}/share/throne/ThroneCore";
owner = "root";
group = "root";
setuid = lib.mkIf cfg.tunMode.setuid true;
@@ -49,7 +49,7 @@ in
# avoid resolvectl password prompt popping up three times
# https://github.com/SagerNet/sing-tun/blob/0686f8c4f210f4e7039c352d42d762252f9d9cf5/tun_linux.go#L1062
# We use a hack here to determine whether the requested process is throne-core
# We use a hack here to determine whether the requested process is ThroneCore
# Detect whether its capabilities contain at least `net_admin` and `net_raw`.
# This does not reduce security, as we can already bypass `resolved` with them.
# Alternatives to consider:
@@ -61,7 +61,7 @@ in
# change its own cmdline. `/proc/<pid>/exe` is reliable but kernel forbids
# checking that entry of process from different users, and polkit runs `spawn`
# as an unprivileged user.
# 3. Put throne-core into a systemd service, and let polkit check service name.
# 3. Put ThroneCore into a systemd service, and let polkit check service name.
# This is the most secure and convenient way but requires heavy modification
# to Throne source code. Would be good to let upstream support that eventually.
security.polkit.extraConfig =
@@ -69,6 +69,7 @@ in
''
polkit.addRule(function(action, subject) {
const allowedActionIds = [
"org.freedesktop.resolve1.revert",
"org.freedesktop.resolve1.set-domains",
"org.freedesktop.resolve1.set-default-route",
"org.freedesktop.resolve1.set-dns-servers"
@@ -1,42 +1,40 @@
diff --git a/server.go b/server.go
index e2f2ab3..f81812f 100644
index 4499a6d..4c14d1a 100644
--- a/server.go
+++ b/server.go
@@ -16,6 +16,7 @@ import (
@@ -24,6 +24,7 @@ import (
"github.com/sagernet/sing-box/experimental/clashapi"
"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions"
+ "golang.org/x/sys/unix"
"github.com/sagernet/sing/service"
"github.com/throneproj/clash2singbox/convert"
"github.com/throneproj/clash2singbox/model"
"github.com/throneproj/clash2singbox/model/clash"
@@ -349,12 +350,25 @@ func (s *server) CompileGeoSiteToSrs(in *gen.CompileGeoSiteToSrsRequest, out *ge
}
"github.com/xtls/xray-core/core"
)
@@ -462,6 +463,27 @@ func (s *server) IsPrivileged(ctx context.Context, _ *gen.EmptyReq) (*gen.IsPriv
}, nil
}
func (s *server) IsPrivileged(in *gen.EmptyReq, out *gen.IsPrivilegedResponse) error {
- if runtime.GOOS == "windows" {
- out.HasPrivilege = To(false)
- return nil
+ ret := false
+ if runtime.GOOS == "windows" || os.Geteuid() == 0 {
+ ret = true
+ } else if runtime.GOOS == "linux" {
+ if runtime.GOOS == "linux" {
+ caps := unix.CapUserHeader{
+ Version: unix.LINUX_CAPABILITY_VERSION_3,
+ Pid: 0, // current
+ }
+
+ var data [2]unix.CapUserData
+ err := unix.Capget(&caps, &data[0])
+
+ if err != nil {
+ ret = false
+ } else {
+ // CAP_NET_ADMIN = 12
+ ret = (data[0].Effective & (1 << unix.CAP_NET_ADMIN)) != 0
+ return &gen.IsPrivilegedResponse{
+ HasPrivilege: To(false),
+ }, nil
+ }
}
- out.HasPrivilege = To(os.Geteuid() == 0)
+ out.HasPrivilege = To(ret)
return nil
+
+ // CAP_NET_ADMIN = 12
+ return &gen.IsPrivilegedResponse{
+ HasPrivilege: To((data[0].Effective & (1 << unix.CAP_NET_ADMIN)) != 0),
+ }, nil
+ }
+
return &gen.IsPrivilegedResponse{HasPrivilege: To(os.Geteuid() == 0)}, nil
}
@@ -0,0 +1,24 @@
diff --git a/src/sys/linux/AutoRun.cpp b/src/sys/linux/AutoRun.cpp
index 1fafe35..fe04c75 100644
--- a/src/sys/linux/AutoRun.cpp
+++ b/src/sys/linux/AutoRun.cpp
@@ -31,18 +31,9 @@ void AutoRun_SetEnabled(bool enable) {
QString desktopFileLocation = userAutoStartPath + appName + QLatin1String(".desktop");
QStringList appCmdList;
- if (QProcessEnvironment::systemEnvironment().contains("APPIMAGE")) {
- appCmdList << QProcessEnvironment::systemEnvironment().value("APPIMAGE");
- } else {
- appCmdList << QApplication::applicationFilePath();
- }
-
+ appCmdList << "Throne";
appCmdList << "-tray";
- if (Configs::dataManager->settingsRepo->flag_use_appdata) {
- appCmdList << "-appdata";
- }
-
if (enable) {
if (!QDir().exists(userAutoStartPath) && !QDir().mkpath(userAutoStartPath)) {
// qCWarning(lcUtility) << "Could not create autostart folder"
@@ -1,42 +1,42 @@
diff --git a/src/global/Configs.cpp b/src/global/Configs.cpp
index e7bec9c..f0dfe53 100644
index 37b69be..2d458f3 100644
--- a/src/global/Configs.cpp
+++ b/src/global/Configs.cpp
@@ -404,6 +404,12 @@ namespace Configs {
// System Utils
@@ -45,6 +45,12 @@ namespace Configs {
}
QString FindCoreRealPath() {
+ // find in PATH first
+ QString path_for_nixos = QStandardPaths::findExecutable("throne-core");
+ QString path_for_nixos = QStandardPaths::findExecutable("ThroneCore");
+ if (!path_for_nixos.isEmpty()) {
+ return path_for_nixos;
+ }
+
auto fn = QApplication::applicationDirPath() + "/Core";
auto fn = QApplication::applicationDirPath() + "/ThroneCore";
#ifdef Q_OS_WIN
fn += ".exe";
diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp
index d31c311..ce4c357 100644
index 9acfee4..c0c313a 100644
--- a/src/ui/mainwindow.cpp
+++ b/src/ui/mainwindow.cpp
@@ -151,8 +151,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
Configs::dataStore->core_port = MkPort();
if (Configs::dataStore->core_port <= 0) Configs::dataStore->core_port = 19810;
@@ -163,8 +163,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
Configs::dataManager->settingsRepo->core_port = MkPort();
if (Configs::dataManager->settingsRepo->core_port <= 0) Configs::dataManager->settingsRepo->core_port = 19810;
- auto core_path = QApplication::applicationDirPath() + "/";
- core_path += "Core";
- core_path += "ThroneCore";
+ auto core_path = Configs::FindCoreRealPath();
QStringList args;
args.push_back("-port");
@@ -1045,6 +1044,15 @@ bool MainWindow::get_elevated_permissions(int reason) {
@@ -1296,6 +1295,15 @@ bool MainWindow::get_elevated_permissions(int reason) {
return true;
}
if (Configs::IsAdmin()) return true;
+ QMessageBox::critical(
+ GetMessageBoxParent(),
+ tr("Unable to elevate privileges when installed with Nix"),
+ tr("Due to the read-only property of Nix store, we cannot set suid for throne-core. If you are using NixOS, please install Throne via `programs.throne.enable` and then set the `programs.throne.tunMode.enable` option to elevate privileges."),
+ tr("Due to the read-only property of the Nix store, we cannot set suid for ThroneCore. If you are using NixOS, please install Throne via `programs.throne.enable` and then set the `programs.throne.tunMode.enable` option to elevate privileges."),
+ QMessageBox::Ok
+ );
+ return false;
+28 -23
View File
@@ -9,7 +9,7 @@
protobuf,
protoc-gen-go,
protorpc,
protoc-gen-go-grpc,
cmake,
copyDesktopItems,
@@ -19,23 +19,20 @@
# override if you want to have more up-to-date rulesets
throne-srslist ? fetchurl {
url = "https://raw.githubusercontent.com/throneproj/routeprofiles/0fca735ff2759422c407ac04fac819aef2fc88f9/srslist.h";
hash = "sha256-G2WUStxFtN0fbZm/KoD9ldUvkMWf9cDA+9fvYt8dcqo=";
url = "https://raw.githubusercontent.com/throneproj/routeprofiles/05793e2da7ca10a7acb2494f60a27ac5f7ec924c/srslist.h";
hash = "sha256-NHer5Vy1zBL9yJlVDLVFNRG4ITzb2GTjmt718KsSrGw=";
},
}:
stdenv.mkDerivation (finalAttrs: {
pname = "throne";
version = "1.0.13";
version = "1.1.1-unstable-2026-03-28";
src = fetchFromGitHub {
owner = "throneproj";
repo = "Throne";
# the release CI job was triggered on the xhttp branch (https://github.com/throneproj/Throne/actions/runs/20588046213),
# but the 1.0.13 tag was wrongly created on the dev branch
# we'll use the revision that was used for the job as well
rev = "3b737ec8cf29e03e4b7d5a09b1f502bdb8ef52e2";
hash = "sha256-OVgmhiKL4BaFYBeUqIX3LRNa54zq5oYyNMUYwKNvo1A=";
rev = "f53bb73790782a9a9b7bfeb30c8d6e6bcc2b05f0";
hash = "sha256-hEjbzS0JV5OA0c9kWTFGc5kv04qzobN0TFBjMJZ1ohc=";
};
strictDeps = true;
@@ -54,33 +51,36 @@ stdenv.mkDerivation (finalAttrs: {
env.INPUT_VERSION = finalAttrs.version;
cmakeFlags = [
# makes sure the app uses the user's config directory to store it's non-static content
# it's essentially the same as always setting the -appdata flag when running the program
(lib.cmakeBool "NKR_PACKAGE" true)
];
# suppress errors in 3rdparty/simple-protobuf
env.NIX_CFLAGS_COMPILE = "-Wno-error=maybe-uninitialized";
patches = [
# disable suid request as it cannot be applied to throne-core in nix store
# and prompt users to use NixOS module instead. And use throne-core from PATH
# disable suid request as it cannot be applied to ThroneCore in nix store
# and prompt users to use NixOS module instead. And use ThroneCore from PATH
# to make use of security wrappers
./nixos-disable-setuid-request.patch
# sets the Exec field of the auto-run .desktop file to use the Throne binary from PATH
./fix-autorun-desktop-exec.patch
];
preBuild = ''
ln -s ${throne-srslist} ./srslist.h
'';
# we'll wrap manually
dontWrapQtApps = true;
installPhase = ''
runHook preInstall
install -Dm755 Throne -t "$out/share/throne/"
install -Dm644 "$src/res/public/Throne.png" -t "$out/share/icons/hicolor/512x512/apps/"
mkdir -p "$out/bin"
ln -s "$out/share/throne/Throne" "$out/bin/"
makeQtWrapper "$out/share/throne/Throne" "$out/bin/Throne" \
--append-flag "-appdata" # use writable config dir
ln -s ${finalAttrs.passthru.core}/bin/Core "$out/share/throne/Core"
ln -s ${finalAttrs.passthru.core}/bin/ThroneCore "$out/share/throne/ThroneCore"
runHook postInstall
'';
@@ -108,18 +108,18 @@ stdenv.mkDerivation (finalAttrs: {
];
proxyVendor = true;
vendorHash = "sha256-cPo/2bUXEF9jomr0Pnty7ZutAaC0TFG397FSIqefrjw=";
vendorHash = "sha256-HNd0HI4JRPZiiSxDzOKgyAOW7tzZPCTPvOC5t+3yhoQ=";
nativeBuildInputs = [
protobuf
protoc-gen-go
protorpc
protoc-gen-go-grpc
];
# taken from script/build_go.sh
preBuild = ''
pushd gen
protoc -I . --go_out=. --protorpc_out=. libcore.proto
protoc -I . --go_out=. --go-grpc_out=. libcore.proto
popd
VERSION_SINGBOX=$(go list -m -f '{{.Version}}' github.com/sagernet/sing-box)
@@ -130,6 +130,9 @@ stdenv.mkDerivation (finalAttrs: {
ldflags = [
"-w"
"-s"
"-X"
"internal/godebug.defaultGODEBUG=multipathtcp=0"
"-checklinkname=0"
];
tags = [
@@ -140,10 +143,12 @@ stdenv.mkDerivation (finalAttrs: {
"with_utls"
"with_dhcp"
"with_tailscale"
"badlinkname"
"tfogo_checklinkname"
];
};
# this tricks nix-update into also updating the vendorHash of throne-core
# this tricks nix-update into also updating the vendorHash of passthru.core
passthru.goModules = finalAttrs.passthru.core.goModules;
meta = {