mirror of
https://github.com/tw93/Mole.git
synced 2026-02-07 11:03:29 +00:00
feat: Enhance app protection with centralized critical component checks, improve UI string width calculation, refine analysis and cleaning logic, and add new tests.
This commit is contained in:
@@ -484,10 +484,17 @@ clean_project_artifacts() {
|
||||
local path="$1"
|
||||
|
||||
# Find the project root by looking for direct child of search paths
|
||||
local search_roots=("$HOME/www" "$HOME/dev" "$HOME/Projects")
|
||||
local search_roots=()
|
||||
if [[ ${#PURGE_SEARCH_PATHS[@]} -gt 0 ]]; then
|
||||
search_roots=("${PURGE_SEARCH_PATHS[@]}")
|
||||
else
|
||||
search_roots=("$HOME/www" "$HOME/dev" "$HOME/Projects")
|
||||
fi
|
||||
|
||||
for root in "${search_roots[@]}"; do
|
||||
if [[ "$path" == "$root/"* ]]; then
|
||||
# Normalize trailing slash for consistent matching
|
||||
root="${root%/}"
|
||||
if [[ -n "$root" && "$path" == "$root/"* ]]; then
|
||||
# Remove root prefix and get first directory component
|
||||
local relative_path="${path#"$root"/}"
|
||||
# Extract first directory name
|
||||
|
||||
@@ -119,6 +119,11 @@ clean_sandboxed_app_caches() {
|
||||
local containers_dir="$HOME/Library/Containers"
|
||||
[[ ! -d "$containers_dir" ]] && return 0
|
||||
|
||||
# Enable nullglob for safe globbing; restore afterwards
|
||||
local _ng_state
|
||||
_ng_state=$(shopt -p nullglob || true)
|
||||
shopt -s nullglob
|
||||
|
||||
if [[ -t 1 ]]; then
|
||||
MOLE_SPINNER_PREFIX=" " start_inline_spinner "Scanning sandboxed apps..."
|
||||
fi
|
||||
@@ -146,6 +151,9 @@ clean_sandboxed_app_caches() {
|
||||
((total_items++))
|
||||
note_activity
|
||||
fi
|
||||
|
||||
# Restore nullglob to previous state
|
||||
eval "$_ng_state"
|
||||
}
|
||||
|
||||
# Process a single container cache directory (reduces nesting)
|
||||
@@ -155,14 +163,10 @@ process_container_cache() {
|
||||
|
||||
# Extract bundle ID and check protection status early
|
||||
local bundle_id=$(basename "$container_dir")
|
||||
local bundle_id_lower=$(echo "$bundle_id" | tr '[:upper:]' '[:lower:]')
|
||||
|
||||
# Check explicit critical system components (case-insensitive regex)
|
||||
if [[ "$bundle_id_lower" =~ backgroundtaskmanagement || "$bundle_id_lower" =~ loginitems || "$bundle_id_lower" =~ systempreferences || "$bundle_id_lower" =~ systemsettings || "$bundle_id_lower" =~ settings || "$bundle_id_lower" =~ preferences || "$bundle_id_lower" =~ controlcenter || "$bundle_id_lower" =~ biometrickit || "$bundle_id_lower" =~ sfl || "$bundle_id_lower" =~ tcc ]]; then
|
||||
if is_critical_system_component "$bundle_id"; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if should_protect_data "$bundle_id" || should_protect_data "$bundle_id_lower"; then
|
||||
if should_protect_data "$bundle_id" || should_protect_data "$(echo "$bundle_id" | tr '[:upper:]' '[:lower:]')"; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
@@ -180,10 +184,14 @@ process_container_cache() {
|
||||
|
||||
if [[ "$DRY_RUN" != "true" ]]; then
|
||||
# Clean contents safely (rm -rf is restricted by safe_remove)
|
||||
local _ng_item_state
|
||||
_ng_item_state=$(shopt -p nullglob || true)
|
||||
shopt -s nullglob
|
||||
for item in "$cache_dir"/*; do
|
||||
[[ -e "$item" ]] || continue
|
||||
safe_remove "$item" true || true
|
||||
done
|
||||
eval "$_ng_item_state"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
@@ -259,6 +267,9 @@ clean_application_support_logs() {
|
||||
local found_any=false
|
||||
|
||||
# Clean log directories and cache patterns
|
||||
local _ng_app_state
|
||||
_ng_app_state=$(shopt -p nullglob || true)
|
||||
shopt -s nullglob
|
||||
for app_dir in ~/Library/Application\ Support/*; do
|
||||
[[ -d "$app_dir" ]] || continue
|
||||
|
||||
@@ -276,7 +287,7 @@ clean_application_support_logs() {
|
||||
continue
|
||||
fi
|
||||
|
||||
if [[ "$app_name_lower" =~ backgroundtaskmanagement || "$app_name_lower" =~ loginitems || "$app_name_lower" =~ systempreferences || "$app_name_lower" =~ systemsettings || "$app_name_lower" =~ settings || "$app_name_lower" =~ preferences || "$app_name_lower" =~ controlcenter || "$app_name_lower" =~ biometrickit || "$app_name_lower" =~ sfl || "$app_name_lower" =~ tcc ]]; then
|
||||
if is_critical_system_component "$app_name"; then
|
||||
continue
|
||||
fi
|
||||
|
||||
@@ -291,15 +302,20 @@ clean_application_support_logs() {
|
||||
found_any=true
|
||||
|
||||
if [[ "$DRY_RUN" != "true" ]]; then
|
||||
local _ng_candidate_state
|
||||
_ng_candidate_state=$(shopt -p nullglob || true)
|
||||
shopt -s nullglob
|
||||
for item in "$candidate"/*; do
|
||||
[[ -e "$item" ]] || continue
|
||||
safe_remove "$item" true > /dev/null 2>&1 || true
|
||||
done
|
||||
eval "$_ng_candidate_state"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
done
|
||||
eval "$_ng_app_state"
|
||||
|
||||
# Clean Group Containers logs
|
||||
local known_group_containers=(
|
||||
|
||||
@@ -435,6 +435,24 @@ readonly DATA_PROTECTED_BUNDLES=(
|
||||
"org.sparkle-project.Sparkle" # Sparkle (update framework)
|
||||
)
|
||||
|
||||
# Centralized check for critical system components (case-insensitive)
|
||||
is_critical_system_component() {
|
||||
local token="$1"
|
||||
[[ -z "$token" ]] && return 1
|
||||
|
||||
local lower
|
||||
lower=$(echo "$token" | tr '[:upper:]' '[:lower:]')
|
||||
|
||||
case "$lower" in
|
||||
*backgroundtaskmanagement* | *loginitems* | *systempreferences* | *systemsettings* | *settings* | *preferences* | *controlcenter* | *biometrickit* | *sfl* | *tcc* )
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Legacy function - preserved for backward compatibility
|
||||
# Use should_protect_from_uninstall() or should_protect_data() instead
|
||||
readonly PRESERVED_BUNDLE_PATTERNS=("${SYSTEM_CRITICAL_BUNDLES[@]}" "${DATA_PROTECTED_BUNDLES[@]}")
|
||||
|
||||
@@ -60,6 +60,22 @@ get_display_width() {
|
||||
local padding=$((extra_bytes / 2))
|
||||
width=$((char_count + padding))
|
||||
|
||||
# Adjust for zero-width joiners and emoji variation selectors (common in filenames/emojis)
|
||||
# These characters add bytes but no visible width; subtract their count if present.
|
||||
local zwj=$'\u200d' # zero-width joiner
|
||||
local vs16=$'\ufe0f' # emoji variation selector
|
||||
local zero_width=0
|
||||
|
||||
local without_zwj=${str//$zwj/}
|
||||
zero_width=$((zero_width + (char_count - ${#without_zwj})))
|
||||
|
||||
local without_vs=${str//$vs16/}
|
||||
zero_width=$((zero_width + (char_count - ${#without_vs})))
|
||||
|
||||
if ((zero_width > 0 && width > zero_width)); then
|
||||
width=$((width - zero_width))
|
||||
fi
|
||||
|
||||
echo "$width"
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user