feat(admin): add platform-specific admin privilege checks
- Upgrade Go version from 1.21 to 1.25.0 - Update golang.org/x/sys dependency to v0.42.0 - Add Unix/Linux admin check using os.Geteuid() with sudo requirement - Add Windows admin check using windows.SID and token membership validation - Integrate admin privilege validation into main CLI entry point - Enhance monitor.go with graceful signal handling for Ctrl+C interrupts - Add signal channels for clean shutdown of monitoring loop - Ensures VPN client runs with required elevated privileges on both platforms
This commit is contained in:
4
go.mod
4
go.mod
@@ -1,11 +1,11 @@
|
||||
module vpn-client
|
||||
|
||||
go 1.21
|
||||
go 1.25.0
|
||||
|
||||
require github.com/fatih/color v1.16.0
|
||||
|
||||
require (
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
golang.org/x/sys v0.16.0 // indirect
|
||||
golang.org/x/sys v0.42.0 // indirect
|
||||
)
|
||||
|
||||
2
go.sum
2
go.sum
@@ -9,3 +9,5 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
|
||||
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
|
||||
29
internal/admin/admin_unix.go
Normal file
29
internal/admin/admin_unix.go
Normal file
@@ -0,0 +1,29 @@
|
||||
// +build !windows
|
||||
|
||||
package admin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
// IsAdmin проверяет, запущено ли приложение с правами root
|
||||
func IsAdmin() bool {
|
||||
return os.Geteuid() == 0
|
||||
}
|
||||
|
||||
// RequireAdmin проверяет права root и завершает программу, если их нет
|
||||
func RequireAdmin() {
|
||||
if !IsAdmin() {
|
||||
fmt.Println("╔════════════════════════════════════════════════════════════╗")
|
||||
fmt.Println("║ ⚠ ТРЕБУЮТСЯ ПРАВА ROOT ║")
|
||||
fmt.Println("╚════════════════════════════════════════════════════════════╝")
|
||||
fmt.Println()
|
||||
fmt.Println("Это приложение требует прав root для работы с VPN.")
|
||||
fmt.Println()
|
||||
fmt.Println("Пожалуйста, запустите приложение с sudo:")
|
||||
fmt.Println(" sudo ./vpn-client-cli")
|
||||
fmt.Println()
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
57
internal/admin/admin_windows.go
Normal file
57
internal/admin/admin_windows.go
Normal file
@@ -0,0 +1,57 @@
|
||||
// +build windows
|
||||
|
||||
package admin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
// IsAdmin проверяет, запущено ли приложение с правами администратора
|
||||
func IsAdmin() bool {
|
||||
var sid *windows.SID
|
||||
|
||||
// Получаем SID группы администраторов
|
||||
err := windows.AllocateAndInitializeSid(
|
||||
&windows.SECURITY_NT_AUTHORITY,
|
||||
2,
|
||||
windows.SECURITY_BUILTIN_DOMAIN_RID,
|
||||
windows.DOMAIN_ALIAS_RID_ADMINS,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
&sid)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
defer windows.FreeSid(sid)
|
||||
|
||||
// Получаем текущий токен процесса
|
||||
token := windows.Token(0)
|
||||
|
||||
// Проверяем членство в группе
|
||||
member, err := token.IsMember(sid)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return member
|
||||
}
|
||||
|
||||
// RequireAdmin проверяет права администратора и завершает программу, если их нет
|
||||
func RequireAdmin() {
|
||||
if !IsAdmin() {
|
||||
fmt.Println("╔════════════════════════════════════════════════════════════╗")
|
||||
fmt.Println("║ ⚠ ТРЕБУЮТСЯ ПРАВА АДМИНИСТРАТОРА ║")
|
||||
fmt.Println("╚════════════════════════════════════════════════════════════╝")
|
||||
fmt.Println()
|
||||
fmt.Println("Это приложение требует прав администратора для работы с VPN.")
|
||||
fmt.Println()
|
||||
fmt.Println("Пожалуйста, запустите приложение от имени администратора:")
|
||||
fmt.Println(" 1. Щелкните правой кнопкой мыши на vpn-client-cli.exe")
|
||||
fmt.Println(" 2. Выберите 'Запуск от имени администратора'")
|
||||
fmt.Println()
|
||||
fmt.Println("Нажмите Enter для выхода...")
|
||||
fmt.Scanln()
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,9 @@ package cli
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"vpn-client/internal/config"
|
||||
@@ -26,6 +28,19 @@ func MonitorConnection() error {
|
||||
fmt.Println("Нажмите Ctrl+C для выхода из мониторинга\n")
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
// Создаем канал для обработки сигналов
|
||||
sigChan := make(chan os.Signal, 1)
|
||||
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)
|
||||
|
||||
// Создаем канал для остановки мониторинга
|
||||
stopChan := make(chan bool, 1)
|
||||
|
||||
// Запускаем горутину для обработки сигналов
|
||||
go func() {
|
||||
<-sigChan
|
||||
stopChan <- true
|
||||
}()
|
||||
|
||||
// Запускаем мониторинг
|
||||
ticker := time.NewTicker(1 * time.Second)
|
||||
defer ticker.Stop()
|
||||
@@ -35,6 +50,12 @@ func MonitorConnection() error {
|
||||
case <-ticker.C:
|
||||
clearScreen()
|
||||
displayRealtimeStatus(state)
|
||||
case <-stopChan:
|
||||
// Восстанавливаем обработку сигналов по умолчанию
|
||||
signal.Reset(os.Interrupt, syscall.SIGTERM)
|
||||
fmt.Println("\n\nВыход из мониторинга...")
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,11 +4,15 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"vpn-client/internal/admin"
|
||||
"vpn-client/internal/cli"
|
||||
"vpn-client/internal/config"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Проверка прав администратора
|
||||
admin.RequireAdmin()
|
||||
|
||||
// Инициализация конфигурации
|
||||
if err := config.Init(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Ошибка инициализации: %v\n", err)
|
||||
|
||||
Reference in New Issue
Block a user