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) <noreply@anthropic.com>
This commit is contained in:
jim800121chen 2026-03-26 09:31:58 +08:00
parent dc896bea4f
commit d9d5b2e4e0

View File

@ -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 {