Rethink library architecture (#301)

This commit is contained in:
Davide De Rosa 2023-05-24 18:19:47 +02:00 committed by GitHub
parent b4ad8dea0d
commit 7ccb10febc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
223 changed files with 2948 additions and 1647 deletions

2
.gitmodules vendored
View File

@ -1,3 +1,3 @@
[submodule "PassepartoutLibrary/Sources/PassepartoutServices/API"] [submodule "PassepartoutLibrary/Sources/PassepartoutServices/API"]
path = PassepartoutLibrary/Sources/PassepartoutServices/API path = PassepartoutLibrary/Sources/PassepartoutProvidersImpl/API
url = https://github.com/passepartoutvpn/api url = https://github.com/passepartoutvpn/api

2
API
View File

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

View File

@ -103,6 +103,11 @@
0E71ACFD27C1321A00F85C4B /* ActivityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E71ACFC27C1321A00F85C4B /* ActivityView.swift */; }; 0E71ACFD27C1321A00F85C4B /* ActivityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E71ACFC27C1321A00F85C4B /* ActivityView.swift */; };
0E7577D72816A3B200081CBE /* DestructiveButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7577D62816A3B200081CBE /* DestructiveButton.swift */; }; 0E7577D72816A3B200081CBE /* DestructiveButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7577D62816A3B200081CBE /* DestructiveButton.swift */; };
0E7577DF2817E22C00081CBE /* VPNToggle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7577DE2817E22C00081CBE /* VPNToggle.swift */; }; 0E7577DF2817E22C00081CBE /* VPNToggle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7577DE2817E22C00081CBE /* VPNToggle.swift */; };
0E7A8C0A2A1D410500780F4B /* PersistenceManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7A8C092A1D410400780F4B /* PersistenceManager.swift */; };
0E7A8C0C2A1D4A6100780F4B /* PassepartoutLibrary in Frameworks */ = {isa = PBXBuildFile; productRef = 0E7A8C0B2A1D4A6100780F4B /* PassepartoutLibrary */; };
0E7A8C0E2A1D4A6E00780F4B /* PassepartoutLibrary in Frameworks */ = {isa = PBXBuildFile; productRef = 0E7A8C0D2A1D4A6E00780F4B /* PassepartoutLibrary */; };
0E7A8C0F2A1D54DE00780F4B /* Picker+OpenVPN.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7A8C072A1D40BA00780F4B /* Picker+OpenVPN.swift */; };
0E7A8C102A1D54DE00780F4B /* Picker+Network.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7A8C082A1D40BA00780F4B /* Picker+Network.swift */; };
0E90DFE627BACC1500EF5078 /* AddHostViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E90DFE527BACC1500EF5078 /* AddHostViewModel.swift */; }; 0E90DFE627BACC1500EF5078 /* AddHostViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E90DFE527BACC1500EF5078 /* AddHostViewModel.swift */; };
0E92D7C627F103300033CB7B /* ProfileView+Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E92D7C527F103300033CB7B /* ProfileView+Configuration.swift */; }; 0E92D7C627F103300033CB7B /* ProfileView+Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E92D7C527F103300033CB7B /* ProfileView+Configuration.swift */; };
0E92D7C927F1042A0033CB7B /* ProfileView+Extra.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E92D7C827F1042A0033CB7B /* ProfileView+Extra.swift */; }; 0E92D7C927F1042A0033CB7B /* ProfileView+Extra.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E92D7C827F1042A0033CB7B /* ProfileView+Extra.swift */; };
@ -138,7 +143,6 @@
0EA1D84728805EAE00F3CA48 /* Flags.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0EA1D84628805EAE00F3CA48 /* Flags.xcassets */; }; 0EA1D84728805EAE00F3CA48 /* Flags.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0EA1D84628805EAE00F3CA48 /* Flags.xcassets */; };
0EA591162733DDDA0096F796 /* Intents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = 0EA591142733DDDA0096F796 /* Intents.intentdefinition */; }; 0EA591162733DDDA0096F796 /* Intents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = 0EA591142733DDDA0096F796 /* Intents.intentdefinition */; };
0EA9030B287045F70087BC73 /* SystemMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA9030A287045F70087BC73 /* SystemMenu.swift */; }; 0EA9030B287045F70087BC73 /* SystemMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA9030A287045F70087BC73 /* SystemMenu.swift */; };
0EB13BBE290E835A003CB654 /* PassepartoutLibrary in Frameworks */ = {isa = PBXBuildFile; productRef = 0EB13BBD290E835A003CB654 /* PassepartoutLibrary */; };
0EB13BC0290E8C8D003CB654 /* PassepartoutTestsApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB13BBF290E8C8D003CB654 /* PassepartoutTestsApp.swift */; }; 0EB13BC0290E8C8D003CB654 /* PassepartoutTestsApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB13BBF290E8C8D003CB654 /* PassepartoutTestsApp.swift */; };
0EB17EA727D226B400D473B5 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB17EA127D2263700D473B5 /* Constants.swift */; }; 0EB17EA727D226B400D473B5 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB17EA127D2263700D473B5 /* Constants.swift */; };
0EB17EA927D226C900D473B5 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB17EA127D2263700D473B5 /* Constants.swift */; }; 0EB17EA927D226C900D473B5 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB17EA127D2263700D473B5 /* Constants.swift */; };
@ -159,7 +163,6 @@
0EBC076027EC587900208AD9 /* SwiftGen+Strings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBC075F27EC587900208AD9 /* SwiftGen+Strings.swift */; }; 0EBC076027EC587900208AD9 /* SwiftGen+Strings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBC075F27EC587900208AD9 /* SwiftGen+Strings.swift */; };
0EBE880F281B18DE0090D9E6 /* OrganizerView+ProfileRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBE880E281B18DE0090D9E6 /* OrganizerView+ProfileRow.swift */; }; 0EBE880F281B18DE0090D9E6 /* OrganizerView+ProfileRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBE880E281B18DE0090D9E6 /* OrganizerView+ProfileRow.swift */; };
0ECB78E9285F5DE300B0E460 /* PassepartoutMac.bundle in Embed Plugins */ = {isa = PBXBuildFile; fileRef = 0ECB78DA285F52F700B0E460 /* PassepartoutMac.bundle */; platformFilter = maccatalyst; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 0ECB78E9285F5DE300B0E460 /* PassepartoutMac.bundle in Embed Plugins */ = {isa = PBXBuildFile; fileRef = 0ECB78DA285F52F700B0E460 /* PassepartoutMac.bundle */; platformFilter = maccatalyst; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
0ECB78EC2863A21600B0E460 /* PassepartoutLibrary in Frameworks */ = {isa = PBXBuildFile; productRef = 0ECB78EB2863A21600B0E460 /* PassepartoutLibrary */; };
0ECF71EE27B6A99300CDB528 /* AccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECF71ED27B6A99300CDB528 /* AccountView.swift */; }; 0ECF71EE27B6A99300CDB528 /* AccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECF71ED27B6A99300CDB528 /* AccountView.swift */; };
0ED1D6DC27DBA41700983466 /* DiagnosticsView+OpenVPN.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ED1D6DB27DBA41700983466 /* DiagnosticsView+OpenVPN.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 */; }; 0ED1D6DE27DBA42100983466 /* DiagnosticsView+WireGuard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ED1D6DD27DBA42100983466 /* DiagnosticsView+WireGuard.swift */; };
@ -295,6 +298,7 @@
0E021D9B284E68580077EF5D /* AppContext.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppContext.swift; sourceTree = "<group>"; }; 0E021D9B284E68580077EF5D /* AppContext.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppContext.swift; sourceTree = "<group>"; };
0E0392762818732D00827C10 /* BuildProducts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BuildProducts.swift; sourceTree = "<group>"; }; 0E0392762818732D00827C10 /* BuildProducts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BuildProducts.swift; sourceTree = "<group>"; };
0E039278281890B100827C10 /* AddHostView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddHostView.swift; sourceTree = "<group>"; }; 0E039278281890B100827C10 /* AddHostView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddHostView.swift; sourceTree = "<group>"; };
0E0480372A1A4AE000462F2F /* Passepartout.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = Passepartout.xctestplan; sourceTree = "<group>"; };
0E04F0052883462E00BFCE1C /* LightUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LightUtils.swift; sourceTree = "<group>"; }; 0E04F0052883462E00BFCE1C /* LightUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LightUtils.swift; sourceTree = "<group>"; };
0E04F0082883466500BFCE1C /* DefaultLightUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultLightUtils.swift; sourceTree = "<group>"; }; 0E04F0082883466500BFCE1C /* DefaultLightUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultLightUtils.swift; sourceTree = "<group>"; };
0E065F102813269500062CAF /* WelcomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeView.swift; sourceTree = "<group>"; }; 0E065F102813269500062CAF /* WelcomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeView.swift; sourceTree = "<group>"; };
@ -390,6 +394,9 @@
0E71ACFC27C1321A00F85C4B /* ActivityView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityView.swift; sourceTree = "<group>"; }; 0E71ACFC27C1321A00F85C4B /* ActivityView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityView.swift; sourceTree = "<group>"; };
0E7577D62816A3B200081CBE /* DestructiveButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DestructiveButton.swift; sourceTree = "<group>"; }; 0E7577D62816A3B200081CBE /* DestructiveButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DestructiveButton.swift; sourceTree = "<group>"; };
0E7577DE2817E22C00081CBE /* VPNToggle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNToggle.swift; sourceTree = "<group>"; }; 0E7577DE2817E22C00081CBE /* VPNToggle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNToggle.swift; sourceTree = "<group>"; };
0E7A8C072A1D40BA00780F4B /* Picker+OpenVPN.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Picker+OpenVPN.swift"; sourceTree = "<group>"; };
0E7A8C082A1D40BA00780F4B /* Picker+Network.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Picker+Network.swift"; sourceTree = "<group>"; };
0E7A8C092A1D410400780F4B /* PersistenceManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersistenceManager.swift; sourceTree = "<group>"; };
0E90DFE527BACC1500EF5078 /* AddHostViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddHostViewModel.swift; sourceTree = "<group>"; }; 0E90DFE527BACC1500EF5078 /* AddHostViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddHostViewModel.swift; sourceTree = "<group>"; };
0E92D7C527F103300033CB7B /* ProfileView+Configuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProfileView+Configuration.swift"; sourceTree = "<group>"; }; 0E92D7C527F103300033CB7B /* ProfileView+Configuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProfileView+Configuration.swift"; sourceTree = "<group>"; };
0E92D7C827F1042A0033CB7B /* ProfileView+Extra.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProfileView+Extra.swift"; sourceTree = "<group>"; }; 0E92D7C827F1042A0033CB7B /* ProfileView+Extra.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProfileView+Extra.swift"; sourceTree = "<group>"; };
@ -532,7 +539,7 @@
files = ( files = (
0E9C3B6F27FC573E00D0F02E /* CloudKit.framework in Frameworks */, 0E9C3B6F27FC573E00D0F02E /* CloudKit.framework in Frameworks */,
0E53249D27D28FC7002565C3 /* Kvitto in Frameworks */, 0E53249D27D28FC7002565C3 /* Kvitto in Frameworks */,
0ECB78EC2863A21600B0E460 /* PassepartoutLibrary in Frameworks */, 0E7A8C0C2A1D4A6100780F4B /* PassepartoutLibrary in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -540,7 +547,7 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
0EB13BBE290E835A003CB654 /* PassepartoutLibrary in Frameworks */, 0E7A8C0E2A1D4A6E00780F4B /* PassepartoutLibrary in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -577,6 +584,7 @@
children = ( children = (
0E021D9A284E68580077EF5D /* CoreContext.swift */, 0E021D9A284E68580077EF5D /* CoreContext.swift */,
0E29385B285A8B30002A6E0E /* CoreContext+Shared.swift */, 0E29385B285A8B30002A6E0E /* CoreContext+Shared.swift */,
0E7A8C092A1D410400780F4B /* PersistenceManager.swift */,
); );
path = Context; path = Context;
sourceTree = "<group>"; sourceTree = "<group>";
@ -792,6 +800,7 @@
children = ( children = (
0EE315DB2733104700F5D461 /* Packages */, 0EE315DB2733104700F5D461 /* Packages */,
0E23B4A12298559800304C30 /* Config.xcconfig */, 0E23B4A12298559800304C30 /* Config.xcconfig */,
0E0480372A1A4AE000462F2F /* Passepartout.xctestplan */,
0E9AA982259F7674003FAFF1 /* Passepartout */, 0E9AA982259F7674003FAFF1 /* Passepartout */,
0EB13BAD290E825E003CB654 /* PassepartoutTests */, 0EB13BAD290E825E003CB654 /* PassepartoutTests */,
0E57F63920C83FC5008323CF /* Products */, 0E57F63920C83FC5008323CF /* Products */,
@ -812,6 +821,15 @@
name = Products; name = Products;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
0E7A8C062A1D40BA00780F4B /* Pickers */ = {
isa = PBXGroup;
children = (
0E7A8C072A1D40BA00780F4B /* Picker+OpenVPN.swift */,
0E7A8C082A1D40BA00780F4B /* Picker+Network.swift */,
);
path = Pickers;
sourceTree = "<group>";
};
0E92781227E7CD530057BB81 /* InApp */ = { 0E92781227E7CD530057BB81 /* InApp */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -875,6 +893,7 @@
0E92781227E7CD530057BB81 /* InApp */, 0E92781227E7CD530057BB81 /* InApp */,
0EA591112733DD4E0096F796 /* Intents */, 0EA591112733DD4E0096F796 /* Intents */,
0E5467F12867A52B00F74D1C /* Mac */, 0E5467F12867A52B00F74D1C /* Mac */,
0E7A8C062A1D40BA00780F4B /* Pickers */,
0E2C171C27CB6307007E8488 /* Reusable */, 0E2C171C27CB6307007E8488 /* Reusable */,
0E35C0AE280EF8A80071FA35 /* Views */, 0E35C0AE280EF8A80071FA35 /* Views */,
0E6059CA27FCC5DE003F4063 /* Assets.xcassets */, 0E6059CA27FCC5DE003F4063 /* Assets.xcassets */,
@ -1076,7 +1095,7 @@
name = Passepartout; name = Passepartout;
packageProductDependencies = ( packageProductDependencies = (
0E53249C27D28FC7002565C3 /* Kvitto */, 0E53249C27D28FC7002565C3 /* Kvitto */,
0ECB78EB2863A21600B0E460 /* PassepartoutLibrary */, 0E7A8C0B2A1D4A6100780F4B /* PassepartoutLibrary */,
); );
productName = Passepartout; productName = Passepartout;
productReference = 0E57F63820C83FC5008323CF /* Passepartout.app */; productReference = 0E57F63820C83FC5008323CF /* Passepartout.app */;
@ -1097,7 +1116,7 @@
); );
name = PassepartoutTests; name = PassepartoutTests;
packageProductDependencies = ( packageProductDependencies = (
0EB13BBD290E835A003CB654 /* PassepartoutLibrary */, 0E7A8C0D2A1D4A6E00780F4B /* PassepartoutLibrary */,
); );
productName = PassepartoutTests; productName = PassepartoutTests;
productReference = 0EB13BAC290E825E003CB654 /* PassepartoutTests.app */; productReference = 0EB13BAC290E825E003CB654 /* PassepartoutTests.app */;
@ -1435,6 +1454,7 @@
0E04F0092883466500BFCE1C /* DefaultLightUtils.swift in Sources */, 0E04F0092883466500BFCE1C /* DefaultLightUtils.swift in Sources */,
0E5349C827C176D100C71BB3 /* EndpointView+WireGuard.swift in Sources */, 0E5349C827C176D100C71BB3 /* EndpointView+WireGuard.swift in Sources */,
0EBC076027EC587900208AD9 /* SwiftGen+Strings.swift in Sources */, 0EBC076027EC587900208AD9 /* SwiftGen+Strings.swift in Sources */,
0E7A8C0F2A1D54DE00780F4B /* Picker+OpenVPN.swift in Sources */,
0E0392772818732D00827C10 /* BuildProducts.swift in Sources */, 0E0392772818732D00827C10 /* BuildProducts.swift in Sources */,
0E0F4C5C29C76B790022E884 /* SceneDelegate+Shortcuts.swift in Sources */, 0E0F4C5C29C76B790022E884 /* SceneDelegate+Shortcuts.swift in Sources */,
0E5683B927C2825D00EAF1CD /* DiagnosticsView.swift in Sources */, 0E5683B927C2825D00EAF1CD /* DiagnosticsView.swift in Sources */,
@ -1487,11 +1507,13 @@
0EF2212F27E66F60001D0BD7 /* AddProfileView.swift in Sources */, 0EF2212F27E66F60001D0BD7 /* AddProfileView.swift in Sources */,
0E96D2FC2871D94E005EFBCF /* DefaultLightProfileManager.swift in Sources */, 0E96D2FC2871D94E005EFBCF /* DefaultLightProfileManager.swift in Sources */,
0EF0FAF627DD0211007EB181 /* PaywallView.swift in Sources */, 0EF0FAF627DD0211007EB181 /* PaywallView.swift in Sources */,
0E7A8C102A1D54DE00780F4B /* Picker+Network.swift in Sources */,
0E293851285A70AC002A6E0E /* AppPreference.swift in Sources */, 0E293851285A70AC002A6E0E /* AppPreference.swift in Sources */,
0E5349BE27C16A4500C71BB3 /* StyledPicker.swift in Sources */, 0E5349BE27C16A4500C71BB3 /* StyledPicker.swift in Sources */,
0E2C172B27CB63F9007E8488 /* Reviewer.swift in Sources */, 0E2C172B27CB63F9007E8488 /* Reviewer.swift in Sources */,
0E71ACDD27C0295C00F85C4B /* View+Extensions.swift in Sources */, 0E71ACDD27C0295C00F85C4B /* View+Extensions.swift in Sources */,
0E021D9C284E68580077EF5D /* CoreContext.swift in Sources */, 0E021D9C284E68580077EF5D /* CoreContext.swift in Sources */,
0E7A8C0A2A1D410500780F4B /* PersistenceManager.swift in Sources */,
A38D607728AFCFD20005C271 /* SettingsView.swift in Sources */, A38D607728AFCFD20005C271 /* SettingsView.swift in Sources */,
0E34A2B627CAA8CC00C73B67 /* Core+L10n.swift in Sources */, 0E34A2B627CAA8CC00C73B67 /* Core+L10n.swift in Sources */,
0E7577DF2817E22C00081CBE /* VPNToggle.swift in Sources */, 0E7577DF2817E22C00081CBE /* VPNToggle.swift in Sources */,
@ -2254,11 +2276,11 @@
package = 0E53249B27D28FC7002565C3 /* XCRemoteSwiftPackageReference "Kvitto" */; package = 0E53249B27D28FC7002565C3 /* XCRemoteSwiftPackageReference "Kvitto" */;
productName = Kvitto; productName = Kvitto;
}; };
0EB13BBD290E835A003CB654 /* PassepartoutLibrary */ = { 0E7A8C0B2A1D4A6100780F4B /* PassepartoutLibrary */ = {
isa = XCSwiftPackageProductDependency; isa = XCSwiftPackageProductDependency;
productName = PassepartoutLibrary; productName = PassepartoutLibrary;
}; };
0ECB78EB2863A21600B0E460 /* PassepartoutLibrary */ = { 0E7A8C0D2A1D4A6E00780F4B /* PassepartoutLibrary */ = {
isa = XCSwiftPackageProductDependency; isa = XCSwiftPackageProductDependency;
productName = PassepartoutLibrary; productName = PassepartoutLibrary;
}; };

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1420" LastUpgradeVersion = "1420"
version = "1.3"> version = "1.7">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"> buildImplicitDependencies = "YES">
@ -78,7 +78,53 @@
ReferencedContainer = "container:Passepartout.xcodeproj"> ReferencedContainer = "container:Passepartout.xcodeproj">
</BuildableReference> </BuildableReference>
</MacroExpansion> </MacroExpansion>
<TestPlans>
<TestPlanReference
reference = "container:Passepartout.xctestplan"
default = "YES">
</TestPlanReference>
</TestPlans>
<Testables> <Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "PassepartoutCoreTests"
BuildableName = "PassepartoutCoreTests"
BlueprintName = "PassepartoutCoreTests"
ReferencedContainer = "container:PassepartoutLibrary">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "PassepartoutProvidersTests"
BuildableName = "PassepartoutProvidersTests"
BlueprintName = "PassepartoutProvidersTests"
ReferencedContainer = "container:PassepartoutLibrary">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "PassepartoutServicesTests"
BuildableName = "PassepartoutServicesTests"
BlueprintName = "PassepartoutServicesTests"
ReferencedContainer = "container:PassepartoutLibrary">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "PassepartoutVPNTests"
BuildableName = "PassepartoutVPNTests"
BlueprintName = "PassepartoutVPNTests"
ReferencedContainer = "container:PassepartoutLibrary">
</BuildableReference>
</TestableReference>
</Testables> </Testables>
</TestAction> </TestAction>
<LaunchAction <LaunchAction

View File

@ -38,26 +38,6 @@
ReferencedContainer = "container:PassepartoutLibrary"> ReferencedContainer = "container:PassepartoutLibrary">
</BuildableReference> </BuildableReference>
</TestableReference> </TestableReference>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "PassepartoutLibraryTests"
BuildableName = "PassepartoutLibraryTests"
BlueprintName = "PassepartoutLibraryTests"
ReferencedContainer = "container:PassepartoutLibrary">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "PassepartoutProfilesTests"
BuildableName = "PassepartoutProfilesTests"
BlueprintName = "PassepartoutProfilesTests"
ReferencedContainer = "container:PassepartoutLibrary">
</BuildableReference>
</TestableReference>
<TestableReference <TestableReference
skipped = "NO"> skipped = "NO">
<BuildableReference <BuildableReference
@ -78,16 +58,6 @@
ReferencedContainer = "container:PassepartoutLibrary"> ReferencedContainer = "container:PassepartoutLibrary">
</BuildableReference> </BuildableReference>
</TestableReference> </TestableReference>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "PassepartoutUtilsTests"
BuildableName = "PassepartoutUtilsTests"
BlueprintName = "PassepartoutUtilsTests"
ReferencedContainer = "container:PassepartoutLibrary">
</BuildableReference>
</TestableReference>
<TestableReference <TestableReference
skipped = "NO"> skipped = "NO">
<BuildableReference <BuildableReference

71
Passepartout.xctestplan Normal file
View File

@ -0,0 +1,71 @@
{
"configurations" : [
{
"id" : "38DB0D3B-F3E5-4BD4-B413-B9C92AE7A2F5",
"name" : "Configuration 1",
"options" : {
}
}
],
"defaultOptions" : {
"codeCoverage" : false,
"commandLineArgumentEntries" : [
{
"argument" : "-com.apple.CoreData.SQLDebug 0"
},
{
"argument" : "-com.apple.CoreData.Logging.stderr 0 "
},
{
"argument" : "-com.apple.CoreData.CloudKitDebug 0"
},
{
"argument" : "-com.apple.CoreData.ConcurrencyDebug 0"
},
{
"argument" : "-com.apple.CoreData.MigrationDebug 0"
}
],
"environmentVariableEntries" : [
{
"key" : "APP_TYPE",
"value" : "2"
},
{
"key" : "LOG_LEVEL",
"value" : "0"
}
],
"targetForVariableExpansion" : {
"containerPath" : "container:Passepartout.xcodeproj",
"identifier" : "0E57F63720C83FC5008323CF",
"name" : "Passepartout"
}
},
"testTargets" : [
{
"target" : {
"containerPath" : "container:PassepartoutLibrary",
"identifier" : "PassepartoutCoreTests",
"name" : "PassepartoutCoreTests"
}
},
{
"target" : {
"containerPath" : "container:PassepartoutLibrary",
"identifier" : "PassepartoutProvidersTests",
"name" : "PassepartoutProvidersTests"
}
},
{
"enabled" : false,
"target" : {
"containerPath" : "container:PassepartoutLibrary",
"identifier" : "PassepartoutVPNTests",
"name" : "PassepartoutVPNTests"
}
}
],
"version" : 1
}

View File

@ -27,7 +27,7 @@ import Foundation
import PassepartoutLibrary import PassepartoutLibrary
import UIKit import UIKit
class AppDelegate: UIResponder, UIApplicationDelegate, ObservableObject { final class AppDelegate: UIResponder, UIApplicationDelegate, ObservableObject {
private let mac = MacBundle.shared private let mac = MacBundle.shared
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {

View File

@ -24,7 +24,7 @@
// //
import Foundation import Foundation
import SwiftyBeaver import PassepartoutLibrary
import UniformTypeIdentifiers import UniformTypeIdentifiers
extension Constants { extension Constants {
@ -154,7 +154,7 @@ extension Constants {
private static let parentPath = "Library/Caches" private static let parentPath = "Library/Caches"
static let level: SwiftyBeaver.Level = { static let level: LoggerLevel = {
guard let levelString = ProcessInfo.processInfo.environment["LOG_LEVEL"], let levelNum = Int(levelString) else { guard let levelString = ProcessInfo.processInfo.environment["LOG_LEVEL"], let levelNum = Int(levelString) else {
return .info return .info
} }

View File

@ -33,7 +33,3 @@ extension AppContext {
extension ProductManager { extension ProductManager {
static let shared = AppContext.shared.productManager static let shared = AppContext.shared.productManager
} }
extension LogManager {
static let shared = AppContext.shared.logManager
}

View File

@ -28,9 +28,7 @@ import Foundation
import PassepartoutLibrary import PassepartoutLibrary
@MainActor @MainActor
class AppContext { final class AppContext {
let logManager: LogManager
let productManager: ProductManager let productManager: ProductManager
private let reviewer: Reviewer private let reviewer: Reviewer
@ -38,12 +36,6 @@ class AppContext {
private var cancellables: Set<AnyCancellable> = [] private var cancellables: Set<AnyCancellable> = []
init(coreContext: CoreContext) { init(coreContext: CoreContext) {
logManager = LogManager(logFile: Constants.Log.App.url)
logManager.logLevel = Constants.Log.level
logManager.logFormat = Constants.Log.App.format
logManager.configureLogging()
pp_log.info("Logging to: \(logManager.logFile!)")
productManager = ProductManager( productManager = ProductManager(
appType: Constants.InApp.appType, appType: Constants.InApp.appType,
buildProducts: Constants.InApp.buildProducts buildProducts: Constants.InApp.buildProducts

View File

@ -35,7 +35,7 @@ enum ProductError: Error {
case beta case beta
} }
class ProductManager: NSObject, ObservableObject { final class ProductManager: NSObject, ObservableObject {
enum AppType: Int { enum AppType: Int {
case freemium = 0 case freemium = 0

View File

@ -27,7 +27,7 @@ import Foundation
import Intents import Intents
import PassepartoutLibrary import PassepartoutLibrary
class IntentDispatcher { final class IntentDispatcher {
private struct Groups { private struct Groups {
static let vpn = "VPN" static let vpn = "VPN"

View File

@ -30,7 +30,7 @@ import IntentsUI
import PassepartoutLibrary import PassepartoutLibrary
@MainActor @MainActor
class IntentsManager: NSObject, ObservableObject { final class IntentsManager: NSObject, ObservableObject {
@Published private(set) var isReloadingShortcuts = false @Published private(set) var isReloadingShortcuts = false
@Published private(set) var shortcuts: [UUID: Shortcut] = [:] @Published private(set) var shortcuts: [UUID: Shortcut] = [:]

View File

@ -25,7 +25,7 @@
import Foundation import Foundation
class MacBundle { final class MacBundle {
static let shared = MacBundle() static let shared = MacBundle()
private var bridge: MacBridge! private var bridge: MacBridge!

View File

@ -25,7 +25,7 @@
import Foundation import Foundation
class MacBundleDelegate: MacMenuDelegate { final class MacBundleDelegate: MacMenuDelegate {
private weak var bundle: MacBundle? private weak var bundle: MacBundle?
@MainActor @MainActor

View File

@ -27,7 +27,7 @@ import Combine
import Foundation import Foundation
import PassepartoutLibrary import PassepartoutLibrary
class DefaultLightProfile: LightProfile { final class DefaultLightProfile: LightProfile {
let id: UUID let id: UUID
let name: String let name: String
@ -50,7 +50,7 @@ class DefaultLightProfile: LightProfile {
} }
} }
class DefaultLightProfileManager: LightProfileManager { final class DefaultLightProfileManager: LightProfileManager {
private let profileManager = ProfileManager.shared private let profileManager = ProfileManager.shared
private let providerManager = ProviderManager.shared private let providerManager = ProviderManager.shared

View File

@ -27,7 +27,7 @@ import Combine
import Foundation import Foundation
import PassepartoutLibrary import PassepartoutLibrary
class DefaultLightProviderCategory: LightProviderCategory { final class DefaultLightProviderCategory: LightProviderCategory {
let name: String let name: String
var locations: [LightProviderLocation] var locations: [LightProviderLocation]
@ -40,7 +40,7 @@ class DefaultLightProviderCategory: LightProviderCategory {
} }
} }
class DefaultLightProviderLocation: LightProviderLocation { final class DefaultLightProviderLocation: LightProviderLocation {
let description: String let description: String
let id: String let id: String
@ -59,7 +59,7 @@ class DefaultLightProviderLocation: LightProviderLocation {
} }
} }
class DefaultLightProviderServer: LightProviderServer { final class DefaultLightProviderServer: LightProviderServer {
let description: String let description: String
let longDescription: String let longDescription: String
@ -79,7 +79,7 @@ class DefaultLightProviderServer: LightProviderServer {
} }
} }
class DefaultLightProviderManager: LightProviderManager { final class DefaultLightProviderManager: LightProviderManager {
private let providerManager = ProviderManager.shared private let providerManager = ProviderManager.shared
private var subscriptions: Set<AnyCancellable> = [] private var subscriptions: Set<AnyCancellable> = []

View File

@ -26,7 +26,7 @@
import Foundation import Foundation
import SwiftUI import SwiftUI
class DefaultLightUtils: LightUtils { final class DefaultLightUtils: LightUtils {
private let app: UIApplication private let app: UIApplication
init() { init() {

View File

@ -26,8 +26,9 @@
import Combine import Combine
import Foundation import Foundation
import PassepartoutLibrary import PassepartoutLibrary
import TunnelKitManager
class DefaultLightVPNManager: LightVPNManager { final class DefaultLightVPNManager: LightVPNManager {
private let vpnManager = VPNManager.shared private let vpnManager = VPNManager.shared
private var subscriptions: Set<AnyCancellable> = [] private var subscriptions: Set<AnyCancellable> = []

View File

@ -24,11 +24,11 @@
// //
import Foundation import Foundation
import PassepartoutCore import PassepartoutLibrary
import TunnelKitCore import TunnelKitCore
extension Network.DNSSettings { extension Network.DNSSettings {
public static func availableConfigurationTypes(forVPNProtocol vpnProtocol: VPNProtocolType) -> [ConfigurationType] { static func availableConfigurationTypes(forVPNProtocol vpnProtocol: VPNProtocolType) -> [ConfigurationType] {
switch vpnProtocol { switch vpnProtocol {
case .openVPN: case .openVPN:
return [.plain, .https, .tls, .disabled] return [.plain, .https, .tls, .disabled]
@ -40,7 +40,7 @@ extension Network.DNSSettings {
} }
extension Network.ProxySettings { extension Network.ProxySettings {
public static let availableConfigurationTypes: [ConfigurationType] = [ static let availableConfigurationTypes: [ConfigurationType] = [
.manual, .manual,
.pac, .pac,
.disabled .disabled
@ -48,5 +48,5 @@ extension Network.ProxySettings {
} }
extension Network.MTUSettings { extension Network.MTUSettings {
public static let availableBytes: [Int] = [0, 1500, 1400, 1300, 1200] static let availableBytes: [Int] = [0, 1500, 1400, 1300, 1200]
} }

View File

@ -27,7 +27,7 @@ import Foundation
import TunnelKitOpenVPN import TunnelKitOpenVPN
extension OpenVPN.Cipher { extension OpenVPN.Cipher {
public static let available: [OpenVPN.Cipher] = [ static let available: [OpenVPN.Cipher] = [
.aes256gcm, .aes256gcm,
.aes192gcm, .aes192gcm,
.aes128gcm, .aes128gcm,
@ -38,7 +38,7 @@ extension OpenVPN.Cipher {
} }
extension OpenVPN.Digest { extension OpenVPN.Digest {
public static let available: [OpenVPN.Digest] = [ static let available: [OpenVPN.Digest] = [
.sha1, .sha1,
.sha224, .sha224,
.sha256, .sha256,
@ -48,7 +48,7 @@ extension OpenVPN.Digest {
} }
extension OpenVPN.CompressionFraming { extension OpenVPN.CompressionFraming {
public static let available: [OpenVPN.CompressionFraming] = [ static let available: [OpenVPN.CompressionFraming] = [
.disabled, .disabled,
.compLZO, .compLZO,
.compress .compress
@ -56,7 +56,7 @@ extension OpenVPN.CompressionFraming {
} }
extension OpenVPN.CompressionAlgorithm { extension OpenVPN.CompressionAlgorithm {
public static let available: [OpenVPN.CompressionAlgorithm] = [ static let available: [OpenVPN.CompressionAlgorithm] = [
.disabled, .disabled,
.LZO .LZO
] ]

View File

@ -115,7 +115,7 @@ struct LockableView<Content: View, LockedContent: View>: View {
} }
} }
private class Lock: ObservableObject { private final class Lock: ObservableObject {
enum State { enum State {
case none case none

View File

@ -27,7 +27,7 @@ import MessageUI
import SwiftUI import SwiftUI
struct MailComposerView: UIViewControllerRepresentable { struct MailComposerView: UIViewControllerRepresentable {
class Coordinator: NSObject, MFMailComposeViewControllerDelegate { final class Coordinator: NSObject, MFMailComposeViewControllerDelegate {
@Binding private var isPresented: Bool @Binding private var isPresented: Bool
init(_ view: MailComposerView) { init(_ view: MailComposerView) {

View File

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

View File

@ -26,7 +26,7 @@
import PassepartoutLibrary import PassepartoutLibrary
import SwiftUI import SwiftUI
class SceneDelegate: UIResponder, UIWindowSceneDelegate { final class SceneDelegate: UIResponder, UIWindowSceneDelegate {
func sceneDidEnterBackground(_ scene: UIScene) { func sceneDidEnterBackground(_ scene: UIScene) {
ProfileManager.shared.persist() ProfileManager.shared.persist()
#if targetEnvironment(macCatalyst) #if targetEnvironment(macCatalyst)

View File

@ -27,7 +27,7 @@ import Foundation
import PassepartoutLibrary import PassepartoutLibrary
extension AddProviderView { extension AddProviderView {
class ViewModel: ObservableObject { final class ViewModel: ObservableObject {
enum PendingOperation { enum PendingOperation {
case index case index

View File

@ -154,7 +154,7 @@ extension DiagnosticsView.OpenVPNView {
} }
private var appLogURL: URL? { private var appLogURL: URL? {
LogManager.shared.logFile Passepartout.shared.logger.logFile
} }
private var tunnelLogURL: URL? { private var tunnelLogURL: URL? {

View File

@ -52,7 +52,7 @@ extension DiagnosticsView {
extension DiagnosticsView.WireGuardView { extension DiagnosticsView.WireGuardView {
private var appLogURL: URL? { private var appLogURL: URL? {
LogManager.shared.logFile Passepartout.shared.logger.logFile
} }
private var tunnelLogURL: URL? { private var tunnelLogURL: URL? {

View File

@ -30,7 +30,8 @@ extension OnDemandView {
struct SSIDList: View { struct SSIDList: View {
@Binding var withSSIDs: [String: Bool] @Binding var withSSIDs: [String: Bool]
@StateObject private var reader = SSIDReader() // FIXME: arch, this is a candidate for DI
@StateObject private var reader = Wifi(observer: CoreLocationWifiObserver())
var body: some View { var body: some View {
EditableTextList(elements: allSSIDs, allowsDuplicates: false, mapping: mapElements) { text in EditableTextList(elements: allSSIDs, allowsDuplicates: false, mapping: mapElements) { text in
@ -73,7 +74,7 @@ extension OnDemandView {
private func requestSSID(_ text: Binding<String>) { private func requestSSID(_ text: Binding<String>) {
Task { @MainActor in Task { @MainActor in
let ssid = try await reader.requestCurrentSSID() let ssid = try await reader.currentSSID()
if !withSSIDs.keys.contains(ssid) { if !withSSIDs.keys.contains(ssid) {
text.wrappedValue = ssid text.wrappedValue = ssid
} }

View File

@ -25,7 +25,6 @@
import PassepartoutLibrary import PassepartoutLibrary
import SwiftUI import SwiftUI
import SwiftyBeaver
extension View { extension View {
func withoutTitleBar() -> some View { func withoutTitleBar() -> some View {
@ -106,7 +105,7 @@ extension View {
extension View { extension View {
func debugChanges() { func debugChanges() {
if SwiftyBeaver.destinations.first?.minLevel == .verbose { if Passepartout.shared.logger.logLevel == .verbose {
Self._printChanges() Self._printChanges()
} }
} }

View File

@ -1 +1 @@
2022 Davide De Rosa 2023 Davide De Rosa

View File

@ -27,7 +27,7 @@ import Foundation
import PassepartoutLibrary import PassepartoutLibrary
extension CoreContext { extension CoreContext {
static let shared = CoreContext(store: UserDefaultsStore(defaults: .standard)) static let shared = CoreContext(store: UserDefaultsStore(defaults: .standard, key: \.key))
} }
extension UpgradeManager { extension UpgradeManager {

View File

@ -26,14 +26,16 @@
import Combine import Combine
import Foundation import Foundation
import PassepartoutLibrary import PassepartoutLibrary
import TunnelKitCore
import TunnelKitManager
@MainActor @MainActor
class CoreContext { final class CoreContext {
let store: KeyValueStore let store: KeyValueStore
private let profilesPersistence: Persistence private let profilesPersistence: CoreDataPersistentStore
private let providersPersistence: Persistence private let providersPersistence: CoreDataPersistentStore
var urlsForProfiles: [URL]? { var urlsForProfiles: [URL]? {
profilesPersistence.containerURLs profilesPersistence.containerURLs
@ -56,6 +58,14 @@ class CoreContext {
init(store: KeyValueStore) { init(store: KeyValueStore) {
self.store = store self.store = store
let logger = SwiftyBeaverLogger(
logFile: Constants.Log.App.url,
logLevel: Constants.Log.level,
logFormat: Constants.Log.App.format
)
Passepartout.shared.logger = logger
pp_log.info("Logging to: \(logger.logFile!)")
let persistenceManager = PersistenceManager(store: store) let persistenceManager = PersistenceManager(store: store)
profilesPersistence = persistenceManager.profilesPersistence( profilesPersistence = persistenceManager.profilesPersistence(
withName: Constants.Persistence.profilesContainerName withName: Constants.Persistence.profilesContainerName
@ -64,29 +74,35 @@ class CoreContext {
withName: Constants.Persistence.providersContainerName withName: Constants.Persistence.providersContainerName
) )
upgradeManager = UpgradeManager(store: store) upgradeManager = UpgradeManager(
store: store,
strategy: DefaultUpgradeStrategy()
)
providerManager = ProviderManager( let remoteProvidersStrategy = APIRemoteProvidersStrategy(
appBuild: Constants.Global.appBuildNumber, appBuild: Constants.Global.appBuildNumber,
bundleServices: DefaultWebServices.bundledServices( bundleServices: APIWebServices.bundledServices(
withVersion: Constants.Services.version withVersion: Constants.Services.version
), ),
webServices: DefaultWebServices( remoteServices: APIWebServices(
Constants.Services.version, Constants.Services.version,
Constants.Repos.api, Constants.Repos.api,
timeout: Constants.Services.connectivityTimeout timeout: Constants.Services.connectivityTimeout
), ),
persistence: providersPersistence webServicesRepository: PassepartoutPersistence.webServicesRepository(providersPersistence)
)
providerManager = ProviderManager(
localProvidersRepository: PassepartoutPersistence.localProvidersRepository(providersPersistence),
remoteProvidersStrategy: remoteProvidersStrategy
) )
profileManager = ProfileManager( profileManager = ProfileManager(
store: store, store: store,
providerManager: providerManager, providerManager: providerManager,
appGroup: Constants.App.appGroupId, profileRepository: PassepartoutPersistence.profileRepository(profilesPersistence),
keychainLabel: Unlocalized.Keychain.passwordLabel, keychain: KeychainSecretRepository(appGroup: Constants.App.appGroupId),
strategy: CoreDataProfileManagerStrategy( keychainEntry: Unlocalized.Keychain.passwordEntry,
persistence: profilesPersistence keychainLabel: Unlocalized.Keychain.passwordLabel
)
) )
#if targetEnvironment(simulator) #if targetEnvironment(simulator)
@ -94,17 +110,16 @@ class CoreContext {
#else #else
let vpn = NetworkExtensionVPN() let vpn = NetworkExtensionVPN()
#endif #endif
let strategy = TunnelKitVPNManagerStrategy( let vpnManagerStrategy = TunnelKitVPNManagerStrategy(
appGroup: Constants.App.appGroupId, appGroup: Constants.App.appGroupId,
tunnelBundleIdentifier: Constants.App.tunnelBundleId, tunnelBundleIdentifier: Constants.App.tunnelBundleId,
vpn: vpn vpn: vpn
) )
vpnManager = VPNManager( vpnManager = VPNManager(
appGroup: Constants.App.appGroupId,
store: store, store: store,
profileManager: profileManager, profileManager: profileManager,
providerManager: providerManager, providerManager: providerManager,
strategy: strategy strategy: vpnManagerStrategy
) )
// post // post

View File

@ -25,13 +25,12 @@
import CoreData import CoreData
import Foundation import Foundation
import PassepartoutCore import PassepartoutLibrary
import PassepartoutUtils
public final class PersistenceManager { final class PersistenceManager {
private let store: KeyValueStore private let store: KeyValueStore
public init(store: KeyValueStore) { init(store: KeyValueStore) {
self.store = store self.store = store
// set once // set once
@ -40,21 +39,19 @@ public final class PersistenceManager {
} }
} }
public func profilesPersistence(withName containerName: String) -> Persistence { func profilesPersistence(withName containerName: String) -> CoreDataPersistentStore {
let model = PassepartoutDataModels.profiles PassepartoutPersistence.profilesStore(withName: containerName, cloudKit: true, author: persistenceAuthor)
return Persistence(withCloudKitName: containerName, model: model, author: persistenceAuthor)
} }
public func providersPersistence(withName containerName: String) -> Persistence { func providersPersistence(withName containerName: String) -> CoreDataPersistentStore {
let model = PassepartoutDataModels.providers PassepartoutPersistence.providersStore(withName: containerName, cloudKit: false, author: persistenceAuthor)
return Persistence(withLocalName: containerName, model: model, author: persistenceAuthor)
} }
} }
// MARK: KeyValueStore // MARK: KeyValueStore
extension PersistenceManager { extension PersistenceManager {
public private(set) var persistenceAuthor: String? { private(set) var persistenceAuthor: String? {
get { get {
store.value(forLocation: StoreKey.persistenceAuthor) store.value(forLocation: StoreKey.persistenceAuthor)
} }

View File

@ -56,8 +56,12 @@ enum Unlocalized {
} }
enum Keychain { enum Keychain {
static func passwordLabel(_ profileName: String, vpnProtocol: VPNProtocolType) -> String { static func passwordEntry(_ profile: Profile) -> String {
"\(Constants.Global.appName): \(profileName) (\(vpnProtocol.description))" "\(profile.id.uuidString):\(profile.currentVPNProtocol.keychainEntry):\(profile.account.username)"
}
static func passwordLabel(_ profile: Profile) -> String {
"\(Constants.Global.appName): \(profile.header.name) (\(profile.currentVPNProtocol.keychainEntry))"
} }
} }
@ -252,3 +256,15 @@ enum Unlocalized {
static let totp = "TOTP" static let totp = "TOTP"
} }
} }
private extension VPNProtocolType {
var keychainEntry: String {
switch self {
case .openVPN:
return "OpenVPN"
case .wireGuard:
return "WireGuard"
}
}
}

View File

@ -26,7 +26,7 @@
import AppKit import AppKit
import Foundation import Foundation
class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject { final class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject {
private let appURL = Constants.Launcher.appURL private let appURL = Constants.Launcher.appURL
private var isAppRunning: Bool { private var isAppRunning: Bool {

View File

@ -25,7 +25,7 @@
import Foundation import Foundation
class DefaultMacMenu: MacMenu { final class DefaultMacMenu: MacMenu {
weak var delegate: MacMenuDelegate? weak var delegate: MacMenuDelegate?
private lazy var menu: PassepartoutMenu = { private lazy var menu: PassepartoutMenu = {

View File

@ -26,7 +26,7 @@
import AppKit import AppKit
import Foundation import Foundation
class DefaultMacUtils: MacUtils { final class DefaultMacUtils: MacUtils {
private(set) lazy var isStartedByLauncher = NSApp.isHidden private(set) lazy var isStartedByLauncher = NSApp.isHidden
private let transformer = ObservableProcessTransformer.shared private let transformer = ObservableProcessTransformer.shared

View File

@ -28,7 +28,7 @@ import Foundation
extension HostProfileItem { extension HostProfileItem {
@MainActor @MainActor
class ViewModel { final class ViewModel {
let profile: LightProfile let profile: LightProfile
private let vpnManager: LightVPNManager private let vpnManager: LightVPNManager

View File

@ -30,7 +30,7 @@ import ServiceManagement
extension LaunchOnLoginItem { extension LaunchOnLoginItem {
@MainActor @MainActor
class ViewModel: ObservableObject { final class ViewModel: ObservableObject {
let title: String let title: String
let utils: LightUtils let utils: LightUtils

View File

@ -29,7 +29,7 @@ import Foundation
extension PassepartoutMenu { extension PassepartoutMenu {
@MainActor @MainActor
class StatusButton { final class StatusButton {
private lazy var statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) private lazy var statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
private lazy var statusButton: NSStatusBarButton = { private lazy var statusButton: NSStatusBarButton = {

View File

@ -27,7 +27,7 @@ import AppKit
import Foundation import Foundation
@MainActor @MainActor
class PassepartoutMenu { final class PassepartoutMenu {
private let macMenuDelegate: MacMenuDelegate private let macMenuDelegate: MacMenuDelegate
private let profileManager: LightProfileManager private let profileManager: LightProfileManager

View File

@ -28,7 +28,7 @@ import Foundation
extension ProviderLocationItem { extension ProviderLocationItem {
@MainActor @MainActor
class ViewModel { final class ViewModel {
private let profile: LightProfile private let profile: LightProfile
let location: LightProviderLocation let location: LightProviderLocation

View File

@ -28,7 +28,7 @@ import Foundation
extension ProviderProfileItem { extension ProviderProfileItem {
@MainActor @MainActor
class ViewModel { final class ViewModel {
let profile: LightProfile let profile: LightProfile
private let providerManager: LightProviderManager private let providerManager: LightProviderManager

View File

@ -28,7 +28,7 @@ import Foundation
extension ProviderServerItem { extension ProviderServerItem {
@MainActor @MainActor
class ViewModel { final class ViewModel {
private let profile: LightProfile private let profile: LightProfile
let server: LightProviderServer let server: LightProviderServer

View File

@ -29,7 +29,7 @@ import Foundation
extension VPNItemGroup { extension VPNItemGroup {
@MainActor @MainActor
class ViewModel { final class ViewModel {
private let vpnManager: LightVPNManager private let vpnManager: LightVPNManager
private let toggleTitleBlock: (Bool) -> String private let toggleTitleBlock: (Bool) -> String

View File

@ -29,7 +29,7 @@ import Foundation
extension VisibilityItem { extension VisibilityItem {
@MainActor @MainActor
class ViewModel { final class ViewModel {
private let transformer: ObservableProcessTransformer private let transformer: ObservableProcessTransformer
private let utils: LightUtils private let utils: LightUtils

View File

@ -25,7 +25,7 @@
import Foundation import Foundation
class PassepartoutMac: NSObject, MacBridge { final class PassepartoutMac: NSObject, MacBridge {
required override init() { required override init() {
super.init() super.init()
} }

View File

@ -26,7 +26,7 @@
import Combine import Combine
import Foundation import Foundation
class ObservableProcessTransformer: ObservableObject { final class ObservableProcessTransformer: ObservableObject {
static let shared = ObservableProcessTransformer() static let shared = ObservableProcessTransformer()
private let transformer = ProcessTransformer() private let transformer = ProcessTransformer()

View File

@ -27,7 +27,7 @@ import Combine
import Foundation import Foundation
extension TextItem { extension TextItem {
class ViewModel { final class ViewModel {
let title: CurrentValueSubject<String, Never> let title: CurrentValueSubject<String, Never>
let state: CurrentValueSubject<State, Never> let state: CurrentValueSubject<State, Never>

View File

@ -26,7 +26,7 @@
import Foundation import Foundation
import OpenVPNAppExtension import OpenVPNAppExtension
class PacketTunnelProvider: OpenVPNTunnelProvider { final class PacketTunnelProvider: OpenVPNTunnelProvider {
override func startTunnel(options: [String: NSObject]?, completionHandler: @escaping (Error?) -> Void) { override func startTunnel(options: [String: NSObject]?, completionHandler: @escaping (Error?) -> Void) {
appVersion = "\(Constants.Global.appName) \(Constants.Global.appVersionString)" appVersion = "\(Constants.Global.appName) \(Constants.Global.appVersionString)"
dnsTimeout = Constants.OpenVPNTunnel.dnsTimeout dnsTimeout = Constants.OpenVPNTunnel.dnsTimeout

View File

@ -26,5 +26,5 @@
import Foundation import Foundation
import WireGuardAppExtension import WireGuardAppExtension
class PacketTunnelProvider: WireGuardTunnelProvider { final class PacketTunnelProvider: WireGuardTunnelProvider {
} }

View File

@ -0,0 +1,45 @@
{
"configurations" : [
{
"id" : "2A4B150B-39A2-417B-98FD-1C5C74C26E3E",
"name" : "Test Scheme Action",
"options" : {
}
}
],
"defaultOptions" : {
"codeCoverage" : false
},
"testTargets" : [
{
"target" : {
"containerPath" : "container:",
"identifier" : "PassepartoutCoreTests",
"name" : "PassepartoutCoreTests"
}
},
{
"target" : {
"containerPath" : "container:",
"identifier" : "PassepartoutProvidersTests",
"name" : "PassepartoutProvidersTests"
}
},
{
"target" : {
"containerPath" : "container:",
"identifier" : "PassepartoutServicesTests",
"name" : "PassepartoutServicesTests"
}
},
{
"target" : {
"containerPath" : "container:",
"identifier" : "PassepartoutVPNTests",
"name" : "PassepartoutVPNTests"
}
}
],
"version" : 1
}

View File

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1430"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "OpenVPNAppExtension"
BuildableName = "OpenVPNAppExtension"
BlueprintName = "OpenVPNAppExtension"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</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 = "OpenVPNAppExtension"
BuildableName = "OpenVPNAppExtension"
BlueprintName = "OpenVPNAppExtension"
ReferencedContainer = "container:">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1430"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "PassepartoutCoreTests"
BuildableName = "PassepartoutCoreTests"
BlueprintName = "PassepartoutCoreTests"
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">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,332 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1430"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "PassepartoutLibrary_PassepartoutVPNImpl"
BuildableName = "PassepartoutLibrary_PassepartoutVPNImpl"
BlueprintName = "PassepartoutLibrary_PassepartoutVPNImpl"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "PassepartoutLibrary_PassepartoutCoreTests"
BuildableName = "PassepartoutLibrary_PassepartoutCoreTests"
BlueprintName = "PassepartoutLibrary_PassepartoutCoreTests"
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 = "PassepartoutVPN"
BuildableName = "PassepartoutVPN"
BlueprintName = "PassepartoutVPN"
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 = "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 = "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 = "PassepartoutVPNImpl"
BuildableName = "PassepartoutVPNImpl"
BlueprintName = "PassepartoutVPNImpl"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "PassepartoutCoreTests"
BuildableName = "PassepartoutCoreTests"
BlueprintName = "PassepartoutCoreTests"
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 = "PassepartoutVPNTests"
BuildableName = "PassepartoutVPNTests"
BlueprintName = "PassepartoutVPNTests"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "PassepartoutServicesImpl"
BuildableName = "PassepartoutServicesImpl"
BlueprintName = "PassepartoutServicesImpl"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "PassepartoutProvidersImpl"
BuildableName = "PassepartoutProvidersImpl"
BlueprintName = "PassepartoutProvidersImpl"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "PassepartoutLibrary_PassepartoutProvidersImpl"
BuildableName = "PassepartoutLibrary_PassepartoutProvidersImpl"
BlueprintName = "PassepartoutLibrary_PassepartoutProvidersImpl"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "PassepartoutLibrary"
BuildableName = "PassepartoutLibrary"
BlueprintName = "PassepartoutLibrary"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "PassepartoutCoreTests"
BuildableName = "PassepartoutCoreTests"
BlueprintName = "PassepartoutCoreTests"
ReferencedContainer = "container:">
</BuildableReference>
</TestableReference>
<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 = "PassepartoutVPNTests"
BuildableName = "PassepartoutVPNTests"
BlueprintName = "PassepartoutVPNTests"
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 = "PassepartoutLibrary_PassepartoutVPNImpl"
BuildableName = "PassepartoutLibrary_PassepartoutVPNImpl"
BlueprintName = "PassepartoutLibrary_PassepartoutVPNImpl"
ReferencedContainer = "container:">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1430"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "PassepartoutLibrary"
BuildableName = "PassepartoutLibrary"
BlueprintName = "PassepartoutLibrary"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<TestPlans>
<TestPlanReference
reference = "container:.swiftpm/PassepartoutLibrary.xctestplan"
default = "YES">
</TestPlanReference>
</TestPlans>
</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 = "PassepartoutLibrary"
BuildableName = "PassepartoutLibrary"
BlueprintName = "PassepartoutLibrary"
ReferencedContainer = "container:">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1430"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "PassepartoutProvidersTests"
BuildableName = "PassepartoutProvidersTests"
BlueprintName = "PassepartoutProvidersTests"
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">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1430"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "PassepartoutVPNTests"
BuildableName = "PassepartoutVPNTests"
BlueprintName = "PassepartoutVPNTests"
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">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1430"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "WireGuardAppExtension"
BuildableName = "WireGuardAppExtension"
BlueprintName = "WireGuardAppExtension"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</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 = "WireGuardAppExtension"
BuildableName = "WireGuardAppExtension"
BlueprintName = "WireGuardAppExtension"
ReferencedContainer = "container:">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -32,58 +32,64 @@ let package = Package(
targets: [ targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite. // 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. // Targets can depend on other targets in this package, and on products in packages this package depends on.
// MARK: Implementations
.target( .target(
name: "PassepartoutLibrary", name: "PassepartoutLibrary",
dependencies: [ dependencies: [
"PassepartoutVPN" "PassepartoutVPNImpl",
"PassepartoutProvidersImpl"
]), ]),
.target(
name: "PassepartoutVPNImpl",
dependencies: [
"PassepartoutVPN",
"SwiftyBeaver",
.product(name: "TunnelKitLZO", package: "TunnelKit")
],
resources: [
.process("Data/Profiles.xcdatamodeld")
]),
.target(
name: "PassepartoutProvidersImpl",
dependencies: [
"PassepartoutProviders",
"PassepartoutServices"
],
resources: [
.copy("API"),
.process("Data/Providers.xcdatamodeld")
]),
// MARK: Interfaces
.target( .target(
name: "PassepartoutVPN", name: "PassepartoutVPN",
dependencies: [ dependencies: [
"PassepartoutProfiles", "PassepartoutProviders",
.product(name: "TunnelKitLZO", package: "TunnelKit") .product(name: "TunnelKit", package: "TunnelKit"),
]), .product(name: "TunnelKitOpenVPN", package: "TunnelKit"), // FIXME: arch, drop this
.target( .product(name: "TunnelKitWireGuard", package: "TunnelKit"), // FIXME: arch, drop this
name: "PassepartoutProfiles",
dependencies: [
"PassepartoutProviders"
],
resources: [
.process("DataModels/Profiles.xcdatamodeld")
]), ]),
.target( .target(
name: "PassepartoutProviders", name: "PassepartoutProviders",
dependencies: [ dependencies: [
"PassepartoutCore", "PassepartoutCore"
"PassepartoutServices" ]),
], .target(
resources: [ name: "PassepartoutServices",
.process("DataModels/Providers.xcdatamodeld") dependencies: [
"PassepartoutCore"
]), ]),
.target( .target(
name: "PassepartoutCore", name: "PassepartoutCore",
dependencies: [ dependencies: [
.product(name: "TunnelKit", package: "TunnelKit"), .product(name: "GenericJSON", package: "generic-json-swift") // FIXME: arch, drop this
.product(name: "TunnelKitOpenVPN", package: "TunnelKit"),
.product(name: "TunnelKitWireGuard", package: "TunnelKit"),
.product(name: "GenericJSON", package: "generic-json-swift")
]), ]),
//
.target( // MARK: App extensions
name: "PassepartoutServices",
dependencies: [
"PassepartoutUtils"
],
resources: [
.copy("API")
]),
.target(
name: "PassepartoutUtils",
dependencies: [
.product(name: "GenericJSON", package: "generic-json-swift"),
"SwiftyBeaver"
]),
//
.target( .target(
name: "OpenVPNAppExtension", name: "OpenVPNAppExtension",
dependencies: [ dependencies: [
@ -95,27 +101,18 @@ let package = Package(
dependencies: [ dependencies: [
.product(name: "TunnelKitWireGuardAppExtension", package: "TunnelKit") .product(name: "TunnelKitWireGuardAppExtension", package: "TunnelKit")
]), ]),
.testTarget(
name: "PassepartoutLibraryTests", // MARK: Tests
dependencies: ["PassepartoutLibrary"]),
.testTarget( .testTarget(
name: "PassepartoutVPNTests", name: "PassepartoutVPNTests",
dependencies: ["PassepartoutVPN"]), dependencies: ["PassepartoutVPNImpl"]),
.testTarget(
name: "PassepartoutProfilesTests",
dependencies: ["PassepartoutProfiles"]),
.testTarget( .testTarget(
name: "PassepartoutProvidersTests", name: "PassepartoutProvidersTests",
dependencies: ["PassepartoutProviders"]), dependencies: ["PassepartoutProvidersImpl"]),
.testTarget( .testTarget(
name: "PassepartoutCoreTests", name: "PassepartoutCoreTests",
dependencies: ["PassepartoutCore"]), dependencies: ["PassepartoutCore"],
.testTarget(
name: "PassepartoutServicesTests",
dependencies: ["PassepartoutServices"]),
.testTarget(
name: "PassepartoutUtilsTests",
dependencies: ["PassepartoutUtils"],
resources: [ resources: [
.process("Resources") .process("Resources")
]) ])

View File

@ -25,6 +25,7 @@
import Foundation import Foundation
// FIXME: arch, provide a well-defined serialization property rather than .rawValue
public enum VPNProtocolType: String, CaseIterable, Codable { public enum VPNProtocolType: String, CaseIterable, Codable {
case openVPN = "ovpn" case openVPN = "ovpn"
@ -34,15 +35,3 @@ public enum VPNProtocolType: String, CaseIterable, Codable {
public protocol VPNProtocolProviding { public protocol VPNProtocolProviding {
var vpnProtocol: VPNProtocolType { get } var vpnProtocol: VPNProtocolType { get }
} }
extension VPNProtocolType: CustomStringConvertible {
public var description: String {
switch self {
case .openVPN:
return "OpenVPN"
case .wireGuard:
return "WireGuard"
}
}
}

View File

@ -0,0 +1,3 @@
public var pp_log: Logger {
Passepartout.shared.logger
}

View File

@ -1,57 +0,0 @@
//
// Profile+Extensions.swift
// Passepartout
//
// Created by Davide De Rosa on 3/13/22.
// Copyright (c) 2023 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 {
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 {
providerAccount = newValue
} else {
hostAccount = newValue
}
}
}
}

View File

@ -1,5 +1,5 @@
// //
// PassepartoutError.swift // Passepartout.swift
// Passepartout // Passepartout
// //
// Created by Davide De Rosa on 6/12/18. // Created by Davide De Rosa on 6/12/18.
@ -25,6 +25,19 @@
import Foundation import Foundation
// FIXME: arch, global variables here are not extensible, use dependency injection instead
public class Passepartout {
public static let shared = Passepartout()
private init() {
}
public var logger: Logger = DefaultLogger()
}
public enum PassepartoutPersistence {
}
public struct PassepartoutError: Error, Equatable { public struct PassepartoutError: Error, Equatable {
private let string: String private let string: String

View File

@ -1,5 +1,5 @@
// //
// Persistence.swift // CoreDataPersistentStore.swift
// Passepartout // Passepartout
// //
// Created by Davide De Rosa on 3/14/22. // Created by Davide De Rosa on 3/14/22.
@ -27,24 +27,16 @@ import Combine
import CoreData import CoreData
import Foundation import Foundation
public class Persistence { public final class CoreDataPersistentStore {
private let container: NSPersistentContainer private let container: NSPersistentContainer
public var context: NSManagedObjectContext { public convenience init(withName containerName: String, model: NSManagedObjectModel, cloudKit: Bool, author: String?) {
container.viewContext let container: NSPersistentContainer
if cloudKit {
container = NSPersistentCloudKitContainer(name: containerName, managedObjectModel: model)
} else {
container = NSPersistentContainer(name: containerName, managedObjectModel: model)
} }
public var coordinator: NSPersistentStoreCoordinator {
container.persistentStoreCoordinator
}
public convenience init(withLocalName containerName: String, model: NSManagedObjectModel, author: String?) {
let container = NSPersistentContainer(name: containerName, managedObjectModel: model)
self.init(withContainer: container, author: author)
}
public convenience init(withCloudKitName containerName: String, model: NSManagedObjectModel, author: String?) {
let container = NSPersistentCloudKitContainer(name: containerName, managedObjectModel: model)
self.init(withContainer: container, author: author) self.init(withContainer: container, author: author)
} }
@ -112,3 +104,13 @@ public class Persistence {
} }
} }
} }
extension CoreDataPersistentStore {
public var context: NSManagedObjectContext {
container.viewContext
}
public var coordinator: NSPersistentStoreCoordinator {
container.persistentStoreCoordinator
}
}

View File

@ -1,8 +1,8 @@
// //
// SSIDReader.swift // CoreLocationWifiObserver.swift
// Passepartout // Passepartout
// //
// Created by Davide De Rosa on 2/24/22. // Created by Davide De Rosa on 5/21/23.
// Copyright (c) 2023 Davide De Rosa. All rights reserved. // Copyright (c) 2023 Davide De Rosa. All rights reserved.
// //
// https://github.com/passepartoutvpn // https://github.com/passepartoutvpn
@ -26,38 +26,37 @@
import CoreLocation import CoreLocation
import Foundation import Foundation
@MainActor public final class CoreLocationWifiObserver: NSObject, WifiObserver {
public class SSIDReader: NSObject, ObservableObject { private let locationManager = CLLocationManager()
private let manager = CLLocationManager()
private var continuation: CheckedContinuation<String, Error>? private var continuation: CheckedContinuation<String, Error>?
private func currentSSID() async -> String { public func currentSSID() async throws -> String {
await Utils.currentWifiSSID() ?? "" switch locationManager.authorizationStatus {
}
public func requestCurrentSSID() async throws -> String {
switch manager.authorizationStatus {
case .authorizedAlways, .authorizedWhenInUse, .denied: case .authorizedAlways, .authorizedWhenInUse, .denied:
return await currentSSID() return await currentSSIDWithoutAuthorization()
default: default:
return try await withCheckedThrowingContinuation { continuation in return try await withCheckedThrowingContinuation { continuation in
self.continuation = continuation self.continuation = continuation
manager.delegate = self locationManager.delegate = self
manager.requestWhenInUseAuthorization() locationManager.requestWhenInUseAuthorization()
} }
} }
} }
private func currentSSIDWithoutAuthorization() async -> String {
await Utils.currentWifiSSID() ?? ""
}
} }
extension SSIDReader: CLLocationManagerDelegate { extension CoreLocationWifiObserver: CLLocationManagerDelegate {
public func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) { public func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
switch manager.authorizationStatus { switch manager.authorizationStatus {
case .authorizedWhenInUse, .authorizedAlways, .denied: case .authorizedWhenInUse, .authorizedAlways, .denied:
Task { Task {
continuation?.resume(returning: await currentSSID()) continuation?.resume(returning: await currentSSIDWithoutAuthorization())
continuation = nil continuation = nil
} }

View File

@ -27,7 +27,7 @@ import Combine
import CoreData import CoreData
import Foundation import Foundation
public class FetchedValueHolder<V>: NSObject, ValueHolder, NSFetchedResultsControllerDelegate { public final class FetchedValueHolder<V>: NSObject, ValueHolder, NSFetchedResultsControllerDelegate {
@Published public var value: V @Published public var value: V
private let controller: NSFetchedResultsController<NSFetchRequestResult> private let controller: NSFetchedResultsController<NSFetchRequestResult>

View File

@ -25,7 +25,7 @@
import Foundation import Foundation
public class GenericWebParser { public final class GenericWebParser {
private static let lmFormatter: DateFormatter = { private static let lmFormatter: DateFormatter = {
let fmt = DateFormatter() let fmt = DateFormatter()
fmt.locale = Locale(identifier: "en") fmt.locale = Locale(identifier: "en")

View File

@ -32,7 +32,7 @@ public protocol GenericWebServicesError: Error {
static var unknown: Self { get } static var unknown: Self { get }
} }
public class GenericWebServices<ErrorType: GenericWebServicesError> { public final class GenericWebServices<ErrorType: GenericWebServicesError> {
private let version: String? private let version: String?
private let root: URL private let root: URL

View File

@ -36,7 +36,7 @@ public enum InAppError: Error {
case unknown case unknown
} }
public class InApp<PID: Hashable & RawRepresentable>: NSObject, public final class InApp<PID: Hashable & RawRepresentable>: NSObject,
SKProductsRequestDelegate, SKPaymentTransactionObserver SKProductsRequestDelegate, SKPaymentTransactionObserver
where PID.RawValue == String { where PID.RawValue == String {

View File

@ -1,5 +1,5 @@
// //
// Utils+Codable.swift // JSON+Codable.swift
// Passepartout // Passepartout
// //
// Created by Davide De Rosa on 3/13/22. // Created by Davide De Rosa on 3/13/22.

View File

@ -33,16 +33,16 @@ public protocol KeyStoreDomainLocation: KeyStoreLocation {
var domain: String { get } var domain: String { get }
} }
public protocol KeyValueStore {
func setValue<L, V>(_ value: V?, forLocation location: L) where L: KeyStoreLocation
func value<L, V>(forLocation location: L) -> V? where L: KeyStoreLocation
func removeValue<L>(forLocation location: L) where L: KeyStoreLocation
}
extension KeyStoreDomainLocation { extension KeyStoreDomainLocation {
public var key: String { public var key: String {
"\(domain).\(rawValue)" "\(domain).\(rawValue)"
} }
} }
public protocol KeyValueStore {
func setValue<L: KeyStoreLocation, V>(_ value: V?, forLocation location: L)
func value<L: KeyStoreLocation, V>(forLocation location: L) -> V?
func removeValue<L: KeyStoreLocation>(forLocation location: L)
}

View File

@ -25,7 +25,7 @@
import Foundation import Foundation
public class KeyedCache<K: Hashable, V> { public struct KeyedCache<K: Hashable, V> {
private let query: String private let query: String
private var store: [K: V] = [:] private var store: [K: V] = [:]
@ -42,15 +42,15 @@ public class KeyedCache<K: Hashable, V> {
self.query = query self.query = query
} }
public func set(_ store: [K: V]) { public mutating func set(_ store: [K: V]) {
self.store = store self.store = store
} }
public func put(_ key: K, value: V) { public mutating func put(_ key: K, value: V) {
store[key] = value store[key] = value
} }
public func put(_ key: K, valueBlock: (K) -> V?) -> V? { public mutating func put(_ key: K, valueBlock: (K) -> V?) -> V? {
if let cachedValue = store[key] { if let cachedValue = store[key] {
return cachedValue return cachedValue
} }
@ -62,18 +62,18 @@ public class KeyedCache<K: Hashable, V> {
return value return value
} }
public func forget(where condition: (K) -> Bool) { public mutating func forget(where condition: (K) -> Bool) {
let removedKeys = store.keys.filter(condition) let removedKeys = store.keys.filter(condition)
removedKeys.forEach { removedKeys.forEach {
store.removeValue(forKey: $0) store.removeValue(forKey: $0)
} }
} }
public func forget(_ key: K) { public mutating func forget(_ key: K) {
store.removeValue(forKey: key) store.removeValue(forKey: key)
} }
public func clear() { public mutating func clear() {
store.removeAll() store.removeAll()
} }
} }

View File

@ -0,0 +1,102 @@
//
// Logger.swift
// Passepartout
//
// Created by Davide De Rosa on 6/15/22.
// Copyright (c) 2023 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 LoggerLevel: Int {
case verbose
case debug
case info
case warning
case error
}
public protocol Logger {
var logFile: URL? { get }
var logLevel: LoggerLevel { get set }
func verbose(_ message: Any)
func debug(_ message: Any)
func info(_ message: Any)
func warning(_ message: Any)
func error(_ message: Any)
}
final class DefaultLogger: Logger {
let logFile: URL? = nil
var logLevel: LoggerLevel = .debug
func verbose(_ message: Any) {
guard logLevel.rawValue >= LoggerLevel.verbose.rawValue else {
return
}
logMessage(message)
}
func debug(_ message: Any) {
guard logLevel.rawValue >= LoggerLevel.debug.rawValue else {
return
}
logMessage(message)
}
func info(_ message: Any) {
guard logLevel.rawValue >= LoggerLevel.info.rawValue else {
return
}
logMessage(message)
}
func warning(_ message: Any) {
guard logLevel.rawValue >= LoggerLevel.warning.rawValue else {
return
}
logMessage(message)
}
func error(_ message: Any) {
guard logLevel.rawValue >= LoggerLevel.error.rawValue else {
return
}
logMessage(message)
}
private func logMessage(_ message: Any) {
guard let string = message as? String else {
return
}
NSLog(string)
}
}

View File

@ -0,0 +1,43 @@
//
// Wifi.swift
// Passepartout
//
// Created by Davide De Rosa on 2/24/22.
// Copyright (c) 2023 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
@MainActor
public final class Wifi: ObservableObject {
private let observer: WifiObserver
public init(observer: WifiObserver) {
self.observer = observer
}
public func currentSSID() async throws -> String {
try await observer.currentSSID()
}
}
public protocol WifiObserver {
func currentSSID() async throws -> String
}

View File

@ -1,8 +1,5 @@
@_exported import PassepartoutCore @_exported import PassepartoutCore
@_exported import PassepartoutProfiles
@_exported import PassepartoutProviders @_exported import PassepartoutProviders
@_exported import PassepartoutServices @_exported import PassepartoutProvidersImpl
@_exported import PassepartoutUtils
@_exported import PassepartoutVPN @_exported import PassepartoutVPN
@_exported import TunnelKit @_exported import PassepartoutVPNImpl
@_exported import TunnelKitCore

View File

@ -1,69 +0,0 @@
//
// CoreDataProfileManagerStrategy.swift
// Passepartout
//
// Created by Davide De Rosa on 4/9/22.
// Copyright (c) 2023 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 Combine
import Foundation
import PassepartoutCore
import PassepartoutUtils
public class CoreDataProfileManagerStrategy: ProfileManagerStrategy {
private let profileRepository: ProfileRepository
private let fetchedProfiles: FetchedValueHolder<[UUID: Profile]>
public init(persistence: Persistence) {
profileRepository = ProfileRepository(persistence.context)
fetchedProfiles = profileRepository.fetchedProfiles()
}
public var allProfiles: [UUID: Profile] {
fetchedProfiles.value
}
public func profiles() -> [Profile] {
profileRepository.profiles()
}
public func profile(withId id: UUID) -> Profile? {
profileRepository.profile(withId: id)
}
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], Never> {
fetchedProfiles.$value
.eraseToAnyPublisher()
}
}

View File

@ -1,119 +0,0 @@
//
// ProfileManager+Keychain.swift
// Passepartout
//
// Created by Davide De Rosa on 4/8/22.
// Copyright (c) 2023 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 PassepartoutCore
import PassepartoutUtils
import TunnelKitManager
extension ProfileManager {
public func savePassword(forProfile profile: Profile, newPassword: String? = nil) {
guard !profile.isPlaceholder else {
assertionFailure("Placeholder")
return
}
guard let keychainEntry = profile.keychainEntry else {
return
}
let password = newPassword ?? profile.account.password
guard !password.isEmpty else {
keychain.removePassword(
for: keychainEntry,
context: appGroup,
userDefined: profile.id.uuidString
)
return
}
do {
try keychain.set(
password: password,
for: keychainEntry,
context: appGroup,
userDefined: profile.id.uuidString,
label: keychainLabel(profile.header.name, profile.currentVPNProtocol)
)
} catch {
pp_log.error("Unable to save password to keychain: \(error)")
}
}
public func passwordReference(forProfile profile: Profile) -> Data? {
guard !profile.isPlaceholder else {
assertionFailure("Placeholder")
return nil
}
guard let keychainEntry = profile.keychainEntry else {
return nil
}
do {
return try keychain.passwordReference(
for: keychainEntry,
context: appGroup,
userDefined: profile.id.uuidString
)
} catch {
pp_log.debug("Unable to load password reference from keychain: \(error)")
return nil
}
}
}
private extension Profile {
var keychainEntry: String? {
"\(id.uuidString):\(currentVPNProtocol.description):\(account.username)"
}
}
extension Keychain {
func debugAllPasswords(matching id: UUID, context: String) {
var query = allPasswordsQuery(id, context)
query[kSecReturnAttributes as String] = true
var list: CFTypeRef?
switch SecItemCopyMatching(query as CFDictionary, &list) {
case errSecSuccess:
break
default:
return
}
guard let list = list else {
pp_log.debug("Keychain items: none")
return
}
pp_log.debug("Keychain items: \(list)")
}
func removeAllPasswords(matching id: UUID, context: String) {
_ = SecItemDelete(allPasswordsQuery(id, context) as CFDictionary)
}
private func allPasswordsQuery(_ id: UUID, _ context: String) -> [String: Any] {
var query = [String: Any]()
setScope(query: &query, context: context, userDefined: id.uuidString)
query[kSecClass as String] = kSecClassGenericPassword
return query
}
}

View File

@ -1,46 +0,0 @@
//
// CDInfrastructure+CoreDataProperties.swift
//
//
// Created by Davide De Rosa on 27/03/22.
//
// This file was automatically generated and should not be edited.
//
import CoreData
import Foundation
extension CDInfrastructure {
@nonobjc public class func fetchRequest() -> NSFetchRequest<CDInfrastructure> {
return NSFetchRequest<CDInfrastructure>(entityName: "CDInfrastructure")
}
@NSManaged public var lastUpdate: Date?
@NSManaged public var vpnProtocol: String?
@NSManaged public var categories: NSSet?
@NSManaged public var defaults: CDInfrastructureDefaultSettings?
@NSManaged public var provider: CDProvider?
}
// MARK: Generated accessors for categories
extension CDInfrastructure {
@objc(addCategoriesObject:)
@NSManaged public func addToCategories(_ value: CDInfrastructureCategory)
@objc(removeCategoriesObject:)
@NSManaged public func removeFromCategories(_ value: CDInfrastructureCategory)
@objc(addCategories:)
@NSManaged public func addToCategories(_ values: NSSet)
@objc(removeCategories:)
@NSManaged public func removeFromCategories(_ values: NSSet)
}
extension CDInfrastructure: Identifiable {
}

View File

@ -1,80 +0,0 @@
//
// CDInfrastructureCategory+CoreDataProperties.swift
//
//
// Created by Davide De Rosa on 27/03/22.
//
// This file was automatically generated and should not be edited.
//
import CoreData
import Foundation
extension CDInfrastructureCategory {
@nonobjc public class func fetchRequest() -> NSFetchRequest<CDInfrastructureCategory> {
return NSFetchRequest<CDInfrastructureCategory>(entityName: "CDInfrastructureCategory")
}
@NSManaged public var name: String?
@NSManaged public var infrastructure: CDInfrastructure?
@NSManaged public var locations: NSSet?
@NSManaged public var presets: NSSet?
@NSManaged public var servers: NSSet?
}
// MARK: Generated accessors for locations
extension CDInfrastructureCategory {
@objc(addLocationsObject:)
@NSManaged public func addToLocations(_ value: CDInfrastructureLocation)
@objc(removeLocationsObject:)
@NSManaged public func removeFromLocations(_ value: CDInfrastructureLocation)
@objc(addLocations:)
@NSManaged public func addToLocations(_ values: NSSet)
@objc(removeLocations:)
@NSManaged public func removeFromLocations(_ values: NSSet)
}
// MARK: Generated accessors for presets
extension CDInfrastructureCategory {
@objc(addPresetsObject:)
@NSManaged public func addToPresets(_ value: CDInfrastructurePreset)
@objc(removePresetsObject:)
@NSManaged public func removeFromPresets(_ value: CDInfrastructurePreset)
@objc(addPresets:)
@NSManaged public func addToPresets(_ values: NSSet)
@objc(removePresets:)
@NSManaged public func removeFromPresets(_ values: NSSet)
}
// MARK: Generated accessors for servers
extension CDInfrastructureCategory {
@objc(addServersObject:)
@NSManaged public func addToServers(_ value: CDInfrastructureServer)
@objc(removeServersObject:)
@NSManaged public func removeFromServers(_ value: CDInfrastructureServer)
@objc(addServers:)
@NSManaged public func addToServers(_ values: NSSet)
@objc(removeServers:)
@NSManaged public func removeFromServers(_ values: NSSet)
}
extension CDInfrastructureCategory: Identifiable {
}

View File

@ -1,47 +0,0 @@
//
// CDInfrastructurePreset+CoreDataProperties.swift
//
//
// Created by Davide De Rosa on 27/03/22.
//
// This file was automatically generated and should not be edited.
//
import CoreData
import Foundation
extension CDInfrastructurePreset {
@nonobjc public class func fetchRequest() -> NSFetchRequest<CDInfrastructurePreset> {
return NSFetchRequest<CDInfrastructurePreset>(entityName: "CDInfrastructurePreset")
}
@NSManaged public var comment: String?
@NSManaged public var id: String?
@NSManaged public var name: String?
@NSManaged public var vpnConfiguration: Data?
@NSManaged public var vpnProtocol: String?
@NSManaged public var category: NSSet?
}
// MARK: Generated accessors for category
extension CDInfrastructurePreset {
@objc(addCategoryObject:)
@NSManaged public func addToCategory(_ value: CDInfrastructureCategory)
@objc(removeCategoryObject:)
@NSManaged public func removeFromCategory(_ value: CDInfrastructureCategory)
@objc(addCategory:)
@NSManaged public func addToCategory(_ values: NSSet)
@objc(removeCategory:)
@NSManaged public func removeFromCategory(_ values: NSSet)
}
extension CDInfrastructurePreset: Identifiable {
}

View File

@ -1,35 +0,0 @@
//
// CDInfrastructureServer+CoreDataProperties.swift
//
//
// Created by Davide De Rosa on 27/03/22.
//
// This file was automatically generated and should not be edited.
//
import CoreData
import Foundation
extension CDInfrastructureServer {
@nonobjc public class func fetchRequest() -> NSFetchRequest<CDInfrastructureServer> {
return NSFetchRequest<CDInfrastructureServer>(entityName: "CDInfrastructureServer")
}
@NSManaged public var area: String?
@NSManaged public var countryCode: String?
@NSManaged public var extraCountryCodes: String?
@NSManaged public var hostname: String?
@NSManaged public var ipAddresses: String?
@NSManaged public var apiId: String?
@NSManaged public var serverIndex: Int16
@NSManaged public var tags: String?
@NSManaged public var uniqueId: String?
@NSManaged public var category: CDInfrastructureCategory?
@NSManaged public var location: CDInfrastructureLocation?
}
extension CDInfrastructureServer: Identifiable {
}

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