From d9d5b2e4e08dacf2183eee485d0d6eea4f8163df Mon Sep 17 00:00:00 2001 From: jim800121chen Date: Thu, 26 Mar 2026 09:31:58 +0800 Subject: [PATCH] fix: elevate WinUSB driver install via UAC with clear error messages Previously the WinUSB driver installation silently failed because it needed admin privileges. Now: - All admin operations (cert creation, certutil, pnputil) run in a single elevated PowerShell script via Start-Process -Verb RunAs, triggering one UAC prompt - If the user declines UAC, a clear error message is shown with instructions to use Zadig as a manual fallback - If driver files are not bundled, error explains what to do - installLibusb now propagates the error instead of swallowing it Co-Authored-By: Claude Opus 4.6 (1M context) --- .../installer/platform_windows.go | 79 +++++++++++++------ 1 file changed, 55 insertions(+), 24 deletions(-) diff --git a/edge-ai-platform/installer/platform_windows.go b/edge-ai-platform/installer/platform_windows.go index ed498a1..e616e74 100644 --- a/edge-ai-platform/installer/platform_windows.go +++ b/edge-ai-platform/installer/platform_windows.go @@ -130,15 +130,18 @@ func installLibusb(installDir string) error { } // 2. Extract and install WinUSB driver for Kneron devices - installWinUSBDriver(installDir) + if err := installWinUSBDriver(installDir); err != nil { + return err + } return nil } // installWinUSBDriver extracts the WinUSB driver INF and co-installer files -// from the payload, then creates a self-signed certificate, installs it to the -// TrustedPublisher store, and uses pnputil to install the driver. -func installWinUSBDriver(installDir string) { +// from the payload, then runs an elevated PowerShell script (UAC prompt) to +// create a self-signed certificate, install it, and register the driver. +// Returns an error message if it fails (non-fatal, caller decides). +func installWinUSBDriver(installDir string) error { driverDir := filepath.Join(installDir, "drivers") os.MkdirAll(filepath.Join(driverDir, "amd64"), 0755) @@ -152,39 +155,67 @@ func installWinUSBDriver(installDir string) { for src, dst := range driverFiles { data, err := payloadFS.ReadFile(src) if err != nil { - return // driver files not bundled, skip + return fmt.Errorf("WinUSB driver files not bundled in installer — please install WinUSB driver manually using Zadig (https://zadig.akeo.ie/)") } if err := os.WriteFile(dst, data, 0644); err != nil { - return + return fmt.Errorf("failed to extract driver file: %w", err) } } infPath := filepath.Join(driverDir, "kneron_winusb.inf") certPath := filepath.Join(driverDir, "kneron_selfsign.cer") - // Step 1: Create self-signed code signing certificate via PowerShell - psCreateCert := fmt.Sprintf(` + // Run all admin operations in a single elevated PowerShell script (one UAC prompt) + psScript := fmt.Sprintf(` $ErrorActionPreference = 'Stop' -Get-ChildItem Cert:\LocalMachine\My | Where-Object { $_.Subject -eq 'CN=Kneron Edge AI Platform' } | Remove-Item -Force -ErrorAction SilentlyContinue -$cert = New-SelfSignedCertificate -Type CodeSigningCert -Subject "CN=Kneron Edge AI Platform" -CertStoreLocation Cert:\LocalMachine\My -NotAfter (Get-Date).AddYears(10) -Export-Certificate -Cert $cert -FilePath '%s' -Force | Out-Null -Write-Output $cert.Thumbprint -`, certPath) +try { + # Step 1: Create self-signed code signing certificate + Get-ChildItem Cert:\LocalMachine\My | Where-Object { $_.Subject -eq 'CN=Kneron Edge AI Platform' } | Remove-Item -Force -ErrorAction SilentlyContinue + $cert = New-SelfSignedCertificate -Type CodeSigningCert -Subject "CN=Kneron Edge AI Platform" -CertStoreLocation Cert:\LocalMachine\My -NotAfter (Get-Date).AddYears(10) + Export-Certificate -Cert $cert -FilePath '%s' -Force | Out-Null - cmd := exec.Command("powershell", "-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", psCreateCert) - if _, err := cmd.CombinedOutput(); err != nil { - return // non-fatal + # Step 2: Install certificate to TrustedPublisher and Root stores + certutil -addstore TrustedPublisher '%s' | Out-Null + certutil -addstore Root '%s' | Out-Null + + # Step 3: Install driver via pnputil + pnputil /add-driver '%s' /install + + # Cleanup + Remove-Item -Path '%s' -Force -ErrorAction SilentlyContinue + + Write-Output 'SUCCESS' +} catch { + Write-Output "FAILED: $_" + exit 1 +} +`, certPath, certPath, certPath, infPath, certPath) + + // Use Start-Process -Verb RunAs to trigger UAC elevation + // Write the script to a temp file so it can be executed elevated + scriptPath := filepath.Join(os.TempDir(), "edge-ai-install-driver.ps1") + resultPath := filepath.Join(os.TempDir(), "edge-ai-driver-result.txt") + os.Remove(resultPath) + + if err := os.WriteFile(scriptPath, []byte(psScript), 0644); err != nil { + return fmt.Errorf("failed to write driver install script: %w", err) + } + defer os.Remove(scriptPath) + + // Launch elevated PowerShell and wait for completion + elevateCmd := fmt.Sprintf( + `Start-Process -FilePath powershell -ArgumentList '-NoProfile','-ExecutionPolicy','Bypass','-File','%s' -Verb RunAs -Wait -WindowStyle Hidden`, + scriptPath, + ) + cmd := exec.Command("powershell", "-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", elevateCmd) + if out, err := cmd.CombinedOutput(); err != nil { + return fmt.Errorf("WinUSB driver installation requires administrator permission. If you declined the prompt, please install the driver manually using Zadig (https://zadig.akeo.ie/). Details: %s", string(out)) } - // Step 2: Install certificate to TrustedPublisher and Root stores - exec.Command("certutil", "-addstore", "TrustedPublisher", certPath).Run() - exec.Command("certutil", "-addstore", "Root", certPath).Run() - - // Step 3: Install driver via pnputil (cert in TrustedPublisher allows unsigned INF) - exec.Command("pnputil", "/add-driver", infPath, "/install").Run() - - // Cleanup temp cert file + // Cleanup os.Remove(certPath) + + return nil } func checkLibusbInstalled() bool {