diff --git a/.gitmodules b/.gitmodules index 36ce8f46..3a539776 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ [submodule "Submodules/fastlane-ci-templates"] path = Submodules/fastlane-ci-templates url = https://github.com/keeshux/fastlane-ci-templates -[submodule "PassepartoutCore/Sources/PassepartoutServices/API"] - path = PassepartoutCore/Sources/PassepartoutServices/API +[submodule "PassepartoutLibrary/Sources/PassepartoutServices/API"] + path = PassepartoutLibrary/Sources/PassepartoutServices/API url = https://github.com/passepartoutvpn/api diff --git a/API b/API index 6a393c30..82aba07e 120000 --- a/API +++ b/API @@ -1 +1 @@ -PassepartoutCore/Sources/PassepartoutServices/API/ \ No newline at end of file +PassepartoutLibrary/Sources/PassepartoutServices/API/ \ No newline at end of file diff --git a/Passepartout.xcodeproj/project.pbxproj b/Passepartout.xcodeproj/project.pbxproj index 24b5513a..0673ede0 100644 --- a/Passepartout.xcodeproj/project.pbxproj +++ b/Passepartout.xcodeproj/project.pbxproj @@ -47,7 +47,6 @@ 0E49F6BF27D764AF00385834 /* EndpointAdvancedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E49F6BE27D764AF00385834 /* EndpointAdvancedView.swift */; }; 0E53249927D26B51002565C3 /* ProductManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E53249627D26B51002565C3 /* ProductManager.swift */; }; 0E53249D27D28FC7002565C3 /* Kvitto in Frameworks */ = {isa = PBXBuildFile; productRef = 0E53249C27D28FC7002565C3 /* Kvitto */; }; - 0E5324A627D297BB002565C3 /* InApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E5324A527D297BB002565C3 /* InApp.swift */; }; 0E5324A927D2AC55002565C3 /* LongContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E5324A827D2AC55002565C3 /* LongContentView.swift */; }; 0E5349BE27C16A4500C71BB3 /* StyledPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E5349BD27C16A4500C71BB3 /* StyledPicker.swift */; }; 0E5349C627C176C200C71BB3 /* EndpointView+OpenVPN.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E5349C527C176C200C71BB3 /* EndpointView+OpenVPN.swift */; }; @@ -98,6 +97,7 @@ 0EBC075D27EC529000208AD9 /* DebugLog+Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBC075C27EC529000208AD9 /* DebugLog+Constants.swift */; }; 0EBC076027EC587900208AD9 /* SwiftGen+Strings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBC075F27EC587900208AD9 /* SwiftGen+Strings.swift */; }; 0EBE880F281B18DE0090D9E6 /* ProfileRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBE880E281B18DE0090D9E6 /* ProfileRow.swift */; }; + 0ECB78EC2863A21600B0E460 /* PassepartoutLibrary in Frameworks */ = {isa = PBXBuildFile; productRef = 0ECB78EB2863A21600B0E460 /* PassepartoutLibrary */; }; 0ECF71EE27B6A99300CDB528 /* AccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECF71ED27B6A99300CDB528 /* AccountView.swift */; }; 0ED1D6DC27DBA41700983466 /* DiagnosticsView+OpenVPN.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ED1D6DB27DBA41700983466 /* DiagnosticsView+OpenVPN.swift */; }; 0ED1D6DE27DBA42100983466 /* DiagnosticsView+WireGuard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ED1D6DD27DBA42100983466 /* DiagnosticsView+WireGuard.swift */; }; @@ -119,7 +119,6 @@ 0EDE02C227F61C79000FBE3C /* EditableTextList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EDE02C127F61C79000FBE3C /* EditableTextList.swift */; }; 0EE11CD2280D8317003BE431 /* InfoMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE11CD1280D8317003BE431 /* InfoMenu.swift */; }; 0EE8B7E327FF340F00B68621 /* VPNProtocolType+FileExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE8B7E227FF340F00B68621 /* VPNProtocolType+FileExtensions.swift */; }; - 0EED0BB92733CEDA00C9FC68 /* PassepartoutCore in Frameworks */ = {isa = PBXBuildFile; productRef = 0EED0BB82733CEDA00C9FC68 /* PassepartoutCore */; }; 0EF0FAF627DD0211007EB181 /* PaywallView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF0FAF527DD0211007EB181 /* PaywallView.swift */; }; 0EF0FAF727DD159C007EB181 /* IntentDispatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA591122733DD4E0096F796 /* IntentDispatcher.swift */; }; 0EF0FAF927DD212C007EB181 /* IntentActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF0FAF827DD212C007EB181 /* IntentActivity.swift */; }; @@ -131,13 +130,6 @@ /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - 0E6059C627FCC33D003F4063 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 0E57F63020C83FC5008323CF /* Project object */; - proxyType = 1; - remoteGlobalIDString = 0E9AAA60259F7D7E003FAFF1; - remoteInfo = "PassepartoutLauncher-macOS"; - }; 0EB2B1492733FB6F007705AB /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0E57F63020C83FC5008323CF /* Project object */; @@ -236,7 +228,6 @@ 0E49F6BC27D7639000385834 /* EndpointAdvancedView+WireGuard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EndpointAdvancedView+WireGuard.swift"; sourceTree = ""; }; 0E49F6BE27D764AF00385834 /* EndpointAdvancedView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EndpointAdvancedView.swift; sourceTree = ""; }; 0E53249627D26B51002565C3 /* ProductManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProductManager.swift; sourceTree = ""; }; - 0E5324A527D297BB002565C3 /* InApp.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InApp.swift; sourceTree = ""; }; 0E5324A827D2AC55002565C3 /* LongContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LongContentView.swift; sourceTree = ""; }; 0E5349BD27C16A4500C71BB3 /* StyledPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StyledPicker.swift; sourceTree = ""; }; 0E5349C527C176C200C71BB3 /* EndpointView+OpenVPN.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EndpointView+OpenVPN.swift"; sourceTree = ""; }; @@ -282,7 +273,6 @@ 0E9E5AED27B44CF1008C95DA /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = ""; }; 0E9E5AEE27B44CF1008C95DA /* pt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pt; path = pt.lproj/Localizable.strings; sourceTree = ""; }; 0E9ED48027FD9BAE003B2316 /* CopySavingButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CopySavingButton.swift; sourceTree = ""; }; - 0EA26DC827353020000F251A /* PassepartoutCore */ = {isa = PBXFileReference; lastKnownFileType = folder; path = PassepartoutCore; sourceTree = ""; }; 0EA591122733DD4E0096F796 /* IntentDispatcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IntentDispatcher.swift; sourceTree = ""; }; 0EA591152733DDDA0096F796 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.intentdefinition; name = Base; path = Base.lproj/Intents.intentdefinition; sourceTree = ""; }; 0EA591182733DDF60096F796 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Intents.strings; sourceTree = ""; }; @@ -321,6 +311,7 @@ 0EBE2FD72360F89600F0D5AB /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/InfoPlist.strings; sourceTree = ""; }; 0EBE2FD82360F89600F0D5AB /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/InfoPlist.strings; sourceTree = ""; }; 0EBE880E281B18DE0090D9E6 /* ProfileRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileRow.swift; sourceTree = ""; }; + 0ECB78EA2861D1F300B0E460 /* PassepartoutLibrary */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = PassepartoutLibrary; sourceTree = ""; }; 0ECF71ED27B6A99300CDB528 /* AccountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountView.swift; sourceTree = ""; }; 0ED1D6DB27DBA41700983466 /* DiagnosticsView+OpenVPN.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DiagnosticsView+OpenVPN.swift"; sourceTree = ""; }; 0ED1D6DD27DBA42100983466 /* DiagnosticsView+WireGuard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DiagnosticsView+WireGuard.swift"; sourceTree = ""; }; @@ -358,8 +349,8 @@ buildActionMask = 2147483647; files = ( 0E9C3B6F27FC573E00D0F02E /* CloudKit.framework in Frameworks */, - 0EED0BB92733CEDA00C9FC68 /* PassepartoutCore in Frameworks */, 0E53249D27D28FC7002565C3 /* Kvitto in Frameworks */, + 0ECB78EC2863A21600B0E460 /* PassepartoutLibrary in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -602,7 +593,6 @@ 0E293859285A7489002A6E0E /* Context */, 0E92781227E7CD530057BB81 /* InApp */, 0E34A2B827CAA8EA00C73B67 /* L10n */, - 0ECB78D5285F508B00B0E460 /* Reusable */, 0E9E5AE227B44CF1008C95DA /* Localizable.strings */, ); path = AppShared; @@ -626,14 +616,6 @@ path = Constants; sourceTree = ""; }; - 0ECB78D5285F508B00B0E460 /* Reusable */ = { - isa = PBXGroup; - children = ( - 0E5324A527D297BB002565C3 /* InApp.swift */, - ); - path = Reusable; - sourceTree = ""; - }; 0ED2B33C27D3C52900FD8EA9 /* OpenVPN */ = { isa = PBXGroup; children = ( @@ -673,7 +655,7 @@ 0EE315DB2733104700F5D461 /* Packages */ = { isa = PBXGroup; children = ( - 0EA26DC827353020000F251A /* PassepartoutCore */, + 0ECB78EA2861D1F300B0E460 /* PassepartoutLibrary */, ); name = Packages; sourceTree = ""; @@ -726,12 +708,11 @@ 0ECF71FC27B6DA6700CDB528 /* PBXTargetDependency */, 0EB2B14A2733FB6F007705AB /* PBXTargetDependency */, 0ED2B36227D3C99100FD8EA9 /* PBXTargetDependency */, - 0E6059C727FCC33D003F4063 /* PBXTargetDependency */, ); name = Passepartout; packageProductDependencies = ( - 0EED0BB82733CEDA00C9FC68 /* PassepartoutCore */, 0E53249C27D28FC7002565C3 /* Kvitto */, + 0ECB78EB2863A21600B0E460 /* PassepartoutLibrary */, ); productName = Passepartout; productReference = 0E57F63820C83FC5008323CF /* Passepartout.app */; @@ -944,7 +925,6 @@ 0EF2213127E674BD001D0BD7 /* AddProviderViewModel.swift in Sources */, 0E90DFE627BACC1500EF5078 /* AddHostViewModel.swift in Sources */, 0E34AC8227F892C40042F2AB /* OnDemandView+SSID.swift in Sources */, - 0E5324A627D297BB002565C3 /* InApp.swift in Sources */, 0E3B7FCD27E47B3700C66F13 /* AddHostView+Name.swift in Sources */, 0E7577D72816A3B200081CBE /* DestructiveButton.swift in Sources */, 0EF2212D27E66EB5001D0BD7 /* AddProviderView.swift in Sources */, @@ -1059,11 +1039,6 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ - 0E6059C727FCC33D003F4063 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - platformFilter = ios; - targetProxy = 0E6059C627FCC33D003F4063 /* PBXContainerItemProxy */; - }; 0EB2B14A2733FB6F007705AB /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 0EDE8DBE20C86910004C739C /* OpenVPNTunnel */; @@ -1509,6 +1484,10 @@ package = 0E53249B27D28FC7002565C3 /* XCRemoteSwiftPackageReference "Kvitto" */; productName = Kvitto; }; + 0ECB78EB2863A21600B0E460 /* PassepartoutLibrary */ = { + isa = XCSwiftPackageProductDependency; + productName = PassepartoutLibrary; + }; 0ED2B33827D3C49800FD8EA9 /* OpenVPNAppExtension */ = { isa = XCSwiftPackageProductDependency; productName = OpenVPNAppExtension; @@ -1517,10 +1496,6 @@ isa = XCSwiftPackageProductDependency; productName = WireGuardAppExtension; }; - 0EED0BB82733CEDA00C9FC68 /* PassepartoutCore */ = { - isa = XCSwiftPackageProductDependency; - productName = PassepartoutCore; - }; /* End XCSwiftPackageProductDependency section */ }; rootObject = 0E57F63020C83FC5008323CF /* Project object */; diff --git a/Passepartout/App/Constants/Theme.swift b/Passepartout/App/Constants/Theme.swift index ec5f1ca7..3088b0ec 100644 --- a/Passepartout/App/Constants/Theme.swift +++ b/Passepartout/App/Constants/Theme.swift @@ -24,7 +24,7 @@ // import SwiftUI -import PassepartoutCore +import PassepartoutLibrary extension View { var themeIdiom: UIUserInterfaceIdiom { diff --git a/Passepartout/App/Context/AppContext.swift b/Passepartout/App/Context/AppContext.swift index 0d56977c..bd10a951 100644 --- a/Passepartout/App/Context/AppContext.swift +++ b/Passepartout/App/Context/AppContext.swift @@ -25,9 +25,8 @@ import Foundation import Combine -import PassepartoutCore +import PassepartoutLibrary -@MainActor class AppContext { private let logManager: LogManager diff --git a/Passepartout/App/Context/AppPreference.swift b/Passepartout/App/Context/AppPreference.swift index 5dbcf2d4..647c4bcf 100644 --- a/Passepartout/App/Context/AppPreference.swift +++ b/Passepartout/App/Context/AppPreference.swift @@ -24,7 +24,7 @@ // import Foundation -import PassepartoutUtils +import PassepartoutLibrary enum AppPreference: String, KeyStoreDomainLocation { case isShowingFavorites diff --git a/Passepartout/App/Extensions/DebugLog+Constants.swift b/Passepartout/App/Extensions/DebugLog+Constants.swift index d67291e3..55173fce 100644 --- a/Passepartout/App/Extensions/DebugLog+Constants.swift +++ b/Passepartout/App/Extensions/DebugLog+Constants.swift @@ -24,7 +24,7 @@ // import Foundation -import PassepartoutCore +import PassepartoutLibrary extension DebugLog { func decoratedString() -> String { diff --git a/Passepartout/App/Extensions/PassepartoutProviders+Extensions.swift b/Passepartout/App/Extensions/PassepartoutProviders+Extensions.swift index 49890e3d..3da2c1e8 100644 --- a/Passepartout/App/Extensions/PassepartoutProviders+Extensions.swift +++ b/Passepartout/App/Extensions/PassepartoutProviders+Extensions.swift @@ -24,7 +24,7 @@ // import Foundation -import PassepartoutCore +import PassepartoutLibrary extension ProviderMetadata: Identifiable, Comparable, Hashable { public var id: String { diff --git a/Passepartout/App/Extensions/ProviderProfileAvailability.swift b/Passepartout/App/Extensions/ProviderProfileAvailability.swift index 5b16955c..4e278364 100644 --- a/Passepartout/App/Extensions/ProviderProfileAvailability.swift +++ b/Passepartout/App/Extensions/ProviderProfileAvailability.swift @@ -24,17 +24,15 @@ // import Foundation -import PassepartoutCore +import PassepartoutLibrary protocol ProviderProfileAvailability { var profile: Profile { get } - var providerManager: ProviderManager { get } + var providerManager: Impl.ProviderManager { get } } extension ProviderProfileAvailability { - - @MainActor var isProviderProfileAvailable: Bool { guard !profile.isPlaceholder else { return false diff --git a/Passepartout/App/Extensions/VPNProtocolType+FileExtensions.swift b/Passepartout/App/Extensions/VPNProtocolType+FileExtensions.swift index ec40def1..93066e80 100644 --- a/Passepartout/App/Extensions/VPNProtocolType+FileExtensions.swift +++ b/Passepartout/App/Extensions/VPNProtocolType+FileExtensions.swift @@ -24,7 +24,7 @@ // import Foundation -import PassepartoutCore +import PassepartoutLibrary extension VPNProtocolType { static let knownFileExtensions: [String] = { diff --git a/Passepartout/App/Intents/IntentDispatcher+Activities.swift b/Passepartout/App/Intents/IntentDispatcher+Activities.swift index 209603bd..940a65cc 100644 --- a/Passepartout/App/Intents/IntentDispatcher+Activities.swift +++ b/Passepartout/App/Intents/IntentDispatcher+Activities.swift @@ -25,9 +25,8 @@ import Foundation import Intents -import PassepartoutCore +import PassepartoutLibrary -@MainActor extension IntentDispatcher { private enum IntentError: Error { case notProvider(UUID) diff --git a/Passepartout/App/Intents/IntentDispatcher.swift b/Passepartout/App/Intents/IntentDispatcher.swift index 52101a0d..76041110 100644 --- a/Passepartout/App/Intents/IntentDispatcher.swift +++ b/Passepartout/App/Intents/IntentDispatcher.swift @@ -25,7 +25,7 @@ import Foundation import Intents -import PassepartoutCore +import PassepartoutLibrary class IntentDispatcher { private struct Groups { @@ -78,7 +78,6 @@ class IntentDispatcher { // MARK: Donations - @MainActor static func donateConnection(with profile: Profile, providerManager: ProviderManager) { let genericIntent: INIntent if let providerName = profile.header.providerName { diff --git a/Passepartout/App/Intents/IntentsManager.swift b/Passepartout/App/Intents/IntentsManager.swift index bb5a2112..15387c85 100644 --- a/Passepartout/App/Intents/IntentsManager.swift +++ b/Passepartout/App/Intents/IntentsManager.swift @@ -28,7 +28,6 @@ import Intents import IntentsUI import Combine -@MainActor class IntentsManager: NSObject, ObservableObject { @Published private(set) var isReloadingShortcuts = false @@ -36,7 +35,6 @@ class IntentsManager: NSObject, ObservableObject { let shouldDismissIntentView = PassthroughSubject() - @MainActor override init() { super.init() reloadShortcuts() diff --git a/Passepartout/App/PassepartoutApp.swift b/Passepartout/App/PassepartoutApp.swift index b1cbf54e..e1c01216 100644 --- a/Passepartout/App/PassepartoutApp.swift +++ b/Passepartout/App/PassepartoutApp.swift @@ -24,7 +24,7 @@ // import SwiftUI -import PassepartoutCore +import PassepartoutLibrary @main struct PassepartoutApp: App { @@ -45,8 +45,6 @@ struct PassepartoutApp: App { } extension View { - - @MainActor fileprivate func onIntentActivity(_ activity: IntentActivity) -> some View { onContinueUserActivity(activity.name) { userActivity in diff --git a/Passepartout/App/Reusable/Reviewer.swift b/Passepartout/App/Reusable/Reviewer.swift index f02a5604..929a157c 100644 --- a/Passepartout/App/Reusable/Reviewer.swift +++ b/Passepartout/App/Reusable/Reviewer.swift @@ -26,7 +26,6 @@ import UIKit import StoreKit -@MainActor public class Reviewer: ObservableObject { private struct Keys { static let eventCount = "Reviewer.EventCount" diff --git a/Passepartout/App/Views/AccountView.swift b/Passepartout/App/Views/AccountView.swift index 4e6e0b53..5bff80fb 100644 --- a/Passepartout/App/Views/AccountView.swift +++ b/Passepartout/App/Views/AccountView.swift @@ -24,10 +24,10 @@ // import SwiftUI -import PassepartoutCore +import PassepartoutLibrary struct AccountView: View { - @ObservedObject private var providerManager: ProviderManager + @ObservedObject private var providerManager: Impl.ProviderManager private let providerName: ProviderName? diff --git a/Passepartout/App/Views/AddHostView+Name.swift b/Passepartout/App/Views/AddHostView+Name.swift index ab317fef..c5deec1f 100644 --- a/Passepartout/App/Views/AddHostView+Name.swift +++ b/Passepartout/App/Views/AddHostView+Name.swift @@ -24,13 +24,13 @@ // import SwiftUI -import PassepartoutCore +import PassepartoutLibrary import TunnelKitOpenVPN import TunnelKitWireGuard extension AddHostView { struct NameView: View { - @ObservedObject private var profileManager: ProfileManager + @ObservedObject private var profileManager: Impl.ProfileManager private let url: URL diff --git a/Passepartout/App/Views/AddHostViewModel.swift b/Passepartout/App/Views/AddHostViewModel.swift index 0b6ca65e..4348a580 100644 --- a/Passepartout/App/Views/AddHostViewModel.swift +++ b/Passepartout/App/Views/AddHostViewModel.swift @@ -24,7 +24,7 @@ // import Foundation -import PassepartoutCore +import PassepartoutLibrary import TunnelKitOpenVPN import TunnelKitWireGuard @@ -52,7 +52,6 @@ extension AddHostView { profileName = url.normalizedFilename } - @MainActor mutating func processURL( _ url: URL, with profileManager: ProfileManager, @@ -97,7 +96,6 @@ extension AddHostView { } } - @MainActor mutating func addProcessedProfile(to profileManager: ProfileManager) -> Bool { guard !processedProfile.isPlaceholder else { assertionFailure("Saving profile without processing first?") diff --git a/Passepartout/App/Views/AddProfileMenu.swift b/Passepartout/App/Views/AddProfileMenu.swift index 0e62eac8..59a472a3 100644 --- a/Passepartout/App/Views/AddProfileMenu.swift +++ b/Passepartout/App/Views/AddProfileMenu.swift @@ -24,7 +24,7 @@ // import SwiftUI -import PassepartoutCore +import PassepartoutLibrary struct AddProfileMenu: View { enum ModalType: Identifiable { diff --git a/Passepartout/App/Views/AddProfileView.swift b/Passepartout/App/Views/AddProfileView.swift index 3822200d..1afd3db2 100644 --- a/Passepartout/App/Views/AddProfileView.swift +++ b/Passepartout/App/Views/AddProfileView.swift @@ -24,7 +24,7 @@ // import SwiftUI -import PassepartoutCore +import PassepartoutLibrary enum AddProfileView { struct Bindings { @@ -71,7 +71,7 @@ enum AddProfileView { } struct AccountWrapperView: View { - @ObservedObject private var profileManager: ProfileManager + @ObservedObject private var profileManager: Impl.ProfileManager @Binding private var profile: Profile diff --git a/Passepartout/App/Views/AddProviderView+Name.swift b/Passepartout/App/Views/AddProviderView+Name.swift index c35daa59..af4c1359 100644 --- a/Passepartout/App/Views/AddProviderView+Name.swift +++ b/Passepartout/App/Views/AddProviderView+Name.swift @@ -24,11 +24,11 @@ // import SwiftUI -import PassepartoutCore +import PassepartoutLibrary extension AddProviderView { struct NameView: View { - @ObservedObject private var profileManager: ProfileManager + @ObservedObject private var profileManager: Impl.ProfileManager @Binding private var profile: Profile diff --git a/Passepartout/App/Views/AddProviderView.swift b/Passepartout/App/Views/AddProviderView.swift index c57bad99..0ea18efa 100644 --- a/Passepartout/App/Views/AddProviderView.swift +++ b/Passepartout/App/Views/AddProviderView.swift @@ -24,10 +24,10 @@ // import SwiftUI -import PassepartoutCore +import PassepartoutLibrary struct AddProviderView: View { - @ObservedObject private var providerManager: ProviderManager + @ObservedObject private var providerManager: Impl.ProviderManager @ObservedObject private var productManager: ProductManager @@ -112,7 +112,7 @@ struct AddProviderView: View { Button { presentOrPurchaseProvider(metadata) } label: { - Label(metadata.description, image: themeAssetsProviderImage(metadata.name)) + Label(metadata.fullName, image: themeAssetsProviderImage(metadata.name)) }.withTrailingProgress(when: viewModel.isFetchingProvider(metadata.name)) } diff --git a/Passepartout/App/Views/AddProviderViewModel.swift b/Passepartout/App/Views/AddProviderViewModel.swift index bc8e4b23..848b9e74 100644 --- a/Passepartout/App/Views/AddProviderViewModel.swift +++ b/Passepartout/App/Views/AddProviderViewModel.swift @@ -24,7 +24,7 @@ // import Foundation -import PassepartoutCore +import PassepartoutLibrary extension AddProviderView { class ViewModel: ObservableObject { @@ -67,7 +67,6 @@ extension AddProviderView { @Published private(set) var errorMessage: String? - @MainActor func selectProvider(_ metadata: ProviderMetadata, _ providerManager: ProviderManager) { errorMessage = nil guard let server = providerManager.anyDefaultServer( @@ -82,7 +81,6 @@ extension AddProviderView { doSelectProvider(metadata, server) } - @MainActor private func selectProviderAfterFetchingInfrastructure(_ metadata: ProviderMetadata, _ providerManager: ProviderManager) async { errorMessage = nil pendingOperation = .provider(metadata.name) @@ -114,7 +112,6 @@ extension AddProviderView { selectedProvider = metadata } - @MainActor func updateIndex(_ providerManager: ProviderManager) { errorMessage = nil pendingOperation = .index @@ -154,7 +151,6 @@ extension AddProviderView.NameView { profileName = metadata.fullName } - @MainActor mutating func addProfile( _ profile: Profile, to profileManager: ProfileManager, diff --git a/Passepartout/App/Views/DebugLogView.swift b/Passepartout/App/Views/DebugLogView.swift index 29677528..ecda6acb 100644 --- a/Passepartout/App/Views/DebugLogView.swift +++ b/Passepartout/App/Views/DebugLogView.swift @@ -25,7 +25,7 @@ import SwiftUI import Combine -import PassepartoutCore +import PassepartoutLibrary struct DebugLogView: View { private let url: URL diff --git a/Passepartout/App/Views/DiagnosticsView+OpenVPN.swift b/Passepartout/App/Views/DiagnosticsView+OpenVPN.swift index 39356a9e..cd8cb484 100644 --- a/Passepartout/App/Views/DiagnosticsView+OpenVPN.swift +++ b/Passepartout/App/Views/DiagnosticsView+OpenVPN.swift @@ -24,7 +24,7 @@ // import SwiftUI -import PassepartoutCore +import PassepartoutLibrary import TunnelKitOpenVPN extension DiagnosticsView { @@ -37,11 +37,11 @@ extension DiagnosticsView { } } - @ObservedObject private var providerManager: ProviderManager + @ObservedObject private var providerManager: Impl.ProviderManager - @ObservedObject private var vpnManager: VPNManager + @ObservedObject private var vpnManager: Impl.VPNManager - @ObservedObject private var currentVPNState: VPNManager.ObservableState + @ObservedObject private var currentVPNState: ObservableVPNState @ObservedObject private var productManager: ProductManager diff --git a/Passepartout/App/Views/DiagnosticsView+WireGuard.swift b/Passepartout/App/Views/DiagnosticsView+WireGuard.swift index 8a970371..6c8d0814 100644 --- a/Passepartout/App/Views/DiagnosticsView+WireGuard.swift +++ b/Passepartout/App/Views/DiagnosticsView+WireGuard.swift @@ -24,12 +24,12 @@ // import SwiftUI -import PassepartoutCore +import PassepartoutLibrary import TunnelKitWireGuard extension DiagnosticsView { struct WireGuardView: View { - @ObservedObject private var vpnManager: VPNManager + @ObservedObject private var vpnManager: Impl.VPNManager private let providerName: ProviderName? diff --git a/Passepartout/App/Views/DiagnosticsView.swift b/Passepartout/App/Views/DiagnosticsView.swift index 62815f44..11faa441 100644 --- a/Passepartout/App/Views/DiagnosticsView.swift +++ b/Passepartout/App/Views/DiagnosticsView.swift @@ -24,7 +24,7 @@ // import SwiftUI -import PassepartoutCore +import PassepartoutLibrary struct DiagnosticsView: View { let vpnProtocol: VPNProtocolType diff --git a/Passepartout/App/Views/DonateView.swift b/Passepartout/App/Views/DonateView.swift index c7c57d5b..13ce1b60 100644 --- a/Passepartout/App/Views/DonateView.swift +++ b/Passepartout/App/Views/DonateView.swift @@ -25,6 +25,7 @@ import SwiftUI import StoreKit +import PassepartoutLibrary struct DonateView: View { enum AlertType: Identifiable { diff --git a/Passepartout/App/Views/EndpointAdvancedView+OpenVPN.swift b/Passepartout/App/Views/EndpointAdvancedView+OpenVPN.swift index 81796750..e1bdbbd9 100644 --- a/Passepartout/App/Views/EndpointAdvancedView+OpenVPN.swift +++ b/Passepartout/App/Views/EndpointAdvancedView+OpenVPN.swift @@ -25,7 +25,7 @@ import SwiftUI import TunnelKitOpenVPN -import PassepartoutCore +import PassepartoutLibrary extension EndpointAdvancedView { struct OpenVPNView: View { diff --git a/Passepartout/App/Views/EndpointView+OpenVPN.swift b/Passepartout/App/Views/EndpointView+OpenVPN.swift index d4266300..0f98a21a 100644 --- a/Passepartout/App/Views/EndpointView+OpenVPN.swift +++ b/Passepartout/App/Views/EndpointView+OpenVPN.swift @@ -24,14 +24,14 @@ // import SwiftUI -import PassepartoutCore +import PassepartoutLibrary import TunnelKitOpenVPN extension EndpointView { struct OpenVPNView: View { @Environment(\.presentationMode) private var presentationMode - @ObservedObject private var providerManager: ProviderManager + @ObservedObject private var providerManager: Impl.ProviderManager @ObservedObject private var currentProfile: ObservableProfile @@ -53,7 +53,7 @@ extension EndpointView { // XXX: do not escape mutating 'self', use constant providerManager init(currentProfile: ObservableProfile) { - let providerManager: ProviderManager = .shared + let providerManager: Impl.ProviderManager = .shared self.providerManager = providerManager self.currentProfile = currentProfile diff --git a/Passepartout/App/Views/EndpointView+WireGuard.swift b/Passepartout/App/Views/EndpointView+WireGuard.swift index abc22803..38b50547 100644 --- a/Passepartout/App/Views/EndpointView+WireGuard.swift +++ b/Passepartout/App/Views/EndpointView+WireGuard.swift @@ -24,12 +24,12 @@ // import SwiftUI -import PassepartoutCore +import PassepartoutLibrary import TunnelKitWireGuard extension EndpointView { struct WireGuardView: View { - @ObservedObject private var providerManager: ProviderManager + @ObservedObject private var providerManager: Impl.ProviderManager @ObservedObject private var currentProfile: ObservableProfile @@ -41,7 +41,7 @@ extension EndpointView { // XXX: do not escape mutating 'self', use constant providerManager init(currentProfile: ObservableProfile, isReadonly: Bool) { - let providerManager: ProviderManager = .shared + let providerManager: Impl.ProviderManager = .shared self.providerManager = providerManager self.currentProfile = currentProfile diff --git a/Passepartout/App/Views/EndpointView.swift b/Passepartout/App/Views/EndpointView.swift index 8ef55893..787541e1 100644 --- a/Passepartout/App/Views/EndpointView.swift +++ b/Passepartout/App/Views/EndpointView.swift @@ -24,7 +24,7 @@ // import SwiftUI -import PassepartoutCore +import PassepartoutLibrary struct EndpointView: View { @ObservedObject private var currentProfile: ObservableProfile diff --git a/Passepartout/App/Views/InfoMenu.swift b/Passepartout/App/Views/InfoMenu.swift index 4cccb5e8..4ee98fcd 100644 --- a/Passepartout/App/Views/InfoMenu.swift +++ b/Passepartout/App/Views/InfoMenu.swift @@ -24,7 +24,7 @@ // import SwiftUI -import PassepartoutCore +import PassepartoutLibrary struct InfoMenu: View { enum ModalType: Identifiable { diff --git a/Passepartout/App/Views/NetworkSettingsView.swift b/Passepartout/App/Views/NetworkSettingsView.swift index 2a026d49..7c608c58 100644 --- a/Passepartout/App/Views/NetworkSettingsView.swift +++ b/Passepartout/App/Views/NetworkSettingsView.swift @@ -24,7 +24,7 @@ // import SwiftUI -import PassepartoutCore +import PassepartoutLibrary struct NetworkSettingsView: View { @ObservedObject private var currentProfile: ObservableProfile diff --git a/Passepartout/App/Views/OnDemandView+SSID.swift b/Passepartout/App/Views/OnDemandView+SSID.swift index d37ed04b..13734661 100644 --- a/Passepartout/App/Views/OnDemandView+SSID.swift +++ b/Passepartout/App/Views/OnDemandView+SSID.swift @@ -24,7 +24,7 @@ // import SwiftUI -import PassepartoutCore +import PassepartoutLibrary extension OnDemandView { struct SSIDList: View { diff --git a/Passepartout/App/Views/OnDemandView.swift b/Passepartout/App/Views/OnDemandView.swift index 1df94afe..f8ac3ceb 100644 --- a/Passepartout/App/Views/OnDemandView.swift +++ b/Passepartout/App/Views/OnDemandView.swift @@ -24,7 +24,7 @@ // import SwiftUI -import PassepartoutCore +import PassepartoutLibrary struct OnDemandView: View { @ObservedObject private var productManager: ProductManager diff --git a/Passepartout/App/Views/OrganizerView+Profiles.swift b/Passepartout/App/Views/OrganizerView+Profiles.swift index 9dc32bc4..aca53552 100644 --- a/Passepartout/App/Views/OrganizerView+Profiles.swift +++ b/Passepartout/App/Views/OrganizerView+Profiles.swift @@ -24,11 +24,11 @@ // import SwiftUI -import PassepartoutCore +import PassepartoutLibrary extension OrganizerView { struct ProfilesList: View { - @ObservedObject private var profileManager: ProfileManager + @ObservedObject private var profileManager: Impl.ProfileManager init() { profileManager = .shared diff --git a/Passepartout/App/Views/OrganizerView+Scene.swift b/Passepartout/App/Views/OrganizerView+Scene.swift index 5016c5ac..392032f4 100644 --- a/Passepartout/App/Views/OrganizerView+Scene.swift +++ b/Passepartout/App/Views/OrganizerView+Scene.swift @@ -24,15 +24,15 @@ // import SwiftUI -import PassepartoutCore +import PassepartoutLibrary extension OrganizerView { struct SceneView: View { @Environment(\.scenePhase) private var scenePhase - @ObservedObject private var profileManager: ProfileManager + @ObservedObject private var profileManager: Impl.ProfileManager - @ObservedObject private var vpnManager: VPNManager + @ObservedObject private var vpnManager: Impl.VPNManager @ObservedObject private var productManager: ProductManager diff --git a/Passepartout/App/Views/OrganizerView.swift b/Passepartout/App/Views/OrganizerView.swift index d204f5d4..2e133877 100644 --- a/Passepartout/App/Views/OrganizerView.swift +++ b/Passepartout/App/Views/OrganizerView.swift @@ -24,7 +24,7 @@ // import SwiftUI -import PassepartoutCore +import PassepartoutLibrary struct OrganizerView: View { enum AlertType: Identifiable { @@ -81,7 +81,7 @@ struct OrganizerView: View { .themePrimaryView() // VPN configuration error publisher (no need to observe VPNManager) - .onReceive(VPNManager.shared.configurationError) { + .onReceive(Impl.VPNManager.shared.configurationError) { alertType = .error($0.profile.header.name, $0.error.localizedAppDescription) } } diff --git a/Passepartout/App/Views/PaywallView+Purchase.swift b/Passepartout/App/Views/PaywallView+Purchase.swift index 839f514d..d631c032 100644 --- a/Passepartout/App/Views/PaywallView+Purchase.swift +++ b/Passepartout/App/Views/PaywallView+Purchase.swift @@ -25,7 +25,7 @@ import SwiftUI import StoreKit -import PassepartoutCore +import PassepartoutLibrary extension PaywallView { struct PurchaseView: View { diff --git a/Passepartout/App/Views/ProfileRow.swift b/Passepartout/App/Views/ProfileRow.swift index 7625e7ea..2ee187d2 100644 --- a/Passepartout/App/Views/ProfileRow.swift +++ b/Passepartout/App/Views/ProfileRow.swift @@ -24,7 +24,7 @@ // import SwiftUI -import PassepartoutCore +import PassepartoutLibrary struct ProfileRow: View { let header: Profile.Header diff --git a/Passepartout/App/Views/ProfileView+Configuration.swift b/Passepartout/App/Views/ProfileView+Configuration.swift index a886a980..70c9bc70 100644 --- a/Passepartout/App/Views/ProfileView+Configuration.swift +++ b/Passepartout/App/Views/ProfileView+Configuration.swift @@ -24,7 +24,7 @@ // import SwiftUI -import PassepartoutCore +import PassepartoutLibrary extension ProfileView { struct ConfigurationSection: View { diff --git a/Passepartout/App/Views/ProfileView+Diagnostics.swift b/Passepartout/App/Views/ProfileView+Diagnostics.swift index cd2597fc..7b086423 100644 --- a/Passepartout/App/Views/ProfileView+Diagnostics.swift +++ b/Passepartout/App/Views/ProfileView+Diagnostics.swift @@ -24,11 +24,11 @@ // import SwiftUI -import PassepartoutCore +import PassepartoutLibrary extension ProfileView { struct DiagnosticsSection: View { - @ObservedObject private var profileManager: ProfileManager + @ObservedObject private var profileManager: Impl.ProfileManager @ObservedObject private var currentProfile: ObservableProfile diff --git a/Passepartout/App/Views/ProfileView+Extra.swift b/Passepartout/App/Views/ProfileView+Extra.swift index ef9a67d5..c97f19a0 100644 --- a/Passepartout/App/Views/ProfileView+Extra.swift +++ b/Passepartout/App/Views/ProfileView+Extra.swift @@ -24,7 +24,7 @@ // import SwiftUI -import PassepartoutCore +import PassepartoutLibrary extension ProfileView { struct ExtraSection: View { diff --git a/Passepartout/App/Views/ProfileView+MainMenu.swift b/Passepartout/App/Views/ProfileView+MainMenu.swift index bc28bddd..aa61efd0 100644 --- a/Passepartout/App/Views/ProfileView+MainMenu.swift +++ b/Passepartout/App/Views/ProfileView+MainMenu.swift @@ -24,7 +24,7 @@ // import SwiftUI -import PassepartoutCore +import PassepartoutLibrary extension ProfileView { struct MainMenu: View { @@ -38,9 +38,9 @@ extension ProfileView { } } - @ObservedObject private var profileManager: ProfileManager + @ObservedObject private var profileManager: Impl.ProfileManager - @ObservedObject private var vpnManager: VPNManager + @ObservedObject private var vpnManager: Impl.VPNManager @ObservedObject private var currentProfile: ObservableProfile @@ -200,7 +200,7 @@ extension ProfileView { } struct DuplicateButton: View { - @ObservedObject private var profileManager: ProfileManager + @ObservedObject private var profileManager: Impl.ProfileManager private let header: Profile.Header diff --git a/Passepartout/App/Views/ProfileView+Provider.swift b/Passepartout/App/Views/ProfileView+Provider.swift index af620d6b..ee74e296 100644 --- a/Passepartout/App/Views/ProfileView+Provider.swift +++ b/Passepartout/App/Views/ProfileView+Provider.swift @@ -24,11 +24,11 @@ // import SwiftUI -import PassepartoutCore +import PassepartoutLibrary extension ProfileView { struct ProviderSection: View, ProviderProfileAvailability { - @ObservedObject var providerManager: ProviderManager + @ObservedObject var providerManager: Impl.ProviderManager @ObservedObject private var currentProfile: ObservableProfile diff --git a/Passepartout/App/Views/ProfileView+Rename.swift b/Passepartout/App/Views/ProfileView+Rename.swift index 8300b693..65873078 100644 --- a/Passepartout/App/Views/ProfileView+Rename.swift +++ b/Passepartout/App/Views/ProfileView+Rename.swift @@ -24,13 +24,13 @@ // import SwiftUI -import PassepartoutCore +import PassepartoutLibrary extension ProfileView { struct RenameView: View { @Environment(\.presentationMode) private var presentationMode - @ObservedObject private var profileManager: ProfileManager + @ObservedObject private var profileManager: Impl.ProfileManager @ObservedObject private var currentProfile: ObservableProfile diff --git a/Passepartout/App/Views/ProfileView+VPN.swift b/Passepartout/App/Views/ProfileView+VPN.swift index 20680d66..e354e28e 100644 --- a/Passepartout/App/Views/ProfileView+VPN.swift +++ b/Passepartout/App/Views/ProfileView+VPN.swift @@ -24,11 +24,11 @@ // import SwiftUI -import PassepartoutCore +import PassepartoutLibrary extension ProfileView { struct VPNSection: View { - @ObservedObject private var profileManager: ProfileManager + @ObservedObject private var profileManager: Impl.ProfileManager private let profileId: UUID diff --git a/Passepartout/App/Views/ProfileView.swift b/Passepartout/App/Views/ProfileView.swift index e538d1d5..cf1dcd05 100644 --- a/Passepartout/App/Views/ProfileView.swift +++ b/Passepartout/App/Views/ProfileView.swift @@ -24,7 +24,7 @@ // import SwiftUI -import PassepartoutCore +import PassepartoutLibrary struct ProfileView: View { enum ModalType: Int, Identifiable { @@ -56,7 +56,7 @@ struct ProfileView: View { @State private var modalType: ModalType? init() { - currentProfile = ProfileManager.shared.currentProfile + currentProfile = Impl.ProfileManager.shared.currentProfile } var body: some View { diff --git a/Passepartout/App/Views/ProviderLocationView.swift b/Passepartout/App/Views/ProviderLocationView.swift index 29da3ef1..c613fd1c 100644 --- a/Passepartout/App/Views/ProviderLocationView.swift +++ b/Passepartout/App/Views/ProviderLocationView.swift @@ -24,10 +24,10 @@ // import SwiftUI -import PassepartoutCore +import PassepartoutLibrary struct ProviderLocationView: View, ProviderProfileAvailability { - @ObservedObject var providerManager: ProviderManager + @ObservedObject var providerManager: Impl.ProviderManager @ObservedObject private var currentProfile: ObservableProfile @@ -64,7 +64,7 @@ struct ProviderLocationView: View, ProviderProfileAvailability { // XXX: do not escape mutating 'self', use constant providerManager init(currentProfile: ObservableProfile, isEditable: Bool, isPresented: Binding) { - let providerManager: ProviderManager = .shared + let providerManager: Impl.ProviderManager = .shared self.providerManager = providerManager self.currentProfile = currentProfile @@ -268,7 +268,7 @@ extension ProviderLocationView { } struct ServerListView: View { - @ObservedObject private var providerManager: ProviderManager + @ObservedObject private var providerManager: Impl.ProviderManager private let location: ProviderLocation diff --git a/Passepartout/App/Views/ProviderPresetView.swift b/Passepartout/App/Views/ProviderPresetView.swift index 861e6c88..4bc7b8bc 100644 --- a/Passepartout/App/Views/ProviderPresetView.swift +++ b/Passepartout/App/Views/ProviderPresetView.swift @@ -24,12 +24,12 @@ // import SwiftUI -import PassepartoutCore +import PassepartoutLibrary struct ProviderPresetView: View { @Environment(\.presentationMode) private var presentationMode - @ObservedObject private var providerManager: ProviderManager + @ObservedObject private var providerManager: Impl.ProviderManager @ObservedObject private var currentProfile: ObservableProfile @@ -39,7 +39,7 @@ struct ProviderPresetView: View { // XXX: do not escape mutating 'self', use constant providerManager init(currentProfile: ObservableProfile) { - let providerManager: ProviderManager = .shared + let providerManager: Impl.ProviderManager = .shared self.providerManager = providerManager self.currentProfile = currentProfile diff --git a/Passepartout/App/Views/ReportIssueView.swift b/Passepartout/App/Views/ReportIssueView.swift index a9a00adb..c4caf769 100644 --- a/Passepartout/App/Views/ReportIssueView.swift +++ b/Passepartout/App/Views/ReportIssueView.swift @@ -25,7 +25,7 @@ import SwiftUI import MessageUI -import PassepartoutCore +import PassepartoutLibrary struct ReportIssueView: View { @Binding private var isPresented: Bool diff --git a/Passepartout/App/Views/ShortcutsView+Add.swift b/Passepartout/App/Views/ShortcutsView+Add.swift index a93cae89..e8fbf0a7 100644 --- a/Passepartout/App/Views/ShortcutsView+Add.swift +++ b/Passepartout/App/Views/ShortcutsView+Add.swift @@ -25,11 +25,11 @@ import SwiftUI import Intents -import PassepartoutCore +import PassepartoutLibrary extension ShortcutsView { struct AddView: View { - @ObservedObject private var providerManager: ProviderManager + @ObservedObject private var providerManager: Impl.ProviderManager @StateObject private var pendingProfile = ObservableProfile() diff --git a/Passepartout/App/Views/ShortcutsView.swift b/Passepartout/App/Views/ShortcutsView.swift index 871273cd..7d7dae13 100644 --- a/Passepartout/App/Views/ShortcutsView.swift +++ b/Passepartout/App/Views/ShortcutsView.swift @@ -25,7 +25,7 @@ import SwiftUI import Intents -import PassepartoutCore +import PassepartoutLibrary struct ShortcutsView: View { enum ModalType: Identifiable { diff --git a/Passepartout/App/Views/VPNStatusText.swift b/Passepartout/App/Views/VPNStatusText.swift index 25e9edbf..dcebcbd9 100644 --- a/Passepartout/App/Views/VPNStatusText.swift +++ b/Passepartout/App/Views/VPNStatusText.swift @@ -24,10 +24,10 @@ // import SwiftUI -import PassepartoutCore +import PassepartoutLibrary struct VPNStatusText: View { - @ObservedObject private var currentVPNState: VPNManager.ObservableState + @ObservedObject private var currentVPNState: ObservableVPNState let isActiveProfile: Bool diff --git a/Passepartout/App/Views/VPNToggle.swift b/Passepartout/App/Views/VPNToggle.swift index 49e75c2a..47bbc012 100644 --- a/Passepartout/App/Views/VPNToggle.swift +++ b/Passepartout/App/Views/VPNToggle.swift @@ -24,14 +24,14 @@ // import SwiftUI -import PassepartoutCore +import PassepartoutLibrary struct VPNToggle: View { - @ObservedObject private var profileManager: ProfileManager + @ObservedObject private var profileManager: Impl.ProfileManager - @ObservedObject private var vpnManager: VPNManager + @ObservedObject private var vpnManager: Impl.VPNManager - @ObservedObject private var currentVPNState: VPNManager.ObservableState + @ObservedObject private var currentVPNState: ObservableVPNState @ObservedObject private var productManager: ProductManager @@ -113,7 +113,7 @@ struct VPNToggle: View { IntentDispatcher.donateDisableVPN() IntentDispatcher.donateConnection( with: profile, - providerManager: .shared + providerManager: Impl.ProviderManager.shared ) } } diff --git a/Passepartout/App/Views/View+Extensions.swift b/Passepartout/App/Views/View+Extensions.swift index 4ef6cb77..6ec6daa8 100644 --- a/Passepartout/App/Views/View+Extensions.swift +++ b/Passepartout/App/Views/View+Extensions.swift @@ -24,7 +24,7 @@ // import SwiftUI -import PassepartoutCore +import PassepartoutLibrary import SwiftyBeaver extension View { diff --git a/Passepartout/AppShared/Constants/Constants+App.swift b/Passepartout/AppShared/Constants/Constants+App.swift index 8bea2526..83d49963 100644 --- a/Passepartout/AppShared/Constants/Constants+App.swift +++ b/Passepartout/AppShared/Constants/Constants+App.swift @@ -25,7 +25,7 @@ import Foundation import UniformTypeIdentifiers -import PassepartoutCore +import PassepartoutLibrary import SwiftyBeaver extension Constants { diff --git a/Passepartout/AppShared/Context/CoreContext+Shared.swift b/Passepartout/AppShared/Context/CoreContext+Shared.swift index fcefc34c..88b5ddef 100644 --- a/Passepartout/AppShared/Context/CoreContext+Shared.swift +++ b/Passepartout/AppShared/Context/CoreContext+Shared.swift @@ -24,7 +24,7 @@ // import Foundation -import PassepartoutCore +import PassepartoutLibrary extension CoreContext { static let shared = CoreContext(store: UserDefaultsStore(defaults: .standard)) @@ -34,20 +34,18 @@ extension UpgradeManager { static let shared = CoreContext.shared.upgradeManager } -extension ProfileManager { +extension Impl.ProfileManager { static let shared = CoreContext.shared.profileManager } -extension ProviderManager { +extension Impl.ProviderManager { static let shared = CoreContext.shared.providerManager } -extension VPNManager { +extension Impl.VPNManager { static let shared = CoreContext.shared.vpnManager } -extension VPNManager.ObservableState { - - @MainActor +extension ObservableVPNState { static let shared = CoreContext.shared.vpnManager.currentState } diff --git a/Passepartout/AppShared/Context/CoreContext.swift b/Passepartout/AppShared/Context/CoreContext.swift index 600b8d00..27555a6a 100644 --- a/Passepartout/AppShared/Context/CoreContext.swift +++ b/Passepartout/AppShared/Context/CoreContext.swift @@ -25,10 +25,16 @@ import Foundation import Combine -import PassepartoutCore -import PassepartoutServices +import PassepartoutLibrary + +enum Impl { + typealias ProfileManager = DefaultProfileManager + + typealias ProviderManager = DefaultProviderManager + + typealias VPNManager = DefaultVPNManager +} -@MainActor class CoreContext { let store: KeyValueStore @@ -46,11 +52,11 @@ class CoreContext { let upgradeManager: UpgradeManager - let providerManager: ProviderManager + let providerManager: Impl.ProviderManager - let profileManager: ProfileManager + let profileManager: Impl.ProfileManager - let vpnManager: VPNManager + let vpnManager: Impl.VPNManager private var cancellables: Set = [] @@ -67,7 +73,7 @@ class CoreContext { upgradeManager = UpgradeManager(store: store) - providerManager = ProviderManager( + providerManager = DefaultProviderManager( appBuild: Constants.Global.appBuildNumber, bundleServices: DefaultWebServices.bundledServices( withVersion: Constants.Services.version @@ -80,12 +86,12 @@ class CoreContext { persistence: providersPersistence ) - profileManager = ProfileManager( + profileManager = DefaultProfileManager( store: store, providerManager: providerManager, appGroup: Constants.App.appGroupId, keychainLabel: Unlocalized.Keychain.passwordLabel, - strategy: ProfileManager.CoreDataStrategy( + strategy: CoreDataProfileManagerStrategy( persistence: profilesPersistence ) ) @@ -93,12 +99,13 @@ class CoreContext { #if targetEnvironment(simulator) let strategy = VPNManager.MockStrategy() #else - let strategy = VPNManager.TunnelKitStrategy( + let strategy = TunnelKitVPNManagerStrategy( appGroup: Constants.App.appGroupId, tunnelBundleIdentifier: Constants.App.tunnelBundleId ) #endif - vpnManager = VPNManager( + vpnManager = DefaultVPNManager( + appGroup: Constants.App.appGroupId, store: store, profileManager: profileManager, providerManager: providerManager, diff --git a/Passepartout/AppShared/InApp/LocalProduct.swift b/Passepartout/AppShared/InApp/LocalProduct.swift index 12dc72a1..21f8c1e3 100644 --- a/Passepartout/AppShared/InApp/LocalProduct.swift +++ b/Passepartout/AppShared/InApp/LocalProduct.swift @@ -25,7 +25,7 @@ import Foundation import StoreKit -import PassepartoutCore +import PassepartoutLibrary struct LocalProduct: RawRepresentable, Equatable, Hashable { private static let bundleSubdomain = "ios" diff --git a/Passepartout/AppShared/InApp/ProductManager.swift b/Passepartout/AppShared/InApp/ProductManager.swift index bc20354f..0b578113 100644 --- a/Passepartout/AppShared/InApp/ProductManager.swift +++ b/Passepartout/AppShared/InApp/ProductManager.swift @@ -24,7 +24,7 @@ // import Foundation -import PassepartoutCore +import PassepartoutLibrary import StoreKit import Kvitto @@ -34,7 +34,6 @@ enum ProductError: Error { case beta } -@MainActor class ProductManager: NSObject, ObservableObject { enum AppType: Int { case freemium = 0 diff --git a/Passepartout/AppShared/L10n/Core+L10n.swift b/Passepartout/AppShared/L10n/Core+L10n.swift index b6fe30b7..13bb2127 100644 --- a/Passepartout/AppShared/L10n/Core+L10n.swift +++ b/Passepartout/AppShared/L10n/Core+L10n.swift @@ -24,7 +24,7 @@ // import Foundation -import PassepartoutCore +import PassepartoutLibrary extension Error { var localizedAppDescription: String { @@ -57,7 +57,7 @@ extension PassepartoutError { } } -extension VPNManager.ObservableState { +extension ObservableVPNState { func localizedStatusDescription(isActiveProfile: Bool, withErrors: Bool, dataCountIfAvailable: Bool) -> String { // FIXME: l10n, sure about this wording? diff --git a/Passepartout/AppShared/L10n/Providers+L10n.swift b/Passepartout/AppShared/L10n/Providers+L10n.swift index b087aee7..05a1c3ff 100644 --- a/Passepartout/AppShared/L10n/Providers+L10n.swift +++ b/Passepartout/AppShared/L10n/Providers+L10n.swift @@ -24,7 +24,7 @@ // import Foundation -import PassepartoutCore +import PassepartoutLibrary extension ProviderManager { // func localizedLocation(forProfile profile: Profile) -> String? { @@ -59,7 +59,7 @@ extension ProviderMetadata { format = NSLocalizedString(defaultKey, bundle: .main, comment: "") } - return String(format: format, locale: .current, description) + return String(format: format, locale: .current, fullName) } } diff --git a/Passepartout/AppShared/L10n/TunnelKit+L10n.swift b/Passepartout/AppShared/L10n/TunnelKit+L10n.swift index 53d64f41..c7a961c5 100644 --- a/Passepartout/AppShared/L10n/TunnelKit+L10n.swift +++ b/Passepartout/AppShared/L10n/TunnelKit+L10n.swift @@ -28,7 +28,7 @@ import TunnelKitManager import TunnelKitOpenVPN import TunnelKitWireGuard import NetworkExtension -import PassepartoutCore +import PassepartoutLibrary extension VPNStatus { var localizedDescription: String { diff --git a/Passepartout/AppShared/L10n/Unlocalized.swift b/Passepartout/AppShared/L10n/Unlocalized.swift index 716ce387..d7af4657 100644 --- a/Passepartout/AppShared/L10n/Unlocalized.swift +++ b/Passepartout/AppShared/L10n/Unlocalized.swift @@ -24,7 +24,7 @@ // import Foundation -import PassepartoutCore +import PassepartoutLibrary enum Unlocalized { static let appName = Constants.Global.appName diff --git a/PassepartoutCore/.swiftpm/xcode/xcshareddata/xcschemes/PassepartoutCore-Package.xcscheme b/PassepartoutCore/.swiftpm/xcode/xcshareddata/xcschemes/PassepartoutCore-Package.xcscheme deleted file mode 100644 index f9b5e0bd..00000000 --- a/PassepartoutCore/.swiftpm/xcode/xcshareddata/xcschemes/PassepartoutCore-Package.xcscheme +++ /dev/null @@ -1,289 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/PassepartoutCore/.swiftpm/xcode/xcshareddata/xcschemes/PassepartoutCore.xcscheme b/PassepartoutCore/.swiftpm/xcode/xcshareddata/xcschemes/PassepartoutCore.xcscheme deleted file mode 100644 index b680278e..00000000 --- a/PassepartoutCore/.swiftpm/xcode/xcshareddata/xcschemes/PassepartoutCore.xcscheme +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/PassepartoutCore/Sources/PassepartoutCore/Managers/VPNManagerStrategy+Mock.swift b/PassepartoutCore/Sources/PassepartoutCore/Managers/VPNManagerStrategy+Mock.swift deleted file mode 100644 index 66d01544..00000000 --- a/PassepartoutCore/Sources/PassepartoutCore/Managers/VPNManagerStrategy+Mock.swift +++ /dev/null @@ -1,108 +0,0 @@ -// -// VPNManagerStrategy+Mock.swift -// Passepartout -// -// Created by Davide De Rosa on 2/9/22. -// Copyright (c) 2022 Davide De Rosa. All rights reserved. -// -// https://github.com/passepartoutvpn -// -// This file is part of Passepartout. -// -// Passepartout is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Passepartout is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Passepartout. If not, see . -// - -import Foundation -import Combine -import TunnelKitManager - -extension VPNManager { - - // XXX: mock connect/disconnect tasks overlap, should cancel other pending task - - public class MockStrategy: VPNManagerStrategy { - private var currentState: ObservableState? - - private var dataCountTimer: AnyCancellable? - - public init() { - } - - public func observe(into state: VPNManager.ObservableState) { - currentState = state - } - - public func reinstate(configuration: VPNConfiguration) { - } - - public func connect(configuration: VPNConfiguration) { - guard currentState?.vpnStatus != .connected else { - return - } - Task { - currentState?.isEnabled = true - currentState?.vpnStatus = .connecting - await Task.maybeWait(forMilliseconds: 1000) - currentState?.vpnStatus = .connected - startCountingData() - } - } - - public func disconnect() { - stopCountingData() - guard currentState?.vpnStatus != .disconnected else { - return - } - Task { - currentState?.isEnabled = false - currentState?.vpnStatus = .disconnecting - await Task.maybeWait(forMilliseconds: 1000) - currentState?.vpnStatus = .disconnected - currentState?.dataCount = nil - } - } - - private func startCountingData() { - guard currentState?.vpnStatus == .connected else { - return - } - guard dataCountTimer == nil else { - return - } - dataCountTimer = Timer.TimerPublisher(interval: 2.0, runLoop: .main, mode: .common) - .autoconnect() - .sink(receiveValue: { _ in - let previous = self.currentState?.dataCount ?? DataCount(0, 0) - self.currentState?.dataCount = DataCount(previous.received + 4000, previous.sent + 2000) - }) - } - - private func stopCountingData() { - dataCountTimer?.cancel() - dataCountTimer = nil - } - - public func removeConfigurations() { - disconnect() - } - - public func serverConfiguration(forProtocol vpnProtocol: VPNProtocolType) -> Any? { - return nil - } - - public func debugLogURL(forProtocol vpnProtocol: VPNProtocolType) -> URL? { - return nil - } - } -} diff --git a/PassepartoutCore/Sources/PassepartoutCore/Managers/VPNManagerStrategy+TunnelKit.swift b/PassepartoutCore/Sources/PassepartoutCore/Managers/VPNManagerStrategy+TunnelKit.swift deleted file mode 100644 index 3e6c8314..00000000 --- a/PassepartoutCore/Sources/PassepartoutCore/Managers/VPNManagerStrategy+TunnelKit.swift +++ /dev/null @@ -1,316 +0,0 @@ -// -// VPNManagerStrategy+TunnelKit.swift -// Passepartout -// -// Created by Davide De Rosa on 3/4/22. -// Copyright (c) 2022 Davide De Rosa. All rights reserved. -// -// https://github.com/passepartoutvpn -// -// This file is part of Passepartout. -// -// Passepartout is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Passepartout is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Passepartout. If not, see . -// - -import Foundation -import Combine -import NetworkExtension -import TunnelKitManager -import TunnelKitOpenVPNCore - -extension VPNManager { - public class TunnelKitStrategy: VPNManagerStrategy { - 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 appGroup: String - - private let tunnelBundleIdentifier: (VPNProtocolType) -> String - - private let defaults: UserDefaults - - private let vpn: NetworkExtensionVPN - - private let dataCountInterval: TimeInterval - - // MARK: State - - private var currentState: ObservableState? - - private let vpnState = CurrentValueSubject(.init()) - - private var dataCountTimer: AnyCancellable? - - private var cancellables: Set = [] - - // MARK: Protocol specific - - private var currentBundleIdentifier: String? - - public init(appGroup: String, tunnelBundleIdentifier: @escaping (VPNProtocolType) -> String, dataCountInterval: TimeInterval = 3.0) { - self.appGroup = appGroup - self.tunnelBundleIdentifier = tunnelBundleIdentifier - guard let defaults = UserDefaults(suiteName: appGroup) else { - fatalError("No entitlements for group '\(appGroup)'") - } - self.defaults = defaults - vpn = NetworkExtensionVPN() - self.dataCountInterval = dataCountInterval - - registerNotification(withName: VPNNotification.didReinstall) { - self.onVPNReinstall($0) - } - registerNotification(withName: VPNNotification.didChangeStatus) { - self.onVPNStatus($0) - } - registerNotification(withName: VPNNotification.didFail) { - self.onVPNFail($0) - } - Task { - await vpn.prepare() - } - } - - private func registerNotification(withName name: Notification.Name, perform: @escaping (Notification) -> Void) { - NotificationCenter.default.publisher(for: name, object: nil) - .receive(on: DispatchQueue.main) - .sink(receiveValue: perform) - .store(in: &cancellables) - } - - // MARK: Strategy - - public func observe(into state: VPNManager.ObservableState) { - currentState = state - - // use this to drop redundant NE notifications - vpnState - .removeDuplicates() - .sink { - self.currentState?.isEnabled = $0.isEnabled - 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") - } - let bundleIdentifier = tunnelBundleIdentifier(vpnType.vpnProtocol) - currentBundleIdentifier = bundleIdentifier - - pp_log.verbose("Configuration: \(configuration)") - pp_log.info("Reinstating VPN...") - do { - try await vpn.install( - bundleIdentifier, - configuration: configuration.neConfiguration, - extra: configuration.neExtra - ) - } catch { - 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") - } - let bundleIdentifier = tunnelBundleIdentifier(vpnType.vpnProtocol) - currentBundleIdentifier = bundleIdentifier - - pp_log.verbose("Configuration: \(configuration)") - pp_log.info("Reconnecting VPN...") - do { - try await vpn.reconnect( - bundleIdentifier, - configuration: configuration.neConfiguration, - extra: configuration.neExtra, - after: .seconds(2) - ) - } catch { - pp_log.error("Unable to connect: \(error)") - } - } - - public func disconnect() async { - await vpn.disconnect() - } - - public func removeConfigurations() async { - await vpn.uninstall() - - // XXX: force isEnabled to false as it's not properly notified by NetworkExtension - vpnState.send(AtomicState( - isEnabled: false, - vpnStatus: vpnState.value.vpnStatus - )) - } - - // MARK: Notifications - - private func onVPNReinstall(_ notification: Notification) { - guard isRelevantNotification(notification) else { - return - } - - vpnState.send(AtomicState( - isEnabled: notification.vpnIsEnabled, - vpnStatus: vpnState.value.vpnStatus - )) - } - - private func onVPNStatus(_ notification: Notification) { - - // assume first notified identifier to be the relevant one - // in order to restore VPN status on app launch - if currentBundleIdentifier == nil { - currentBundleIdentifier = notification.vpnBundleIdentifier - } - guard isRelevantNotification(notification) else { - return - } - - var error: Error? - - switch notification.vpnStatus { - case .connected: - startCountingData() - - case .disconnecting: - error = lastError(withBundleIdentifier: notification.vpnBundleIdentifier) - - case .disconnected: - error = lastError(withBundleIdentifier: notification.vpnBundleIdentifier) - stopCountingData() - - default: - break - } - - vpnState.send(AtomicState( - isEnabled: notification.vpnIsEnabled, - vpnStatus: notification.vpnStatus - )) - currentState?.lastError = error - } - - private func onVPNFail(_ notification: Notification) { - vpnState.send(AtomicState( - isEnabled: notification.vpnIsEnabled, - vpnStatus: vpnState.value.vpnStatus - )) - currentState?.lastError = notification.vpnError - } - - private func isRelevantNotification(_ notification: Notification) -> Bool { - guard let notificationTunnelIdentifier = notification.vpnBundleIdentifier else { - return false - } - guard notificationTunnelIdentifier == currentBundleIdentifier else { - pp_log.debug("Skipping not relevant notification from \(notificationTunnelIdentifier)") - return false - } - return true - } - - // MARK: Data count - - private func onDataCount(_: Date) { - switch vpnState.value.vpnStatus { - case .connected: - guard let currentDataCount = currentDataCount else { - return - } - currentState?.dataCount = currentDataCount - - default: - currentState?.dataCount = nil - } - } - - private func startCountingData() { - guard dataCountTimer == nil else { - return - } - dataCountTimer = Timer.TimerPublisher(interval: dataCountInterval, runLoop: .main, mode: .common) - .autoconnect() - .sink { - self.onDataCount($0) - } - } - - private func stopCountingData() { - dataCountTimer?.cancel() - dataCountTimer = nil - - currentState?.dataCount = nil - } - - // MARK: Pulled - - public func serverConfiguration(forProtocol vpnProtocol: VPNProtocolType) -> Any? { - switch vpnProtocol { - case .openVPN: - return defaults.openVPNServerConfiguration - - default: - return nil - } - } - - public func debugLogURL(forProtocol vpnProtocol: VPNProtocolType) -> URL? { - switch vpnProtocol { - case .openVPN: - return defaults.openVPNURLForDebugLog(appGroup: appGroup) - - default: - return defaults.wireGuardURLForDebugLog(appGroup: appGroup) - } - } - - // MARK: Callbacks - - private func lastError(withBundleIdentifier bundleIdentifier: String?) -> Error? { - switch bundleIdentifier { - case tunnelBundleIdentifier(.openVPN): - return defaults.openVPNLastError - - case tunnelBundleIdentifier(.wireGuard): - return defaults.wireGuardLastError - - default: - return nil - } - } - - private var currentDataCount: DataCount? { - switch currentBundleIdentifier { - case tunnelBundleIdentifier(.openVPN): - return defaults.openVPNDataCount - - default: - return nil - } - } - } -} diff --git a/PassepartoutCore/Sources/PassepartoutProfiles/Managers/ProfileManagerStrategy+CoreData.swift b/PassepartoutCore/Sources/PassepartoutProfiles/Managers/ProfileManagerStrategy+CoreData.swift deleted file mode 100644 index 9862ee7e..00000000 --- a/PassepartoutCore/Sources/PassepartoutProfiles/Managers/ProfileManagerStrategy+CoreData.swift +++ /dev/null @@ -1,66 +0,0 @@ -// -// ProfileManagerStrategy+CoreData.swift -// Passepartout -// -// Created by Davide De Rosa on 4/9/22. -// Copyright (c) 2022 Davide De Rosa. All rights reserved. -// -// https://github.com/passepartoutvpn -// -// This file is part of Passepartout. -// -// Passepartout is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Passepartout is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Passepartout. If not, see . -// - -import Foundation -import Combine -import PassepartoutUtils - -extension ProfileManager { - public class CoreDataStrategy: ProfileManagerStrategy { - private let profileRepository: ProfileRepository - - private let fetchedHeaders: FetchedValueHolder<[UUID: Profile.Header]> - - public init(persistence: Persistence) { - profileRepository = ProfileRepository(persistence.context) - fetchedHeaders = profileRepository.fetchedHeaders() - } - - public var allHeaders: [UUID: Profile.Header] { - fetchedHeaders.value - } - - public func profile(withId id: UUID) -> Profile? { - profileRepository.profile(withId: id) - } - - public func saveProfiles(_ profiles: [Profile]) { - do { - try profileRepository.saveProfiles(profiles) - } catch { - pp_log.error("Unable to save profile: \(error)") - } - } - - public func removeProfiles(withIds ids: [UUID]) { - profileRepository.removeProfiles(withIds: ids) - } - - public func willUpdateProfiles() -> AnyPublisher<[UUID : Profile.Header], Never> { - fetchedHeaders.$value - .eraseToAnyPublisher() - } - } -} diff --git a/PassepartoutCore/.gitignore b/PassepartoutLibrary/.gitignore similarity index 100% rename from PassepartoutCore/.gitignore rename to PassepartoutLibrary/.gitignore diff --git a/PassepartoutCore/.swiftpm/xcode/xcshareddata/xcschemes/OpenVPNAppExtension.xcscheme b/PassepartoutLibrary/.swiftpm/xcode/xcshareddata/xcschemes/OpenVPNAppExtension.xcscheme similarity index 100% rename from PassepartoutCore/.swiftpm/xcode/xcshareddata/xcschemes/OpenVPNAppExtension.xcscheme rename to PassepartoutLibrary/.swiftpm/xcode/xcshareddata/xcschemes/OpenVPNAppExtension.xcscheme diff --git a/PassepartoutCore/.swiftpm/xcode/xcshareddata/xcschemes/PassepartoutProvidersTests.xcscheme b/PassepartoutLibrary/.swiftpm/xcode/xcshareddata/xcschemes/PassepartoutProvidersTests.xcscheme similarity index 100% rename from PassepartoutCore/.swiftpm/xcode/xcshareddata/xcschemes/PassepartoutProvidersTests.xcscheme rename to PassepartoutLibrary/.swiftpm/xcode/xcshareddata/xcschemes/PassepartoutProvidersTests.xcscheme diff --git a/PassepartoutCore/.swiftpm/xcode/xcshareddata/xcschemes/PassepartoutServicesTests.xcscheme b/PassepartoutLibrary/.swiftpm/xcode/xcshareddata/xcschemes/PassepartoutServicesTests.xcscheme similarity index 100% rename from PassepartoutCore/.swiftpm/xcode/xcshareddata/xcschemes/PassepartoutServicesTests.xcscheme rename to PassepartoutLibrary/.swiftpm/xcode/xcshareddata/xcschemes/PassepartoutServicesTests.xcscheme diff --git a/PassepartoutCore/.swiftpm/xcode/xcshareddata/xcschemes/PassepartoutUtilsTests.xcscheme b/PassepartoutLibrary/.swiftpm/xcode/xcshareddata/xcschemes/PassepartoutUtilsTests.xcscheme similarity index 100% rename from PassepartoutCore/.swiftpm/xcode/xcshareddata/xcschemes/PassepartoutUtilsTests.xcscheme rename to PassepartoutLibrary/.swiftpm/xcode/xcshareddata/xcschemes/PassepartoutUtilsTests.xcscheme diff --git a/PassepartoutCore/.swiftpm/xcode/xcshareddata/xcschemes/WireGuardAppExtension.xcscheme b/PassepartoutLibrary/.swiftpm/xcode/xcshareddata/xcschemes/WireGuardAppExtension.xcscheme similarity index 100% rename from PassepartoutCore/.swiftpm/xcode/xcshareddata/xcschemes/WireGuardAppExtension.xcscheme rename to PassepartoutLibrary/.swiftpm/xcode/xcshareddata/xcschemes/WireGuardAppExtension.xcscheme diff --git a/PassepartoutCore/Package.swift b/PassepartoutLibrary/Package.swift similarity index 82% rename from PassepartoutCore/Package.swift rename to PassepartoutLibrary/Package.swift index 3f042a31..deb385f1 100644 --- a/PassepartoutCore/Package.swift +++ b/PassepartoutLibrary/Package.swift @@ -4,15 +4,15 @@ import PackageDescription let package = Package( - name: "PassepartoutCore", + name: "PassepartoutLibrary", platforms: [ .iOS(.v14), .macOS(.v11) ], products: [ // Products define the executables and libraries a package produces, and make them visible to other packages. .library( - name: "PassepartoutCore", - targets: ["PassepartoutCore"]), + name: "PassepartoutLibrary", + targets: ["PassepartoutLibrary"]), .library( name: "OpenVPNAppExtension", targets: ["OpenVPNAppExtension"]), @@ -33,26 +33,41 @@ let package = Package( // Targets are the basic building blocks of a package. A target can define a module or a test suite. // Targets can depend on other targets in this package, and on products in packages this package depends on. .target( - name: "PassepartoutCore", + name: "PassepartoutLibrary", + dependencies: [ + "PassepartoutVPN" + ]), + .target( + name: "PassepartoutVPN", dependencies: [ "PassepartoutProfiles", - "PassepartoutProviders" + .product(name: "TunnelKitLZO", package: "TunnelKit") ]), .target( name: "PassepartoutProfiles", dependencies: [ - "PassepartoutProviders", - .product(name: "TunnelKit", package: "TunnelKit"), - .product(name: "TunnelKitOpenVPN", package: "TunnelKit"), - .product(name: "TunnelKitWireGuard", package: "TunnelKit"), - .product(name: "TunnelKitLZO", package: "TunnelKit") + "PassepartoutProviders" ]), .target( name: "PassepartoutProviders", - dependencies: ["PassepartoutServices"]), + dependencies: [ + "PassepartoutCore", + "PassepartoutServices" + ]), + .target( + name: "PassepartoutCore", + dependencies: [ + .product(name: "TunnelKit", package: "TunnelKit"), + .product(name: "TunnelKitOpenVPN", package: "TunnelKit"), + .product(name: "TunnelKitWireGuard", package: "TunnelKit"), + .product(name: "GenericJSON", package: "generic-json-swift") + ]), + // .target( name: "PassepartoutServices", - dependencies: ["PassepartoutUtils"], + dependencies: [ + "PassepartoutUtils", + ], resources: [ .copy("API") ]), @@ -62,6 +77,7 @@ let package = Package( .product(name: "GenericJSON", package: "generic-json-swift"), "SwiftyBeaver" ]), + // .target( name: "OpenVPNAppExtension", dependencies: [ @@ -74,8 +90,8 @@ let package = Package( .product(name: "TunnelKitWireGuardAppExtension", package: "TunnelKit") ]), // .testTarget( -// name: "PassepartoutCoreTests", -// dependencies: ["PassepartoutCore"]), +// name: "PassepartoutLibraryTests", +// dependencies: ["PassepartoutLibrary"]), // .testTarget( // name: "PassepartoutProfilesTests", // dependencies: ["PassepartoutProfiles"]), diff --git a/PassepartoutCore/Sources/OpenVPNAppExtension/Exports.swift b/PassepartoutLibrary/Sources/OpenVPNAppExtension/Exports.swift similarity index 100% rename from PassepartoutCore/Sources/OpenVPNAppExtension/Exports.swift rename to PassepartoutLibrary/Sources/OpenVPNAppExtension/Exports.swift diff --git a/PassepartoutCore/Sources/PassepartoutProfiles/Extensions/Host+Extensions.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Extensions/Host+Extensions.swift similarity index 92% rename from PassepartoutCore/Sources/PassepartoutProfiles/Extensions/Host+Extensions.swift rename to PassepartoutLibrary/Sources/PassepartoutCore/Extensions/Host+Extensions.swift index 9af732ef..34c46e49 100644 --- a/PassepartoutCore/Sources/PassepartoutProfiles/Extensions/Host+Extensions.swift +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Extensions/Host+Extensions.swift @@ -25,7 +25,6 @@ import Foundation import TunnelKitCore -import PassepartoutProviders extension Profile { public func hostAccount() -> Profile.Account? { @@ -99,8 +98,4 @@ extension Profile.Host: ProfileSubtype { fatalError("No VPN settings found") } } - - public func requiresCredentials(forProtocol vpnProtocol: VPNProtocolType) -> Bool { - return vpnProtocol == .openVPN && (ovpnSettings?.configuration.authUserPass ?? false) - } } diff --git a/PassepartoutCore/Sources/PassepartoutProfiles/Extensions/NetworkSettings+Extensions.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Extensions/NetworkSettings+Extensions.swift similarity index 98% rename from PassepartoutCore/Sources/PassepartoutProfiles/Extensions/NetworkSettings+Extensions.swift rename to PassepartoutLibrary/Sources/PassepartoutCore/Extensions/NetworkSettings+Extensions.swift index 4b3f0a78..862110e0 100644 --- a/PassepartoutCore/Sources/PassepartoutProfiles/Extensions/NetworkSettings+Extensions.swift +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Extensions/NetworkSettings+Extensions.swift @@ -24,7 +24,6 @@ // import Foundation -import PassepartoutUtils extension Profile.NetworkSettings { public var isAutomaticGateway: Bool { diff --git a/PassepartoutCore/Sources/PassepartoutProfiles/Extensions/OnDemand+Extensions.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Extensions/OnDemand+Extensions.swift similarity index 98% rename from PassepartoutCore/Sources/PassepartoutProfiles/Extensions/OnDemand+Extensions.swift rename to PassepartoutLibrary/Sources/PassepartoutCore/Extensions/OnDemand+Extensions.swift index 24f933c0..c4c8c56e 100644 --- a/PassepartoutCore/Sources/PassepartoutProfiles/Extensions/OnDemand+Extensions.swift +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Extensions/OnDemand+Extensions.swift @@ -24,7 +24,6 @@ // import Foundation -import PassepartoutUtils extension Profile.OnDemand { public var withMobileNetwork: Bool { diff --git a/PassepartoutLibrary/Sources/PassepartoutCore/Extensions/Profile+Extensions.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Extensions/Profile+Extensions.swift new file mode 100644 index 00000000..097a78a4 --- /dev/null +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Extensions/Profile+Extensions.swift @@ -0,0 +1,57 @@ +// +// Profile+Extensions.swift +// Passepartout +// +// Created by Davide De Rosa on 3/13/22. +// Copyright (c) 2022 Davide De Rosa. All rights reserved. +// +// https://github.com/passepartoutvpn +// +// This file is part of Passepartout. +// +// Passepartout is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Passepartout is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Passepartout. If not, see . +// + +import Foundation + +extension Profile { + public var isProvider: Bool { + return provider != nil + } + + public var vpnProtocols: [VPNProtocolType] { + if isProvider { + return provider?.vpnProtocols ?? [] + } else { + return host?.vpnProtocols ?? [] + } + } + + public var account: Profile.Account { + get { + if isProvider { + return providerAccount() ?? .init() + } else { + return hostAccount() ?? .init() + } + } + set { + if isProvider { + setProviderAccount(newValue) + } else { + setHostAccount(newValue) + } + } + } +} diff --git a/PassepartoutCore/Sources/PassepartoutProfiles/Extensions/Provider+Extensions.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Extensions/Provider+Extensions.swift similarity index 68% rename from PassepartoutCore/Sources/PassepartoutProfiles/Extensions/Provider+Extensions.swift rename to PassepartoutLibrary/Sources/PassepartoutCore/Extensions/Provider+Extensions.swift index 4dda517a..20ad1e4d 100644 --- a/PassepartoutCore/Sources/PassepartoutProfiles/Extensions/Provider+Extensions.swift +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Extensions/Provider+Extensions.swift @@ -25,8 +25,6 @@ import Foundation import TunnelKitCore -import PassepartoutProviders -import PassepartoutUtils extension Profile { public init(_ providerMetadata: ProviderMetadata, server: ProviderServer) { @@ -42,8 +40,11 @@ extension Profile { self.init(name: providerMetadata.fullName, provider: provider) } + + public var providerName: String? { + provider?.name + } - @MainActor public func providerServer(_ providerManager: ProviderManager) -> ProviderServer? { guard let serverId = provider?.vpnSettings[currentVPNProtocol]?.serverId else { return nil @@ -102,52 +103,8 @@ extension Profile { } } -extension Profile { - - @MainActor - public func providerOpenVPNSettings(withManager providerManager: ProviderManager) throws -> Profile.OpenVPNSettings { - guard let _ = provider else { - fatalError("Not a provider") - } - - // infer remotes from preset + server - guard let server = providerServer(providerManager) else { - throw PassepartoutError.missingProviderServer - } - guard let preset = providerPreset(server) else { - throw PassepartoutError.missingProviderPreset - } - guard var builder = preset.openVPNConfiguration?.builder() else { - fatalError("Preset \(preset.id) has no OpenVPN configuration") - } - try builder.setRemotes(from: preset, with: server, excludingHostname: !networkSettings.resolvesHostname) - - // enforce default gateway - builder.routingPolicies = [.IPv4, .IPv6] - - // apply provider settings (username, custom endpoint) - let cfg = builder.build() - return OpenVPNSettings( - configuration: cfg, - account: providerAccount(), - customEndpoint: providerCustomEndpoint() - ) - } - - public func providerWireGuardSettings(withManager providerManager: ProviderManager) throws -> Profile.WireGuardSettings { - guard let _ = provider else { - fatalError("Not a provider") - } - fatalError("WireGuard not yet implemented for providers") - } -} - extension Profile.Provider: ProfileSubtype { public var vpnProtocols: [VPNProtocolType] { - return vpnSettings.keys.sorted() - } - - public func requiresCredentials(forProtocol vpnProtocol: VPNProtocolType) -> Bool { - return name.requiresCredentials(forProtocol: vpnProtocol) + Array(vpnSettings.keys) } } diff --git a/PassepartoutCore/Sources/PassepartoutProviders/Extensions/VPNProtocolType+Extensions.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Managers/CurrentProfileProviding.swift similarity index 78% rename from PassepartoutCore/Sources/PassepartoutProviders/Extensions/VPNProtocolType+Extensions.swift rename to PassepartoutLibrary/Sources/PassepartoutCore/Managers/CurrentProfileProviding.swift index ea59a0e7..5d1bd070 100644 --- a/PassepartoutCore/Sources/PassepartoutProviders/Extensions/VPNProtocolType+Extensions.swift +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Managers/CurrentProfileProviding.swift @@ -1,8 +1,8 @@ // -// VPNProtocolType+Extensions.swift +// CurrentProfileProviding.swift // Passepartout // -// Created by Davide De Rosa on 4/7/22. +// Created by Davide De Rosa on 6/22/22. // Copyright (c) 2022 Davide De Rosa. All rights reserved. // // https://github.com/passepartoutvpn @@ -25,8 +25,8 @@ import Foundation -extension VPNProtocolType: Comparable { - public static func <(lhs: Self, rhs: Self) -> Bool { - return lhs.description < rhs.description - } +public protocol CurrentProfileProviding { + associatedtype WrappedType: WrappedProfile + + var currentProfile: WrappedType { get } } diff --git a/PassepartoutLibrary/Sources/PassepartoutCore/Managers/CurrentVPNStateProviding.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Managers/CurrentVPNStateProviding.swift new file mode 100644 index 00000000..2bc2ceaf --- /dev/null +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Managers/CurrentVPNStateProviding.swift @@ -0,0 +1,32 @@ +// +// CurrentVPNStateProviding.swift +// Passepartout +// +// Created by Davide De Rosa on 6/22/22. +// Copyright (c) 2022 Davide De Rosa. All rights reserved. +// +// https://github.com/passepartoutvpn +// +// This file is part of Passepartout. +// +// Passepartout is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Passepartout is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Passepartout. If not, see . +// + +import Foundation + +public protocol CurrentVPNStateProviding { + associatedtype WrappedType: WrappedVPNState + + var currentState: WrappedType { get } +} diff --git a/PassepartoutLibrary/Sources/PassepartoutCore/Managers/ProfileManager.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Managers/ProfileManager.swift new file mode 100644 index 00000000..ae04f446 --- /dev/null +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Managers/ProfileManager.swift @@ -0,0 +1,68 @@ +// +// ProfileManager.swift +// Passepartout +// +// Created by Davide De Rosa on 6/20/22. +// Copyright (c) 2022 Davide De Rosa. All rights reserved. +// +// https://github.com/passepartoutvpn +// +// This file is part of Passepartout. +// +// Passepartout is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Passepartout is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Passepartout. If not, see . +// + +import Foundation +import Combine + +public protocol ProfileManager { + typealias ProfileEx = (profile: Profile, isReady: Bool) + + var activeProfileId: UUID? { get } + + var activeProfileIdPublisher: Published.Publisher { get } + + var currentProfileId: UUID? { get set } + + var didCreateProfile: PassthroughSubject { get } + + var headers: [Profile.Header] { get } + + func isExistingProfile(withId id: UUID) -> Bool + + func isExistingProfile(withName name: String) -> Bool + + func liveProfileEx(withId id: UUID) throws -> ProfileEx + + func makeProfileReady(_ profile: Profile) async throws + + func saveProfile(_ profile: Profile, isActive: Bool?, updateIfCurrent: Bool) + + func savePassword(forProfile profile: Profile) + + func passwordReference(forProfile profile: Profile) -> Data? + + func removeProfiles(withIds ids: [UUID]) + + @available(*, deprecated, message: "only use for testing") + func removeAllProfiles() + + func duplicateProfile(withId id: UUID, setAsCurrent: Bool) + + func profile(withHeader header: Profile.Header, fromContents contents: String, originalURL: URL?, passphrase: String?) throws -> Profile + + func persist() + + func observeUpdates() +} diff --git a/PassepartoutLibrary/Sources/PassepartoutCore/Managers/ProfileManagerWithCurrentProfile.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Managers/ProfileManagerWithCurrentProfile.swift new file mode 100644 index 00000000..76dc8f95 --- /dev/null +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Managers/ProfileManagerWithCurrentProfile.swift @@ -0,0 +1,29 @@ +// +// ProfileManagerWithCurrentProfile.swift +// Passepartout +// +// Created by Davide De Rosa on 6/22/22. +// Copyright (c) 2022 Davide De Rosa. All rights reserved. +// +// https://github.com/passepartoutvpn +// +// This file is part of Passepartout. +// +// Passepartout is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Passepartout is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Passepartout. If not, see . +// + +import Foundation + +public protocol ProfileManagerWithCurrentProfile: ProfileManager, CurrentProfileProviding { +} diff --git a/PassepartoutLibrary/Sources/PassepartoutCore/Managers/ProviderManager.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Managers/ProviderManager.swift new file mode 100644 index 00000000..f97f816e --- /dev/null +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Managers/ProviderManager.swift @@ -0,0 +1,59 @@ +// +// ProviderManager.swift +// Passepartout +// +// Created by Davide De Rosa on 6/19/22. +// Copyright (c) 2022 Davide De Rosa. All rights reserved. +// +// https://github.com/passepartoutvpn +// +// This file is part of Passepartout. +// +// Passepartout is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Passepartout is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Passepartout. If not, see . +// + +import Foundation +import Combine + +public protocol ProviderManager { + func allProviders() -> [ProviderMetadata] + + func provider(withName name: ProviderName) -> ProviderMetadata? + + func isAvailable(_ name: ProviderName, vpnProtocol: VPNProtocolType) -> Bool + + func defaultUsername(_ name: ProviderName, vpnProtocol: VPNProtocolType) -> String? + + func lastUpdate(_ name: ProviderName, vpnProtocol: VPNProtocolType) -> Date? + + func categories(_ name: ProviderName, vpnProtocol: VPNProtocolType) -> [ProviderCategory] + + func servers(forLocation location: ProviderLocation) -> [ProviderServer] + + func server(_ name: ProviderName, vpnProtocol: VPNProtocolType, apiId: String) -> ProviderServer? + + func anyDefaultServer(_ name: ProviderName, vpnProtocol: VPNProtocolType) -> ProviderServer? + + func server(withId id: String) -> ProviderServer? + + func fetchProvidersIndexPublisher(priority: ProviderManagerFetchPriority) -> AnyPublisher + + func fetchProviderPublisher( + withName providerName: ProviderName, + vpnProtocol: VPNProtocolType, + priority: ProviderManagerFetchPriority + ) -> AnyPublisher + + func reset() +} diff --git a/PassepartoutLibrary/Sources/PassepartoutCore/Managers/ProviderManagerFetchPriority.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Managers/ProviderManagerFetchPriority.swift new file mode 100644 index 00000000..893a2564 --- /dev/null +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Managers/ProviderManagerFetchPriority.swift @@ -0,0 +1,34 @@ +// +// ProviderManagerFetchPriority.swift +// Passepartout +// +// Created by Davide De Rosa on 6/22/22. +// Copyright (c) 2022 Davide De Rosa. All rights reserved. +// +// https://github.com/passepartoutvpn +// +// This file is part of Passepartout. +// +// Passepartout is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Passepartout is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Passepartout. If not, see . +// + +import Foundation + +public enum ProviderManagerFetchPriority { + case bundle + + case remote + + case remoteThenBundle +} diff --git a/PassepartoutLibrary/Sources/PassepartoutCore/Managers/VPNManager.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Managers/VPNManager.swift new file mode 100644 index 00000000..599fb27e --- /dev/null +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Managers/VPNManager.swift @@ -0,0 +1,61 @@ +// +// VPNManager.swift +// Passepartout +// +// Created by Davide De Rosa on 6/22/22. +// Copyright (c) 2022 Davide De Rosa. All rights reserved. +// +// https://github.com/passepartoutvpn +// +// This file is part of Passepartout. +// +// Passepartout is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Passepartout is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Passepartout. If not, see . +// + +import Foundation +import Combine + +public protocol VPNManager { + var lastError: Error? { get } + + var configurationError: PassthroughSubject { get } + + var tunnelLogPath: String? { get set } + + var tunnelLogFormat: String? { get set } + + var masksPrivateData: Bool { get set } + + func connectWithActiveProfile() async throws + + @discardableResult + func connect(with profileId: UUID) async throws -> Profile + + @discardableResult + func connect(with profileId: UUID, toServer newServerId: String) async throws -> Profile + + func modifyActiveProfile(_ block: (inout Profile) -> Void) async throws + + func toggle() -> Bool + + func disable() async + + func uninstall() async + + func serverConfiguration(forProtocol vpnProtocol: VPNProtocolType) -> Any? + + func debugLogURL(forProtocol vpnProtocol: VPNProtocolType) -> URL? + + func observeUpdates() +} diff --git a/PassepartoutLibrary/Sources/PassepartoutCore/Managers/VPNManagerWithCurrentState.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Managers/VPNManagerWithCurrentState.swift new file mode 100644 index 00000000..009f64ac --- /dev/null +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Managers/VPNManagerWithCurrentState.swift @@ -0,0 +1,29 @@ +// +// VPNManagerWithCurrentState.swift +// Passepartout +// +// Created by Davide De Rosa on 6/22/22. +// Copyright (c) 2022 Davide De Rosa. All rights reserved. +// +// https://github.com/passepartoutvpn +// +// This file is part of Passepartout. +// +// Passepartout is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Passepartout is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Passepartout. If not, see . +// + +import Foundation + +public protocol VPNManagerWithCurrentState: VPNManager, CurrentVPNStateProviding { +} diff --git a/PassepartoutCore/Sources/PassepartoutProviders/Models/CredentialsPurpose.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Models/CredentialsPurpose.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutProviders/Models/CredentialsPurpose.swift rename to PassepartoutLibrary/Sources/PassepartoutCore/Models/CredentialsPurpose.swift diff --git a/PassepartoutCore/Sources/PassepartoutCore/Models/DebugLog.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Models/DebugLog.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutCore/Models/DebugLog.swift rename to PassepartoutLibrary/Sources/PassepartoutCore/Models/DebugLog.swift diff --git a/PassepartoutCore/Sources/PassepartoutProfiles/DataModels/Network.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Models/Network.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutProfiles/DataModels/Network.swift rename to PassepartoutLibrary/Sources/PassepartoutCore/Models/Network.swift diff --git a/PassepartoutCore/Sources/PassepartoutProfiles/DataModels/Profile+Account.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+Account.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutProfiles/DataModels/Profile+Account.swift rename to PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+Account.swift diff --git a/PassepartoutCore/Sources/PassepartoutProfiles/DataModels/Profile+Header.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+Header.swift similarity index 98% rename from PassepartoutCore/Sources/PassepartoutProfiles/DataModels/Profile+Header.swift rename to PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+Header.swift index 6c959e57..6dde4289 100644 --- a/PassepartoutCore/Sources/PassepartoutProfiles/DataModels/Profile+Header.swift +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+Header.swift @@ -24,7 +24,6 @@ // import Foundation -import PassepartoutProviders extension Profile { public struct Header: Codable, Identifiable, Hashable { diff --git a/PassepartoutCore/Sources/PassepartoutProfiles/DataModels/Profile+Host.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+Host.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutProfiles/DataModels/Profile+Host.swift rename to PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+Host.swift diff --git a/PassepartoutCore/Sources/PassepartoutProfiles/DataModels/Profile+NetworkSettings.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+NetworkSettings.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutProfiles/DataModels/Profile+NetworkSettings.swift rename to PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+NetworkSettings.swift diff --git a/PassepartoutCore/Sources/PassepartoutProfiles/DataModels/Profile+OnDemand.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+OnDemand.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutProfiles/DataModels/Profile+OnDemand.swift rename to PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+OnDemand.swift diff --git a/PassepartoutCore/Sources/PassepartoutProfiles/DataModels/Profile+OpenVPNSettings.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+OpenVPNSettings.swift similarity index 91% rename from PassepartoutCore/Sources/PassepartoutProfiles/DataModels/Profile+OpenVPNSettings.swift rename to PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+OpenVPNSettings.swift index d15f10b9..04cfb709 100644 --- a/PassepartoutCore/Sources/PassepartoutProfiles/DataModels/Profile+OpenVPNSettings.swift +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+OpenVPNSettings.swift @@ -25,7 +25,6 @@ import Foundation import TunnelKitOpenVPN -import PassepartoutProviders extension Profile { public struct OpenVPNSettings: Codable, Equatable, VPNProtocolProviding { @@ -38,5 +37,9 @@ extension Profile { public var account: Profile.Account? public var customEndpoint: Endpoint? + + public init(configuration: OpenVPN.Configuration) { + self.configuration = configuration + } } } diff --git a/PassepartoutCore/Sources/PassepartoutProfiles/DataModels/Profile+Provider.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+Provider.swift similarity index 98% rename from PassepartoutCore/Sources/PassepartoutProfiles/DataModels/Profile+Provider.swift rename to PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+Provider.swift index c7c32894..fea44db1 100644 --- a/PassepartoutCore/Sources/PassepartoutProfiles/DataModels/Profile+Provider.swift +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+Provider.swift @@ -24,7 +24,6 @@ // import Foundation -import PassepartoutProviders import TunnelKitCore extension Profile { diff --git a/PassepartoutCore/Sources/PassepartoutProfiles/DataModels/Profile+WireGuardSettings.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+WireGuardSettings.swift similarity index 91% rename from PassepartoutCore/Sources/PassepartoutProfiles/DataModels/Profile+WireGuardSettings.swift rename to PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+WireGuardSettings.swift index 8e873fc5..1004aaec 100644 --- a/PassepartoutCore/Sources/PassepartoutProfiles/DataModels/Profile+WireGuardSettings.swift +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile+WireGuardSettings.swift @@ -25,7 +25,6 @@ import Foundation import TunnelKitWireGuard -import PassepartoutProviders extension Profile { public struct WireGuardSettings: Codable, Equatable, VPNProtocolProviding { @@ -34,5 +33,9 @@ extension Profile { } public var configuration: WireGuard.Configuration + + public init(configuration: WireGuard.Configuration) { + self.configuration = configuration + } } } diff --git a/PassepartoutCore/Sources/PassepartoutProfiles/DataModels/Profile.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile.swift similarity index 95% rename from PassepartoutCore/Sources/PassepartoutProfiles/DataModels/Profile.swift rename to PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile.swift index c5f4f413..9b3fb782 100644 --- a/PassepartoutCore/Sources/PassepartoutProfiles/DataModels/Profile.swift +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Models/Profile.swift @@ -24,14 +24,11 @@ // import Foundation -import PassepartoutProviders import TunnelKitOpenVPN import TunnelKitWireGuard public protocol ProfileSubtype { var vpnProtocols: [VPNProtocolType] { get } - - func requiresCredentials(forProtocol vpnProtocol: VPNProtocolType) -> Bool } public struct Profile: Identifiable, Codable, Equatable { @@ -103,7 +100,7 @@ public struct Profile: Identifiable, Codable, Equatable { } public init(_ header: Header, provider: Profile.Provider) { - guard let firstVPNProtocol = provider.vpnProtocols.first else { + guard let firstVPNProtocol = provider.vpnSettings.keys.first else { fatalError("No VPN protocols defined in provider") } self.header = header diff --git a/PassepartoutCore/Sources/PassepartoutProviders/Models/ProviderCategory.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Models/ProviderCategory.swift similarity index 77% rename from PassepartoutCore/Sources/PassepartoutProviders/Models/ProviderCategory.swift rename to PassepartoutLibrary/Sources/PassepartoutCore/Models/ProviderCategory.swift index eaf18692..aaf90311 100644 --- a/PassepartoutCore/Sources/PassepartoutProviders/Models/ProviderCategory.swift +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Models/ProviderCategory.swift @@ -24,7 +24,6 @@ // import Foundation -import PassepartoutUtils public struct ProviderCategory { public let providerMetadata: ProviderMetadata @@ -34,4 +33,16 @@ public struct ProviderCategory { public let name: String public let locations: [ProviderLocation] + + public init( + providerMetadata: ProviderMetadata, + vpnProtocol: VPNProtocolType, + name: String, + locations: [ProviderLocation] + ) { + self.providerMetadata = providerMetadata + self.vpnProtocol = vpnProtocol + self.name = name + self.locations = locations + } } diff --git a/PassepartoutCore/Sources/PassepartoutProviders/Models/ProviderLocation.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Models/ProviderLocation.swift similarity index 76% rename from PassepartoutCore/Sources/PassepartoutProviders/Models/ProviderLocation.swift rename to PassepartoutLibrary/Sources/PassepartoutCore/Models/ProviderLocation.swift index cbaf724e..6e1aec25 100644 --- a/PassepartoutCore/Sources/PassepartoutProviders/Models/ProviderLocation.swift +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Models/ProviderLocation.swift @@ -24,7 +24,6 @@ // import Foundation -import PassepartoutUtils public struct ProviderLocation { public let providerMetadata: ProviderMetadata @@ -36,4 +35,12 @@ public struct ProviderLocation { public let countryCode: String public let onlyServer: ProviderServer? + + public init(providerMetadata: ProviderMetadata, vpnProtocol: VPNProtocolType, categoryName: String, countryCode: String, onlyServer: ProviderServer?) { + self.providerMetadata = providerMetadata + self.vpnProtocol = vpnProtocol + self.categoryName = categoryName + self.countryCode = countryCode + self.onlyServer = onlyServer + } } diff --git a/PassepartoutLibrary/Sources/PassepartoutCore/Models/ProviderMetadata.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Models/ProviderMetadata.swift new file mode 100644 index 00000000..c8a5cbeb --- /dev/null +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Models/ProviderMetadata.swift @@ -0,0 +1,40 @@ +// +// ProviderMetadata.swift +// Passepartout +// +// Created by Davide De Rosa on 3/15/22. +// Copyright (c) 2022 Davide De Rosa. All rights reserved. +// +// https://github.com/passepartoutvpn +// +// This file is part of Passepartout. +// +// Passepartout is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Passepartout is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Passepartout. If not, see . +// + +import Foundation + +public struct ProviderMetadata { + public let name: String + + public let fullName: String + + public let supportedVPNProtocols: [VPNProtocolType] + + public init(name: String, fullName: String, supportedVPNProtocols: [VPNProtocolType]) { + self.name = name + self.fullName = fullName + self.supportedVPNProtocols = supportedVPNProtocols + } +} diff --git a/PassepartoutCore/Sources/PassepartoutProviders/Models/ProviderName.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Models/ProviderName.swift similarity index 92% rename from PassepartoutCore/Sources/PassepartoutProviders/Models/ProviderName.swift rename to PassepartoutLibrary/Sources/PassepartoutCore/Models/ProviderName.swift index 33917b59..231c20ba 100644 --- a/PassepartoutCore/Sources/PassepartoutProviders/Models/ProviderName.swift +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Models/ProviderName.swift @@ -24,6 +24,5 @@ // import Foundation -import PassepartoutServices -public typealias ProviderName = WSProviderName +public typealias ProviderName = String diff --git a/PassepartoutCore/Sources/PassepartoutProviders/Models/ProviderServer.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Models/ProviderServer.swift similarity index 60% rename from PassepartoutCore/Sources/PassepartoutProviders/Models/ProviderServer.swift rename to PassepartoutLibrary/Sources/PassepartoutCore/Models/ProviderServer.swift index 73311d4a..9825549f 100644 --- a/PassepartoutCore/Sources/PassepartoutProviders/Models/ProviderServer.swift +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Models/ProviderServer.swift @@ -25,8 +25,6 @@ import Foundation import GenericJSON -import CryptoKit -import PassepartoutUtils public struct ProviderServer: Identifiable { public struct Preset { @@ -39,6 +37,14 @@ public struct ProviderServer: Identifiable { public let vpnProtocol: VPNProtocolType public let vpnConfiguration: JSON + + public init(id: String, name: String, comment: String, vpnProtocol: VPNProtocolType, vpnConfiguration: JSON) { + self.id = id + self.name = name + self.comment = comment + self.vpnProtocol = vpnProtocol + self.vpnConfiguration = vpnConfiguration + } } public let providerMetadata: ProviderMetadata @@ -63,24 +69,31 @@ public struct ProviderServer: Identifiable { public let presetIds: [String] - public internal(set) var presets: [Preset]? + public private(set) var presets: [Preset]? + + public init(providerMetadata: ProviderMetadata, id: String, apiId: String, categoryName: String, countryCode: String, extraCountryCodes: [String]?, serverIndex: Int?, details: String?, hostname: String?, ipAddresses: [String], presetIds: [String]) { + self.providerMetadata = providerMetadata + self.id = id + self.apiId = apiId + self.categoryName = categoryName + self.countryCode = countryCode + self.extraCountryCodes = extraCountryCodes + self.serverIndex = serverIndex + self.details = details + self.hostname = hostname + self.ipAddresses = ipAddresses + self.presetIds = presetIds + } public func preset(withId presetId: String) -> Preset? { return presets?.first { $0.id == presetId } } -} - -extension ProviderServer { - public static func id(withName providerName: ProviderName, vpnProtocol: VPNProtocolType, apiId: String) -> String? { - let idSource = "\(providerName):\(vpnProtocol.rawValue):\(apiId)" - guard let data = idSource.data(using: .utf8) else { - return nil - } - let sha = SHA256.hash(data: data) - return sha.map { - String(format: "%02X", $0) - }.joined() + + public func withPresets(_ presets: [Preset]?) -> Self { + var copy = self + copy.presets = presets + return copy } } diff --git a/PassepartoutLibrary/Sources/PassepartoutCore/Models/VPNConfiguration.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Models/VPNConfiguration.swift new file mode 100644 index 00000000..bc0b721d --- /dev/null +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Models/VPNConfiguration.swift @@ -0,0 +1,30 @@ +// +// VPNConfiguration.swift +// Passepartout +// +// Created by Davide De Rosa on 3/7/22. +// Copyright (c) 2022 Davide De Rosa. All rights reserved. +// +// https://github.com/passepartoutvpn +// +// This file is part of Passepartout. +// +// Passepartout is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Passepartout is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Passepartout. If not, see . +// + +import Foundation +import TunnelKitManager +import NetworkExtension + +public typealias VPNConfiguration = (neConfiguration: NetworkExtensionConfiguration, neExtra: NetworkExtensionExtra?) diff --git a/PassepartoutCore/Sources/PassepartoutProviders/Models/ProviderMetadata.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Models/VPNConfigurationError.swift similarity index 84% rename from PassepartoutCore/Sources/PassepartoutProviders/Models/ProviderMetadata.swift rename to PassepartoutLibrary/Sources/PassepartoutCore/Models/VPNConfigurationError.swift index b67df478..b0938394 100644 --- a/PassepartoutCore/Sources/PassepartoutProviders/Models/ProviderMetadata.swift +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Models/VPNConfigurationError.swift @@ -1,8 +1,8 @@ // -// ProviderMetadata.swift +// VPNConfigurationError.swift // Passepartout // -// Created by Davide De Rosa on 3/15/22. +// Created by Davide De Rosa on 3/7/22. // Copyright (c) 2022 Davide De Rosa. All rights reserved. // // https://github.com/passepartoutvpn @@ -24,6 +24,5 @@ // import Foundation -import PassepartoutServices -public typealias ProviderMetadata = WSProvidersIndex.Metadata +public typealias VPNConfigurationError = (profile: Profile, error: Error) diff --git a/PassepartoutCore/Sources/PassepartoutProviders/Models/VPNProtocolType.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Models/VPNProtocolType.swift similarity index 74% rename from PassepartoutCore/Sources/PassepartoutProviders/Models/VPNProtocolType.swift rename to PassepartoutLibrary/Sources/PassepartoutCore/Models/VPNProtocolType.swift index c086d260..073a1810 100644 --- a/PassepartoutCore/Sources/PassepartoutProviders/Models/VPNProtocolType.swift +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Models/VPNProtocolType.swift @@ -24,14 +24,25 @@ // import Foundation -import PassepartoutServices -public typealias VPNProtocolType = WSVPNProtocol - -extension VPNProtocolType { - public static let allTypes: [VPNProtocolType] = [.openVPN, .wireGuard] +public enum VPNProtocolType: String, Codable { + case openVPN = "ovpn" + + case wireGuard = "wg" } public protocol VPNProtocolProviding { var vpnProtocol: VPNProtocolType { get } } + +extension VPNProtocolType: CustomStringConvertible { + public var description: String { + switch self { + case .openVPN: + return "OpenVPN" + + case .wireGuard: + return "WireGuard" + } + } +} diff --git a/PassepartoutLibrary/Sources/PassepartoutCore/Models/WrappedProfile.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Models/WrappedProfile.swift new file mode 100644 index 00000000..17627c43 --- /dev/null +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Models/WrappedProfile.swift @@ -0,0 +1,41 @@ +// +// WrappedProfile.swift +// Passepartout +// +// Created by Davide De Rosa on 3/27/22. +// Copyright (c) 2022 Davide De Rosa. All rights reserved. +// +// https://github.com/passepartoutvpn +// +// This file is part of Passepartout. +// +// Passepartout is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Passepartout is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Passepartout. If not, see . +// + +import Foundation + +public protocol WrappedProfile { + var isLoading: Bool { get } + + var value: Profile { get } +} + +extension WrappedProfile { + public var name: String { + guard !isLoading && !value.isPlaceholder else { + return "" + } + return value.header.name + } +} diff --git a/PassepartoutLibrary/Sources/PassepartoutCore/Models/WrappedVPNState.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Models/WrappedVPNState.swift new file mode 100644 index 00000000..9e3fc36c --- /dev/null +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Models/WrappedVPNState.swift @@ -0,0 +1,38 @@ +// +// WrappedVPNState.swift +// Passepartout +// +// Created by Davide De Rosa on 6/21/22. +// Copyright (c) 2022 Davide De Rosa. All rights reserved. +// +// https://github.com/passepartoutvpn +// +// This file is part of Passepartout. +// +// Passepartout is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Passepartout is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Passepartout. If not, see . +// + +import Foundation +import TunnelKitCore +import TunnelKitManager + +public protocol WrappedVPNState { + var isEnabled: Bool { get } + + var vpnStatus: VPNStatus { get } + + var lastError: Error? { get } + + var dataCount: DataCount? { get } +} diff --git a/PassepartoutCore/Sources/PassepartoutUtils/PassepartoutDataModels.swift b/PassepartoutLibrary/Sources/PassepartoutCore/PassepartoutDataModels.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutUtils/PassepartoutDataModels.swift rename to PassepartoutLibrary/Sources/PassepartoutCore/PassepartoutDataModels.swift diff --git a/PassepartoutCore/Sources/PassepartoutUtils/PassepartoutError.swift b/PassepartoutLibrary/Sources/PassepartoutCore/PassepartoutError.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutUtils/PassepartoutError.swift rename to PassepartoutLibrary/Sources/PassepartoutCore/PassepartoutError.swift diff --git a/PassepartoutCore/Sources/PassepartoutCore/Exports.swift b/PassepartoutLibrary/Sources/PassepartoutLibrary/Exports.swift similarity index 61% rename from PassepartoutCore/Sources/PassepartoutCore/Exports.swift rename to PassepartoutLibrary/Sources/PassepartoutLibrary/Exports.swift index cbad96f0..9717d973 100644 --- a/PassepartoutCore/Sources/PassepartoutCore/Exports.swift +++ b/PassepartoutLibrary/Sources/PassepartoutLibrary/Exports.swift @@ -1,5 +1,8 @@ +@_exported import PassepartoutVPN @_exported import PassepartoutProfiles @_exported import PassepartoutProviders +@_exported import PassepartoutServices @_exported import PassepartoutUtils +@_exported import PassepartoutCore @_exported import TunnelKit @_exported import TunnelKitCore diff --git a/PassepartoutCore/Sources/PassepartoutCore/Extensions/DebugLog+Decorated.swift b/PassepartoutLibrary/Sources/PassepartoutLibrary/Extensions/DebugLog+Extensions.swift similarity index 98% rename from PassepartoutCore/Sources/PassepartoutCore/Extensions/DebugLog+Decorated.swift rename to PassepartoutLibrary/Sources/PassepartoutLibrary/Extensions/DebugLog+Extensions.swift index 9b040610..ad43717b 100644 --- a/PassepartoutCore/Sources/PassepartoutCore/Extensions/DebugLog+Decorated.swift +++ b/PassepartoutLibrary/Sources/PassepartoutLibrary/Extensions/DebugLog+Extensions.swift @@ -1,5 +1,5 @@ // -// DebugLog+Decorated.swift +// DebugLog+Extensions.swift // Passepartout // // Created by Davide De Rosa on 3/14/22. diff --git a/PassepartoutCore/Sources/PassepartoutCore/Managers/UpgradeManager+Migrations.swift b/PassepartoutLibrary/Sources/PassepartoutLibrary/Managers/UpgradeManager+Migrations.swift similarity index 99% rename from PassepartoutCore/Sources/PassepartoutCore/Managers/UpgradeManager+Migrations.swift rename to PassepartoutLibrary/Sources/PassepartoutLibrary/Managers/UpgradeManager+Migrations.swift index 3610bdb9..689ca634 100644 --- a/PassepartoutCore/Sources/PassepartoutCore/Managers/UpgradeManager+Migrations.swift +++ b/PassepartoutLibrary/Sources/PassepartoutLibrary/Managers/UpgradeManager+Migrations.swift @@ -28,6 +28,7 @@ import GenericJSON import TunnelKitCore import TunnelKitOpenVPNCore import TunnelKitManager +import PassepartoutCore import PassepartoutUtils private typealias Map = [String: Any] diff --git a/PassepartoutCore/Sources/PassepartoutCore/Managers/UpgradeManager.swift b/PassepartoutLibrary/Sources/PassepartoutLibrary/Managers/UpgradeManager.swift similarity index 99% rename from PassepartoutCore/Sources/PassepartoutCore/Managers/UpgradeManager.swift rename to PassepartoutLibrary/Sources/PassepartoutLibrary/Managers/UpgradeManager.swift index 1458da96..d54ed835 100644 --- a/PassepartoutCore/Sources/PassepartoutCore/Managers/UpgradeManager.swift +++ b/PassepartoutLibrary/Sources/PassepartoutLibrary/Managers/UpgradeManager.swift @@ -26,9 +26,9 @@ import Foundation import CoreData import SwiftyBeaver +import PassepartoutCore import PassepartoutUtils -@MainActor public class UpgradeManager: ObservableObject { // MARK: Initialization diff --git a/PassepartoutCore/Sources/PassepartoutProfiles/DataModels/CDProfile+CoreDataClass.swift b/PassepartoutLibrary/Sources/PassepartoutProfiles/DataModels/CDProfile+CoreDataClass.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutProfiles/DataModels/CDProfile+CoreDataClass.swift rename to PassepartoutLibrary/Sources/PassepartoutProfiles/DataModels/CDProfile+CoreDataClass.swift diff --git a/PassepartoutCore/Sources/PassepartoutProfiles/DataModels/CDProfile+CoreDataProperties.swift b/PassepartoutLibrary/Sources/PassepartoutProfiles/DataModels/CDProfile+CoreDataProperties.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutProfiles/DataModels/CDProfile+CoreDataProperties.swift rename to PassepartoutLibrary/Sources/PassepartoutProfiles/DataModels/CDProfile+CoreDataProperties.swift diff --git a/PassepartoutCore/Sources/PassepartoutProfiles/Profiles.xcdatamodeld/Model.xcdatamodel/contents b/PassepartoutLibrary/Sources/PassepartoutProfiles/DataModels/Profiles.xcdatamodeld/Model.xcdatamodel/contents similarity index 100% rename from PassepartoutCore/Sources/PassepartoutProfiles/Profiles.xcdatamodeld/Model.xcdatamodel/contents rename to PassepartoutLibrary/Sources/PassepartoutProfiles/DataModels/Profiles.xcdatamodeld/Model.xcdatamodel/contents diff --git a/PassepartoutCore/Sources/PassepartoutProfiles/Extensions/OpenVPNSettings+Network.swift b/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/OpenVPNSettings+Network.swift similarity index 99% rename from PassepartoutCore/Sources/PassepartoutProfiles/Extensions/OpenVPNSettings+Network.swift rename to PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/OpenVPNSettings+Network.swift index 9baf8767..2f29c240 100644 --- a/PassepartoutCore/Sources/PassepartoutProfiles/Extensions/OpenVPNSettings+Network.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/OpenVPNSettings+Network.swift @@ -26,6 +26,7 @@ import Foundation import TunnelKitCore import TunnelKitOpenVPN +import PassepartoutCore extension Profile.OpenVPNSettings: GatewaySettingsProviding { diff --git a/PassepartoutCore/Sources/PassepartoutProfiles/PassepartoutProfiles.swift b/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/PassepartoutDataModels+Profiles.swift similarity index 79% rename from PassepartoutCore/Sources/PassepartoutProfiles/PassepartoutProfiles.swift rename to PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/PassepartoutDataModels+Profiles.swift index f281e5e5..fd8a9fea 100644 --- a/PassepartoutCore/Sources/PassepartoutProfiles/PassepartoutProfiles.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/PassepartoutDataModels+Profiles.swift @@ -1,5 +1,5 @@ // -// PassepartoutProfiles.swift +// PassepartoutDataModels+Profiles.swift // Passepartout // // Created by Davide De Rosa on 4/7/22. @@ -25,15 +25,7 @@ import Foundation import CoreData -import PassepartoutUtils - -extension PassepartoutError { - public static let missingProfile = Self("missingProfile") - - public static let missingProviderServer = Self("missingProviderServer") - - public static let missingProviderPreset = Self("missingProviderPreset") -} +import PassepartoutCore extension PassepartoutDataModels { public static let profiles: NSManagedObjectModel = { diff --git a/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/PassepartoutError+Profiles.swift b/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/PassepartoutError+Profiles.swift new file mode 100644 index 00000000..90254893 --- /dev/null +++ b/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/PassepartoutError+Profiles.swift @@ -0,0 +1,31 @@ +// +// PassepartoutError+Profiles.swift +// Passepartout +// +// Created by Davide De Rosa on 6/21/22. +// Copyright (c) 2022 Davide De Rosa. All rights reserved. +// +// https://github.com/passepartoutvpn +// +// This file is part of Passepartout. +// +// Passepartout is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Passepartout is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Passepartout. If not, see . +// + +import Foundation +import PassepartoutCore + +extension PassepartoutError { + public static let missingProfile = Self("missingProfile") +} diff --git a/PassepartoutCore/Sources/PassepartoutProfiles/Extensions/PassepartoutProfiles+Logging.swift b/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/PassepartoutProfiles+Logging.swift similarity index 97% rename from PassepartoutCore/Sources/PassepartoutProfiles/Extensions/PassepartoutProfiles+Logging.swift rename to PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/PassepartoutProfiles+Logging.swift index d7d0977a..fde64bf7 100644 --- a/PassepartoutCore/Sources/PassepartoutProfiles/Extensions/PassepartoutProfiles+Logging.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/PassepartoutProfiles+Logging.swift @@ -24,6 +24,7 @@ // import Foundation +import PassepartoutCore extension Profile.Header { public var logDescription: String { diff --git a/PassepartoutCore/Sources/PassepartoutProfiles/Extensions/PassepartoutProfiles+StrippableContent.swift b/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/PassepartoutProfiles+StrippableContent.swift similarity index 98% rename from PassepartoutCore/Sources/PassepartoutProfiles/Extensions/PassepartoutProfiles+StrippableContent.swift rename to PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/PassepartoutProfiles+StrippableContent.swift index e416641d..2ae315ca 100644 --- a/PassepartoutCore/Sources/PassepartoutProfiles/Extensions/PassepartoutProfiles+StrippableContent.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/PassepartoutProfiles+StrippableContent.swift @@ -24,6 +24,7 @@ // import Foundation +import PassepartoutCore import PassepartoutUtils extension Profile.Account: StrippableContent { diff --git a/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/PassepartoutProfiles+Subtype.swift b/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/PassepartoutProfiles+Subtype.swift new file mode 100644 index 00000000..26a87a4e --- /dev/null +++ b/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/PassepartoutProfiles+Subtype.swift @@ -0,0 +1,76 @@ +// +// PassepartoutProfiles+Subtype.swift +// Passepartout +// +// Created by Davide De Rosa on 6/20/22. +// Copyright (c) 2022 Davide De Rosa. All rights reserved. +// +// https://github.com/passepartoutvpn +// +// This file is part of Passepartout. +// +// Passepartout is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Passepartout is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Passepartout. If not, see . +// + +import Foundation +import PassepartoutCore +import PassepartoutProviders +import PassepartoutCore + +extension Profile { + public var requiresCredentials: Bool { + if let providerName = providerName { + return providerName.requiresCredentials(forProtocol: currentVPNProtocol) + } else { + return currentVPNProtocol == .openVPN && (hostOpenVPNSettings?.configuration.authUserPass ?? false) + } + } +} + +extension Profile { + public func providerOpenVPNSettings(withManager providerManager: ProviderManager) throws -> Profile.OpenVPNSettings { + guard isProvider else { + fatalError("Not a provider") + } + + // infer remotes from preset + server + guard let server = providerServer(providerManager) else { + throw PassepartoutError.missingProviderServer + } + guard let preset = providerPreset(server) else { + throw PassepartoutError.missingProviderPreset + } + guard var builder = preset.openVPNConfiguration?.builder() else { + fatalError("Preset \(preset.id) has no OpenVPN configuration") + } + try builder.setRemotes(from: preset, with: server, excludingHostname: !networkSettings.resolvesHostname) + + // enforce default gateway + builder.routingPolicies = [.IPv4, .IPv6] + + // apply provider settings (username, custom endpoint) + let cfg = builder.build() + var settings = OpenVPNSettings(configuration: cfg) + settings.account = providerAccount() + settings.customEndpoint = providerCustomEndpoint() + return settings + } + + public func providerWireGuardSettings(withManager providerManager: ProviderManager) throws -> Profile.WireGuardSettings { + guard isProvider else { + fatalError("Not a provider") + } + fatalError("WireGuard not yet implemented for providers") + } +} diff --git a/PassepartoutCore/Sources/PassepartoutProfiles/Extensions/PassepartoutProviders+TunnelKit.swift b/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/PassepartoutProviders+TunnelKit.swift similarity index 99% rename from PassepartoutCore/Sources/PassepartoutProfiles/Extensions/PassepartoutProviders+TunnelKit.swift rename to PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/PassepartoutProviders+TunnelKit.swift index 795f09e0..ae9386dd 100644 --- a/PassepartoutCore/Sources/PassepartoutProfiles/Extensions/PassepartoutProviders+TunnelKit.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/PassepartoutProviders+TunnelKit.swift @@ -27,7 +27,7 @@ import Foundation import Combine import TunnelKitOpenVPN import TunnelKitWireGuard -import PassepartoutProviders +import PassepartoutCore import PassepartoutUtils extension ProviderServer.Preset { diff --git a/PassepartoutCore/Sources/PassepartoutProfiles/Extensions/Profile+Extensions.swift b/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/Profile+Extensions.swift similarity index 68% rename from PassepartoutCore/Sources/PassepartoutProfiles/Extensions/Profile+Extensions.swift rename to PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/Profile+Extensions.swift index 489ff099..32789fd8 100644 --- a/PassepartoutCore/Sources/PassepartoutProfiles/Extensions/Profile+Extensions.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/Profile+Extensions.swift @@ -2,7 +2,7 @@ // Profile+Extensions.swift // Passepartout // -// Created by Davide De Rosa on 3/13/22. +// Created by Davide De Rosa on 6/20/22. // Copyright (c) 2022 Davide De Rosa. All rights reserved. // // https://github.com/passepartoutvpn @@ -24,49 +24,8 @@ // import Foundation -import PassepartoutProviders +import PassepartoutCore import PassepartoutUtils -import TunnelKitOpenVPN -import TunnelKitWireGuard - -extension Profile { - public var isProvider: Bool { - return provider != nil - } - - public var vpnProtocols: [VPNProtocolType] { - if isProvider { - return provider?.vpnProtocols ?? [] - } else { - return host?.vpnProtocols ?? [] - } - } - - public var requiresCredentials: Bool { - if isProvider { - return provider?.requiresCredentials(forProtocol: currentVPNProtocol) ?? false - } else { - return host?.requiresCredentials(forProtocol: currentVPNProtocol) ?? false - } - } - - public var account: Profile.Account { - get { - if isProvider { - return providerAccount() ?? .init() - } else { - return hostAccount() ?? .init() - } - } - set { - if isProvider { - setProviderAccount(newValue) - } else { - setHostAccount(newValue) - } - } - } -} extension Profile.Header { public func withNewId() -> Self { diff --git a/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/ProfileManager+Extensions.swift b/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/ProfileManager+Extensions.swift new file mode 100644 index 00000000..faee21d0 --- /dev/null +++ b/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/ProfileManager+Extensions.swift @@ -0,0 +1,75 @@ +// +// ProfileManager+Extensions.swift +// Passepartout +// +// Created by Davide De Rosa on 6/22/22. +// Copyright (c) 2022 Davide De Rosa. All rights reserved. +// +// https://github.com/passepartoutvpn +// +// This file is part of Passepartout. +// +// Passepartout is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Passepartout is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Passepartout. If not, see . +// + +import Foundation +import PassepartoutCore + +extension ProfileManager { + public var hasProfiles: Bool { + !headers.isEmpty + } + + public var activeProfile: Profile? { + guard let id = activeProfileId else { + return nil + } + return (try? liveProfileEx(withId: id))?.profile + } + + public var hasActiveProfile: Bool { + activeProfileId != nil + } + + public func isActiveProfile(_ id: UUID) -> Bool { + id == activeProfileId + } + + public func activateProfile(_ profile: Profile) { + saveProfile(profile, isActive: true, updateIfCurrent: true) + } + + public func saveProfile(_ profile: Profile, isActive: Bool?) { + saveProfile(profile, isActive: isActive, updateIfCurrent: true) + } + + public func profile(withHeader header: Profile.Header, fromURL url: URL, passphrase: String?) throws -> Profile { + let contents = try String(contentsOf: url) + return try profile(withHeader: header, fromContents: contents, originalURL: url, passphrase: passphrase) + } +} + +extension ProfileManagerWithCurrentProfile { + public func isCurrentProfileActive() -> Bool { + currentProfile.value.id == activeProfileId + } + + public func isCurrentProfile(_ id: UUID) -> Bool { + id == currentProfile.value.id + } + + public func activateCurrentProfile() { + saveProfile(currentProfile.value, isActive: true, updateIfCurrent: false) + } +} diff --git a/PassepartoutCore/Sources/PassepartoutProfiles/Extensions/ProviderManager+Extensions.swift b/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/ProviderManager+Extensions.swift similarity index 91% rename from PassepartoutCore/Sources/PassepartoutProfiles/Extensions/ProviderManager+Extensions.swift rename to PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/ProviderManager+Extensions.swift index d46a2297..bb2e3114 100644 --- a/PassepartoutCore/Sources/PassepartoutProfiles/Extensions/ProviderManager+Extensions.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/ProviderManager+Extensions.swift @@ -25,15 +25,15 @@ import Foundation import Combine -import PassepartoutProviders +import PassepartoutCore extension ProviderManager { public func fetchRemoteProviderPublisher(forProfile profile: Profile) -> AnyPublisher { - guard let provider = profile.provider else { + guard let providerName = profile.providerName else { fatalError("Not a provider") } return fetchProviderPublisher( - withName: provider.name, + withName: providerName, vpnProtocol: profile.currentVPNProtocol, priority: .remote ) diff --git a/PassepartoutCore/Sources/PassepartoutProfiles/Extensions/WireGuardSettings+Network.swift b/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/WireGuardSettings+Network.swift similarity index 98% rename from PassepartoutCore/Sources/PassepartoutProfiles/Extensions/WireGuardSettings+Network.swift rename to PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/WireGuardSettings+Network.swift index de379824..9dd128a9 100644 --- a/PassepartoutCore/Sources/PassepartoutProfiles/Extensions/WireGuardSettings+Network.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProfiles/Extensions/WireGuardSettings+Network.swift @@ -26,6 +26,7 @@ import Foundation import TunnelKitCore import TunnelKitWireGuard +import PassepartoutCore extension Profile.WireGuardSettings: DNSSettingsProviding { public var dnsProtocol: DNSProtocol? { diff --git a/PassepartoutLibrary/Sources/PassepartoutProfiles/Managers/CoreDataProfileManagerStrategy.swift b/PassepartoutLibrary/Sources/PassepartoutProfiles/Managers/CoreDataProfileManagerStrategy.swift new file mode 100644 index 00000000..b131f2a7 --- /dev/null +++ b/PassepartoutLibrary/Sources/PassepartoutProfiles/Managers/CoreDataProfileManagerStrategy.swift @@ -0,0 +1,65 @@ +// +// CoreDataProfileManagerStrategy.swift +// Passepartout +// +// Created by Davide De Rosa on 4/9/22. +// Copyright (c) 2022 Davide De Rosa. All rights reserved. +// +// https://github.com/passepartoutvpn +// +// This file is part of Passepartout. +// +// Passepartout is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Passepartout is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Passepartout. If not, see . +// + +import Foundation +import Combine +import PassepartoutCore +import PassepartoutUtils + +public class CoreDataProfileManagerStrategy: ProfileManagerStrategy { + private let profileRepository: ProfileRepository + + private let fetchedHeaders: FetchedValueHolder<[UUID: Profile.Header]> + + public init(persistence: Persistence) { + profileRepository = ProfileRepository(persistence.context) + fetchedHeaders = profileRepository.fetchedHeaders() + } + + public var allHeaders: [UUID: Profile.Header] { + fetchedHeaders.value + } + + public func profile(withId id: UUID) -> Profile? { + profileRepository.profile(withId: id) + } + + public func saveProfiles(_ profiles: [Profile]) { + do { + try profileRepository.saveProfiles(profiles) + } catch { + pp_log.error("Unable to save profile: \(error)") + } + } + + public func removeProfiles(withIds ids: [UUID]) { + profileRepository.removeProfiles(withIds: ids) + } + + public func willUpdateProfiles() -> AnyPublisher<[UUID : Profile.Header], Never> { + fetchedHeaders.$value + .eraseToAnyPublisher() + } +} diff --git a/PassepartoutCore/Sources/PassepartoutProfiles/Managers/ProfileManager+Keychain.swift b/PassepartoutLibrary/Sources/PassepartoutProfiles/Managers/DefaultProfileManager+Keychain.swift similarity index 97% rename from PassepartoutCore/Sources/PassepartoutProfiles/Managers/ProfileManager+Keychain.swift rename to PassepartoutLibrary/Sources/PassepartoutProfiles/Managers/DefaultProfileManager+Keychain.swift index 8249dde9..ffe7bbd4 100644 --- a/PassepartoutCore/Sources/PassepartoutProfiles/Managers/ProfileManager+Keychain.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProfiles/Managers/DefaultProfileManager+Keychain.swift @@ -1,5 +1,5 @@ // -// ProfileManager+Keychain.swift +// DefaultProfileManager+Keychain.swift // Passepartout // // Created by Davide De Rosa on 4/8/22. @@ -25,9 +25,10 @@ import Foundation import TunnelKitManager +import PassepartoutCore import PassepartoutUtils -extension ProfileManager { +extension DefaultProfileManager { public func savePassword(forProfile profile: Profile) { guard !profile.isPlaceholder else { assertionFailure("Placeholder") diff --git a/PassepartoutCore/Sources/PassepartoutProfiles/Managers/ProfileManager+Processing.swift b/PassepartoutLibrary/Sources/PassepartoutProfiles/Managers/DefaultProfileManager+Processing.swift similarity index 82% rename from PassepartoutCore/Sources/PassepartoutProfiles/Managers/ProfileManager+Processing.swift rename to PassepartoutLibrary/Sources/PassepartoutProfiles/Managers/DefaultProfileManager+Processing.swift index 74b631a6..86edf2a7 100644 --- a/PassepartoutCore/Sources/PassepartoutProfiles/Managers/ProfileManager+Processing.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProfiles/Managers/DefaultProfileManager+Processing.swift @@ -1,5 +1,5 @@ // -// ProfileManager+Processing.swift +// DefaultProfileManager+Processing.swift // Passepartout // // Created by Davide De Rosa on 4/7/22. @@ -26,13 +26,9 @@ import Foundation import TunnelKitOpenVPN import TunnelKitWireGuard +import PassepartoutCore -extension ProfileManager { - public func profile(withHeader header: Profile.Header, fromURL url: URL, passphrase: String?) throws -> Profile { - let contents = try String(contentsOf: url) - return try profile(withHeader: header, fromContents: contents, originalURL: url, passphrase: passphrase) - } - +extension DefaultProfileManager { public func profile(withHeader header: Profile.Header, fromContents contents: String, originalURL: URL?, passphrase: String?) throws -> Profile { do { let ovpn = try OpenVPN.ConfigurationParser.parsed(fromContents: contents, passphrase: passphrase, originalURL: originalURL) diff --git a/PassepartoutCore/Sources/PassepartoutProfiles/Managers/ProfileManager.swift b/PassepartoutLibrary/Sources/PassepartoutProfiles/Managers/DefaultProfileManager.swift similarity index 91% rename from PassepartoutCore/Sources/PassepartoutProfiles/Managers/ProfileManager.swift rename to PassepartoutLibrary/Sources/PassepartoutProfiles/Managers/DefaultProfileManager.swift index 17fdaca4..4dd9cd71 100644 --- a/PassepartoutCore/Sources/PassepartoutProfiles/Managers/ProfileManager.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProfiles/Managers/DefaultProfileManager.swift @@ -1,5 +1,5 @@ // -// ProfileManager.swift +// DefaultProfileManager.swift // Passepartout // // Created by Davide De Rosa on 2/25/22. @@ -26,12 +26,11 @@ import Foundation import Combine import TunnelKitManager -import PassepartoutProviders +import PassepartoutCore +import PassepartoutCore import PassepartoutUtils -@MainActor -public class ProfileManager: ObservableObject { - public typealias ProfileEx = (profile: Profile, isReady: Bool) +public class DefaultProfileManager: ProfileManagerWithCurrentProfile, ObservableObject { // MARK: Initialization @@ -39,7 +38,7 @@ public class ProfileManager: ObservableObject { private let providerManager: ProviderManager - public let appGroup: String + let appGroup: String let keychainLabel: (String, VPNProtocolType) -> String @@ -111,7 +110,7 @@ public class ProfileManager: ObservableObject { // MARK: Index -extension ProfileManager { +extension DefaultProfileManager { private var allHeaders: [UUID: Profile.Header] { strategy.allHeaders } @@ -120,18 +119,6 @@ extension ProfileManager { Array(allHeaders.values) } - public var hasProfiles: Bool { - !allHeaders.isEmpty - } - - public var hasActiveProfile: Bool { - activeProfileId != nil - } - - public func isActiveProfile(_ id: UUID) -> Bool { - id == activeProfileId - } - public func isExistingProfile(withId id: UUID) -> Bool { allHeaders[id] != nil } @@ -145,18 +132,7 @@ extension ProfileManager { // MARK: Profiles -extension ProfileManager { - public var activeProfile: Profile? { - guard let id = activeProfileId else { - return nil - } - return liveProfile(withId: id) - } - - public func activateProfile(_ profile: Profile) { - saveProfile(profile, isActive: true) - } - +extension DefaultProfileManager { public func liveProfileEx(withId id: UUID) throws -> ProfileEx { guard let profile = liveProfile(withId: id) else { pp_log.error("Profile not found: \(id)") @@ -266,7 +242,7 @@ extension ProfileManager { // MARK: Observation -extension ProfileManager { +extension DefaultProfileManager { private func setCurrentProfile(_ profile: Profile) { guard !currentProfile.isLoading else { pp_log.warning("Already loading another profile") @@ -313,21 +289,9 @@ extension ProfileManager { } } } - - public func isCurrentProfileActive() -> Bool { - currentProfile.value.id == activeProfileId - } - - public func isCurrentProfile(_ id: UUID) -> Bool { - id == currentProfile.value.id - } - - public func activateCurrentProfile() { - saveProfile(currentProfile.value, isActive: true, updateIfCurrent: false) - } } -extension ProfileManager { +extension DefaultProfileManager { public func observeUpdates() { strategy.willUpdateProfiles() .dropFirst() @@ -413,7 +377,7 @@ extension ProfileManager { // MARK: Readiness -extension ProfileManager { +extension DefaultProfileManager { private func isProfileReady(_ profile: Profile) -> Bool { isProfileProviderAvailable(profile) } @@ -453,7 +417,7 @@ extension ProfileManager { // MARK: KeyValueStore -extension ProfileManager { +extension DefaultProfileManager { public private(set) var activeProfileId: UUID? { get { guard let idString: String = store.value(forLocation: StoreKey.activeProfileId) else { @@ -479,7 +443,7 @@ extension ProfileManager { } } -private extension ProfileManager { +private extension DefaultProfileManager { private enum StoreKey: String, KeyStoreDomainLocation { case activeProfileId diff --git a/PassepartoutCore/Sources/PassepartoutCore/Managers/PersistenceManager.swift b/PassepartoutLibrary/Sources/PassepartoutProfiles/Managers/PersistenceManager.swift similarity index 98% rename from PassepartoutCore/Sources/PassepartoutCore/Managers/PersistenceManager.swift rename to PassepartoutLibrary/Sources/PassepartoutProfiles/Managers/PersistenceManager.swift index 7054ba0b..37908c4a 100644 --- a/PassepartoutCore/Sources/PassepartoutCore/Managers/PersistenceManager.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProfiles/Managers/PersistenceManager.swift @@ -25,6 +25,7 @@ import Foundation import CoreData +import PassepartoutCore import PassepartoutUtils public class PersistenceManager { diff --git a/PassepartoutCore/Sources/PassepartoutProfiles/Managers/ProfileManagerStrategy.swift b/PassepartoutLibrary/Sources/PassepartoutProfiles/Managers/ProfileManagerStrategy.swift similarity index 98% rename from PassepartoutCore/Sources/PassepartoutProfiles/Managers/ProfileManagerStrategy.swift rename to PassepartoutLibrary/Sources/PassepartoutProfiles/Managers/ProfileManagerStrategy.swift index b9712e91..176a6517 100644 --- a/PassepartoutCore/Sources/PassepartoutProfiles/Managers/ProfileManagerStrategy.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProfiles/Managers/ProfileManagerStrategy.swift @@ -25,8 +25,8 @@ import Foundation import Combine +import PassepartoutCore -@MainActor public protocol ProfileManagerStrategy { var allHeaders: [UUID: Profile.Header] { get } diff --git a/PassepartoutCore/Sources/PassepartoutProfiles/Models/ObservableProfile.swift b/PassepartoutLibrary/Sources/PassepartoutProfiles/Models/ObservableProfile.swift similarity index 80% rename from PassepartoutCore/Sources/PassepartoutProfiles/Models/ObservableProfile.swift rename to PassepartoutLibrary/Sources/PassepartoutProfiles/Models/ObservableProfile.swift index ec6b8924..098b067f 100644 --- a/PassepartoutCore/Sources/PassepartoutProfiles/Models/ObservableProfile.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProfiles/Models/ObservableProfile.swift @@ -2,7 +2,7 @@ // ObservableProfile.swift // Passepartout // -// Created by Davide De Rosa on 3/27/22. +// Created by Davide De Rosa on 6/20/22. // Copyright (c) 2022 Davide De Rosa. All rights reserved. // // https://github.com/passepartoutvpn @@ -24,20 +24,14 @@ // import Foundation +import PassepartoutCore import PassepartoutUtils -public class ObservableProfile: ValueHolder, ObservableObject { +public class ObservableProfile: WrappedProfile, ValueHolder, ObservableObject { @Published public internal(set) var isLoading = false @Published public var value: Profile - public var name: String { - guard !isLoading && !value.isPlaceholder else { - return "" - } - return value.header.name - } - public init() { value = .placeholder } diff --git a/PassepartoutCore/Sources/PassepartoutProfiles/Pickers/Picker+Network.swift b/PassepartoutLibrary/Sources/PassepartoutProfiles/Pickers/Picker+Network.swift similarity index 98% rename from PassepartoutCore/Sources/PassepartoutProfiles/Pickers/Picker+Network.swift rename to PassepartoutLibrary/Sources/PassepartoutProfiles/Pickers/Picker+Network.swift index 2b629f2b..94e3b202 100644 --- a/PassepartoutCore/Sources/PassepartoutProfiles/Pickers/Picker+Network.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProfiles/Pickers/Picker+Network.swift @@ -25,7 +25,7 @@ import Foundation import TunnelKitCore -import PassepartoutProviders +import PassepartoutCore extension Network.DNSSettings { public static func availableConfigurationTypes(forVPNProtocol vpnProtocol: VPNProtocolType) -> [ConfigurationType] { diff --git a/PassepartoutCore/Sources/PassepartoutProfiles/Pickers/Picker+OpenVPN.swift b/PassepartoutLibrary/Sources/PassepartoutProfiles/Pickers/Picker+OpenVPN.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutProfiles/Pickers/Picker+OpenVPN.swift rename to PassepartoutLibrary/Sources/PassepartoutProfiles/Pickers/Picker+OpenVPN.swift diff --git a/PassepartoutCore/Sources/PassepartoutProfiles/Repositories/ProfileMapper.swift b/PassepartoutLibrary/Sources/PassepartoutProfiles/Repositories/ProfileMapper.swift similarity index 99% rename from PassepartoutCore/Sources/PassepartoutProfiles/Repositories/ProfileMapper.swift rename to PassepartoutLibrary/Sources/PassepartoutProfiles/Repositories/ProfileMapper.swift index 7b0a49f1..9a392403 100644 --- a/PassepartoutCore/Sources/PassepartoutProfiles/Repositories/ProfileMapper.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProfiles/Repositories/ProfileMapper.swift @@ -25,6 +25,7 @@ import Foundation import CoreData +import PassepartoutCore import PassepartoutUtils struct ProfileMapper: DTOMapper, ModelMapper { diff --git a/PassepartoutCore/Sources/PassepartoutProfiles/Repositories/ProfileRepository.swift b/PassepartoutLibrary/Sources/PassepartoutProfiles/Repositories/ProfileRepository.swift similarity index 99% rename from PassepartoutCore/Sources/PassepartoutProfiles/Repositories/ProfileRepository.swift rename to PassepartoutLibrary/Sources/PassepartoutProfiles/Repositories/ProfileRepository.swift index ca2154c7..f1f7f420 100644 --- a/PassepartoutCore/Sources/PassepartoutProfiles/Repositories/ProfileRepository.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProfiles/Repositories/ProfileRepository.swift @@ -25,6 +25,7 @@ import Foundation import CoreData +import PassepartoutCore import PassepartoutUtils class ProfileRepository: Repository { diff --git a/PassepartoutCore/Sources/PassepartoutProviders/DataModels/CDInfrastructure+CoreDataClass.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructure+CoreDataClass.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutProviders/DataModels/CDInfrastructure+CoreDataClass.swift rename to PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructure+CoreDataClass.swift diff --git a/PassepartoutCore/Sources/PassepartoutProviders/DataModels/CDInfrastructure+CoreDataProperties.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructure+CoreDataProperties.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutProviders/DataModels/CDInfrastructure+CoreDataProperties.swift rename to PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructure+CoreDataProperties.swift diff --git a/PassepartoutCore/Sources/PassepartoutProviders/DataModels/CDInfrastructureCategory+CoreDataClass.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructureCategory+CoreDataClass.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutProviders/DataModels/CDInfrastructureCategory+CoreDataClass.swift rename to PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructureCategory+CoreDataClass.swift diff --git a/PassepartoutCore/Sources/PassepartoutProviders/DataModels/CDInfrastructureCategory+CoreDataProperties.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructureCategory+CoreDataProperties.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutProviders/DataModels/CDInfrastructureCategory+CoreDataProperties.swift rename to PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructureCategory+CoreDataProperties.swift diff --git a/PassepartoutCore/Sources/PassepartoutProviders/DataModels/CDInfrastructureDefaultSettings+CoreDataClass.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructureDefaultSettings+CoreDataClass.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutProviders/DataModels/CDInfrastructureDefaultSettings+CoreDataClass.swift rename to PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructureDefaultSettings+CoreDataClass.swift diff --git a/PassepartoutCore/Sources/PassepartoutProviders/DataModels/CDInfrastructureDefaultSettings+CoreDataProperties.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructureDefaultSettings+CoreDataProperties.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutProviders/DataModels/CDInfrastructureDefaultSettings+CoreDataProperties.swift rename to PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructureDefaultSettings+CoreDataProperties.swift diff --git a/PassepartoutCore/Sources/PassepartoutProviders/DataModels/CDInfrastructureLocation+CoreDataClass.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructureLocation+CoreDataClass.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutProviders/DataModels/CDInfrastructureLocation+CoreDataClass.swift rename to PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructureLocation+CoreDataClass.swift diff --git a/PassepartoutCore/Sources/PassepartoutProviders/DataModels/CDInfrastructureLocation+CoreDataProperties.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructureLocation+CoreDataProperties.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutProviders/DataModels/CDInfrastructureLocation+CoreDataProperties.swift rename to PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructureLocation+CoreDataProperties.swift diff --git a/PassepartoutCore/Sources/PassepartoutProviders/DataModels/CDInfrastructurePreset+CoreDataClass.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructurePreset+CoreDataClass.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutProviders/DataModels/CDInfrastructurePreset+CoreDataClass.swift rename to PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructurePreset+CoreDataClass.swift diff --git a/PassepartoutCore/Sources/PassepartoutProviders/DataModels/CDInfrastructurePreset+CoreDataProperties.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructurePreset+CoreDataProperties.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutProviders/DataModels/CDInfrastructurePreset+CoreDataProperties.swift rename to PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructurePreset+CoreDataProperties.swift diff --git a/PassepartoutCore/Sources/PassepartoutProviders/DataModels/CDInfrastructureServer+CoreDataClass.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructureServer+CoreDataClass.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutProviders/DataModels/CDInfrastructureServer+CoreDataClass.swift rename to PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructureServer+CoreDataClass.swift diff --git a/PassepartoutCore/Sources/PassepartoutProviders/DataModels/CDInfrastructureServer+CoreDataProperties.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructureServer+CoreDataProperties.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutProviders/DataModels/CDInfrastructureServer+CoreDataProperties.swift rename to PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDInfrastructureServer+CoreDataProperties.swift diff --git a/PassepartoutCore/Sources/PassepartoutProviders/DataModels/CDProvider+CoreDataClass.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDProvider+CoreDataClass.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutProviders/DataModels/CDProvider+CoreDataClass.swift rename to PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDProvider+CoreDataClass.swift diff --git a/PassepartoutCore/Sources/PassepartoutProviders/DataModels/CDProvider+CoreDataProperties.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDProvider+CoreDataProperties.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutProviders/DataModels/CDProvider+CoreDataProperties.swift rename to PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/CDProvider+CoreDataProperties.swift diff --git a/PassepartoutCore/Sources/PassepartoutProviders/Providers.xcdatamodeld/Model.xcdatamodel/contents b/PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/Providers.xcdatamodeld/Model.xcdatamodel/contents similarity index 100% rename from PassepartoutCore/Sources/PassepartoutProviders/Providers.xcdatamodeld/Model.xcdatamodel/contents rename to PassepartoutLibrary/Sources/PassepartoutProviders/DataModels/Providers.xcdatamodeld/Model.xcdatamodel/contents diff --git a/PassepartoutCore/Sources/PassepartoutProviders/PassepartoutProviders.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/Extensions/PassepartoutDataModels+Providers.swift similarity index 94% rename from PassepartoutCore/Sources/PassepartoutProviders/PassepartoutProviders.swift rename to PassepartoutLibrary/Sources/PassepartoutProviders/Extensions/PassepartoutDataModels+Providers.swift index a30aa4b7..feee60ab 100644 --- a/PassepartoutCore/Sources/PassepartoutProviders/PassepartoutProviders.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProviders/Extensions/PassepartoutDataModels+Providers.swift @@ -1,5 +1,5 @@ // -// PassepartoutProviders.swift +// PassepartoutDataModels+Providers.swift // Passepartout // // Created by Davide De Rosa on 4/7/22. @@ -25,7 +25,7 @@ import Foundation import CoreData -import PassepartoutUtils +import PassepartoutCore extension PassepartoutDataModels { public static let providers: NSManagedObjectModel = { diff --git a/PassepartoutLibrary/Sources/PassepartoutProviders/Extensions/PassepartoutError+Providers.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/Extensions/PassepartoutError+Providers.swift new file mode 100644 index 00000000..fae68c89 --- /dev/null +++ b/PassepartoutLibrary/Sources/PassepartoutProviders/Extensions/PassepartoutError+Providers.swift @@ -0,0 +1,33 @@ +// +// PassepartoutError+Providers.swift +// Passepartout +// +// Created by Davide De Rosa on 6/21/22. +// Copyright (c) 2022 Davide De Rosa. All rights reserved. +// +// https://github.com/passepartoutvpn +// +// This file is part of Passepartout. +// +// Passepartout is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Passepartout is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Passepartout. If not, see . +// + +import Foundation +import PassepartoutCore + +extension PassepartoutError { + public static let missingProviderServer = Self("missingProviderServer") + + public static let missingProviderPreset = Self("missingProviderPreset") +} diff --git a/PassepartoutCore/Sources/PassepartoutProviders/Extensions/PassepartoutProviders+Identifiable.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/Extensions/PassepartoutProviders+Identifiable.swift similarity index 74% rename from PassepartoutCore/Sources/PassepartoutProviders/Extensions/PassepartoutProviders+Identifiable.swift rename to PassepartoutLibrary/Sources/PassepartoutProviders/Extensions/PassepartoutProviders+Identifiable.swift index 26276fab..7964a575 100644 --- a/PassepartoutCore/Sources/PassepartoutProviders/Extensions/PassepartoutProviders+Identifiable.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProviders/Extensions/PassepartoutProviders+Identifiable.swift @@ -24,6 +24,8 @@ // import Foundation +import PassepartoutCore +import CryptoKit // primary keys within infrastructure (pinned: vpnProtocol) @@ -44,3 +46,16 @@ extension ProviderServer { return "\(providerMetadata.name):\(categoryName):\(countryCode)" } } + +extension ProviderServer { + public static func id(withName providerName: ProviderName, vpnProtocol: VPNProtocolType, apiId: String) -> String? { + let idSource = "\(providerName):\(vpnProtocol.rawValue):\(apiId)" + guard let data = idSource.data(using: .utf8) else { + return nil + } + let sha = SHA256.hash(data: data) + return sha.map { + String(format: "%02X", $0) + }.joined() + } +} diff --git a/PassepartoutCore/Sources/PassepartoutProviders/Extensions/PassepartoutProviders+Logging.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/Extensions/PassepartoutProviders+Logging.swift similarity index 97% rename from PassepartoutCore/Sources/PassepartoutProviders/Extensions/PassepartoutProviders+Logging.swift rename to PassepartoutLibrary/Sources/PassepartoutProviders/Extensions/PassepartoutProviders+Logging.swift index ac055a4f..b1ca25d3 100644 --- a/PassepartoutCore/Sources/PassepartoutProviders/Extensions/PassepartoutProviders+Logging.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProviders/Extensions/PassepartoutProviders+Logging.swift @@ -24,6 +24,7 @@ // import Foundation +import PassepartoutCore extension ProviderServer { public var logDescription: String { diff --git a/PassepartoutCore/Sources/PassepartoutProviders/Extensions/ProviderName+Credentials.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/Extensions/ProviderName+Credentials.swift similarity index 98% rename from PassepartoutCore/Sources/PassepartoutProviders/Extensions/ProviderName+Credentials.swift rename to PassepartoutLibrary/Sources/PassepartoutProviders/Extensions/ProviderName+Credentials.swift index b1332cd9..4e84c0c2 100644 --- a/PassepartoutCore/Sources/PassepartoutProviders/Extensions/ProviderName+Credentials.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProviders/Extensions/ProviderName+Credentials.swift @@ -24,6 +24,7 @@ // import Foundation +import PassepartoutCore extension ProviderName { public func requiresCredentials(forProtocol vpnProtocol: VPNProtocolType) -> Bool { diff --git a/PassepartoutCore/Sources/PassepartoutProviders/Managers/ProviderManager.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/Managers/DefaultProviderManager.swift similarity index 78% rename from PassepartoutCore/Sources/PassepartoutProviders/Managers/ProviderManager.swift rename to PassepartoutLibrary/Sources/PassepartoutProviders/Managers/DefaultProviderManager.swift index f19507e1..1dc12d82 100644 --- a/PassepartoutCore/Sources/PassepartoutProviders/Managers/ProviderManager.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProviders/Managers/DefaultProviderManager.swift @@ -25,30 +25,11 @@ import Foundation import Combine +import PassepartoutCore import PassepartoutServices import PassepartoutUtils -enum ProviderManagerError: LocalizedError { - case outdatedBuild(Int, Int) - - var errorDescription: String? { - switch self { - case .outdatedBuild(let current, let min): - return "Build is outdated (found \(current), required \(min))" - } - } -} - -@MainActor -public class ProviderManager: ObservableObject, RateLimited { - public enum FetchPriority { - case bundle - - case remote - - case remoteThenBundle - } - +public class DefaultProviderManager: ProviderManager, ObservableObject, RateLimited { private let appBuild: Int private let bundleServices: WebServices @@ -105,15 +86,10 @@ public class ProviderManager: ObservableObject, RateLimited { serverRepository.servers(forLocation: location) } -// @available(*, deprecated, message: "only use for migration, server is not cached") public func server(_ name: ProviderName, vpnProtocol: VPNProtocolType, apiId: String) -> ProviderServer? { serverRepository.server(forProviderWithName: name, vpnProtocol: vpnProtocol, apiId: apiId) } -// public func anyServer(forProviderWithName providerName: ProviderName, vpnProtocol: VPNProtocolType, countryCode: String) -> ProviderServer? { -// serverRepository.anyServer(forProviderWithName: providerName, vpnProtocol: vpnProtocol, countryCode: countryCode) -// } - public func anyDefaultServer(_ name: ProviderName, vpnProtocol: VPNProtocolType) -> ProviderServer? { serverRepository.anyDefaultServer(forProviderWithName: name, vpnProtocol: vpnProtocol) } @@ -124,7 +100,7 @@ public class ProviderManager: ObservableObject, RateLimited { // MARK: Modification - public func fetchProvidersIndexPublisher(priority: FetchPriority) -> AnyPublisher { + public func fetchProvidersIndexPublisher(priority: ProviderManagerFetchPriority) -> AnyPublisher { guard !isRateLimited(indexActionName) else { return Just(()) .setFailureType(to: Error.self) @@ -145,7 +121,7 @@ public class ProviderManager: ObservableObject, RateLimited { }.eraseToAnyPublisher() } - public func fetchProviderPublisher(withName providerName: ProviderName, vpnProtocol: VPNProtocolType, priority: FetchPriority) -> AnyPublisher { + public func fetchProviderPublisher(withName providerName: ProviderName, vpnProtocol: VPNProtocolType, priority: ProviderManagerFetchPriority) -> AnyPublisher { guard !isRateLimited(providerName) else { return Just(()) .setFailureType(to: Error.self) @@ -154,9 +130,17 @@ public class ProviderManager: ObservableObject, RateLimited { let publisher = priority.publisher(remote: { let ifModifiedSince = self.infrastructureRepository.lastInfrastructureUpdate(withName: providerName, vpnProtocol: vpnProtocol) - return self.webServices.providerNetwork(with: providerName, vpnProtocol: vpnProtocol, ifModifiedSince: ifModifiedSince) + return self.webServices.providerNetwork( + with: providerName.asWSProviderName, + vpnProtocol: vpnProtocol.asWSVPNProtocol, + ifModifiedSince: ifModifiedSince + ) }, bundle: { - self.bundleServices.providerNetwork(with: providerName, vpnProtocol: vpnProtocol, ifModifiedSince: nil) + self.bundleServices.providerNetwork( + with: providerName.asWSProviderName, + vpnProtocol: vpnProtocol.asWSVPNProtocol, + ifModifiedSince: nil + ) }) return publisher @@ -205,46 +189,18 @@ public class ProviderManager: ObservableObject, RateLimited { public var rateLimitMilliseconds: Int? } -private struct InfrastructureKey: Hashable { - let providerName: ProviderName +private enum ProviderManagerError: LocalizedError { + case outdatedBuild(Int, Int) - let vpnProtocol: VPNProtocolType - - init(_ providerName: ProviderName, _ vpnProtocol: VPNProtocolType) { - self.providerName = providerName - self.vpnProtocol = vpnProtocol + var errorDescription: String? { + switch self { + case .outdatedBuild(let current, let min): + return "Build is outdated (found \(current), required \(min))" + } } } -private struct LocationKey: Hashable { - let providerName: ProviderName - - let vpnProtocol: VPNProtocolType - - let categoryName: String - - let countryCode: String - - init( - _ providerName: ProviderName, - _ vpnProtocol: VPNProtocolType, - _ categoryName: String, - _ countryCode: String - ) { - self.providerName = providerName - self.vpnProtocol = vpnProtocol - self.categoryName = categoryName - self.countryCode = countryCode - } -} - -private extension ProviderLocation { - var key: LocationKey { - return .init(providerMetadata.name, vpnProtocol, categoryName, countryCode) - } -} - -private extension ProviderManager.FetchPriority { +private extension ProviderManagerFetchPriority { func publisher( remote: @escaping () -> AnyPublisher, bundle: @escaping () -> AnyPublisher @@ -266,3 +222,21 @@ private extension ProviderManager.FetchPriority { } } } + +private extension ProviderName { + var asWSProviderName: WSProviderName { + self + } +} + +private extension VPNProtocolType { + var asWSVPNProtocol: WSVPNProtocol { + switch self { + case .openVPN: + return .openVPN + + case .wireGuard: + return .wireGuard + } + } +} diff --git a/PassepartoutCore/Sources/PassepartoutProviders/Repositories/CategoryMapper.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/CategoryMapper.swift similarity index 99% rename from PassepartoutCore/Sources/PassepartoutProviders/Repositories/CategoryMapper.swift rename to PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/CategoryMapper.swift index 40fa26d7..649740fb 100644 --- a/PassepartoutCore/Sources/PassepartoutProviders/Repositories/CategoryMapper.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/CategoryMapper.swift @@ -24,6 +24,7 @@ // import Foundation +import PassepartoutCore import PassepartoutServices import PassepartoutUtils import CoreData diff --git a/PassepartoutCore/Sources/PassepartoutProviders/Repositories/DefaultSettingsMapper.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/DefaultSettingsMapper.swift similarity index 98% rename from PassepartoutCore/Sources/PassepartoutProviders/Repositories/DefaultSettingsMapper.swift rename to PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/DefaultSettingsMapper.swift index b74acad2..923f0cda 100644 --- a/PassepartoutCore/Sources/PassepartoutProviders/Repositories/DefaultSettingsMapper.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/DefaultSettingsMapper.swift @@ -25,6 +25,7 @@ import Foundation import CoreData +import PassepartoutCore import PassepartoutServices import PassepartoutUtils diff --git a/PassepartoutCore/Sources/PassepartoutProviders/Repositories/InfrastructureMapper.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/InfrastructureMapper.swift similarity index 99% rename from PassepartoutCore/Sources/PassepartoutProviders/Repositories/InfrastructureMapper.swift rename to PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/InfrastructureMapper.swift index f55e7828..4b72842a 100644 --- a/PassepartoutCore/Sources/PassepartoutProviders/Repositories/InfrastructureMapper.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/InfrastructureMapper.swift @@ -25,6 +25,7 @@ import Foundation import CoreData +import PassepartoutCore import PassepartoutServices import PassepartoutUtils diff --git a/PassepartoutCore/Sources/PassepartoutProviders/Repositories/InfrastructureRepository.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/InfrastructureRepository.swift similarity index 99% rename from PassepartoutCore/Sources/PassepartoutProviders/Repositories/InfrastructureRepository.swift rename to PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/InfrastructureRepository.swift index 92f72612..0c441104 100644 --- a/PassepartoutCore/Sources/PassepartoutProviders/Repositories/InfrastructureRepository.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/InfrastructureRepository.swift @@ -25,6 +25,7 @@ import Foundation import CoreData +import PassepartoutCore import PassepartoutServices import PassepartoutUtils diff --git a/PassepartoutCore/Sources/PassepartoutProviders/Repositories/LocationMapper.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/LocationMapper.swift similarity index 99% rename from PassepartoutCore/Sources/PassepartoutProviders/Repositories/LocationMapper.swift rename to PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/LocationMapper.swift index 1fd95646..85cde36b 100644 --- a/PassepartoutCore/Sources/PassepartoutProviders/Repositories/LocationMapper.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/LocationMapper.swift @@ -25,6 +25,7 @@ import Foundation import CoreData +import PassepartoutCore import PassepartoutServices import PassepartoutUtils diff --git a/PassepartoutCore/Sources/PassepartoutProviders/Repositories/PresetMapper.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/PresetMapper.swift similarity index 99% rename from PassepartoutCore/Sources/PassepartoutProviders/Repositories/PresetMapper.swift rename to PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/PresetMapper.swift index 93141849..97036474 100644 --- a/PassepartoutCore/Sources/PassepartoutProviders/Repositories/PresetMapper.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/PresetMapper.swift @@ -25,6 +25,7 @@ import Foundation import CoreData +import PassepartoutCore import PassepartoutServices import PassepartoutUtils import GenericJSON diff --git a/PassepartoutCore/Sources/PassepartoutProviders/Repositories/ProviderMapper.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/ProviderMapper.swift similarity index 98% rename from PassepartoutCore/Sources/PassepartoutProviders/Repositories/ProviderMapper.swift rename to PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/ProviderMapper.swift index de02e3c2..cf155e43 100644 --- a/PassepartoutCore/Sources/PassepartoutProviders/Repositories/ProviderMapper.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/ProviderMapper.swift @@ -25,6 +25,7 @@ import Foundation import CoreData +import PassepartoutCore import PassepartoutServices import PassepartoutUtils diff --git a/PassepartoutCore/Sources/PassepartoutProviders/Repositories/ProviderRepository.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/ProviderRepository.swift similarity index 99% rename from PassepartoutCore/Sources/PassepartoutProviders/Repositories/ProviderRepository.swift rename to PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/ProviderRepository.swift index 34988ef9..faf79288 100644 --- a/PassepartoutCore/Sources/PassepartoutProviders/Repositories/ProviderRepository.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/ProviderRepository.swift @@ -25,6 +25,7 @@ import Foundation import CoreData +import PassepartoutCore import PassepartoutServices import PassepartoutUtils diff --git a/PassepartoutCore/Sources/PassepartoutProviders/Repositories/ServerMapper.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/ServerMapper.swift similarity index 97% rename from PassepartoutCore/Sources/PassepartoutProviders/Repositories/ServerMapper.swift rename to PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/ServerMapper.swift index 5dbcd866..ae2b5d9c 100644 --- a/PassepartoutCore/Sources/PassepartoutProviders/Repositories/ServerMapper.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/ServerMapper.swift @@ -25,6 +25,7 @@ import Foundation import CoreData +import PassepartoutCore import PassepartoutServices import PassepartoutUtils @@ -103,7 +104,7 @@ struct ServerMapper: DTOMapper, ModelMapper { } static func toModelWithPresets(_ dto: CDInfrastructureServer) -> ProviderServer? { - guard var server = toModel(dto), + guard let server = toModel(dto), let categoryDTO = dto.category, let categoryName = categoryDTO.name else { @@ -118,11 +119,11 @@ struct ServerMapper: DTOMapper, ModelMapper { return nil } - server.presets = presetDTOs + let presets = presetDTOs .sorted() .compactMap(PresetMapper.toModel) - - return server + + return server.withPresets(presets) } } diff --git a/PassepartoutCore/Sources/PassepartoutProviders/Repositories/ServerRepository.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/ServerRepository.swift similarity index 99% rename from PassepartoutCore/Sources/PassepartoutProviders/Repositories/ServerRepository.swift rename to PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/ServerRepository.swift index 8c679dae..392b5786 100644 --- a/PassepartoutCore/Sources/PassepartoutProviders/Repositories/ServerRepository.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/ServerRepository.swift @@ -25,6 +25,7 @@ import Foundation import CoreData +import PassepartoutCore import PassepartoutServices import PassepartoutUtils diff --git a/PassepartoutCore/Sources/PassepartoutServices/API b/PassepartoutLibrary/Sources/PassepartoutServices/API similarity index 100% rename from PassepartoutCore/Sources/PassepartoutServices/API rename to PassepartoutLibrary/Sources/PassepartoutServices/API diff --git a/PassepartoutCore/Sources/PassepartoutServices/DataModels/WSProviderCategory.swift b/PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSProviderCategory.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutServices/DataModels/WSProviderCategory.swift rename to PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSProviderCategory.swift diff --git a/PassepartoutCore/Sources/PassepartoutServices/DataModels/WSProviderInfrastructure.swift b/PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSProviderInfrastructure.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutServices/DataModels/WSProviderInfrastructure.swift rename to PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSProviderInfrastructure.swift diff --git a/PassepartoutCore/Sources/PassepartoutServices/DataModels/WSProviderLocation.swift b/PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSProviderLocation.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutServices/DataModels/WSProviderLocation.swift rename to PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSProviderLocation.swift diff --git a/PassepartoutCore/Sources/PassepartoutServices/DataModels/WSProviderName.swift b/PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSProviderName.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutServices/DataModels/WSProviderName.swift rename to PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSProviderName.swift diff --git a/PassepartoutCore/Sources/PassepartoutServices/DataModels/WSProviderPreset.swift b/PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSProviderPreset.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutServices/DataModels/WSProviderPreset.swift rename to PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSProviderPreset.swift diff --git a/PassepartoutCore/Sources/PassepartoutServices/DataModels/WSProviderServer.swift b/PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSProviderServer.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutServices/DataModels/WSProviderServer.swift rename to PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSProviderServer.swift diff --git a/PassepartoutCore/Sources/PassepartoutServices/DataModels/WSProvidersIndex.swift b/PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSProvidersIndex.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutServices/DataModels/WSProvidersIndex.swift rename to PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSProvidersIndex.swift diff --git a/PassepartoutCore/Sources/PassepartoutServices/DataModels/WSVPNProtocol.swift b/PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSVPNProtocol.swift similarity index 80% rename from PassepartoutCore/Sources/PassepartoutServices/DataModels/WSVPNProtocol.swift rename to PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSVPNProtocol.swift index 06e9e2ad..93ab268f 100644 --- a/PassepartoutCore/Sources/PassepartoutServices/DataModels/WSVPNProtocol.swift +++ b/PassepartoutLibrary/Sources/PassepartoutServices/DataModels/WSVPNProtocol.swift @@ -30,15 +30,3 @@ public enum WSVPNProtocol: String, Codable { case wireGuard = "wg" } - -extension WSVPNProtocol: CustomStringConvertible { - public var description: String { - switch self { - case .openVPN: - return "OpenVPN" - - case .wireGuard: - return "WireGuard" - } - } -} diff --git a/PassepartoutCore/Sources/PassepartoutServices/DefaultWebServices.swift b/PassepartoutLibrary/Sources/PassepartoutServices/DefaultWebServices.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutServices/DefaultWebServices.swift rename to PassepartoutLibrary/Sources/PassepartoutServices/DefaultWebServices.swift diff --git a/PassepartoutCore/Sources/PassepartoutServices/Extensions/WSProviderName+Extensions.swift b/PassepartoutLibrary/Sources/PassepartoutServices/Extensions/WSProviderName+Extensions.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutServices/Extensions/WSProviderName+Extensions.swift rename to PassepartoutLibrary/Sources/PassepartoutServices/Extensions/WSProviderName+Extensions.swift diff --git a/PassepartoutCore/Sources/PassepartoutServices/WebServices.swift b/PassepartoutLibrary/Sources/PassepartoutServices/WebServices.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutServices/WebServices.swift rename to PassepartoutLibrary/Sources/PassepartoutServices/WebServices.swift diff --git a/PassepartoutCore/Sources/PassepartoutUtils/Exports.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Exports.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutUtils/Exports.swift rename to PassepartoutLibrary/Sources/PassepartoutUtils/Exports.swift diff --git a/PassepartoutCore/Sources/PassepartoutUtils/Reusable/FetchedValueHolder.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/FetchedValueHolder.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutUtils/Reusable/FetchedValueHolder.swift rename to PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/FetchedValueHolder.swift diff --git a/PassepartoutCore/Sources/PassepartoutUtils/Reusable/GenericWebEndpoint.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/GenericWebEndpoint.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutUtils/Reusable/GenericWebEndpoint.swift rename to PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/GenericWebEndpoint.swift diff --git a/PassepartoutCore/Sources/PassepartoutUtils/Reusable/GenericWebParser.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/GenericWebParser.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutUtils/Reusable/GenericWebParser.swift rename to PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/GenericWebParser.swift diff --git a/PassepartoutCore/Sources/PassepartoutUtils/Reusable/GenericWebResponse.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/GenericWebResponse.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutUtils/Reusable/GenericWebResponse.swift rename to PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/GenericWebResponse.swift diff --git a/PassepartoutCore/Sources/PassepartoutUtils/Reusable/GenericWebServices.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/GenericWebServices.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutUtils/Reusable/GenericWebServices.swift rename to PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/GenericWebServices.swift diff --git a/Passepartout/AppShared/Reusable/InApp.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/InApp.swift similarity index 100% rename from Passepartout/AppShared/Reusable/InApp.swift rename to PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/InApp.swift diff --git a/PassepartoutCore/Sources/PassepartoutUtils/Reusable/KeyValueStore.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/KeyValueStore.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutUtils/Reusable/KeyValueStore.swift rename to PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/KeyValueStore.swift diff --git a/PassepartoutCore/Sources/PassepartoutUtils/Reusable/KeyedCache.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/KeyedCache.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutUtils/Reusable/KeyedCache.swift rename to PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/KeyedCache.swift diff --git a/PassepartoutCore/Sources/PassepartoutCore/Managers/LogManager.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/LogManager.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutCore/Managers/LogManager.swift rename to PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/LogManager.swift diff --git a/PassepartoutCore/Sources/PassepartoutUtils/Reusable/Mapper.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/Mapper.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutUtils/Reusable/Mapper.swift rename to PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/Mapper.swift diff --git a/PassepartoutCore/Sources/PassepartoutUtils/Reusable/Persistence.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/Persistence.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutUtils/Reusable/Persistence.swift rename to PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/Persistence.swift diff --git a/PassepartoutCore/Sources/PassepartoutUtils/Reusable/RateLimited.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/RateLimited.swift similarity index 99% rename from PassepartoutCore/Sources/PassepartoutUtils/Reusable/RateLimited.swift rename to PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/RateLimited.swift index aedcfc3d..e7538ff0 100644 --- a/PassepartoutCore/Sources/PassepartoutUtils/Reusable/RateLimited.swift +++ b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/RateLimited.swift @@ -25,7 +25,6 @@ import Foundation -@MainActor public protocol RateLimited: AnyObject { associatedtype ActionID: Hashable diff --git a/PassepartoutCore/Sources/PassepartoutUtils/Reusable/Repository.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/Repository.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutUtils/Reusable/Repository.swift rename to PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/Repository.swift diff --git a/PassepartoutCore/Sources/PassepartoutUtils/Reusable/SSIDReader.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/SSIDReader.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutUtils/Reusable/SSIDReader.swift rename to PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/SSIDReader.swift diff --git a/PassepartoutCore/Sources/PassepartoutUtils/Reusable/StrippableContent.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/StrippableContent.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutUtils/Reusable/StrippableContent.swift rename to PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/StrippableContent.swift diff --git a/PassepartoutCore/Sources/PassepartoutUtils/Reusable/UserDefaultsStore.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/UserDefaultsStore.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutUtils/Reusable/UserDefaultsStore.swift rename to PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/UserDefaultsStore.swift diff --git a/PassepartoutCore/Sources/PassepartoutUtils/Reusable/ValueHolder.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/ValueHolder.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutUtils/Reusable/ValueHolder.swift rename to PassepartoutLibrary/Sources/PassepartoutUtils/Reusable/ValueHolder.swift diff --git a/PassepartoutCore/Sources/PassepartoutUtils/Utils/Utils+Async.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Utils/Utils+Async.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutUtils/Utils/Utils+Async.swift rename to PassepartoutLibrary/Sources/PassepartoutUtils/Utils/Utils+Async.swift diff --git a/PassepartoutCore/Sources/PassepartoutUtils/Utils/Utils+Codable.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Utils/Utils+Codable.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutUtils/Utils/Utils+Codable.swift rename to PassepartoutLibrary/Sources/PassepartoutUtils/Utils/Utils+Codable.swift diff --git a/PassepartoutCore/Sources/PassepartoutUtils/Utils/Utils+CoreData.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Utils/Utils+CoreData.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutUtils/Utils/Utils+CoreData.swift rename to PassepartoutLibrary/Sources/PassepartoutUtils/Utils/Utils+CoreData.swift diff --git a/PassepartoutCore/Sources/PassepartoutUtils/Utils/Utils+Dates.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Utils/Utils+Dates.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutUtils/Utils/Utils+Dates.swift rename to PassepartoutLibrary/Sources/PassepartoutUtils/Utils/Utils+Dates.swift diff --git a/PassepartoutCore/Sources/PassepartoutUtils/Utils/Utils+FileManager.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Utils/Utils+FileManager.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutUtils/Utils/Utils+FileManager.swift rename to PassepartoutLibrary/Sources/PassepartoutUtils/Utils/Utils+FileManager.swift diff --git a/PassepartoutCore/Sources/PassepartoutUtils/Utils/Utils+Logging.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Utils/Utils+Logging.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutUtils/Utils/Utils+Logging.swift rename to PassepartoutLibrary/Sources/PassepartoutUtils/Utils/Utils+Logging.swift diff --git a/PassepartoutCore/Sources/PassepartoutUtils/Utils/Utils+Network.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Utils/Utils+Network.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutUtils/Utils/Utils+Network.swift rename to PassepartoutLibrary/Sources/PassepartoutUtils/Utils/Utils+Network.swift diff --git a/PassepartoutCore/Sources/PassepartoutUtils/Utils/Utils+Strings.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Utils/Utils+Strings.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutUtils/Utils/Utils+Strings.swift rename to PassepartoutLibrary/Sources/PassepartoutUtils/Utils/Utils+Strings.swift diff --git a/PassepartoutCore/Sources/PassepartoutUtils/Utils/Utils+TestFlight.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Utils/Utils+TestFlight.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutUtils/Utils/Utils+TestFlight.swift rename to PassepartoutLibrary/Sources/PassepartoutUtils/Utils/Utils+TestFlight.swift diff --git a/PassepartoutCore/Sources/PassepartoutUtils/Utils/Utils+URL.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Utils/Utils+URL.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutUtils/Utils/Utils+URL.swift rename to PassepartoutLibrary/Sources/PassepartoutUtils/Utils/Utils+URL.swift diff --git a/PassepartoutCore/Sources/PassepartoutUtils/Utils/Utils.swift b/PassepartoutLibrary/Sources/PassepartoutUtils/Utils/Utils.swift similarity index 100% rename from PassepartoutCore/Sources/PassepartoutUtils/Utils/Utils.swift rename to PassepartoutLibrary/Sources/PassepartoutUtils/Utils/Utils.swift diff --git a/PassepartoutCore/Sources/PassepartoutCore/Extensions/OnDemand+Rules.swift b/PassepartoutLibrary/Sources/PassepartoutVPN/Extensions/OnDemand+Rules.swift similarity index 98% rename from PassepartoutCore/Sources/PassepartoutCore/Extensions/OnDemand+Rules.swift rename to PassepartoutLibrary/Sources/PassepartoutVPN/Extensions/OnDemand+Rules.swift index 8a182c67..b3d9d5bd 100644 --- a/PassepartoutCore/Sources/PassepartoutCore/Extensions/OnDemand+Rules.swift +++ b/PassepartoutLibrary/Sources/PassepartoutVPN/Extensions/OnDemand+Rules.swift @@ -25,6 +25,8 @@ import Foundation import NetworkExtension +import PassepartoutCore +import PassepartoutUtils extension NEOnDemandRuleInterfaceType { static var compatibleEthernet: NEOnDemandRuleInterfaceType? { diff --git a/PassepartoutCore/Sources/PassepartoutCore/Extensions/OpenVPNSettings+VPNConfiguration.swift b/PassepartoutLibrary/Sources/PassepartoutVPN/Extensions/OpenVPNSettings+VPNConfiguration.swift similarity index 98% rename from PassepartoutCore/Sources/PassepartoutCore/Extensions/OpenVPNSettings+VPNConfiguration.swift rename to PassepartoutLibrary/Sources/PassepartoutVPN/Extensions/OpenVPNSettings+VPNConfiguration.swift index 52daaebd..2030a3e7 100644 --- a/PassepartoutCore/Sources/PassepartoutCore/Extensions/OpenVPNSettings+VPNConfiguration.swift +++ b/PassepartoutLibrary/Sources/PassepartoutVPN/Extensions/OpenVPNSettings+VPNConfiguration.swift @@ -24,11 +24,12 @@ // import Foundation +import TunnelKitManager import TunnelKitOpenVPN +import PassepartoutCore +import PassepartoutUtils extension Profile.OpenVPNSettings: VPNConfigurationProviding { - - @MainActor func vpnConfiguration(_ parameters: VPNConfigurationParameters) throws -> VPNConfiguration { var customBuilder = configuration.builder() diff --git a/PassepartoutCore/Sources/PassepartoutCore/PassepartoutCore.swift b/PassepartoutLibrary/Sources/PassepartoutVPN/Extensions/PassepartoutError+VPN.swift similarity index 94% rename from PassepartoutCore/Sources/PassepartoutCore/PassepartoutCore.swift rename to PassepartoutLibrary/Sources/PassepartoutVPN/Extensions/PassepartoutError+VPN.swift index 9b36bd61..4dc3a5f9 100644 --- a/PassepartoutCore/Sources/PassepartoutCore/PassepartoutCore.swift +++ b/PassepartoutLibrary/Sources/PassepartoutVPN/Extensions/PassepartoutError+VPN.swift @@ -1,5 +1,5 @@ // -// PassepartoutCore.swift +// PassepartoutError+VPN.swift // Passepartout // // Created by Davide De Rosa on 4/7/22. @@ -24,6 +24,7 @@ // import Foundation +import PassepartoutCore extension PassepartoutError { public static let missingAccount = Self("missingAccount") diff --git a/PassepartoutCore/Sources/PassepartoutProfiles/Extensions/VPNProtocolType+Network.swift b/PassepartoutLibrary/Sources/PassepartoutVPN/Extensions/VPNProtocolType+Extensions.swift similarity index 87% rename from PassepartoutCore/Sources/PassepartoutProfiles/Extensions/VPNProtocolType+Network.swift rename to PassepartoutLibrary/Sources/PassepartoutVPN/Extensions/VPNProtocolType+Extensions.swift index d34c7898..4ea1efdf 100644 --- a/PassepartoutCore/Sources/PassepartoutProfiles/Extensions/VPNProtocolType+Network.swift +++ b/PassepartoutLibrary/Sources/PassepartoutVPN/Extensions/VPNProtocolType+Extensions.swift @@ -2,7 +2,7 @@ // VPNProtocolType+Extensions.swift // Passepartout // -// Created by Davide De Rosa on 2/11/22. +// Created by Davide De Rosa on 4/7/22. // Copyright (c) 2022 Davide De Rosa. All rights reserved. // // https://github.com/passepartoutvpn @@ -26,7 +26,13 @@ import Foundation import TunnelKitOpenVPN import TunnelKitWireGuard -import PassepartoutProviders +import PassepartoutCore + +extension VPNProtocolType: Comparable { + public static func <(lhs: Self, rhs: Self) -> Bool { + return lhs.description < rhs.description + } +} extension OpenVPN.ProviderConfiguration: VPNProtocolProviding { public var vpnProtocol: VPNProtocolType { diff --git a/PassepartoutCore/Sources/PassepartoutCore/Extensions/WireGuardSettings+VPNConfiguration.swift b/PassepartoutLibrary/Sources/PassepartoutVPN/Extensions/WireGuardSettings+VPNConfiguration.swift similarity index 98% rename from PassepartoutCore/Sources/PassepartoutCore/Extensions/WireGuardSettings+VPNConfiguration.swift rename to PassepartoutLibrary/Sources/PassepartoutVPN/Extensions/WireGuardSettings+VPNConfiguration.swift index cc95128f..aebdcc67 100644 --- a/PassepartoutCore/Sources/PassepartoutCore/Extensions/WireGuardSettings+VPNConfiguration.swift +++ b/PassepartoutLibrary/Sources/PassepartoutVPN/Extensions/WireGuardSettings+VPNConfiguration.swift @@ -24,11 +24,12 @@ // import Foundation +import TunnelKitManager import TunnelKitWireGuard +import PassepartoutCore +import PassepartoutUtils extension Profile.WireGuardSettings: VPNConfigurationProviding { - - @MainActor func vpnConfiguration(_ parameters: VPNConfigurationParameters) throws -> VPNConfiguration { var customBuilder = configuration.builder() diff --git a/PassepartoutCore/Sources/PassepartoutCore/Managers/VPNManager+Actions.swift b/PassepartoutLibrary/Sources/PassepartoutVPN/Managers/DefaultVPNManager+Actions.swift similarity index 97% rename from PassepartoutCore/Sources/PassepartoutCore/Managers/VPNManager+Actions.swift rename to PassepartoutLibrary/Sources/PassepartoutVPN/Managers/DefaultVPNManager+Actions.swift index 7b7d44ce..dc0710df 100644 --- a/PassepartoutCore/Sources/PassepartoutCore/Managers/VPNManager+Actions.swift +++ b/PassepartoutLibrary/Sources/PassepartoutVPN/Managers/DefaultVPNManager+Actions.swift @@ -1,5 +1,5 @@ // -// VPNManager+Actions.swift +// DefaultVPNManager+Actions.swift // Passepartout // // Created by Davide De Rosa on 3/30/22. @@ -24,12 +24,14 @@ // import Foundation +import PassepartoutCore +import PassepartoutUtils // IMPORTANT: if active profile is set/modified and it happens to also be // current profile, this must be updated too. this is done in // ProfileManager.activateProfile() -extension VPNManager { +extension DefaultVPNManager { public func connectWithActiveProfile() async throws { guard currentState.vpnStatus != .connected else { pp_log.warning("VPN is already connected") diff --git a/PassepartoutCore/Sources/PassepartoutCore/Managers/VPNManager+Configuration.swift b/PassepartoutLibrary/Sources/PassepartoutVPN/Managers/DefaultVPNManager+Configuration.swift similarity index 96% rename from PassepartoutCore/Sources/PassepartoutCore/Managers/VPNManager+Configuration.swift rename to PassepartoutLibrary/Sources/PassepartoutVPN/Managers/DefaultVPNManager+Configuration.swift index ea5cc2ca..f4eda44f 100644 --- a/PassepartoutCore/Sources/PassepartoutCore/Managers/VPNManager+Configuration.swift +++ b/PassepartoutLibrary/Sources/PassepartoutVPN/Managers/DefaultVPNManager+Configuration.swift @@ -1,5 +1,5 @@ // -// VPNManager+Configuration.swift +// DefaultVPNManager+Configuration.swift // Passepartout // // Created by Davide De Rosa on 3/12/22. @@ -24,8 +24,10 @@ // import Foundation +import PassepartoutCore +import PassepartoutUtils -extension VPNManager { +extension DefaultVPNManager { private var vpnPreferences: VPNPreferences { DefaultVPNPreferences( tunnelLogPath: tunnelLogPath, @@ -59,7 +61,7 @@ extension VPNManager { let parameters = VPNConfigurationParameters( profile, - appGroup: profileManager.appGroup, + appGroup: appGroup, preferences: vpnPreferences, passwordReference: profileManager.passwordReference(forProfile: profile), withNetworkSettings: isNetworkSettingsSupported(), diff --git a/PassepartoutCore/Sources/PassepartoutCore/Managers/VPNManager.swift b/PassepartoutLibrary/Sources/PassepartoutVPN/Managers/DefaultVPNManager.swift similarity index 92% rename from PassepartoutCore/Sources/PassepartoutCore/Managers/VPNManager.swift rename to PassepartoutLibrary/Sources/PassepartoutVPN/Managers/DefaultVPNManager.swift index c7a709c1..a9be63b2 100644 --- a/PassepartoutCore/Sources/PassepartoutCore/Managers/VPNManager.swift +++ b/PassepartoutLibrary/Sources/PassepartoutVPN/Managers/DefaultVPNManager.swift @@ -1,5 +1,5 @@ // -// VPNManager.swift +// DefaultVPNManager.swift // Passepartout // // Created by Davide De Rosa on 2/9/22. @@ -27,17 +27,19 @@ import Foundation import Combine import TunnelKitCore import TunnelKitManager +import PassepartoutCore +import PassepartoutProfiles import PassepartoutUtils -@MainActor -public class VPNManager: ObservableObject { - public typealias ConfigurationError = (profile: Profile, error: Error) +public class DefaultVPNManager: VPNManagerWithCurrentState, ObservableObject where ProfileManagerType.WrappedType == ObservableProfile { // MARK: Initialization + let appGroup: String + private let store: KeyValueStore - let profileManager: ProfileManager + let profileManager: ProfileManagerType let providerManager: ProviderManager @@ -49,7 +51,7 @@ public class VPNManager: ObservableObject { // MARK: State - public let currentState: ObservableState + public let currentState: ObservableVPNState public private(set) var lastError: Error? { get { @@ -60,7 +62,7 @@ public class VPNManager: ObservableObject { } } - public let configurationError = PassthroughSubject() + public let configurationError = PassthroughSubject() // MARK: Internals @@ -69,11 +71,13 @@ public class VPNManager: ObservableObject { private var cancellables: Set = [] public init( + appGroup: String, store: KeyValueStore, - profileManager: ProfileManager, + profileManager: ProfileManagerType, providerManager: ProviderManager, strategy: VPNManagerStrategy ) { + self.appGroup = appGroup self.store = store self.profileManager = profileManager self.providerManager = providerManager @@ -81,7 +85,7 @@ public class VPNManager: ObservableObject { isNetworkSettingsSupported = { true } isOnDemandRulesSupported = { true } - currentState = ObservableState() + currentState = ObservableVPNState() CoreConfiguration.masksPrivateData = masksPrivateData } @@ -144,7 +148,7 @@ public class VPNManager: ObservableObject { // MARK: Observation -extension VPNManager { +extension DefaultVPNManager { public func observeUpdates() { observeStrategy() observeProfileManager() @@ -258,7 +262,7 @@ extension VPNManager { // MARK: KeyValueStore -extension VPNManager { +extension DefaultVPNManager { public var tunnelLogPath: String? { get { store.value(forLocation: StoreKey.tunnelLogPath) @@ -289,7 +293,7 @@ extension VPNManager { } } -private extension VPNManager { +private extension DefaultVPNManager { private enum StoreKey: String, KeyStoreDomainLocation { case tunnelLogPath diff --git a/PassepartoutLibrary/Sources/PassepartoutVPN/Managers/MockVPNManagerStrategy.swift b/PassepartoutLibrary/Sources/PassepartoutVPN/Managers/MockVPNManagerStrategy.swift new file mode 100644 index 00000000..e6ac0ea4 --- /dev/null +++ b/PassepartoutLibrary/Sources/PassepartoutVPN/Managers/MockVPNManagerStrategy.swift @@ -0,0 +1,106 @@ +// +// MockVPNManagerStrategy.swift +// Passepartout +// +// Created by Davide De Rosa on 2/9/22. +// Copyright (c) 2022 Davide De Rosa. All rights reserved. +// +// https://github.com/passepartoutvpn +// +// This file is part of Passepartout. +// +// Passepartout is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Passepartout is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Passepartout. If not, see . +// + +import Foundation +import Combine +import TunnelKitCore +import PassepartoutCore + +// XXX: mock connect/disconnect tasks overlap, should cancel other pending task + +public class MockVPNManagerStrategy: VPNManagerStrategy { + private var currentState: ObservableVPNState? + + private var dataCountTimer: AnyCancellable? + + public init() { + } + + public func observe(into state: ObservableVPNState) { + currentState = state + } + + public func reinstate(configuration: VPNConfiguration) { + } + + public func connect(configuration: VPNConfiguration) { + guard currentState?.vpnStatus != .connected else { + return + } + Task { + currentState?.isEnabled = true + currentState?.vpnStatus = .connecting + await Task.maybeWait(forMilliseconds: 1000) + currentState?.vpnStatus = .connected + startCountingData() + } + } + + public func disconnect() { + stopCountingData() + guard currentState?.vpnStatus != .disconnected else { + return + } + Task { + currentState?.isEnabled = false + currentState?.vpnStatus = .disconnecting + await Task.maybeWait(forMilliseconds: 1000) + currentState?.vpnStatus = .disconnected + currentState?.dataCount = nil + } + } + + private func startCountingData() { + guard currentState?.vpnStatus == .connected else { + return + } + guard dataCountTimer == nil else { + return + } + dataCountTimer = Timer.TimerPublisher(interval: 2.0, runLoop: .main, mode: .common) + .autoconnect() + .sink(receiveValue: { _ in + let previous = self.currentState?.dataCount ?? DataCount(0, 0) + self.currentState?.dataCount = DataCount(previous.received + 4000, previous.sent + 2000) + }) + } + + private func stopCountingData() { + dataCountTimer?.cancel() + dataCountTimer = nil + } + + public func removeConfigurations() { + disconnect() + } + + public func serverConfiguration(forProtocol vpnProtocol: VPNProtocolType) -> Any? { + return nil + } + + public func debugLogURL(forProtocol vpnProtocol: VPNProtocolType) -> URL? { + return nil + } +} diff --git a/PassepartoutLibrary/Sources/PassepartoutVPN/Managers/TunnelKitVPNManagerStrategy.swift b/PassepartoutLibrary/Sources/PassepartoutVPN/Managers/TunnelKitVPNManagerStrategy.swift new file mode 100644 index 00000000..127a8619 --- /dev/null +++ b/PassepartoutLibrary/Sources/PassepartoutVPN/Managers/TunnelKitVPNManagerStrategy.swift @@ -0,0 +1,317 @@ +// +// TunnelKitVPNManagerStrategy.swift +// Passepartout +// +// Created by Davide De Rosa on 3/4/22. +// Copyright (c) 2022 Davide De Rosa. All rights reserved. +// +// https://github.com/passepartoutvpn +// +// This file is part of Passepartout. +// +// Passepartout is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Passepartout is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Passepartout. If not, see . +// + +import Foundation +import Combine +import NetworkExtension +import TunnelKitCore +import TunnelKitManager +import TunnelKitOpenVPNCore +import PassepartoutCore +import PassepartoutUtils + +public class TunnelKitVPNManagerStrategy: VPNManagerStrategy { + 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 appGroup: String + + private let tunnelBundleIdentifier: (VPNProtocolType) -> String + + private let defaults: UserDefaults + + private let vpn: NetworkExtensionVPN + + 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(appGroup: String, tunnelBundleIdentifier: @escaping (VPNProtocolType) -> String, dataCountInterval: TimeInterval = 3.0) { + self.appGroup = appGroup + self.tunnelBundleIdentifier = tunnelBundleIdentifier + guard let defaults = UserDefaults(suiteName: appGroup) else { + fatalError("No entitlements for group '\(appGroup)'") + } + self.defaults = defaults + vpn = NetworkExtensionVPN() + self.dataCountInterval = dataCountInterval + + registerNotification(withName: VPNNotification.didReinstall) { + self.onVPNReinstall($0) + } + registerNotification(withName: VPNNotification.didChangeStatus) { + self.onVPNStatus($0) + } + registerNotification(withName: VPNNotification.didFail) { + self.onVPNFail($0) + } + Task { + await vpn.prepare() + } + } + + private func registerNotification(withName name: Notification.Name, perform: @escaping (Notification) -> Void) { + NotificationCenter.default.publisher(for: name, object: nil) + .receive(on: DispatchQueue.main) + .sink(receiveValue: perform) + .store(in: &cancellables) + } + + // MARK: Strategy + + public func observe(into state: ObservableVPNState) { + currentState = state + + // use this to drop redundant NE notifications + vpnState + .removeDuplicates() + .sink { + self.currentState?.isEnabled = $0.isEnabled + 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") + } + let bundleIdentifier = tunnelBundleIdentifier(vpnType.vpnProtocol) + currentBundleIdentifier = bundleIdentifier + + pp_log.verbose("Configuration: \(configuration)") + pp_log.info("Reinstating VPN...") + do { + try await vpn.install( + bundleIdentifier, + configuration: configuration.neConfiguration, + extra: configuration.neExtra + ) + } catch { + 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") + } + let bundleIdentifier = tunnelBundleIdentifier(vpnType.vpnProtocol) + currentBundleIdentifier = bundleIdentifier + + pp_log.verbose("Configuration: \(configuration)") + pp_log.info("Reconnecting VPN...") + do { + try await vpn.reconnect( + bundleIdentifier, + configuration: configuration.neConfiguration, + extra: configuration.neExtra, + after: .seconds(2) + ) + } catch { + pp_log.error("Unable to connect: \(error)") + } + } + + public func disconnect() async { + await vpn.disconnect() + } + + public func removeConfigurations() async { + await vpn.uninstall() + + // XXX: force isEnabled to false as it's not properly notified by NetworkExtension + vpnState.send(AtomicState( + isEnabled: false, + vpnStatus: vpnState.value.vpnStatus + )) + } + + // MARK: Notifications + + private func onVPNReinstall(_ notification: Notification) { + guard isRelevantNotification(notification) else { + return + } + + vpnState.send(AtomicState( + isEnabled: notification.vpnIsEnabled, + vpnStatus: vpnState.value.vpnStatus + )) + } + + private func onVPNStatus(_ notification: Notification) { + + // assume first notified identifier to be the relevant one + // in order to restore VPN status on app launch + if currentBundleIdentifier == nil { + currentBundleIdentifier = notification.vpnBundleIdentifier + } + guard isRelevantNotification(notification) else { + return + } + + var error: Error? + + switch notification.vpnStatus { + case .connected: + startCountingData() + + case .disconnecting: + error = lastError(withBundleIdentifier: notification.vpnBundleIdentifier) + + case .disconnected: + error = lastError(withBundleIdentifier: notification.vpnBundleIdentifier) + stopCountingData() + + default: + break + } + + vpnState.send(AtomicState( + isEnabled: notification.vpnIsEnabled, + vpnStatus: notification.vpnStatus + )) + currentState?.lastError = error + } + + private func onVPNFail(_ notification: Notification) { + vpnState.send(AtomicState( + isEnabled: notification.vpnIsEnabled, + vpnStatus: vpnState.value.vpnStatus + )) + currentState?.lastError = notification.vpnError + } + + private func isRelevantNotification(_ notification: Notification) -> Bool { + guard let notificationTunnelIdentifier = notification.vpnBundleIdentifier else { + return false + } + guard notificationTunnelIdentifier == currentBundleIdentifier else { + pp_log.debug("Skipping not relevant notification from \(notificationTunnelIdentifier)") + return false + } + return true + } + + // MARK: Data count + + private func onDataCount(_: Date) { + switch vpnState.value.vpnStatus { + case .connected: + guard let currentDataCount = currentDataCount else { + return + } + currentState?.dataCount = currentDataCount + + default: + currentState?.dataCount = nil + } + } + + private func startCountingData() { + guard dataCountTimer == nil else { + return + } + dataCountTimer = Timer.TimerPublisher(interval: dataCountInterval, runLoop: .main, mode: .common) + .autoconnect() + .sink { + self.onDataCount($0) + } + } + + private func stopCountingData() { + dataCountTimer?.cancel() + dataCountTimer = nil + + currentState?.dataCount = nil + } + + // MARK: Pulled + + public func serverConfiguration(forProtocol vpnProtocol: VPNProtocolType) -> Any? { + switch vpnProtocol { + case .openVPN: + return defaults.openVPNServerConfiguration + + default: + return nil + } + } + + public func debugLogURL(forProtocol vpnProtocol: VPNProtocolType) -> URL? { + switch vpnProtocol { + case .openVPN: + return defaults.openVPNURLForDebugLog(appGroup: appGroup) + + default: + return defaults.wireGuardURLForDebugLog(appGroup: appGroup) + } + } + + // MARK: Callbacks + + private func lastError(withBundleIdentifier bundleIdentifier: String?) -> Error? { + switch bundleIdentifier { + case tunnelBundleIdentifier(.openVPN): + return defaults.openVPNLastError + + case tunnelBundleIdentifier(.wireGuard): + return defaults.wireGuardLastError + + default: + return nil + } + } + + private var currentDataCount: DataCount? { + switch currentBundleIdentifier { + case tunnelBundleIdentifier(.openVPN): + return defaults.openVPNDataCount + + default: + return nil + } + } +} diff --git a/PassepartoutCore/Sources/PassepartoutCore/Managers/VPNManagerStrategy.swift b/PassepartoutLibrary/Sources/PassepartoutVPN/Managers/VPNManagerStrategy.swift similarity index 94% rename from PassepartoutCore/Sources/PassepartoutCore/Managers/VPNManagerStrategy.swift rename to PassepartoutLibrary/Sources/PassepartoutVPN/Managers/VPNManagerStrategy.swift index 94b4aa84..6695f2e5 100644 --- a/PassepartoutCore/Sources/PassepartoutCore/Managers/VPNManagerStrategy.swift +++ b/PassepartoutLibrary/Sources/PassepartoutVPN/Managers/VPNManagerStrategy.swift @@ -25,10 +25,10 @@ import Foundation import Combine +import PassepartoutCore -@MainActor public protocol VPNManagerStrategy { - func observe(into state: VPNManager.ObservableState) + func observe(into state: ObservableVPNState) func reinstate(configuration: VPNConfiguration) async diff --git a/PassepartoutCore/Sources/PassepartoutCore/Models/VPNManager+ObservableState.swift b/PassepartoutLibrary/Sources/PassepartoutVPN/Models/ObservableVPNState.swift similarity index 50% rename from PassepartoutCore/Sources/PassepartoutCore/Models/VPNManager+ObservableState.swift rename to PassepartoutLibrary/Sources/PassepartoutVPN/Models/ObservableVPNState.swift index 57cb2906..cb2a4ef0 100644 --- a/PassepartoutCore/Sources/PassepartoutCore/Models/VPNManager+ObservableState.swift +++ b/PassepartoutLibrary/Sources/PassepartoutVPN/Models/ObservableVPNState.swift @@ -1,5 +1,5 @@ // -// VPNManager+ObservableState.swift +// ObservableVPNState.swift // Passepartout // // Created by Davide De Rosa on 3/27/22. @@ -24,41 +24,42 @@ // import Foundation +import TunnelKitCore import TunnelKitManager +import PassepartoutCore +import PassepartoutUtils -extension VPNManager { - public class ObservableState: ObservableObject { - @Published public internal(set) var isEnabled = false { - didSet { - pp_log.debug("VPN enabled -> \(isEnabled)") - } - } - - @Published public internal(set) var vpnStatus: VPNStatus = .disconnected { - didSet { - pp_log.debug("VPN status: \(vpnStatus)") - } - } - - @Published public internal(set) var lastError: Error? { - didSet { - guard let lastError = lastError else { - return - } - pp_log.debug("Last error: \(lastError)") - } - } - - @Published public internal(set) var dataCount: DataCount? { - didSet { - guard let dataCount = dataCount else { - return - } - pp_log.debug("Data count: \(dataCount)") - } - } - - public init() { +public class ObservableVPNState: WrappedVPNState, ObservableObject { + @Published public internal(set) var isEnabled = false { + didSet { + pp_log.debug("VPN enabled -> \(isEnabled)") } } + + @Published public internal(set) var vpnStatus: VPNStatus = .disconnected { + didSet { + pp_log.debug("VPN status: \(vpnStatus)") + } + } + + @Published public internal(set) var lastError: Error? { + didSet { + guard let lastError = lastError else { + return + } + pp_log.debug("Last error: \(lastError)") + } + } + + @Published public internal(set) var dataCount: DataCount? { + didSet { + guard let dataCount = dataCount else { + return + } + pp_log.debug("Data count: \(dataCount)") + } + } + + public init() { + } } diff --git a/PassepartoutCore/Sources/PassepartoutCore/Models/VPNConfiguration.swift b/PassepartoutLibrary/Sources/PassepartoutVPN/Models/VPNConfigurationParameters.swift similarity index 91% rename from PassepartoutCore/Sources/PassepartoutCore/Models/VPNConfiguration.swift rename to PassepartoutLibrary/Sources/PassepartoutVPN/Models/VPNConfigurationParameters.swift index 6877b88c..1accf5a3 100644 --- a/PassepartoutCore/Sources/PassepartoutCore/Models/VPNConfiguration.swift +++ b/PassepartoutLibrary/Sources/PassepartoutVPN/Models/VPNConfigurationParameters.swift @@ -1,8 +1,8 @@ // -// VPNConfiguration.swift +// VPNConfigurationParameters.swift // Passepartout // -// Created by Davide De Rosa on 3/7/22. +// Created by Davide De Rosa on 6/22/22. // Copyright (c) 2022 Davide De Rosa. All rights reserved. // // https://github.com/passepartoutvpn @@ -26,13 +26,7 @@ import Foundation import TunnelKitManager import NetworkExtension - -public typealias VPNConfiguration = (neConfiguration: NetworkExtensionConfiguration, neExtra: NetworkExtensionExtra?) - -@MainActor -protocol VPNConfigurationProviding { - func vpnConfiguration(_ parameters: VPNConfigurationParameters) throws -> VPNConfiguration -} +import PassepartoutCore struct VPNConfigurationParameters { let title: String @@ -69,3 +63,7 @@ struct VPNConfigurationParameters { onDemandRules = profile.onDemand.rules(withCustomRules: withCustomRules) } } + +protocol VPNConfigurationProviding { + func vpnConfiguration(_ parameters: VPNConfigurationParameters) throws -> VPNConfiguration +} diff --git a/PassepartoutCore/Sources/PassepartoutCore/Models/VPNPreferences.swift b/PassepartoutLibrary/Sources/PassepartoutVPN/Models/VPNPreferences.swift similarity index 97% rename from PassepartoutCore/Sources/PassepartoutCore/Models/VPNPreferences.swift rename to PassepartoutLibrary/Sources/PassepartoutVPN/Models/VPNPreferences.swift index 1d333ed4..bdc8785f 100644 --- a/PassepartoutCore/Sources/PassepartoutCore/Models/VPNPreferences.swift +++ b/PassepartoutLibrary/Sources/PassepartoutVPN/Models/VPNPreferences.swift @@ -25,7 +25,7 @@ import Foundation -public protocol VPNPreferences { +protocol VPNPreferences { var tunnelLogPath: String? { get } var tunnelLogFormat: String? { get } diff --git a/PassepartoutLibrary/Sources/PassepartoutVPN/Pickers/VPNProtocolType+All.swift b/PassepartoutLibrary/Sources/PassepartoutVPN/Pickers/VPNProtocolType+All.swift new file mode 100644 index 00000000..8e419d60 --- /dev/null +++ b/PassepartoutLibrary/Sources/PassepartoutVPN/Pickers/VPNProtocolType+All.swift @@ -0,0 +1,34 @@ +// +// VPNProtocolType+All.swift +// Passepartout +// +// Created by Davide De Rosa on 6/22/22. +// Copyright (c) 2022 Davide De Rosa. All rights reserved. +// +// https://github.com/passepartoutvpn +// +// This file is part of Passepartout. +// +// Passepartout is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Passepartout is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Passepartout. If not, see . +// + +import Foundation +import PassepartoutCore + +extension VPNProtocolType { + public static let allTypes: [VPNProtocolType] = [ + .openVPN, + .wireGuard + ].sorted() +} diff --git a/PassepartoutCore/Sources/WireGuardAppExtension/Exports.swift b/PassepartoutLibrary/Sources/WireGuardAppExtension/Exports.swift similarity index 100% rename from PassepartoutCore/Sources/WireGuardAppExtension/Exports.swift rename to PassepartoutLibrary/Sources/WireGuardAppExtension/Exports.swift diff --git a/PassepartoutCore/Tests/PassepartoutCoreTests/CoreTests.swift b/PassepartoutLibrary/Tests/PassepartoutCoreTests/CoreTests.swift similarity index 97% rename from PassepartoutCore/Tests/PassepartoutCoreTests/CoreTests.swift rename to PassepartoutLibrary/Tests/PassepartoutCoreTests/CoreTests.swift index ab59a4a0..bfabcd25 100644 --- a/PassepartoutCore/Tests/PassepartoutCoreTests/CoreTests.swift +++ b/PassepartoutLibrary/Tests/PassepartoutCoreTests/CoreTests.swift @@ -24,7 +24,7 @@ // import XCTest -import PassepartoutCore +import PassepartoutLibrary class CoreTests: XCTestCase { override func setUp() { diff --git a/PassepartoutCore/Tests/PassepartoutProfilesTests/ProfilesTests.swift b/PassepartoutLibrary/Tests/PassepartoutProfilesTests/ProfilesTests.swift similarity index 97% rename from PassepartoutCore/Tests/PassepartoutProfilesTests/ProfilesTests.swift rename to PassepartoutLibrary/Tests/PassepartoutProfilesTests/ProfilesTests.swift index 5c947a65..e92b74ca 100644 --- a/PassepartoutCore/Tests/PassepartoutProfilesTests/ProfilesTests.swift +++ b/PassepartoutLibrary/Tests/PassepartoutProfilesTests/ProfilesTests.swift @@ -27,10 +27,7 @@ import XCTest @testable import PassepartoutProfiles import SwiftyBeaver -@MainActor class ProfilesTests: XCTestCase { - - @MainActor override func setUp() { } diff --git a/PassepartoutCore/Tests/PassepartoutProvidersTests/ProvidersTests.swift b/PassepartoutLibrary/Tests/PassepartoutProvidersTests/ProvidersTests.swift similarity index 99% rename from PassepartoutCore/Tests/PassepartoutProvidersTests/ProvidersTests.swift rename to PassepartoutLibrary/Tests/PassepartoutProvidersTests/ProvidersTests.swift index 7d221e75..6088657d 100644 --- a/PassepartoutCore/Tests/PassepartoutProvidersTests/ProvidersTests.swift +++ b/PassepartoutLibrary/Tests/PassepartoutProvidersTests/ProvidersTests.swift @@ -31,7 +31,6 @@ import PassepartoutServices import PassepartoutUtils import SwiftyBeaver -@MainActor class ProvidersTests: XCTestCase { private static let persistence: Persistence = { let model = NSManagedObjectModel.mergedModel(from: [.module])! @@ -42,7 +41,6 @@ class ProvidersTests: XCTestCase { private var cancellables: Set = [] - @MainActor override func setUp() { pp_log.addDestination(ConsoleDestination()) diff --git a/PassepartoutCore/Tests/PassepartoutServicesTests/ServicesTests.swift b/PassepartoutLibrary/Tests/PassepartoutServicesTests/ServicesTests.swift similarity index 100% rename from PassepartoutCore/Tests/PassepartoutServicesTests/ServicesTests.swift rename to PassepartoutLibrary/Tests/PassepartoutServicesTests/ServicesTests.swift diff --git a/PassepartoutCore/Tests/PassepartoutUtilsTests/Resources/Debug.log b/PassepartoutLibrary/Tests/PassepartoutUtilsTests/Resources/Debug.log similarity index 100% rename from PassepartoutCore/Tests/PassepartoutUtilsTests/Resources/Debug.log rename to PassepartoutLibrary/Tests/PassepartoutUtilsTests/Resources/Debug.log diff --git a/PassepartoutCore/Tests/PassepartoutUtilsTests/UtilsTests.swift b/PassepartoutLibrary/Tests/PassepartoutUtilsTests/UtilsTests.swift similarity index 100% rename from PassepartoutCore/Tests/PassepartoutUtilsTests/UtilsTests.swift rename to PassepartoutLibrary/Tests/PassepartoutUtilsTests/UtilsTests.swift