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,7 +5,7 @@ struct SetupGuideView: View {
@Environment(AppState.self) private var appState
var isReady: Bool {
appState.isVPNConnected && appState.isCertificateTrusted
appState.isVPNConnected && appState.hasSharedCertificate
}
var body: some View {
@@ -15,9 +15,9 @@ struct SetupGuideView: View {
Image(systemName: isReady ? "checkmark.circle.fill" : "exclamationmark.triangle.fill")
.font(.title2)
VStack(alignment: .leading) {
Text(isReady ? "Ready to Intercept" : "Setup Required")
Text(isReady ? "Ready to Capture" : "Setup Required")
.font(.headline)
Text(isReady ? "All systems are configured correctly" : "Complete the steps below to start")
Text(isReady ? "The tunnel and shared certificate are configured" : "Complete the steps below to start")
.font(.caption)
.foregroundStyle(.white.opacity(0.8))
}
@@ -44,43 +44,42 @@ struct SetupGuideView: View {
)
// Step 2: Certificate
stepRow(
title: "Certificate Installed & Trusted",
subtitle: appState.isCertificateTrusted
? "HTTPS traffic can now be decrypted"
: "Install and trust the CA certificate",
isComplete: appState.isCertificateTrusted,
action: {
// TODO: Phase 3 - Open certificate installation flow
}
)
NavigationLink {
CertificateView()
} label: {
HStack(spacing: 12) {
Image(systemName: appState.hasSharedCertificate ? "checkmark.circle.fill" : "circle")
.font(.title2)
.foregroundStyle(appState.hasSharedCertificate ? .green : .secondary)
Divider()
VStack(alignment: .leading) {
Text("Shared Certificate Available")
.font(.subheadline.weight(.medium))
.foregroundStyle(appState.hasSharedCertificate ? .green : .primary)
Text(certificateSubtitle)
.font(.caption)
.foregroundStyle(.secondary)
}
// Help section
VStack(alignment: .leading, spacing: 12) {
Text("Need Help?")
.font(.headline)
HStack {
Image(systemName: "play.rectangle.fill")
.foregroundStyle(.red)
Text("Watch Video Tutorial")
Spacer()
Image(systemName: "arrow.up.forward")
}
.padding()
.background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 12))
}
.buttonStyle(.plain)
if let lastError = appState.lastRuntimeError {
VStack(alignment: .leading, spacing: 8) {
Label("Latest Runtime Error", systemImage: "exclamationmark.triangle.fill")
.font(.subheadline.weight(.medium))
.foregroundStyle(.orange)
Text(lastError)
.font(.caption)
.foregroundStyle(.secondary)
}
.padding(.vertical, 4)
HStack {
Image(systemName: "book.fill")
.foregroundStyle(.blue)
Text("Read Documentation")
Spacer()
Image(systemName: "arrow.up.forward")
.foregroundStyle(.secondary)
}
.padding(.vertical, 4)
.frame(maxWidth: .infinity, alignment: .leading)
.padding()
.background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 12))
}
Spacer()
@@ -90,6 +89,19 @@ struct SetupGuideView: View {
.navigationBarTitleDisplayMode(.inline)
}
private var certificateSubtitle: String {
if !appState.isCertificateInstalled {
return "Generate and install the Proxy CA certificate."
}
if !appState.hasSharedCertificate {
return "The app has a CA, but the extension has not loaded the same one yet."
}
if appState.isHTTPSInspectionVerified {
return "HTTPS inspection has been verified on live traffic."
}
return "Include a domain in SSL Proxying, trust the CA in Settings, then retry the request."
}
private func stepRow(title: String, subtitle: String, isComplete: Bool, action: @escaping () -> Void) -> some View {
Button(action: action) {
HStack(spacing: 12) {