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:
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BIN
windows/cmd/analyze/analyze.exe
Normal file
BIN
windows/cmd/analyze/analyze.exe
Normal file
Binary file not shown.
@@ -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}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user