mirror of
https://github.com/tw93/Mole.git
synced 2026-02-04 15:04:42 +00:00
329 lines
10 KiB
Bash
Executable File
329 lines
10 KiB
Bash
Executable File
#!/bin/bash
|
|
# Mole - Touch ID command.
|
|
# Configures sudo with Touch ID.
|
|
# Guided toggle with safety checks.
|
|
|
|
set -euo pipefail
|
|
|
|
# Determine script location and source common functions
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
LIB_DIR="$(cd "$SCRIPT_DIR/../lib" && pwd)"
|
|
|
|
# Source common functions
|
|
# shellcheck source=../lib/core/common.sh
|
|
source "$LIB_DIR/core/common.sh"
|
|
|
|
# Set up global cleanup trap
|
|
trap cleanup_temp_files EXIT INT TERM
|
|
|
|
PAM_SUDO_FILE="${MOLE_PAM_SUDO_FILE:-/etc/pam.d/sudo}"
|
|
PAM_SUDO_LOCAL_FILE="${MOLE_PAM_SUDO_LOCAL_FILE:-$(dirname "$PAM_SUDO_FILE")/sudo_local}"
|
|
readonly PAM_SUDO_FILE
|
|
readonly PAM_SUDO_LOCAL_FILE
|
|
readonly PAM_TID_LINE="auth sufficient pam_tid.so"
|
|
|
|
# Check if Touch ID is already configured
|
|
is_touchid_configured() {
|
|
# Check sudo_local first
|
|
if [[ -f "$PAM_SUDO_LOCAL_FILE" ]]; then
|
|
grep -q "pam_tid.so" "$PAM_SUDO_LOCAL_FILE" 2> /dev/null && return 0
|
|
fi
|
|
|
|
# Fallback to standard sudo file
|
|
if [[ ! -f "$PAM_SUDO_FILE" ]]; then
|
|
return 1
|
|
fi
|
|
grep -q "pam_tid.so" "$PAM_SUDO_FILE" 2> /dev/null
|
|
}
|
|
|
|
# Check if system supports Touch ID
|
|
supports_touchid() {
|
|
# Check if bioutil exists and has Touch ID capability
|
|
if command -v bioutil &> /dev/null; then
|
|
bioutil -r 2> /dev/null | grep -q "Touch ID" && return 0
|
|
fi
|
|
|
|
# Fallback: check if running on Apple Silicon or modern Intel Mac
|
|
local arch
|
|
arch=$(uname -m)
|
|
if [[ "$arch" == "arm64" ]]; then
|
|
return 0
|
|
fi
|
|
|
|
# For Intel Macs, check if it's 2018 or later (approximation)
|
|
local model_year
|
|
model_year=$(system_profiler SPHardwareDataType 2> /dev/null | grep "Model Identifier" | grep -o "[0-9]\{4\}" | head -1)
|
|
if [[ -n "$model_year" ]] && [[ "$model_year" -ge 2018 ]]; then
|
|
return 0
|
|
fi
|
|
|
|
return 1
|
|
}
|
|
|
|
# Show current Touch ID status
|
|
show_status() {
|
|
if is_touchid_configured; then
|
|
echo -e "${GREEN}${ICON_SUCCESS}${NC} Touch ID is enabled for sudo"
|
|
else
|
|
echo -e "${YELLOW}☻${NC} Touch ID is not configured for sudo"
|
|
fi
|
|
}
|
|
|
|
# Enable Touch ID for sudo
|
|
enable_touchid() {
|
|
# Cleanup trap handled by global EXIT trap
|
|
local temp_file=""
|
|
|
|
# First check if system supports Touch ID
|
|
if ! supports_touchid; then
|
|
log_warning "This Mac may not support Touch ID"
|
|
read -rp "Continue anyway? [y/N] " confirm
|
|
if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
|
|
echo -e "${YELLOW}Cancelled${NC}"
|
|
return 1
|
|
fi
|
|
echo ""
|
|
fi
|
|
|
|
# Check if we should use sudo_local (Sonoma+)
|
|
if grep -q "sudo_local" "$PAM_SUDO_FILE"; then
|
|
# Check if already correctly configured in sudo_local
|
|
if [[ -f "$PAM_SUDO_LOCAL_FILE" ]] && grep -q "pam_tid.so" "$PAM_SUDO_LOCAL_FILE"; then
|
|
# It is in sudo_local, but let's check if it's ALSO in sudo (incomplete migration)
|
|
if grep -q "pam_tid.so" "$PAM_SUDO_FILE"; then
|
|
# Clean up legacy config
|
|
temp_file=$(create_temp_file)
|
|
grep -v "pam_tid.so" "$PAM_SUDO_FILE" > "$temp_file"
|
|
if sudo mv "$temp_file" "$PAM_SUDO_FILE" 2> /dev/null; then
|
|
echo -e "${GREEN}${ICON_SUCCESS} Cleanup legacy configuration${NC}"
|
|
fi
|
|
fi
|
|
echo -e "${GREEN}${ICON_SUCCESS} Touch ID is already enabled${NC}"
|
|
return 0
|
|
fi
|
|
|
|
# Not configured in sudo_local yet.
|
|
# Check if configured in sudo (Legacy)
|
|
local is_legacy_configured=false
|
|
if grep -q "pam_tid.so" "$PAM_SUDO_FILE"; then
|
|
is_legacy_configured=true
|
|
fi
|
|
|
|
# Function to write to sudo_local
|
|
local write_success=false
|
|
if [[ ! -f "$PAM_SUDO_LOCAL_FILE" ]]; then
|
|
# Create the file
|
|
echo "# sudo_local: local customizations for sudo" | sudo tee "$PAM_SUDO_LOCAL_FILE" > /dev/null
|
|
echo "$PAM_TID_LINE" | sudo tee -a "$PAM_SUDO_LOCAL_FILE" > /dev/null
|
|
sudo chmod 444 "$PAM_SUDO_LOCAL_FILE"
|
|
sudo chown root:wheel "$PAM_SUDO_LOCAL_FILE"
|
|
write_success=true
|
|
else
|
|
# Append if not present
|
|
if ! grep -q "pam_tid.so" "$PAM_SUDO_LOCAL_FILE"; then
|
|
temp_file=$(create_temp_file)
|
|
cp "$PAM_SUDO_LOCAL_FILE" "$temp_file"
|
|
echo "$PAM_TID_LINE" >> "$temp_file"
|
|
sudo mv "$temp_file" "$PAM_SUDO_LOCAL_FILE"
|
|
sudo chmod 444 "$PAM_SUDO_LOCAL_FILE"
|
|
sudo chown root:wheel "$PAM_SUDO_LOCAL_FILE"
|
|
write_success=true
|
|
else
|
|
write_success=true # Already there (should be caught by first check, but safe fallback)
|
|
fi
|
|
fi
|
|
|
|
if $write_success; then
|
|
# If we migrated from legacy, clean it up now
|
|
if $is_legacy_configured; then
|
|
temp_file=$(create_temp_file)
|
|
grep -v "pam_tid.so" "$PAM_SUDO_FILE" > "$temp_file"
|
|
sudo mv "$temp_file" "$PAM_SUDO_FILE"
|
|
log_success "Touch ID migrated to sudo_local"
|
|
else
|
|
log_success "Touch ID enabled (via sudo_local) - try: sudo ls"
|
|
fi
|
|
return 0
|
|
else
|
|
log_error "Failed to write to sudo_local"
|
|
return 1
|
|
fi
|
|
fi
|
|
|
|
# Legacy method: Modify sudo file directly
|
|
|
|
# Check if already configured (Legacy)
|
|
if is_touchid_configured; then
|
|
echo -e "${GREEN}${ICON_SUCCESS} Touch ID is already enabled${NC}"
|
|
return 0
|
|
fi
|
|
|
|
# Create backup only if it doesn't exist to preserve original state
|
|
if [[ ! -f "${PAM_SUDO_FILE}.mole-backup" ]]; then
|
|
if ! sudo cp "$PAM_SUDO_FILE" "${PAM_SUDO_FILE}.mole-backup" 2> /dev/null; then
|
|
log_error "Failed to create backup"
|
|
return 1
|
|
fi
|
|
fi
|
|
|
|
# Create temp file
|
|
temp_file=$(create_temp_file)
|
|
|
|
# Insert pam_tid.so after the first comment block
|
|
awk '
|
|
BEGIN { inserted = 0 }
|
|
/^#/ { print; next }
|
|
!inserted && /^[^#]/ {
|
|
print "'"$PAM_TID_LINE"'"
|
|
inserted = 1
|
|
}
|
|
{ print }
|
|
' "$PAM_SUDO_FILE" > "$temp_file"
|
|
|
|
# Verify content change
|
|
if cmp -s "$PAM_SUDO_FILE" "$temp_file"; then
|
|
log_error "Failed to modify configuration"
|
|
return 1
|
|
fi
|
|
|
|
# Apply the changes
|
|
if sudo mv "$temp_file" "$PAM_SUDO_FILE" 2> /dev/null; then
|
|
log_success "Touch ID enabled - try: sudo ls"
|
|
return 0
|
|
else
|
|
log_error "Failed to enable Touch ID"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Disable Touch ID for sudo
|
|
disable_touchid() {
|
|
# Cleanup trap handled by global EXIT trap
|
|
local temp_file=""
|
|
|
|
if ! is_touchid_configured; then
|
|
echo -e "${YELLOW}Touch ID is not currently enabled${NC}"
|
|
return 0
|
|
fi
|
|
|
|
# Check sudo_local first
|
|
if [[ -f "$PAM_SUDO_LOCAL_FILE" ]] && grep -q "pam_tid.so" "$PAM_SUDO_LOCAL_FILE"; then
|
|
# Remove from sudo_local
|
|
temp_file=$(create_temp_file)
|
|
grep -v "pam_tid.so" "$PAM_SUDO_LOCAL_FILE" > "$temp_file"
|
|
|
|
if sudo mv "$temp_file" "$PAM_SUDO_LOCAL_FILE" 2> /dev/null; then
|
|
# Since we modified sudo_local, we should also check if it's in sudo file (legacy cleanup)
|
|
if grep -q "pam_tid.so" "$PAM_SUDO_FILE"; then
|
|
temp_file=$(create_temp_file)
|
|
grep -v "pam_tid.so" "$PAM_SUDO_FILE" > "$temp_file"
|
|
sudo mv "$temp_file" "$PAM_SUDO_FILE"
|
|
fi
|
|
echo -e "${GREEN}${ICON_SUCCESS} Touch ID disabled (removed from sudo_local)${NC}"
|
|
echo ""
|
|
return 0
|
|
else
|
|
log_error "Failed to disable Touch ID from sudo_local"
|
|
return 1
|
|
fi
|
|
fi
|
|
|
|
# Fallback to sudo file (legacy)
|
|
if grep -q "pam_tid.so" "$PAM_SUDO_FILE"; then
|
|
# Create backup only if it doesn't exist
|
|
if [[ ! -f "${PAM_SUDO_FILE}.mole-backup" ]]; then
|
|
if ! sudo cp "$PAM_SUDO_FILE" "${PAM_SUDO_FILE}.mole-backup" 2> /dev/null; then
|
|
log_error "Failed to create backup"
|
|
return 1
|
|
fi
|
|
fi
|
|
|
|
# Remove pam_tid.so line
|
|
temp_file=$(create_temp_file)
|
|
grep -v "pam_tid.so" "$PAM_SUDO_FILE" > "$temp_file"
|
|
|
|
if sudo mv "$temp_file" "$PAM_SUDO_FILE" 2> /dev/null; then
|
|
echo -e "${GREEN}${ICON_SUCCESS} Touch ID disabled${NC}"
|
|
echo ""
|
|
return 0
|
|
else
|
|
log_error "Failed to disable Touch ID"
|
|
return 1
|
|
fi
|
|
fi
|
|
|
|
# Should not reach here if is_touchid_configured was true
|
|
log_error "Could not find Touch ID configuration to disable"
|
|
return 1
|
|
}
|
|
|
|
# Interactive menu
|
|
show_menu() {
|
|
echo ""
|
|
show_status
|
|
if is_touchid_configured; then
|
|
echo -ne "${PURPLE}☛${NC} Press ${GREEN}Enter${NC} to disable, ${GRAY}Q${NC} to quit: "
|
|
IFS= read -r -s -n1 key || key=""
|
|
drain_pending_input # Clean up any escape sequence remnants
|
|
echo ""
|
|
|
|
case "$key" in
|
|
$'\e') # ESC
|
|
return 0
|
|
;;
|
|
"" | $'\n' | $'\r') # Enter
|
|
printf "\r\033[K" # Clear the prompt line
|
|
disable_touchid
|
|
;;
|
|
*)
|
|
echo ""
|
|
log_error "Invalid key"
|
|
;;
|
|
esac
|
|
else
|
|
echo -ne "${PURPLE}☛${NC} Press ${GREEN}Enter${NC} to enable, ${GRAY}Q${NC} to quit: "
|
|
IFS= read -r -s -n1 key || key=""
|
|
drain_pending_input # Clean up any escape sequence remnants
|
|
|
|
case "$key" in
|
|
$'\e') # ESC
|
|
return 0
|
|
;;
|
|
"" | $'\n' | $'\r') # Enter
|
|
printf "\r\033[K" # Clear the prompt line
|
|
enable_touchid
|
|
;;
|
|
*)
|
|
echo ""
|
|
log_error "Invalid key"
|
|
;;
|
|
esac
|
|
fi
|
|
}
|
|
|
|
# Main
|
|
main() {
|
|
local command="${1:-}"
|
|
|
|
case "$command" in
|
|
enable)
|
|
enable_touchid
|
|
;;
|
|
disable)
|
|
disable_touchid
|
|
;;
|
|
status)
|
|
show_status
|
|
;;
|
|
"")
|
|
show_menu
|
|
;;
|
|
*)
|
|
log_error "Unknown command: $command"
|
|
exit 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
main "$@"
|