Add iPad support, auto-pinning, and comprehensive logging

- Adaptive iPhone/iPad layout with NavigationSplitView sidebar
- Auto-detect SSL-pinned domains, fall back to passthrough
- Certificate install via local HTTP server (Safari profile flow)
- App Group-backed CA, per-domain leaf cert LRU cache
- DB-backed config repository, Darwin notification throttling
- Rules engine, breakpoint rules, pinned domain tracking
- os.Logger instrumentation across tunnel/proxy/mitm/capture/cert/rules/db/ipc/ui
- Fix dyld framework embed, race conditions, thread safety
This commit is contained in:
Trey t
2026-04-11 12:52:18 -05:00
parent c77e506db5
commit 148bc3887c
77 changed files with 6710 additions and 847 deletions

View File

@@ -5,6 +5,7 @@ import GRDB
struct PinView: View {
@State private var pinnedRequests: [CapturedTraffic] = []
@State private var observation: AnyDatabaseCancellable?
@State private var showClearAllConfirmation = false
private let trafficRepo = TrafficRepository()
@@ -19,19 +20,54 @@ struct PinView: View {
} else {
List {
ForEach(pinnedRequests) { request in
NavigationLink(value: request.id) {
TrafficRowView(traffic: request)
if let id = request.id {
NavigationLink(value: id) {
TrafficRowView(traffic: request)
}
}
}
.onDelete { offsets in
for index in offsets {
let request = pinnedRequests[index]
if let id = request.id {
try? trafficRepo.togglePin(id: id, isPinned: false)
}
}
}
}
.navigationDestination(for: Int64?.self) { id in
if let id {
RequestDetailView(trafficId: id)
}
.navigationDestination(for: Int64.self) { id in
RequestDetailView(trafficId: id)
}
}
}
.navigationTitle("Pin")
.toolbar {
if !pinnedRequests.isEmpty {
ToolbarItem(placement: .topBarTrailing) {
Button(role: .destructive) {
showClearAllConfirmation = true
} label: {
Text("Clear All")
}
}
}
}
.confirmationDialog(
"Clear All Pins",
isPresented: $showClearAllConfirmation,
titleVisibility: .visible
) {
Button("Clear All Pins", role: .destructive) {
for request in pinnedRequests {
if let id = request.id {
try? trafficRepo.togglePin(id: id, isPinned: false)
}
}
}
Button("Cancel", role: .cancel) {}
} message: {
Text("This will unpin all \(pinnedRequests.count) pinned requests.")
}
.task {
observation = trafficRepo.observePinnedTraffic()
.start(in: DatabaseManager.shared.dbPool) { error in