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:
@@ -8,6 +8,8 @@ struct HomeView: View {
|
||||
@State private var searchText = ""
|
||||
@State private var showClearConfirmation = false
|
||||
@State private var observation: AnyDatabaseCancellable?
|
||||
@State private var didInitializeObservers = false
|
||||
@State private var refreshSequence = 0
|
||||
|
||||
private let trafficRepo = TrafficRepository()
|
||||
|
||||
@@ -52,6 +54,23 @@ struct HomeView: View {
|
||||
.foregroundStyle(.tertiary)
|
||||
}
|
||||
}
|
||||
.contextMenu {
|
||||
Button {
|
||||
addToSSLProxyingList(domain: group.domain)
|
||||
} label: {
|
||||
Label("Add to SSL Proxying", systemImage: "lock.shield")
|
||||
}
|
||||
Button {
|
||||
addToBlockList(domain: group.domain)
|
||||
} label: {
|
||||
Label("Add to Block List", systemImage: "xmark.shield")
|
||||
}
|
||||
Button(role: .destructive) {
|
||||
try? trafficRepo.deleteForDomain(group.domain)
|
||||
} label: {
|
||||
Label("Delete Domain", systemImage: "trash")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -86,19 +105,70 @@ struct HomeView: View {
|
||||
} message: {
|
||||
Text("This will permanently delete all captured traffic.")
|
||||
}
|
||||
.onAppear {
|
||||
ProxyLogger.ui.info("HomeView: onAppear vpnConnected=\(appState.isVPNConnected) domains=\(domains.count)")
|
||||
}
|
||||
.onDisappear {
|
||||
ProxyLogger.ui.info("HomeView: onDisappear domains=\(domains.count)")
|
||||
}
|
||||
.task {
|
||||
startObservation()
|
||||
guard !didInitializeObservers else {
|
||||
ProxyLogger.ui.info("HomeView: task rerun ignored; observers already initialized")
|
||||
return
|
||||
}
|
||||
|
||||
didInitializeObservers = true
|
||||
ProxyLogger.ui.info("HomeView: initial task setup")
|
||||
startObservation(source: "initial")
|
||||
observeNewTraffic()
|
||||
}
|
||||
}
|
||||
|
||||
private func startObservation() {
|
||||
private let rulesRepo = RulesRepository()
|
||||
|
||||
private func addToSSLProxyingList(domain: String) {
|
||||
var entry = SSLProxyingEntry(domainPattern: domain, isInclude: true)
|
||||
try? rulesRepo.insertSSLEntry(&entry)
|
||||
// Auto-enable SSL proxying if not already
|
||||
if !IPCManager.shared.isSSLProxyingEnabled {
|
||||
IPCManager.shared.isSSLProxyingEnabled = true
|
||||
}
|
||||
IPCManager.shared.post(.configurationChanged)
|
||||
}
|
||||
|
||||
private func addToBlockList(domain: String) {
|
||||
var entry = BlockListEntry(urlPattern: "*\(domain)*")
|
||||
try? rulesRepo.insertBlockEntry(&entry)
|
||||
if !IPCManager.shared.isBlockListEnabled {
|
||||
IPCManager.shared.isBlockListEnabled = true
|
||||
}
|
||||
IPCManager.shared.post(.configurationChanged)
|
||||
}
|
||||
|
||||
private func startObservation(source: String) {
|
||||
refreshSequence += 1
|
||||
let sequence = refreshSequence
|
||||
ProxyLogger.ui.info("HomeView: starting GRDB observation source=\(source) seq=\(sequence)")
|
||||
observation?.cancel()
|
||||
observation = trafficRepo.observeDomainGroups()
|
||||
.start(in: DatabaseManager.shared.dbPool) { error in
|
||||
print("[HomeView] Observation error: \(error)")
|
||||
ProxyLogger.ui.error("HomeView: observation error source=\(source) seq=\(sequence) error=\(error.localizedDescription)")
|
||||
} onChange: { newDomains in
|
||||
let preview = newDomains.prefix(3).map(\.domain).joined(separator: ", ")
|
||||
ProxyLogger.ui.info("HomeView: domains updated source=\(source) seq=\(sequence) count=\(newDomains.count) preview=\(preview)")
|
||||
withAnimation {
|
||||
domains = newDomains
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func observeNewTraffic() {
|
||||
ProxyLogger.ui.info("HomeView: registering Darwin notification observer")
|
||||
IPCManager.shared.observe(.newTrafficCaptured) {
|
||||
ProxyLogger.ui.info("HomeView: Darwin notification received")
|
||||
DispatchQueue.main.async {
|
||||
startObservation(source: "darwin")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user