Initial project setup - Phases 1-3 complete

This commit is contained in:
Trey t
2026-04-06 11:28:40 -05:00
commit c77e506db5
293 changed files with 14233 additions and 0 deletions

103
App/AppState.swift Normal file
View File

@@ -0,0 +1,103 @@
import SwiftUI
import NetworkExtension
import ProxyCore
@Observable
@MainActor
final class AppState {
var vpnStatus: NEVPNStatus = .disconnected
var isCertificateInstalled: Bool = false
var isCertificateTrusted: Bool = false
private var vpnManager: NETunnelProviderManager?
private var statusObservation: NSObjectProtocol?
init() {
Task {
await loadVPNManager()
}
}
func loadVPNManager() async {
do {
let managers = try await NETunnelProviderManager.loadAllFromPreferences()
if let existing = managers.first {
vpnManager = existing
} else {
let manager = NETunnelProviderManager()
let proto = NETunnelProviderProtocol()
proto.providerBundleIdentifier = ProxyConstants.extensionBundleIdentifier
proto.serverAddress = ProxyConstants.proxyHost
manager.protocolConfiguration = proto
manager.localizedDescription = "Proxy"
manager.isEnabled = true
try await manager.saveToPreferences()
try await manager.loadFromPreferences()
vpnManager = manager
}
observeVPNStatus()
vpnStatus = vpnManager?.connection.status ?? .disconnected
} catch {
print("[AppState] Failed to load VPN manager: \(error)")
}
}
func toggleVPN() async {
guard let manager = vpnManager else {
await loadVPNManager()
return
}
switch manager.connection.status {
case .connected, .connecting:
manager.connection.stopVPNTunnel()
case .disconnected, .invalid:
do {
// Ensure saved and fresh before starting
manager.isEnabled = true
try await manager.saveToPreferences()
try await manager.loadFromPreferences()
try manager.connection.startVPNTunnel()
} catch {
print("[AppState] Failed to start VPN: \(error)")
}
default:
break
}
}
var isVPNConnected: Bool {
vpnStatus == .connected
}
var vpnStatusText: String {
switch vpnStatus {
case .connected: "Connected"
case .connecting: "Connecting..."
case .disconnecting: "Disconnecting..."
case .disconnected: "Disconnected"
case .invalid: "Not Configured"
case .reasserting: "Reconnecting..."
@unknown default: "Unknown"
}
}
private func observeVPNStatus() {
guard let manager = vpnManager else { return }
// Remove existing observer
if let existing = statusObservation {
NotificationCenter.default.removeObserver(existing)
}
statusObservation = NotificationCenter.default.addObserver(
forName: .NEVPNStatusDidChange,
object: manager.connection,
queue: .main
) { [weak self] _ in
Task { @MainActor in
self?.vpnStatus = manager.connection.status
}
}
}
}

47
App/ContentView.swift Normal file
View File

@@ -0,0 +1,47 @@
import SwiftUI
struct ContentView: View {
@Environment(AppState.self) private var appState
enum Tab: Hashable {
case home, pin, compose, more
}
@State private var selectedTab: Tab = .home
var body: some View {
TabView(selection: $selectedTab) {
NavigationStack {
HomeView()
}
.tabItem {
Label("Home", systemImage: "house.fill")
}
.tag(Tab.home)
NavigationStack {
PinView()
}
.tabItem {
Label("Pin", systemImage: "pin.fill")
}
.tag(Tab.pin)
NavigationStack {
ComposeListView()
}
.tabItem {
Label("Compose", systemImage: "square.and.pencil")
}
.tag(Tab.compose)
NavigationStack {
MoreView()
}
.tabItem {
Label("More", systemImage: "ellipsis.circle.fill")
}
.tag(Tab.more)
}
}
}

View File

@@ -0,0 +1,14 @@
<?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>com.apple.security.application-groups</key>
<array>
<string>group.com.treyt.proxyapp</string>
</array>
<key>com.apple.developer.networking.networkextension</key>
<array>
<string>packet-tunnel-provider</string>
</array>
</dict>
</plist>

35
App/Info.plist Normal file
View File

@@ -0,0 +1,35 @@
<?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>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Proxy</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<false/>
</dict>
<key>UILaunchScreen</key>
<dict/>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
</array>
</dict>
</plist>

13
App/ProxyApp.swift Normal file
View File

@@ -0,0 +1,13 @@
import SwiftUI
@main
struct ProxyApp: App {
@State private var appState = AppState()
var body: some Scene {
WindowGroup {
ContentView()
.environment(appState)
}
}
}