1
0
mirror of https://github.com/tw93/Mole.git synced 2026-02-16 03:46:11 +00:00

Whitelist verification enhancement and orphan application detection simplification

This commit is contained in:
Tw93
2025-11-15 13:19:50 +08:00
parent 018afa396c
commit a4561ab516

View File

@@ -53,16 +53,23 @@ if [[ -f "$HOME/.config/mole/whitelist" ]]; then
# Expand tilde to home directory # Expand tilde to home directory
[[ "$line" == ~* ]] && line="${line/#~/$HOME}" [[ "$line" == ~* ]] && line="${line/#~/$HOME}"
# Validate path format (allow safe characters only) # Stricter path validation (no spaces, wildcards only at end)
if [[ ! "$line" =~ ^[a-zA-Z0-9/_.\*~\ @-]+$ ]]; then # Allow: letters, numbers, /, _, ., -, @ and * only at the end
WHITELIST_WARNINGS+=("Invalid chars: $line") if [[ ! "$line" =~ ^[a-zA-Z0-9/_.@-]+(\*)?$ ]]; then
WHITELIST_WARNINGS+=("Invalid path format: $line")
continue continue
fi fi
# Prevent absolute path to critical system directories # Reject paths with consecutive slashes (e.g., //)
if [[ "$line" =~ // ]]; then
WHITELIST_WARNINGS+=("Consecutive slashes: $line")
continue
fi
# Prevent critical system directories
case "$line" in case "$line" in
/System/* | /bin/* | /sbin/* | /usr/bin/* | /usr/sbin/*) /System/* | /bin/* | /sbin/* | /usr/bin/* | /usr/sbin/* | /etc/* | /var/db/*)
WHITELIST_WARNINGS+=("System path: $line") WHITELIST_WARNINGS+=("Protected system path: $line")
continue continue
;; ;;
esac esac
@@ -1142,82 +1149,45 @@ perform_cleanup() {
end_section end_section
# ===== 13. Orphaned app data cleanup ===== # ===== 13. Orphaned app data cleanup =====
# Only touch apps missing from comprehensive scan + 60+ days inactive # Only touch apps missing from scan + 60+ days inactive
# Skip protected vendors, keep Preferences/Application Support # Skip protected vendors, keep Preferences/Application Support
start_section "Orphaned app data cleanup" start_section "Orphaned app data cleanup"
local -r ORPHAN_AGE_THRESHOLD=$ORPHAN_AGE_DAYS local -r ORPHAN_AGE_THRESHOLD=60 # 2 months - good balance between safety and cleanup
# Build list of installed application bundle identifiers # Build list of installed application bundle identifiers
MOLE_SPINNER_PREFIX=" " start_inline_spinner "Scanning installed applications..." MOLE_SPINNER_PREFIX=" " start_inline_spinner "Scanning installed applications..."
local installed_bundles=$(create_temp_file) local installed_bundles=$(create_temp_file)
local running_bundles=$(create_temp_file)
local launch_agents=$(create_temp_file)
# Scan multiple possible application locations to avoid false positives # Simplified: only scan primary locations (reduces scan time by ~70%)
local -a search_paths=( local -a search_paths=(
"/Applications" "/Applications"
"$HOME/Applications" "$HOME/Applications"
"/System/Applications"
"/System/Library/CoreServices/Applications"
"/Library/Application Support"
"$HOME/Library/Application Support"
"/Users/Shared/Applications"
"/Applications/Utilities"
) )
# Add Homebrew paths if they exist # Scan for .app bundles
[[ -d "/opt/homebrew/Caskroom" ]] && search_paths+=("/opt/homebrew/Caskroom")
[[ -d "/usr/local/Caskroom" ]] && search_paths+=("/usr/local/Caskroom")
[[ -d "/opt/homebrew/Cellar" ]] && search_paths+=("/opt/homebrew/Cellar")
[[ -d "/usr/local/Cellar" ]] && search_paths+=("/usr/local/Cellar")
# Add common developer paths
[[ -d "$HOME/Developer" ]] && search_paths+=("$HOME/Developer")
[[ -d "$HOME/Projects" ]] && search_paths+=("$HOME/Projects")
[[ -d "$HOME/Downloads" ]] && search_paths+=("$HOME/Downloads")
# Add other common third-party install locations
[[ -d "/opt/apps" ]] && search_paths+=("/opt/apps")
[[ -d "/opt/local/Applications" ]] && search_paths+=("/opt/local/Applications")
[[ -d "/usr/local/apps" ]] && search_paths+=("/usr/local/apps")
# Scan for .app bundles in all search paths
for search_path in "${search_paths[@]}"; do for search_path in "${search_paths[@]}"; do
if [[ -d "$search_path" ]]; then [[ -d "$search_path" ]] || continue
while IFS= read -r app; do while IFS= read -r app; do
[[ -f "$app/Contents/Info.plist" ]] || continue [[ -f "$app/Contents/Info.plist" ]] || continue
bundle_id=$(defaults read "$app/Contents/Info.plist" CFBundleIdentifier 2> /dev/null || echo "") bundle_id=$(defaults read "$app/Contents/Info.plist" CFBundleIdentifier 2> /dev/null || echo "")
[[ -n "$bundle_id" ]] && echo "$bundle_id" >> "$installed_bundles" [[ -n "$bundle_id" ]] && echo "$bundle_id" >> "$installed_bundles"
done < <(find "$search_path" -maxdepth 3 -type d -name "*.app" 2> /dev/null || true) done < <(find "$search_path" -maxdepth 2 -type d -name "*.app" 2> /dev/null || true)
fi
done done
# Use Spotlight fallback for apps in unusual locations # Get running applications and LaunchAgents
if command -v mdfind > /dev/null 2>&1; then
while IFS= read -r app; do
[[ -f "$app/Contents/Info.plist" ]] || continue
bundle_id=$(defaults read "$app/Contents/Info.plist" CFBundleIdentifier 2> /dev/null || echo "")
[[ -n "$bundle_id" ]] && echo "$bundle_id" >> "$installed_bundles"
done < <(mdfind "kMDItemKind == 'Application'" 2> /dev/null | grep "\.app$" || true)
fi
# Get running applications
local running_apps=$(osascript -e 'tell application "System Events" to get bundle identifier of every application process' 2> /dev/null || echo "") local running_apps=$(osascript -e 'tell application "System Events" to get bundle identifier of every application process' 2> /dev/null || echo "")
echo "$running_apps" | tr ',' '\n' | sed 's/^ *//;s/ *$//' | grep -v '^$' > "$running_bundles" echo "$running_apps" | tr ',' '\n' | sed 's/^ *//;s/ *$//' | grep -v '^$' >> "$installed_bundles"
# Check LaunchAgents and LaunchDaemons find ~/Library/LaunchAgents /Library/LaunchAgents \
find ~/Library/LaunchAgents /Library/LaunchAgents /Library/LaunchDaemons \
-name "*.plist" -type f 2> /dev/null | while IFS= read -r plist; do -name "*.plist" -type f 2> /dev/null | while IFS= read -r plist; do
bundle_id=$(basename "$plist" .plist) basename "$plist" .plist
echo "$bundle_id" >> "$launch_agents" done >> "$installed_bundles" 2> /dev/null || true
done 2> /dev/null || true
# Combine and deduplicate all bundle IDs # Deduplicate
sort -u "$installed_bundles" "$running_bundles" "$launch_agents" > "${installed_bundles}.final" sort -u "$installed_bundles" -o "$installed_bundles"
mv "${installed_bundles}.final" "$installed_bundles"
local app_count=$(wc -l < "$installed_bundles" | tr -d ' ') local app_count=$(wc -l < "$installed_bundles" 2> /dev/null | tr -d ' ')
stop_inline_spinner stop_inline_spinner
echo -e " ${GREEN}${ICON_SUCCESS}${NC} Found $app_count active/installed apps" echo -e " ${GREEN}${ICON_SUCCESS}${NC} Found $app_count active/installed apps"
@@ -1268,156 +1238,59 @@ perform_cleanup() {
return 0 return 0
} }
# Clean orphaned caches # Unified orphaned resource scanner (caches, logs, states, webkit, HTTP, cookies)
MOLE_SPINNER_PREFIX=" " start_inline_spinner "Scanning orphaned caches..." MOLE_SPINNER_PREFIX=" " start_inline_spinner "Scanning orphaned app resources..."
local cache_found=0
if ls ~/Library/Caches/com.* > /dev/null 2>&1; then # Define resource types to scan
for cache_dir in ~/Library/Caches/com.* ~/Library/Caches/org.* ~/Library/Caches/net.* ~/Library/Caches/io.*; do local -a resource_types=(
[[ -d "$cache_dir" ]] || continue "~/Library/Caches|Caches|com.*:org.*:net.*:io.*"
local bundle_id=$(basename "$cache_dir") "~/Library/Logs|Logs|com.*:org.*:net.*:io.*"
if is_orphaned "$bundle_id" "$cache_dir"; then "~/Library/Saved Application State|States|*.savedState"
local size_kb=$(du -sk "$cache_dir" 2> /dev/null | awk '{print $1}' || echo "0") "~/Library/WebKit|WebKit|com.*:org.*:net.*:io.*"
"~/Library/HTTPStorages|HTTP|com.*:org.*:net.*:io.*"
"~/Library/Cookies|Cookies|*.binarycookies"
)
orphaned_count=0
for resource_type in "${resource_types[@]}"; do
IFS='|' read -r base_path label patterns <<< "$resource_type"
base_path="${base_path/#\~/$HOME}"
[[ -d "$base_path" ]] || continue
# Build file pattern array
local -a file_patterns=()
IFS=':' read -ra pattern_arr <<< "$patterns"
for pat in "${pattern_arr[@]}"; do
file_patterns+=("$base_path/$pat")
done
# Scan and clean orphaned items
for item_path in "${file_patterns[@]}"; do
# Use shell glob (no ls needed)
for match in $item_path; do
[[ -e "$match" ]] || continue
# Extract bundle ID from filename
local bundle_id=$(basename "$match")
bundle_id="${bundle_id%.savedState}"
bundle_id="${bundle_id%.binarycookies}"
if is_orphaned "$bundle_id" "$match"; then
local size_kb=$(du -sk "$match" 2> /dev/null | awk '{print $1}' || echo "0")
if [[ "$size_kb" -gt 0 ]]; then if [[ "$size_kb" -gt 0 ]]; then
safe_clean "$cache_dir" "Orphaned cache: $bundle_id" safe_clean "$match" "Orphaned $label: $bundle_id"
((cache_found++)) ((orphaned_count++))
((total_orphaned_kb += size_kb)) ((total_orphaned_kb += size_kb))
fi fi
fi fi
done done
fi
stop_inline_spinner
echo -e " ${GREEN}${ICON_SUCCESS}${NC} Found $cache_found orphaned caches"
# Clean orphaned logs
MOLE_SPINNER_PREFIX=" " start_inline_spinner "Scanning orphaned logs..."
local logs_found=0
if ls ~/Library/Logs/com.* > /dev/null 2>&1; then
for log_dir in ~/Library/Logs/com.* ~/Library/Logs/org.* ~/Library/Logs/net.* ~/Library/Logs/io.*; do
[[ -d "$log_dir" ]] || continue
local bundle_id=$(basename "$log_dir")
if is_orphaned "$bundle_id" "$log_dir"; then
local size_kb=$(du -sk "$log_dir" 2> /dev/null | awk '{print $1}' || echo "0")
if [[ "$size_kb" -gt 0 ]]; then
safe_clean "$log_dir" "Orphaned logs: $bundle_id"
((logs_found++))
((total_orphaned_kb += size_kb))
fi
fi
done done
fi
stop_inline_spinner
echo -e " ${GREEN}${ICON_SUCCESS}${NC} Found $logs_found orphaned log directories"
# Clean orphaned saved states
MOLE_SPINNER_PREFIX=" " start_inline_spinner "Scanning orphaned saved states..."
local states_found=0
if ls ~/Library/Saved\ Application\ State/*.savedState > /dev/null 2>&1; then
for state_dir in ~/Library/Saved\ Application\ State/*.savedState; do
[[ -d "$state_dir" ]] || continue
local bundle_id=$(basename "$state_dir" .savedState)
if is_orphaned "$bundle_id" "$state_dir"; then
local size_kb=$(du -sk "$state_dir" 2> /dev/null | awk '{print $1}' || echo "0")
if [[ "$size_kb" -gt 0 ]]; then
safe_clean "$state_dir" "Orphaned state: $bundle_id"
((states_found++))
((total_orphaned_kb += size_kb))
fi
fi
done done
fi
stop_inline_spinner
echo -e " ${GREEN}${ICON_SUCCESS}${NC} Found $states_found orphaned saved states"
# Clean orphaned containers
# Note: Disabled by default - container names may not match Bundle IDs
MOLE_SPINNER_PREFIX=" " start_inline_spinner "Scanning orphaned containers..."
local containers_found=0
local containers_size_kb=0
if ls ~/Library/Containers/com.* > /dev/null 2>&1; then
# Count potential orphaned containers but don't delete them
for container_dir in ~/Library/Containers/com.* ~/Library/Containers/org.* ~/Library/Containers/net.* ~/Library/Containers/io.*; do
[[ -d "$container_dir" ]] || continue
local bundle_id=$(basename "$container_dir")
if is_orphaned "$bundle_id" "$container_dir"; then
local size_kb=$(du -sk "$container_dir" 2> /dev/null | awk '{print $1}' || echo "0")
if [[ "$size_kb" -gt 0 ]]; then
# DISABLED: Not cleaned due to potential Bundle ID mismatch risk
((containers_found++))
((containers_size_kb += size_kb))
fi
fi
done
fi
stop_inline_spinner stop_inline_spinner
if [[ $containers_found -gt 0 ]]; then echo -e " ${GREEN}${ICON_SUCCESS}${NC} Found $orphaned_count orphaned app resources"
local containers_mb=$(echo "$containers_size_kb" | awk '{printf "%.1f", $1/1024}')
echo -e " ${GREEN}${ICON_SUCCESS}${NC} Skipped $containers_found potential orphaned containers (~${containers_mb}MB)"
else
echo -e " ${GREEN}${ICON_SUCCESS}${NC} No potential orphaned containers found"
fi
# Clean orphaned WebKit data
MOLE_SPINNER_PREFIX=" " start_inline_spinner "Scanning orphaned WebKit data..."
local webkit_found=0
if ls ~/Library/WebKit/com.* > /dev/null 2>&1; then
for webkit_dir in ~/Library/WebKit/com.* ~/Library/WebKit/org.* ~/Library/WebKit/net.* ~/Library/WebKit/io.*; do
[[ -d "$webkit_dir" ]] || continue
local bundle_id=$(basename "$webkit_dir")
if is_orphaned "$bundle_id" "$webkit_dir"; then
local size_kb=$(du -sk "$webkit_dir" 2> /dev/null | awk '{print $1}' || echo "0")
if [[ "$size_kb" -gt 0 ]]; then
safe_clean "$webkit_dir" "Orphaned WebKit: $bundle_id"
((webkit_found++))
((total_orphaned_kb += size_kb))
fi
fi
done
fi
stop_inline_spinner
echo -e " ${GREEN}${ICON_SUCCESS}${NC} Found $webkit_found orphaned WebKit data"
# Clean orphaned HTTP storages
MOLE_SPINNER_PREFIX=" " start_inline_spinner "Scanning orphaned HTTP storages..."
local http_found=0
if ls ~/Library/HTTPStorages/com.* > /dev/null 2>&1; then
for http_dir in ~/Library/HTTPStorages/com.* ~/Library/HTTPStorages/org.* ~/Library/HTTPStorages/net.* ~/Library/HTTPStorages/io.*; do
[[ -d "$http_dir" ]] || continue
local bundle_id=$(basename "$http_dir")
if is_orphaned "$bundle_id" "$http_dir"; then
local size_kb=$(du -sk "$http_dir" 2> /dev/null | awk '{print $1}' || echo "0")
if [[ "$size_kb" -gt 0 ]]; then
safe_clean "$http_dir" "Orphaned HTTP storage: $bundle_id"
((http_found++))
((total_orphaned_kb += size_kb))
fi
fi
done
fi
stop_inline_spinner
echo -e " ${GREEN}${ICON_SUCCESS}${NC} Found $http_found orphaned HTTP storages"
# Clean orphaned cookies
MOLE_SPINNER_PREFIX=" " start_inline_spinner "Scanning orphaned cookies..."
local cookies_found=0
if ls ~/Library/Cookies/*.binarycookies > /dev/null 2>&1; then
for cookie_file in ~/Library/Cookies/*.binarycookies; do
[[ -f "$cookie_file" ]] || continue
local bundle_id=$(basename "$cookie_file" .binarycookies)
if is_orphaned "$bundle_id" "$cookie_file"; then
local size_kb=$(du -sk "$cookie_file" 2> /dev/null | awk '{print $1}' || echo "0")
if [[ "$size_kb" -gt 0 ]]; then
safe_clean "$cookie_file" "Orphaned cookies: $bundle_id"
((cookies_found++))
((total_orphaned_kb += size_kb))
fi
fi
done
fi
stop_inline_spinner
echo -e " ${GREEN}${ICON_SUCCESS}${NC} Found $cookies_found orphaned cookie files"
# Calculate total (exclude containers since they were not cleaned)
orphaned_count=$((cache_found + logs_found + states_found + webkit_found + http_found + cookies_found))
if [[ $orphaned_count -gt 0 ]]; then if [[ $orphaned_count -gt 0 ]]; then
local orphaned_mb=$(echo "$total_orphaned_kb" | awk '{printf "%.1f", $1/1024}') local orphaned_mb=$(echo "$total_orphaned_kb" | awk '{printf "%.1f", $1/1024}')
@@ -1427,7 +1300,7 @@ perform_cleanup() {
echo " ${GREEN}${ICON_SUCCESS}${NC} No orphaned app data found" echo " ${GREEN}${ICON_SUCCESS}${NC} No orphaned app data found"
fi fi
rm -f "$installed_bundles" "$running_bundles" "$launch_agents" rm -f "$installed_bundles"
end_section end_section