// // TetheringHiderApp.swift // // // Created by Jesús David Chapman Vélez on 12/08/26. // import SwiftUI import AppKit @MainActor final class StatusBarController: NSObject, NSMenuDelegate { private var statusItem: NSStatusItem? private let ttlManager: TTLManager private let authService = AuthenticationService() private let commandService = SystemCommandService() init(ttlManager: TTLManager) { self.ttlManager = ttlManager super.init() setupStatusItem() self.ttlManager.onStatusChanged = { [weak self] in Task { @MainActor in self?.updateMenu() } } } func setupStatusItem() { statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) updateMenu() } func updateMenu() { guard let statusItem = statusItem, let button = statusItem.button else { return } // Status Bar Icon let imageName = ttlManager.isProtected ? "antenna.radiowaves.left.and.right" : "antenna.radiowaves.left.and.right.slash" button.image = NSImage(systemSymbolName: imageName, accessibilityDescription: "Tethering Hider") let menu = NSMenu() menu.delegate = self let statusTitle = ttlManager.isProtected ? String(localized: "Tethering Hider — Hotspot Cloaked") : String(localized: "Tethering Hider — Standard Tethering") let headerItem = NSMenuItem(title: statusTitle, action: nil, keyEquivalent: "") headerItem.isEnabled = false headerItem.image = NSImage( systemSymbolName: ttlManager.isProtected ? "eye.slash.fill" : "eye.fill", accessibilityDescription: nil ) menu.addItem(headerItem) menu.addItem(NSMenuItem.separator()) let toggleTitle = ttlManager.isProtected ? String(localized: "Disable Hotspot Cloak (Set TTL 64)") : String(localized: "Enable Hotspot Cloak (Set TTL 65)") let toggleItem = NSMenuItem(title: toggleTitle, action: #selector(toggleAction), keyEquivalent: "") toggleItem.target = self toggleItem.image = NSImage( systemSymbolName: ttlManager.isProtected ? "eye.fill" : "eye.slash.fill", accessibilityDescription: nil ) menu.addItem(toggleItem) menu.addItem(NSMenuItem.separator()) let ipv4Format = String(localized: "IPv4 TTL: %d") let ipv4Item = NSMenuItem(title: String(format: ipv4Format, ttlManager.currentTTL), action: nil, keyEquivalent: "") ipv4Item.isEnabled = false ipv4Item.image = NSImage(systemSymbolName: "network", accessibilityDescription: nil) menu.addItem(ipv4Item) let ipv6Format = String(localized: "IPv6 HLIM: %d") let ipv6Item = NSMenuItem(title: String(format: ipv6Format, ttlManager.currentIPv6HopLimit), action: nil, keyEquivalent: "") ipv6Item.isEnabled = false ipv6Item.image = NSImage(systemSymbolName: "globe", accessibilityDescription: nil) menu.addItem(ipv6Item) let dnsTitle = String(localized: "DNS Flush: AUTO") let dnsItem = NSMenuItem(title: dnsTitle, action: nil, keyEquivalent: "") dnsItem.isEnabled = false dnsItem.image = NSImage(systemSymbolName: "arrow.triangle.2.circlepath", accessibilityDescription: nil) menu.addItem(dnsItem) menu.addItem(NSMenuItem.separator()) let aboutTitle = String(localized: "About Tethering Hider...") let aboutItem = NSMenuItem(title: aboutTitle, action: #selector(aboutAction), keyEquivalent: "") aboutItem.target = self aboutItem.image = NSImage(systemSymbolName: "info.circle.fill", accessibilityDescription: nil) menu.addItem(aboutItem) menu.addItem(NSMenuItem.separator()) let quitTitle = String(localized: "Quit Tethering Hider") let quitItem = NSMenuItem(title: quitTitle, action: #selector(quitAction), keyEquivalent: "q") quitItem.target = self quitItem.image = NSImage(systemSymbolName: "rectangle.portrait.and.arrow.right", accessibilityDescription: nil) menu.addItem(quitItem) statusItem.menu = menu } func menuWillOpen(_ menu: NSMenu) { ttlManager.refreshStatus() } @objc private func toggleAction() { Task { @MainActor in do { let authenticated = try await authService.authenticateWithBiometrics() guard authenticated else { return } if ttlManager.isProtected { try await commandService.resetTTL() ttlManager.didSetTTL(ttlManager.defaultTTL) } else { try await commandService.setTTL(ttlManager.targetTTL) ttlManager.didSetTTL(ttlManager.targetTTL) } updateMenu() } catch { ttlManager.setError(error.localizedDescription) } } } @objc private func aboutAction() { let creditsString = String(localized: "Bypasses mobile carrier hotspot tethering detection by adjusting outgoing IPv4 TTL to 65, IPv6 Hop Limit to 65, and flushing system DNS caches.\n\nDesigned for macOS.") let options: [NSApplication.AboutPanelOptionKey: Any] = [ .credits: NSAttributedString( string: creditsString, attributes: [ .font: NSFont.systemFont(ofSize: 11), .foregroundColor: NSColor.secondaryLabelColor ] ), .applicationName: "Tethering Hider", .version: "1.0.0" ] NSApp.orderFrontStandardAboutPanel(options: options) NSApp.activate(ignoringOtherApps: true) } @objc private func quitAction() { NSApp.terminate(nil) } } @MainActor final class AppDelegate: NSObject, NSApplicationDelegate { var statusBarController: StatusBarController? let ttlManager = TTLManager() func applicationWillFinishLaunching(_ notification: Notification) { NSApp.setActivationPolicy(.accessory) } func applicationDidFinishLaunching(_ notification: Notification) { NSApp.setActivationPolicy(.accessory) self.statusBarController = StatusBarController(ttlManager: ttlManager) } } @main struct TetheringHiderApp: App { @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate var body: some Scene { Settings { EmptyView() } } }