mirror of
https://github.com/acamarata/curtain.git
synced 2026-06-30 18:54:25 +00:00
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.
128 lines
4.9 KiB
Swift
128 lines
4.9 KiB
Swift
import XCTest
|
|
@testable import CurtainShared
|
|
|
|
final class NetstatParseTests: XCTestCase {
|
|
func testListenOnlyIsFalse() {
|
|
let out = """
|
|
Active Internet connections (including servers)
|
|
Proto Recv-Q Send-Q Local Address Foreign Address (state)
|
|
tcp4 0 0 *.5900 *.* LISTEN
|
|
"""
|
|
XCTAssertFalse(NetstatParse.hasEstablishedVNC(out))
|
|
}
|
|
|
|
func testEstablishedInboundIsTrue() {
|
|
let out = """
|
|
Proto Recv-Q Send-Q Local Address Foreign Address (state)
|
|
tcp4 0 0 192.168.1.20.5900 192.168.1.55.51234 ESTABLISHED
|
|
"""
|
|
XCTAssertTrue(NetstatParse.hasEstablishedVNC(out))
|
|
}
|
|
|
|
func testEstablishedDifferentPortIsFalse() {
|
|
let out = """
|
|
Proto Recv-Q Send-Q Local Address Foreign Address (state)
|
|
tcp4 0 0 192.168.1.20.22 192.168.1.55.51234 ESTABLISHED
|
|
"""
|
|
XCTAssertFalse(NetstatParse.hasEstablishedVNC(out))
|
|
}
|
|
|
|
func testForeignWildcardIsFalse() {
|
|
let out = """
|
|
Proto Recv-Q Send-Q Local Address Foreign Address (state)
|
|
tcp4 0 0 192.168.1.20.5900 *.* ESTABLISHED
|
|
"""
|
|
XCTAssertFalse(NetstatParse.hasEstablishedVNC(out))
|
|
}
|
|
|
|
func testOutboundFiveNineHundredIsFalse() {
|
|
// 5900 appears in the FOREIGN column (we are the client) — not an inbound VNC session.
|
|
let out = """
|
|
Proto Recv-Q Send-Q Local Address Foreign Address (state)
|
|
tcp4 0 0 192.168.1.20.51234 192.168.1.55.5900 ESTABLISHED
|
|
"""
|
|
XCTAssertFalse(NetstatParse.hasEstablishedVNC(out))
|
|
}
|
|
|
|
func testEmptyOutputIsFalse() {
|
|
XCTAssertFalse(NetstatParse.hasEstablishedVNC(""))
|
|
}
|
|
|
|
func testEstablishedAmongNoiseIsTrue() {
|
|
let out = """
|
|
Proto Recv-Q Send-Q Local Address Foreign Address (state)
|
|
tcp4 0 0 *.5900 *.* LISTEN
|
|
tcp4 0 0 192.168.1.20.22 10.0.0.9.4421 ESTABLISHED
|
|
tcp4 0 0 192.168.1.20.5900 10.0.0.9.62000 ESTABLISHED
|
|
"""
|
|
XCTAssertTrue(NetstatParse.hasEstablishedVNC(out))
|
|
}
|
|
|
|
func testRealMacOS26ListenFormatIsFalse() {
|
|
// Verbatim from `netstat -an` on macOS 26.5 with Screen Sharing enabled,
|
|
// no session: LISTEN rows only must never read as established.
|
|
let out = """
|
|
Active Internet connections (including servers)
|
|
Proto Recv-Q Send-Q Local Address Foreign Address (state)
|
|
tcp4 0 0 *.5900 *.* LISTEN
|
|
tcp6 0 0 *.5900 *.* LISTEN
|
|
"""
|
|
XCTAssertFalse(NetstatParse.hasEstablishedVNC(out))
|
|
XCTAssertFalse(NetstatParse.hasPeeredUDPVNC(out))
|
|
}
|
|
|
|
// MARK: - Peered UDP (High-Performance transport)
|
|
|
|
func testPeeredUDPOn5900IsTrue() {
|
|
let out = """
|
|
Proto Recv-Q Send-Q Local Address Foreign Address
|
|
udp4 0 0 192.168.1.20.5900 192.168.1.55.61234
|
|
"""
|
|
XCTAssertTrue(NetstatParse.hasPeeredUDPVNC(out))
|
|
}
|
|
|
|
func testPeeredUDPOn5901And5902IsTrue() {
|
|
let out5901 = """
|
|
udp4 0 0 192.168.1.20.5901 192.168.1.55.61234
|
|
"""
|
|
let out5902 = """
|
|
udp6 0 0 fe80::1%en0.5902 fe80::2%en0.61234
|
|
"""
|
|
XCTAssertTrue(NetstatParse.hasPeeredUDPVNC(out5901))
|
|
XCTAssertTrue(NetstatParse.hasPeeredUDPVNC(out5902))
|
|
}
|
|
|
|
func testWildcardUDPListenerIsFalse() {
|
|
// An unconnected UDP listener (foreign *.*) is just Screen Sharing being
|
|
// enabled — it must NEVER activate (the overnight false-positive class).
|
|
let out = """
|
|
udp4 0 0 *.5900 *.*
|
|
udp4 0 0 192.168.1.20.5900 *.*
|
|
"""
|
|
XCTAssertFalse(NetstatParse.hasPeeredUDPVNC(out))
|
|
}
|
|
|
|
func testPeeredUDPOnOtherPortIsFalse() {
|
|
let out = """
|
|
udp4 0 0 192.168.1.20.5353 192.168.1.55.5353
|
|
udp4 0 0 192.168.1.20.59000 10.0.0.9.443
|
|
"""
|
|
XCTAssertFalse(NetstatParse.hasPeeredUDPVNC(out))
|
|
}
|
|
|
|
func testPeeredUDPIsNotEstablishedTCP() {
|
|
// The two detectors must not bleed into each other.
|
|
let udpOnly = """
|
|
udp4 0 0 192.168.1.20.5900 192.168.1.55.61234
|
|
"""
|
|
let tcpOnly = """
|
|
tcp4 0 0 192.168.1.20.5900 192.168.1.55.61234 ESTABLISHED
|
|
"""
|
|
XCTAssertFalse(NetstatParse.hasEstablishedVNC(udpOnly))
|
|
XCTAssertFalse(NetstatParse.hasPeeredUDPVNC(tcpOnly))
|
|
}
|
|
|
|
func testEmptyOutputUDPIsFalse() {
|
|
XCTAssertFalse(NetstatParse.hasPeeredUDPVNC(""))
|
|
}
|
|
}
|