Skip to content

Commit d5c6eca

Browse files
committed
fixes 21012026
redesign proxy tun switches fix aur build px-service fix systemproxy with px-service
1 parent 03bcdbe commit d5c6eca

File tree

19 files changed

+566
-113
lines changed

19 files changed

+566
-113
lines changed

.github/workflows/release.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,7 @@ jobs:
507507
install -Dm755 "\${srcdir}/prizrak-box.sh" "\${pkgdir}/usr/bin/\${pkgname%-bin}"
508508
install -Dm644 "\${srcdir}/app.asar" -t "\${pkgdir}/usr/lib/\${pkgname%-bin}"
509509
install -Dm755 "\${srcdir}/usr/lib/\${_pkgname}/resources/px" -t "\${pkgdir}/usr/lib/\${pkgname%-bin}"
510+
install -Dm755 "\${srcdir}/usr/lib/\${_pkgname}/resources/px-service" -t "\${pkgdir}/usr/lib/\${pkgname%-bin}"
510511
install -Dm644 "\${srcdir}/usr/share/pixmaps/\${_pkgname}.png" "\${pkgdir}/usr/share/pixmaps/\${pkgname%-bin}.png"
511512
install -Dm644 "\${srcdir}/usr/share/applications/\${_pkgname}.desktop" "\${pkgdir}/usr/share/applications/\${pkgname%-bin}.desktop"
512513
install -Dm644 "\${srcdir}/usr/share/doc/\${_pkgname}/copyright" "\${pkgdir}/usr/share/licenses/\${pkgname}/LICENSE"

src-electron/preload.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,16 @@ contextBridge.exposeInMainWorld('pxOs', () => {
4747
}
4848
});
4949

50+
// Получить имя текущего пользователя
51+
contextBridge.exposeInMainWorld('pxUsername', () => {
52+
try {
53+
return os.userInfo().username;
54+
} catch (e) {
55+
console.error('Failed to get username:', e);
56+
return '';
57+
}
58+
});
59+
5060
// 打开配置目录
5161
contextBridge.exposeInMainWorld('pxConfigDir', (url: string) => shell.openPath(url));
5262

src-go/api/handlers/pandora.go

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ func PrizrakRouter() chi.Router {
3131
r := chi.NewRouter()
3232
// 代理相关
3333
r.Put("/enableProxy", enableProxy)
34-
r.Get("/disableProxy", disableProxy)
34+
r.Put("/disableProxy", disableProxy)
3535

3636
// 地址相关
3737
r.Put("/checkAddressPort", checkAddressPort)
@@ -57,21 +57,60 @@ func enableProxy(w http.ResponseWriter, r *http.Request) {
5757
mi := struct {
5858
BindAddress string `json:"bindAddress"`
5959
Port int `json:"port"`
60+
Username string `json:"username"`
6061
}{}
6162
if err := render.DecodeJSON(r.Body, &mi); err != nil {
6263
ErrorResponse(w, r, err)
6364
return
6465
}
6566

66-
// 开启
67-
_ = sys.EnableProxy(mi.BindAddress, mi.Port)
67+
log.Infoln("EnableProxy request: bindAddress=", mi.BindAddress, ", port=", mi.Port, ", username=", mi.Username)
68+
69+
// 开启 - если указан username, используем EnableProxyForUser
70+
var err error
71+
if mi.Username != "" {
72+
log.Infoln("Enabling system proxy for user:", mi.Username)
73+
err = sys.EnableProxyForUser(mi.BindAddress, mi.Port, mi.Username)
74+
if err == nil {
75+
log.Infoln("System proxy successfully enabled for user", mi.Username)
76+
}
77+
} else {
78+
log.Infoln("Enabling system proxy for current user (no username provided)")
79+
err = sys.EnableProxy(mi.BindAddress, mi.Port)
80+
if err == nil {
81+
log.Infoln("System proxy successfully enabled")
82+
}
83+
}
84+
85+
if err != nil {
86+
log.Errorln("Failed to enable system proxy:", err)
87+
ErrorResponse(w, r, err)
88+
return
89+
}
6890

6991
render.NoContent(w, r)
7092
}
7193

7294
func disableProxy(w http.ResponseWriter, r *http.Request) {
73-
sys.DisableProxy()
74-
log.Warnln("System proxy disabled")
95+
// Читаем username из тела запроса
96+
mi := struct {
97+
Username string `json:"username"`
98+
}{}
99+
// Игнорируем ошибку чтения body - если body пустой, username будет пустым
100+
_ = render.DecodeJSON(r.Body, &mi)
101+
102+
log.Infoln("DisableProxy request: username=", mi.Username)
103+
104+
if mi.Username != "" {
105+
log.Infoln("Disabling system proxy for user:", mi.Username)
106+
sys.DisableProxyForUser(mi.Username)
107+
log.Infoln("System proxy successfully disabled for user", mi.Username)
108+
} else {
109+
log.Infoln("Disabling system proxy for current user (no username provided)")
110+
sys.DisableProxy()
111+
log.Infoln("System proxy successfully disabled")
112+
}
113+
75114
if !executor.GetGeneral().Tun.Enable {
76115
statistic.DefaultManager.Range(func(c statistic.Tracker) bool {
77116
_ = c.Close()

src-go/api/models/Mihomo.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ type Mihomo struct {
55
Proxy bool `json:"proxy"`
66
Tun bool `json:"tun"`
77

8-
Port int `json:"port"`
9-
BindAddress string `json:"bindAddress"`
10-
Stack string `json:"stack"`
11-
Dns bool `json:"dns"`
12-
Ipv6 bool `json:"ipv6"`
8+
Port int `json:"port"`
9+
BindAddress string `json:"bindAddress"`
10+
Stack string `json:"stack"`
11+
Dns bool `json:"dns"`
12+
Ipv6 bool `json:"ipv6"`
13+
SystemProxyMode bool `json:"systemProxyMode"`
14+
Username string `json:"username"` // Имя пользователя для системного прокси (для режима сервиса)
1315
}

src-go/internal/meta.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1115,9 +1115,13 @@ func startCore(profile models.Profile, profiles []models.Profile, reload bool) {
11151115
// 激活配置
11161116
go executor.ApplyConfig(NowConfig, !reload)
11171117

1118-
// 代理开启
1119-
if mi.Proxy {
1120-
_ = sysProxy.EnableProxy(mi.BindAddress, mi.Port)
1118+
// 代理开启 - включаем системный прокси только если включен режим системного прокси
1119+
if mi.Proxy && mi.SystemProxyMode {
1120+
if mi.Username != "" {
1121+
_ = sysProxy.EnableProxyForUser(mi.BindAddress, mi.Port, mi.Username)
1122+
} else {
1123+
_ = sysProxy.EnableProxy(mi.BindAddress, mi.Port)
1124+
}
11211125
}
11221126
// 存储配置
11231127
_ = cache.Put(constant.Mihomo, mi)

src-go/pkg/sys/cmd/cmd_darwin.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,9 @@ func Command(name string, arg ...string) (string, error) {
1414
}
1515
return strings.TrimSpace(string(out)), nil
1616
}
17+
18+
// CommandAsUser выполняет команду от имени указанного пользователя
19+
// На macOS username игнорируется, так как networksetup автоматически работает с текущим пользователем
20+
func CommandAsUser(username string, name string, arg ...string) (string, error) {
21+
return Command(name, arg...)
22+
}

src-go/pkg/sys/cmd/cmd_linux.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ package sys
22

33
import (
44
"fmt"
5+
"os"
56
"os/exec"
7+
"os/user"
8+
"strconv"
69
"strings"
710
)
811

@@ -14,3 +17,76 @@ func Command(name string, arg ...string) (string, error) {
1417
}
1518
return strings.TrimSpace(string(out)), nil
1619
}
20+
21+
// CommandAsUser выполняет команду от имени указанного пользователя
22+
// Используется для установки системного прокси для конкретного пользователя
23+
func CommandAsUser(username string, name string, arg ...string) (string, error) {
24+
// Если username пустой или текущий пользователь уже нужный, выполняем напрямую
25+
if username == "" {
26+
return Command(name, arg...)
27+
}
28+
29+
currentUser, err := user.Current()
30+
if err == nil && currentUser.Username == username {
31+
return Command(name, arg...)
32+
}
33+
34+
// Получаем информацию о пользователе
35+
targetUser, err := user.Lookup(username)
36+
if err != nil {
37+
return "", fmt.Errorf("user %q not found: %w", username, err)
38+
}
39+
40+
// Получаем UID пользователя для запуска D-Bus сессии
41+
uid, err := strconv.Atoi(targetUser.Uid)
42+
if err != nil {
43+
return "", fmt.Errorf("invalid UID for user %q: %w", username, err)
44+
}
45+
46+
// Определяем DBUS_SESSION_BUS_ADDRESS для пользователя
47+
// Обычно это unix:path=/run/user/{UID}/bus
48+
dbusAddr := fmt.Sprintf("unix:path=/run/user/%d/bus", uid)
49+
50+
// Пробуем использовать runuser (не требует пароля от root) или sudo
51+
// runuser доступен по умолчанию в большинстве дистрибутивов
52+
var cmdName string
53+
var cmdArgs []string
54+
55+
// Проверяем, запущены ли мы от root
56+
if currentUser != nil && (currentUser.Username == "root" || currentUser.Uid == "0") {
57+
// От root используем runuser (не требует пароля)
58+
cmdName = "runuser"
59+
cmdArgs = []string{
60+
"-u", username,
61+
"--",
62+
"env",
63+
"DBUS_SESSION_BUS_ADDRESS=" + dbusAddr,
64+
"HOME=" + targetUser.HomeDir,
65+
"USER=" + username,
66+
name,
67+
}
68+
} else {
69+
// Не от root - используем sudo с -n (может потребовать настройки sudoers)
70+
cmdName = "sudo"
71+
cmdArgs = []string{
72+
"-n", // non-interactive mode
73+
"-u", username,
74+
"env",
75+
"DBUS_SESSION_BUS_ADDRESS=" + dbusAddr,
76+
"HOME=" + targetUser.HomeDir,
77+
"USER=" + username,
78+
name,
79+
}
80+
}
81+
82+
cmdArgs = append(cmdArgs, arg...)
83+
84+
c := exec.Command(cmdName, cmdArgs...)
85+
// Наследуем переменные окружения
86+
c.Env = os.Environ()
87+
out, err := c.CombinedOutput()
88+
if err != nil {
89+
return "", fmt.Errorf("%s as %q: %w: %q", strings.Join(append([]string{cmdName, "-u", username, name}, arg...), " "), username, err, out)
90+
}
91+
return strings.TrimSpace(string(out)), nil
92+
}

src-go/pkg/sys/cmd/cmd_windows.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,9 @@ func Command(name string, arg ...string) (string, error) {
1616
}
1717
return strings.TrimSpace(string(out)), nil
1818
}
19+
20+
// CommandAsUser выполняет команду от имени указанного пользователя
21+
// На Windows username игнорируется, так как реестр автоматически работает с текущим пользователем
22+
func CommandAsUser(username string, name string, arg ...string) (string, error) {
23+
return Command(name, arg...)
24+
}

src-go/pkg/sys/proxy/proxy.go

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,33 @@ package sys
22

33
// EnableProxy 开启系统代理
44
func EnableProxy(host string, port int) error {
5-
_ = OnHttp(Addr{
5+
return EnableProxyForUser(host, port, "")
6+
}
7+
8+
// DisableProxy 关闭代理
9+
func DisableProxy() {
10+
DisableProxyForUser("")
11+
}
12+
13+
// EnableProxyForUser 为指定用户开启系统代理
14+
func EnableProxyForUser(host string, port int, username string) error {
15+
_ = OnHttpForUser(Addr{
616
Host: host,
717
Port: port,
8-
})
9-
_ = OnHttps(Addr{
18+
}, username)
19+
_ = OnHttpsForUser(Addr{
1020
Host: host,
1121
Port: port,
12-
})
13-
_ = OnSocks(Addr{
22+
}, username)
23+
_ = OnSocksForUser(Addr{
1424
Host: host,
1525
Port: port,
16-
})
26+
}, username)
1727

1828
return nil
1929
}
2030

21-
// DisableProxy 关闭代理
22-
func DisableProxy() {
23-
_ = OffAll()
31+
// DisableProxyForUser 为指定用户关闭代理
32+
func DisableProxyForUser(username string) {
33+
_ = OffAllForUser(username)
2434
}

src-go/pkg/sys/proxy/proxy_darwin.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ import (
1313
)
1414

1515
func OffAll() error {
16+
return OffAllForUser("")
17+
}
18+
19+
func OffAllForUser(username string) error {
20+
// На macOS username игнорируется, так как networksetup работает для текущего пользователя
1621
if err := OffHttps(); err != nil {
1722
return err
1823
}
@@ -59,6 +64,11 @@ func GetIgnore() ([]string, error) {
5964
}
6065

6166
func OnHttps(addr Addr) error {
67+
return OnHttpsForUser(addr, "")
68+
}
69+
70+
func OnHttpsForUser(addr Addr, username string) error {
71+
// На macOS username игнорируется
6272
s, err := getNetworkInterface()
6373
if err != nil {
6474
return err
@@ -75,6 +85,11 @@ func OnHttps(addr Addr) error {
7585
}
7686

7787
func OffHttps() error {
88+
return OffHttpsForUser("")
89+
}
90+
91+
func OffHttpsForUser(username string) error {
92+
// На macOS username игнорируется
7893
s, err := getNetworkInterface()
7994
if err != nil {
8095
return err
@@ -107,6 +122,11 @@ func GetHttps() (*Addr, error) {
107122
}
108123

109124
func OnHttp(addr Addr) error {
125+
return OnHttpForUser(addr, "")
126+
}
127+
128+
func OnHttpForUser(addr Addr, username string) error {
129+
// На macOS username игнорируется
110130
s, err := getNetworkInterface()
111131
if err != nil {
112132
return err
@@ -123,6 +143,11 @@ func OnHttp(addr Addr) error {
123143
}
124144

125145
func OffHttp() error {
146+
return OffHttpForUser("")
147+
}
148+
149+
func OffHttpForUser(username string) error {
150+
// На macOS username игнорируется
126151
s, err := getNetworkInterface()
127152
if err != nil {
128153
return err
@@ -155,6 +180,11 @@ func GetHttp() (*Addr, error) {
155180
}
156181

157182
func OnSocks(addr Addr) error {
183+
return OnSocksForUser(addr, "")
184+
}
185+
186+
func OnSocksForUser(addr Addr, username string) error {
187+
// На macOS username игнорируется
158188
s, err := getNetworkInterface()
159189
if err != nil {
160190
return err
@@ -171,6 +201,11 @@ func OnSocks(addr Addr) error {
171201
}
172202

173203
func OffSocks() error {
204+
return OffSocksForUser("")
205+
}
206+
207+
func OffSocksForUser(username string) error {
208+
// На macOS username игнорируется
174209
s, err := getNetworkInterface()
175210
if err != nil {
176211
return err

0 commit comments

Comments
 (0)