The game library rides the management REST API over HTTPS (TCP 47990) through URLSession, authenticated by mTLS and pinned by SHA-256 fingerprint. The app declared no App Transport Security policy at all, so it ran under default ATS -- which exempts only "local" destinations (.local, unqualified names, RFC1918 and link-local literals) and applies the full policy everywhere else. The host certificate is self-signed (and carries no SubjectAltName), so it cannot satisfy that policy: the library loaded at 192.168.x and failed at the TLS layer on any other address. Field-reported against a Tailscale host. 100.64.0.0/10 is CGNAT, not RFC1918, so the library failed there while streaming to the very same address worked -- the QUIC stream plane is raw UDP and never enters the URL loading system. A WireGuard peer or a public-IP host breaks identically. Declares NSAllowsArbitraryLoads, which must stay the dict's only key: iOS 10+ and macOS 10.12+ ignore it whenever a more granular ATS key sits alongside it. Trust is unchanged -- LibraryTLSDelegate still pins the host by fingerprint and hands every other origin (cover-art CDNs) to full system trust evaluation.
70 lines
3.2 KiB
Plaintext
70 lines
3.2 KiB
Plaintext
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
<plist version="1.0">
|
|
<dict>
|
|
<key>CADisableMinimumFrameDurationOnPhone</key>
|
|
<true/>
|
|
<key>GCSupportedGameControllers</key>
|
|
<array>
|
|
<dict>
|
|
<key>ProfileName</key>
|
|
<string>ExtendedGamepad</string>
|
|
</dict>
|
|
<dict>
|
|
<key>ProfileName</key>
|
|
<string>MicroGamepad</string>
|
|
</dict>
|
|
</array>
|
|
<key>NSBonjourServices</key>
|
|
<array>
|
|
<string>_punktfunk._udp</string>
|
|
</array>
|
|
<!-- App Transport Security. We talk to the user's OWN host over HTTPS with a SELF-SIGNED
|
|
certificate at a user-supplied address, and verify it by SHA-256 fingerprint pinning
|
|
established during PIN pairing (LibraryTLSDelegate) — for a box on someone's LAN there is
|
|
no CA that could vouch for it, so pinning is the stronger check, not a weaker one.
|
|
Default ATS exempts only "local" destinations (.local, unqualified names, RFC1918 and
|
|
link-local literals). Every other address gets the full policy, which a self-signed cert
|
|
cannot satisfy — so the management API (game library) worked at 192.168.x but died at the
|
|
TLS layer on Tailscale's 100.64/10 CGNAT range, a WireGuard peer, or a public IP. The QUIC
|
|
stream plane never showed it: that is raw UDP and never enters the URL loading system.
|
|
⚠ This must stay the ONLY key in this dict. On iOS 10+/macOS 10.12+ the system IGNORES
|
|
NSAllowsArbitraryLoads whenever NSAllowsLocalNetworking, NSAllowsArbitraryLoadsInWebContent
|
|
or NSAllowsArbitraryLoadsForMedia is present alongside it — adding one silently restores
|
|
the bug. Other origins (cover-art CDNs) keep full system trust evaluation regardless:
|
|
LibraryTLSDelegate hands every non-host challenge to .performDefaultHandling. -->
|
|
<key>NSAppTransportSecurity</key>
|
|
<dict>
|
|
<key>NSAllowsArbitraryLoads</key>
|
|
<true/>
|
|
</dict>
|
|
<!-- Background keep-alive (opt-in, iOS/iPadOS): the ONLY sanctioned way to keep the long-lived
|
|
QUIC socket + pump-thread set alive while backgrounded is the audio background mode, backed
|
|
by the session's real, audible remote audio (AVAudioEngine keeps rendering). Video decode is
|
|
dropped; a bounded timer auto-disconnects. Never silence-as-keepalive (App Review 2.5.4).
|
|
tvOS ignores/tolerates the key; macOS is not gated by it. -->
|
|
<key>UIBackgroundModes</key>
|
|
<array>
|
|
<string>audio</string>
|
|
</array>
|
|
<!-- Live Activities (iOS/iPadOS): the Lock-Screen / Dynamic-Island session surface. Updated
|
|
locally (pushType nil) from the alive app process — no aps-environment. tvOS/macOS ignore it. -->
|
|
<key>NSSupportsLiveActivities</key>
|
|
<true/>
|
|
<!-- Deep links: punktfunk://connect/<host-uuid>[?launch=<GameEntry.id>]. Emitted by the
|
|
launcher widget and Siri/Shortcuts; routed by ContentView.onOpenURL into the existing
|
|
connect path. Shared across all three targets (tvOS/macOS accept it harmlessly). -->
|
|
<key>CFBundleURLTypes</key>
|
|
<array>
|
|
<dict>
|
|
<key>CFBundleURLName</key>
|
|
<string>io.unom.punktfunk.deeplink</string>
|
|
<key>CFBundleURLSchemes</key>
|
|
<array>
|
|
<string>punktfunk</string>
|
|
</array>
|
|
</dict>
|
|
</array>
|
|
</dict>
|
|
</plist>
|