Refactor library into domain + impl

This commit is contained in:
Davide De Rosa 2022-06-23 23:31:01 +02:00
parent 8504998bbb
commit 9a8477225e
239 changed files with 1713 additions and 1415 deletions

4
.gitmodules vendored
View File

@ -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

2
API
View File

@ -1 +1 @@
PassepartoutCore/Sources/PassepartoutServices/API/
PassepartoutLibrary/Sources/PassepartoutServices/API/

View File

@ -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 = "<group>"; };
0E49F6BE27D764AF00385834 /* EndpointAdvancedView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EndpointAdvancedView.swift; sourceTree = "<group>"; };
0E53249627D26B51002565C3 /* ProductManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProductManager.swift; sourceTree = "<group>"; };
0E5324A527D297BB002565C3 /* InApp.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InApp.swift; sourceTree = "<group>"; };
0E5324A827D2AC55002565C3 /* LongContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LongContentView.swift; sourceTree = "<group>"; };
0E5349BD27C16A4500C71BB3 /* StyledPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StyledPicker.swift; sourceTree = "<group>"; };
0E5349C527C176C200C71BB3 /* EndpointView+OpenVPN.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EndpointView+OpenVPN.swift"; sourceTree = "<group>"; };
@ -282,7 +273,6 @@
0E9E5AED27B44CF1008C95DA /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = "<group>"; };
0E9E5AEE27B44CF1008C95DA /* pt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pt; path = pt.lproj/Localizable.strings; sourceTree = "<group>"; };
0E9ED48027FD9BAE003B2316 /* CopySavingButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CopySavingButton.swift; sourceTree = "<group>"; };
0EA26DC827353020000F251A /* PassepartoutCore */ = {isa = PBXFileReference; lastKnownFileType = folder; path = PassepartoutCore; sourceTree = "<group>"; };
0EA591122733DD4E0096F796 /* IntentDispatcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IntentDispatcher.swift; sourceTree = "<group>"; };
0EA591152733DDDA0096F796 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.intentdefinition; name = Base; path = Base.lproj/Intents.intentdefinition; sourceTree = "<group>"; };
0EA591182733DDF60096F796 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Intents.strings; sourceTree = "<group>"; };
@ -321,6 +311,7 @@
0EBE2FD72360F89600F0D5AB /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/InfoPlist.strings; sourceTree = "<group>"; };
0EBE2FD82360F89600F0D5AB /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/InfoPlist.strings; sourceTree = "<group>"; };
0EBE880E281B18DE0090D9E6 /* ProfileRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileRow.swift; sourceTree = "<group>"; };
0ECB78EA2861D1F300B0E460 /* PassepartoutLibrary */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = PassepartoutLibrary; sourceTree = "<group>"; };
0ECF71ED27B6A99300CDB528 /* AccountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountView.swift; sourceTree = "<group>"; };
0ED1D6DB27DBA41700983466 /* DiagnosticsView+OpenVPN.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DiagnosticsView+OpenVPN.swift"; sourceTree = "<group>"; };
0ED1D6DD27DBA42100983466 /* DiagnosticsView+WireGuard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DiagnosticsView+WireGuard.swift"; sourceTree = "<group>"; };
@ -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 = "<group>";
};
0ECB78D5285F508B00B0E460 /* Reusable */ = {
isa = PBXGroup;
children = (
0E5324A527D297BB002565C3 /* InApp.swift */,
);
path = Reusable;
sourceTree = "<group>";
};
0ED2B33C27D3C52900FD8EA9 /* OpenVPN */ = {
isa = PBXGroup;
children = (
@ -673,7 +655,7 @@
0EE315DB2733104700F5D461 /* Packages */ = {
isa = PBXGroup;
children = (
0EA26DC827353020000F251A /* PassepartoutCore */,
0ECB78EA2861D1F300B0E460 /* PassepartoutLibrary */,
);
name = Packages;
sourceTree = "<group>";
@ -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 */;

View File

@ -24,7 +24,7 @@
//
import SwiftUI
import PassepartoutCore
import PassepartoutLibrary
extension View {
var themeIdiom: UIUserInterfaceIdiom {

View File

@ -25,9 +25,8 @@
import Foundation
import Combine
import PassepartoutCore
import PassepartoutLibrary
@MainActor
class AppContext {
private let logManager: LogManager

View File

@ -24,7 +24,7 @@
//
import Foundation
import PassepartoutUtils
import PassepartoutLibrary
enum AppPreference: String, KeyStoreDomainLocation {
case isShowingFavorites

View File

@ -24,7 +24,7 @@
//
import Foundation
import PassepartoutCore
import PassepartoutLibrary
extension DebugLog {
func decoratedString() -> String {

View File

@ -24,7 +24,7 @@
//
import Foundation
import PassepartoutCore
import PassepartoutLibrary
extension ProviderMetadata: Identifiable, Comparable, Hashable {
public var id: String {

View File

@ -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

View File

@ -24,7 +24,7 @@
//
import Foundation
import PassepartoutCore
import PassepartoutLibrary
extension VPNProtocolType {
static let knownFileExtensions: [String] = {

View File

@ -25,9 +25,8 @@
import Foundation
import Intents
import PassepartoutCore
import PassepartoutLibrary
@MainActor
extension IntentDispatcher {
private enum IntentError: Error {
case notProvider(UUID)

View File

@ -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 {

View File

@ -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<Void, Never>()
@MainActor
override init() {
super.init()
reloadShortcuts()

View File

@ -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<VPNManager>) -> some View {
onContinueUserActivity(activity.name) { userActivity in

View File

@ -26,7 +26,6 @@
import UIKit
import StoreKit
@MainActor
public class Reviewer: ObservableObject {
private struct Keys {
static let eventCount = "Reviewer.EventCount"

View File

@ -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?

View File

@ -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

View File

@ -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?")

View File

@ -24,7 +24,7 @@
//
import SwiftUI
import PassepartoutCore
import PassepartoutLibrary
struct AddProfileMenu: View {
enum ModalType: Identifiable {

View File

@ -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

View File

@ -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

View File

@ -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))
}

View File

@ -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,

View File

@ -25,7 +25,7 @@
import SwiftUI
import Combine
import PassepartoutCore
import PassepartoutLibrary
struct DebugLogView: View {
private let url: URL

View File

@ -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

View File

@ -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?

View File

@ -24,7 +24,7 @@
//
import SwiftUI
import PassepartoutCore
import PassepartoutLibrary
struct DiagnosticsView: View {
let vpnProtocol: VPNProtocolType

View File

@ -25,6 +25,7 @@
import SwiftUI
import StoreKit
import PassepartoutLibrary
struct DonateView: View {
enum AlertType: Identifiable {

View File

@ -25,7 +25,7 @@
import SwiftUI
import TunnelKitOpenVPN
import PassepartoutCore
import PassepartoutLibrary
extension EndpointAdvancedView {
struct OpenVPNView: View {

View File

@ -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

View File

@ -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

View File

@ -24,7 +24,7 @@
//
import SwiftUI
import PassepartoutCore
import PassepartoutLibrary
struct EndpointView: View {
@ObservedObject private var currentProfile: ObservableProfile

View File

@ -24,7 +24,7 @@
//
import SwiftUI
import PassepartoutCore
import PassepartoutLibrary
struct InfoMenu: View {
enum ModalType: Identifiable {

View File

@ -24,7 +24,7 @@
//
import SwiftUI
import PassepartoutCore
import PassepartoutLibrary
struct NetworkSettingsView: View {
@ObservedObject private var currentProfile: ObservableProfile

View File

@ -24,7 +24,7 @@
//
import SwiftUI
import PassepartoutCore
import PassepartoutLibrary
extension OnDemandView {
struct SSIDList: View {

View File

@ -24,7 +24,7 @@
//
import SwiftUI
import PassepartoutCore
import PassepartoutLibrary
struct OnDemandView: View {
@ObservedObject private var productManager: ProductManager

View File

@ -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

View File

@ -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

View File

@ -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)
}
}

View File

@ -25,7 +25,7 @@
import SwiftUI
import StoreKit
import PassepartoutCore
import PassepartoutLibrary
extension PaywallView {
struct PurchaseView: View {

View File

@ -24,7 +24,7 @@
//
import SwiftUI
import PassepartoutCore
import PassepartoutLibrary
struct ProfileRow: View {
let header: Profile.Header

View File

@ -24,7 +24,7 @@
//
import SwiftUI
import PassepartoutCore
import PassepartoutLibrary
extension ProfileView {
struct ConfigurationSection: View {

View File

@ -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

View File

@ -24,7 +24,7 @@
//
import SwiftUI
import PassepartoutCore
import PassepartoutLibrary
extension ProfileView {
struct ExtraSection: View {

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 {

View File

@ -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<Bool>) {
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

View File

@ -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

View File

@ -25,7 +25,7 @@
import SwiftUI
import MessageUI
import PassepartoutCore
import PassepartoutLibrary
struct ReportIssueView: View {
@Binding private var isPresented: Bool

View File

@ -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()

View File

@ -25,7 +25,7 @@
import SwiftUI
import Intents
import PassepartoutCore
import PassepartoutLibrary
struct ShortcutsView: View {
enum ModalType: Identifiable {

View File

@ -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

View File

@ -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
)
}
}

View File

@ -24,7 +24,7 @@
//
import SwiftUI
import PassepartoutCore
import PassepartoutLibrary
import SwiftyBeaver
extension View {

View File

@ -25,7 +25,7 @@
import Foundation
import UniformTypeIdentifiers
import PassepartoutCore
import PassepartoutLibrary
import SwiftyBeaver
extension Constants {

View File

@ -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
}

View File

@ -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<DefaultProfileManager>
}
@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<AnyCancellable> = []
@ -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,

View File

@ -25,7 +25,7 @@
import Foundation
import StoreKit
import PassepartoutCore
import PassepartoutLibrary
struct LocalProduct: RawRepresentable, Equatable, Hashable {
private static let bundleSubdomain = "ios"

View File

@ -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

View File

@ -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?

View File

@ -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)
}
}

View File

@ -28,7 +28,7 @@ import TunnelKitManager
import TunnelKitOpenVPN
import TunnelKitWireGuard
import NetworkExtension
import PassepartoutCore
import PassepartoutLibrary
extension VPNStatus {
var localizedDescription: String {

View File

@ -24,7 +24,7 @@
//
import Foundation
import PassepartoutCore
import PassepartoutLibrary
enum Unlocalized {
static let appName = Constants.Global.appName

View File

@ -1,289 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1330"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "PassepartoutCore_PassepartoutServices"
BuildableName = "PassepartoutCore_PassepartoutServices"
BlueprintName = "PassepartoutCore_PassepartoutServices"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "PassepartoutCore_PassepartoutProviders"
BuildableName = "PassepartoutCore_PassepartoutProviders"
BlueprintName = "PassepartoutCore_PassepartoutProviders"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "PassepartoutCore_PassepartoutProfiles"
BuildableName = "PassepartoutCore_PassepartoutProfiles"
BlueprintName = "PassepartoutCore_PassepartoutProfiles"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "PassepartoutCore_PassepartoutUtilsTests"
BuildableName = "PassepartoutCore_PassepartoutUtilsTests"
BlueprintName = "PassepartoutCore_PassepartoutUtilsTests"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "OpenVPNAppExtension"
BuildableName = "OpenVPNAppExtension"
BlueprintName = "OpenVPNAppExtension"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "PassepartoutCore"
BuildableName = "PassepartoutCore"
BlueprintName = "PassepartoutCore"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "WireGuardAppExtension"
BuildableName = "WireGuardAppExtension"
BlueprintName = "WireGuardAppExtension"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "PassepartoutProvidersTests"
BuildableName = "PassepartoutProvidersTests"
BlueprintName = "PassepartoutProvidersTests"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "PassepartoutServicesTests"
BuildableName = "PassepartoutServicesTests"
BlueprintName = "PassepartoutServicesTests"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "PassepartoutUtilsTests"
BuildableName = "PassepartoutUtilsTests"
BlueprintName = "PassepartoutUtilsTests"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "PassepartoutProfiles"
BuildableName = "PassepartoutProfiles"
BlueprintName = "PassepartoutProfiles"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "PassepartoutProviders"
BuildableName = "PassepartoutProviders"
BlueprintName = "PassepartoutProviders"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "PassepartoutServices"
BuildableName = "PassepartoutServices"
BlueprintName = "PassepartoutServices"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "PassepartoutUtils"
BuildableName = "PassepartoutUtils"
BlueprintName = "PassepartoutUtils"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "PassepartoutProvidersTests"
BuildableName = "PassepartoutProvidersTests"
BlueprintName = "PassepartoutProvidersTests"
ReferencedContainer = "container:">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "PassepartoutServicesTests"
BuildableName = "PassepartoutServicesTests"
BlueprintName = "PassepartoutServicesTests"
ReferencedContainer = "container:">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "PassepartoutUtilsTests"
BuildableName = "PassepartoutUtilsTests"
BlueprintName = "PassepartoutUtilsTests"
ReferencedContainer = "container:">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "PassepartoutProfilesTests"
BuildableName = "PassepartoutProfilesTests"
BlueprintName = "PassepartoutProfilesTests"
ReferencedContainer = "container:">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "PassepartoutCore_PassepartoutServices"
BuildableName = "PassepartoutCore_PassepartoutServices"
BlueprintName = "PassepartoutCore_PassepartoutServices"
ReferencedContainer = "container:">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -1,67 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1320"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "PassepartoutCore"
BuildableName = "PassepartoutCore"
BlueprintName = "PassepartoutCore"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "PassepartoutCore"
BuildableName = "PassepartoutCore"
BlueprintName = "PassepartoutCore"
ReferencedContainer = "container:">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -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 <http://www.gnu.org/licenses/>.
//
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
}
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
//
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<AtomicState, Never>(.init())
private var dataCountTimer: AnyCancellable?
private var cancellables: Set<AnyCancellable> = []
// 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
}
}
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
//
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()
}
}
}

View File

@ -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"]),

View File

@ -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)
}
}

View File

@ -24,7 +24,6 @@
//
import Foundation
import PassepartoutUtils
extension Profile.NetworkSettings {
public var isAutomaticGateway: Bool {

View File

@ -24,7 +24,6 @@
//
import Foundation
import PassepartoutUtils
extension Profile.OnDemand {
public var withMobileNetwork: Bool {

View File

@ -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 <http://www.gnu.org/licenses/>.
//
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)
}
}
}
}

View File

@ -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)
}
}

View File

@ -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 }
}

View File

@ -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 <http://www.gnu.org/licenses/>.
//
import Foundation
public protocol CurrentVPNStateProviding {
associatedtype WrappedType: WrappedVPNState
var currentState: WrappedType { get }
}

View File

@ -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 <http://www.gnu.org/licenses/>.
//
import Foundation
import Combine
public protocol ProfileManager {
typealias ProfileEx = (profile: Profile, isReady: Bool)
var activeProfileId: UUID? { get }
var activeProfileIdPublisher: Published<UUID?>.Publisher { get }
var currentProfileId: UUID? { get set }
var didCreateProfile: PassthroughSubject<Profile, Never> { 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()
}

View File

@ -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 <http://www.gnu.org/licenses/>.
//
import Foundation
public protocol ProfileManagerWithCurrentProfile: ProfileManager, CurrentProfileProviding {
}

View File

@ -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 <http://www.gnu.org/licenses/>.
//
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<Void, Error>
func fetchProviderPublisher(
withName providerName: ProviderName,
vpnProtocol: VPNProtocolType,
priority: ProviderManagerFetchPriority
) -> AnyPublisher<Void, Error>
func reset()
}

View File

@ -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 <http://www.gnu.org/licenses/>.
//
import Foundation
public enum ProviderManagerFetchPriority {
case bundle
case remote
case remoteThenBundle
}

View File

@ -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 <http://www.gnu.org/licenses/>.
//
import Foundation
import Combine
public protocol VPNManager {
var lastError: Error? { get }
var configurationError: PassthroughSubject<VPNConfigurationError, Never> { 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()
}

View File

@ -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 <http://www.gnu.org/licenses/>.
//
import Foundation
public protocol VPNManagerWithCurrentState: VPNManager, CurrentVPNStateProviding {
}

View File

@ -24,7 +24,6 @@
//
import Foundation
import PassepartoutProviders
extension Profile {
public struct Header: Codable, Identifiable, Hashable {

Some files were not shown because too many files have changed in this diff Show More