curtain/.github/wiki/Home.md
Aric Camarata 8c19e960d2 Detection root-cause fix + audit batch: netstat path, UDP activator, settings coherence, refactor, docs
Detection: netstat lives at /usr/sbin/netstat, not /usr/bin — the hardcoded wrong
path silently killed the ESTABLISHED-TCP activator (root cause of the failed live
test). Fixed and live-verified. Added peered-UDP activator (5900-5902) for
High-Performance sessions, per-signal transition logging, unconditional error
logging for dead probe helpers, and probe v2 with full CGSession dictionary
diffing. 7 new parser tests (32 total).

Fixes from a full audit + adversarial review: idle source setting honored
(default now Remote session activity), cover scope reduced to a coherent
two-mode model with legacy migration (per-display toggle was inverted in
onlyMarked and dead in all), curtain test no longer schedules a teardown over a
live session, specific-display password box placement gets a real picker,
refuse-to-arm enforced, activation notification posts a real banner, menu
password gate bypassed when the event tap is dead, shared single-decoder aerial
player with stale-task guard and async playability check, password buffer zeroed
on successful unlock and Esc, XPC interruption/invalidation handlers, modern
Accessibility settings URL, launchPath modernized, codesign failures now abort
release.sh, monotonic CFBundleVersion, install.sh temp cleanup, dead
armDisarmHotkey setting removed.

Refactor: Curtain.swift and PreferencesWindow.swift split into focused files
(largest now 479 lines). Wiki, README, and contributing docs updated to match.
Build clean at 0 warnings, 32/32 tests pass.
2026-06-09 20:36:30 -04:00

42 lines
2.8 KiB
Markdown

# Curtain
A privacy curtain for macOS Screen Sharing. When you remote into your Mac, Curtain hides the screen from anyone sitting at it and makes the local keyboard and mouse do nothing to your apps, while you keep full control from your laptop. When the session goes idle or ends, it can lock the Mac and sleep the displays.
macOS does Screen Sharing well. Curtain is the missing privacy layer around it: a lightweight menu-bar agent with a SwiftUI settings window, in the spirit of Caffeine.
## Behavior at a glance
| Event | Default (all configurable) |
|---|---|
| Remote session connects | Cover every physical display. Block desk keyboard and mouse from reaching apps. Keep displays awake. Remote input works normally. |
| Key pressed at the desk | A password box appears on the curtain. Correct password reveals the desktop and offers to disconnect the remote. |
| Session idle (default 30 min, tracks remote activity by default) | Disconnect remote, lock Mac, turn off displays, deactivate curtain. |
| Remote session disconnects | Lock Mac, turn off displays, deactivate curtain. |
## The key idea
Your laptop and the desk share one login session (standard Screen Sharing shares the console). A window that blocks input would block your remote too. Curtain detects sessions with three independent signals: a transport-independent macOS capture flag, an established TCP connection on port 5900, and a peered UDP socket on ports 5900-5902. It then filters input by **event source**: macOS tags real hardware events differently from injected remote events. Curtain blocks events with source ID `1` (physical hardware) and passes everything else. No virtual display, no second account.
**Emergency unlock:** press **Control + Option + Command + U** at the desk to force-deactivate at any time. It works even without Accessibility granted.
## Pages
| Page | What it covers |
|---|---|
| [Installation](Installation) | Clone, `install.sh`, Accessibility grant, password setup, DisplayLink, uninstall |
| [Settings](Settings) | Every option in the settings window explained |
| [How It Works](How-It-Works) | Lifecycle walkthrough, the physical-vs-remote trick, DisplayLink caveat |
| [Security](Security) | Threat model, input-filter limits, password storage, the optional helper, distribution trust |
| [Architecture](Architecture) | 12-module breakdown, macOS APIs, data flow |
| [Lessons Learned](Lessons-Learned) | What was discovered building this, including what did not work |
| [Troubleshooting](Troubleshooting) | Common problems and fixes |
## Requirements
- macOS 13 (Ventura) or later. Built and tested on macOS 26 / Apple Silicon.
- Screen Sharing enabled: System Settings → General → Sharing → Screen Sharing.
- Accessibility permission for Curtain, granted once after install.
## License
MIT © Aric Camarata