1
0
mirror of https://github.com/tw93/Mole.git synced 2026-02-04 15:39:42 +00:00

fix(windows): address code review security and reliability issues

- Add protection checks to Go analyze tool before delete operations
- Use try/finally to ensure Windows Update service restarts after cleanup
- Don't count interactive uninstall as automatic success
- Tighten orphaned app detection with stricter prefix matching
This commit is contained in:
Bhadra
2026-01-08 22:25:57 +05:30
parent 3255fa2451
commit 800db2429d
5 changed files with 98 additions and 21 deletions

View File

@@ -523,10 +523,10 @@ function Uninstall-SelectedApps {
}
if (-not $uninstalled) {
# Fallback to interactive
Write-Host " $esc[33m(launching uninstaller)$esc[0m"
# Fallback to interactive - don't count as automatic success
Write-Host " $esc[33m(launching uninstaller - verify completion manually)$esc[0m"
Start-Process -FilePath "cmd.exe" -ArgumentList "/c", "`"$uninstallString`"" -Wait
$successCount++
# Note: Not incrementing $successCount since we can't verify if user completed or cancelled
}
}
}

Binary file not shown.

View File

@@ -89,6 +89,59 @@ var skipPatterns = map[string]bool{
"Config.Msi": true,
}
// Protected paths that should NEVER be deleted
var protectedPaths = []string{
`C:\Windows`,
`C:\Program Files`,
`C:\Program Files (x86)`,
`C:\ProgramData`,
`C:\Users\Default`,
`C:\Users\Public`,
`C:\Recovery`,
`C:\System Volume Information`,
}
// isProtectedPath checks if a path is protected from deletion
func isProtectedPath(path string) bool {
absPath, err := filepath.Abs(path)
if err != nil {
return true // If we can't resolve the path, treat it as protected
}
absPath = strings.ToLower(absPath)
// Check against protected paths
for _, protected := range protectedPaths {
protectedLower := strings.ToLower(protected)
if absPath == protectedLower || strings.HasPrefix(absPath, protectedLower+`\`) {
return true
}
}
// Check against skip patterns (system directories)
baseName := strings.ToLower(filepath.Base(absPath))
for pattern := range skipPatterns {
if strings.ToLower(pattern) == baseName {
// Only protect if it's at a root level (e.g., C:\Windows, not C:\Projects\Windows)
parent := filepath.Dir(absPath)
if len(parent) <= 3 { // e.g., "C:\"
return true
}
}
}
// Protect Windows directory itself
winDir := strings.ToLower(os.Getenv("WINDIR"))
sysRoot := strings.ToLower(os.Getenv("SYSTEMROOT"))
if winDir != "" && (absPath == winDir || strings.HasPrefix(absPath, winDir+`\`)) {
return true
}
if sysRoot != "" && (absPath == sysRoot || strings.HasPrefix(absPath, sysRoot+`\`)) {
return true
}
return false
}
// Entry types
type dirEntry struct {
Name string
@@ -462,9 +515,17 @@ func (m model) scanPath(path string) tea.Cmd {
}
}
// deletePath deletes a file or directory
// deletePath deletes a file or directory with protection checks
func (m model) deletePath(path string) tea.Cmd {
return func() tea.Msg {
// Safety check: never delete protected paths
if isProtectedPath(path) {
return deleteCompleteMsg{
path: path,
err: fmt.Errorf("cannot delete protected system path: %s", path),
}
}
err := os.RemoveAll(path)
return deleteCompleteMsg{path: path, err: err}
}

View File

@@ -88,10 +88,23 @@ function Find-OrphanedAppData {
# Skip if recently modified
if ($folder.LastWriteTime -gt $cutoffDate) { continue }
# Check if app is installed
# Check if app is installed using stricter matching
# Require exact match or that folder name is a clear prefix/suffix of app name
$isInstalled = $false
$folderLower = $folder.Name.ToLower()
foreach ($name in $installedNames) {
if ($name -like "*$($folder.Name.ToLower())*" -or $folder.Name.ToLower() -like "*$name*") {
# Exact match
if ($name -eq $folderLower) {
$isInstalled = $true
break
}
# Folder is prefix of app name (e.g., "chrome" matches "chrome browser")
if ($name.StartsWith($folderLower) -and $folderLower.Length -ge 4) {
$isInstalled = $true
break
}
# App name is prefix of folder (e.g., "vscode" matches "vscode-data")
if ($folderLower.StartsWith($name) -and $name.Length -ge 4) {
$isInstalled = $true
break
}

View File

@@ -121,6 +121,7 @@ function Clear-WindowsUpdateFiles {
}
}
try {
# Clean download cache
$wuDownloadPath = "$env:WINDIR\SoftwareDistribution\Download"
if (Test-Path $wuDownloadPath) {
@@ -133,12 +134,14 @@ function Clear-WindowsUpdateFiles {
if (Test-Path $wuDataStore) {
Clear-DirectoryContents -Path $wuDataStore -Description "Windows Update logs"
}
# Restart service if it was running
}
finally {
# Always restart service if it was running, even if cleanup failed
if ($wasRunning) {
Start-Service -Name wuauserv -ErrorAction SilentlyContinue
}
}
}
# ============================================================================
# Installer Cleanup