From 1cb22964809024d6ac3a3e3ba52c65aa5f12d86f Mon Sep 17 00:00:00 2001 From: Elias Fierke Date: Sun, 27 Sep 2026 16:30:02 +0200 Subject: [PATCH] windowss architecture is shitty --- main.go | 9 ++ platform_linux.go | 4 + platform_windows.go | 204 +++++++++++++++++++++----------------------- 3 files changed, 111 insertions(+), 106 deletions(-) diff --git a/main.go b/main.go index 100d053..f58c2bf 100644 --- a/main.go +++ b/main.go @@ -47,8 +47,17 @@ func main() { Repo: envOrDefault("GITEA_REPO", defaultRepo), } + if err := platformEnsureElevated(); err != nil { + printError(err) + os.Exit(1) + } + args := os.Args[1:] + if len(args) > 0 && args[0] == "--elevated" { + args = args[1:] + } + if len(args) == 0 { runTUI(config) return diff --git a/platform_linux.go b/platform_linux.go index f416c3b..68ca2f8 100644 --- a/platform_linux.go +++ b/platform_linux.go @@ -13,6 +13,10 @@ func getInstallDir() (string, error) { return "/opt/logofclient", nil } +func platformEnsureElevated() error { + return nil +} + func platformRunPrivileged(config Config, action string) error { // Bereits als root gestartet. if os.Geteuid() == 0 { diff --git a/platform_windows.go b/platform_windows.go index f68048d..09021e7 100644 --- a/platform_windows.go +++ b/platform_windows.go @@ -20,18 +20,17 @@ var ( openProcessToken = advapi32.NewProc("OpenProcessToken") getTokenInformation = advapi32.NewProc("GetTokenInformation") - kernel32 = syscall.NewLazyDLL("kernel32.dll") - closeHandle = kernel32.NewProc("CloseHandle") - waitForSingleObject = kernel32.NewProc("WaitForSingleObject") + kernel32 = syscall.NewLazyDLL("kernel32.dll") + closeHandle = kernel32.NewProc("CloseHandle") ) const ( - tokenQuery = 0x0008 - tokenElevationClass = 20 - seeMaskNoCloseProcess = 0x00000040 - swShow = 1 - infinite = 0xFFFFFFFF - errorCancelled = 1223 + tokenQuery = 0x0008 + tokenElevationClass = 20 + + errorCancelled = 1223 + + swShow = 1 ) type shellExecuteInfo struct { @@ -56,46 +55,94 @@ type tokenElevationData struct { TokenIsElevated uint32 } -func getInstallDir() (string, error) { - programFiles := os.Getenv("ProgramFiles") - - if programFiles == "" { - return "", errors.New("ProgramFiles ist nicht gesetzt") - } - - return filepath.Join(programFiles, "logofclient"), nil -} - -func platformRunPrivileged(config Config, action string) error { - if isWindowsElevated() { - return runAction(config, action) - } - - fmt.Println() - fmt.Println("Für diese Aktion werden Administratorrechte benötigt.") - fmt.Print("Jetzt Administratorrechte anfordern? [J/n]: ") - - var answer string - if _, err := fmt.Scanln(&answer); err != nil { - // Enter ohne Eingabe = Ja - answer = "" - } - - answer = strings.ToLower(strings.TrimSpace(answer)) - - if answer != "" && answer != "j" && answer != "ja" { - fmt.Println("Abgebrochen.") +func platformEnsureElevated() error { + // Die erhöhte Instanz wurde bereits gestartet. + // Sie darf sich nicht noch einmal selbst per runas starten. + if hasElevatedFlag() { return nil } - return runElevated(action) + if isWindowsElevated() { + return nil + } + + return restartElevated() +} + +func hasElevatedFlag() bool { + for _, arg := range os.Args[1:] { + if arg == "--elevated" { + return true + } + } + + return false +} + +func restartElevated() error { + exe, err := os.Executable() + if err != nil { + return fmt.Errorf( + "Pfad des Installers konnte nicht ermittelt werden: %w", + err, + ) + } + + verb, err := syscall.UTF16PtrFromString("runas") + if err != nil { + return err + } + + file, err := syscall.UTF16PtrFromString(exe) + if err != nil { + return err + } + + // Die erhöhte Instanz bekommt nur das interne Flag. + parameters, err := syscall.UTF16PtrFromString("--elevated") + if err != nil { + return err + } + + info := shellExecuteInfo{ + cbSize: uint32(unsafe.Sizeof(shellExecuteInfo{})), + lpVerb: verb, + lpFile: file, + lpParameters: parameters, + nShow: swShow, + } + + ret, _, callErr := shellExecuteExW.Call( + uintptr(unsafe.Pointer(&info)), + ) + + if ret == 0 { + if errno, ok := callErr.(syscall.Errno); ok && + errno == errorCancelled { + fmt.Println("Administratorrechte wurden nicht erteilt.") + return errors.New("Administratorrechte erforderlich") + } + + return fmt.Errorf( + "Administratorrechte konnten nicht angefordert werden: %w", + callErr, + ) + } + + // WICHTIG: + // Die ursprüngliche Instanz beendet sich sofort. + // Nur die erhöhte Instanz führt danach main() weiter aus. + os.Exit(0) + + return nil } func isWindowsElevated() bool { var token uintptr + // GetCurrentProcess() = -1 ret, _, _ := openProcessToken.Call( - uintptr(^uint(0)>>1), + uintptr(^uint(0)), tokenQuery, uintptr(unsafe.Pointer(&token)), ) @@ -124,72 +171,17 @@ func isWindowsElevated() bool { return elevation.TokenIsElevated != 0 } -func runElevated(action string) error { - exe, err := os.Executable() - if err != nil { - return fmt.Errorf( - "Pfad des Installers konnte nicht ermittelt werden: %w", - err, - ) +func platformRunPrivileged(config Config, action string) error { + // Die komplette Windows-Anwendung läuft bereits erhöht. + return runAction(config, action) +} + +func getInstallDir() (string, error) { + programFiles := os.Getenv("ProgramFiles") + + if programFiles == "" { + return "", errors.New("ProgramFiles ist nicht gesetzt") } - verb, err := syscall.UTF16PtrFromString("runas") - if err != nil { - return err - } - - file, err := syscall.UTF16PtrFromString(exe) - if err != nil { - return err - } - - parameters, err := syscall.UTF16PtrFromString(action) - if err != nil { - return err - } - - info := shellExecuteInfo{ - cbSize: uint32(unsafe.Sizeof(shellExecuteInfo{})), - fMask: seeMaskNoCloseProcess, - lpVerb: verb, - lpFile: file, - lpParameters: parameters, - nShow: swShow, - } - - ret, _, callErr := shellExecuteExW.Call( - uintptr(unsafe.Pointer(&info)), - ) - - if ret == 0 { - if errno, ok := callErr.(syscall.Errno); ok && - errno == errorCancelled { - fmt.Println("Administratorrechte wurden nicht erteilt.") - return nil - } - - return fmt.Errorf( - "Administratorrechte konnten nicht angefordert werden: %w", - callErr, - ) - } - - if info.hProcess != 0 { - handle := syscall.Handle(info.hProcess) - defer syscall.CloseHandle(handle) - - ret, _, err := waitForSingleObject.Call( - uintptr(handle), - infinite, - ) - - if ret == 0xFFFFFFFF { - return fmt.Errorf( - "auf erhöhte Instanz konnte nicht gewartet werden: %w", - err, - ) - } - } - - return nil + return filepath.Join(programFiles, "logofclient"), nil } \ No newline at end of file