Add local bypass

This commit is contained in:
Peter Steinberger 2025-06-24 03:26:52 +02:00
parent fff51301cf
commit bb6934de5d
4 changed files with 84 additions and 21 deletions

View file

@ -1,5 +1,6 @@
import Foundation
import OSLog
import CryptoKit
/// Server state enumeration
enum ServerState {
@ -44,6 +45,21 @@ final class BunServer {
var port: String = ""
var bindAddress: String = "127.0.0.1"
/// Local authentication token for bypassing auth on localhost
private let localAuthToken: String = {
// Generate a secure random token for this session
let randomData = Data((0..<32).map { _ in UInt8.random(in: 0...255) })
return randomData.base64EncodedString()
.replacingOccurrences(of: "+", with: "-")
.replacingOccurrences(of: "/", with: "_")
.replacingOccurrences(of: "=", with: "")
}()
/// Get the local auth token for use in HTTP requests
var localToken: String {
localAuthToken
}
// MARK: - Initialization
@ -150,6 +166,13 @@ final class BunServer {
// OS authentication is the default, no special flags needed
break
}
// Add local bypass authentication for the Mac app
if authMode != "none" {
// Enable local bypass with our generated token
vibetunnelArgs += " --allow-local-bypass --local-auth-token \(localAuthToken)"
logger.info("Local authentication bypass enabled for Mac app")
}
// Create wrapper to run vibetunnel with a parent death signal
// Using a subshell that monitors parent process and kills vibetunnel if parent dies

View file

@ -224,6 +224,9 @@ class ServerManager {
}
logger.info("Started server on port \(self.port)")
// Pass the local auth token to SessionMonitor
SessionMonitor.shared.setLocalAuthToken(server.localToken)
// Trigger cleanup of old sessions after server starts
await triggerInitialCleanup()
@ -253,6 +256,9 @@ class ServerManager {
await server.stop()
bunServer = nil
isRunning = false
// Clear the auth token from SessionMonitor
SessionMonitor.shared.setLocalAuthToken(nil)
// Reset crash tracking when manually stopped
consecutiveCrashes = 0
@ -316,6 +322,11 @@ class ServerManager {
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.timeoutInterval = 10
// Add local auth token if available
if let server = bunServer {
request.setValue(server.localToken, forHTTPHeaderField: "X-VibeTunnel-Local")
}
// Make the cleanup request
let (data, response) = try await URLSession.shared.data(for: request)

View file

@ -29,11 +29,17 @@ final class SessionMonitor {
private var lastFetch: Date?
private let cacheInterval: TimeInterval = 2.0
private let serverPort: Int
private var localAuthToken: String?
private init() {
let port = UserDefaults.standard.integer(forKey: "serverPort")
self.serverPort = port > 0 ? port : 4_020
}
/// Set the local auth token for server requests
func setLocalAuthToken(_ token: String?) {
self.localAuthToken = token
}
/// Number of running sessions
var sessionCount: Int {
@ -69,7 +75,13 @@ final class SessionMonitor {
throw URLError(.badURL)
}
let request = URLRequest(url: url, timeoutInterval: 3.0)
var request = URLRequest(url: url, timeoutInterval: 3.0)
// Add local auth token if available
if let token = localAuthToken {
request.setValue(token, forHTTPHeaderField: "X-VibeTunnel-Local")
}
let (data, response) = try await URLSession.shared.data(for: request)
guard let httpResponse = response as? HTTPURLResponse,

View file

@ -64,6 +64,43 @@ struct DashboardSettingsView: View {
restartServerWithNewPort: restartServerWithNewPort,
serverManager: serverManager
)
// Dashboard URL display
VStack(spacing: 4) {
if accessMode == .localhost {
HStack(spacing: 5) {
Text("Dashboard available at")
.font(.caption)
.foregroundStyle(.secondary)
if let url = URL(string: "http://127.0.0.1:\(serverPort)") {
Link(url.absoluteString, destination: url)
.font(.caption)
.foregroundStyle(.blue)
}
}
} else if accessMode == .network {
if let ip = localIPAddress {
HStack(spacing: 5) {
Text("Dashboard available at")
.font(.caption)
.foregroundStyle(.secondary)
if let url = URL(string: "http://\(ip):\(serverPort)") {
Link(url.absoluteString, destination: url)
.font(.caption)
.foregroundStyle(.blue)
}
}
} else {
Text("Fetching local IP address...")
.font(.caption)
.foregroundStyle(.secondary)
}
}
}
.frame(maxWidth: .infinity)
.padding(.vertical, 8)
NgrokIntegrationSection(
ngrokEnabled: $ngrokEnabled,
@ -427,26 +464,6 @@ private struct AccessModeView: View {
restartServerWithNewBindAddress()
}
}
if accessMode == .network {
if let ip = localIPAddress {
HStack {
Text("Dashboard available at")
.font(.caption)
.foregroundStyle(.secondary)
if let url = URL(string: "http://\(ip):\(serverPort)") {
Link(url.absoluteString, destination: url)
.font(.caption)
.foregroundStyle(.blue)
}
}
} else {
Text("Fetching local IP address...")
.font(.caption)
.foregroundStyle(.secondary)
}
}
}
}
}