1
0
mirror of https://github.com/tw93/Mole.git synced 2026-02-07 19:44:18 +00:00

More secure deletion and cannot delete path

This commit is contained in:
Tw93
2025-11-14 11:38:25 +08:00
parent ddef8c4bc0
commit 4f8f31444d
5 changed files with 139 additions and 10 deletions

View File

@@ -42,6 +42,77 @@ mo_spinner_chars() {
printf "%s" "$chars"
}
# Security and Path Validation Functions
# Validates a path for safe deletion
# Returns 0 if path is safe to delete, 1 otherwise
validate_path_for_deletion() {
local path="$1"
# Check path is not empty
if [[ -z "$path" ]]; then
log_error "Path validation failed: empty path"
return 1
fi
# Check path is absolute
if [[ "$path" != /* ]]; then
log_error "Path validation failed: path must be absolute: $path"
return 1
fi
# Check path doesn't contain dangerous characters
if [[ "$path" =~ [[:cntrl:]] ]] || [[ "$path" =~ $'\n' ]]; then
log_error "Path validation failed: contains control characters: $path"
return 1
fi
# Check path isn't critical system directory
case "$path" in
/ | /bin | /sbin | /usr | /usr/bin | /usr/sbin | /etc | /var | /System | /Library/Extensions)
log_error "Path validation failed: critical system directory: $path"
return 1
;;
esac
# Path is safe
return 0
}
# Safe wrapper around rm -rf with validation and logging
# Usage: safe_remove "/path/to/file"
# Returns 0 on success, 1 on failure
safe_remove() {
local path="$1"
local silent="${2:-false}"
# Validate path
if ! validate_path_for_deletion "$path"; then
return 1
fi
# Check if path exists
if [[ ! -e "$path" ]]; then
[[ "$silent" != "true" ]] && log_warning "Path does not exist, skipping: $path"
return 0
fi
# Log what we're about to delete
if [[ -d "$path" ]]; then
log_info "Removing directory: $path"
else
log_info "Removing file: $path"
fi
# Perform the deletion
if rm -rf "$path" 2> /dev/null; then
return 0
else
log_error "Failed to remove: $path"
return 1
fi
}
# Logging configuration
readonly LOG_FILE="${HOME}/.config/mole/mole.log"
readonly LOG_MAX_SIZE_DEFAULT=1048576 # 1MB

View File

@@ -8,6 +8,40 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
# Batch uninstall functionality with minimal confirmations
# Replaces the overly verbose individual confirmation approach
# Decode and validate base64 encoded file list
# Returns decoded string if valid, empty string otherwise
decode_file_list() {
local encoded="$1"
local app_name="$2"
local decoded
# Decode base64 data
if ! decoded=$(printf '%s' "$encoded" | base64 -d 2>/dev/null); then
log_error "Failed to decode file list for $app_name"
echo ""
return 1
fi
# Validate decoded data doesn't contain null bytes
if [[ "$decoded" =~ $'\0' ]]; then
log_warning "File list for $app_name contains null bytes, rejecting"
echo ""
return 1
fi
# Validate paths look reasonable (each line should be a path or empty)
while IFS= read -r line; do
if [[ -n "$line" && ! "$line" =~ ^/ ]]; then
log_warning "Invalid path in file list for $app_name: $line"
echo ""
return 1
fi
done <<< "$decoded"
echo "$decoded"
return 0
}
# Note: find_app_files() and calculate_total_size() functions now in lib/common.sh
# Batch uninstall with single confirmation
@@ -64,7 +98,7 @@ batch_uninstall_applications() {
echo ""
for detail in "${app_details[@]}"; do
IFS='|' read -r app_name app_path bundle_id total_kb encoded_files <<< "$detail"
local related_files=$(printf '%s' "$encoded_files" | base64 -d)
local related_files=$(decode_file_list "$encoded_files" "$app_name")
local app_size_display=$(bytes_to_human "$((total_kb * 1024))")
echo -e "${BLUE}${ICON_CONFIRM}${NC} ${app_name} ${GRAY}(${app_size_display})${NC}"
@@ -129,10 +163,15 @@ batch_uninstall_applications() {
return 1
fi
fi
# Start sudo keepalive with robust parent checking
parent_pid=$$
(while true; do
# Check if parent process still exists first
if ! kill -0 "$parent_pid" 2> /dev/null; then
exit 0
fi
sudo -n true
sleep 60
kill -0 "$$" || exit
done 2> /dev/null) &
sudo_keepalive_pid=$!
fi
@@ -149,7 +188,7 @@ batch_uninstall_applications() {
local -a success_items=()
for detail in "${app_details[@]}"; do
IFS='|' read -r app_name app_path bundle_id total_kb encoded_files <<< "$detail"
local related_files=$(printf '%s' "$encoded_files" | base64 -d)
local related_files=$(decode_file_list "$encoded_files" "$app_name")
local reason=""
local needs_sudo=false
[[ ! -w "$(dirname "$app_path")" || "$(stat -f%Su "$app_path" 2> /dev/null)" == "root" ]] && needs_sudo=true

View File

@@ -184,9 +184,8 @@ is_whitelisted() {
for existing in "${CURRENT_WHITELIST_PATTERNS[@]}"; do
local existing_expanded="${existing/#\~/$HOME}"
# Support both exact match and glob pattern match
# shellcheck disable=SC2053
if [[ "$check_pattern" == "$existing_expanded" ]] || [[ $check_pattern == $existing_expanded ]]; then
# Only use exact string match to prevent glob expansion security issues
if [[ "$check_pattern" == "$existing_expanded" ]]; then
return 0
fi
done