#!/bin/bash # 06-lock-screen-saver.sh — lock the Mac screen after a HearthGate session ends. # # Why you might want this: # You SSH into a Mac at home from a café, get your thing done, and # disconnect. The Mac at home is now sitting unlocked with the VNC # session leftover in muscle memory of whoever walks past. This hook # triggers the standard macOS screen lock the second the session ends — # the screen saver kicks in and the next keypress will ask for the user # password. # # Why not on connect? # You probably don't want the screen to lock as soon as someone connects # — they may be trying to actually use the Mac at the screen too. This # script intentionally only runs on disconnect. # # How it locks: # Two strategies, in order: # 1. Call CGSession's suspend method via osascript — equivalent to # Apple Menu → Lock Screen. Works on every macOS version since 10.13. # 2. If that fails for some reason, fall back to `pmset displaysleepnow` # which puts the display to sleep; the system Lock setting in # Security & Privacy will lock when the display wakes. # # Setup: # Make the script executable, then add it from HearthGate's Hooks tab. # Full guide: https://codnamacs.com/hearthgate/help/features/hooks # # Environment HearthGate provides: # HEARTHGATE_EVENT # # Test it: # HEARTHGATE_EVENT=after-disconnect ./06-lock-screen-saver.sh # # Screen should immediately lock to the login prompt. set -euo pipefail EVENT="${HEARTHGATE_EVENT:-${1:-unknown}}" lock_screen() { # Path to the private CGSession framework that powers Apple Menu → # Lock Screen. This is the documented Apple way to lock from a script # without needing accessibility permission. local cgsession="/System/Library/CoreServices/Menu Extras/User.menu/Contents/Resources/CGSession" if [ -x "$cgsession" ]; then "$cgsession" -suspend 2>/dev/null && return 0 fi # Newer macOS releases moved CGSession around — fall back to sending # the lock keystroke ⌃⌘Q through osascript. if osascript -e 'tell application "System Events" to keystroke "q" using {control down, command down}' 2>/dev/null; then return 0 fi # Last resort: put the display to sleep. Combined with the standard # "Require password immediately after sleep" setting in System Settings # → Lock Screen, this functions as a lock. pmset displaysleepnow 2>/dev/null } case "$EVENT" in on-disconnect|after-disconnect) lock_screen ;; on-connect|after-connect) # Intentionally a no-op. Locking the screen on connect would fight # whoever is also physically at the Mac. : ;; *) echo "lock-screen-saver: unrecognised event '$EVENT'" >&2 ;; esac