#!/usr/bin/env bash
# ─────────────────────────────────────────────────────────────────────────────
# MCProof Device Security Check — macOS
#
# A passive, one-time audit of this Mac's security posture, mapped to CIS/NIST
# controls. It reads settings only — it changes nothing, installs nothing, and
# sends nothing off the device. Produces a plain-English HTML report on your
# Desktop. Run it with no arguments:  bash mcproof-device-check.sh
#
# Some checks read more when run with sudo (Remote Login); it degrades to
# "review manually" without elevation rather than failing.
#
# NOT antivirus. This is an assessment of hygiene (encryption, firewall,
# updates, screen lock, etc.) — not real-time protection. For protection, keep
# macOS updated (built-in XProtect) or run a reputable endpoint product.
# ─────────────────────────────────────────────────────────────────────────────
set -u
LANG=C

REPORT="${HOME}/Desktop/mcproof-device-report.html"
[ -d "${HOME}/Desktop" ] || REPORT="${HOME}/mcproof-device-report.html"
HOST="$(scutil --get ComputerName 2>/dev/null || hostname)"
OSVER="$(sw_vers -productVersion 2>/dev/null || echo '?')"
NOW="$(date '+%Y-%m-%d %H:%M')"

rows=""; pass=0; warn=0; fail=0; unknown=0

esc() { printf '%s' "$1" | sed 's/&/\&amp;/g; s/</\&lt;/g; s/>/\&gt;/g'; }

add() { # name status detail fix control
  local name="$1" status="$2" detail="$3" fix="$4" control="$5" sym
  case "$status" in
    pass) pass=$((pass+1)); sym="✓ PASS ";;
    warn) warn=$((warn+1)); sym="! WARN ";;
    fail) fail=$((fail+1)); sym="✗ FAIL ";;
    *)    unknown=$((unknown+1)); status="unknown"; sym="? CHECK";;
  esac
  printf '%s  %s\n' "$sym" "$name"
  [ -n "$detail" ] && printf '          %s\n' "$detail"
  local fixhtml=""; [ -n "$fix" ] && fixhtml="<div class=\"fix\">Fix: $(esc "$fix")</div>"
  rows="${rows}<tr class=\"${status}\"><td>$(esc "$name")</td><td class=\"st ${status}\">${status}</td><td>$(esc "$detail")${fixhtml}</td><td class=\"ctl\">$(esc "$control")</td></tr>"
}

# 1. Disk encryption — FileVault
fv="$(fdesetup status 2>/dev/null)"
if printf '%s' "$fv" | grep -qi 'On'; then
  add "Disk encryption (FileVault)" pass "FileVault is ON — data at rest is encrypted." "" "NIST SC-28 · CIS 3.11"
elif [ -n "$fv" ]; then
  add "Disk encryption (FileVault)" fail "FileVault is OFF — a lost/stolen Mac exposes all data." "Enable it: System Settings > Privacy & Security > FileVault > Turn On." "NIST SC-28 · CIS 3.11"
else
  add "Disk encryption (FileVault)" unknown "Could not read FileVault status." "Check System Settings > Privacy & Security > FileVault." "NIST SC-28"
fi

# 2. Firewall
fwstate="$(/usr/libexec/ApplicationFirewall/socketfilterfw --getglobalstate 2>/dev/null)"
if printf '%s' "$fwstate" | grep -qi 'enabled'; then
  add "Firewall" pass "The application firewall is on." "" "NIST SC-7 · CIS 4"
else
  alf="$(defaults read /Library/Preferences/com.apple.alf globalstate 2>/dev/null)"
  if [ "${alf:-0}" != "0" ] && [ -n "${alf:-}" ]; then
    add "Firewall" pass "The application firewall is on (state ${alf})." "" "NIST SC-7 · CIS 4"
  else
    add "Firewall" fail "The firewall appears OFF." "Turn it on: System Settings > Network > Firewall." "NIST SC-7 · CIS 4"
  fi
fi

# 3. Gatekeeper (only run signed/notarized apps) — the built-in "AV-ish" control
gk="$(spctl --status 2>/dev/null)"
if printf '%s' "$gk" | grep -qi 'assessments enabled'; then
  add "App protection (Gatekeeper)" pass "Gatekeeper is on — blocks unsigned/untrusted apps." "" "NIST SI-3 · CIS 10"
elif [ -n "$gk" ]; then
  add "App protection (Gatekeeper)" fail "Gatekeeper is DISABLED — untrusted apps can run freely." "Re-enable: 'sudo spctl --master-enable', or System Settings > Privacy & Security." "NIST SI-3 · CIS 10"
else
  add "App protection (Gatekeeper)" unknown "Could not read Gatekeeper status." "" "NIST SI-3"
fi

# 4. System Integrity Protection
sip="$(csrutil status 2>/dev/null)"
if printf '%s' "$sip" | grep -qi 'enabled'; then
  add "System Integrity Protection" pass "SIP is enabled — core OS files are protected." "" "NIST SI-7 · CIS 3"
elif printf '%s' "$sip" | grep -qi 'disabled'; then
  add "System Integrity Protection" fail "SIP is DISABLED — malware can tamper with the OS." "Re-enable from Recovery: 'csrutil enable'." "NIST SI-7 · CIS 3"
else
  add "System Integrity Protection" unknown "Could not read SIP status." "" "NIST SI-7"
fi

# 5. Automatic security updates
au="$(defaults read /Library/Preferences/com.apple.SoftwareUpdate AutomaticCheckEnabled 2>/dev/null)"
ci="$(defaults read /Library/Preferences/com.apple.SoftwareUpdate CriticalUpdateInstall 2>/dev/null)"
if [ "${au:-0}" = "1" ] && [ "${ci:-0}" = "1" ]; then
  add "Automatic updates" pass "Automatic check + security updates are enabled." "" "NIST SI-2 · CIS 7"
elif [ "${au:-0}" = "1" ]; then
  add "Automatic updates" warn "Update checks are on, but automatic security installs may be off." "System Settings > General > Software Update > Automatic updates > enable 'Install Security Responses and system files'." "NIST SI-2 · CIS 7"
else
  add "Automatic updates" warn "Automatic updates may be disabled." "System Settings > General > Software Update > turn on automatic updates." "NIST SI-2 · CIS 7"
fi

# 6. Screen lock requires password
afp="$(defaults read com.apple.screensaver askForPassword 2>/dev/null)"
afd="$(defaults read com.apple.screensaver askForPasswordDelay 2>/dev/null)"
if [ "${afp:-0}" = "1" ] && [ "${afd:-9999%.*}" != "" ] && awk "BEGIN{exit !(${afd:-9999}<=900)}" 2>/dev/null; then
  add "Screen lock" pass "A password is required shortly after sleep/screensaver." "" "NIST AC-11 · CIS 4"
else
  add "Screen lock" warn "The Mac may not require a password quickly when it sleeps." "System Settings > Lock Screen > 'Require password after screen saver begins' = immediately (or <5 min)." "NIST AC-11 · CIS 4"
fi

# 7. Least privilege — is the current user an admin?
if id -Gn 2>/dev/null | tr ' ' '\n' | grep -qx 'admin'; then
  add "Least privilege" warn "Your everyday account is an administrator; daily admin use widens the blast radius of any compromise." "Create a separate standard account for daily work; keep an admin account only for installs." "NIST AC-6 · CIS 5"
else
  add "Least privilege" pass "You are signed in as a standard (non-admin) user." "" "NIST AC-6 · CIS 5"
fi

# 8. Guest account
ge="$(defaults read /Library/Preferences/com.apple.loginwindow GuestEnabled 2>/dev/null)"
if [ "${ge:-0}" = "1" ]; then
  add "Guest account" warn "The Guest account is enabled." "Disable it: System Settings > Users & Groups > Guest User > off." "NIST AC-2 · CIS 5"
else
  add "Guest account" pass "The Guest account is disabled." "" "NIST AC-2 · CIS 5"
fi

# 9. Remote Login (SSH) — needs elevation to read reliably
rl="$(systemsetup -getremotelogin 2>/dev/null)"
if printf '%s' "$rl" | grep -qi 'On'; then
  add "Remote Login (SSH)" warn "Remote Login (SSH) is ON — ensure it's needed and access is restricted." "If unused: System Settings > General > Sharing > Remote Login > off." "NIST AC-17 · CIS 4"
elif printf '%s' "$rl" | grep -qi 'Off'; then
  add "Remote Login (SSH)" pass "Remote Login (SSH) is off." "" "NIST AC-17 · CIS 4"
else
  add "Remote Login (SSH)" unknown "Could not read Remote Login (try: sudo bash $0)." "Verify under System Settings > General > Sharing." "NIST AC-17"
fi

# 10. Automatic login
ali="$(defaults read /Library/Preferences/com.apple.loginwindow autoLoginUser 2>/dev/null)"
if [ -n "$ali" ]; then
  add "Automatic login" fail "Automatic login is ON for '${ali}' — anyone who powers on this Mac is signed straight in." "System Settings > Users & Groups > Automatically log in as > Off." "NIST AC-3 · CIS 5"
else
  add "Automatic login" pass "Automatic login is off — a password is required at startup." "" "NIST AC-3 · CIS 5"
fi

# 11. Sharing services (remote entry points beyond SSH)
share_on=""
ll="$(launchctl list 2>/dev/null)"
printf '%s' "$ll" | grep -qi 'com.apple.screensharing' && share_on="Screen Sharing"
printf '%s' "$ll" | grep -qi 'com.apple.smbd' && share_on="${share_on:+$share_on, }File Sharing"
printf '%s' "$ll" | grep -qiE 'com.apple.RemoteDesktop.agent|ARDAgent' && share_on="${share_on:+$share_on, }Remote Management"
if [ -n "$share_on" ]; then
  add "Sharing services" warn "Enabled: ${share_on} — each is a remote entry point into this Mac." "Turn off what you don't use: System Settings > General > Sharing." "NIST AC-17 · CIS 4"
else
  add "Sharing services" pass "No high-risk sharing services detected (Screen/File Sharing, Remote Management)." "" "NIST AC-17 · CIS 4"
fi

# 12. Backups (Time Machine)
tmdest="$(tmutil destinationinfo 2>/dev/null)"
tmauto="$(defaults read /Library/Preferences/com.apple.TimeMachine AutoBackup 2>/dev/null)"
if printf '%s' "$tmdest" | grep -qiE 'Name|ID|URL'; then
  if [ "${tmauto:-0}" = "1" ]; then
    add "Backups (Time Machine)" pass "Time Machine is configured with automatic backups." "" "NIST CP-9 · CIS 11"
  else
    add "Backups (Time Machine)" warn "A backup destination exists, but automatic backup may be off." "System Settings > General > Time Machine > Back Up Automatically." "NIST CP-9 · CIS 11"
  fi
else
  add "Backups (Time Machine)" warn "No Time Machine backup destination is configured — you have no recovery if this Mac is lost or hit by ransomware." "Set up Time Machine (System Settings > General > Time Machine) or another backup." "NIST CP-9 · CIS 11"
fi

# ── grade ─────────────────────────────────────────────────────────────────────
total=$((pass+warn+fail+unknown))
if   [ "$fail" -gt 0 ]; then grade="At risk"; gcolor="#e02a4d"
elif [ "$warn" -gt 0 ]; then grade="Needs attention"; gcolor="#d4af37"
else grade="Solid"; gcolor="#4cc47f"; fi

echo
echo "Device posture: ${grade}   (${pass} pass · ${warn} warn · ${fail} fail · ${unknown} review)"

cat > "$REPORT" <<HTML
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>MCProof Device Security Check — ${HOST}</title><style>
:root{color-scheme:dark}
body{margin:0;background:#0b0a0d;color:#f1ece4;font:15px/1.6 system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
  background-image:radial-gradient(800px 420px at 84% -10%,rgba(212,175,55,.12),transparent 66%),radial-gradient(760px 440px at -8% 3%,rgba(224,42,77,.13),transparent 64%)}
.wrap{max-width:900px;margin:0 auto;padding:28px 22px 60px}
.brand{display:flex;align-items:center;gap:10px;font-weight:850;font-size:1.2rem}
.mark{width:26px;height:26px;border-radius:7px;background:linear-gradient(150deg,#e02a4d 46%,#d4af37 54%);clip-path:polygon(50% 0,100% 18%,100% 62%,50% 100%,0 62%,0 18%)}
h1{font-size:1.5rem;margin:22px 0 4px;letter-spacing:-.02em}
.meta{color:#a99f93;font-size:13px}
.grade{display:inline-block;margin:16px 0;padding:10px 18px;border-radius:12px;font-weight:800;font-size:1.05rem;color:#0b0a0d;background:${gcolor}}
.counts{color:#a99f93;font-size:13.5px;margin-left:10px}
table{width:100%;border-collapse:collapse;margin-top:14px;font-size:13.5px}
th,td{text-align:left;padding:12px 12px;border-bottom:1px solid #2c2632;vertical-align:top}
th{color:#a99f93;font-size:11px;letter-spacing:.12em;text-transform:uppercase}
.st{font-weight:800;text-transform:uppercase;font-size:11px;white-space:nowrap}
.st.pass{color:#4cc47f}.st.warn{color:#e0a24a}.st.fail{color:#ff5670}.st.unknown{color:#a99f93}
tr.fail td:first-child{box-shadow:inset 3px 0 #ff5670}tr.warn td:first-child{box-shadow:inset 3px 0 #e0a24a}
.fix{margin-top:6px;color:#ecc862;font-size:12.5px}
.ctl{color:#a99f93;font-family:ui-monospace,Menlo,monospace;font-size:11.5px;white-space:nowrap}
.note{margin-top:22px;color:#6f675e;font-size:12px;max-width:70ch}
</style></head><body><div class="wrap">
<div class="brand"><span class="mark"></span>MCProof</div>
<h1>Device Security Check</h1>
<div class="meta">${HOST} · macOS ${OSVER} · ${NOW}</div>
<div><span class="grade">${grade}</span><span class="counts">${pass} pass · ${warn} warn · ${fail} fail · ${unknown} review</span></div>
<table><thead><tr><th>Check</th><th>Status</th><th>What it means</th><th>Control</th></tr></thead>
<tbody>${rows}</tbody></table>
<div class="note">MCProof Device Security Check reads settings only — it changes nothing and sends nothing off this device. This is an automated <b>assessment</b> of security hygiene, not antivirus and not legal advice; a qualified reviewer should confirm before any compliance representation. Controls referenced: NIST SP 800-53 / CIS Controls v8. — Millennials Creatives LLC</div>
</div></body></html>
HTML

echo "Report saved: ${REPORT}"
command -v open >/dev/null 2>&1 && open "$REPORT" >/dev/null 2>&1 || true
