From 0c119ca4727751c93cfa969d83312aed69ad27e6 Mon Sep 17 00:00:00 2001 From: Matthias Nott <mnott@mnsoft.org> Date: Wed, 25 Mar 2026 13:41:36 +0100 Subject: [PATCH] fix: remove NSAllowsArbitraryLoads, add App Store readiness checklist --- TODO-appstore.md | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ ios/Runner/Info.plist | 3 --- 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/TODO-appstore.md b/TODO-appstore.md new file mode 100644 index 0000000..2eab22c --- /dev/null +++ b/TODO-appstore.md @@ -0,0 +1,54 @@ +# PAILot App Store Readiness Checklist + +Date: 2026-03-25 +Source: Security & Code Quality Review + +## CRITICAL (Must fix before submission) + +- [ ] **C1: Remove NSAllowsArbitraryLoads** — ATS bypass, Apple will reject. Use NSAllowsLocalNetworking only, add TLS to MQTT or use NSExceptionDomains for specific hosts +- [ ] **C2: Add TLS to MQTT** — All conversations and auth token travel in plaintext. Set `client.secure = true`, configure TLS on AIBroker broker +- [ ] **C3: Remove debug log files in production** — `mqtt_debug.log` and `_chatLog` write truncated message content to Documents. Wrap in `kDebugMode` or remove entirely + +## HIGH (Should fix before submission) + +- [ ] **H1: Unbounded image cache** — `_imageCache` in message_bubble.dart grows without limit. Add LRU eviction (cap at 50) +- [ ] **H2: Audio temp files never cleaned** — `_base64ToFile` creates .m4a files never deleted. Clean up after playback completes +- [ ] **H3: TextEditingController leak** — Rename dialog in session_drawer.dart creates controller but never disposes it +- [ ] **H4: Input validation on settings** — No validation on host IPs, port range, MAC format. Add regex validators +- [ ] **H5: LifecycleObserver never removed** — AudioService.init() adds observer but dispose() doesn't remove it +- [ ] **H6: MQTT token in memory** — Acceptable for personal use, document as known limitation + +## MEDIUM (Improve before submission) + +- [ ] **M1: Subnet scan hammers 254 hosts** — Could trigger IDS. Detect subnet mask or cap range +- [ ] **M2: No loadMore debounce** — Scroll pagination fires repeatedly on iOS bounce. Add isLoading guard +- [ ] **M3: NavigateNotifier global singleton** — Mutable static, stale reference risk. Move to Riverpod provider +- [ ] **M4: Unbounded _seenSeqs set** — O(n log n) eviction. Use FIFO deque instead +- [ ] **M5: Screenshots bloat iCloud backup** — Store images as files, not base64 in JSON. Or exclude from backup +- [ ] **M6: Unused import** — `server_config.dart` import in chat_screen.dart suppressed with ignore comment +- [ ] **M7: Silent error swallowing** — ServerConfig _load() catches all exceptions silently. Add debugPrint + +## LOW (Nice-to-haves) + +- [ ] **L1: PrivacyInfo.xcprivacy** — Required since 2024 for UserDefaults and FileTimestamp APIs +- [ ] **L2: Privacy policy URL** — Required for microphone/camera access apps +- [ ] **L3: Unused dependencies** — Remove `web_socket_channel` and `wakelock_plus` from pubspec.yaml +- [ ] **L4: Unnecessary _http._tcp** — Remove from NSBonjourServices, only _mqtt._tcp needed +- [ ] **L5: Typing indicator timeout** — Can get stuck if typing_end missed during background. Auto-clear after 10s +- [ ] **L6: Version number** — Default 1.0.0+1, set correctly before submission +- [ ] **L7: App icon** — Verify meets Apple guidelines (no alpha channel, correct sizes) + +## App Store Requirements + +| Requirement | Status | Action | +|------------|--------|--------| +| NSMicrophoneUsageDescription | PASS | - | +| NSCameraUsageDescription | PASS | - | +| NSPhotoLibraryUsageDescription | PASS | - | +| NSLocalNetworkUsageDescription | PASS | - | +| NSBonjourServices | PASS | Remove _http._tcp | +| NSAppTransportSecurity | FAIL | Fix C1 | +| UIBackgroundModes: audio | PASS | - | +| Privacy Policy | FAIL | Fix L2 | +| PrivacyInfo.xcprivacy | FAIL | Fix L1 | +| TLS for network | FAIL | Fix C2 | diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 8103c41..d888f20 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -61,8 +61,6 @@ <string>PAILot needs camera access to take photos</string> <key>NSAppTransportSecurity</key> <dict> - <key>NSAllowsArbitraryLoads</key> - <true/> <key>NSAllowsLocalNetworking</key> <true/> </dict> @@ -70,7 +68,6 @@ <string>PAILot needs local network access to discover and connect to AIBroker</string> <key>NSBonjourServices</key> <array> - <string>_http._tcp</string> <string>_mqtt._tcp</string> </array> <key>UISupportedInterfaceOrientations</key> -- Gitblit v1.3.1