From f06f097f276b4e10e5f611870f27ca5539dee22a Mon Sep 17 00:00:00 2001 From: Davide De Rosa Date: Fri, 17 Mar 2023 21:55:47 +0100 Subject: [PATCH] Add SwiftLint phase (#262) --- Passepartout.xcodeproj/project.pbxproj | 19 +++++ Passepartout/App/AppDelegate.swift | 4 +- .../App/Constants/Constants+App.swift | 58 +++++++------- Passepartout/App/Constants/Theme.swift | 72 +++++++++--------- Passepartout/App/Context/AppContext.swift | 20 ++--- .../PassepartoutProviders+Extensions.swift | 6 +- .../ProviderProfileAvailability.swift | 2 +- .../VPNProtocolType+FileExtensions.swift | 4 +- Passepartout/App/InApp/BuildProducts.swift | 4 +- Passepartout/App/InApp/LocalProduct.swift | 36 ++++----- Passepartout/App/InApp/ProductManager.swift | 54 ++++++------- .../Intents/IntentDispatcher+Activities.swift | 20 ++--- .../App/Intents/IntentDispatcher.swift | 36 ++++----- Passepartout/App/Intents/IntentsManager.swift | 14 ++-- Passepartout/App/Mac/MacBundle.swift | 10 +-- Passepartout/App/Mac/MacBundleDelegate.swift | 8 +- .../Models/DefaultLightProfileManager.swift | 16 ++-- .../Models/DefaultLightProviderManager.swift | 30 ++++---- .../App/Mac/Models/DefaultLightUtils.swift | 6 +- .../Mac/Models/DefaultLightVPNManager.swift | 22 +++--- .../App/Reusable/AddingTextField.swift | 8 +- .../App/Reusable/Binding+Extensions.swift | 8 +- .../App/Reusable/CopySavingButton.swift | 8 +- .../App/Reusable/DestructiveButton.swift | 4 +- .../App/Reusable/EditableTextList.swift | 28 +++---- .../App/Reusable/GenericCreditsView.swift | 40 +++++----- .../App/Reusable/GenericVersionView.swift | 8 +- .../App/Reusable/IntentActivity.swift | 2 +- Passepartout/App/Reusable/IntentAddView.swift | 4 +- .../App/Reusable/IntentEditView.swift | 4 +- .../App/Reusable/LongContentView.swift | 10 +-- .../App/Reusable/MailComposerView.swift | 18 ++--- .../App/Reusable/RevealingSecureField.swift | 12 +-- Passepartout/App/Reusable/Reviewer.swift | 14 ++-- Passepartout/App/Reusable/Shortcut.swift | 6 +- Passepartout/App/Reusable/StyledPicker.swift | 8 +- Passepartout/App/Reusable/Validators.swift | 10 +-- Passepartout/App/Views/AboutView.swift | 6 +- Passepartout/App/Views/AccountView.swift | 20 ++--- Passepartout/App/Views/AddHostView+Name.swift | 18 ++--- Passepartout/App/Views/AddHostViewModel.swift | 16 ++-- Passepartout/App/Views/AddProfileMenu.swift | 14 ++-- Passepartout/App/Views/AddProfileView.swift | 22 +++--- .../App/Views/AddProviderView+Name.swift | 12 +-- Passepartout/App/Views/AddProviderView.swift | 24 +++--- .../App/Views/AddProviderViewModel.swift | 22 +++--- Passepartout/App/Views/CreditsView.swift | 4 +- Passepartout/App/Views/DebugLogView.swift | 26 +++---- .../App/Views/DiagnosticsView+OpenVPN.swift | 16 ++-- .../App/Views/DiagnosticsView+WireGuard.swift | 4 +- Passepartout/App/Views/DiagnosticsView.swift | 10 +-- Passepartout/App/Views/DonateView.swift | 20 ++--- .../Views/EndpointAdvancedView+OpenVPN.swift | 26 +++---- .../EndpointAdvancedView+WireGuard.swift | 2 +- .../App/Views/EndpointView+OpenVPN.swift | 20 ++--- .../App/Views/EndpointView+WireGuard.swift | 2 +- Passepartout/App/Views/EndpointView.swift | 4 +- .../App/Views/NetworkSettingsView.swift | 18 ++--- .../App/Views/OnDemandView+SSID.swift | 14 ++-- Passepartout/App/Views/OnDemandView.swift | 6 +- .../App/Views/OrganizerView+ProfileRow.swift | 12 +-- .../App/Views/OrganizerView+Profiles.swift | 18 ++--- .../App/Views/OrganizerView+Scene.swift | 14 ++-- Passepartout/App/Views/OrganizerView.swift | 16 ++-- .../App/Views/PaywallView+Purchase.swift | 42 +++++----- Passepartout/App/Views/PaywallView.swift | 4 +- .../App/Views/ProfileView+Configuration.swift | 8 +- .../App/Views/ProfileView+Diagnostics.swift | 2 +- .../App/Views/ProfileView+Extra.swift | 4 +- .../App/Views/ProfileView+MainMenu.swift | 58 +++++++------- .../App/Views/ProfileView+Provider.swift | 14 ++-- .../App/Views/ProfileView+Rename.swift | 16 ++-- Passepartout/App/Views/ProfileView+VPN.swift | 10 +-- Passepartout/App/Views/ProfileView.swift | 24 +++--- .../App/Views/ProviderLocationView.swift | 38 +++++----- .../App/Views/ProviderPresetView.swift | 10 +-- Passepartout/App/Views/ReportIssueView.swift | 14 ++-- Passepartout/App/Views/SettingsView.swift | 8 +- .../App/Views/ShortcutsView+Add.swift | 10 +-- Passepartout/App/Views/ShortcutsView.swift | 34 ++++----- Passepartout/App/Views/VPNStatusText.swift | 6 +- Passepartout/App/Views/VPNToggle.swift | 20 ++--- Passepartout/App/Views/View+Extensions.swift | 8 +- .../AppShared/Context/CoreContext.swift | 24 +++--- Passepartout/AppShared/L10n/Core+L10n.swift | 16 ++-- .../AppShared/L10n/OpenVPN+L10n.swift | 26 +++---- .../AppShared/L10n/Providers+L10n.swift | 2 +- .../AppShared/L10n/TunnelKit+L10n.swift | 28 +++---- Passepartout/AppShared/L10n/Unlocalized.swift | 76 +++++++++---------- Passepartout/AppShared/Mac/MacBridge.swift | 4 +- Passepartout/AppShared/Mac/MacUtils.swift | 2 +- .../Mac/Models/LightProfileManager.swift | 12 +-- .../Mac/Models/LightProviderManager.swift | 10 +-- .../AppShared/Mac/Models/LightUtils.swift | 2 +- .../Mac/Models/LightVPNManager.swift | 20 ++--- Passepartout/AppShared/Menu/MenuBuilder.swift | 4 +- Passepartout/Launcher/AppDelegate.swift | 6 +- .../Mac/Constants/Constants+Mac.swift | 2 +- Passepartout/Mac/Constants/Theme.swift | 6 +- Passepartout/Mac/Mac/DefaultMacMenu.swift | 4 +- Passepartout/Mac/Mac/DefaultMacUtils.swift | 4 +- .../Mac/Menu/HostProfileItem+ViewModel.swift | 12 +-- Passepartout/Mac/Menu/HostProfileItem.swift | 6 +- .../Menu/LaunchOnLoginItem+ViewModel.swift | 10 +-- Passepartout/Mac/Menu/LaunchOnLoginItem.swift | 4 +- .../Menu/PassepartoutMenu+StatusButton.swift | 8 +- Passepartout/Mac/Menu/PassepartoutMenu.swift | 24 +++--- Passepartout/Mac/Menu/ProfileItemGroup.swift | 8 +- .../Menu/ProviderLocationItem+ViewModel.swift | 10 +-- .../Mac/Menu/ProviderLocationItem.swift | 8 +- .../Menu/ProviderProfileItem+ViewModel.swift | 14 ++-- .../Mac/Menu/ProviderProfileItem.swift | 14 ++-- .../Menu/ProviderServerItem+ViewModel.swift | 10 +-- .../Mac/Menu/ProviderServerItem.swift | 8 +- .../Mac/Menu/VPNItemGroup+ViewModel.swift | 16 ++-- Passepartout/Mac/Menu/VPNItemGroup.swift | 4 +- .../Mac/Menu/VisibilityItem+ViewModel.swift | 2 +- Passepartout/Mac/Menu/VisibilityItem.swift | 4 +- Passepartout/Mac/PassepartoutMac.swift | 4 +- .../ObservableProcessTransformer.swift | 8 +- .../Mac/Reusable/StaticSystemMenu.swift | 4 +- .../Mac/Reusable/TextItem+ViewModel.swift | 12 +-- Passepartout/Mac/Reusable/TextItem.swift | 18 ++--- .../Tunnel/OpenVPN/PacketTunnelProvider.swift | 2 +- PassepartoutLibrary/Package.swift | 2 +- .../Extensions/Host+Extensions.swift | 4 +- .../Extensions/Profile+Extensions.swift | 2 +- .../Extensions/Provider+Extensions.swift | 12 +-- .../Models/CredentialsPurpose.swift | 2 +- .../PassepartoutCore/Models/Network.swift | 44 +++++------ .../Models/Profile+Account.swift | 12 +-- .../Models/Profile+Header.swift | 14 ++-- .../Models/Profile+NetworkSettings.swift | 12 +-- .../Models/Profile+OnDemand.swift | 12 +-- .../Models/Profile+OpenVPNSettings.swift | 4 +- .../Models/Profile+Provider.swift | 12 +-- .../Models/Profile+WireGuardSettings.swift | 2 +- .../PassepartoutCore/Models/Profile.swift | 12 +-- .../Models/ProviderCategory.swift | 6 +- .../Models/ProviderLocation.swift | 8 +- .../Models/ProviderServer.swift | 24 +++--- .../Models/VPNProtocolType.swift | 4 +- .../PassepartoutCore/PassepartoutError.swift | 4 +- .../Extensions/DebugLog+Extensions.swift | 8 +- .../Managers/UpgradeManager+Migrations.swift | 64 ++++++++-------- .../Managers/UpgradeManager.swift | 12 +-- .../CDProfile+CoreDataProperties.swift | 3 +- .../Extensions/OpenVPNSettings+Network.swift | 10 +-- .../PassepartoutProfiles+Subtype.swift | 1 - .../PassepartoutProviders+TunnelKit.swift | 4 +- .../Extensions/Profile+Extensions.swift | 6 +- .../ProfileManager+Extensions.swift | 2 +- .../WireGuardSettings+Network.swift | 8 +- .../CoreDataProfileManagerStrategy.swift | 10 +-- .../Managers/PersistenceManager.swift | 6 +- .../Managers/ProfileManager+Keychain.swift | 4 +- .../Managers/ProfileManager.swift | 44 +++++------ .../Managers/ProfileManagerStrategy.swift | 6 +- .../Models/ObservableProfile.swift | 4 +- .../Repositories/ProfileMapper.swift | 12 +-- .../Repositories/ProfileRepository.swift | 6 +- .../CDInfrastructure+CoreDataProperties.swift | 3 +- ...structureCategory+CoreDataProperties.swift | 3 +- ...reDefaultSettings+CoreDataProperties.swift | 3 +- ...structureLocation+CoreDataProperties.swift | 3 +- ...rastructurePreset+CoreDataProperties.swift | 3 +- ...rastructureServer+CoreDataProperties.swift | 3 +- .../CDProvider+CoreDataProperties.swift | 3 +- .../Extensions/ProviderName+Credentials.swift | 2 +- .../Managers/ProviderManager.swift | 44 +++++------ .../ProviderManagerFetchPriority.swift | 4 +- .../Repositories/CategoryMapper.swift | 8 +- .../Repositories/DefaultSettingsMapper.swift | 2 +- .../Repositories/InfrastructureMapper.swift | 14 ++-- .../InfrastructureRepository.swift | 10 +-- .../Repositories/LocationMapper.swift | 8 +- .../Repositories/PresetMapper.swift | 6 +- .../Repositories/ProviderMapper.swift | 6 +- .../Repositories/ProviderRepository.swift | 6 +- .../Repositories/ServerMapper.swift | 14 ++-- .../Repositories/ServerRepository.swift | 4 +- .../DataModels/WSProviderCategory.swift | 10 +-- .../DataModels/WSProviderInfrastructure.swift | 12 +-- .../DataModels/WSProviderLocation.swift | 4 +- .../DataModels/WSProviderPreset.swift | 16 ++-- .../DataModels/WSProviderServer.swift | 18 ++--- .../DataModels/WSProvidersIndex.swift | 14 ++-- .../DataModels/WSVPNProtocol.swift | 2 +- .../DefaultWebServices.swift | 10 +-- .../WSProviderName+Extensions.swift | 4 +- .../PassepartoutServices/WebServices.swift | 10 +-- .../Reusable/FetchedValueHolder.swift | 8 +- .../Reusable/GenericWebResponse.swift | 6 +- .../Reusable/GenericWebServices.swift | 14 ++-- .../PassepartoutUtils/Reusable/InApp.swift | 46 +++++------ .../Reusable/KeyValueStore.swift | 2 +- .../Reusable/KeyedCache.swift | 12 +-- .../Reusable/LogManager.swift | 8 +- .../PassepartoutUtils/Reusable/Mapper.swift | 2 +- .../Reusable/Persistence.swift | 8 +- .../Reusable/RateLimited.swift | 4 +- .../Reusable/Repository.swift | 2 +- .../Reusable/SSIDReader.swift | 12 +-- .../Reusable/UserDefaultsStore.swift | 6 +- .../PassepartoutUtils/Utils/Utils+Async.swift | 2 +- .../Utils/Utils+FileManager.swift | 2 +- .../Utils/Utils+Logging.swift | 2 +- .../Utils/Utils+Network.swift | 6 +- .../PassepartoutUtils/Utils/Utils+URL.swift | 2 +- .../Extensions/OnDemand+Rules.swift | 2 +- .../OpenVPNSettings+VPNConfiguration.swift | 14 ++-- .../VPNProtocolType+Extensions.swift | 2 +- .../WireGuardSettings+VPNConfiguration.swift | 2 +- .../TunnelKitVPNManagerStrategy.swift | 52 ++++++------- .../Managers/VPNManager+Actions.swift | 4 +- .../Managers/VPNManager+Configuration.swift | 8 +- .../PassepartoutVPN/Managers/VPNManager.swift | 54 ++++++------- .../Managers/VPNManagerStrategy.swift | 6 +- .../Models/ObservableVPNState.swift | 2 +- .../Models/VPNConfiguration.swift | 8 +- .../Models/VPNPreferences.swift | 6 +- .../PassepartoutCoreTests/CoreTests.swift | 2 +- .../LibraryTests.swift | 2 +- .../ProvidersTests.swift | 10 +-- .../ServicesTests.swift | 2 +- .../PassepartoutUtilsTests/UtilsTests.swift | 8 +- .../Tests/PassepartoutVPNTests/VPNTests.swift | 2 +- 227 files changed, 1399 insertions(+), 1389 deletions(-) diff --git a/Passepartout.xcodeproj/project.pbxproj b/Passepartout.xcodeproj/project.pbxproj index 0dc5275e..23aea9c6 100644 --- a/Passepartout.xcodeproj/project.pbxproj +++ b/Passepartout.xcodeproj/project.pbxproj @@ -1047,6 +1047,7 @@ 0E41BDA828671339006346B4 /* Embed Launcher */, 0E3152B7223F9EF500F61841 /* Embed Plugins */, 0EB2B14B2733FB6F007705AB /* Embed Foundation Extensions */, + 0E1B5F5D29C5082700FE7D18 /* SwiftLint */, ); buildRules = ( ); @@ -1297,6 +1298,24 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 0E1B5F5D29C5082700FE7D18 /* SwiftLint */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = SwiftLint; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "if which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n"; + }; 0EADDC7227F0677F0093E303 /* Copy Core Data codegen */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; diff --git a/Passepartout/App/AppDelegate.swift b/Passepartout/App/AppDelegate.swift index ea1e4b00..f0e46acf 100644 --- a/Passepartout/App/AppDelegate.swift +++ b/Passepartout/App/AppDelegate.swift @@ -28,8 +28,8 @@ import UIKit class AppDelegate: NSObject, UIApplicationDelegate, ObservableObject { private let mac = MacBundle.shared - - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool { #if targetEnvironment(macCatalyst) mac.configure() mac.menu.install() diff --git a/Passepartout/App/Constants/Constants+App.swift b/Passepartout/App/Constants/Constants+App.swift index f13cae80..a6bcc540 100644 --- a/Passepartout/App/Constants/Constants+App.swift +++ b/Passepartout/App/Constants/Constants+App.swift @@ -44,7 +44,7 @@ extension Constants { Bundle.main.isTestFlight }() } - + enum Plugins { static let macBridgeName = "PassepartoutMac.bundle" } @@ -92,9 +92,9 @@ extension Constants { static let disableVPN = "DisableVPNIntent" static let connectVPN = "ConnectVPNIntent" - + static let moveToLocation = "MoveToLocationIntent" - + static let trustCellularNetwork = "TrustCellularNetworkIntent" static let trustCurrentNetwork = "TrustCurrentNetworkIntent" @@ -109,7 +109,7 @@ extension Constants { enum Domain { static let name = "passepartoutvpn.app" } - + enum Services { static let version = "v5" @@ -120,38 +120,38 @@ extension Constants { "https://www.facebook.com", "https://www.instagram.com" ] - + static let connectivityURL = URL(string: connectivityStrings.randomElement()!)! - + static let connectivityTimeout: TimeInterval = 10.0 } - + enum Persistence { static let profilesContainerName = "Profiles" static let providersContainerName = "Providers" } - + // milliseconds enum RateLimit { static let providerManager = 10000 - + static let vpnToggle = 500 } - + enum Log { enum App { static let url = containerURL(filename: "App.log") static let format = "$DHH:mm:ss.SSS$d $C$L$c $N.$F:$l - $M" } - + enum Tunnel { static let path = containerPath(filename: "Tunnel.log") static let format = "$DHH:mm:ss$d - $M" } - + private static let parentPath = "Library/Caches" static let level: SwiftyBeaver.Level = { @@ -160,9 +160,9 @@ extension Constants { } return .init(rawValue: levelNum) ?? .info }() - + static let maxBytes = 100000 - + static let refreshInterval: TimeInterval = 5.0 private static func containerURL(filename: String) -> URL { @@ -175,30 +175,30 @@ extension Constants { "\(parentPath)/\(filename)" } } - + enum URLs { static let readme = Repos.apple.appendingPathComponent("blob/master/README.md") - + static let changelog = Repos.apple.appendingPathComponent("blob/master/CHANGELOG.md") - + static let filetypes: [UTType] = [.item] static let website = URL(string: "https://\(Domain.name)")! - + static let faq = website.appendingPathComponent("faq") static let disclaimer = website.appendingPathComponent("disclaimer") static let privacyPolicy = website.appendingPathComponent("privacy") - + static let donate = website.appendingPathComponent("donate") - + static let subreddit = URL(string: "https://www.reddit.com/r/passepartout")! - + static let twitch = URL(string: "twitch://stream/keeshux")! - + static let twitchFallback = URL(string: "https://twitch.tv/keeshux")! - + static let githubSponsors = URL(string: "https://www.github.com/sponsors/passepartoutvpn")! } @@ -206,31 +206,31 @@ extension Constants { private static let githubRoot = URL(string: "https://github.com/passepartoutvpn/")! private static let githubRawRoot = URL(string: "https://\(Domain.name)/")! - + private static func github(repo: String) -> URL { githubRoot.appendingPathComponent(repo) } - + private static func githubRaw(repo: String) -> URL { githubRawRoot.appendingPathComponent(repo) } - + static let apple = github(repo: "passepartout-apple") - + static let api = githubRaw(repo: "api") } // milliseconds enum Delays { static let scrolling = 100 - + // @available(*, deprecated, message: "file importer stops showing again after closing with swipe down") static let xxxPresentFileImporter = 200 // @available(*, deprecated, message: "edited shortcut is outdated in delegate") static let xxxReloadEditedShortcut = 200 } - + enum Rating { #if targetEnvironment(macCatalyst) static let eventCount = 10 diff --git a/Passepartout/App/Constants/Theme.swift b/Passepartout/App/Constants/Theme.swift index 05aebf76..47dcd21d 100644 --- a/Passepartout/App/Constants/Theme.swift +++ b/Passepartout/App/Constants/Theme.swift @@ -30,7 +30,7 @@ extension View { var themeIdiom: UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom } - + var themeIsiPadPortrait: Bool { #if targetEnvironment(macCatalyst) false @@ -39,7 +39,7 @@ extension View { return device.userInterfaceIdiom == .pad && device.orientation.isPortrait #endif } - + var themeIsiPadMultitasking: Bool { #if targetEnvironment(macCatalyst) false @@ -128,15 +128,15 @@ extension View { fileprivate var themePrimaryBackgroundColor: Color { Color(Asset.Assets.primaryColor.color) } - + fileprivate var themeSecondaryColor: Color { .secondary } - + fileprivate var themeLightTextColor: Color { Color(Asset.Assets.lightTextColor.color) } - + fileprivate var themeErrorColor: Color { .red } @@ -160,11 +160,11 @@ extension View { var themeAssetsLogoImage: String { "Logo" } - + var themeCheckmarkImage: String { "checkmark" } - + var themeShareImage: String { "square.and.arrow.up" } @@ -172,11 +172,11 @@ extension View { var themeCopyImage: String { "doc.on.doc" } - + var themeCloseImage: String { "xmark" } - + var themeConceilImage: String { "eye.slash" } @@ -186,11 +186,11 @@ extension View { } // MARK: Organizer - + func themeAssetsProviderImage(_ providerName: ProviderName) -> String { "providers/\(providerName)" } - + func themeAssetsCountryImage(_ countryCode: String) -> String { "flags/\(countryCode.lowercased())" } @@ -198,15 +198,15 @@ extension View { var themeProviderImage: String { "externaldrive.connected.to.line.below" } - + var themeHostFilesImage: String { "folder" } - + var themeHostTextImage: String { "text.justify" } - + var themeSettingsImage: String { "gearshape" } @@ -222,11 +222,11 @@ extension View { var themeWriteReviewImage: String { "star" } - + var themeAddMenuImage: String { "plus" } - + var themeProfileActiveImage: String { "checkmark.circle" } @@ -257,19 +257,19 @@ extension View { "highlighter" // "character.cursor.ibeam" } - + var themeDuplicateImage: String { "doc.on.doc" } - + var themeUninstallImage: String { "arrow.uturn.down" } - + var themeDeleteImage: String { "trash" } - + var themeVPNProtocolImage: String { "bolt" // "waveform.path.ecg" @@ -277,36 +277,36 @@ extension View { // "pc" // "captions.bubble.fill" } - + var themeEndpointImage: String { "link" } - + var themeAccountImage: String { "person" } - + var themeProviderLocationImage: String { "location" } - + var themeProviderPresetImage: String { "slider.horizontal.3" } - + var themeNetworkSettingsImage: String { // "network" "globe" } - + var themeOnDemandImage: String { "wifi" } - + var themeDiagnosticsImage: String { "bandage.fill" } - + var themeFAQImage: String { "questionmark.diamond" } @@ -345,11 +345,11 @@ extension View { func themeSecondaryTextStyle() -> some View { foregroundColor(themeSecondaryColor) } - + func themeLightTextStyle() -> some View { foregroundColor(themeLightTextColor) } - + @available(iOS 15, *) func themePrimaryTintStyle() -> some View { tint(themePrimaryBackgroundColor) @@ -363,7 +363,7 @@ extension View { lineLimit(1) .truncationMode(.middle) } - + func themeRawTextStyle() -> some View { disableAutocorrection(true) .autocapitalization(.none) @@ -381,7 +381,7 @@ extension View { } // MARK: Animations - + extension View { func themeAnimation(on value: V) -> some View { animation(.default, value: value) @@ -416,7 +416,7 @@ extension View { } } } - + func themeSaveButtonLabel() -> some View { // themeCheckmarkImage.asSystemImage Text(L10n.Global.Strings.save) @@ -451,7 +451,7 @@ extension View { .foregroundColor(themeSecondaryColor) } } - + @ViewBuilder func themeErrorMessage(_ message: String?) -> some View { if let message = message { @@ -480,13 +480,13 @@ extension View { .keyboardType(.asciiCapable) .themeRawTextStyle() } - + func themeValidIPAddress(_ ipAddress: String?) -> some View { themeValidating(ipAddress, validator: Validators.ipAddress) .keyboardType(.numbersAndPunctuation) .themeRawTextStyle() } - + func themeValidSocketPort() -> some View { keyboardType(.numberPad) } diff --git a/Passepartout/App/Context/AppContext.swift b/Passepartout/App/Context/AppContext.swift index f964cb60..3aa58b02 100644 --- a/Passepartout/App/Context/AppContext.swift +++ b/Passepartout/App/Context/AppContext.swift @@ -30,20 +30,20 @@ import PassepartoutLibrary @MainActor class AppContext { let logManager: LogManager - + let productManager: ProductManager - + private let reviewer: Reviewer - + private var cancellables: Set = [] - + init(coreContext: CoreContext) { logManager = LogManager(logFile: Constants.Log.App.url) logManager.logLevel = Constants.Log.level logManager.logFormat = Constants.Log.App.format logManager.configureLogging() pp_log.info("Logging to: \(logManager.logFile!)") - + productManager = ProductManager( appType: Constants.InApp.appType, buildProducts: Constants.InApp.buildProducts @@ -51,12 +51,12 @@ class AppContext { reviewer = Reviewer() reviewer.eventCountBeforeRating = Constants.Rating.eventCount - + // post - + configureObjects(coreContext: coreContext) } - + private func configureObjects(coreContext: CoreContext) { coreContext.vpnManager.isOnDemandRulesSupported = { self.isEligibleForOnDemandRules() @@ -81,7 +81,7 @@ class AppContext { } }.store(in: &cancellables) } - + // eligibility: ignore network settings if ineligible private func isEligibleForNetworkSettings() -> Bool { guard productManager.isEligible(forFeature: .networkSettings) else { @@ -90,7 +90,7 @@ class AppContext { } return true } - + // eligibility: reset on-demand rules if no trusted networks private func isEligibleForOnDemandRules() -> Bool { guard productManager.isEligible(forFeature: .trustedNetworks) else { diff --git a/Passepartout/App/Extensions/PassepartoutProviders+Extensions.swift b/Passepartout/App/Extensions/PassepartoutProviders+Extensions.swift index 56ae44b8..1569d224 100644 --- a/Passepartout/App/Extensions/PassepartoutProviders+Extensions.swift +++ b/Passepartout/App/Extensions/PassepartoutProviders+Extensions.swift @@ -38,7 +38,7 @@ extension ProviderMetadata: Identifiable, Comparable, Hashable { public static func <(lhs: Self, rhs: Self) -> Bool { lhs.fullName.lowercased() < rhs.fullName.lowercased() } - + public func hash(into hasher: inout Hasher) { hasher.combine(name) } @@ -68,7 +68,7 @@ extension ProviderServer: Comparable { public static func ==(lhs: Self, rhs: Self) -> Bool { lhs.id == rhs.id } - + // "Default" comes first (nil localizedName) public static func <(lhs: Self, rhs: Self) -> Bool { guard lhs.localizedName != rhs.localizedName else { @@ -113,7 +113,7 @@ extension ProviderMetadata { } return URL(string: string) } - + var referralURL: URL? { guard let string = Constants.URLs.referrals[name] else { return nil diff --git a/Passepartout/App/Extensions/ProviderProfileAvailability.swift b/Passepartout/App/Extensions/ProviderProfileAvailability.swift index 3194cfd3..04e55bfc 100644 --- a/Passepartout/App/Extensions/ProviderProfileAvailability.swift +++ b/Passepartout/App/Extensions/ProviderProfileAvailability.swift @@ -28,7 +28,7 @@ import PassepartoutLibrary protocol ProviderProfileAvailability { var profile: Profile { get } - + var providerManager: ProviderManager { get } } diff --git a/Passepartout/App/Extensions/VPNProtocolType+FileExtensions.swift b/Passepartout/App/Extensions/VPNProtocolType+FileExtensions.swift index 8b32709f..b148c71f 100644 --- a/Passepartout/App/Extensions/VPNProtocolType+FileExtensions.swift +++ b/Passepartout/App/Extensions/VPNProtocolType+FileExtensions.swift @@ -31,12 +31,12 @@ extension VPNProtocolType { let protos: [Self] = [.openVPN, .wireGuard] return protos.map(\.fileExtension) }() - + var fileExtension: String { switch self { case .openVPN: return "ovpn" - + case .wireGuard: return "conf" } diff --git a/Passepartout/App/InApp/BuildProducts.swift b/Passepartout/App/InApp/BuildProducts.swift index fbbef856..75871244 100644 --- a/Passepartout/App/InApp/BuildProducts.swift +++ b/Passepartout/App/InApp/BuildProducts.swift @@ -27,11 +27,11 @@ import Foundation struct BuildProducts { private let productsAtBuild: (Int) -> [LocalProduct] - + init(productsAtBuild: @escaping (Int) -> [LocalProduct]) { self.productsAtBuild = productsAtBuild } - + func products(atBuild build: Int) -> [LocalProduct] { productsAtBuild(build) } diff --git a/Passepartout/App/InApp/LocalProduct.swift b/Passepartout/App/InApp/LocalProduct.swift index bb10c1b1..226d1e5e 100644 --- a/Passepartout/App/InApp/LocalProduct.swift +++ b/Passepartout/App/InApp/LocalProduct.swift @@ -33,13 +33,13 @@ struct LocalProduct: RawRepresentable, Equatable, Hashable { private static let bundle = "com.algoritmico.\(bundleSubdomain).Passepartout" private static let donationsBundle = "\(bundle).donations" - + private static let featuresBundle = "\(bundle).features" - + static let providersBundle = "\(bundle).providers" - + // MARK: Donations - + static let tinyDonation = LocalProduct(donationDescription: "Tiny") static let smallDonation = LocalProduct(donationDescription: "Small") @@ -51,7 +51,7 @@ struct LocalProduct: RawRepresentable, Equatable, Hashable { static let hugeDonation = LocalProduct(donationDescription: "Huge") static let maxiDonation = LocalProduct(donationDescription: "Maxi") - + static let allDonations: [LocalProduct] = [ .tinyDonation, .smallDonation, @@ -66,9 +66,9 @@ struct LocalProduct: RawRepresentable, Equatable, Hashable { } // MARK: Features - + static let allProviders = LocalProduct(featureId: "all_providers") - + static let networkSettings = LocalProduct(featureId: "network_settings") static let trustedNetworks = LocalProduct(featureId: "trusted_networks") @@ -76,7 +76,7 @@ struct LocalProduct: RawRepresentable, Equatable, Hashable { static let siriShortcuts = LocalProduct(featureId: "siri") static let fullVersion_iOS = LocalProduct(featureId: "full_version") - + static let fullVersion_macOS = LocalProduct(featureId: "full_mac_version") static let fullVersion = LocalProduct(featureId: "full_multi_version") @@ -100,7 +100,7 @@ struct LocalProduct: RawRepresentable, Equatable, Hashable { static var all: [LocalProduct] { allDonations + allFeatures// + allProviders } - + var isDonation: Bool { rawValue.hasPrefix(LocalProduct.donationsBundle) } @@ -112,11 +112,11 @@ struct LocalProduct: RawRepresentable, Equatable, Hashable { var isProvider: Bool { rawValue.hasPrefix(LocalProduct.providersBundle) } - + // MARK: RawRepresentable - + let rawValue: String - + init?(rawValue: String) { self.rawValue = rawValue } @@ -140,22 +140,22 @@ private extension ProviderName { switch self { case .mullvad: return "Mullvad" - + case .nordvpn: return "NordVPN" - + case .pia: return "PIA" - + case .protonvpn: return "ProtonVPN" - + case .tunnelbear: return "TunnelBear" - + case .vyprvpn: return "VyprVPN" - + case .windscribe: return "Windscribe" diff --git a/Passepartout/App/InApp/ProductManager.swift b/Passepartout/App/InApp/ProductManager.swift index d3aec9b4..c728c94c 100644 --- a/Passepartout/App/InApp/ProductManager.swift +++ b/Passepartout/App/InApp/ProductManager.swift @@ -31,7 +31,7 @@ import Combine enum ProductError: Error { case uneligible - + case beta } @@ -40,30 +40,30 @@ class ProductManager: NSObject, ObservableObject { case freemium = 0 case beta = 1 - + case fullVersion = 2 } - + let appType: AppType - + let buildProducts: BuildProducts - + let didRefundProducts = PassthroughSubject() - + @Published private(set) var isRefreshingProducts = false @Published private(set) var products: [SKProduct] // - + private let inApp: InApp - + private var purchasedAppBuild: Int? - + private var purchasedFeatures: Set - + private var purchaseDates: [LocalProduct: Date] - + private var cancelledPurchases: Set? { willSet { guard cancelledPurchases != nil else { @@ -76,20 +76,20 @@ class ProductManager: NSObject, ObservableObject { detectRefunds(newCancelledPurchases) } } - + private var refreshRequest: SKReceiptRefreshRequest? - + init(appType: AppType, buildProducts: BuildProducts) { self.appType = appType self.buildProducts = buildProducts - + products = [] inApp = InApp() purchasedAppBuild = nil purchasedFeatures = [] purchaseDates = [:] cancelledPurchases = nil - + super.init() reloadReceipt() @@ -97,15 +97,15 @@ class ProductManager: NSObject, ObservableObject { refreshProducts() } - + deinit { SKPaymentQueue.default().remove(self) } - + func canMakePayments() -> Bool { SKPaymentQueue.canMakePayments() } - + func refreshProducts() { let ids = LocalProduct.all guard !ids.isEmpty else { @@ -130,7 +130,7 @@ class ProductManager: NSObject, ObservableObject { func product(withIdentifier identifier: LocalProduct) -> SKProduct? { inApp.product(withIdentifier: identifier) } - + func featureProducts(including: [LocalProduct]) -> [SKProduct] { inApp.products.filter { guard let p = LocalProduct(rawValue: $0.productIdentifier) else { @@ -145,7 +145,7 @@ class ProductManager: NSObject, ObservableObject { return true } } - + func featureProducts(excluding: [LocalProduct]) -> [SKProduct] { inApp.products.filter { guard let p = LocalProduct(rawValue: $0.productIdentifier) else { @@ -160,7 +160,7 @@ class ProductManager: NSObject, ObservableObject { return true } } - + func purchase(_ product: SKProduct, completionHandler: @escaping (Result) -> Void) { inApp.purchase(product: product) { result in if case .success = result { @@ -171,7 +171,7 @@ class ProductManager: NSObject, ObservableObject { } } } - + func restorePurchases(completionHandler: @escaping (Error?) -> Void) { inApp.restorePurchases { (finished, _, error) in guard finished else { @@ -184,7 +184,7 @@ class ProductManager: NSObject, ObservableObject { } // MARK: In-app eligibility - + private func isCurrentPlatformVersion() -> Bool { purchasedFeatures.contains(isMac ? .fullVersion_macOS : .fullVersion_iOS) } @@ -222,7 +222,7 @@ class ProductManager: NSObject, ObservableObject { func isEligibleForFeedback() -> Bool { appType == .beta || !purchasedFeatures.isEmpty } - + func hasPurchased(_ product: LocalProduct) -> Bool { purchasedFeatures.contains(product) } @@ -257,7 +257,7 @@ class ProductManager: NSObject, ObservableObject { } if let iapReceipts = receipt.inAppPurchaseReceipts { purchaseDates.removeAll() - + pp_log.debug("In-app receipts:") iapReceipts.forEach { guard let pid = $0.productIdentifier, let product = LocalProduct(rawValue: pid) else { @@ -296,7 +296,7 @@ extension ProductManager { let isEligibleForFullVersion = isFullVersion() let hasCancelledFullVersion: Bool let hasCancelledTrustedNetworks: Bool - + if isMac { hasCancelledFullVersion = !isEligibleForFullVersion && ( refunds.contains(.fullVersion) || refunds.contains(.fullVersion_macOS) @@ -308,7 +308,7 @@ extension ProductManager { ) hasCancelledTrustedNetworks = !isEligibleForFullVersion && refunds.contains(.trustedNetworks) } - + // review features and potentially revert them if they were used (Siri is handled in AppDelegate) if hasCancelledFullVersion || hasCancelledTrustedNetworks { didRefundProducts.send() diff --git a/Passepartout/App/Intents/IntentDispatcher+Activities.swift b/Passepartout/App/Intents/IntentDispatcher+Activities.swift index 2029742e..6f4ebc14 100644 --- a/Passepartout/App/Intents/IntentDispatcher+Activities.swift +++ b/Passepartout/App/Intents/IntentDispatcher+Activities.swift @@ -36,10 +36,10 @@ extension IntentDispatcher { case activeAndConnected(UUID) } - + typealias VPNIntentActivity = IntentActivity - static let enableVPN = VPNIntentActivity(name: Constants.Activities.enableVPN) { activity, vpnManager in + static let enableVPN = VPNIntentActivity(name: Constants.Activities.enableVPN) { _, vpnManager in pp_log.info("Enabling VPN...") Task { @@ -51,7 +51,7 @@ extension IntentDispatcher { } } - static let disableVPN = VPNIntentActivity(name: Constants.Activities.disableVPN) { activity, vpnManager in + static let disableVPN = VPNIntentActivity(name: Constants.Activities.disableVPN) { _, vpnManager in pp_log.info("Disabling VPN...") Task { @@ -81,7 +81,7 @@ extension IntentDispatcher { } } } - + static let moveToLocation = VPNIntentActivity(name: Constants.Activities.moveToLocation) { activity, vpnManager in pp_log.info("Moving to VPN location...") @@ -110,27 +110,27 @@ extension IntentDispatcher { } } } - - static let trustCellularNetwork = VPNIntentActivity(name: Constants.Activities.trustCellularNetwork) { activity, vpnManager in + + static let trustCellularNetwork = VPNIntentActivity(name: Constants.Activities.trustCellularNetwork) { _, vpnManager in pp_log.info("Trusting mobile network...") handleCellularNetwork(true, vpnManager) } - static let trustCurrentNetwork = VPNIntentActivity(name: Constants.Activities.trustCurrentNetwork) { activity, vpnManager in + static let trustCurrentNetwork = VPNIntentActivity(name: Constants.Activities.trustCurrentNetwork) { _, vpnManager in pp_log.info("Trusting current Wi-Fi...") handleCurrentNetwork(true, vpnManager) } - static let untrustCellularNetwork = VPNIntentActivity(name: Constants.Activities.untrustCellularNetwork) { activity, vpnManager in + static let untrustCellularNetwork = VPNIntentActivity(name: Constants.Activities.untrustCellularNetwork) { _, vpnManager in pp_log.info("Untrusting mobile network...") handleCellularNetwork(false, vpnManager) } - static let untrustCurrentNetwork = VPNIntentActivity(name: Constants.Activities.untrustCurrentNetwork) { activity, vpnManager in + static let untrustCurrentNetwork = VPNIntentActivity(name: Constants.Activities.untrustCurrentNetwork) { _, vpnManager in pp_log.info("Untrusting current Wi-Fi...") handleCurrentNetwork(false, vpnManager) } - + private static func handleCellularNetwork(_ trust: Bool, _ vpnManager: VPNManager) { Task { do { diff --git a/Passepartout/App/Intents/IntentDispatcher.swift b/Passepartout/App/Intents/IntentDispatcher.swift index 5f2e0d43..e94991d3 100644 --- a/Passepartout/App/Intents/IntentDispatcher.swift +++ b/Passepartout/App/Intents/IntentDispatcher.swift @@ -30,19 +30,19 @@ import PassepartoutLibrary class IntentDispatcher { private struct Groups { static let vpn = "VPN" - + static let trust = "Trust" } - + // MARK: Intents - + static func intentConnect(header: Profile.Header) -> ConnectVPNIntent { let intent = ConnectVPNIntent() intent.profileId = header.id.uuidString intent.profileName = header.name return intent } - + static func intentMoveTo(header: Profile.Header, providerFullName: String, server: ProviderServer) -> MoveToLocationIntent { let intent = MoveToLocationIntent() intent.profileId = header.id.uuidString @@ -51,33 +51,33 @@ class IntentDispatcher { intent.serverName = server.localizedLongDescription(withCategory: false) return intent } - + static func intentEnable() -> EnableVPNIntent { EnableVPNIntent() } - + static func intentDisable() -> DisableVPNIntent { DisableVPNIntent() } - + static func intentTrustWiFi() -> TrustCurrentNetworkIntent { TrustCurrentNetworkIntent() } - + static func intentUntrustWiFi() -> UntrustCurrentNetworkIntent { UntrustCurrentNetworkIntent() } - + static func intentTrustCellular() -> TrustCellularNetworkIntent { TrustCellularNetworkIntent() } - + static func intentUntrustCellular() -> UntrustCellularNetworkIntent { UntrustCellularNetworkIntent() } // MARK: Donations - + static func donateConnection(with profile: Profile, providerManager: ProviderManager) { let genericIntent: INIntent if let providerName = profile.header.providerName { @@ -93,24 +93,24 @@ class IntentDispatcher { } else { genericIntent = intentConnect(header: profile.header) } - + let interaction = INInteraction(intent: genericIntent, response: nil) interaction.groupIdentifier = profile.id.uuidString interaction.donateAndLog() } - + static func donateEnableVPN() { let interaction = INInteraction(intent: intentEnable(), response: nil) interaction.groupIdentifier = Groups.vpn interaction.donateAndLog() } - + static func donateDisableVPN() { let interaction = INInteraction(intent: intentDisable(), response: nil) interaction.groupIdentifier = Groups.vpn interaction.donateAndLog() } - + static func donateTrustCurrentNetwork() { let interaction = INInteraction(intent: intentTrustWiFi(), response: nil) interaction.groupIdentifier = Groups.trust @@ -122,19 +122,19 @@ class IntentDispatcher { interaction.groupIdentifier = Groups.trust interaction.donateAndLog() } - + static func donateTrustCellularNetwork() { let interaction = INInteraction(intent: intentTrustCellular(), response: nil) interaction.groupIdentifier = Groups.trust interaction.donateAndLog() } - + static func donateUntrustCellularNetwork() { let interaction = INInteraction(intent: intentUntrustCellular(), response: nil) interaction.groupIdentifier = Groups.trust interaction.donateAndLog() } - + static func forgetProfile(withHeader header: Profile.Header) { INInteraction.delete(with: header.id.uuidString) { (error) in if let error = error { diff --git a/Passepartout/App/Intents/IntentsManager.swift b/Passepartout/App/Intents/IntentsManager.swift index 3ab16070..97decaa4 100644 --- a/Passepartout/App/Intents/IntentsManager.swift +++ b/Passepartout/App/Intents/IntentsManager.swift @@ -32,20 +32,20 @@ import PassepartoutLibrary @MainActor class IntentsManager: NSObject, ObservableObject { @Published private(set) var isReloadingShortcuts = false - + @Published private(set) var shortcuts: [UUID: Shortcut] = [:] - + let shouldDismissIntentView = PassthroughSubject() - + private var continuation: CheckedContinuation<[INVoiceShortcut], Never>? - + override init() { super.init() Task { await reloadShortcuts() } } - + func reloadShortcuts() async { isReloadingShortcuts = true do { @@ -81,10 +81,10 @@ extension IntentsManager: INUIEditVoiceShortcutViewControllerDelegate { guard let vs = voiceShortcut else { return } - + shortcuts[vs.identifier] = Shortcut(vs) shouldDismissIntentView.send() - + // XXX: iOS bug, vs.invocationPhrase here is still the old one before edit // // additionally, back from edit view controller does not trigger either onAppear or diff --git a/Passepartout/App/Mac/MacBundle.swift b/Passepartout/App/Mac/MacBundle.swift index 9ce4b5cb..13e1c4f7 100644 --- a/Passepartout/App/Mac/MacBundle.swift +++ b/Passepartout/App/Mac/MacBundle.swift @@ -27,11 +27,11 @@ import Foundation class MacBundle { static let shared = MacBundle() - + private var bridge: MacBridge! - + private lazy var bridgeDelegate = MacBundleDelegate(bundle: self) - + @MainActor func configure() { guard let bundleURL = Bundle.main.builtInPlugInsURL?.appendingPathComponent(Constants.Plugins.macBridgeName) else { @@ -46,11 +46,11 @@ class MacBundle { bridge = bridgeClass.init() bridge.menu.delegate = bridgeDelegate } - + var utils: MacUtils { bridge.utils } - + var menu: MacMenu { bridge.menu } diff --git a/Passepartout/App/Mac/MacBundleDelegate.swift b/Passepartout/App/Mac/MacBundleDelegate.swift index c943322e..72e1e139 100644 --- a/Passepartout/App/Mac/MacBundleDelegate.swift +++ b/Passepartout/App/Mac/MacBundleDelegate.swift @@ -27,17 +27,17 @@ import Foundation class MacBundleDelegate: MacMenuDelegate { private weak var bundle: MacBundle? - + @MainActor var profileManager: LightProfileManager { DefaultLightProfileManager() } - + @MainActor var providerManager: LightProviderManager { DefaultLightProviderManager() } - + @MainActor var vpnManager: LightVPNManager { DefaultLightVPNManager() @@ -46,7 +46,7 @@ class MacBundleDelegate: MacMenuDelegate { var utils: LightUtils { DefaultLightUtils() } - + init(bundle: MacBundle?) { self.bundle = bundle } diff --git a/Passepartout/App/Mac/Models/DefaultLightProfileManager.swift b/Passepartout/App/Mac/Models/DefaultLightProfileManager.swift index d0e1cd69..780c4b10 100644 --- a/Passepartout/App/Mac/Models/DefaultLightProfileManager.swift +++ b/Passepartout/App/Mac/Models/DefaultLightProfileManager.swift @@ -29,17 +29,17 @@ import Combine class DefaultLightProfile: LightProfile { let id: UUID - + let name: String - + let vpnProtocol: String let isActive: Bool - + let providerName: String? let providerServer: LightProviderServer? - + init(_ header: Profile.Header, vpnProtocol: String, isActive: Bool, providerServer: LightProviderServer?) { id = header.id name = header.name @@ -52,11 +52,11 @@ class DefaultLightProfile: LightProfile { class DefaultLightProfileManager: LightProfileManager { private let profileManager = ProfileManager.shared - + private let providerManager = ProviderManager.shared - + private var subscriptions: Set = [] - + weak var delegate: LightProfileManagerDelegate? init() { @@ -66,7 +66,7 @@ class DefaultLightProfileManager: LightProfileManager { self.delegate?.didUpdateProfiles() }.store(in: &subscriptions) } - + var hasProfiles: Bool { profileManager.hasProfiles } diff --git a/Passepartout/App/Mac/Models/DefaultLightProviderManager.swift b/Passepartout/App/Mac/Models/DefaultLightProviderManager.swift index 6640cb82..799163ab 100644 --- a/Passepartout/App/Mac/Models/DefaultLightProviderManager.swift +++ b/Passepartout/App/Mac/Models/DefaultLightProviderManager.swift @@ -29,9 +29,9 @@ import PassepartoutLibrary class DefaultLightProviderCategory: LightProviderCategory { let name: String - + var locations: [LightProviderLocation] - + init(_ category: ProviderCategory) { name = category.name locations = category.locations @@ -42,13 +42,13 @@ class DefaultLightProviderCategory: LightProviderCategory { class DefaultLightProviderLocation: LightProviderLocation { let description: String - + let id: String - + let countryCode: String - + let servers: [LightProviderServer] - + init(_ location: ProviderLocation) { description = location.localizedCountry id = location.id @@ -61,15 +61,15 @@ class DefaultLightProviderLocation: LightProviderLocation { class DefaultLightProviderServer: LightProviderServer { let description: String - + let longDescription: String - + let categoryName: String - + let locationId: String - + let serverId: String - + init(_ server: ProviderServer) { description = server.localizedShortDescriptionWithDefault longDescription = server.localizedLongDescription(withCategory: false) @@ -81,11 +81,11 @@ class DefaultLightProviderServer: LightProviderServer { class DefaultLightProviderManager: LightProviderManager { private let providerManager = ProviderManager.shared - + private var subscriptions: Set = [] - + weak var delegate: LightProviderManagerDelegate? - + init() { providerManager.didUpdateProviders .receive(on: DispatchQueue.main) @@ -93,7 +93,7 @@ class DefaultLightProviderManager: LightProviderManager { self.delegate?.didUpdateProviders() }.store(in: &subscriptions) } - + func categories(_ name: String, vpnProtocol: String) -> [LightProviderCategory] { guard let vpnProtocolType = VPNProtocolType(rawValue: vpnProtocol) else { fatalError("Unrecognized VPN protocol: \(vpnProtocol)") diff --git a/Passepartout/App/Mac/Models/DefaultLightUtils.swift b/Passepartout/App/Mac/Models/DefaultLightUtils.swift index 9abdc1b5..de47b660 100644 --- a/Passepartout/App/Mac/Models/DefaultLightUtils.swift +++ b/Passepartout/App/Mac/Models/DefaultLightUtils.swift @@ -28,18 +28,18 @@ import SwiftUI class DefaultLightUtils: LightUtils { private let app: UIApplication - + init() { app = .shared } - + @AppStorage(AppPreference.launchesOnLogin.key) var launchesOnLogin = false func requestScene() { guard app.connectedScenes.isEmpty else { return } - app.requestSceneSessionActivation(nil, userActivity: nil, options: nil) { error in + app.requestSceneSessionActivation(nil, userActivity: nil, options: nil) { _ in // } } diff --git a/Passepartout/App/Mac/Models/DefaultLightVPNManager.swift b/Passepartout/App/Mac/Models/DefaultLightVPNManager.swift index cfa11263..3fb9dacf 100644 --- a/Passepartout/App/Mac/Models/DefaultLightVPNManager.swift +++ b/Passepartout/App/Mac/Models/DefaultLightVPNManager.swift @@ -29,17 +29,17 @@ import Combine class DefaultLightVPNManager: LightVPNManager { private let vpnManager = VPNManager.shared - + private var subscriptions: Set = [] - + var isEnabled: Bool { vpnManager.currentState.isEnabled } - + var vpnStatus: LightVPNStatus { vpnManager.currentState.vpnStatus.asLightVPNStatus } - + private var delegates: [String: LightVPNManagerDelegate] = [:] init() { @@ -63,7 +63,7 @@ class DefaultLightVPNManager: LightVPNManager { ) }.store(in: &subscriptions) } - + func connect(with profileId: UUID) { Task { try? await vpnManager.connect(with: profileId) @@ -75,7 +75,7 @@ class DefaultLightVPNManager: LightVPNManager { try? await vpnManager.connect(with: profileId, toServer: serverId) } } - + func disconnect() { Task { await vpnManager.disable() @@ -97,11 +97,11 @@ class DefaultLightVPNManager: LightVPNManager { await vpnManager.reconnect() } } - + func addDelegate(_ delegate: LightVPNManagerDelegate, withIdentifier identifier: String) { delegates[identifier] = delegate } - + func removeDelegate(withIdentifier identifier: String) { delegates.removeValue(forKey: identifier) } @@ -120,13 +120,13 @@ private extension VPNStatus { switch self { case .connected: return .connected - + case .connecting: return .connecting - + case .disconnected: return .disconnected - + case .disconnecting: return .disconnecting } diff --git a/Passepartout/App/Reusable/AddingTextField.swift b/Passepartout/App/Reusable/AddingTextField.swift index b35d5ae3..96990837 100644 --- a/Passepartout/App/Reusable/AddingTextField.swift +++ b/Passepartout/App/Reusable/AddingTextField.swift @@ -33,9 +33,9 @@ struct AddingTextField: View { let textField: (@escaping () -> Void) -> Field let addLabel: () -> ActionLabel - + var commitLabel: (() -> ActionLabel)? - + @State private var isAdding = false var body: some View { @@ -51,14 +51,14 @@ struct AddingTextField: View { } } } - + private func doAdd() { withAnimation { onAdd?() isAdding = true } } - + private func doCommit() { withAnimation { onCommit?() diff --git a/Passepartout/App/Reusable/Binding+Extensions.swift b/Passepartout/App/Reusable/Binding+Extensions.swift index f46b2d20..9ab401f7 100644 --- a/Passepartout/App/Reusable/Binding+Extensions.swift +++ b/Passepartout/App/Reusable/Binding+Extensions.swift @@ -25,7 +25,7 @@ import SwiftUI -func ??(lhs: Binding>, rhs: T) -> Binding { +func ??(lhs: Binding, rhs: T) -> Binding { Binding { lhs.wrappedValue ?? rhs } set: { @@ -34,15 +34,15 @@ func ??(lhs: Binding>, rhs: T) -> Binding { } extension Binding { - func toString() -> Binding where Value == Optional { + func toString() -> Binding where Value == URL? { .init { wrappedValue?.absoluteString ?? "" } set: { wrappedValue = URL(string: $0) ?? wrappedValue } } - - func toString() -> Binding where Value == Optional, T: FixedWidthInteger { + + func toString() -> Binding where Value == T?, T: FixedWidthInteger { .init { guard let v = wrappedValue else { return "" diff --git a/Passepartout/App/Reusable/CopySavingButton.swift b/Passepartout/App/Reusable/CopySavingButton.swift index 55aeff63..4dd74919 100644 --- a/Passepartout/App/Reusable/CopySavingButton.swift +++ b/Passepartout/App/Reusable/CopySavingButton.swift @@ -29,17 +29,17 @@ struct CopySavingButton: View { @Binding var original: T @Binding var copy: T - + var mapping: (T) -> T - + let label: () -> Label var saveAnyway = false var onSave: (() -> Void)? - + @State private var isLoaded = false - + var body: some View { Button(action: saveToOriginal, label: label) .disabled(!canSave) diff --git a/Passepartout/App/Reusable/DestructiveButton.swift b/Passepartout/App/Reusable/DestructiveButton.swift index 7cf1c5fc..da4661e7 100644 --- a/Passepartout/App/Reusable/DestructiveButton.swift +++ b/Passepartout/App/Reusable/DestructiveButton.swift @@ -27,9 +27,9 @@ import SwiftUI struct DestructiveButton: View { let action: () -> Void - + let label: () -> Label - + var body: some View { if #available(iOS 15, *) { Button(role: .destructive, action: action, label: label) diff --git a/Passepartout/App/Reusable/EditableTextList.swift b/Passepartout/App/Reusable/EditableTextList.swift index c78c27fe..0539d84b 100644 --- a/Passepartout/App/Reusable/EditableTextList.swift +++ b/Passepartout/App/Reusable/EditableTextList.swift @@ -38,21 +38,21 @@ struct EditableTextList: View { onEditingChanged: (Bool) -> Void, onCommit: () -> Void ) - + @Binding var elements: [String] var allowsDuplicates = true - + var mapping: ([IdentifiableString]) -> [IdentifiableString] = { $0 } - + var onAdd: ((Binding) -> Void)? - + let textField: (FieldCallback) -> Field let addLabel: () -> ActionLabel - + var commitLabel: (() -> ActionLabel)? - + @State private var isLoaded = false @State private var identifiableElements: [IdentifiableString] = [] @@ -60,7 +60,7 @@ struct EditableTextList: View { @State private var editedTextStrings: [UUID: String] = [:] private let addedUUID = UUID() - + private var addedText: Binding { .init { editedTextStrings[addedUUID] ?? "" @@ -68,7 +68,7 @@ struct EditableTextList: View { editedTextStrings[addedUUID] = $0 } } - + var body: some View { debugChanges() return Group { @@ -87,7 +87,7 @@ struct EditableTextList: View { } }.onChange(of: elements, perform: remapElements) } - + private func existingRow(_ element: IdentifiableString) -> some View { let editedText = binding(toEditedElement: element) @@ -100,7 +100,7 @@ struct EditableTextList: View { replaceElement(at: element.id, with: editedText) })) } - + private var newRow: some View { AddingTextField( onAdd: { @@ -144,7 +144,7 @@ extension EditableTextList { identifiableElements = newIdentifiableElements } } - + private func addElement() { guard allowsDuplicates || !identifiableElements.contains(where: { $0.string == addedText.wrappedValue @@ -155,7 +155,7 @@ extension EditableTextList { identifiableElements.append(.init(string: addedText.wrappedValue)) commit() } - + private func binding(toEditedElement element: IdentifiableString) -> Binding { // print(">>> <-> \(element)") .init { @@ -184,14 +184,14 @@ extension EditableTextList { } commit() } - + private func onDelete(offsets: IndexSet) { var mapped = mapping(identifiableElements) mapped.remove(atOffsets: offsets) identifiableElements = mapped commit() } - + private func onMove(indexSet: IndexSet, to: Int) { var mapped = mapping(identifiableElements) mapped.move(fromOffsets: indexSet, toOffset: to) diff --git a/Passepartout/App/Reusable/GenericCreditsView.swift b/Passepartout/App/Reusable/GenericCreditsView.swift index de7c5a7d..043b72b3 100644 --- a/Passepartout/App/Reusable/GenericCreditsView.swift +++ b/Passepartout/App/Reusable/GenericCreditsView.swift @@ -27,23 +27,23 @@ import SwiftUI struct GenericCreditsView: View { typealias License = (String, String, URL) - + typealias Notice = (String, String) - + var licensesHeader: String? = "Licenses" - + var noticesHeader: String? = "Notices" - + var translationsHeader: String? = "Translations" - + let licenses: [License] - + let notices: [Notice] - + let translations: [String: String] - + @State private var contentForLicense: [String: String] = [:] - + var body: some View { List { if !licenses.isEmpty { @@ -57,27 +57,27 @@ struct GenericCreditsView: View { } } } - + private var sortedLicenses: [License] { licenses.sorted { $0.0.lowercased() < $1.0.lowercased() } } - + private var sortedNotices: [Notice] { notices.sorted { $0.0.lowercased() < $1.0.lowercased() } } - + private var sortedLanguages: [String] { translations.keys.sorted { $0.localizedAsCountryCode < $1.localizedAsCountryCode } } - + private var licensesSection: some View { - Section ( + Section( header: licensesHeader.map(Text.init) ) { ForEach(sortedLicenses, id: \.0) { license in @@ -98,7 +98,7 @@ struct GenericCreditsView: View { } private var noticesSection: some View { - Section ( + Section( header: noticesHeader.map(Text.init) ) { ForEach(sortedNotices, id: \.0) { notice in @@ -108,7 +108,7 @@ struct GenericCreditsView: View { } private var translationsSection: some View { - Section ( + Section( header: translationsHeader.map(Text.init) ) { ForEach(sortedLanguages, id: \.self) { code in @@ -123,7 +123,7 @@ struct GenericCreditsView: View { } } } - + private func noticeView(_ content: (String, String)) -> some View { VStack { Text(content.1) @@ -137,9 +137,9 @@ struct GenericCreditsView: View { extension GenericCreditsView { struct LicenseView: View { let url: URL - + @Binding var content: String? - + var body: some View { ZStack { content.map { unwrapped in @@ -154,7 +154,7 @@ extension GenericCreditsView { } }.onAppear(perform: loadURL) } - + private func loadURL() { guard content == nil else { return diff --git a/Passepartout/App/Reusable/GenericVersionView.swift b/Passepartout/App/Reusable/GenericVersionView.swift index 3d46fdfd..dff31c06 100644 --- a/Passepartout/App/Reusable/GenericVersionView.swift +++ b/Passepartout/App/Reusable/GenericVersionView.swift @@ -27,13 +27,13 @@ import SwiftUI struct GenericVersionView: View { let logoName: String - + let appName: String - + let versionString: String - + let extraString: String? - + var body: some View { ScrollView { Image(logoName) diff --git a/Passepartout/App/Reusable/IntentActivity.swift b/Passepartout/App/Reusable/IntentActivity.swift index f5735f46..df0f84be 100644 --- a/Passepartout/App/Reusable/IntentActivity.swift +++ b/Passepartout/App/Reusable/IntentActivity.swift @@ -27,7 +27,7 @@ import SwiftUI public struct IntentActivity { public let name: String - + public let handler: (NSUserActivity, UserObject) -> Void } diff --git a/Passepartout/App/Reusable/IntentAddView.swift b/Passepartout/App/Reusable/IntentAddView.swift index 14215d65..3663abb1 100644 --- a/Passepartout/App/Reusable/IntentAddView.swift +++ b/Passepartout/App/Reusable/IntentAddView.swift @@ -29,9 +29,9 @@ import IntentsUI struct IntentAddView: UIViewControllerRepresentable { let shortcut: INShortcut - + let delegate: INUIAddVoiceShortcutViewControllerDelegate? - + func makeUIViewController(context: UIViewControllerRepresentableContext) -> INUIAddVoiceShortcutViewController { let vc = INUIAddVoiceShortcutViewController(shortcut: shortcut) vc.delegate = delegate diff --git a/Passepartout/App/Reusable/IntentEditView.swift b/Passepartout/App/Reusable/IntentEditView.swift index 1191d856..ee37d015 100644 --- a/Passepartout/App/Reusable/IntentEditView.swift +++ b/Passepartout/App/Reusable/IntentEditView.swift @@ -29,9 +29,9 @@ import IntentsUI struct IntentEditView: UIViewControllerRepresentable { let shortcut: Shortcut - + let delegate: INUIEditVoiceShortcutViewControllerDelegate? - + func makeUIViewController(context: UIViewControllerRepresentableContext) -> INUIEditVoiceShortcutViewController { let vc = INUIEditVoiceShortcutViewController(voiceShortcut: shortcut.native) vc.delegate = delegate diff --git a/Passepartout/App/Reusable/LongContentView.swift b/Passepartout/App/Reusable/LongContentView.swift index 06f7c39c..6b337a82 100644 --- a/Passepartout/App/Reusable/LongContentView.swift +++ b/Passepartout/App/Reusable/LongContentView.swift @@ -27,7 +27,7 @@ import SwiftUI struct LongContentView: View { @Binding var content: String - + var body: some View { TextEditor(text: $content) .font(.system(.body, design: .monospaced)) @@ -39,13 +39,13 @@ struct LongContentView: View { struct LongContentLink: View { private let title: String - + @Binding private var content: String - + private let preview: String? private let previewLabel: ((String) -> Preview)? - + init( _ title: String, content: Binding, @@ -57,7 +57,7 @@ struct LongContentLink: View { self.preview = preview self.previewLabel = previewLabel } - + var body: some View { NavigationLink { LongContentView(content: $content) diff --git a/Passepartout/App/Reusable/MailComposerView.swift b/Passepartout/App/Reusable/MailComposerView.swift index bdbe3fdd..654ce91b 100644 --- a/Passepartout/App/Reusable/MailComposerView.swift +++ b/Passepartout/App/Reusable/MailComposerView.swift @@ -29,32 +29,32 @@ import MessageUI struct MailComposerView: UIViewControllerRepresentable { class Coordinator: NSObject, MFMailComposeViewControllerDelegate { @Binding private var isPresented: Bool - + init(_ view: MailComposerView) { _isPresented = view._isPresented } - + public func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) { isPresented = false } } typealias Attachment = (data: Data, mimeType: String, fileName: String) - + static func canSendMail() -> Bool { MFMailComposeViewController.canSendMail() } @Binding var isPresented: Bool - + let toRecipients: [String] - + let subject: String - + let messageBody: String - + var attachments: [Attachment]? - + func makeUIViewController(context: UIViewControllerRepresentableContext) -> MFMailComposeViewController { let vc = MFMailComposeViewController() vc.setToRecipients(toRecipients) @@ -69,7 +69,7 @@ struct MailComposerView: UIViewControllerRepresentable { func updateUIViewController(_ uiViewController: MFMailComposeViewController, context: UIViewControllerRepresentableContext) { } - + func makeCoordinator() -> Coordinator { Coordinator(self) } diff --git a/Passepartout/App/Reusable/RevealingSecureField.swift b/Passepartout/App/Reusable/RevealingSecureField.swift index ed20de4e..a8a0cbf4 100644 --- a/Passepartout/App/Reusable/RevealingSecureField.swift +++ b/Passepartout/App/Reusable/RevealingSecureField.swift @@ -27,15 +27,15 @@ import SwiftUI struct RevealingSecureField: View { let title: String - + @Binding private var text: String - + private let conceilImage: () -> ImageContent - + private let revealImage: () -> ImageContent - + @State private var isRevealed = false - + init( _ title: String, text: Binding, @@ -47,7 +47,7 @@ struct RevealingSecureField: View { self.conceilImage = conceilImage self.revealImage = revealImage } - + var body: some View { HStack { if isRevealed { diff --git a/Passepartout/App/Reusable/Reviewer.swift b/Passepartout/App/Reusable/Reviewer.swift index 06bcbc98..7a5a0384 100644 --- a/Passepartout/App/Reusable/Reviewer.swift +++ b/Passepartout/App/Reusable/Reviewer.swift @@ -29,14 +29,14 @@ import StoreKit public class Reviewer: ObservableObject { private struct Keys { static let eventCount = "Reviewer.EventCount" - + static let lastVersion = "Reviewer.LastVersion" } - + private let defaults: UserDefaults - + public var eventCountBeforeRating: Int = .max - + public init() { defaults = .standard } @@ -66,7 +66,7 @@ public class Reviewer: ObservableObject { count += eventCount defaults.set(count, forKey: Keys.eventCount) print("Reviewer: Event reported for version \(currentVersion) (count: \(count), prompt: \(eventCountBeforeRating))") - + guard count >= eventCountBeforeRating else { return false } @@ -74,11 +74,11 @@ public class Reviewer: ObservableObject { defaults.removeObject(forKey: Keys.eventCount) defaults.set(currentVersion, forKey: Keys.lastVersion) - + requestReview() return true } - + // may or may not appear private func requestReview() { guard let scene = UIApplication.shared.windows.first(where: { $0.windowScene != nil })?.windowScene else { diff --git a/Passepartout/App/Reusable/Shortcut.swift b/Passepartout/App/Reusable/Shortcut.swift index 1eac52dc..735fb980 100644 --- a/Passepartout/App/Reusable/Shortcut.swift +++ b/Passepartout/App/Reusable/Shortcut.swift @@ -28,11 +28,11 @@ import Intents struct Shortcut: Identifiable, Hashable, Comparable { let native: INVoiceShortcut - + init(_ native: INVoiceShortcut) { self.native = native } - + var id: UUID { native.identifier } @@ -40,7 +40,7 @@ struct Shortcut: Identifiable, Hashable, Comparable { static func ==(lhs: Self, rhs: Self) -> Bool { lhs.phrase == rhs.phrase } - + static func <(lhs: Self, rhs: Self) -> Bool { lhs.phrase < rhs.phrase } diff --git a/Passepartout/App/Reusable/StyledPicker.swift b/Passepartout/App/Reusable/StyledPicker.swift index 0bb6ae41..45cf8147 100644 --- a/Passepartout/App/Reusable/StyledPicker.swift +++ b/Passepartout/App/Reusable/StyledPicker.swift @@ -27,15 +27,15 @@ import SwiftUI struct StyledPicker: View { let title: String - + @Binding var selection: T - + let values: [T] let pickerLabel: (T) -> Label let selectionLabel: (T) -> Label - + let listStyle: () -> Style @State private var isPresented = false @@ -49,7 +49,7 @@ struct StyledPicker: View { } } } - + private func pickerView() -> some View { List { Section { diff --git a/Passepartout/App/Reusable/Validators.swift b/Passepartout/App/Reusable/Validators.swift index 8a2d3509..71ea2b17 100644 --- a/Passepartout/App/Reusable/Validators.swift +++ b/Passepartout/App/Reusable/Validators.swift @@ -28,13 +28,13 @@ import Foundation struct Validators { enum ValidationError: Error { case notSet - + case empty - + case ipAddress - + case domainName - + case url } @@ -71,7 +71,7 @@ struct Validators { throw ValidationError.domainName } } - + static func url(_ string: String) throws { guard let _ = URL(string: string) else { throw ValidationError.url diff --git a/Passepartout/App/Views/AboutView.swift b/Passepartout/App/Views/AboutView.swift index bbf0fe5b..47250afc 100644 --- a/Passepartout/App/Views/AboutView.swift +++ b/Passepartout/App/Views/AboutView.swift @@ -31,7 +31,7 @@ struct AboutView: View { private let versionString = Constants.Global.appVersionString private let redditURL = Constants.URLs.subreddit - + private let shareMessage = L10n.Global.Messages.share private let readmeURL = Constants.URLs.readme @@ -55,7 +55,7 @@ struct AboutView: View { }.themeSecondaryView() .navigationTitle(L10n.About.title) } - + private var infoSection: some View { Section { NavigationLink { @@ -69,7 +69,7 @@ struct AboutView: View { } } } - + private var supportSection: some View { Section { Button(L10n.About.Items.JoinCommunity.caption) { diff --git a/Passepartout/App/Views/AccountView.swift b/Passepartout/App/Views/AccountView.swift index 207bfbaa..e4d78e01 100644 --- a/Passepartout/App/Views/AccountView.swift +++ b/Passepartout/App/Views/AccountView.swift @@ -28,19 +28,19 @@ import PassepartoutLibrary struct AccountView: View { @ObservedObject private var providerManager: ProviderManager - + private let providerName: ProviderName? - + private let vpnProtocol: VPNProtocolType - + @Binding private var account: Profile.Account - + private let saveAnyway: Bool - + private let onSave: (() -> Void)? @State private var liveAccount = Profile.Account() - + init( providerName: ProviderName?, vpnProtocol: VPNProtocolType, @@ -55,7 +55,7 @@ struct AccountView: View { self.saveAnyway = saveAnyway self.onSave = onSave } - + var body: some View { List { Section { @@ -126,7 +126,7 @@ struct AccountView: View { ) } } - + private func openGuidanceURL(_ url: URL) { URL.openURL(url) } @@ -155,10 +155,10 @@ private extension Profile.Account.AuthenticationMethod { switch self { case .persistent: return L10n.Account.Items.AuthenticationMethod.persistent - + case .interactive: return L10n.Account.Items.AuthenticationMethod.interactive - + case .totp: return Unlocalized.Other.totp } diff --git a/Passepartout/App/Views/AddHostView+Name.swift b/Passepartout/App/Views/AddHostView+Name.swift index dd6be36f..79cc68bc 100644 --- a/Passepartout/App/Views/AddHostView+Name.swift +++ b/Passepartout/App/Views/AddHostView+Name.swift @@ -31,15 +31,15 @@ import TunnelKitWireGuard extension AddHostView { struct NameView: View { @ObservedObject private var profileManager: ProfileManager - + private let url: URL - + private let deletingURLOnSuccess: Bool - + private let bindings: AddProfileView.Bindings - + @State private var viewModel = ViewModel() - + @State private var isEnteringCredentials = false private var isComplete: Bool { @@ -107,7 +107,7 @@ extension AddHostView { completeSection } } - + private var encryptionSection: some View { Section { SecureField(L10n.AddProfile.Host.Sections.Encryption.footer, text: $viewModel.encryptionPassphrase) { @@ -132,7 +132,7 @@ extension AddHostView { themeErrorMessage(viewModel.errorMessage) } } - + private var hiddenAccountLink: some View { NavigationLink("", isActive: $isEnteringCredentials) { AddProfileView.AccountWrapperView( @@ -153,11 +153,11 @@ extension AddHostView { private func requestResourcePermissions() { _ = url.startAccessingSecurityScopedResource() } - + private func dropResourcePermissions() { url.stopAccessingSecurityScopedResource() } - + private func alertOverwriteExistingProfile() -> Alert { Alert( title: Text(L10n.AddProfile.Shared.title), diff --git a/Passepartout/App/Views/AddHostViewModel.swift b/Passepartout/App/Views/AddHostViewModel.swift index d6fda357..726734c0 100644 --- a/Passepartout/App/Views/AddHostViewModel.swift +++ b/Passepartout/App/Views/AddHostViewModel.swift @@ -31,19 +31,19 @@ import TunnelKitWireGuard extension AddHostView { struct ViewModel: Equatable { private var isNamePreset = false - + var profileName = "" - + private(set) var requiresPassphrase = false - + var encryptionPassphrase = "" var processedProfile: Profile = .placeholder - + private(set) var errorMessage: String? - + var isAskingOverwrite = false - + mutating func presetName(withURL url: URL) { guard !isNamePreset else { return @@ -96,7 +96,7 @@ extension AddHostView { setMessage(forParsingError: error) } } - + @MainActor mutating func addProcessedProfile(to profileManager: ProfileManager) -> Bool { guard !processedProfile.isPlaceholder else { @@ -107,7 +107,7 @@ extension AddHostView { profileManager.saveProfile(processedProfile, isActive: nil) return true } - + private mutating func setMessage(forParsingError error: Error) { errorMessage = error.localizedVPNParsingDescription } diff --git a/Passepartout/App/Views/AddProfileMenu.swift b/Passepartout/App/Views/AddProfileMenu.swift index 670de2ee..4bfc5ecd 100644 --- a/Passepartout/App/Views/AddProfileMenu.swift +++ b/Passepartout/App/Views/AddProfileMenu.swift @@ -31,7 +31,7 @@ struct AddProfileMenu: View { case addProvider case addHost(URL, Bool) - + // XXX: alert ids var id: Int { switch self { @@ -41,16 +41,16 @@ struct AddProfileMenu: View { } } } - + @Binding private var modalType: ModalType? - + @Binding private var isHostFileImporterPresented: Bool - + init(modalType: Binding, isHostFileImporterPresented: Binding) { _modalType = modalType _isHostFileImporterPresented = isHostFileImporterPresented } - + var body: some View { Menu { Button { @@ -74,7 +74,7 @@ struct AddProfileMenu: View { themeAddMenuImage.asSystemImage }.sheet(item: $modalType, content: presentedModal) } - + @ViewBuilder private func presentedModal(_ modalType: ModalType) -> some View { switch modalType { @@ -99,7 +99,7 @@ struct AddProfileMenu: View { }.themeGlobal() } } - + private var isModalPresented: Binding { .init { modalType != nil diff --git a/Passepartout/App/Views/AddProfileView.swift b/Passepartout/App/Views/AddProfileView.swift index ed661fb4..b8fa4de4 100644 --- a/Passepartout/App/Views/AddProfileView.swift +++ b/Passepartout/App/Views/AddProfileView.swift @@ -30,14 +30,14 @@ enum AddProfileView { struct Bindings { @Binding var isPresented: Bool } - + struct ProfileNameSection: View { @Binding var profileName: String - + let errorMessage: String? - + let onCommit: () -> Void - + var body: some View { Section { TextField(L10n.Global.Placeholders.profileName, text: $profileName, onCommit: onCommit) @@ -49,12 +49,12 @@ enum AddProfileView { } } } - + struct ExistingProfilesSection: View { let headers: [Profile.Header] - + @Binding var profileName: String - + var body: some View { Section { ForEach(headers, content: existingProfileButton) @@ -62,7 +62,7 @@ enum AddProfileView { Text(L10n.AddProfile.Shared.Views.Existing.header) } } - + private func existingProfileButton(_ header: Profile.Header) -> some View { Button(header.name) { profileName = header.name @@ -74,11 +74,11 @@ enum AddProfileView { @ObservedObject private var profileManager: ProfileManager @Binding private var profile: Profile - + private let bindings: AddProfileView.Bindings @State private var account = Profile.Account() - + init( profile: Binding, bindings: AddProfileView.Bindings @@ -87,7 +87,7 @@ enum AddProfileView { _profile = profile self.bindings = bindings } - + var body: some View { AccountView( providerName: profile.header.providerName, diff --git a/Passepartout/App/Views/AddProviderView+Name.swift b/Passepartout/App/Views/AddProviderView+Name.swift index a4cadbe2..238c4ad8 100644 --- a/Passepartout/App/Views/AddProviderView+Name.swift +++ b/Passepartout/App/Views/AddProviderView+Name.swift @@ -29,17 +29,17 @@ import PassepartoutLibrary extension AddProviderView { struct NameView: View { @ObservedObject private var profileManager: ProfileManager - + @Binding private var profile: Profile - + private let providerMetadata: ProviderMetadata - + private let bindings: AddProfileView.Bindings @State private var viewModel = ViewModel() - + @State private var isEnteringCredentials = false - + init( profile: Binding, providerMetadata: ProviderMetadata, @@ -80,7 +80,7 @@ extension AddProviderView { }.alert(isPresented: $viewModel.isAskingOverwrite, content: alertOverwriteExistingProfile) .navigationTitle(providerMetadata.fullName) } - + private var hiddenAccountLink: some View { NavigationLink("", isActive: $isEnteringCredentials) { AddProfileView.AccountWrapperView( diff --git a/Passepartout/App/Views/AddProviderView.swift b/Passepartout/App/Views/AddProviderView.swift index b18ad3e3..d4a7800a 100644 --- a/Passepartout/App/Views/AddProviderView.swift +++ b/Passepartout/App/Views/AddProviderView.swift @@ -28,26 +28,26 @@ import PassepartoutLibrary struct AddProviderView: View { @ObservedObject private var providerManager: ProviderManager - + @ObservedObject private var productManager: ProductManager - + private let bindings: AddProfileView.Bindings - + @StateObject private var viewModel = ViewModel() - + init(bindings: AddProfileView.Bindings) { providerManager = .shared productManager = .shared self.bindings = bindings } - + private var providers: [ProviderMetadata] { providerManager.allProviders() .filter { $0.supportedVPNProtocols.contains(viewModel.selectedVPNProtocol) }.sorted() } - + private var availableVPNProtocols: [VPNProtocolType] { var protos: Set = [] providers.forEach { @@ -57,7 +57,7 @@ struct AddProviderView: View { } return protos.sorted() } - + var body: some View { ZStack { ForEach(providers, id: \.navigationId, content: hiddenProviderLink) @@ -82,7 +82,7 @@ struct AddProviderView: View { }.navigationTitle(L10n.AddProfile.Shared.title) .themeSecondaryView() } - + private var mainSection: some View { Section { let protos = availableVPNProtocols @@ -99,7 +99,7 @@ struct AddProviderView: View { Text(L10n.AddProfile.Provider.Sections.Vpn.footer) } } - + private var providersSection: some View { Section { ForEach(providers, content: providerRow) @@ -107,7 +107,7 @@ struct AddProviderView: View { themeErrorMessage(viewModel.errorMessage) }.disabled(viewModel.isFetchingAnyProvider) } - + private func providerRow(_ metadata: ProviderMetadata) -> some View { Button { presentOrPurchaseProvider(metadata) @@ -115,7 +115,7 @@ struct AddProviderView: View { Label(metadata.fullName, image: themeAssetsProviderImage(metadata.name)) }.withTrailingProgress(when: viewModel.isFetchingProvider(metadata.name)) } - + private func hiddenProviderLink(_ metadata: ProviderMetadata) -> some View { NavigationLink("", tag: metadata, selection: $viewModel.selectedProvider) { NameView( @@ -132,7 +132,7 @@ struct AddProviderView: View { }.withTrailingProgress(when: viewModel.isUpdatingIndex) .disabled(viewModel.isUpdatingIndex) } - + // eligibility: select or purchase provider private func presentOrPurchaseProvider(_ metadata: ProviderMetadata) { guard productManager.isEligible(forProvider: metadata.name) else { diff --git a/Passepartout/App/Views/AddProviderViewModel.swift b/Passepartout/App/Views/AddProviderViewModel.swift index b0fa90a9..76103ab7 100644 --- a/Passepartout/App/Views/AddProviderViewModel.swift +++ b/Passepartout/App/Views/AddProviderViewModel.swift @@ -30,7 +30,7 @@ extension AddProviderView { class ViewModel: ObservableObject { enum PendingOperation { case index - + case provider(ProviderName) } @@ -54,19 +54,19 @@ extension AddProviderView { } return false } - + @Published var selectedVPNProtocol: VPNProtocolType = .openVPN @Published var selectedProvider: ProviderMetadata? - + @Published var pendingProfile: Profile = .placeholder - + @Published private(set) var pendingOperation: PendingOperation? @Published var isPaywallPresented = false - + @Published private(set) var errorMessage: String? - + func selectProvider(_ metadata: ProviderMetadata, _ providerManager: ProviderManager) { errorMessage = nil guard let server = providerManager.anyDefaultServer( @@ -109,7 +109,7 @@ extension AddProviderView { pendingProfile = Profile(metadata, server: server) selectedProvider = metadata } - + func updateIndex(_ providerManager: ProviderManager) { errorMessage = nil pendingOperation = .index @@ -136,11 +136,11 @@ extension AddProviderView.NameView { private var isNamePreset = false var profileName = "" - + var isAskingOverwrite = false - + private(set) var errorMessage: String? - + mutating func presetName(withMetadata metadata: ProviderMetadata) { guard !isNamePreset else { return @@ -173,7 +173,7 @@ extension AddProviderView.NameView { profileManager.saveProfile(finalProfile, isActive: nil) return finalProfile } - + private mutating func setMessage(forError error: Error) { errorMessage = error.localizedDescription } diff --git a/Passepartout/App/Views/CreditsView.swift b/Passepartout/App/Views/CreditsView.swift index 4e29adda..bb58129d 100644 --- a/Passepartout/App/Views/CreditsView.swift +++ b/Passepartout/App/Views/CreditsView.swift @@ -28,8 +28,8 @@ import SwiftUI struct CreditsView: View { var body: some View { GenericCreditsView( - licensesHeader: nil,//L10n.Credits.Sections.Licenses.header, - noticesHeader: nil,//L10n.Credits.Sections.Notices.header, + licensesHeader: nil,// L10n.Credits.Sections.Licenses.header, + noticesHeader: nil,// L10n.Credits.Sections.Notices.header, translationsHeader: L10n.Global.Strings.translations, licenses: Unlocalized.Credits.licenses, notices: Unlocalized.Credits.notices, diff --git a/Passepartout/App/Views/DebugLogView.swift b/Passepartout/App/Views/DebugLogView.swift index 5e47f481..4f2a3d29 100644 --- a/Passepartout/App/Views/DebugLogView.swift +++ b/Passepartout/App/Views/DebugLogView.swift @@ -29,23 +29,23 @@ import PassepartoutLibrary struct DebugLogView: View { private let title: String - + private let url: URL - + private let timer: AnyPublisher - + @State private var logLines: [String] = [] - + @State private var isSharing = false - + private let maxBytes = UInt64(Constants.Log.maxBytes) private let appName = Constants.Global.appName private let appVersion = Constants.Global.appVersionString - + private let shareFilename = Unlocalized.Issues.Filenames.debugLog - + init(title: String, url: URL, refreshInterval: TimeInterval?) { self.title = title self.url = url @@ -58,7 +58,7 @@ struct DebugLogView: View { .eraseToAnyPublisher() } } - + var body: some View { ScrollViewReader { scrollProxy in ScrollView(showsIndicators: true) { @@ -96,22 +96,22 @@ struct DebugLogView: View { Text(logLines[$0]) .frame(maxWidth: .infinity, alignment: .leading) } - }//.padding() + }// .padding() // TODO: layout, a slight padding would be nice, but it glitches on first touch } - + private func refreshLog(scrollingToLatestWith scrollProxy: ScrollViewProxy?) { logLines = url.trailingLines(bytes: maxBytes) if let scrollProxy = scrollProxy { scrollToLatestUpdate(scrollProxy) } } - + private func refreshLog(_: Date) { refreshLog(scrollingToLatestWith: nil) } } - + extension DebugLogView { private func shareDebugLog() { guard !logLines.isEmpty else { @@ -120,7 +120,7 @@ extension DebugLogView { } isSharing = true } - + private func sharingActivityView() -> some View { ActivityView(activityItems: sharingItems) } diff --git a/Passepartout/App/Views/DiagnosticsView+OpenVPN.swift b/Passepartout/App/Views/DiagnosticsView+OpenVPN.swift index b4fbbad0..5cb477ed 100644 --- a/Passepartout/App/Views/DiagnosticsView+OpenVPN.swift +++ b/Passepartout/App/Views/DiagnosticsView+OpenVPN.swift @@ -31,7 +31,7 @@ extension DiagnosticsView { struct OpenVPNView: View { enum AlertType: Int, Identifiable { case emailNotConfigured - + var id: Int { return rawValue } @@ -40,23 +40,23 @@ extension DiagnosticsView { @ObservedObject private var providerManager: ProviderManager @ObservedObject private var vpnManager: VPNManager - + @ObservedObject private var currentVPNState: ObservableVPNState @ObservedObject private var productManager: ProductManager private let providerName: ProviderName? - + private var isEligibleForFeedback: Bool { productManager.isEligibleForFeedback() } - + @State private var isReportingIssue = false @State private var alertType: AlertType? - + private let vpnProtocol: VPNProtocolType = .openVPN - + init(providerName: ProviderName?) { providerManager = .shared vpnManager = .shared @@ -103,7 +103,7 @@ extension DiagnosticsView { }.disabled(cfg == nil) } } - + private var debugLogSection: some View { Section { DebugLogSection(appLogURL: appLogURL, tunnelLogURL: tunnelLogURL) @@ -114,7 +114,7 @@ extension DiagnosticsView { Text(L10n.Diagnostics.Sections.DebugLog.footer) } } - + private var issueReporterSection: some View { Section { Button(L10n.Diagnostics.Items.ReportIssue.caption, action: presentReportIssue) diff --git a/Passepartout/App/Views/DiagnosticsView+WireGuard.swift b/Passepartout/App/Views/DiagnosticsView+WireGuard.swift index 7ecf63f2..7d48c552 100644 --- a/Passepartout/App/Views/DiagnosticsView+WireGuard.swift +++ b/Passepartout/App/Views/DiagnosticsView+WireGuard.swift @@ -30,9 +30,9 @@ import TunnelKitWireGuard extension DiagnosticsView { struct WireGuardView: View { @ObservedObject private var vpnManager: VPNManager - + private let providerName: ProviderName? - + init(providerName: ProviderName?) { vpnManager = .shared self.providerName = providerName diff --git a/Passepartout/App/Views/DiagnosticsView.swift b/Passepartout/App/Views/DiagnosticsView.swift index 9d206489..f661b022 100644 --- a/Passepartout/App/Views/DiagnosticsView.swift +++ b/Passepartout/App/Views/DiagnosticsView.swift @@ -28,7 +28,7 @@ import PassepartoutLibrary struct DiagnosticsView: View { let vpnProtocol: VPNProtocolType - + let providerName: ProviderName? var body: some View { @@ -38,7 +38,7 @@ struct DiagnosticsView: View { DiagnosticsView.OpenVPNView( providerName: providerName ) - + case .wireGuard: DiagnosticsView.WireGuardView( providerName: providerName @@ -51,9 +51,9 @@ struct DiagnosticsView: View { extension DiagnosticsView { struct DebugLogSection: View { let appLogURL: URL? - + let tunnelLogURL: URL? - + private let refreshInterval = Constants.Log.refreshInterval var body: some View { @@ -68,7 +68,7 @@ extension DiagnosticsView { refreshInterval: nil ) } - + private var tunnelLink: some View { navigationLink( withTitle: Unlocalized.VPN.vpn, diff --git a/Passepartout/App/Views/DonateView.swift b/Passepartout/App/Views/DonateView.swift index f70f71e9..6a1e454e 100644 --- a/Passepartout/App/Views/DonateView.swift +++ b/Passepartout/App/Views/DonateView.swift @@ -30,9 +30,9 @@ import PassepartoutLibrary struct DonateView: View { enum AlertType: Identifiable { case thankYou - + case purchaseFailed(Error) - + // XXX: alert ids var id: Int { switch self { @@ -42,19 +42,19 @@ struct DonateView: View { } } } - + @Environment(\.scenePhase) private var scenePhase @ObservedObject private var productManager: ProductManager - + @State private var alertType: AlertType? @State private var pendingDonationIdentifier: String? - + init() { productManager = .shared } - + var body: some View { List { productsSection @@ -90,7 +90,7 @@ struct DonateView: View { ) } } - + private var productsSection: some View { Section { if !productManager.isRefreshingProducts { @@ -104,7 +104,7 @@ struct DonateView: View { Text(L10n.Donate.Sections.OneTime.footer) } } - + @ViewBuilder private func productRow(_ product: SKProduct) -> some View { HStack { @@ -129,7 +129,7 @@ extension DonateView { pendingDonationIdentifier = product.productIdentifier productManager.purchase(product, completionHandler: handlePurchaseResult) } - + private func handlePurchaseResult(_ result: Result) { switch result { case .success(let value): @@ -138,7 +138,7 @@ extension DonateView { } else { // cancelled } - + case .failure(let error): alertType = .purchaseFailed(error) } diff --git a/Passepartout/App/Views/EndpointAdvancedView+OpenVPN.swift b/Passepartout/App/Views/EndpointAdvancedView+OpenVPN.swift index c8a72880..fe3ea1f8 100644 --- a/Passepartout/App/Views/EndpointAdvancedView+OpenVPN.swift +++ b/Passepartout/App/Views/EndpointAdvancedView+OpenVPN.swift @@ -32,11 +32,11 @@ extension EndpointAdvancedView { @Binding var builder: OpenVPN.ConfigurationBuilder let isReadonly: Bool - + let isServerPushed: Bool - + private let fallbackConfiguration = OpenVPN.ConfigurationBuilder(withFallbacks: true).build() - + var body: some View { List { let cfg = builder.build() @@ -104,7 +104,7 @@ extension EndpointAdvancedView.OpenVPNView { Text(Unlocalized.Network.ipv4) } } - + private var ipv6Section: some View { Section { if let settings = builder.ipv6 { @@ -156,7 +156,7 @@ extension EndpointAdvancedView.OpenVPNView { } } } - + private var communicationEditableSection: some View { Section { themeTextPicker( @@ -185,7 +185,7 @@ extension EndpointAdvancedView.OpenVPNView { Text(L10n.Endpoint.Advanced.Openvpn.Sections.Communication.header) } } - + private func compressionSection(configuration: OpenVPN.Configuration) -> some View { configuration.compressionSettings.map { settings in Section { @@ -202,7 +202,7 @@ extension EndpointAdvancedView.OpenVPNView { } } } - + private var compressionEditableSection: some View { Section { themeTextPicker( @@ -334,21 +334,21 @@ extension OpenVPN.Configuration { } return (compressionFraming, compressionAlgorithm) } - + var dnsSettings: (servers: [String], domains: [String])? { guard !(dnsServers?.isEmpty ?? true) || !(searchDomains?.isEmpty ?? true) else { return nil } return (dnsServers ?? [], searchDomains ?? []) } - + var proxySettings: (proxy: Proxy?, pac: URL?, bypass: [String])? { guard httpsProxy != nil || httpProxy != nil || proxyAutoConfigurationURL != nil || !(proxyBypassDomains?.isEmpty ?? true) else { return nil } return (httpsProxy ?? httpProxy, proxyAutoConfigurationURL, proxyBypassDomains ?? []) } - + var otherSettings: (keepAlive: TimeInterval?, reneg: TimeInterval?, randomizeEndpoint: Bool?, randomizeHostnames: Bool?)? { guard keepAliveInterval != nil || renegotiatesAfter != nil || randomizeEndpoint != nil || randomizeHostnames != nil else { return nil @@ -361,15 +361,15 @@ private extension EndpointAdvancedView.OpenVPNView { var fallbackCipher: OpenVPN.Cipher { fallbackConfiguration.cipher! } - + var fallbackDigest: OpenVPN.Digest { fallbackConfiguration.digest! } - + var fallbackCompressionFraming: OpenVPN.CompressionFraming { fallbackConfiguration.compressionFraming! } - + var fallbackCompressionAlgorithm: OpenVPN.CompressionAlgorithm { fallbackConfiguration.compressionAlgorithm! } diff --git a/Passepartout/App/Views/EndpointAdvancedView+WireGuard.swift b/Passepartout/App/Views/EndpointAdvancedView+WireGuard.swift index b94b0165..6c277aef 100644 --- a/Passepartout/App/Views/EndpointAdvancedView+WireGuard.swift +++ b/Passepartout/App/Views/EndpointAdvancedView+WireGuard.swift @@ -78,7 +78,7 @@ extension EndpointAdvancedView.WireGuardView { } } } - + private var mtuSection: some View { builder.mtu.map { mtu in Section { diff --git a/Passepartout/App/Views/EndpointView+OpenVPN.swift b/Passepartout/App/Views/EndpointView+OpenVPN.swift index 477c64f7..2bcb788b 100644 --- a/Passepartout/App/Views/EndpointView+OpenVPN.swift +++ b/Passepartout/App/Views/EndpointView+OpenVPN.swift @@ -36,21 +36,21 @@ extension EndpointView { @ObservedObject private var currentProfile: ObservableProfile @Binding private var builder: OpenVPN.ConfigurationBuilder - + @Binding private var customEndpoint: Endpoint? - + private var isConfigurationReadonly: Bool { currentProfile.value.isProvider } @State private var isFirstAppearance = true - + @State private var isAutomatic = false @State private var selectedSocketType: SocketType = .udp - + @State private var selectedPort: UInt16 = 0 - + // XXX: do not escape mutating 'self', use constant providerManager init(currentProfile: ObservableProfile) { let providerManager: ProviderManager = .shared @@ -104,7 +104,7 @@ extension EndpointView { } } } - + var body: some View { ScrollViewReader { scrollProxy in List { @@ -135,7 +135,7 @@ extension EndpointView.OpenVPNView { Toggle(L10n.Global.Strings.automatic, isOn: $isAutomatic.themeAnimation()) } } - + private var filtersSection: some View { Section { themeTextPicker( @@ -162,7 +162,7 @@ extension EndpointView.OpenVPNView { Text(L10n.Global.Strings.addresses) } } - + private var advancedSection: some View { Section { let caption = L10n.Endpoint.Advanced.title @@ -175,7 +175,7 @@ extension EndpointView.OpenVPNView { } } } - + private func button(forEndpoint endpoint: Endpoint?) -> some View { Button { customEndpoint = endpoint @@ -265,7 +265,7 @@ extension EndpointView.OpenVPNView { }.map(\.proto.port)) return Array(allPorts).sorted() } - + private var filteredRemotes: [Endpoint]? { builder.remotes?.filter { $0.proto.socketType == selectedSocketType && $0.proto.port == selectedPort diff --git a/Passepartout/App/Views/EndpointView+WireGuard.swift b/Passepartout/App/Views/EndpointView+WireGuard.swift index 6635bf22..e5cf50a7 100644 --- a/Passepartout/App/Views/EndpointView+WireGuard.swift +++ b/Passepartout/App/Views/EndpointView+WireGuard.swift @@ -38,7 +38,7 @@ extension EndpointView { @Binding private var builder: WireGuard.ConfigurationBuilder // var customPeer: Binding? = nil - + // XXX: do not escape mutating 'self', use constant providerManager init(currentProfile: ObservableProfile, isReadonly: Bool) { let providerManager: ProviderManager = .shared diff --git a/Passepartout/App/Views/EndpointView.swift b/Passepartout/App/Views/EndpointView.swift index f4e85963..a2400a01 100644 --- a/Passepartout/App/Views/EndpointView.swift +++ b/Passepartout/App/Views/EndpointView.swift @@ -28,11 +28,11 @@ import PassepartoutLibrary struct EndpointView: View { @ObservedObject private var currentProfile: ObservableProfile - + init(currentProfile: ObservableProfile) { self.currentProfile = currentProfile } - + var body: some View { switch currentProfile.value.currentVPNProtocol { case .openVPN: diff --git a/Passepartout/App/Views/NetworkSettingsView.swift b/Passepartout/App/Views/NetworkSettingsView.swift index a40a2631..e95b47c6 100644 --- a/Passepartout/App/Views/NetworkSettingsView.swift +++ b/Passepartout/App/Views/NetworkSettingsView.swift @@ -34,7 +34,7 @@ struct NetworkSettingsView: View { } @State private var settings = Profile.NetworkSettings() - + init(currentProfile: ObservableProfile) { self.currentProfile = currentProfile } @@ -64,7 +64,7 @@ struct NetworkSettingsView: View { ) } } - + // EditButton() // .disabled(!isAnythingManual) @@ -83,7 +83,7 @@ struct NetworkSettingsView: View { // } return false } - + private func mapNotEmpty(elements: [IdentifiableString]) -> [IdentifiableString] { elements .filter { !$0.string.isEmpty } @@ -110,7 +110,7 @@ extension NetworkSettingsView { // MARK: DNS extension NetworkSettingsView { - + @ViewBuilder private var dnsView: some View { Section { @@ -146,7 +146,7 @@ extension NetworkSettingsView { dnsManualDomains } } - + private var dnsManualHTTPSRow: some View { TextField(Unlocalized.Placeholders.dohURL, text: $settings.dns.dnsHTTPSURL.toString()) .themeValidURL(settings.dns.dnsHTTPSURL?.absoluteString) @@ -177,7 +177,7 @@ extension NetworkSettingsView { } } } - + private var dnsManualDomains: some View { Section { EditableTextList( @@ -203,7 +203,7 @@ extension NetworkSettingsView { // MARK: Proxy extension NetworkSettingsView { - + @ViewBuilder private var proxyView: some View { Section { @@ -242,7 +242,7 @@ extension NetworkSettingsView { proxyManualBypassDomains } } - + private var proxyManualBypassDomains: some View { Section { EditableTextList( @@ -271,7 +271,7 @@ extension NetworkSettingsView { private var mtuView: some View { Section { Toggle(L10n.Global.Strings.automatic, isOn: $settings.isAutomaticMTU.themeAnimation()) - + if !settings.isAutomaticMTU { themeTextPicker( L10n.Global.Strings.bytes, diff --git a/Passepartout/App/Views/OnDemandView+SSID.swift b/Passepartout/App/Views/OnDemandView+SSID.swift index 7c92fdf2..41e7c571 100644 --- a/Passepartout/App/Views/OnDemandView+SSID.swift +++ b/Passepartout/App/Views/OnDemandView+SSID.swift @@ -29,9 +29,9 @@ import PassepartoutLibrary extension OnDemandView { struct SSIDList: View { @Binding var withSSIDs: [String: Bool] - + @StateObject private var reader = SSIDReader() - + var body: some View { EditableTextList(elements: allSSIDs, allowsDuplicates: false, mapping: mapElements) { text in requestSSID(text) @@ -43,13 +43,13 @@ extension OnDemandView { Text(L10n.Global.Strings.add) } } - + private func mapElements(elements: [IdentifiableString]) -> [IdentifiableString] { elements .filter { !$0.string.isEmpty } .sorted { $0.string.lowercased() < $1.string.lowercased() } } - + private func ssidRow(callback: EditableTextList.FieldCallback) -> some View { Group { if callback.isNewElement { @@ -61,7 +61,7 @@ extension OnDemandView { } } } - + private func ssidField(callback: EditableTextList.FieldCallback) -> some View { TextField( Unlocalized.Network.ssid, @@ -102,7 +102,7 @@ extension OnDemandView.SSIDList { // print(">>> withSSIDs (allSSIDs): \(withSSIDs)") } } - + private var onSSIDs: Binding> { .init { Set(withSSIDs.filter { @@ -128,7 +128,7 @@ extension OnDemandView.SSIDList { // print(">>> withSSIDs (onSSIDs): \(withSSIDs)") } } - + private func isSSIDOn(_ ssid: String) -> Binding { .init { withSSIDs[ssid] ?? false diff --git a/Passepartout/App/Views/OnDemandView.swift b/Passepartout/App/Views/OnDemandView.swift index 4e09b045..6ae8706c 100644 --- a/Passepartout/App/Views/OnDemandView.swift +++ b/Passepartout/App/Views/OnDemandView.swift @@ -36,7 +36,7 @@ struct OnDemandView: View { } @State private var onDemand = Profile.OnDemand() - + init(currentProfile: ObservableProfile) { productManager = .shared self.currentProfile = currentProfile @@ -72,7 +72,7 @@ extension OnDemandView { Toggle(L10n.Global.Strings.enabled, isOn: $onDemand.isEnabled.themeAnimation()) } } - + @ViewBuilder private var mainView: some View { if Utils.hasCellularData() { @@ -118,7 +118,7 @@ extension OnDemandView { IntentDispatcher.donateTrustCellularNetwork() IntentDispatcher.donateUntrustCellularNetwork() } - + // eligibility: donate intents if eligible for Siri private func donateNetworkIntents(_: [String: Bool]) { guard isEligibleForSiri else { diff --git a/Passepartout/App/Views/OrganizerView+ProfileRow.swift b/Passepartout/App/Views/OrganizerView+ProfileRow.swift index 1da06542..712ddab3 100644 --- a/Passepartout/App/Views/OrganizerView+ProfileRow.swift +++ b/Passepartout/App/Views/OrganizerView+ProfileRow.swift @@ -29,11 +29,11 @@ import PassepartoutLibrary extension OrganizerView { struct ProfileRow: View { private let profile: Profile - + private let isActiveProfile: Bool - + @Binding private var modalType: ModalType? - + private var interactiveProfile: Binding { .init { if case .interactiveAccount(let profile) = modalType { @@ -48,13 +48,13 @@ extension OrganizerView { } } } - + init(profile: Profile, isActiveProfile: Bool, modalType: Binding) { self.profile = profile self.isActiveProfile = isActiveProfile _modalType = modalType } - + var body: some View { debugChanges() return HStack { @@ -62,7 +62,7 @@ extension OrganizerView { Text(profile.header.name) .font(.headline) .themeLongTextStyle() - + VPNStatusText(isActiveProfile: isActiveProfile) .font(.subheadline) .themeSecondaryTextStyle() diff --git a/Passepartout/App/Views/OrganizerView+Profiles.swift b/Passepartout/App/Views/OrganizerView+Profiles.swift index 217821eb..4c17fae9 100644 --- a/Passepartout/App/Views/OrganizerView+Profiles.swift +++ b/Passepartout/App/Views/OrganizerView+Profiles.swift @@ -29,7 +29,7 @@ import PassepartoutLibrary extension OrganizerView { struct ProfilesList: View { @ObservedObject private var profileManager: ProfileManager - + @Binding private var modalType: ModalType? init(modalType: Binding) { @@ -49,7 +49,7 @@ extension OrganizerView { profileManager.currentProfileId = $0.id } } - + private var mainView: some View { List { if profileManager.hasProfiles { @@ -69,7 +69,7 @@ extension OrganizerView { } }.themeAnimation(on: profileManager.headers) } - + private var profilesView: some View { ForEach(sortedProfiles, content: profileRow(forProfile:)) .onDelete(perform: removeProfiles) @@ -91,7 +91,7 @@ extension OrganizerView { ProfileContextMenu(header: profile.header) } } - + private func profileLabel(forProfile profile: Profile) -> some View { ProfileRow( profile: profile, @@ -124,7 +124,7 @@ extension OrganizerView { profileManager.removeProfiles(withIds: toDelete) } } - + private func performMigrationsIfNeeded() { Task { @MainActor in UpgradeManager.shared.doMigrations(profileManager) @@ -140,13 +140,13 @@ extension OrganizerView { @ObservedObject private var currentVPNState: ObservableVPNState let header: Profile.Header - + init(header: Profile.Header) { profileManager = .shared currentVPNState = .shared self.header = header } - + var body: some View { if #available(iOS 16, *), isActiveProfileNotDisconnected { reconnectButton @@ -154,11 +154,11 @@ extension OrganizerView { duplicateButton deleteButton } - + private var isActiveProfileNotDisconnected: Bool { profileManager.isActiveProfile(header.id) && currentVPNState.vpnStatus != .disconnected } - + private var reconnectButton: some View { ProfileView.ReconnectButton() } diff --git a/Passepartout/App/Views/OrganizerView+Scene.swift b/Passepartout/App/Views/OrganizerView+Scene.swift index bcbab4b5..c67b4925 100644 --- a/Passepartout/App/Views/OrganizerView+Scene.swift +++ b/Passepartout/App/Views/OrganizerView+Scene.swift @@ -31,13 +31,13 @@ extension OrganizerView { @Environment(\.scenePhase) private var scenePhase @ObservedObject private var profileManager: ProfileManager - + @ObservedObject private var vpnManager: VPNManager - + @Binding private var alertType: AlertType? - + @Binding private var didHandleSubreddit: Bool - + @State private var isFirstLaunch = true init(alertType: Binding, didHandleSubreddit: Binding) { @@ -46,7 +46,7 @@ extension OrganizerView { _alertType = alertType _didHandleSubreddit = didHandleSubreddit } - + var body: some View { // dummy text, EmptyView() does not trigger on*() handlers @@ -55,7 +55,7 @@ extension OrganizerView { .onAppear(perform: onAppear) .onChange(of: scenePhase, perform: onScenePhase) } - + private func onAppear() { guard didHandleSubreddit else { alertType = .subscribeReddit @@ -92,7 +92,7 @@ extension OrganizerView { break } } - + private func persist() { profileManager.persist() } diff --git a/Passepartout/App/Views/OrganizerView.swift b/Passepartout/App/Views/OrganizerView.swift index e3bd7977..2dfe51e4 100644 --- a/Passepartout/App/Views/OrganizerView.swift +++ b/Passepartout/App/Views/OrganizerView.swift @@ -40,9 +40,9 @@ struct OrganizerView: View { enum AlertType: Identifiable { case subscribeReddit - + case error(String, String) - + // XXX: alert ids var id: Int { switch self { @@ -62,11 +62,11 @@ struct OrganizerView: View { @State private var isHostFileImporterPresented = false @AppStorage(AppPreference.didHandleSubreddit.key) private var didHandleSubreddit = false - + private let hostFileTypes = Constants.URLs.filetypes - + private let redditURL = Constants.URLs.subreddit - + var body: some View { debugChanges() return ZStack { @@ -93,13 +93,13 @@ struct OrganizerView: View { onCompletion: onHostFileImporterResult ).onOpenURL(perform: onOpenURL) .themePrimaryView() - + // VPN configuration error publisher (no need to observe VPNManager) .onReceive(VPNManager.shared.configurationError) { alertType = .error($0.profile.header.name, $0.error.localizedAppDescription) } } - + private var hiddenSceneView: some View { SceneView( alertType: $alertType, @@ -128,7 +128,7 @@ extension OrganizerView { ) } } - + private func onOpenURL(_ url: URL) { addProfileModalType = .addHost(url, false) } diff --git a/Passepartout/App/Views/PaywallView+Purchase.swift b/Passepartout/App/Views/PaywallView+Purchase.swift index 2852ec3f..86fb0f05 100644 --- a/Passepartout/App/Views/PaywallView+Purchase.swift +++ b/Passepartout/App/Views/PaywallView+Purchase.swift @@ -37,7 +37,7 @@ extension PaywallView { var id: Int { switch self { case .purchaseFailed: return 1 - + case .restoreFailed: return 2 } } @@ -48,19 +48,19 @@ extension PaywallView { case restoring } - + private typealias RowModel = (product: SKProduct, extra: String?) - + @Environment(\.scenePhase) private var scenePhase @ObservedObject private var productManager: ProductManager @Binding private var isPresented: Bool - + private let feature: LocalProduct? - + @State private var alertType: AlertType? - + @State private var purchaseState: PurchaseState? init(isPresented: Binding, feature: LocalProduct? = nil) { @@ -68,7 +68,7 @@ extension PaywallView { _isPresented = isPresented self.feature = feature } - + var body: some View { List { productsSection @@ -85,7 +85,7 @@ extension PaywallView { } }.themeAnimation(on: productManager.isRefreshingProducts) } - + private func presentedAlert(_ alertType: AlertType) -> Alert { switch alertType { case .purchaseFailed(let product, let error): @@ -96,7 +96,7 @@ extension PaywallView { purchaseState = nil } ) - + case .restoreFailed(let error): return Alert( title: Text(L10n.Paywall.Items.Restore.title), @@ -107,7 +107,7 @@ extension PaywallView { ) } } - + private var productsSection: some View { Section { if !productManager.isRefreshingProducts { @@ -134,7 +134,7 @@ extension PaywallView { purchaseState: purchaseState ) } - + private var restoreRow: some View { PurchaseRow( title: L10n.Paywall.Items.Restore.title, @@ -156,7 +156,7 @@ extension PaywallView.PurchaseView { switch result { case .done: isPresented = false - + case .cancelled: break } @@ -168,7 +168,7 @@ extension PaywallView.PurchaseView { } } } - + private func restorePurchases() { purchaseState = .restoring @@ -191,7 +191,7 @@ extension PaywallView.PurchaseView { } return productManager.product(withIdentifier: feature) } - + private var skPlatformVersion: SKProduct? { #if targetEnvironment(macCatalyst) productManager.product(withIdentifier: .fullVersion_macOS) @@ -258,13 +258,13 @@ private struct PurchaseRow: View { var product: SKProduct? let title: String - + let extra: String? - + let action: () -> Void - + let purchaseState: PaywallView.PurchaseView.PurchaseState? - + var body: some View { VStack(alignment: .leading) { actionButton @@ -276,7 +276,7 @@ private struct PurchaseRow: View { } }.padding([.top, .bottom]) } - + @ViewBuilder private var actionButton: some View { if let product = product { @@ -285,7 +285,7 @@ private struct PurchaseRow: View { restoreButton } } - + private func purchaseButton(_ product: SKProduct) -> some View { HStack { Button(title, action: action) @@ -300,7 +300,7 @@ private struct PurchaseRow: View { } } } - + private var restoreButton: some View { HStack { Button(title, action: action) diff --git a/Passepartout/App/Views/PaywallView.swift b/Passepartout/App/Views/PaywallView.swift index 57bd184a..51cca061 100644 --- a/Passepartout/App/Views/PaywallView.swift +++ b/Passepartout/App/Views/PaywallView.swift @@ -27,9 +27,9 @@ import SwiftUI struct PaywallView: View { @ObservedObject private var productManager: ProductManager - + @Binding private var isPresented: Bool - + private let feature: LocalProduct? init(modalType: Binding, feature: LocalProduct? = nil) { diff --git a/Passepartout/App/Views/ProfileView+Configuration.swift b/Passepartout/App/Views/ProfileView+Configuration.swift index 5560db1d..331f4c90 100644 --- a/Passepartout/App/Views/ProfileView+Configuration.swift +++ b/Passepartout/App/Views/ProfileView+Configuration.swift @@ -33,15 +33,15 @@ extension ProfileView { @ObservedObject private var currentProfile: ObservableProfile @Binding private var modalType: ModalType? - + private var isEligibleForNetworkSettings: Bool { productManager.isEligible(forFeature: .networkSettings) } - + private var isEligibleForTrustedNetworks: Bool { productManager.isEligible(forFeature: .trustedNetworks) } - + init(currentProfile: ObservableProfile, modalType: Binding) { productManager = .shared self.currentProfile = currentProfile @@ -111,7 +111,7 @@ extension ProfileView { Text(L10n.Global.Strings.configuration) } } - + private var networkSettingsRow: some View { Label(L10n.NetworkSettings.title, systemImage: themeNetworkSettingsImage) } diff --git a/Passepartout/App/Views/ProfileView+Diagnostics.swift b/Passepartout/App/Views/ProfileView+Diagnostics.swift index 07e635ed..128045e7 100644 --- a/Passepartout/App/Views/ProfileView+Diagnostics.swift +++ b/Passepartout/App/Views/ProfileView+Diagnostics.swift @@ -29,7 +29,7 @@ import PassepartoutLibrary extension ProfileView { struct DiagnosticsSection: View { @ObservedObject var currentProfile: ObservableProfile - + var body: some View { Section { NavigationLink { diff --git a/Passepartout/App/Views/ProfileView+Extra.swift b/Passepartout/App/Views/ProfileView+Extra.swift index 77b16dc1..28fc8daa 100644 --- a/Passepartout/App/Views/ProfileView+Extra.swift +++ b/Passepartout/App/Views/ProfileView+Extra.swift @@ -29,11 +29,11 @@ import PassepartoutLibrary extension ProfileView { struct ExtraSection: View { @ObservedObject private var currentProfile: ObservableProfile - + init(currentProfile: ObservableProfile) { self.currentProfile = currentProfile } - + var body: some View { if currentProfile.value.isProvider { Section { diff --git a/Passepartout/App/Views/ProfileView+MainMenu.swift b/Passepartout/App/Views/ProfileView+MainMenu.swift index d5cb0f47..fed656f9 100644 --- a/Passepartout/App/Views/ProfileView+MainMenu.swift +++ b/Passepartout/App/Views/ProfileView+MainMenu.swift @@ -30,36 +30,36 @@ extension ProfileView { struct MainMenu: View { enum ActionSheetType: Int, Identifiable { case uninstallVPN - + case deleteProfile - + var id: Int { rawValue } } - + @ObservedObject private var profileManager: ProfileManager - + @ObservedObject private var vpnManager: VPNManager - + @ObservedObject private var currentVPNState: ObservableVPNState - + @ObservedObject private var currentProfile: ObservableProfile - + private var header: Profile.Header { currentProfile.value.header } - + @Binding private var modalType: ModalType? - + @State private var actionSheetType: ActionSheetType? - + private let uninstallVPNTitle = L10n.Global.Strings.uninstall - + private let deleteProfileTitle = L10n.Global.Strings.delete - + private let cancelTitle = L10n.Global.Strings.cancel - + init(currentProfile: ObservableProfile, modalType: Binding) { profileManager = .shared vpnManager = .shared @@ -79,7 +79,7 @@ extension ProfileView { primaryButton: .destructive(Text(uninstallVPNTitle), action: uninstallVPN), secondaryButton: .cancel(Text(cancelTitle)) ) - + case .deleteProfile: return Alert( title: Text(deleteProfileTitle), @@ -114,7 +114,7 @@ extension ProfileView { themeSettingsMenuImage.asSystemImage } } - + private var isActiveProfileNotDisconnected: Bool { profileManager.isActiveProfile(header.id) && currentVPNState.vpnStatus != .disconnected } @@ -126,7 +126,7 @@ extension ProfileView { Label(uninstallVPNTitle, systemImage: themeUninstallImage) } } - + private var deleteProfileButton: some View { DestructiveButton { actionSheetType = .deleteProfile @@ -152,11 +152,11 @@ extension ProfileView { extension ProfileView { struct ReconnectButton: View { @ObservedObject private var vpnManager: VPNManager - + init() { vpnManager = .shared } - + var body: some View { Button { Task { @MainActor in @@ -167,12 +167,12 @@ extension ProfileView { } } } - + struct ShortcutsButton: View { @ObservedObject private var productManager: ProductManager - + @Binding private var modalType: ModalType? - + init(modalType: Binding) { productManager = .shared _modalType = modalType @@ -181,7 +181,7 @@ extension ProfileView { private var isEligibleForSiri: Bool { productManager.isEligible(forFeature: .siriShortcuts) } - + var body: some View { Button { presentShortcutsOrPaywall() @@ -200,14 +200,14 @@ extension ProfileView { } } } - + struct RenameButton: View { @Binding private var modalType: ModalType? - + init(modalType: Binding) { _modalType = modalType } - + var body: some View { Button { modalType = .rename @@ -219,17 +219,17 @@ extension ProfileView { struct DuplicateButton: View { @ObservedObject private var profileManager: ProfileManager - + private let header: Profile.Header - + private let setAsCurrent: Bool - + init(header: Profile.Header, setAsCurrent: Bool) { profileManager = .shared self.header = header self.setAsCurrent = setAsCurrent } - + var body: some View { Button { duplicateProfile(withId: header.id) diff --git a/Passepartout/App/Views/ProfileView+Provider.swift b/Passepartout/App/Views/ProfileView+Provider.swift index df837433..3f3ed40f 100644 --- a/Passepartout/App/Views/ProfileView+Provider.swift +++ b/Passepartout/App/Views/ProfileView+Provider.swift @@ -29,17 +29,17 @@ import PassepartoutLibrary extension ProfileView { struct ProviderSection: View, ProviderProfileAvailability { @ObservedObject var providerManager: ProviderManager - + @ObservedObject private var currentProfile: ObservableProfile - + var profile: Profile { currentProfile.value } - + @State private var isProviderLocationPresented = false @State private var isRefreshingInfrastructure = false - + init(currentProfile: ObservableProfile) { providerManager = .shared self.currentProfile = currentProfile @@ -55,7 +55,7 @@ extension ProfileView { } } } - + @ViewBuilder private var mainView: some View { Section { @@ -116,11 +116,11 @@ extension ProfileView { } return themeAssetsCountryImage(code).asAssetImage } - + private var currentProviderPreset: String? { providerManager.localizedPreset(forProfile: profile) } - + private var lastInfrastructureUpdate: String? { providerManager.localizedInfrastructureUpdate(forProfile: profile) } diff --git a/Passepartout/App/Views/ProfileView+Rename.swift b/Passepartout/App/Views/ProfileView+Rename.swift index e7b74764..70f8dcc1 100644 --- a/Passepartout/App/Views/ProfileView+Rename.swift +++ b/Passepartout/App/Views/ProfileView+Rename.swift @@ -29,20 +29,20 @@ import PassepartoutLibrary extension ProfileView { struct RenameView: View { @Environment(\.presentationMode) private var presentationMode - + @ObservedObject private var profileManager: ProfileManager - + @ObservedObject private var currentProfile: ObservableProfile - + @State private var newName = "" - + @State private var isOverwritingExistingProfile = false - + init(currentProfile: ObservableProfile) { profileManager = .shared self.currentProfile = currentProfile } - + var body: some View { List { Section { @@ -61,7 +61,7 @@ extension ProfileView { } }.alert(isPresented: $isOverwritingExistingProfile, content: alertOverwriteExistingProfile) } - + private func alertOverwriteExistingProfile() -> Alert { Alert( title: Text(L10n.Profile.Alerts.Rename.title), @@ -72,7 +72,7 @@ extension ProfileView { secondaryButton: .cancel(Text(L10n.Global.Strings.cancel)) ) } - + private func loadCurrentName() { newName = currentProfile.value.header.name } diff --git a/Passepartout/App/Views/ProfileView+VPN.swift b/Passepartout/App/Views/ProfileView+VPN.swift index 74b4f54e..4a20b6b1 100644 --- a/Passepartout/App/Views/ProfileView+VPN.swift +++ b/Passepartout/App/Views/ProfileView+VPN.swift @@ -33,7 +33,7 @@ extension ProfileView { private let profile: Profile @Binding private var modalType: ModalType? - + private var interactiveProfile: Binding { .init { modalType == .interactiveAccount ? profile : nil @@ -41,7 +41,7 @@ extension ProfileView { modalType = $0 != nil ? .interactiveAccount : nil } } - + private var isActiveProfile: Bool { profileManager.isActiveProfile(profile.id) } @@ -51,7 +51,7 @@ extension ProfileView { self.profile = profile _modalType = modalType } - + var body: some View { Section { toggleView @@ -63,7 +63,7 @@ extension ProfileView { .xxxThemeTruncation() } } - + private var toggleView: some View { VPNToggle( profile: profile, @@ -71,7 +71,7 @@ extension ProfileView { rateLimit: Constants.RateLimit.vpnToggle ) } - + private var statusView: some View { HStack { Text(L10n.Profile.Items.ConnectionStatus.caption) diff --git a/Passepartout/App/Views/ProfileView.swift b/Passepartout/App/Views/ProfileView.swift index ec26f6e3..16e84730 100644 --- a/Passepartout/App/Views/ProfileView.swift +++ b/Passepartout/App/Views/ProfileView.swift @@ -31,13 +31,13 @@ struct ProfileView: View { case interactiveAccount case shortcuts - + case rename - + case paywallShortcuts case paywallNetworkSettings - + case paywallTrustedNetworks var id: Int { @@ -46,17 +46,17 @@ struct ProfileView: View { } @ObservedObject private var currentProfile: ObservableProfile - + private var isLoading: Bool { currentProfile.isLoading } - + private var isExisting: Bool { !currentProfile.value.isPlaceholder } @State private var modalType: ModalType? - + init() { currentProfile = ProfileManager.shared.currentProfile } @@ -83,11 +83,11 @@ struct ProfileView: View { .navigationTitle(title) .themeSecondaryView() } - + private var title: String { currentProfile.name } - + private var mainView: some View { List { if !isLoading { @@ -107,7 +107,7 @@ struct ProfileView: View { } }.themeAnimation(on: isLoading) } - + @ViewBuilder private func presentedModal(_ modalType: ModalType) -> some View { switch modalType { @@ -115,17 +115,17 @@ struct ProfileView: View { NavigationView { InteractiveConnectionView(profile: currentProfile.value) }.themeGlobal() - + case .shortcuts: NavigationView { ShortcutsView(target: currentProfile.value) }.themeGlobal() - + case .rename: NavigationView { RenameView(currentProfile: currentProfile) }.themeGlobal() - + case .paywallShortcuts: NavigationView { PaywallView( diff --git a/Passepartout/App/Views/ProviderLocationView.swift b/Passepartout/App/Views/ProviderLocationView.swift index 72b3b029..80ff1515 100644 --- a/Passepartout/App/Views/ProviderLocationView.swift +++ b/Passepartout/App/Views/ProviderLocationView.swift @@ -30,13 +30,13 @@ struct ProviderLocationView: View, ProviderProfileAvailability { @ObservedObject var providerManager: ProviderManager @ObservedObject private var currentProfile: ObservableProfile - + var profile: Profile { currentProfile.value } private let isEditable: Bool - + private var providerName: ProviderName { guard let name = currentProfile.value.header.providerName else { assertionFailure("Not a provider") @@ -44,15 +44,15 @@ struct ProviderLocationView: View, ProviderProfileAvailability { } return name } - + private var vpnProtocol: VPNProtocolType { currentProfile.value.currentVPNProtocol } @Binding private var selectedServer: ProviderServer? - + @Binding private var favoriteLocationIds: Set? - + @AppStorage(AppPreference.isShowingFavorites.key) private var isShowingFavorites = false private var isShowingEmptyFavorites: Bool { @@ -61,7 +61,7 @@ struct ProviderLocationView: View, ProviderProfileAvailability { } return favoriteLocationIds?.isEmpty ?? true } - + // XXX: do not escape mutating 'self', use constant providerManager init(currentProfile: ObservableProfile, isEditable: Bool, isPresented: Binding) { let providerManager: ProviderManager = .shared @@ -69,7 +69,7 @@ struct ProviderLocationView: View, ProviderProfileAvailability { self.providerManager = providerManager self.currentProfile = currentProfile self.isEditable = isEditable - + _selectedServer = .init { guard let serverId = currentProfile.value.providerServerId() else { return nil @@ -89,7 +89,7 @@ struct ProviderLocationView: View, ProviderProfileAvailability { currentProfile.value.setProviderFavoriteLocationIds($0) } } - + var body: some View { debugChanges() return Group { @@ -110,7 +110,7 @@ struct ProviderLocationView: View, ProviderProfileAvailability { } }.navigationTitle(L10n.Provider.Location.title) } - + private var mainView: some View { // FIXME: layout, restore ScrollViewReader, but content inside it is not re-rendered on isShowingFavorites // ScrollViewReader { scrollProxy in @@ -129,7 +129,7 @@ struct ProviderLocationView: View, ProviderProfileAvailability { private var categoriesView: some View { ForEach(categories, content: categorySection) } - + private func categorySection(_ category: ProviderCategory) -> some View { Section { ForEach(filteredLocations(for: category)) { location in @@ -146,7 +146,7 @@ struct ProviderLocationView: View, ProviderProfileAvailability { !category.name.isEmpty ? Text(category.name) : nil } } - + @ViewBuilder private func locationRow(_ location: ProviderLocation) -> some View { if let onlyServer = location.onlyServer { @@ -155,7 +155,7 @@ struct ProviderLocationView: View, ProviderProfileAvailability { multipleServersRow(location) } } - + private func multipleServersRow(_ location: ProviderLocation) -> some View { NavigationLink(destination: { ServerListView( @@ -180,7 +180,7 @@ struct ProviderLocationView: View, ProviderProfileAvailability { ) } } - + private var emptyFavoritesSection: some View { Section { } footer: { @@ -204,7 +204,7 @@ extension ProviderLocationView { private func server(withId serverId: String) -> ProviderServer? { providerManager.server(withId: serverId) } - + private var categories: [ProviderCategory] { providerManager.categories(providerName, vpnProtocol: vpnProtocol) .filter { @@ -223,11 +223,11 @@ extension ProviderLocationView { } return locations.sorted() } - + private func isFavoriteLocation(_ location: ProviderLocation) -> Bool { favoriteLocationIds?.contains(location.id) ?? false } - + private func toggleFavoriteLocation(_ location: ProviderLocation) { if !isFavoriteLocation(location) { if favoriteLocationIds == nil { @@ -248,7 +248,7 @@ extension ProviderLocationView { let location: ProviderLocation let selectedLocationId: String? - + var body: some View { HStack { themeAssetsCountryImage(location.countryCode).asAssetImage @@ -269,11 +269,11 @@ extension ProviderLocationView { struct ServerListView: View { @ObservedObject private var providerManager: ProviderManager - + private let location: ProviderLocation @Binding private var selectedServer: ProviderServer? - + init(location: ProviderLocation, selectedServer: Binding) { providerManager = .shared self.location = location diff --git a/Passepartout/App/Views/ProviderPresetView.swift b/Passepartout/App/Views/ProviderPresetView.swift index a62c4214..50496f1d 100644 --- a/Passepartout/App/Views/ProviderPresetView.swift +++ b/Passepartout/App/Views/ProviderPresetView.swift @@ -34,13 +34,13 @@ struct ProviderPresetView: View { @ObservedObject private var currentProfile: ObservableProfile private var server: ProviderServer? - + @Binding private var selectedPreset: ProviderServer.Preset? // XXX: do not escape mutating 'self', use constant providerManager init(currentProfile: ObservableProfile) { let providerManager: ProviderManager = .shared - + self.providerManager = providerManager self.currentProfile = currentProfile @@ -61,7 +61,7 @@ struct ProviderPresetView: View { currentProfile.value.setProviderPreset(preset) } } - + var body: some View { List { ForEach(availablePresets, id: \.id, content: presetSection) @@ -77,7 +77,7 @@ struct ProviderPresetView: View { presetSelectionRow(preset) } NavigationLink(L10n.Endpoint.Advanced.title) { - + // TODO: WireGuard, preset assumes OpenVPN (read current protocol instead) preset.openVPNConfiguration.map { EndpointAdvancedView.OpenVPNView( @@ -91,7 +91,7 @@ struct ProviderPresetView: View { Text(preset.name) } } - + private func presetSelectionRow(_ preset: ProviderServer.Preset) -> some View { Text(preset.comment) .withTrailingCheckmark(when: preset.id == selectedPreset?.id) diff --git a/Passepartout/App/Views/ReportIssueView.swift b/Passepartout/App/Views/ReportIssueView.swift index 3176e31a..9cc28d9a 100644 --- a/Passepartout/App/Views/ReportIssueView.swift +++ b/Passepartout/App/Views/ReportIssueView.swift @@ -29,15 +29,15 @@ import PassepartoutLibrary struct ReportIssueView: View { @Binding private var isPresented: Bool - + private let toRecipients: [String] - + private let subject: String - + private let messageBody: String - + private let attachments: [MailComposerView.Attachment] - + init( isPresented: Binding, vpnProtocol: VPNProtocolType, @@ -46,7 +46,7 @@ struct ReportIssueView: View { lastUpdate: Date? = nil ) { _isPresented = isPresented - + toRecipients = [Unlocalized.Issues.recipient] subject = Unlocalized.Issues.subject @@ -77,7 +77,7 @@ struct ReportIssueView: View { } self.attachments = attachments } - + var body: some View { MailComposerView( isPresented: $isPresented, diff --git a/Passepartout/App/Views/SettingsView.swift b/Passepartout/App/Views/SettingsView.swift index 623357cc..34574409 100644 --- a/Passepartout/App/Views/SettingsView.swift +++ b/Passepartout/App/Views/SettingsView.swift @@ -30,9 +30,9 @@ struct SettingsView: View { @ObservedObject private var profileManager: ProfileManager @ObservedObject private var productManager: ProductManager - + @Environment(\.presentationMode) private var presentationMode - + // private var isTestBuild: Bool { // Constants.App.isBeta || Constants.InApp.appType == .beta // } @@ -45,7 +45,7 @@ struct SettingsView: View { profileManager = .shared productManager = .shared } - + var body: some View { List { aboutSection @@ -54,7 +54,7 @@ struct SettingsView: View { }.themeSecondaryView() .navigationTitle(L10n.Settings.title) } - + private var aboutSection: some View { Section { NavigationLink { diff --git a/Passepartout/App/Views/ShortcutsView+Add.swift b/Passepartout/App/Views/ShortcutsView+Add.swift index 1525ac0a..5adea811 100644 --- a/Passepartout/App/Views/ShortcutsView+Add.swift +++ b/Passepartout/App/Views/ShortcutsView+Add.swift @@ -30,11 +30,11 @@ import PassepartoutLibrary extension ShortcutsView { struct AddView: View { @ObservedObject private var providerManager: ProviderManager - + @StateObject private var pendingProfile = ObservableProfile() private let target: Profile - + @Binding private var pendingShortcut: INShortcut? @State private var isPresentingProviderLocation = false @@ -44,7 +44,7 @@ extension ShortcutsView { self.target = target _pendingShortcut = pendingShortcut } - + var body: some View { ZStack { hiddenProviderLocationLink @@ -82,7 +82,7 @@ extension ShortcutsView { } } } - + private var hiddenProviderLocationLink: some View { NavigationLink("", isActive: $isPresentingProviderLocation) { ProviderLocationView( @@ -106,7 +106,7 @@ extension ShortcutsView.AddView { } } } - + private func addConnect(_ header: Profile.Header) { pendingShortcut = INShortcut(intent: IntentDispatcher.intentConnect( header: header diff --git a/Passepartout/App/Views/ShortcutsView.swift b/Passepartout/App/Views/ShortcutsView.swift index 2f3d5d37..bb8c60d8 100644 --- a/Passepartout/App/Views/ShortcutsView.swift +++ b/Passepartout/App/Views/ShortcutsView.swift @@ -30,35 +30,35 @@ import PassepartoutLibrary struct ShortcutsView: View { enum ModalType: Identifiable { case edit(shortcut: Shortcut) - + case add(shortcut: INShortcut) - + // XXX: alert ids var id: Int { switch self { case .edit: return 1 - + case .add: return 2 } } } @StateObject private var intentsManager = IntentsManager() - + @Environment(\.presentationMode) private var presentationMode - + private let target: Profile @State private var modalType: ModalType? - + @State private var isNavigationPresented = false - + @State private var pendingShortcut: INShortcut? - + init(target: Profile) { self.target = target } - + var body: some View { List { if !intentsManager.shortcuts.isEmpty { @@ -69,16 +69,16 @@ struct ShortcutsView: View { themeCloseItem(presentationMode: presentationMode) }.sheet(item: $modalType, content: presentedModal) .themeAnimation(on: intentsManager.isReloadingShortcuts) - + // IntentsUI .onReceive(intentsManager.shouldDismissIntentView) { _ in modalType = nil } - + .navigationTitle(Unlocalized.Other.siri) .themeSecondaryView() } - + private var shortcutsSection: some View { Section { ForEach(relevantShortcuts, content: rowView) @@ -86,13 +86,13 @@ struct ShortcutsView: View { Text(L10n.Shortcuts.Edit.Sections.All.header) } } - + private var relevantShortcuts: [Shortcut] { intentsManager.shortcuts.values.filter { $0.isRelevant(to: target) }.sorted() } - + private var addSection: some View { Section { NavigationLink(isActive: $isNavigationPresented) { @@ -116,7 +116,7 @@ struct ShortcutsView: View { shortcut: shortcut, delegate: intentsManager ) - + case .add(let shortcut): IntentAddView( shortcut: shortcut, @@ -124,7 +124,7 @@ struct ShortcutsView: View { ) } } - + private func rowView(forShortcut vs: Shortcut) -> some View { Button { presentEditShortcut(vs) @@ -143,7 +143,7 @@ struct ShortcutsView: View { presentAddShortcut(pendingShortcut) } } - + private func presentEditShortcut(_ shortcut: Shortcut) { modalType = .edit(shortcut: shortcut) } diff --git a/Passepartout/App/Views/VPNStatusText.swift b/Passepartout/App/Views/VPNStatusText.swift index 36bdd3e3..017aad4c 100644 --- a/Passepartout/App/Views/VPNStatusText.swift +++ b/Passepartout/App/Views/VPNStatusText.swift @@ -28,14 +28,14 @@ import PassepartoutLibrary struct VPNStatusText: View { @ObservedObject private var currentVPNState: ObservableVPNState - + let isActiveProfile: Bool - + init(isActiveProfile: Bool) { currentVPNState = .shared self.isActiveProfile = isActiveProfile } - + var body: some View { Text(statusText) } diff --git a/Passepartout/App/Views/VPNToggle.swift b/Passepartout/App/Views/VPNToggle.swift index baaf7ef7..1fe5f81c 100644 --- a/Passepartout/App/Views/VPNToggle.swift +++ b/Passepartout/App/Views/VPNToggle.swift @@ -36,11 +36,11 @@ struct VPNToggle: View { @ObservedObject private var productManager: ProductManager private let profile: Profile - + @Binding private var interactiveProfile: Profile? - + private let rateLimit: Int - + private var isEnabled: Binding { .init { isActiveProfile && currentVPNState.isEnabled && !shouldPromptForAccount @@ -56,11 +56,11 @@ struct VPNToggle: View { enableVPN() } } - + private var isActiveProfile: Bool { profileManager.isActiveProfile(profile.id) } - + private var shouldPromptForAccount: Bool { profile.account.authenticationMethod == .interactive && (currentVPNState.vpnStatus == .disconnecting || currentVPNState.vpnStatus == .disconnected) } @@ -68,9 +68,9 @@ struct VPNToggle: View { private var isEligibleForSiri: Bool { productManager.isEligible(forFeature: .siriShortcuts) } - + @State private var canToggle = true - + init(profile: Profile, interactiveProfile: Binding, rateLimit: Int) { profileManager = .shared vpnManager = .shared @@ -86,7 +86,7 @@ struct VPNToggle: View { .disabled(!canToggle) .themeAnimation(on: currentVPNState.isEnabled) } - + private func enableVPN() { Task { @MainActor in canToggle = false @@ -101,7 +101,7 @@ struct VPNToggle: View { } } } - + private func disableVPN() { Task { @MainActor in canToggle = false @@ -109,7 +109,7 @@ struct VPNToggle: View { canToggle = true } } - + private func donateIntents(withProfile profile: Profile) { // eligibility: donate intents if eligible for Siri diff --git a/Passepartout/App/Views/View+Extensions.swift b/Passepartout/App/Views/View+Extensions.swift index e6842f60..698329ab 100644 --- a/Passepartout/App/Views/View+Extensions.swift +++ b/Passepartout/App/Views/View+Extensions.swift @@ -52,7 +52,7 @@ extension View { self } } - + func withLeadingLabel(_ text: String, color: Color? = nil, image: String) -> some View { HStack { Label(text, image: image) @@ -80,7 +80,7 @@ extension View { } } } - + func withTrailingCheckmark(when condition: Bool) -> some View { HStack { self @@ -91,7 +91,7 @@ extension View { } } } - + func withTrailingProgress(when condition: Bool) -> some View { HStack { self @@ -145,7 +145,7 @@ private extension View { } private struct HostingWindowFinder: UIViewRepresentable { - var callback: (UIWindow?) -> () + var callback: (UIWindow?) -> Void func makeUIView(context: Context) -> UIView { let view = UIView() diff --git a/Passepartout/AppShared/Context/CoreContext.swift b/Passepartout/AppShared/Context/CoreContext.swift index c45514bd..d54a82c2 100644 --- a/Passepartout/AppShared/Context/CoreContext.swift +++ b/Passepartout/AppShared/Context/CoreContext.swift @@ -30,11 +30,11 @@ import PassepartoutLibrary @MainActor class CoreContext { let store: KeyValueStore - + private let profilesPersistence: Persistence - + private let providersPersistence: Persistence - + var urlsForProfiles: [URL]? { profilesPersistence.containerURLs } @@ -44,18 +44,18 @@ class CoreContext { } let upgradeManager: UpgradeManager - + let providerManager: ProviderManager - + let profileManager: ProfileManager - + let vpnManager: VPNManager - + private var cancellables: Set = [] - + init(store: KeyValueStore) { self.store = store - + let persistenceManager = PersistenceManager(store: store) profilesPersistence = persistenceManager.profilesPersistence( withName: Constants.Persistence.profilesContainerName @@ -106,12 +106,12 @@ class CoreContext { providerManager: providerManager, strategy: strategy ) - + // post - + configureObjects() } - + private func configureObjects() { providerManager.rateLimitMilliseconds = Constants.RateLimit.providerManager vpnManager.tunnelLogPath = Constants.Log.Tunnel.path diff --git a/Passepartout/AppShared/L10n/Core+L10n.swift b/Passepartout/AppShared/L10n/Core+L10n.swift index 2e2bac92..aa17c220 100644 --- a/Passepartout/AppShared/L10n/Core+L10n.swift +++ b/Passepartout/AppShared/L10n/Core+L10n.swift @@ -41,16 +41,16 @@ extension PassepartoutError { switch self { case .missingProfile: return V.missingProfile - + case .missingAccount: return V.missingAccount - + case .missingProviderServer: return V.missingProviderServer - + case .missingProviderPreset: return V.missingProviderPreset - + default: return nil } @@ -103,7 +103,7 @@ extension Network.Choice { switch self { case .automatic: return L10n.Global.Strings.automatic - + case .manual: return L10n.Global.Strings.manual } @@ -115,7 +115,7 @@ extension Network.DNSSettings.ConfigurationType { switch self { case .plain: return Unlocalized.DNS.plain - + case .https: return Unlocalized.Network.https @@ -133,10 +133,10 @@ extension Network.ProxySettings.ConfigurationType { switch self { case .manual: return L10n.Global.Strings.manual - + case .pac: return Unlocalized.Network.proxyAutoConfiguration - + case .disabled: return L10n.Global.Strings.disabled } diff --git a/Passepartout/AppShared/L10n/OpenVPN+L10n.swift b/Passepartout/AppShared/L10n/OpenVPN+L10n.swift index 9bf659f5..17f8428c 100644 --- a/Passepartout/AppShared/L10n/OpenVPN+L10n.swift +++ b/Passepartout/AppShared/L10n/OpenVPN+L10n.swift @@ -43,10 +43,10 @@ extension OpenVPN.CompressionFraming { switch self { case .disabled: return L10n.Global.Strings.disabled - + case .compLZO: return Unlocalized.OpenVPN.compLZO - + case .compress, .compressV2: return Unlocalized.OpenVPN.compress } @@ -59,10 +59,10 @@ extension OpenVPN.CompressionAlgorithm { switch self { case .disabled: return L10n.Global.Strings.disabled - + case .LZO: return Unlocalized.OpenVPN.lzo - + case .other: return V.CompressionAlgorithm.Value.other } @@ -90,26 +90,26 @@ extension OpenVPN.XORMethod { switch self { case .xormask: return Unlocalized.OpenVPN.XOR.xormask.rawValue - + case .xorptrpos: return Unlocalized.OpenVPN.XOR.xorptrpos.rawValue - + case .reverse: return Unlocalized.OpenVPN.XOR.reverse.rawValue - + case .obfuscate: return Unlocalized.OpenVPN.XOR.obfuscate.rawValue } } - + var localizedLongDescription: String { switch self { case .xormask(let mask): return "\(localizedDescription) \(mask.toHex())" - + case .obfuscate(let mask): return "\(localizedDescription) \(mask.toHex())" - + default: return localizedDescription } @@ -139,7 +139,7 @@ extension Bool { let V = L10n.Global.Strings.self return self ? V.enabled : V.disabled } - + var localizedDescriptionAsRandomizeHostnames: String { let V = L10n.Global.Strings.self return self ? V.enabled : V.disabled @@ -151,10 +151,10 @@ extension OpenVPN.PullMask { switch self { case .routes: return L10n.Endpoint.Advanced.Openvpn.Items.Route.caption - + case .dns: return Unlocalized.Network.dns - + case .proxy: return L10n.Global.Strings.proxy } diff --git a/Passepartout/AppShared/L10n/Providers+L10n.swift b/Passepartout/AppShared/L10n/Providers+L10n.swift index 58dd6eb7..6301d9fe 100644 --- a/Passepartout/AppShared/L10n/Providers+L10n.swift +++ b/Passepartout/AppShared/L10n/Providers+L10n.swift @@ -33,7 +33,7 @@ extension ProviderManager { } return profile.providerPreset(server)?.localizedDescription } - + func localizedInfrastructureUpdate(forProfile profile: Profile) -> String? { guard let providerName = profile.header.providerName else { return nil diff --git a/Passepartout/AppShared/L10n/TunnelKit+L10n.swift b/Passepartout/AppShared/L10n/TunnelKit+L10n.swift index 5cbbdd2b..13841e85 100644 --- a/Passepartout/AppShared/L10n/TunnelKit+L10n.swift +++ b/Passepartout/AppShared/L10n/TunnelKit+L10n.swift @@ -35,13 +35,13 @@ extension VPNStatus { switch self { case .connecting: return L10n.Tunnelkit.Vpn.connecting - + case .connected: return L10n.Tunnelkit.Vpn.active - + case .disconnecting: return L10n.Tunnelkit.Vpn.disconnecting - + case .disconnected: return L10n.Tunnelkit.Vpn.inactive } @@ -121,37 +121,37 @@ extension Error { } return localizedDescription } - + private func ovpnErrorDescription(_ error: OpenVPNProviderError) -> String? { let V = L10n.Tunnelkit.Errors.Vpn.self switch error { case .socketActivity, .timeout: return V.timeout - + case .dnsFailure: return V.dns - + case .tlsInitialization, .tlsServerVerification, .tlsHandshake: return V.tls - + case .authentication: return V.auth - + case .encryptionInitialization, .encryptionData: return V.encryption case .serverCompression, .lzo: return V.compression - + case .networkChanged: return V.network - + case .routing: return V.routing - + case .gatewayUnattainable: return V.gateway - + case .serverShutdown: return V.shutdown @@ -184,7 +184,7 @@ extension Error { pp_log.error("Could not parse configuration URL: \(localizedDescription)") return L10n.Tunnelkit.Errors.parsing(localizedDescription) } - + private func ovpnErrorDescription(_ error: OpenVPN.ConfigurationError) -> String { let V = L10n.Tunnelkit.Errors.Openvpn.self switch error { @@ -203,7 +203,7 @@ extension Error { case .missingConfiguration(let option): pp_log.error("Could not parse configuration URL: missing configuration, \(option)") return V.requiredOption(option) - + case .unsupportedConfiguration(var option): if option.contains("external") { option.append(" (see FAQ)") diff --git a/Passepartout/AppShared/L10n/Unlocalized.swift b/Passepartout/AppShared/L10n/Unlocalized.swift index 65216f95..2746da4f 100644 --- a/Passepartout/AppShared/L10n/Unlocalized.swift +++ b/Passepartout/AppShared/L10n/Unlocalized.swift @@ -28,24 +28,24 @@ import PassepartoutLibrary enum Unlocalized { static let appName = Constants.Global.appName - + enum Placeholders { static let empty = "" static let address = "0.0.0.0" - + static let port = "8080" static let hostname = "example.com" static let dohURL = "https://example.com/dns-query" - + static let dotServerName = hostname static let dnsAddress = address static let dnsDomain = hostname - + static let pacURL = "https://proxy/auto-conf" static let proxyBypassDomain = hostname @@ -54,24 +54,24 @@ enum Unlocalized { enum DNS { static let plain = "Cleartext" } - + enum Keychain { static func passwordLabel(_ profileName: String, vpnProtocol: VPNProtocolType) -> String { "\(Constants.Global.appName): \(profileName) (\(vpnProtocol.description))" } } - + enum Issues { static let recipient = "issues@\(Constants.Domain.name)" - + static let subject = "\(appName) - Report issue" - + static func body(_ description: String, _ metadata: String) -> String { "Hi,\n\n\(description)\n\n\(metadata)\n\nRegards" } - + static let template = "description of the issue: " - + static let maxLogBytes = UInt64(20000) enum Filenames { @@ -81,13 +81,13 @@ enum Unlocalized { let iso = fmt.string(from: Date()) return "debug-\(iso).txt" } - + static let configuration = "profile.ovpn" // static let configuration = "profile.ovpn.txt" - + static let template = "description of the issue: " } - + enum MIME { static let debugLog = "text/plain" @@ -98,9 +98,9 @@ enum Unlocalized { enum Social { static let reddit = "Reddit" - + private static let twitterHashtags = ["OpenVPN", "WireGuard", "iOS", "macOS"] - + static func twitterIntent(withMessage message: String) -> URL { var text = message for ht in twitterHashtags { @@ -121,7 +121,7 @@ enum Unlocalized { static let recipient = "translate@\(Constants.Domain.name)" static let subject = "\(appName) - Translations" - + static func body(_ description: String) -> String { "Hi,\n\n\(description)\n\nRegards" } @@ -148,9 +148,9 @@ enum Unlocalized { enum Credits { typealias License = (String, String, URL) - + typealias Notice = (String, String) - + static let author = "Davide De Rosa" static let licenses: [License] = [( @@ -178,7 +178,7 @@ enum Unlocalized { "MIT", URL(string: "https://raw.githubusercontent.com/SwiftyBeaver/SwiftyBeaver/master/LICENSE")! )] - + static let notices: [Notice] = [( "Circle Icons", "The logo is taken from the awesome Circle Icons set by Nick Roach." @@ -196,63 +196,63 @@ enum Unlocalized { enum About { static let github = "GitHub" - + static let readme = "README" - + static let changelog = "CHANGELOG" - + static let faq = "FAQ" } - + enum VPN { static let vpn = "VPN" - + static let certificateAuthority = "CA" static let xor = "XOR" } - + enum OpenVPN { static let compLZO = "--comp-lzo" - + static let compress = "--compress" - + static let lzo = "LZO" - + enum XOR: String { case xormask - + case xorptrpos - + case reverse - + case obfuscate } } - + enum Network { static let dns = "DNS" - + static let tls = "TLS" static let https = "HTTPS" static let url = "URL" - + static let mtu = "MTU" - + static let ipv4 = "IPv4" static let ipv6 = "IPv6" - + static let ssid = "SSID" - + static let proxyAutoConfiguration = "PAC" } enum Other { static let siri = "Siri" - + static let totp = "TOTP" } } diff --git a/Passepartout/AppShared/Mac/MacBridge.swift b/Passepartout/AppShared/Mac/MacBridge.swift index 1354c9c1..05f0cf60 100644 --- a/Passepartout/AppShared/Mac/MacBridge.swift +++ b/Passepartout/AppShared/Mac/MacBridge.swift @@ -28,8 +28,8 @@ import Foundation @objc(MacBridge) public protocol MacBridge: NSObjectProtocol { init() - + var utils: MacUtils { get } - + var menu: MacMenu { get } } diff --git a/Passepartout/AppShared/Mac/MacUtils.swift b/Passepartout/AppShared/Mac/MacUtils.swift index d74d97ca..9e8aa09f 100644 --- a/Passepartout/AppShared/Mac/MacUtils.swift +++ b/Passepartout/AppShared/Mac/MacUtils.swift @@ -28,7 +28,7 @@ import Foundation @objc public protocol MacUtils { var isStartedByLauncher: Bool { get } - + func sendAppToBackground() } diff --git a/Passepartout/AppShared/Mac/Models/LightProfileManager.swift b/Passepartout/AppShared/Mac/Models/LightProfileManager.swift index a20bb7ae..7ebb9e06 100644 --- a/Passepartout/AppShared/Mac/Models/LightProfileManager.swift +++ b/Passepartout/AppShared/Mac/Models/LightProfileManager.swift @@ -28,13 +28,13 @@ import Foundation @objc(LightProfile) public protocol LightProfile { var id: UUID { get } - + var name: String { get } - + var vpnProtocol: String { get } var isActive: Bool { get } - + var providerName: String? { get } var providerServer: LightProviderServer? { get } @@ -50,13 +50,13 @@ extension LightProfile { @objc public protocol LightProfileManager { var hasProfiles: Bool { get } - + var profiles: [LightProfile] { get } var activeProfileId: UUID? { get } - + var activeProfileName: String? { get } - + var delegate: LightProfileManagerDelegate? { get set } } diff --git a/Passepartout/AppShared/Mac/Models/LightProviderManager.swift b/Passepartout/AppShared/Mac/Models/LightProviderManager.swift index 938d5feb..de833782 100644 --- a/Passepartout/AppShared/Mac/Models/LightProviderManager.swift +++ b/Passepartout/AppShared/Mac/Models/LightProviderManager.swift @@ -39,20 +39,20 @@ public protocol LightProviderLocation { var id: String { get } var countryCode: String { get } - + var servers: [LightProviderServer] { get } } @objc(LightProviderServer) public protocol LightProviderServer { var description: String { get } - + var longDescription: String { get } - + var categoryName: String { get } var locationId: String { get } - + var serverId: String { get } } @@ -60,7 +60,7 @@ public protocol LightProviderServer { @objc public protocol LightProviderManager { var delegate: LightProviderManagerDelegate? { get set } - + func categories(_ name: String, vpnProtocol: String) -> [LightProviderCategory] func downloadIfNeeded(_ name: String, vpnProtocol: String) diff --git a/Passepartout/AppShared/Mac/Models/LightUtils.swift b/Passepartout/AppShared/Mac/Models/LightUtils.swift index 0b8be1bb..f81ea25a 100644 --- a/Passepartout/AppShared/Mac/Models/LightUtils.swift +++ b/Passepartout/AppShared/Mac/Models/LightUtils.swift @@ -28,6 +28,6 @@ import Foundation @objc public protocol LightUtils { var launchesOnLogin: Bool { get set } - + func requestScene() } diff --git a/Passepartout/AppShared/Mac/Models/LightVPNManager.swift b/Passepartout/AppShared/Mac/Models/LightVPNManager.swift index c4bad2fb..4457aa6c 100644 --- a/Passepartout/AppShared/Mac/Models/LightVPNManager.swift +++ b/Passepartout/AppShared/Mac/Models/LightVPNManager.swift @@ -28,11 +28,11 @@ import Foundation @objc(LightVPNStatus) public enum LightVPNStatus: Int { case connecting - + case connected - + case disconnecting - + case disconnected } @@ -42,19 +42,19 @@ public protocol LightVPNManager { var isEnabled: Bool { get } var vpnStatus: LightVPNStatus { get } - + func connect(with profileId: UUID) - + func connect(with profileId: UUID, to serverId: String) - + func disconnect() - + func toggle() - + func reconnect() - + func addDelegate(_ delegate: LightVPNManagerDelegate, withIdentifier identifier: String) - + func removeDelegate(withIdentifier identifier: String) } diff --git a/Passepartout/AppShared/Menu/MenuBuilder.swift b/Passepartout/AppShared/Menu/MenuBuilder.swift index 5c4854b7..cb4918be 100644 --- a/Passepartout/AppShared/Menu/MenuBuilder.swift +++ b/Passepartout/AppShared/Menu/MenuBuilder.swift @@ -28,10 +28,10 @@ import Foundation @objc(MenuBuilder) public protocol MenuBuilder: NSObjectProtocol { weak var delegate: MenuDelegate? { get set } - + init() func sendAppToBackground() - + func buildMenu() } diff --git a/Passepartout/Launcher/AppDelegate.swift b/Passepartout/Launcher/AppDelegate.swift index 26b82779..f2f891fe 100644 --- a/Passepartout/Launcher/AppDelegate.swift +++ b/Passepartout/Launcher/AppDelegate.swift @@ -28,7 +28,7 @@ import AppKit class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject { private let appURL = Constants.Launcher.appURL - + private var isAppRunning: Bool { NSWorkspace.shared.runningApplications.contains { $0.bundleIdentifier == Constants.Launcher.appId @@ -40,12 +40,12 @@ class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject { NSApp.terminate(self) return } - + let cfg = NSWorkspace.OpenConfiguration() cfg.hides = true cfg.activates = false cfg.addsToRecentItems = false - NSWorkspace.shared.openApplication(at: appURL, configuration: cfg) { app, error in + NSWorkspace.shared.openApplication(at: appURL, configuration: cfg) { _, error in if let error = error { NSLog("Unable to launch main app: \(error)") return diff --git a/Passepartout/Mac/Constants/Constants+Mac.swift b/Passepartout/Mac/Constants/Constants+Mac.swift index 2dfc808c..7ac8a45d 100644 --- a/Passepartout/Mac/Constants/Constants+Mac.swift +++ b/Passepartout/Mac/Constants/Constants+Mac.swift @@ -30,7 +30,7 @@ extension Constants { static var bundle: Bundle { Bundle(for: PassepartoutMac.self) } - + static let appLauncherId: String = bundleConfig("launcher_id", in: bundle) } } diff --git a/Passepartout/Mac/Constants/Theme.swift b/Passepartout/Mac/Constants/Theme.swift index 266378c9..c1642c3e 100644 --- a/Passepartout/Mac/Constants/Theme.swift +++ b/Passepartout/Mac/Constants/Theme.swift @@ -52,7 +52,7 @@ extension LightVPNStatus { switch self { case .connected, .disconnected: resourceName = "StatusActive" - + case .connecting, .disconnecting: resourceName = "StatusPending" } @@ -61,12 +61,12 @@ extension LightVPNStatus { } return image } - + var imageAlpha: Double { switch self { case .disconnected: return 0.5 - + default: return 1.0 } diff --git a/Passepartout/Mac/Mac/DefaultMacMenu.swift b/Passepartout/Mac/Mac/DefaultMacMenu.swift index e9e6f93c..27c567f6 100644 --- a/Passepartout/Mac/Mac/DefaultMacMenu.swift +++ b/Passepartout/Mac/Mac/DefaultMacMenu.swift @@ -27,14 +27,14 @@ import Foundation class DefaultMacMenu: MacMenu { weak var delegate: MacMenuDelegate? - + private lazy var menu: PassepartoutMenu = { guard let delegate = delegate else { fatalError("Must set MacMenu.delegate") } return PassepartoutMenu(macMenuDelegate: delegate) }() - + func install() { menu.install() } diff --git a/Passepartout/Mac/Mac/DefaultMacUtils.swift b/Passepartout/Mac/Mac/DefaultMacUtils.swift index 2b58437e..1bd16f67 100644 --- a/Passepartout/Mac/Mac/DefaultMacUtils.swift +++ b/Passepartout/Mac/Mac/DefaultMacUtils.swift @@ -28,9 +28,9 @@ import AppKit class DefaultMacUtils: MacUtils { private(set) lazy var isStartedByLauncher = NSApp.isHidden - + private let transformer = ObservableProcessTransformer.shared - + func sendAppToBackground() { transformer.sendToBackground() } diff --git a/Passepartout/Mac/Menu/HostProfileItem+ViewModel.swift b/Passepartout/Mac/Menu/HostProfileItem+ViewModel.swift index 312fec5a..59b2b163 100644 --- a/Passepartout/Mac/Menu/HostProfileItem+ViewModel.swift +++ b/Passepartout/Mac/Menu/HostProfileItem+ViewModel.swift @@ -32,30 +32,30 @@ extension HostProfileItem { let profile: LightProfile private let vpnManager: LightVPNManager - + private var didUpdate: ((LightVPNStatus) -> Void)? init(_ profile: LightProfile, vpnManager: LightVPNManager) { self.profile = profile self.vpnManager = vpnManager - + vpnManager.addDelegate(self, withIdentifier: profile.id.uuidString) } - + deinit { Task { @MainActor in vpnManager.removeDelegate(withIdentifier: profile.id.uuidString) } } - + @objc func connectTo() { vpnManager.connect(with: profile.id) } - + @objc func disconnect() { vpnManager.disconnect() } - + func subscribe(_ block: @escaping (LightVPNStatus) -> Void) { didUpdate = block } diff --git a/Passepartout/Mac/Menu/HostProfileItem.swift b/Passepartout/Mac/Menu/HostProfileItem.swift index 6a43d5f6..478b79bf 100644 --- a/Passepartout/Mac/Menu/HostProfileItem.swift +++ b/Passepartout/Mac/Menu/HostProfileItem.swift @@ -28,11 +28,11 @@ import AppKit struct HostProfileItem: Item { private let viewModel: ViewModel - + init(_ profile: LightProfile, vpnManager: LightVPNManager) { viewModel = ViewModel(profile, vpnManager: vpnManager) } - + func asMenuItem(withParent parent: NSMenu) -> NSMenuItem { let item = NSMenuItem( title: viewModel.profile.name, @@ -44,7 +44,7 @@ struct HostProfileItem: Item { item.representedObject = viewModel return item } - + private func submenu() -> NSMenu { let menu = NSMenu() menu.autoenablesItems = false diff --git a/Passepartout/Mac/Menu/LaunchOnLoginItem+ViewModel.swift b/Passepartout/Mac/Menu/LaunchOnLoginItem+ViewModel.swift index d3aeee5b..a5922059 100644 --- a/Passepartout/Mac/Menu/LaunchOnLoginItem+ViewModel.swift +++ b/Passepartout/Mac/Menu/LaunchOnLoginItem+ViewModel.swift @@ -34,7 +34,7 @@ extension LaunchOnLoginItem { let title: String let utils: LightUtils - + var persistentlyLaunchesOnLogin: Bool { get { launchesOnLogin @@ -47,7 +47,7 @@ extension LaunchOnLoginItem { objectWillChange.send() } } - + private var launchesOnLogin: Bool { get { utils.launchesOnLogin @@ -56,18 +56,18 @@ extension LaunchOnLoginItem { utils.launchesOnLogin = newValue } } - + private var subscriptions: Set = [] init(_ title: String, utils: LightUtils) { self.title = title self.utils = utils } - + @objc func toggleLaunchesOnLogin() { persistentlyLaunchesOnLogin.toggle() } - + func subscribe(_ block: @escaping (Bool) -> Void) { objectWillChange .sink { diff --git a/Passepartout/Mac/Menu/LaunchOnLoginItem.swift b/Passepartout/Mac/Menu/LaunchOnLoginItem.swift index a9ca248b..42e4048f 100644 --- a/Passepartout/Mac/Menu/LaunchOnLoginItem.swift +++ b/Passepartout/Mac/Menu/LaunchOnLoginItem.swift @@ -28,7 +28,7 @@ import AppKit struct LaunchOnLoginItem: Item { private let viewModel: ViewModel - + init(_ title: String, utils: LightUtils) { viewModel = ViewModel(title, utils: utils) } @@ -48,7 +48,7 @@ struct LaunchOnLoginItem: Item { } return item } - + private var state: NSControl.StateValue { viewModel.persistentlyLaunchesOnLogin ? .on : .off } diff --git a/Passepartout/Mac/Menu/PassepartoutMenu+StatusButton.swift b/Passepartout/Mac/Menu/PassepartoutMenu+StatusButton.swift index e440e328..f2b87e58 100644 --- a/Passepartout/Mac/Menu/PassepartoutMenu+StatusButton.swift +++ b/Passepartout/Mac/Menu/PassepartoutMenu+StatusButton.swift @@ -31,7 +31,7 @@ extension PassepartoutMenu { @MainActor class StatusButton { private lazy var statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) - + private lazy var statusButton: NSStatusBarButton = { guard let statusButton = statusItem.button else { fatalError("Missing status item button?") @@ -46,17 +46,17 @@ extension PassepartoutMenu { init(profileManager: LightProfileManager, vpnManager: LightVPNManager) { self.profileManager = profileManager self.vpnManager = vpnManager - + vpnManager.addDelegate(self, withIdentifier: "PassepartoutMenu") setStatus(vpnManager.vpnStatus) } - + deinit { Task { @MainActor in vpnManager.removeDelegate(withIdentifier: "PassepartoutMenu") } } - + func install(systemMenu: SystemMenu) { statusItem.menu = systemMenu.asMenu } diff --git a/Passepartout/Mac/Menu/PassepartoutMenu.swift b/Passepartout/Mac/Menu/PassepartoutMenu.swift index 34aade78..48bdde59 100644 --- a/Passepartout/Mac/Menu/PassepartoutMenu.swift +++ b/Passepartout/Mac/Menu/PassepartoutMenu.swift @@ -29,13 +29,13 @@ import AppKit @MainActor class PassepartoutMenu { private let macMenuDelegate: MacMenuDelegate - + private let profileManager: LightProfileManager - + private let providerManager: LightProviderManager - + private let statusButton: StatusButton - + init(macMenuDelegate: MacMenuDelegate) { self.macMenuDelegate = macMenuDelegate profileManager = macMenuDelegate.profileManager @@ -47,16 +47,16 @@ class PassepartoutMenu { profileManager.delegate = self providerManager.delegate = self - + } - + func install() { statusButton.install(systemMenu: StaticSystemMenu(body)) } - + private var body: [ItemGroup] { var children: [ItemGroup] = [] - + children.append(contentsOf: [ VisibilityItem( L10n.Global.Strings.show, @@ -65,7 +65,7 @@ class PassepartoutMenu { LaunchOnLoginItem( L10n.Preferences.Items.LaunchesOnLogin.caption, utils: macMenuDelegate.utils - ), + ) ] as [ItemGroup]) if profileManager.hasProfiles { @@ -88,10 +88,10 @@ class PassepartoutMenu { $0 ? L10n.Profile.Items.Vpn.TurnOff.caption : L10n.Profile.Items.Vpn.TurnOn.caption } reconnectTitleBlock: { L10n.Global.Strings.reconnect - }, + } ] as [ItemGroup]) } - + children.append(contentsOf: [ SeparatorItem(), // TextItem(L10n.Menu.All.About.title(Constants.Global.appName)) { @@ -104,7 +104,7 @@ class PassepartoutMenu { NSApp.terminate(nil) } ] as [ItemGroup]) - + return children } } diff --git a/Passepartout/Mac/Menu/ProfileItemGroup.swift b/Passepartout/Mac/Menu/ProfileItemGroup.swift index 6754a67a..87a749c1 100644 --- a/Passepartout/Mac/Menu/ProfileItemGroup.swift +++ b/Passepartout/Mac/Menu/ProfileItemGroup.swift @@ -28,17 +28,17 @@ import AppKit struct ProfileItemGroup: ItemGroup { private let profileManager: LightProfileManager - + private let providerManager: LightProviderManager - + private let vpnManager: LightVPNManager - + init(profileManager: LightProfileManager, providerManager: LightProviderManager, vpnManager: LightVPNManager) { self.profileManager = profileManager self.providerManager = providerManager self.vpnManager = vpnManager } - + func asMenuItems(withParent parent: NSMenu) -> [NSMenuItem] { profileManager.profiles.map { $0.isProvider ? providerItem(withProfile: $0, parent: parent) : hostItem(withProfile: $0, parent: parent) diff --git a/Passepartout/Mac/Menu/ProviderLocationItem+ViewModel.swift b/Passepartout/Mac/Menu/ProviderLocationItem+ViewModel.swift index 592a7083..a91227f0 100644 --- a/Passepartout/Mac/Menu/ProviderLocationItem+ViewModel.swift +++ b/Passepartout/Mac/Menu/ProviderLocationItem+ViewModel.swift @@ -32,23 +32,23 @@ extension ProviderLocationItem { private let profile: LightProfile let location: LightProviderLocation - + private let vpnManager: LightVPNManager - + init(_ profile: LightProfile, _ location: LightProviderLocation, vpnManager: LightVPNManager) { self.profile = profile self.location = location self.vpnManager = vpnManager } - + var isActiveLocation: Bool { location.id == profile.providerServer?.locationId } - + var isOnlyServer: Bool { location.servers.count == 1 } - + @objc func connectTo() { guard isOnlyServer else { fatalError("Connecting to a location with multiple servers?") diff --git a/Passepartout/Mac/Menu/ProviderLocationItem.swift b/Passepartout/Mac/Menu/ProviderLocationItem.swift index 3adfc061..51a086d2 100644 --- a/Passepartout/Mac/Menu/ProviderLocationItem.swift +++ b/Passepartout/Mac/Menu/ProviderLocationItem.swift @@ -28,17 +28,17 @@ import AppKit struct ProviderLocationItem: Item { private let profile: LightProfile - + private let location: LightProviderLocation - + private let vpnManager: LightVPNManager - + init(_ profile: LightProfile, _ location: LightProviderLocation, vpnManager: LightVPNManager) { self.profile = profile self.location = location self.vpnManager = vpnManager } - + func asMenuItem(withParent parent: NSMenu) -> NSMenuItem { let viewModel = ViewModel(profile, location, vpnManager: vpnManager) let item = NSMenuItem( diff --git a/Passepartout/Mac/Menu/ProviderProfileItem+ViewModel.swift b/Passepartout/Mac/Menu/ProviderProfileItem+ViewModel.swift index 0a67a564..a4be6719 100644 --- a/Passepartout/Mac/Menu/ProviderProfileItem+ViewModel.swift +++ b/Passepartout/Mac/Menu/ProviderProfileItem+ViewModel.swift @@ -30,7 +30,7 @@ extension ProviderProfileItem { @MainActor class ViewModel { let profile: LightProfile - + private let providerManager: LightProviderManager private let vpnManager: LightVPNManager @@ -41,10 +41,10 @@ extension ProviderProfileItem { self.profile = profile self.providerManager = providerManager self.vpnManager = vpnManager - + vpnManager.addDelegate(self, withIdentifier: profile.id.uuidString) } - + deinit { Task { @MainActor in vpnManager.removeDelegate(withIdentifier: profile.id.uuidString) @@ -65,15 +65,15 @@ extension ProviderProfileItem { var categories: [LightProviderCategory] { providerManager.categories(providerName, vpnProtocol: vpnProtocol) } - + func isActiveCategory(_ category: LightProviderCategory) -> Bool { category.name == profile.providerServer?.categoryName } - + @objc func connectTo() { vpnManager.connect(with: profile.id) } - + @objc func disconnect() { vpnManager.disconnect() } @@ -81,7 +81,7 @@ extension ProviderProfileItem { func downloadIfNeeded() { providerManager.downloadIfNeeded(providerName, vpnProtocol: vpnProtocol) } - + func subscribe(_ block: @escaping (LightVPNStatus) -> Void) { didUpdate = block } diff --git a/Passepartout/Mac/Menu/ProviderProfileItem.swift b/Passepartout/Mac/Menu/ProviderProfileItem.swift index 8e298c81..3a6b9f6d 100644 --- a/Passepartout/Mac/Menu/ProviderProfileItem.swift +++ b/Passepartout/Mac/Menu/ProviderProfileItem.swift @@ -28,14 +28,14 @@ import AppKit struct ProviderProfileItem: Item { private let viewModel: ViewModel - + private let vpnManager: LightVPNManager - + init(_ profile: LightProfile, providerManager: LightProviderManager, vpnManager: LightVPNManager) { viewModel = ViewModel(profile, providerManager: providerManager, vpnManager: vpnManager) self.vpnManager = vpnManager } - + func asMenuItem(withParent parent: NSMenu) -> NSMenuItem { let item = NSMenuItem( title: viewModel.profile.name, @@ -47,7 +47,7 @@ struct ProviderProfileItem: Item { item.submenu = submenu() return item } - + private func submenu() -> NSMenu { let menu = NSMenu() menu.autoenablesItems = false @@ -60,7 +60,7 @@ struct ProviderProfileItem: Item { menu.addItem(downloadItem.asMenuItem(withParent: menu)) return menu } - + let toggleItem = NSMenuItem() toggleItem.target = viewModel toggleItem.representedObject = viewModel @@ -101,7 +101,7 @@ struct ProviderProfileItem: Item { return menu } - + private func categoryItem(with category: LightProviderCategory, parent: NSMenu) -> NSMenuItem { let title = !category.name.isEmpty ? category.name.capitalized : L10n.Global.Strings.default let item = NSMenuItem( @@ -121,7 +121,7 @@ struct ProviderProfileItem: Item { return item } - + private func locationItem(with location: LightProviderLocation, parent: NSMenu) -> NSMenuItem { ProviderLocationItem(viewModel.profile, location, vpnManager: vpnManager) .asMenuItem(withParent: parent) diff --git a/Passepartout/Mac/Menu/ProviderServerItem+ViewModel.swift b/Passepartout/Mac/Menu/ProviderServerItem+ViewModel.swift index b4122c91..b3ab1c9d 100644 --- a/Passepartout/Mac/Menu/ProviderServerItem+ViewModel.swift +++ b/Passepartout/Mac/Menu/ProviderServerItem+ViewModel.swift @@ -30,21 +30,21 @@ extension ProviderServerItem { @MainActor class ViewModel { private let profile: LightProfile - + let server: LightProviderServer - + private let vpnManager: LightVPNManager - + init(_ profile: LightProfile, _ server: LightProviderServer, vpnManager: LightVPNManager) { self.profile = profile self.server = server self.vpnManager = vpnManager } - + var isActiveServer: Bool { server.serverId == profile.providerServer?.serverId } - + @objc func connectTo() { vpnManager.connect(with: profile.id, to: server.serverId) } diff --git a/Passepartout/Mac/Menu/ProviderServerItem.swift b/Passepartout/Mac/Menu/ProviderServerItem.swift index 1d718090..7ae84703 100644 --- a/Passepartout/Mac/Menu/ProviderServerItem.swift +++ b/Passepartout/Mac/Menu/ProviderServerItem.swift @@ -28,17 +28,17 @@ import AppKit struct ProviderServerItem: Item { private let profile: LightProfile - + private let server: LightProviderServer - + private let vpnManager: LightVPNManager - + init(_ profile: LightProfile, _ server: LightProviderServer, vpnManager: LightVPNManager) { self.profile = profile self.server = server self.vpnManager = vpnManager } - + func asMenuItem(withParent parent: NSMenu) -> NSMenuItem { let viewModel = ViewModel(profile, server, vpnManager: vpnManager) let item = NSMenuItem( diff --git a/Passepartout/Mac/Menu/VPNItemGroup+ViewModel.swift b/Passepartout/Mac/Menu/VPNItemGroup+ViewModel.swift index e5d8779d..ecd30c43 100644 --- a/Passepartout/Mac/Menu/VPNItemGroup+ViewModel.swift +++ b/Passepartout/Mac/Menu/VPNItemGroup+ViewModel.swift @@ -35,11 +35,11 @@ extension VPNItemGroup { private let toggleTitleBlock: (Bool) -> String private let reconnectTitleBlock: () -> String - + private var didUpdateState: [(Bool, LightVPNStatus) -> Void] = [] private var subscriptions: Set = [] - + init( vpnManager: LightVPNManager, toggleTitleBlock: @escaping (Bool) -> String, @@ -48,28 +48,28 @@ extension VPNItemGroup { self.vpnManager = vpnManager self.toggleTitleBlock = toggleTitleBlock self.reconnectTitleBlock = reconnectTitleBlock - + vpnManager.addDelegate(self, withIdentifier: "VPNItemGroup") } - + deinit { Task { @MainActor in vpnManager.removeDelegate(withIdentifier: "VPNItemGroup") } } - + var toggleTitle: String { toggleTitleBlock(vpnManager.isEnabled) } - + var reconnectTitle: String { reconnectTitleBlock() } - + @objc func toggleVPN() { vpnManager.toggle() } - + @objc func reconnectVPN() { vpnManager.reconnect() } diff --git a/Passepartout/Mac/Menu/VPNItemGroup.swift b/Passepartout/Mac/Menu/VPNItemGroup.swift index 61717472..e691d5dd 100644 --- a/Passepartout/Mac/Menu/VPNItemGroup.swift +++ b/Passepartout/Mac/Menu/VPNItemGroup.swift @@ -28,7 +28,7 @@ import AppKit struct VPNItemGroup: ItemGroup { private let viewModel: ViewModel - + init( vpnManager: LightVPNManager, toggleTitleBlock: @escaping (Bool) -> String, @@ -40,7 +40,7 @@ struct VPNItemGroup: ItemGroup { reconnectTitleBlock: reconnectTitleBlock ) } - + func asMenuItems(withParent parent: NSMenu) -> [NSMenuItem] { [ toggleItem(withParent: parent), diff --git a/Passepartout/Mac/Menu/VisibilityItem+ViewModel.swift b/Passepartout/Mac/Menu/VisibilityItem+ViewModel.swift index 6b6d1b94..5cf18c11 100644 --- a/Passepartout/Mac/Menu/VisibilityItem+ViewModel.swift +++ b/Passepartout/Mac/Menu/VisibilityItem+ViewModel.swift @@ -31,7 +31,7 @@ extension VisibilityItem { @MainActor class ViewModel { private let transformer: ObservableProcessTransformer - + private let utils: LightUtils init(utils: LightUtils) { diff --git a/Passepartout/Mac/Menu/VisibilityItem.swift b/Passepartout/Mac/Menu/VisibilityItem.swift index bd9f0045..8425caa0 100644 --- a/Passepartout/Mac/Menu/VisibilityItem.swift +++ b/Passepartout/Mac/Menu/VisibilityItem.swift @@ -28,14 +28,14 @@ import AppKit struct VisibilityItem: Item { private let title: String - + private let viewModel: ViewModel init(_ title: String, utils: LightUtils) { self.title = title viewModel = ViewModel(utils: utils) } - + func asMenuItem(withParent parent: NSMenu) -> NSMenuItem { let item = NSMenuItem( title: title, diff --git a/Passepartout/Mac/PassepartoutMac.swift b/Passepartout/Mac/PassepartoutMac.swift index 8f22b950..e9eea107 100644 --- a/Passepartout/Mac/PassepartoutMac.swift +++ b/Passepartout/Mac/PassepartoutMac.swift @@ -29,9 +29,9 @@ class PassepartoutMac: NSObject, MacBridge { required override init() { super.init() } - + let utils: MacUtils = DefaultMacUtils() - + @MainActor let menu: MacMenu = DefaultMacMenu() } diff --git a/Passepartout/Mac/Reusable/ObservableProcessTransformer.swift b/Passepartout/Mac/Reusable/ObservableProcessTransformer.swift index 379fa361..66a61ae3 100644 --- a/Passepartout/Mac/Reusable/ObservableProcessTransformer.swift +++ b/Passepartout/Mac/Reusable/ObservableProcessTransformer.swift @@ -30,23 +30,23 @@ class ObservableProcessTransformer: ObservableObject { static let shared = ObservableProcessTransformer() private let transformer = ProcessTransformer() - + private var subscriptions: Set = [] - + private init() { } var isForeground: Bool { transformer.isForeground } - + func toggleForeground() { guard transformer.toggleForeground() else { return } objectWillChange.send() } - + func bringToForeground() { guard transformer.bringToForeground() else { return diff --git a/Passepartout/Mac/Reusable/StaticSystemMenu.swift b/Passepartout/Mac/Reusable/StaticSystemMenu.swift index 6580d2f2..0baa636c 100644 --- a/Passepartout/Mac/Reusable/StaticSystemMenu.swift +++ b/Passepartout/Mac/Reusable/StaticSystemMenu.swift @@ -28,11 +28,11 @@ import AppKit struct StaticSystemMenu: SystemMenu { let children: [ItemGroup] - + init(_ children: [ItemGroup]) { self.children = children } - + var asMenu: NSMenu { let menu = NSMenu() if !children.isEmpty { diff --git a/Passepartout/Mac/Reusable/TextItem+ViewModel.swift b/Passepartout/Mac/Reusable/TextItem+ViewModel.swift index 824ff7af..e83d562a 100644 --- a/Passepartout/Mac/Reusable/TextItem+ViewModel.swift +++ b/Passepartout/Mac/Reusable/TextItem+ViewModel.swift @@ -31,25 +31,25 @@ extension TextItem { let title: CurrentValueSubject let state: CurrentValueSubject - + private let action: (() -> Void)? - + var hasAction: Bool { action != nil } - + private var subscriptions: Set = [] - + init(_ title: String, state: State = .none, action: (() -> Void)? = nil) { self.title = CurrentValueSubject(title) self.state = CurrentValueSubject(state) self.action = action } - + @objc func representedAction() { action?() } - + func subscribeTitle(_ block: @escaping (String) -> Void) { title .removeDuplicates() diff --git a/Passepartout/Mac/Reusable/TextItem.swift b/Passepartout/Mac/Reusable/TextItem.swift index 6c9fdd85..98488f28 100644 --- a/Passepartout/Mac/Reusable/TextItem.swift +++ b/Passepartout/Mac/Reusable/TextItem.swift @@ -29,18 +29,18 @@ import AppKit struct TextItem: Item { enum State { case none - + case checked - + case unchecked } - + private let viewModel: ViewModel - + private let key: String? - + let children: [Item] - + init(_ title: String, state: State = .none, key: String? = nil, _ children: [Item] = [], action: (() -> Void)? = nil) { self.init(ViewModel(title, state: state, action: action), key: key, children) } @@ -62,7 +62,7 @@ struct TextItem: Item { } item.state = state item.representedObject = viewModel - + if !children.isEmpty { let submenu = NSMenu() children.forEach { @@ -80,12 +80,12 @@ struct TextItem: Item { return item } - + private var state: NSControl.StateValue { switch viewModel.state.value { case .none, .unchecked: return .off - + case .checked: return .on } diff --git a/Passepartout/Tunnel/OpenVPN/PacketTunnelProvider.swift b/Passepartout/Tunnel/OpenVPN/PacketTunnelProvider.swift index c5373f28..769fac58 100644 --- a/Passepartout/Tunnel/OpenVPN/PacketTunnelProvider.swift +++ b/Passepartout/Tunnel/OpenVPN/PacketTunnelProvider.swift @@ -27,7 +27,7 @@ import Foundation import OpenVPNAppExtension class PacketTunnelProvider: OpenVPNTunnelProvider { - override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) { + override func startTunnel(options: [String: NSObject]?, completionHandler: @escaping (Error?) -> Void) { appVersion = "\(Constants.Global.appName) \(Constants.Global.appVersionString)" dnsTimeout = Constants.OpenVPNTunnel.dnsTimeout logSeparator = Constants.OpenVPNTunnel.sessionMarker diff --git a/PassepartoutLibrary/Package.swift b/PassepartoutLibrary/Package.swift index d0611676..da1227ae 100644 --- a/PassepartoutLibrary/Package.swift +++ b/PassepartoutLibrary/Package.swift @@ -66,7 +66,7 @@ let package = Package( .target( name: "PassepartoutServices", dependencies: [ - "PassepartoutUtils", + "PassepartoutUtils" ], resources: [ .copy("API") diff --git a/PassepartoutLibrary/Sources/PassepartoutCore/Extensions/Host+Extensions.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Extensions/Host+Extensions.swift index af99e7b1..1909a8eb 100644 --- a/PassepartoutLibrary/Sources/PassepartoutCore/Extensions/Host+Extensions.swift +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Extensions/Host+Extensions.swift @@ -31,7 +31,7 @@ extension Profile { switch currentVPNProtocol { case .openVPN: return host?.ovpnSettings?.account - + case .wireGuard: return nil } @@ -41,7 +41,7 @@ extension Profile { switch currentVPNProtocol { case .openVPN: host?.ovpnSettings?.account = account - + case .wireGuard: break } diff --git a/PassepartoutLibrary/Sources/PassepartoutCore/Extensions/Profile+Extensions.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Extensions/Profile+Extensions.swift index dbce5d53..bca32108 100644 --- a/PassepartoutLibrary/Sources/PassepartoutCore/Extensions/Profile+Extensions.swift +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Extensions/Profile+Extensions.swift @@ -37,7 +37,7 @@ extension Profile { return host?.vpnProtocols ?? [] } } - + public var account: Profile.Account { get { if isProvider { diff --git a/PassepartoutLibrary/Sources/PassepartoutCore/Extensions/Provider+Extensions.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Extensions/Provider+Extensions.swift index f4ec7323..a1ae74b1 100644 --- a/PassepartoutLibrary/Sources/PassepartoutCore/Extensions/Provider+Extensions.swift +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Extensions/Provider+Extensions.swift @@ -31,7 +31,7 @@ extension Profile { guard let vpnProtocol = server.presets?.first?.vpnProtocol else { fatalError("Server has no presets") } - + var provider = Provider(providerMetadata.name) var settings = Provider.Settings() settings.serverId = server.id @@ -40,7 +40,7 @@ extension Profile { self.init(name: providerMetadata.fullName, provider: provider) } - + public var providerName: String? { provider?.name } @@ -70,11 +70,11 @@ extension Profile { public mutating func setProviderPreset(_ preset: ProviderServer.Preset) { provider?.vpnSettings[currentVPNProtocol]?.presetId = preset.id } - + public func providerFavoriteLocationIds() -> Set? { provider?.vpnSettings[currentVPNProtocol]?.favoriteLocationIds } - + public mutating func setProviderFavoriteLocationIds(_ ids: Set?) { provider?.vpnSettings[currentVPNProtocol]?.favoriteLocationIds = ids } @@ -86,11 +86,11 @@ extension Profile { public mutating func setProviderCustomEndpoint(_ endpoint: Endpoint?) { provider?.vpnSettings[currentVPNProtocol]?.customEndpoint = endpoint } - + public func providerAccount() -> Profile.Account? { provider?.vpnSettings[currentVPNProtocol]?.account } - + public mutating func setProviderAccount(_ account: Profile.Account?) { provider?.vpnSettings[currentVPNProtocol]?.account = account } diff --git a/PassepartoutLibrary/Sources/PassepartoutCore/Models/CredentialsPurpose.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Models/CredentialsPurpose.swift index 5c232d22..03bc150d 100644 --- a/PassepartoutLibrary/Sources/PassepartoutCore/Models/CredentialsPurpose.swift +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Models/CredentialsPurpose.swift @@ -27,6 +27,6 @@ import Foundation public enum CredentialsPurpose { case web - + case specific } diff --git a/PassepartoutLibrary/Sources/PassepartoutCore/Models/Network.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Models/Network.swift index c6e55708..1dfb9e66 100644 --- a/PassepartoutLibrary/Sources/PassepartoutCore/Models/Network.swift +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Models/Network.swift @@ -32,9 +32,9 @@ public enum Network { extension Network { public enum Choice: String, Codable { case automatic // OpenVPN pulls from server - + case manual - + public static let defaultChoice: Choice = .automatic } } @@ -45,25 +45,25 @@ public protocol NetworkChoiceRepresentable { public protocol GatewaySettingsProviding { var isDefaultIPv4: Bool { get } - + var isDefaultIPv6: Bool { get } } public protocol DNSSettingsProviding { var dnsProtocol: DNSProtocol? { get } - + var dnsServers: [String]? { get } - + var dnsSearchDomains: [String]? { get } var dnsHTTPSURL: URL? { get } - + var dnsTLSServerName: String? { get } } public protocol ProxySettingsProviding { var proxyServer: Proxy? { get } - + var proxyBypassDomains: [String]? { get } var proxyAutoConfigurationURL: URL? { get } @@ -89,28 +89,28 @@ extension Network { public struct DNSSettings: Codable, Equatable, NetworkChoiceRepresentable, DNSSettingsProviding { public enum ConfigurationType: String, Codable { case plain - + case https - + case tls - + case disabled } public var choice: Network.Choice - + public var configurationType: ConfigurationType = .plain - + public var dnsProtocol: DNSProtocol? { DNSProtocol(rawValue: configurationType.rawValue) } - + public var dnsServers: [String]? - + public var dnsSearchDomains: [String]? public var dnsHTTPSURL: URL? - + public var dnsTLSServerName: String? } } @@ -119,24 +119,24 @@ extension Network { public struct ProxySettings: Codable, Equatable, NetworkChoiceRepresentable, ProxySettingsProviding { public enum ConfigurationType: String, Codable { case manual - + case pac - + case disabled } - + public var choice: Network.Choice - + public var configurationType: ConfigurationType = .manual public var proxyAddress: String? - + public var proxyPort: UInt16? - + public var proxyBypassDomains: [String]? public var proxyAutoConfigurationURL: URL? - + public var proxyServer: Proxy? { guard let address = proxyAddress, let port = proxyPort, !address.isEmpty, port > 0 else { return nil diff --git a/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+Account.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+Account.swift index b152a1ee..7b12839e 100644 --- a/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+Account.swift +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+Account.swift @@ -29,27 +29,27 @@ extension Profile { public struct Account: Codable, Equatable { public enum AuthenticationMethod: String, Codable { case persistent - + case interactive - + case totp } public var authenticationMethod: AuthenticationMethod? public var username: String - + public var password: String - + public var isEmpty: Bool { username.isEmpty && password.isEmpty } - + public init() { username = "" password = "" } - + public init(_ username: String, _ password: String) { self.username = username self.password = password diff --git a/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+Header.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+Header.swift index e1847163..d5ce91a2 100644 --- a/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+Header.swift +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+Header.swift @@ -28,11 +28,11 @@ import Foundation extension Profile { public struct Header: Codable, Identifiable, Hashable { public let uuid: UUID - + public var name: String - + public let providerName: ProviderName? - + public let lastUpdate: Date? public init( @@ -46,15 +46,15 @@ extension Profile { self.providerName = providerName self.lastUpdate = lastUpdate ?? Date() } - + // MARK: Hashable - + public static func ==(lhs: Self, rhs: Self) -> Bool { lhs.uuid == rhs.uuid && lhs.name == rhs.name && lhs.providerName == rhs.providerName } - + public func hash(into hasher: inout Hasher) { hasher.combine(uuid) hasher.combine(name) @@ -62,7 +62,7 @@ extension Profile { } // MARK: Identifiable - + public var id: UUID { uuid } diff --git a/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+NetworkSettings.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+NetworkSettings.swift index ccf4b127..a64d0cab 100644 --- a/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+NetworkSettings.swift +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+NetworkSettings.swift @@ -29,15 +29,15 @@ import TunnelKit extension Profile { public struct NetworkSettings: Codable, Equatable { public var gateway: Network.GatewaySettings - + public var dns: Network.DNSSettings - + public var proxy: Network.ProxySettings - + public var mtu: Network.MTUSettings - + public var resolvesHostname = true - + public var keepsAliveOnSleep = true public init(choice: Network.Choice) { @@ -46,7 +46,7 @@ extension Profile { proxy = Network.ProxySettings(choice: choice) mtu = Network.MTUSettings(choice: choice) } - + public init() { self.init(choice: .defaultChoice) } diff --git a/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+OnDemand.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+OnDemand.swift index 18655e4d..b2d1d02a 100644 --- a/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+OnDemand.swift +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+OnDemand.swift @@ -29,28 +29,28 @@ extension Profile { public struct OnDemand: Codable, Equatable { public enum Policy: String, Codable { case any - + case including - + case excluding // "trusted networks" } - + public enum OtherNetwork: String, Codable { case mobile case ethernet } - + // hardcode this to keep "Trusted networks" semantics public var isEnabled = true // hardcode this to keep "Trusted networks" semantics public var policy: Policy = .excluding - + public var withSSIDs: [String: Bool] = [:] public var withOtherNetworks: Set = [] - + public var disconnectsIfNotMatching = true public init() { diff --git a/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+OpenVPNSettings.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+OpenVPNSettings.swift index d6e9b613..e2619109 100644 --- a/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+OpenVPNSettings.swift +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+OpenVPNSettings.swift @@ -31,9 +31,9 @@ extension Profile { public var vpnProtocol: VPNProtocolType { .openVPN } - + public var configuration: OpenVPN.Configuration - + public var account: Profile.Account? public var customEndpoint: Endpoint? diff --git a/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+Provider.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+Provider.swift index 8f49601a..b7877ccc 100644 --- a/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+Provider.swift +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+Provider.swift @@ -30,23 +30,23 @@ extension Profile { public struct Provider: Codable, Equatable { public struct Settings: Codable, Equatable { public var account: Profile.Account? - + public var serverId: String? public var presetId: String? public var favoriteLocationIds: Set? - + public var customEndpoint: Endpoint? - + public init() { } } - + public let name: ProviderName - + public var vpnSettings: [VPNProtocolType: Settings] = [:] - + public init(_ name: ProviderName) { self.name = name } diff --git a/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+WireGuardSettings.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+WireGuardSettings.swift index 030816d1..5731b001 100644 --- a/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+WireGuardSettings.swift +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+WireGuardSettings.swift @@ -31,7 +31,7 @@ extension Profile { public var vpnProtocol: VPNProtocolType { .wireGuard } - + public var configuration: WireGuard.Configuration public init(configuration: WireGuard.Configuration) { diff --git a/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile.swift index b5eb78fc..3b3cd389 100644 --- a/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile.swift +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile.swift @@ -33,11 +33,11 @@ public protocol ProfileSubtype { public struct Profile: Identifiable, Codable, Equatable { public var header: Header - + public var currentVPNProtocol: VPNProtocolType public var networkSettings = Profile.NetworkSettings() - + public var onDemand = Profile.OnDemand() var host: Host? @@ -57,7 +57,7 @@ public struct Profile: Identifiable, Codable, Equatable { ) currentVPNProtocol = .openVPN } - + init(_ id: UUID = UUID(), name: String, configuration: OpenVPN.Configuration) { let header = Header( uuid: id, @@ -109,7 +109,7 @@ public struct Profile: Identifiable, Codable, Equatable { } // MARK: Identifiable - + public var id: UUID { header.id } @@ -120,11 +120,11 @@ extension Profile { UUID(uuidString: "00000000-0000-0000-0000-000000000000")!, name: "" ) - + public static func isPlaceholder(_ id: UUID) -> Bool { id == placeholder.id } - + public var isPlaceholder: Bool { header.id == Self.placeholder.id } diff --git a/PassepartoutLibrary/Sources/PassepartoutCore/Models/ProviderCategory.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Models/ProviderCategory.swift index 41af7296..f24d9189 100644 --- a/PassepartoutLibrary/Sources/PassepartoutCore/Models/ProviderCategory.swift +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Models/ProviderCategory.swift @@ -27,11 +27,11 @@ import Foundation public struct ProviderCategory { public let providerMetadata: ProviderMetadata - + public let vpnProtocol: VPNProtocolType - + public let name: String - + public let locations: [ProviderLocation] public init( diff --git a/PassepartoutLibrary/Sources/PassepartoutCore/Models/ProviderLocation.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Models/ProviderLocation.swift index 7db1339d..6f45a5d9 100644 --- a/PassepartoutLibrary/Sources/PassepartoutCore/Models/ProviderLocation.swift +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Models/ProviderLocation.swift @@ -27,13 +27,13 @@ import Foundation public struct ProviderLocation { public let providerMetadata: ProviderMetadata - + public let vpnProtocol: VPNProtocolType - + public let categoryName: String - + public let countryCode: String - + public var onlyServer: ProviderServer? { guard servers?.count == 1 else { return nil diff --git a/PassepartoutLibrary/Sources/PassepartoutCore/Models/ProviderServer.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Models/ProviderServer.swift index 0a2d3cc8..dddff794 100644 --- a/PassepartoutLibrary/Sources/PassepartoutCore/Models/ProviderServer.swift +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Models/ProviderServer.swift @@ -35,7 +35,7 @@ public struct ProviderServer: Identifiable { public let comment: String public let vpnProtocol: VPNProtocolType - + public let vpnConfiguration: JSON public init(id: String, name: String, comment: String, vpnProtocol: VPNProtocolType, vpnConfiguration: JSON) { @@ -50,29 +50,29 @@ public struct ProviderServer: Identifiable { public let providerMetadata: ProviderMetadata public let id: String - + public let apiId: String - + public let categoryName: String - + public let countryCode: String - + public let extraCountryCodes: [String]? - + public let localizedName: String? - + public let serverIndex: Int? - + public let tags: [String]? - + public let hostname: String? - + public let ipAddresses: [String] public let presetIds: [String] public private(set) var presets: [Preset]? - + public init(providerMetadata: ProviderMetadata, id: String, apiId: String, categoryName: String, countryCode: String, extraCountryCodes: [String]?, localizedName: String?, serverIndex: Int?, tags: [String]?, hostname: String?, ipAddresses: [String], presetIds: [String]) { self.providerMetadata = providerMetadata self.id = id @@ -93,7 +93,7 @@ public struct ProviderServer: Identifiable { $0.id == presetId } } - + public func withPresets(_ presets: [Preset]?) -> Self { var copy = self copy.presets = presets diff --git a/PassepartoutLibrary/Sources/PassepartoutCore/Models/VPNProtocolType.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Models/VPNProtocolType.swift index 97a0605e..d9fb7e4a 100644 --- a/PassepartoutLibrary/Sources/PassepartoutCore/Models/VPNProtocolType.swift +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Models/VPNProtocolType.swift @@ -27,7 +27,7 @@ import Foundation public enum VPNProtocolType: String, Codable { case openVPN = "ovpn" - + case wireGuard = "wg" } @@ -40,7 +40,7 @@ extension VPNProtocolType: CustomStringConvertible { switch self { case .openVPN: return "OpenVPN" - + case .wireGuard: return "WireGuard" } diff --git a/PassepartoutLibrary/Sources/PassepartoutCore/PassepartoutError.swift b/PassepartoutLibrary/Sources/PassepartoutCore/PassepartoutError.swift index 5f43e243..9e37f661 100644 --- a/PassepartoutLibrary/Sources/PassepartoutCore/PassepartoutError.swift +++ b/PassepartoutLibrary/Sources/PassepartoutCore/PassepartoutError.swift @@ -27,11 +27,11 @@ import Foundation public struct PassepartoutError: Error, Equatable { private let string: String - + public init(_ string: String) { self.string = string } - + public static func ==(lhs: Self, rhs: Self) -> Bool { lhs.string == rhs.string } diff --git a/PassepartoutLibrary/Sources/PassepartoutLibrary/Extensions/DebugLog+Extensions.swift b/PassepartoutLibrary/Sources/PassepartoutLibrary/Extensions/DebugLog+Extensions.swift index e67f31e2..a3673c72 100644 --- a/PassepartoutLibrary/Sources/PassepartoutLibrary/Extensions/DebugLog+Extensions.swift +++ b/PassepartoutLibrary/Sources/PassepartoutLibrary/Extensions/DebugLog+Extensions.swift @@ -58,7 +58,7 @@ extension DebugLog { fullText += content return fullText } - + public func decoratedData(_ appName: String, _ appVersion: String) -> Data { guard let data = decoratedString(appName, appVersion).data(using: .utf8) else { assertionFailure("Could not encode log metadata to UTF8?") @@ -74,13 +74,13 @@ private extension UIUserInterfaceIdiom { switch self { case .phone: return "Phone" - + case .pad: return "Pad" - + case .mac: return "Mac" - + default: return "Other" } diff --git a/PassepartoutLibrary/Sources/PassepartoutLibrary/Managers/UpgradeManager+Migrations.swift b/PassepartoutLibrary/Sources/PassepartoutLibrary/Managers/UpgradeManager+Migrations.swift index 19b6fbc0..eb3ece6c 100644 --- a/PassepartoutLibrary/Sources/PassepartoutLibrary/Managers/UpgradeManager+Migrations.swift +++ b/PassepartoutLibrary/Sources/PassepartoutLibrary/Managers/UpgradeManager+Migrations.swift @@ -38,40 +38,40 @@ private typealias Map = [String: Any] extension UpgradeManager { fileprivate enum LegacyStoreKey: String, KeyStoreLocation, CaseIterable { case activeProfileId - + case launchesOnLogin - + case isStatusMenuEnabled - + case isShowingFavorites case confirmsQuit - + case logFormat - + case tunnelLogFormat - + case masksPrivateData - + case didHandleSubreddit - + case persistenceAuthor case didMigrateToV2 - + case other1 = "MasksPrivateData" - + case other2 = "DidHandleSubreddit" - + case other3 = "Convenience.Reviewer.LastVersion" - + case other4 = "didMigrateKeychainContext" - + var key: String { rawValue } } - + func doMigrateStore(_ store: KeyValueStore) { if !didMigrateToV2 { guard let legacyDidMigrateToV2: Bool = store.value(forLocation: LegacyStoreKey.didMigrateToV2) else { @@ -79,7 +79,7 @@ extension UpgradeManager { } didMigrateToV2 = legacyDidMigrateToV2 } - + LegacyStoreKey.allCases.forEach { store.removeValue(forLocation: $0) } @@ -91,15 +91,15 @@ extension UpgradeManager { extension UpgradeManager { fileprivate enum MigrationError: Error { case json - + case missingId case missingOpenVPNConfiguration - + case missingHostname - + case missingEndpointProtocols - + case missingProviderName } @@ -110,9 +110,9 @@ extension UpgradeManager { func doMigrateToV2() -> [Profile] { var migrated: [Profile] = [] pp_log.info("Migrating data to v2") - + let fm = FileManager.default - + guard let documents = fm.containerURL(forSecurityApplicationGroupIdentifier: appGroup)? .appendingPathComponent("Documents") else { @@ -127,7 +127,7 @@ extension UpgradeManager { do { let csJSON = try cs.asJSON() // pp_log.error(csJSON) - + do { var authUserPassUUIDs: Set = [] @@ -147,7 +147,7 @@ extension UpgradeManager { pp_log.warning("Unable to read host profile .ovpn: \(host)") } } - + // print(">>> authUserPassUUIDs: \(authUserPassUUIDs)") for host in try fm.contentsOfDirectory(at: hostsFolder, includingPropertiesForKeys: nil) { @@ -157,11 +157,11 @@ extension UpgradeManager { do { let json = try host.asJSON() // pp_log.error(json) - + let result = try migratedV1Profile(csJSON, hostMap: json, authUserPass: authUserPassUUIDs) // pp_log.info(result.profile) // print(">>> Account: \(result.profile.username) -> \(result.password)") - + migrated.append(result) } catch { pp_log.warning("Unable to migrate host profile: \(host)") @@ -184,7 +184,7 @@ extension UpgradeManager { let result = try migratedV1Profile(csJSON, providerMap: json) // pp_log.info(result.profile) // print(">>> Account: \(result.profile.username) -> \(result.password)") - + migrated.append(result) } catch { pp_log.warning("Unable to migrate provider profile: \(provider)") @@ -243,7 +243,7 @@ extension UpgradeManager { ovpn["remotes"] = remotes ovpn["authUserPass"] = authUserPass.contains(oldUUIDString) let cfg = try JSON(ovpn).decode(OpenVPN.Configuration.self) - + // keychain let username = hostMap["username"] as? String ?? "" let password = migratedV1Password(forProfileId: oldUUIDString, profileType: "host", username: username) @@ -310,7 +310,7 @@ extension UpgradeManager { return "" } } - + private func migratedV1TrustedNetworks(_ map: Map) -> Profile.OnDemand { var onDemand = Profile.OnDemand() onDemand.isEnabled = true @@ -324,17 +324,17 @@ extension UpgradeManager { } return onDemand } - + private func migratedV1NetworkSettings(_ map: Map) -> Profile.NetworkSettings { var settings = Profile.NetworkSettings() - + if let choices = map["networkChoices"] as? Map { settings.gateway.choice = migratedV1Choice(choices, key: "gateway") settings.dns.choice = migratedV1Choice(choices, key: "dns") settings.proxy.choice = migratedV1Choice(choices, key: "proxy") settings.mtu.choice = migratedV1Choice(choices, key: "mtu") } - + if let manual = map["manualNetworkSettings"] as? Map { // gateway @@ -366,7 +366,7 @@ extension UpgradeManager { return settings } - + private func migratedV1Choice(_ map: Map, key: String) -> Network.Choice { (map[key] as? String) == "manual" ? .manual : .automatic } diff --git a/PassepartoutLibrary/Sources/PassepartoutLibrary/Managers/UpgradeManager.swift b/PassepartoutLibrary/Sources/PassepartoutLibrary/Managers/UpgradeManager.swift index ca76f1a6..8288cc72 100644 --- a/PassepartoutLibrary/Sources/PassepartoutLibrary/Managers/UpgradeManager.swift +++ b/PassepartoutLibrary/Sources/PassepartoutLibrary/Managers/UpgradeManager.swift @@ -31,22 +31,22 @@ import PassepartoutUtils @MainActor public final class UpgradeManager: ObservableObject { - + // MARK: Initialization - + private let store: KeyValueStore - + // MARK: State - + @Published public private(set) var isDoingMigrations = true public init(store: KeyValueStore) { self.store = store } - + public func doMigrations(_ profileManager: ProfileManager) { doMigrateStore(store) - + // profileManager.removeAllProfiles() guard didMigrateToV2 else { isDoingMigrations = true diff --git a/PassepartoutLibrary/Sources/PassepartoutProfiles/DataModels/CDProfile+CoreDataProperties.swift b/PassepartoutLibrary/Sources/PassepartoutProfiles/DataModels/CDProfile+CoreDataProperties.swift index 1350470c..a1ac80cd 100644 --- a/PassepartoutLibrary/Sources/PassepartoutProfiles/DataModels/CDProfile+CoreDataProperties.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProfiles/DataModels/CDProfile+CoreDataProperties.swift @@ -10,7 +10,6 @@ import Foundation import CoreData - extension CDProfile { @nonobjc public class func fetchRequest() -> NSFetchRequest { @@ -25,6 +24,6 @@ extension CDProfile { } -extension CDProfile : Identifiable { +extension CDProfile: Identifiable { } diff --git a/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/OpenVPNSettings+Network.swift b/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/OpenVPNSettings+Network.swift index 63bc88b6..97b01658 100644 --- a/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/OpenVPNSettings+Network.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/OpenVPNSettings+Network.swift @@ -47,22 +47,22 @@ extension Profile.OpenVPNSettings: DNSSettingsProviding { public var dnsProtocol: DNSProtocol? { (configuration.isDNSEnabled ?? true) ? .plain : nil } - + // dhcp-option DNS public var dnsServers: [String]? { configuration.dnsServers } - + // dhcp-option DOMAIN/DOMAIN-SEARCH public var dnsSearchDomains: [String]? { configuration.searchDomains } - + // not a dhcp-option public var dnsHTTPSURL: URL? { nil } - + // not a dhcp-option public var dnsTLSServerName: String? { nil @@ -75,7 +75,7 @@ extension Profile.OpenVPNSettings: ProxySettingsProviding { public var proxyServer: Proxy? { configuration.httpsProxy ?? configuration.httpProxy } - + // dhcp-option PROXY_BYPASS public var proxyBypassDomains: [String]? { configuration.proxyBypassDomains diff --git a/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/PassepartoutProfiles+Subtype.swift b/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/PassepartoutProfiles+Subtype.swift index 8dad3290..ee124291 100644 --- a/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/PassepartoutProfiles+Subtype.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/PassepartoutProfiles+Subtype.swift @@ -26,7 +26,6 @@ import Foundation import PassepartoutCore import PassepartoutProviders -import PassepartoutCore extension Profile { public var requiresCredentials: Bool { diff --git a/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/PassepartoutProviders+TunnelKit.swift b/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/PassepartoutProviders+TunnelKit.swift index d13ef84c..0d2eeec6 100644 --- a/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/PassepartoutProviders+TunnelKit.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/PassepartoutProviders+TunnelKit.swift @@ -46,7 +46,7 @@ extension ProviderServer.Preset { return nil } } - + public var openVPNEndpoints: [EndpointProtocol] { guard vpnProtocol == .openVPN else { return [] @@ -65,7 +65,7 @@ extension ProviderServer.Preset { } return endpoints } - + public var wireGuardConfiguration: WireGuard.Configuration? { guard vpnProtocol == .wireGuard else { return nil diff --git a/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/Profile+Extensions.swift b/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/Profile+Extensions.swift index 36200ad6..8822216d 100644 --- a/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/Profile+Extensions.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/Profile+Extensions.swift @@ -36,13 +36,13 @@ extension Profile.Header { lastUpdate: lastUpdate ) } - + public func renamed(to newName: String) -> Self { var header = self header.name = newName return header } - + public func renamedUniquely(withLastUpdate: Bool) -> Self { let suffix: String if withLastUpdate, let lastUpdate = lastUpdate { @@ -71,7 +71,7 @@ extension Profile { profile.header = profile.header.renamed(to: newName) return profile } - + public func renamedUniquely(withLastUpdate: Bool) -> Self { var profile = self profile.header = profile.header.renamedUniquely(withLastUpdate: withLastUpdate) diff --git a/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/ProfileManager+Extensions.swift b/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/ProfileManager+Extensions.swift index 7cf7a14c..d0c9076c 100644 --- a/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/ProfileManager+Extensions.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/ProfileManager+Extensions.swift @@ -64,7 +64,7 @@ extension ProfileManager { public func isCurrentProfileActive() -> Bool { currentProfile.value.id == activeProfileId } - + public func isCurrentProfile(_ id: UUID) -> Bool { id == currentProfile.value.id } diff --git a/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/WireGuardSettings+Network.swift b/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/WireGuardSettings+Network.swift index 2cebc6b7..9025584d 100644 --- a/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/WireGuardSettings+Network.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/WireGuardSettings+Network.swift @@ -32,19 +32,19 @@ extension Profile.WireGuardSettings: DNSSettingsProviding { public var dnsProtocol: DNSProtocol? { .plain } - + public var dnsServers: [String]? { configuration.dnsServers } - + public var dnsSearchDomains: [String]? { configuration.dnsSearchDomains } - + public var dnsHTTPSURL: URL? { nil } - + public var dnsTLSServerName: String? { nil } diff --git a/PassepartoutLibrary/Sources/PassepartoutProfiles/Managers/CoreDataProfileManagerStrategy.swift b/PassepartoutLibrary/Sources/PassepartoutProfiles/Managers/CoreDataProfileManagerStrategy.swift index 299ce3a6..07ec7a06 100644 --- a/PassepartoutLibrary/Sources/PassepartoutProfiles/Managers/CoreDataProfileManagerStrategy.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProfiles/Managers/CoreDataProfileManagerStrategy.swift @@ -37,15 +37,15 @@ public class CoreDataProfileManagerStrategy: ProfileManagerStrategy { profileRepository = ProfileRepository(persistence.context) fetchedProfiles = profileRepository.fetchedProfiles() } - + public var allProfiles: [UUID: Profile] { fetchedProfiles.value } - + public func profiles() -> [Profile] { profileRepository.profiles() } - + public func profile(withId id: UUID) -> Profile? { profileRepository.profile(withId: id) } @@ -57,12 +57,12 @@ public class CoreDataProfileManagerStrategy: ProfileManagerStrategy { pp_log.error("Unable to save profile: \(error)") } } - + public func removeProfiles(withIds ids: [UUID]) { profileRepository.removeProfiles(withIds: ids) } - public func willUpdateProfiles() -> AnyPublisher<[UUID : Profile], Never> { + public func willUpdateProfiles() -> AnyPublisher<[UUID: Profile], Never> { fetchedProfiles.$value .eraseToAnyPublisher() } diff --git a/PassepartoutLibrary/Sources/PassepartoutProfiles/Managers/PersistenceManager.swift b/PassepartoutLibrary/Sources/PassepartoutProfiles/Managers/PersistenceManager.swift index 06be3a47..3a491d02 100644 --- a/PassepartoutLibrary/Sources/PassepartoutProfiles/Managers/PersistenceManager.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProfiles/Managers/PersistenceManager.swift @@ -30,10 +30,10 @@ import PassepartoutUtils public final class PersistenceManager { private let store: KeyValueStore - + public init(store: KeyValueStore) { self.store = store - + // set once if persistenceAuthor == nil { persistenceAuthor = UUID().uuidString @@ -44,7 +44,7 @@ public final class PersistenceManager { let model = PassepartoutDataModels.profiles return Persistence(withCloudKitName: containerName, model: model, author: persistenceAuthor) } - + public func providersPersistence(withName containerName: String) -> Persistence { let model = PassepartoutDataModels.providers return Persistence(withLocalName: containerName, model: model, author: persistenceAuthor) diff --git a/PassepartoutLibrary/Sources/PassepartoutProfiles/Managers/ProfileManager+Keychain.swift b/PassepartoutLibrary/Sources/PassepartoutProfiles/Managers/ProfileManager+Keychain.swift index 2128b1df..610aa46d 100644 --- a/PassepartoutLibrary/Sources/PassepartoutProfiles/Managers/ProfileManager+Keychain.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProfiles/Managers/ProfileManager+Keychain.swift @@ -95,7 +95,7 @@ extension Keychain { switch SecItemCopyMatching(query as CFDictionary, &list) { case errSecSuccess: break - + default: return } @@ -105,7 +105,7 @@ extension Keychain { } pp_log.debug("Keychain items: \(list)") } - + func removeAllPasswords(matching id: UUID, context: String) { _ = SecItemDelete(allPasswordsQuery(id, context) as CFDictionary) } diff --git a/PassepartoutLibrary/Sources/PassepartoutProfiles/Managers/ProfileManager.swift b/PassepartoutLibrary/Sources/PassepartoutProfiles/Managers/ProfileManager.swift index 0341ea34..25cf1961 100644 --- a/PassepartoutLibrary/Sources/PassepartoutProfiles/Managers/ProfileManager.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProfiles/Managers/ProfileManager.swift @@ -35,19 +35,19 @@ public final class ProfileManager: ObservableObject { public typealias ProfileEx = (profile: Profile, isReady: Bool) // MARK: Initialization - + private let store: KeyValueStore - + private let providerManager: ProviderManager - + let appGroup: String - + let keychainLabel: (String, VPNProtocolType) -> String - + let keychain: Keychain - + private let strategy: ProfileManagerStrategy - + // MARK: State @Published private var internalActiveProfileId: UUID? { @@ -80,13 +80,13 @@ public final class ProfileManager: ObservableObject { } public let currentProfile: ObservableProfile - + public let didUpdateProfiles = PassthroughSubject() public let didUpdateActiveProfile = PassthroughSubject() public let didCreateProfile = PassthroughSubject() - + private var cancellables: Set = [] public init( @@ -116,7 +116,7 @@ extension ProfileManager { private var allProfiles: [UUID: Profile] { strategy.allProfiles } - + public var profiles: [Profile] { strategy.profiles() } @@ -124,11 +124,11 @@ extension ProfileManager { public var headers: [Profile.Header] { Array(allProfiles.values.map(\.header)) } - + public func isExistingProfile(withId id: UUID) -> Bool { allProfiles[id] != nil } - + public func isExistingProfile(withName name: String) -> Bool { allProfiles.contains { $0.value.header.name == name @@ -200,7 +200,7 @@ extension ProfileManager { currentProfile.value = profile } } - + public func removeProfiles(withIds ids: [UUID]) { pp_log.info("Deleting profiles with ids \(ids)") @@ -212,13 +212,13 @@ extension ProfileManager { pp_log.info("\tDeleting from persistent store...") strategy.removeProfiles(withIds: ids) } - + @available(*, deprecated, message: "only use for testing") public func removeAllProfiles() { let ids = Array(allProfiles.keys) removeProfiles(withIds: ids) } - + public func duplicateProfile(withId id: UUID, setAsCurrent: Bool) { guard let source = liveProfile(withId: id) else { return @@ -233,7 +233,7 @@ extension ProfileManager { if #available(iOS 15, *) { internalCurrentProfileId = copy.id } - + // autosaves copy if non-existing in persistent store setCurrentProfile(copy) } else { @@ -313,13 +313,13 @@ extension ProfileManager { self.willUpdateProfiles($0) }.store(in: &cancellables) } - + private func willUpdateProfiles(_ newProfiles: [UUID: Profile]) { pp_log.debug("Profiles updated: \(newProfiles.values.map(\.header))") defer { objectWillChange.send() } - + // IMPORTANT: invalidate current profile if deleted if !currentProfile.value.isPlaceholder && !newProfiles.keys.contains(currentProfile.value.id) { pp_log.info("\tCurrent profile deleted, invalidating...") @@ -336,7 +336,7 @@ extension ProfileManager { pp_log.info("\tActive profile was deleted") self.activeProfileId = nil } - + didUpdateProfiles.send() // IMPORTANT: defer task to avoid recursive saves (is non-main thread an issue?) @@ -345,7 +345,7 @@ extension ProfileManager { fixDuplicateNames(in: newProfiles) } } - + private func fixDuplicateNames(in newProfiles: [UUID: Profile]) { var allNames = newProfiles.values.map(\.header.name) let distinctNames = Set(allNames) @@ -403,7 +403,7 @@ extension ProfileManager { public func makeProfileReady(_ profile: Profile) async throws { try await fetchProfileProviderIfMissing(profile) } - + private func isProfileProviderAvailable(_ profile: Profile) -> Bool { guard let providerName = profile.header.providerName else { return true // host @@ -464,7 +464,7 @@ extension ProfileManager { private extension ProfileManager { private enum StoreKey: String, KeyStoreDomainLocation { case activeProfileId - + var domain: String { "Passepartout.ProfileManager" } diff --git a/PassepartoutLibrary/Sources/PassepartoutProfiles/Managers/ProfileManagerStrategy.swift b/PassepartoutLibrary/Sources/PassepartoutProfiles/Managers/ProfileManagerStrategy.swift index 5d0228b9..88201165 100644 --- a/PassepartoutLibrary/Sources/PassepartoutProfiles/Managers/ProfileManagerStrategy.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProfiles/Managers/ProfileManagerStrategy.swift @@ -29,11 +29,11 @@ import PassepartoutCore public protocol ProfileManagerStrategy { var allProfiles: [UUID: Profile] { get } - + func profiles() -> [Profile] - + func profile(withId: UUID) -> Profile? - + func saveProfiles(_ profiles: [Profile]) func removeProfiles(withIds ids: [UUID]) diff --git a/PassepartoutLibrary/Sources/PassepartoutProfiles/Models/ObservableProfile.swift b/PassepartoutLibrary/Sources/PassepartoutProfiles/Models/ObservableProfile.swift index f0d34165..bf3c36f3 100644 --- a/PassepartoutLibrary/Sources/PassepartoutProfiles/Models/ObservableProfile.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProfiles/Models/ObservableProfile.swift @@ -29,9 +29,9 @@ import PassepartoutUtils public class ObservableProfile: ValueHolder, ObservableObject { @Published public internal(set) var isLoading = false - + @Published public var value: Profile - + public init() { value = .placeholder } diff --git a/PassepartoutLibrary/Sources/PassepartoutProfiles/Repositories/ProfileMapper.swift b/PassepartoutLibrary/Sources/PassepartoutProfiles/Repositories/ProfileMapper.swift index 18e05904..df1b8696 100644 --- a/PassepartoutLibrary/Sources/PassepartoutProfiles/Repositories/ProfileMapper.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProfiles/Repositories/ProfileMapper.swift @@ -30,11 +30,11 @@ import PassepartoutUtils struct ProfileMapper: DTOMapper, ModelMapper { private let context: NSManagedObjectContext - + init(_ context: NSManagedObjectContext) { self.context = context } - + func toDTO(_ ws: Profile) throws -> CDProfile { let profile = ProfileHeaderMapper(context).toDTO(ws) do { @@ -62,11 +62,11 @@ struct ProfileMapper: DTOMapper, ModelMapper { struct ProfileHeaderMapper: DTOMapper, ModelMapper { private let context: NSManagedObjectContext - + init(_ context: NSManagedObjectContext) { self.context = context } - + func toDTO(_ ws: Profile) -> CDProfile { let profile = CDProfile(context: context) profile.uuid = ws.header.id @@ -75,14 +75,14 @@ struct ProfileHeaderMapper: DTOMapper, ModelMapper { profile.lastUpdate = Date() return profile } - + static func toModel(_ dto: CDProfile) -> Profile.Header? { guard let uuid = dto.uuid, let name = dto.name else { Utils.assertCoreDataDecodingFailed(#file, #function, #line) return nil - } + } return Profile.Header( uuid: uuid, name: name, diff --git a/PassepartoutLibrary/Sources/PassepartoutProfiles/Repositories/ProfileRepository.swift b/PassepartoutLibrary/Sources/PassepartoutProfiles/Repositories/ProfileRepository.swift index a1af0ca9..bd070e4e 100644 --- a/PassepartoutLibrary/Sources/PassepartoutProfiles/Repositories/ProfileRepository.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProfiles/Repositories/ProfileRepository.swift @@ -30,11 +30,11 @@ import PassepartoutUtils class ProfileRepository: Repository { private let context: NSManagedObjectContext - + required init(_ context: NSManagedObjectContext) { self.context = context } - + func fetchedProfiles() -> FetchedValueHolder<[UUID: Profile]> { let request: NSFetchRequest = CDProfile.fetchRequest() request.sortDescriptors = [ @@ -60,7 +60,7 @@ class ProfileRepository: Repository { initial: [:] ) } - + func profiles() -> [Profile] { let request = CDProfile.fetchRequest() request.sortDescriptors = [ diff --git a/PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructure+CoreDataProperties.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructure+CoreDataProperties.swift index 7572a354..7af01970 100644 --- a/PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructure+CoreDataProperties.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructure+CoreDataProperties.swift @@ -10,7 +10,6 @@ import Foundation import CoreData - extension CDInfrastructure { @nonobjc public class func fetchRequest() -> NSFetchRequest { @@ -42,6 +41,6 @@ extension CDInfrastructure { } -extension CDInfrastructure : Identifiable { +extension CDInfrastructure: Identifiable { } diff --git a/PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructureCategory+CoreDataProperties.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructureCategory+CoreDataProperties.swift index df36533f..ba1dc05f 100644 --- a/PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructureCategory+CoreDataProperties.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructureCategory+CoreDataProperties.swift @@ -10,7 +10,6 @@ import Foundation import CoreData - extension CDInfrastructureCategory { @nonobjc public class func fetchRequest() -> NSFetchRequest { @@ -76,6 +75,6 @@ extension CDInfrastructureCategory { } -extension CDInfrastructureCategory : Identifiable { +extension CDInfrastructureCategory: Identifiable { } diff --git a/PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructureDefaultSettings+CoreDataProperties.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructureDefaultSettings+CoreDataProperties.swift index a35ce90a..892b30e0 100644 --- a/PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructureDefaultSettings+CoreDataProperties.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructureDefaultSettings+CoreDataProperties.swift @@ -10,7 +10,6 @@ import Foundation import CoreData - extension CDInfrastructureDefaultSettings { @nonobjc public class func fetchRequest() -> NSFetchRequest { @@ -23,6 +22,6 @@ extension CDInfrastructureDefaultSettings { } -extension CDInfrastructureDefaultSettings : Identifiable { +extension CDInfrastructureDefaultSettings: Identifiable { } diff --git a/PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructureLocation+CoreDataProperties.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructureLocation+CoreDataProperties.swift index b472d2e4..e0883d40 100644 --- a/PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructureLocation+CoreDataProperties.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructureLocation+CoreDataProperties.swift @@ -10,7 +10,6 @@ import Foundation import CoreData - extension CDInfrastructureLocation { @nonobjc public class func fetchRequest() -> NSFetchRequest { @@ -40,6 +39,6 @@ extension CDInfrastructureLocation { } -extension CDInfrastructureLocation : Identifiable { +extension CDInfrastructureLocation: Identifiable { } diff --git a/PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructurePreset+CoreDataProperties.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructurePreset+CoreDataProperties.swift index c2cdc072..26e0d33e 100644 --- a/PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructurePreset+CoreDataProperties.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructurePreset+CoreDataProperties.swift @@ -10,7 +10,6 @@ import Foundation import CoreData - extension CDInfrastructurePreset { @nonobjc public class func fetchRequest() -> NSFetchRequest { @@ -43,6 +42,6 @@ extension CDInfrastructurePreset { } -extension CDInfrastructurePreset : Identifiable { +extension CDInfrastructurePreset: Identifiable { } diff --git a/PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructureServer+CoreDataProperties.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructureServer+CoreDataProperties.swift index e5ba5a35..04f15ac4 100644 --- a/PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructureServer+CoreDataProperties.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructureServer+CoreDataProperties.swift @@ -10,7 +10,6 @@ import Foundation import CoreData - extension CDInfrastructureServer { @nonobjc public class func fetchRequest() -> NSFetchRequest { @@ -31,6 +30,6 @@ extension CDInfrastructureServer { } -extension CDInfrastructureServer : Identifiable { +extension CDInfrastructureServer: Identifiable { } diff --git a/PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDProvider+CoreDataProperties.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDProvider+CoreDataProperties.swift index bb514a1b..f28ddddc 100644 --- a/PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDProvider+CoreDataProperties.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDProvider+CoreDataProperties.swift @@ -10,7 +10,6 @@ import Foundation import CoreData - extension CDProvider { @nonobjc public class func fetchRequest() -> NSFetchRequest { @@ -41,6 +40,6 @@ extension CDProvider { } -extension CDProvider : Identifiable { +extension CDProvider: Identifiable { } diff --git a/PassepartoutLibrary/Sources/PassepartoutProviders/Extensions/ProviderName+Credentials.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/Extensions/ProviderName+Credentials.swift index 137c01a2..2cce64eb 100644 --- a/PassepartoutLibrary/Sources/PassepartoutProviders/Extensions/ProviderName+Credentials.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProviders/Extensions/ProviderName+Credentials.swift @@ -35,7 +35,7 @@ extension ProviderName { switch self { case .protonvpn, .surfshark, .torguard, .windscribe: return .specific - + default: return .web } diff --git a/PassepartoutLibrary/Sources/PassepartoutProviders/Managers/ProviderManager.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/Managers/ProviderManager.swift index 02f9d10b..26e6acc4 100644 --- a/PassepartoutLibrary/Sources/PassepartoutProviders/Managers/ProviderManager.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProviders/Managers/ProviderManager.swift @@ -31,13 +31,13 @@ import PassepartoutUtils public final class ProviderManager: ObservableObject, RateLimited { private let appBuild: Int - + private let bundleServices: WebServices - + private let webServices: WebServices - + private let persistence: Persistence - + private let providerRepository: ProviderRepository private let infrastructureRepository: InfrastructureRepository @@ -57,29 +57,29 @@ public final class ProviderManager: ObservableObject, RateLimited { _ = allProviders() } - + // MARK: Queries public func allProviders() -> [ProviderMetadata] { providerRepository.allProviders() } - + public func provider(withName name: ProviderName) -> ProviderMetadata? { providerRepository.provider(withName: name) } - + public func isAvailable(_ name: ProviderName, vpnProtocol: VPNProtocolType) -> Bool { infrastructureRepository.lastInfrastructureUpdate(withName: name, vpnProtocol: vpnProtocol) != nil } - + public func defaultUsername(_ name: ProviderName, vpnProtocol: VPNProtocolType) -> String? { infrastructureRepository.defaultUsername(forProviderWithName: name, vpnProtocol: vpnProtocol) } - + public func lastUpdate(_ name: ProviderName, vpnProtocol: VPNProtocolType) -> Date? { infrastructureRepository.lastInfrastructureUpdate(withName: name, vpnProtocol: vpnProtocol) } - + public func categories(_ name: ProviderName, vpnProtocol: VPNProtocolType) -> [ProviderCategory] { serverRepository.categories(forProviderWithName: name, vpnProtocol: vpnProtocol) } @@ -95,7 +95,7 @@ public final class ProviderManager: ObservableObject, RateLimited { public func anyDefaultServer(_ name: ProviderName, vpnProtocol: VPNProtocolType) -> ProviderServer? { serverRepository.anyDefaultServer(forProviderWithName: name, vpnProtocol: vpnProtocol) } - + public func server(withId id: String) -> ProviderServer? { serverRepository.server(withId: id) } @@ -108,7 +108,7 @@ public final class ProviderManager: ObservableObject, RateLimited { .setFailureType(to: Error.self) .eraseToAnyPublisher() } - + let publisher = priority.publisher(remote: { self.webServices.providersIndex() }, bundle: { @@ -124,7 +124,7 @@ public final class ProviderManager: ObservableObject, RateLimited { self.didUpdateProviders.send() }.eraseToAnyPublisher() } - + public func fetchProviderPublisher(withName providerName: ProviderName, vpnProtocol: VPNProtocolType, priority: ProviderManagerFetchPriority) -> AnyPublisher { guard !isRateLimited(providerName) else { return Just(()) @@ -158,7 +158,7 @@ public final class ProviderManager: ObservableObject, RateLimited { .setFailureType(to: Error.self) .eraseToAnyPublisher() } - + guard self.appBuild >= infrastructure.build else { pp_log.error("Infrastructure requires app build >= \(infrastructure.build) (app is \(self.appBuild))") return Fail(error: ProviderManagerError.outdatedBuild(self.appBuild, infrastructure.build)) @@ -181,7 +181,7 @@ public final class ProviderManager: ObservableObject, RateLimited { .eraseToAnyPublisher() }.eraseToAnyPublisher() } - + public func reset() { persistence.truncate() @@ -189,17 +189,17 @@ public final class ProviderManager: ObservableObject, RateLimited { } // MARK: RateLimited - + private let indexActionName = "" - + public var lastActionDate: [String: Date] = [:] - + public var rateLimitMilliseconds: Int? } private enum ProviderManagerError: LocalizedError { case outdatedBuild(Int, Int) - + var errorDescription: String? { switch self { case .outdatedBuild(let current, let min): @@ -216,10 +216,10 @@ private extension ProviderManagerFetchPriority { switch self { case .bundle: return bundle() - + case .remote: return remote() - + case .remoteThenBundle: return remote() .catch { error -> AnyPublisher in @@ -242,7 +242,7 @@ private extension VPNProtocolType { switch self { case .openVPN: return .openVPN - + case .wireGuard: return .wireGuard } diff --git a/PassepartoutLibrary/Sources/PassepartoutProviders/Managers/ProviderManagerFetchPriority.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/Managers/ProviderManagerFetchPriority.swift index c151607d..ea442a62 100644 --- a/PassepartoutLibrary/Sources/PassepartoutProviders/Managers/ProviderManagerFetchPriority.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProviders/Managers/ProviderManagerFetchPriority.swift @@ -27,8 +27,8 @@ import Foundation public enum ProviderManagerFetchPriority { case bundle - + case remote - + case remoteThenBundle } diff --git a/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/CategoryMapper.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/CategoryMapper.swift index 152d01c3..abe1bac5 100644 --- a/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/CategoryMapper.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/CategoryMapper.swift @@ -31,14 +31,14 @@ import CoreData struct CategoryMapper: DTOMapper, ModelMapper { private let context: NSManagedObjectContext - + private let vpnProtocol: VPNProtocolType - + init(_ context: NSManagedObjectContext, _ vpnProtocol: VPNProtocolType) { self.context = context self.vpnProtocol = vpnProtocol } - + func toDTO(_ ws: WSProviderCategory) -> CDInfrastructureCategory { let category = CDInfrastructureCategory(context: context) let locations = ws.locations.compactMap(LocationMapper(context).toDTO) @@ -54,7 +54,7 @@ struct CategoryMapper: DTOMapper, ModelMapper { return category } - + static func toModel(_ dto: CDInfrastructureCategory) -> ProviderCategory? { guard let infrastructureDTO = dto.infrastructure, let providerDTO = infrastructureDTO.provider, diff --git a/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/DefaultSettingsMapper.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/DefaultSettingsMapper.swift index a37f9f7c..5a3c1357 100644 --- a/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/DefaultSettingsMapper.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/DefaultSettingsMapper.swift @@ -31,7 +31,7 @@ import PassepartoutUtils struct DefaultSettingsMapper: DTOMapper { private let context: NSManagedObjectContext - + init(_ context: NSManagedObjectContext) { self.context = context } diff --git a/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/InfrastructureMapper.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/InfrastructureMapper.swift index fdc21ff7..18bee3d5 100644 --- a/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/InfrastructureMapper.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/InfrastructureMapper.swift @@ -31,11 +31,11 @@ import PassepartoutUtils struct InfrastructureMapper: DTOMapper { private let context: NSManagedObjectContext - + private let providerName: ProviderName - + private let vpnProtocol: VPNProtocolType - + init(_ context: NSManagedObjectContext, _ providerName: ProviderName, _ vpnProtocol: VPNProtocolType) { self.context = context self.providerName = providerName @@ -45,7 +45,7 @@ struct InfrastructureMapper: DTOMapper { func toDTO(_ ws: WSProviderInfrastructure) -> CDInfrastructure { let infrastructure = CDInfrastructure(context: context) infrastructure.vpnProtocol = vpnProtocol.rawValue - + let defaults = DefaultSettingsMapper(context).toDTO(ws.defaults) infrastructure.defaults = defaults defaults.infrastructure = infrastructure @@ -54,7 +54,7 @@ struct InfrastructureMapper: DTOMapper { let categories = ws.categories.compactMap(CategoryMapper(context, vpnProtocol).toDTO) infrastructure.addToCategories(Set(categories) as NSSet) - + var categoryByName: [String: CDInfrastructureCategory] = [:] categories.forEach { category in category.infrastructure = infrastructure @@ -85,7 +85,7 @@ struct InfrastructureMapper: DTOMapper { } } } - + // do this at the very end, when all entities have their parent chain set categories.forEach { $0.servers?.forEach { @@ -106,7 +106,7 @@ struct InfrastructureMapper: DTOMapper { server.uniqueId = uniqueId } } - + return infrastructure } } diff --git a/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/InfrastructureRepository.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/InfrastructureRepository.swift index 5a5eda94..9fc13457 100644 --- a/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/InfrastructureRepository.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/InfrastructureRepository.swift @@ -31,11 +31,11 @@ import PassepartoutUtils class InfrastructureRepository: Repository { private let context: NSManagedObjectContext - + required init(_ context: NSManagedObjectContext) { self.context = context } - + func saveInfrastructure( _ infrastructure: WSProviderInfrastructure, vpnProtocol: VPNProtocolType, @@ -53,7 +53,7 @@ class InfrastructureRepository: Repository { let request = fetchRequest(infrastructure.name, vpnProtocol) let existing = try context.fetch(request) existing.forEach(context.delete) - + let dto = InfrastructureMapper( context, infrastructure.name, @@ -113,7 +113,7 @@ class InfrastructureRepository: Repository { return nil } } - + private func fetchRequest(_ name: ProviderName, _ vpnProtocol: VPNProtocolType) -> NSFetchRequest { let request = CDInfrastructure.fetchRequest() request.predicate = NSPredicate( @@ -123,7 +123,7 @@ class InfrastructureRepository: Repository { ) return request } - + private func providerDTO(forName name: ProviderName) throws -> CDProvider? { let request = CDProvider.fetchRequest() request.sortDescriptors = [ diff --git a/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/LocationMapper.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/LocationMapper.swift index 715e148e..659674b2 100644 --- a/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/LocationMapper.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/LocationMapper.swift @@ -31,7 +31,7 @@ import PassepartoutUtils struct LocationMapper: DTOMapper, ModelMapper { private let context: NSManagedObjectContext - + init(_ context: NSManagedObjectContext) { self.context = context } @@ -48,7 +48,7 @@ struct LocationMapper: DTOMapper, ModelMapper { return location } - + static func toModel(_ dto: CDInfrastructureLocation) -> ProviderLocation? { guard let infrastructureDTO = dto.category?.infrastructure, let providerDTO = infrastructureDTO.provider, @@ -61,14 +61,14 @@ struct LocationMapper: DTOMapper, ModelMapper { Utils.assertCoreDataDecodingFailed(#file, #function, #line) return nil } - + // var server: ProviderServer? // if dto.servers?.count == 1, let serverDTO = dto.servers?.anyObject() as? CDInfrastructureServer { // server = ServerMapper.toModel(serverDTO) // } let servers = (dto.servers?.allObjects as? [CDInfrastructureServer])? .compactMap(ServerMapper.toModel) - + return ProviderLocation( providerMetadata: providerMetadata, vpnProtocol: vpnProtocol, diff --git a/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/PresetMapper.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/PresetMapper.swift index f22d9497..954312b7 100644 --- a/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/PresetMapper.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/PresetMapper.swift @@ -32,7 +32,7 @@ import GenericJSON struct PresetMapper: DTOMapper, ModelMapper { private let context: NSManagedObjectContext - + init(_ context: NSManagedObjectContext) { self.context = context } @@ -51,7 +51,7 @@ struct PresetMapper: DTOMapper, ModelMapper { } return preset } - + static func toModel(_ dto: CDInfrastructurePreset) -> ProviderServer.Preset? { guard let id = dto.id, let name = dto.name, @@ -78,7 +78,7 @@ private extension WSProviderPreset { var encodedOpenVPNConfiguration: Data? { return try? jsonOpenVPNConfiguration?.encoded() } - + var encodedWireGuardConfiguration: Data? { return try? jsonWireGuardConfiguration?.encoded() } diff --git a/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/ProviderMapper.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/ProviderMapper.swift index 35b433f8..7a705e5e 100644 --- a/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/ProviderMapper.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/ProviderMapper.swift @@ -31,7 +31,7 @@ import PassepartoutUtils struct ProviderMapper: DTOMapper, ModelMapper { private let context: NSManagedObjectContext - + init(_ context: NSManagedObjectContext) { self.context = context } @@ -49,7 +49,7 @@ struct ProviderMapper: DTOMapper, ModelMapper { infra.provider = provider provider.addToInfrastructures(infra) } - + return provider } @@ -60,7 +60,7 @@ struct ProviderMapper: DTOMapper, ModelMapper { Utils.assertCoreDataDecodingFailed(#file, #function, #line) return nil } - + var protos: [VPNProtocolType] = [] if let infraDTOs = dto.infrastructures?.allObjects as? [CDInfrastructure] { protos = infraDTOs diff --git a/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/ProviderRepository.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/ProviderRepository.swift index ef46e8cc..ffc43c35 100644 --- a/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/ProviderRepository.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/ProviderRepository.swift @@ -31,11 +31,11 @@ import PassepartoutUtils class ProviderRepository: Repository { private let context: NSManagedObjectContext - + required init(_ context: NSManagedObjectContext) { self.context = context } - + func allProviders() -> [ProviderMetadata] { let request = CDProvider.fetchRequest() request.sortDescriptors = [ @@ -129,7 +129,7 @@ class ProviderRepository: Repository { throw error } } - + private func reassignInfrastructures(from oldProvider: CDProvider, to newProvider: CDProvider) { oldProvider.infrastructures?.forEach { guard let infra = $0 as? CDInfrastructure else { diff --git a/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/ServerMapper.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/ServerMapper.swift index 749e9377..4a1216fd 100644 --- a/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/ServerMapper.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/ServerMapper.swift @@ -31,7 +31,7 @@ import PassepartoutUtils struct ServerMapper: DTOMapper, ModelMapper { private let context: NSManagedObjectContext - + init(_ context: NSManagedObjectContext) { self.context = context } @@ -62,7 +62,7 @@ struct ServerMapper: DTOMapper, ModelMapper { return server } - + static func toModel(_ dto: CDInfrastructureServer) -> ProviderServer? { guard let uniqueId = dto.uniqueId, let apiId = dto.apiId, @@ -103,7 +103,7 @@ struct ServerMapper: DTOMapper, ModelMapper { presetIds: supportedPresetIds ) } - + static func toModelWithPresets(_ dto: CDInfrastructureServer) -> ProviderServer? { guard let server = toModel(dto), let categoryDTO = dto.category, @@ -123,7 +123,7 @@ struct ServerMapper: DTOMapper, ModelMapper { let presets = presetDTOs .sorted() .compactMap(PresetMapper.toModel) - + return server.withPresets(presets) } } @@ -132,7 +132,7 @@ private extension WSProviderServer { var encodedExtraCountryCodes: String? { extraCountryCodes?.joined(separator: ",") } - + var encodedTags: String? { tags?.joined(separator: ",") } @@ -151,11 +151,11 @@ private extension CDInfrastructureServer { var decodedExtraCountryCodes: [String]? { extraCountryCodes?.components(separatedBy: ",") } - + var decodedTags: [String]? { tags?.components(separatedBy: ",") } - + var decodedIPAddresses: [String] { ipAddresses?.components(separatedBy: ",") ?? [] } diff --git a/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/ServerRepository.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/ServerRepository.swift index e496335f..4ed39cbc 100644 --- a/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/ServerRepository.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/ServerRepository.swift @@ -31,11 +31,11 @@ import PassepartoutUtils class ServerRepository: Repository { private let context: NSManagedObjectContext - + required init(_ context: NSManagedObjectContext) { self.context = context } - + func categories(forProviderWithName name: ProviderName, vpnProtocol: VPNProtocolType) -> [ProviderCategory] { let request = CDInfrastructureCategory.fetchRequest() request.predicate = NSPredicate( diff --git a/PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSProviderCategory.swift b/PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSProviderCategory.swift index 8516bc5b..6760f8de 100644 --- a/PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSProviderCategory.swift +++ b/PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSProviderCategory.swift @@ -28,18 +28,18 @@ import Foundation public struct WSProviderCategory: Codable { enum CodingKeys: String, CodingKey { case name - + case locations - + case supportedPresetIds = "presets" } - + public let name: String - + public let locations: [WSProviderLocation] public var supportedPresetIds: [String]? - + public init(name: String, locations: [WSProviderLocation]) { self.name = name self.locations = locations diff --git a/PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSProviderInfrastructure.swift b/PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSProviderInfrastructure.swift index 18bba023..21ed760a 100644 --- a/PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSProviderInfrastructure.swift +++ b/PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSProviderInfrastructure.swift @@ -29,21 +29,21 @@ public struct WSProviderInfrastructure: Codable { public struct Defaults: Codable { enum CodingKeys: String, CodingKey { case usernamePlaceholder = "username" - + case countryCode = "country" } - + public let usernamePlaceholder: String? public let countryCode: String } - + public let build: Int - + public let name: WSProviderName - + public let fullName: String - + public let categories: [WSProviderCategory] public let presets: [WSProviderPreset] diff --git a/PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSProviderLocation.swift b/PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSProviderLocation.swift index a95a814e..d023aa48 100644 --- a/PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSProviderLocation.swift +++ b/PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSProviderLocation.swift @@ -33,9 +33,9 @@ public struct WSProviderLocation: Codable { } public let countryCode: String - + public let servers: [WSProviderServer] - + public init(countryCode: String, servers: [WSProviderServer]) { self.countryCode = countryCode self.servers = servers diff --git a/PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSProviderPreset.swift b/PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSProviderPreset.swift index 5f4138a7..927a28d0 100644 --- a/PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSProviderPreset.swift +++ b/PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSProviderPreset.swift @@ -29,28 +29,28 @@ import GenericJSON public struct WSProviderPreset: Codable { enum CodingKeys: String, CodingKey { case id - + case name - + case comment case external case jsonOpenVPNConfiguration = "ovpn" - + case jsonWireGuardConfiguration = "wg" } - + public let id: String - + public let name: String - + public let comment: String public var external: [String: String]? - + public var jsonOpenVPNConfiguration: JSON? - + public var jsonWireGuardConfiguration: JSON? public init(id: String, name: String, comment: String) { diff --git a/PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSProviderServer.swift b/PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSProviderServer.swift index d0445971..bb750f66 100644 --- a/PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSProviderServer.swift +++ b/PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSProviderServer.swift @@ -38,30 +38,30 @@ public struct WSProviderServer: Codable { case serverIndex = "num" case tags - + case hostname case numericAddresses = "addrs" } - + public let id: String - + public let countryCode: String - + public var extraCountryCodes: [String]? public var area: String? public var serverIndex: Int? - + public var tags: [String]? - + // public var geo: (Double, Double)? - + public var hostname: String? - + public var numericAddresses: Set? - + public init(id: String, countryCode: String) { self.id = id self.countryCode = countryCode diff --git a/PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSProvidersIndex.swift b/PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSProvidersIndex.swift index 5eddce86..e71ae231 100644 --- a/PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSProvidersIndex.swift +++ b/PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSProvidersIndex.swift @@ -29,18 +29,18 @@ public struct WSProvidersIndex: Codable { public struct Metadata: Codable, CustomStringConvertible { enum CodingKeys: String, CodingKey { case name - + case fullName - + case supportedVPNProtocols = "vpn" } - + public let name: WSProviderName - + public let fullName: String - + public let supportedVPNProtocols: [WSVPNProtocol] - + public init(name: WSProviderName, fullName: String, supportedVPNProtocols: [WSVPNProtocol]) { self.name = name self.fullName = fullName @@ -55,7 +55,7 @@ public struct WSProvidersIndex: Codable { } public let metadata: [Metadata] - + public init(metadata: [Metadata]) { self.metadata = metadata } diff --git a/PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSVPNProtocol.swift b/PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSVPNProtocol.swift index f54090e5..1cfa5079 100644 --- a/PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSVPNProtocol.swift +++ b/PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSVPNProtocol.swift @@ -27,6 +27,6 @@ import Foundation public enum WSVPNProtocol: String, Codable { case openVPN = "ovpn" - + case wireGuard = "wg" } diff --git a/PassepartoutLibrary/Sources/PassepartoutServices/DefaultWebServices.swift b/PassepartoutLibrary/Sources/PassepartoutServices/DefaultWebServices.swift index c3a14d7f..53d48aa6 100644 --- a/PassepartoutLibrary/Sources/PassepartoutServices/DefaultWebServices.swift +++ b/PassepartoutLibrary/Sources/PassepartoutServices/DefaultWebServices.swift @@ -36,7 +36,7 @@ public class DefaultWebServices: WebServices { case providersIndex case providerNetwork(WSProviderName, WSVPNProtocol) - + private var pathName: String { switch self { case .providersIndex: @@ -46,11 +46,11 @@ public class DefaultWebServices: WebServices { return "\(Group.providers.rawValue)/\(providerName)/\(vpnProtocol.filename)" } } - + private var fileType: String { "json" } - + // MARK: GenericWebEndpoint var path: String { @@ -59,7 +59,7 @@ public class DefaultWebServices: WebServices { } private let ws: GenericWebServices - + public init(_ version: String, _ root: URL, timeout: TimeInterval?, queue: DispatchQueue = .main) { ws = GenericWebServices(version, root, timeout: timeout) } @@ -98,7 +98,7 @@ private extension WSVPNProtocol { switch self { case .openVPN: return "ovpn" - + case .wireGuard: return "wg" } diff --git a/PassepartoutLibrary/Sources/PassepartoutServices/Extensions/WSProviderName+Extensions.swift b/PassepartoutLibrary/Sources/PassepartoutServices/Extensions/WSProviderName+Extensions.swift index dcc86853..f928d7c9 100644 --- a/PassepartoutLibrary/Sources/PassepartoutServices/Extensions/WSProviderName+Extensions.swift +++ b/PassepartoutLibrary/Sources/PassepartoutServices/Extensions/WSProviderName+Extensions.swift @@ -37,9 +37,9 @@ extension WSProviderName { public static let pia = "pia" public static let protonvpn = "protonvpn" - + public static let surfshark = "surfshark" - + public static let torguard = "torguard" public static let tunnelbear = "tunnelbear" diff --git a/PassepartoutLibrary/Sources/PassepartoutServices/WebServices.swift b/PassepartoutLibrary/Sources/PassepartoutServices/WebServices.swift index c0876449..73c11e1f 100644 --- a/PassepartoutLibrary/Sources/PassepartoutServices/WebServices.swift +++ b/PassepartoutLibrary/Sources/PassepartoutServices/WebServices.swift @@ -29,23 +29,23 @@ import PassepartoutUtils public enum WebError: GenericWebServicesError, LocalizedError { case http(Int) - + case emptyResponse - + case unknown public static func httpStatus(_ status: Int) -> WebError { .http(status) } - + public var errorDescription: String? { switch self { case .http(let status): return "HTTP \(status)" - + case .emptyResponse: return "Empty response" - + default: return nil } diff --git a/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/FetchedValueHolder.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/FetchedValueHolder.swift index 863d44e3..45b4add9 100644 --- a/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/FetchedValueHolder.swift +++ b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/FetchedValueHolder.swift @@ -29,11 +29,11 @@ import Combine public class FetchedValueHolder: NSObject, ValueHolder, NSFetchedResultsControllerDelegate { @Published public var value: V - + private let controller: NSFetchedResultsController - + private let mapping: ([NSFetchRequestResult]) -> V? - + public convenience init( context: NSManagedObjectContext, request: NSFetchRequest, @@ -71,7 +71,7 @@ public class FetchedValueHolder: NSObject, ValueHolder, NSFetchedResultsContr public func controllerDidChangeContent(_ controller: NSFetchedResultsController) { mapResults() } - + private func mapResults() { guard let results = controller.fetchedObjects else { return diff --git a/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/GenericWebResponse.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/GenericWebResponse.swift index 0aa3ffcd..f021052b 100644 --- a/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/GenericWebResponse.swift +++ b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/GenericWebResponse.swift @@ -27,16 +27,16 @@ import Foundation public struct GenericWebResponse { public let value: T? - + public let lastModifiedString: String? - + public var lastModified: Date? { guard let string = lastModifiedString else { return nil } return GenericWebParser.lastModifiedDate(string: string) } - + public let isCached: Bool public static func empty() -> GenericWebResponse { diff --git a/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/GenericWebServices.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/GenericWebServices.swift index 51b5a467..19c57741 100644 --- a/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/GenericWebServices.swift +++ b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/GenericWebServices.swift @@ -28,23 +28,23 @@ import Combine public protocol GenericWebServicesError: Error { static func httpStatus(_ status: Int) -> Self - + static var unknown: Self { get } } public class GenericWebServices { private let version: String? - + private let root: URL - + private let timeout: TimeInterval? - + public init(_ version: String?, _ root: URL, timeout: TimeInterval?) { self.version = version self.root = root self.timeout = timeout } - + public func get(_ endpoint: GenericWebEndpoint) -> URLRequest { var request = URLRequest(url: url(forEndpoint: endpoint), cachePolicy: .reloadIgnoringCacheData) if let timeout = timeout { @@ -52,7 +52,7 @@ public class GenericWebServices { } return request } - + public func parse(_ type: T.Type, request: URLRequest) -> AnyPublisher, Error> { pp_log.debug("GET \(request.url!)") pp_log.debug("Request headers: \(request.allHTTPHeaderFields?.description ?? "none")") @@ -63,7 +63,7 @@ public class GenericWebServices { switch result { case .failure(let error): pp_log.error("Error (response): \(error.localizedDescription)") - + default: break } diff --git a/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/InApp.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/InApp.swift index 9701900b..73400e23 100644 --- a/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/InApp.swift +++ b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/InApp.swift @@ -28,7 +28,7 @@ import StoreKit public enum InAppPurchaseResult { case done - + case cancelled } @@ -41,27 +41,27 @@ public class InApp: NSObject, where PID.RawValue == String { public typealias ProductObserver = ([PID: SKProduct]) -> Void - + public typealias TransactionObserver = (Result) -> Void - + public typealias RestoreObserver = (Bool, PID?, Error?) -> Void - + public typealias FailureObserver = (Error) -> Void - + private var productsMap: [PID: SKProduct] - + public var products: [SKProduct] { [SKProduct](productsMap.values) } - + private var productObservers: [ProductObserver] - + private var productFailureObserver: FailureObserver? - + private var transactionObservers: [String: TransactionObserver] - + private var restoreObservers: [RestoreObserver] - + public override init() { productsMap = [:] productObservers = [] @@ -69,14 +69,14 @@ public class InApp: NSObject, transactionObservers = [:] restoreObservers = [] super.init() - + SKPaymentQueue.default().add(self) } - + deinit { SKPaymentQueue.default().remove(self) } - + public func requestProducts(withIdentifiers identifiers: [PID], completionHandler: ProductObserver?, failureHandler: FailureObserver?) { let req = SKProductsRequest(productIdentifiers: Set(identifiers.map { $0.rawValue })) req.delegate = self @@ -102,13 +102,13 @@ public class InApp: NSObject, transactionObservers[product.productIdentifier] = completionHandler queue.add(payment) } - + public func restorePurchases(completionHandler: @escaping RestoreObserver) { let queue = SKPaymentQueue.default() restoreObservers.append(completionHandler) queue.restoreCompletedTransactions() } - + public func product(withIdentifier productIdentifier: PID) -> SKProduct? { productsMap[productIdentifier] } @@ -120,7 +120,7 @@ public class InApp: NSObject, self.receiveProducts(response.products) } } - + public func request(_ request: SKRequest, didFailWithError error: Error) { if let _ = request as? SKProductsRequest { DispatchQueue.main.async { @@ -131,7 +131,7 @@ public class InApp: NSObject, self.transactionObservers.removeAll() } } - + private func receiveProducts(_ products: [SKProduct]) { productsMap.removeAll() for p in products { @@ -149,11 +149,11 @@ public class InApp: NSObject, public func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) { DispatchQueue.main.async { let currentRestoreObservers = self.restoreObservers - + for tx in transactions { let productIdentifier = tx.payment.productIdentifier let observer = self.transactionObservers[productIdentifier] - + switch tx.transactionState { case .purchased: queue.finishTransaction(tx) @@ -168,7 +168,7 @@ public class InApp: NSObject, } r(false, pid, nil) } - + case .failed: queue.finishTransaction(tx) if let skError = tx.error as? SKError, skError.code == .paymentCancelled { @@ -182,7 +182,7 @@ public class InApp: NSObject, r(false, pid, tx.error) } } - + default: break } @@ -198,7 +198,7 @@ public class InApp: NSObject, self.restoreObservers.removeAll() } } - + public func paymentQueue(_ queue: SKPaymentQueue, restoreCompletedTransactionsFailedWithError error: Error) { DispatchQueue.main.async { for r in self.restoreObservers { diff --git a/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/KeyValueStore.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/KeyValueStore.swift index a7596b86..0e86e212 100644 --- a/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/KeyValueStore.swift +++ b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/KeyValueStore.swift @@ -41,7 +41,7 @@ extension KeyStoreDomainLocation { public protocol KeyValueStore { func setValue(_ value: V?, forLocation location: L) - + func value(forLocation location: L) -> V? func removeValue(forLocation location: L) diff --git a/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/KeyedCache.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/KeyedCache.swift index 685da676..4d608aea 100644 --- a/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/KeyedCache.swift +++ b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/KeyedCache.swift @@ -27,21 +27,21 @@ import Foundation public class KeyedCache { private let query: String - + private var store: [K: V] = [:] public var isEmpty: Bool { store.isEmpty } - + public var storeValues: [V] { Array(store.values) } - + public init(_ query: String) { self.query = query } - + public func set(_ store: [K: V]) { self.store = store } @@ -61,7 +61,7 @@ public class KeyedCache { pp_log.debug("Cache MISS [\(query)]") return value } - + public func forget(where condition: (K) -> Bool) { let removedKeys = store.keys.filter(condition) removedKeys.forEach { @@ -72,7 +72,7 @@ public class KeyedCache { public func forget(_ key: K) { store.removeValue(forKey: key) } - + public func clear() { store.removeAll() } diff --git a/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/LogManager.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/LogManager.swift index 8fd96977..5debb9c7 100644 --- a/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/LogManager.swift +++ b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/LogManager.swift @@ -29,11 +29,11 @@ import SwiftyBeaver @MainActor public class LogManager { public let logFile: URL? - + public var logLevel: SwiftyBeaver.Level = .info - + public var logFormat: String? - + public init(logFile: URL?) { self.logFile = logFile } @@ -46,7 +46,7 @@ public class LogManager { console.format = logFormat } SwiftyBeaver.addDestination(console) - + if let fileURL = logFile { let file = FileDestination() file.minLevel = logLevel diff --git a/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/Mapper.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/Mapper.swift index 6d3bb5f4..fba97877 100644 --- a/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/Mapper.swift +++ b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/Mapper.swift @@ -29,7 +29,7 @@ public protocol DTOMapper { associatedtype WS associatedtype DTO - + func toDTO(_ ws: WS) throws -> DTO } diff --git a/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/Persistence.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/Persistence.swift index b96a849f..c1832940 100644 --- a/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/Persistence.swift +++ b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/Persistence.swift @@ -29,11 +29,11 @@ import Combine public class Persistence { private let container: NSPersistentContainer - + public var context: NSManagedObjectContext { container.viewContext } - + public var coordinator: NSPersistentStoreCoordinator { container.persistentStoreCoordinator } @@ -77,7 +77,7 @@ public class Persistence { container.viewContext.transactionAuthor = author } } - + public var containerURLs: [URL]? { guard let url = container.persistentStoreDescriptions.first?.url else { return nil @@ -88,7 +88,7 @@ public class Persistence { url.deletingPathExtension().appendingPathExtension("sqlite-wal") ] } - + // public func remoteChangesPublisher() -> AnyPublisher { // NotificationCenter.default.publisher( // for: .NSPersistentStoreRemoteChange, diff --git a/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/RateLimited.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/RateLimited.swift index d9c3c09d..c5c1fa22 100644 --- a/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/RateLimited.swift +++ b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/RateLimited.swift @@ -27,7 +27,7 @@ import Foundation public protocol RateLimited: AnyObject { associatedtype ActionID: Hashable - + var lastActionDate: [ActionID: Date] { get set } var rateLimitMilliseconds: Int? { get } @@ -37,7 +37,7 @@ extension RateLimited { public func saveLastAction(_ id: ActionID) { lastActionDate[id] = Date() } - + public func isRateLimited(_ id: ActionID) -> Bool { guard let lastActionDate = lastActionDate[id] else { return false diff --git a/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/Repository.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/Repository.swift index 33e3ab90..08a4f6a8 100644 --- a/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/Repository.swift +++ b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/Repository.swift @@ -27,6 +27,6 @@ import Foundation public protocol Repository { associatedtype Context - + init(_ context: Context) } diff --git a/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/SSIDReader.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/SSIDReader.swift index ced70176..a1a9b43a 100644 --- a/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/SSIDReader.swift +++ b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/SSIDReader.swift @@ -29,22 +29,22 @@ import CoreLocation @MainActor public class SSIDReader: NSObject, ObservableObject { private let manager = CLLocationManager() - + private var continuation: CheckedContinuation? - + private func currentSSID() async -> String { await Utils.currentWifiSSID() ?? "" } - + public func requestCurrentSSID() async throws -> String { switch manager.authorizationStatus { case .authorizedAlways, .authorizedWhenInUse, .denied: return await currentSSID() - + default: return try await withCheckedThrowingContinuation { continuation in self.continuation = continuation - + manager.delegate = self manager.requestWhenInUseAuthorization() } @@ -66,7 +66,7 @@ extension SSIDReader: CLLocationManagerDelegate { continuation = nil } } - + public func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { continuation?.resume(throwing: error) continuation = nil diff --git a/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/UserDefaultsStore.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/UserDefaultsStore.swift index 04b67d85..6f6fbfc8 100644 --- a/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/UserDefaultsStore.swift +++ b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/UserDefaultsStore.swift @@ -27,7 +27,7 @@ import Foundation public struct UserDefaultsStore: KeyValueStore { private let defaults: UserDefaults - + public init(defaults: UserDefaults) { self.defaults = defaults } @@ -39,11 +39,11 @@ public struct UserDefaultsStore: KeyValueStore { } defaults.setValue(value, forKey: location.key) } - + public func value(forLocation location: L) -> V? { defaults.value(forKey: location.key) as? V } - + public func removeValue(forLocation location: L) { defaults.removeObject(forKey: location.key) } diff --git a/PassepartoutLibrary/Sources/PassepartoutUtils/Utils/Utils+Async.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Utils/Utils+Async.swift index 786f41af..2e69f568 100644 --- a/PassepartoutLibrary/Sources/PassepartoutUtils/Utils/Utils+Async.swift +++ b/PassepartoutLibrary/Sources/PassepartoutUtils/Utils/Utils+Async.swift @@ -37,7 +37,7 @@ extension Publisher { try await withCheckedThrowingContinuation { continuation in var cancellable: AnyCancellable? var isResumed = false - + cancellable = first() .sink { result in switch result { diff --git a/PassepartoutLibrary/Sources/PassepartoutUtils/Utils/Utils+FileManager.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Utils/Utils+FileManager.swift index 1fd20e9f..3e0423db 100644 --- a/PassepartoutLibrary/Sources/PassepartoutUtils/Utils/Utils+FileManager.swift +++ b/PassepartoutLibrary/Sources/PassepartoutUtils/Utils/Utils+FileManager.swift @@ -34,7 +34,7 @@ extension FileManager { } return directory } - + // public func creationDate(of path: String) -> Date? { // guard let attrs = try? attributesOfItem(atPath: path) else { // return nil diff --git a/PassepartoutLibrary/Sources/PassepartoutUtils/Utils/Utils+Logging.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Utils/Utils+Logging.swift index e79c3feb..07255356 100644 --- a/PassepartoutLibrary/Sources/PassepartoutUtils/Utils/Utils+Logging.swift +++ b/PassepartoutLibrary/Sources/PassepartoutUtils/Utils/Utils+Logging.swift @@ -36,7 +36,7 @@ extension Utils { // assertionFailure(message ?? "Cannot decode entity required fields - \(file):\(function):\(line)") pp_log.warning(message ?? "Cannot decode entity required fields - \(file):\(function):\(line)") } - + public static func logFetchError(_ file: String, _ function: String, _ line: Int, _ error: Error) { pp_log.error("Unable to fetch: \(error) - \(file):\(function):\(line)") } diff --git a/PassepartoutLibrary/Sources/PassepartoutUtils/Utils/Utils+Network.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Utils/Utils+Network.swift index 8939f03a..a0a27e9f 100644 --- a/PassepartoutLibrary/Sources/PassepartoutUtils/Utils/Utils+Network.swift +++ b/PassepartoutLibrary/Sources/PassepartoutUtils/Utils/Utils+Network.swift @@ -55,7 +55,7 @@ extension Utils { return isFound } #endif - + public static func hasEthernet() -> Bool { #if targetEnvironment(macCatalyst) || os(macOS) true @@ -108,7 +108,7 @@ extension Utils { } } -//extension Utils { +// extension Utils { // public static func checkConnectivityURL(_ url: URL, timeout: TimeInterval, completionHandler: @escaping (Bool) -> Void) { // let session = URLSession(configuration: .ephemeral) // let request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalAndRemoteCacheData, timeoutInterval: timeout) @@ -128,4 +128,4 @@ extension Utils { // } // }.resume() // } -//} +// } diff --git a/PassepartoutLibrary/Sources/PassepartoutUtils/Utils/Utils+URL.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Utils/Utils+URL.swift index 007d0d25..8a2e0ce1 100644 --- a/PassepartoutLibrary/Sources/PassepartoutUtils/Utils/Utils+URL.swift +++ b/PassepartoutLibrary/Sources/PassepartoutUtils/Utils/Utils+URL.swift @@ -35,7 +35,7 @@ extension URL { public var filename: String { deletingPathExtension().lastPathComponent } - + @discardableResult public static func openURL(_ url: URL) -> Bool { #if os(iOS) diff --git a/PassepartoutLibrary/Sources/PassepartoutVPN/Extensions/OnDemand+Rules.swift b/PassepartoutLibrary/Sources/PassepartoutVPN/Extensions/OnDemand+Rules.swift index 8fb0a52a..64a228a6 100644 --- a/PassepartoutLibrary/Sources/PassepartoutVPN/Extensions/OnDemand+Rules.swift +++ b/PassepartoutLibrary/Sources/PassepartoutVPN/Extensions/OnDemand+Rules.swift @@ -90,7 +90,7 @@ private extension Profile.OnDemand { rules.append(connection) return rules } - + private var policyRule: NEOnDemandRule { disconnectsIfNotMatching ? NEOnDemandRuleDisconnect() : NEOnDemandRuleIgnore() } diff --git a/PassepartoutLibrary/Sources/PassepartoutVPN/Extensions/OpenVPNSettings+VPNConfiguration.swift b/PassepartoutLibrary/Sources/PassepartoutVPN/Extensions/OpenVPNSettings+VPNConfiguration.swift index 44b84eab..5d2598c9 100644 --- a/PassepartoutLibrary/Sources/PassepartoutVPN/Extensions/OpenVPNSettings+VPNConfiguration.swift +++ b/PassepartoutLibrary/Sources/PassepartoutVPN/Extensions/OpenVPNSettings+VPNConfiguration.swift @@ -61,7 +61,7 @@ extension Profile.OpenVPNSettings: VPNConfigurationProviding { cfg.debugLogPath = parameters.preferences.tunnelLogPath cfg.debugLogFormat = parameters.preferences.tunnelLogFormat cfg.masksPrivateData = parameters.preferences.masksPrivateData - + var extra = NetworkExtensionExtra() extra.passwordReference = parameters.passwordReference extra.onDemandRules = parameters.onDemandRules @@ -81,7 +81,7 @@ extension OpenVPN.ConfigurationBuilder { switch settings.choice { case .automatic: break - + case .manual: appendNoPullMask(.routes) var policies: [OpenVPN.RoutingPolicy] = [] @@ -120,7 +120,7 @@ extension OpenVPN.ConfigurationBuilder { case .disabled: break } - + if isDNSEnabled { dnsServers = settings.dnsServers?.filter { !$0.isEmpty } searchDomains = settings.dnsSearchDomains @@ -143,19 +143,19 @@ extension OpenVPN.ConfigurationBuilder { httpsProxy = settings.proxyServer proxyBypassDomains = settings.proxyBypassDomains?.filter { !$0.isEmpty } proxyAutoConfigurationURL = nil - + case .pac: httpProxy = nil httpsProxy = nil proxyBypassDomains = nil proxyAutoConfigurationURL = settings.proxyAutoConfigurationURL - + case .disabled: break } } } - + mutating func applyMTU(from settings: Network.MTUSettings) { switch settings.choice { case .automatic: @@ -165,7 +165,7 @@ extension OpenVPN.ConfigurationBuilder { mtu = settings.mtuBytes } } - + private mutating func appendNoPullMask(_ mask: OpenVPN.PullMask) { if noPullMask == nil { noPullMask = [] diff --git a/PassepartoutLibrary/Sources/PassepartoutVPN/Extensions/VPNProtocolType+Extensions.swift b/PassepartoutLibrary/Sources/PassepartoutVPN/Extensions/VPNProtocolType+Extensions.swift index 5cbff11c..7766e471 100644 --- a/PassepartoutLibrary/Sources/PassepartoutVPN/Extensions/VPNProtocolType+Extensions.swift +++ b/PassepartoutLibrary/Sources/PassepartoutVPN/Extensions/VPNProtocolType+Extensions.swift @@ -50,7 +50,7 @@ extension VPNProtocolType { public var supportsGateway: Bool { true } - + public var supportsDNS: Bool { true } diff --git a/PassepartoutLibrary/Sources/PassepartoutVPN/Extensions/WireGuardSettings+VPNConfiguration.swift b/PassepartoutLibrary/Sources/PassepartoutVPN/Extensions/WireGuardSettings+VPNConfiguration.swift index 09407783..2b129918 100644 --- a/PassepartoutLibrary/Sources/PassepartoutVPN/Extensions/WireGuardSettings+VPNConfiguration.swift +++ b/PassepartoutLibrary/Sources/PassepartoutVPN/Extensions/WireGuardSettings+VPNConfiguration.swift @@ -69,7 +69,7 @@ extension WireGuard.ConfigurationBuilder { switch settings.choice { case .automatic: break - + case .manual: for i in 0..: VPNManagerStrategy where VPNType.Configuration == NetworkExtensionConfiguration, VPNType.Extra == NetworkExtensionExtra { private struct AtomicState: Equatable { let isEnabled: Bool - + let vpnStatus: VPNStatus - + init(isEnabled: Bool = false, vpnStatus: VPNStatus = .disconnected) { self.isEnabled = isEnabled self.vpnStatus = vpnStatus } } - + private let reconnectionSeconds = 2 private let appGroup: String - + private let tunnelBundleIdentifier: (VPNProtocolType) -> String - + private let defaults: UserDefaults private let vpn: VPNType - + private let dataCountInterval: TimeInterval - + // MARK: State - + private var currentState: ObservableVPNState? private let vpnState = CurrentValueSubject(.init()) private var dataCountTimer: AnyCancellable? - + private var cancellables: Set = [] // MARK: Protocol specific - + private var currentBundleIdentifier: String? public init( @@ -105,9 +105,9 @@ public class TunnelKitVPNManagerStrategy: VPNManagerStrategy where .sink(receiveValue: perform) .store(in: &cancellables) } - + // MARK: Strategy - + public func observe(into state: ObservableVPNState) { currentState = state @@ -120,7 +120,7 @@ public class TunnelKitVPNManagerStrategy: VPNManagerStrategy where self.currentState?.vpnStatus = $0.vpnStatus }.store(in: &cancellables) } - + public func reinstate(configuration: VPNConfiguration) async { guard let vpnType = configuration.neConfiguration as? VPNProtocolProviding else { fatalError("Configuration must implement VPNProtocolProviding") @@ -140,7 +140,7 @@ public class TunnelKitVPNManagerStrategy: VPNManagerStrategy where pp_log.error("Unable to install: \(error)") } } - + public func connect(configuration: VPNConfiguration) async { guard let vpnType = configuration.neConfiguration as? VPNProtocolProviding else { fatalError("Configuration must implement VPNProtocolProviding") @@ -161,17 +161,17 @@ public class TunnelKitVPNManagerStrategy: VPNManagerStrategy where pp_log.error("Unable to connect: \(error)") } } - + public func reconnect() async { try? await vpn.reconnect( after: .seconds(reconnectionSeconds) ) } - + public func disconnect() async { await vpn.disconnect() } - + public func removeConfigurations() async { await vpn.uninstall() @@ -181,7 +181,7 @@ public class TunnelKitVPNManagerStrategy: VPNManagerStrategy where vpnStatus: vpnState.value.vpnStatus )) } - + // MARK: Notifications private func onVPNReinstall(_ notification: Notification) { @@ -229,7 +229,7 @@ public class TunnelKitVPNManagerStrategy: VPNManagerStrategy where )) currentState?.lastError = error } - + private func onVPNFail(_ notification: Notification) { vpnState.send(AtomicState( isEnabled: notification.vpnIsEnabled, @@ -258,12 +258,12 @@ public class TunnelKitVPNManagerStrategy: VPNManagerStrategy where return } currentState?.dataCount = currentDataCount - + default: currentState?.dataCount = nil } } - + private func startCountingData() { guard dataCountTimer == nil else { return @@ -283,12 +283,12 @@ public class TunnelKitVPNManagerStrategy: VPNManagerStrategy where } // MARK: Pulled - + public func serverConfiguration(forProtocol vpnProtocol: VPNProtocolType) -> Any? { switch vpnProtocol { case .openVPN: return defaults.openVPNServerConfiguration - + default: return nil } @@ -298,7 +298,7 @@ public class TunnelKitVPNManagerStrategy: VPNManagerStrategy where switch vpnProtocol { case .openVPN: return defaults.openVPNURLForDebugLog(appGroup: appGroup) - + default: return defaults.wireGuardURLForDebugLog(appGroup: appGroup) } @@ -310,10 +310,10 @@ public class TunnelKitVPNManagerStrategy: VPNManagerStrategy where switch bundleIdentifier { case tunnelBundleIdentifier(.openVPN): return defaults.openVPNLastError - + case tunnelBundleIdentifier(.wireGuard): return defaults.wireGuardLastError - + default: return nil } diff --git a/PassepartoutLibrary/Sources/PassepartoutVPN/Managers/VPNManager+Actions.swift b/PassepartoutLibrary/Sources/PassepartoutVPN/Managers/VPNManager+Actions.swift index e6bbc86c..fd706044 100644 --- a/PassepartoutLibrary/Sources/PassepartoutVPN/Managers/VPNManager+Actions.swift +++ b/PassepartoutLibrary/Sources/PassepartoutVPN/Managers/VPNManager+Actions.swift @@ -72,7 +72,7 @@ extension VPNManager { await reconnect(cfg) return profile } - + @discardableResult public func connect(with profileId: UUID, toServer newServerId: String) async throws -> Profile { let result = try profileManager.liveProfileEx(withId: profileId) @@ -110,7 +110,7 @@ extension VPNManager { await reconnect(cfg) return profile } - + public func modifyActiveProfile(_ block: (inout Profile) -> Void) async throws { guard var profile = profileManager.activeProfile else { pp_log.warning("Nothing to modify, no active profile") diff --git a/PassepartoutLibrary/Sources/PassepartoutVPN/Managers/VPNManager+Configuration.swift b/PassepartoutLibrary/Sources/PassepartoutVPN/Managers/VPNManager+Configuration.swift index ac4c27c5..71f51c72 100644 --- a/PassepartoutLibrary/Sources/PassepartoutVPN/Managers/VPNManager+Configuration.swift +++ b/PassepartoutLibrary/Sources/PassepartoutVPN/Managers/VPNManager+Configuration.swift @@ -35,7 +35,7 @@ extension VPNManager { masksPrivateData: masksPrivateData ) } - + func vpnConfigurationWithCurrentProfile() -> VPNConfiguration? { do { guard profileManager.isCurrentProfileActive() else { @@ -55,19 +55,19 @@ extension VPNManager { throw PassepartoutError.missingAccount } } - + // specific provider customizations var newPassword: String? if let providerName = profile.providerName { switch providerName { case .mullvad: newPassword = "m" - + default: break } } - + // IMPORTANT: must commit password to keychain (tunnel needs a password reference) profileManager.savePassword(forProfile: profile, newPassword: newPassword) diff --git a/PassepartoutLibrary/Sources/PassepartoutVPN/Managers/VPNManager.swift b/PassepartoutLibrary/Sources/PassepartoutVPN/Managers/VPNManager.swift index ad981a7d..99b1299f 100644 --- a/PassepartoutLibrary/Sources/PassepartoutVPN/Managers/VPNManager.swift +++ b/PassepartoutLibrary/Sources/PassepartoutVPN/Managers/VPNManager.swift @@ -34,25 +34,25 @@ import PassepartoutUtils public final class VPNManager: ObservableObject { // MARK: Initialization - + let appGroup: String - + private let store: KeyValueStore - + let profileManager: ProfileManager - + let providerManager: ProviderManager private let strategy: VPNManagerStrategy - + public var isNetworkSettingsSupported: () -> Bool - + public var isOnDemandRulesSupported: () -> Bool // MARK: State - + public let currentState: ObservableVPNState - + public let didUpdatePreferences = PassthroughSubject() public private(set) var lastError: Error? { @@ -63,15 +63,15 @@ public final class VPNManager: ObservableObject { currentState.lastError = newValue } } - + public let configurationError = PassthroughSubject() - + // MARK: Internals - + private var lastProfile: Profile = .placeholder - + private var cancellables: Set = [] - + public init( appGroup: String, store: KeyValueStore, @@ -95,19 +95,19 @@ public final class VPNManager: ObservableObject { clearLastError() await strategy.reinstate(configuration: configuration) } - + func reconnect(_ configuration: VPNConfiguration) async { pp_log.info("Reconnecting VPN (with new configuration)") clearLastError() await strategy.connect(configuration: configuration) } - + public func reconnect() async { pp_log.info("Reconnecting VPN") clearLastError() await strategy.reconnect() } - + public func disable() async { pp_log.info("Disabling VPN") clearLastError() @@ -127,7 +127,7 @@ public final class VPNManager: ObservableObject { public func debugLogURL(forProtocol vpnProtocol: VPNProtocolType) -> URL? { strategy.debugLogURL(forProtocol: vpnProtocol) } - + private func clearLastError() { guard currentState.lastError != nil else { return @@ -143,7 +143,7 @@ extension VPNManager { observeStrategy() observeProfileManager() } - + private func observeStrategy() { strategy.observe(into: currentState) } @@ -167,7 +167,7 @@ extension VPNManager { } }.store(in: &cancellables) } - + private func willUpdateActiveId(_ newId: UUID?) async { guard let newId = newId else { pp_log.info("No active profile, disconnecting VPN...") @@ -176,7 +176,7 @@ extension VPNManager { } pp_log.debug("Active profile: \(newId)") } - + private func willUpdateCurrentProfile(_ newProfile: Profile) async { defer { lastProfile = newProfile @@ -197,7 +197,7 @@ extension VPNManager { } pp_log.debug("Active profile updated: \(newProfile.header.name)") - + var isHandled = false var shouldReconnect = false let notDisconnected = (currentState.vpnStatus != .disconnected) @@ -211,7 +211,7 @@ extension VPNManager { isHandled = true shouldReconnect = notDisconnected } - + // endpoint changed? else if newProfile.providerCustomEndpoint() != lastProfile.providerCustomEndpoint() { pp_log.info("Provider endpoint changed: \(newProfile.providerCustomEndpoint()?.description ?? "automatic")") @@ -219,7 +219,7 @@ extension VPNManager { shouldReconnect = notDisconnected } } else { - + // endpoint changed? if newProfile.hostCustomEndpoint != lastProfile.hostCustomEndpoint { pp_log.info("Host endpoint changed: \(newProfile.hostCustomEndpoint?.description ?? "automatic")") @@ -272,7 +272,7 @@ extension VPNManager { didUpdatePreferences.send(vpnPreferences) } } - + public var masksPrivateData: Bool { get { store.value(forLocation: StoreKey.masksPrivateData) ?? true @@ -287,11 +287,11 @@ extension VPNManager { private extension VPNManager { private enum StoreKey: String, KeyStoreDomainLocation { case tunnelLogPath - + case tunnelLogFormat - + case masksPrivateData - + var domain: String { "Passepartout.VPNManager" } diff --git a/PassepartoutLibrary/Sources/PassepartoutVPN/Managers/VPNManagerStrategy.swift b/PassepartoutLibrary/Sources/PassepartoutVPN/Managers/VPNManagerStrategy.swift index 40737372..c56ee4f4 100644 --- a/PassepartoutLibrary/Sources/PassepartoutVPN/Managers/VPNManagerStrategy.swift +++ b/PassepartoutLibrary/Sources/PassepartoutVPN/Managers/VPNManagerStrategy.swift @@ -29,11 +29,11 @@ import PassepartoutCore public protocol VPNManagerStrategy { func observe(into state: ObservableVPNState) - + func reinstate(configuration: VPNConfiguration) async func connect(configuration: VPNConfiguration) async - + func reconnect() async func disconnect() async @@ -41,6 +41,6 @@ public protocol VPNManagerStrategy { func removeConfigurations() async func serverConfiguration(forProtocol vpnProtocol: VPNProtocolType) -> Any? - + func debugLogURL(forProtocol vpnProtocol: VPNProtocolType) -> URL? } diff --git a/PassepartoutLibrary/Sources/PassepartoutVPN/Models/ObservableVPNState.swift b/PassepartoutLibrary/Sources/PassepartoutVPN/Models/ObservableVPNState.swift index 7570f5e4..b97cf6d0 100644 --- a/PassepartoutLibrary/Sources/PassepartoutVPN/Models/ObservableVPNState.swift +++ b/PassepartoutLibrary/Sources/PassepartoutVPN/Models/ObservableVPNState.swift @@ -49,7 +49,7 @@ public class ObservableVPNState: ObservableObject { pp_log.debug("Last error: \(lastError)") } } - + @Published public internal(set) var dataCount: DataCount? { didSet { guard let dataCount = dataCount else { diff --git a/PassepartoutLibrary/Sources/PassepartoutVPN/Models/VPNConfiguration.swift b/PassepartoutLibrary/Sources/PassepartoutVPN/Models/VPNConfiguration.swift index a16ab313..c44ae2a0 100644 --- a/PassepartoutLibrary/Sources/PassepartoutVPN/Models/VPNConfiguration.swift +++ b/PassepartoutLibrary/Sources/PassepartoutVPN/Models/VPNConfiguration.swift @@ -36,9 +36,9 @@ protocol VPNConfigurationProviding { struct VPNConfigurationParameters { let title: String - + let appGroup: String - + let preferences: VPNPreferences let networkSettings: Profile.NetworkSettings @@ -46,9 +46,9 @@ struct VPNConfigurationParameters { let username: String? let passwordReference: Data? - + let withNetworkSettings: Bool - + let onDemandRules: [NEOnDemandRule] init( diff --git a/PassepartoutLibrary/Sources/PassepartoutVPN/Models/VPNPreferences.swift b/PassepartoutLibrary/Sources/PassepartoutVPN/Models/VPNPreferences.swift index b1ea5458..e570f06d 100644 --- a/PassepartoutLibrary/Sources/PassepartoutVPN/Models/VPNPreferences.swift +++ b/PassepartoutLibrary/Sources/PassepartoutVPN/Models/VPNPreferences.swift @@ -27,9 +27,9 @@ import Foundation public protocol VPNPreferences { var tunnelLogPath: String? { get } - + var tunnelLogFormat: String? { get } - + var masksPrivateData: Bool { get } } @@ -37,6 +37,6 @@ struct DefaultVPNPreferences: VPNPreferences { let tunnelLogPath: String? let tunnelLogFormat: String? - + let masksPrivateData: Bool } diff --git a/PassepartoutLibrary/Tests/PassepartoutCoreTests/CoreTests.swift b/PassepartoutLibrary/Tests/PassepartoutCoreTests/CoreTests.swift index 3b98651c..de136b26 100644 --- a/PassepartoutLibrary/Tests/PassepartoutCoreTests/CoreTests.swift +++ b/PassepartoutLibrary/Tests/PassepartoutCoreTests/CoreTests.swift @@ -29,7 +29,7 @@ import XCTest class CoreTests: XCTestCase { override func setUp() { } - + override func tearDown() { // Put teardown code here. This method is called after the invocation of each test method in the class. } diff --git a/PassepartoutLibrary/Tests/PassepartoutLibraryTests/LibraryTests.swift b/PassepartoutLibrary/Tests/PassepartoutLibraryTests/LibraryTests.swift index db598ed6..0a7897e4 100644 --- a/PassepartoutLibrary/Tests/PassepartoutLibraryTests/LibraryTests.swift +++ b/PassepartoutLibrary/Tests/PassepartoutLibraryTests/LibraryTests.swift @@ -29,7 +29,7 @@ import XCTest class LibraryTests: XCTestCase { override func setUp() { } - + override func tearDown() { // Put teardown code here. This method is called after the invocation of each test method in the class. } diff --git a/PassepartoutLibrary/Tests/PassepartoutProvidersTests/ProvidersTests.swift b/PassepartoutLibrary/Tests/PassepartoutProvidersTests/ProvidersTests.swift index dca3d604..8f3deb47 100644 --- a/PassepartoutLibrary/Tests/PassepartoutProvidersTests/ProvidersTests.swift +++ b/PassepartoutLibrary/Tests/PassepartoutProvidersTests/ProvidersTests.swift @@ -39,7 +39,7 @@ class ProvidersTests: XCTestCase { }() private var manager: ProviderManager! - + private var cancellables: Set = [] override func setUp() { @@ -140,7 +140,7 @@ class ProvidersTests: XCTestCase { pp_log.debug("\($0.fullName): Servers [\(location.countryCode)] (\(servers.count)): \(servers)") } } - + func testServerId() async { await fetchProvider(.nordvpn) guard let server = manager.server(.nordvpn, vpnProtocol: .openVPN, apiId: "es143") else { @@ -148,7 +148,7 @@ class ProvidersTests: XCTestCase { } pp_log.debug(server) } - + func testDefaultServer() async { await fetchProvider(.protonvpn) guard let server = manager.anyDefaultServer(.protonvpn, vpnProtocol: .openVPN) else { @@ -156,7 +156,7 @@ class ProvidersTests: XCTestCase { } pp_log.debug(server) } - + func testServerUniqueId() async { await fetchProvider(.nordvpn) guard let server = manager.server(withId: "BEA03D24A5854DD17395057DEFBE7D6BEEA981227ACF8949E487443E6B5EF9C7") else { @@ -165,7 +165,7 @@ class ProvidersTests: XCTestCase { pp_log.debug(server) XCTAssertEqual(server.apiId, "es143") } - + private func fetchProvider(_ name: ProviderName) async { try? await manager.fetchProvidersIndexPublisher(priority: .bundle).async() try? await manager.fetchProviderPublisher(withName: name, vpnProtocol: .openVPN, priority: .bundle).async() diff --git a/PassepartoutLibrary/Tests/PassepartoutServicesTests/ServicesTests.swift b/PassepartoutLibrary/Tests/PassepartoutServicesTests/ServicesTests.swift index 0e9923bc..1a55d2ba 100644 --- a/PassepartoutLibrary/Tests/PassepartoutServicesTests/ServicesTests.swift +++ b/PassepartoutLibrary/Tests/PassepartoutServicesTests/ServicesTests.swift @@ -33,7 +33,7 @@ class ServicesTests: XCTestCase { let wsLocal = DefaultWebServices.bundledServices(withVersion: "v5") let wsRemote = DefaultWebServices("v5", URL(string: "https://passepartoutvpn.app/api/")!, timeout: nil) - + private var cancellables: Set = [] override func setUp() { diff --git a/PassepartoutLibrary/Tests/PassepartoutUtilsTests/UtilsTests.swift b/PassepartoutLibrary/Tests/PassepartoutUtilsTests/UtilsTests.swift index 6a414a5a..6e785bdb 100644 --- a/PassepartoutLibrary/Tests/PassepartoutUtilsTests/UtilsTests.swift +++ b/PassepartoutLibrary/Tests/PassepartoutUtilsTests/UtilsTests.swift @@ -31,11 +31,11 @@ class UtilsTests: XCTestCase { override func setUp() { pp_log.addDestination(ConsoleDestination()) } - + override func tearDown() { // Put teardown code here. This method is called after the invocation of each test method in the class. } - + func testLanguageLocalization() { let languages = ["en", "it", "de", "pt-BR", "ru"] let english = Locale(identifier: "en") @@ -50,7 +50,7 @@ class UtilsTests: XCTestCase { // Inglese, Italiano, Portoghese, Russo, Tedesco XCTAssertEqual(languagesIT, ["en", "it", "pt-BR", "ru", "de"]) } - + func testTrailing() { let file = Bundle.module.url(forResource: "Debug", withExtension: "log")! @@ -63,7 +63,7 @@ class UtilsTests: XCTestCase { pp_log.debug(file.trailingLines(bytes: 1000)) } - + private func privateSortedLanguages(_ languages: [String], with locale: Locale) -> [String] { languages.sorted { locale.localizedString(forLanguageCode: $0)! < locale.localizedString(forLanguageCode: $1)! diff --git a/PassepartoutLibrary/Tests/PassepartoutVPNTests/VPNTests.swift b/PassepartoutLibrary/Tests/PassepartoutVPNTests/VPNTests.swift index cfa3f103..ec972ce5 100644 --- a/PassepartoutLibrary/Tests/PassepartoutVPNTests/VPNTests.swift +++ b/PassepartoutLibrary/Tests/PassepartoutVPNTests/VPNTests.swift @@ -29,7 +29,7 @@ import XCTest class VPNTests: XCTestCase { override func setUp() { } - + override func tearDown() { // Put teardown code here. This method is called after the invocation of each test method in the class. }