diff --git a/CHANGELOG.md b/CHANGELOG.md index 859f36365..e2f92f835 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,15 @@ All notable changes to this project will be documented in this file. +## 2.12.4 - 2024-09-17 + +[NEW] Option to show/hide Account ID +[IMPROVED] Error handling for in-app purchases +[FIXED] Location marker disappearing when the app wakes up from the background (iOS 18) +[FIXED] Privacy overlay not working (iOS 18) +[FIXED] Widget actions to Connect/Disconnect not working (iOS 18) +[FIXED] Actions not appearing in the Shortcuts app (iOS 18) + ## 2.12.3 - 2024-06-04 [IMPROVED] Post-Quantum library updated to the latest version diff --git a/IVPNClient.xcodeproj/project.pbxproj b/IVPNClient.xcodeproj/project.pbxproj index 623991b6c..c1fb42950 100644 --- a/IVPNClient.xcodeproj/project.pbxproj +++ b/IVPNClient.xcodeproj/project.pbxproj @@ -25,8 +25,6 @@ 8206BAFF29ED6FFF00F916B7 /* ConnectionInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8206BAFE29ED6FFF00F916B7 /* ConnectionInfoView.swift */; }; 8206BB0129ED7BEE00F916B7 /* ConnectionInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8206BB0029ED7BEE00F916B7 /* ConnectionInfo.swift */; }; 8206BB0329ED7C3700F916B7 /* ConnectionInfoViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8206BB0229ED7C3700F916B7 /* ConnectionInfoViewModel.swift */; }; - 8206E5D022967E37003119AF /* UserActivityType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8206E5CF22967E37003119AF /* UserActivityType.swift */; }; - 8206E5D222967EAF003119AF /* UserActivityTitle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8206E5D122967EAF003119AF /* UserActivityTitle.swift */; }; 8206F32124347A8F0056B465 /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8206F32024347A8F0056B465 /* MainView.swift */; }; 8206F32324367A240056B465 /* VPNErrorObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8206F32224367A240056B465 /* VPNErrorObserver.swift */; }; 8208525623FD56870008C112 /* FloatingPanelMainLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8208525523FD56870008C112 /* FloatingPanelMainLayout.swift */; }; @@ -68,6 +66,11 @@ 822BC68A2A7CF3A700C733DF /* Decodable+Ext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 822BC6892A7CF3A700C733DF /* Decodable+Ext.swift */; }; 822BC68B2A7CF3A700C733DF /* Decodable+Ext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 822BC6892A7CF3A700C733DF /* Decodable+Ext.swift */; }; 822BC68C2A7CF3A700C733DF /* Decodable+Ext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 822BC6892A7CF3A700C733DF /* Decodable+Ext.swift */; }; + 822EBCA22C91947700E708F6 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 822EBCA12C91947700E708F6 /* PrivacyInfo.xcprivacy */; }; + 822EBCA42C91AADA00E708F6 /* PrivacyInfo-IVPNWidget.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 822EBCA32C91AADA00E708F6 /* PrivacyInfo-IVPNWidget.xcprivacy */; }; + 822EBCA62C91AB3800E708F6 /* PrivacyInfo-openvpn-tunnel-provider.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 822EBCA52C91AB3800E708F6 /* PrivacyInfo-openvpn-tunnel-provider.xcprivacy */; }; + 822EBCA82C91AB5900E708F6 /* PrivacyInfo-wireguard-tunnel-provider.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 822EBCA72C91AB5900E708F6 /* PrivacyInfo-wireguard-tunnel-provider.xcprivacy */; }; + 822EBCA92C91AB5900E708F6 /* PrivacyInfo-wireguard-tunnel-provider.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 822EBCA72C91AB5900E708F6 /* PrivacyInfo-wireguard-tunnel-provider.xcprivacy */; }; 822EE96C215CE0E300BE77F6 /* UserDefaults+Ext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825A43FC215CCFE70076131F /* UserDefaults+Ext.swift */; }; 8232FBF42240DE19006B81D2 /* ErrorResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8232FBF32240DE19006B81D2 /* ErrorResult.swift */; }; 8232FBF62240E40F006B81D2 /* Error+Ext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8232FBF52240E40F006B81D2 /* Error+Ext.swift */; }; @@ -151,6 +154,7 @@ 828772F7221C008100D5E330 /* ServerConfigurationCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 828772F6221C008100D5E330 /* ServerConfigurationCell.swift */; }; 828772F9221C01C300D5E330 /* ServersConfigurationTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 828772F8221C01C300D5E330 /* ServersConfigurationTableViewController.swift */; }; 828772FB221C28E000D5E330 /* FlagImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 828772FA221C28E000D5E330 /* FlagImageView.swift */; }; + 828C45692C88772E0064F365 /* AppIntentsHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 828C45682C8877290064F365 /* AppIntentsHandler.swift */; }; 828D8A6D258245AD00CB0E5B /* TwoFactorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 828D8A6C258245AD00CB0E5B /* TwoFactorViewController.swift */; }; 828E9C95231E5780001E1FCF /* Data+Ext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 828E9C94231E5780001E1FCF /* Data+Ext.swift */; }; 828E9C96231E5780001E1FCF /* Data+Ext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 828E9C94231E5780001E1FCF /* Data+Ext.swift */; }; @@ -267,6 +271,7 @@ 82DB75EE239E766A0073E846 /* NEVPNStatusTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82DB75ED239E766A0073E846 /* NEVPNStatusTests.swift */; }; 82DC75BC22B277D200D3C73C /* APIClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82DC75BB22B277D200D3C73C /* APIClient.swift */; }; 82DC75BD22B7647500D3C73C /* APIClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82DC75BB22B277D200D3C73C /* APIClient.swift */; }; + 82DE85712C8861CB00501935 /* AppIntents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82DE85702C8861CB00501935 /* AppIntents.swift */; }; 82DEF01E244714D900CCB5CD /* ScannerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82DEF01D244714D900CCB5CD /* ScannerViewController.swift */; }; 82DEF021244714F000CCB5CD /* ScannerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82DEF020244714F000CCB5CD /* ScannerView.swift */; }; 82DEF0262447285F00CCB5CD /* CreateAccountViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82DEF0252447285F00CCB5CD /* CreateAccountViewController.swift */; }; @@ -471,8 +476,6 @@ 8206BAFE29ED6FFF00F916B7 /* ConnectionInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionInfoView.swift; sourceTree = ""; }; 8206BB0029ED7BEE00F916B7 /* ConnectionInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionInfo.swift; sourceTree = ""; }; 8206BB0229ED7C3700F916B7 /* ConnectionInfoViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionInfoViewModel.swift; sourceTree = ""; }; - 8206E5CF22967E37003119AF /* UserActivityType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserActivityType.swift; sourceTree = ""; }; - 8206E5D122967EAF003119AF /* UserActivityTitle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserActivityTitle.swift; sourceTree = ""; }; 8206F32024347A8F0056B465 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = ""; }; 8206F32224367A240056B465 /* VPNErrorObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNErrorObserver.swift; sourceTree = ""; }; 8208525523FD56870008C112 /* FloatingPanelMainLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FloatingPanelMainLayout.swift; sourceTree = ""; }; @@ -504,6 +507,10 @@ 8229209F2480FA3600476FC1 /* ServersSort.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServersSort.swift; sourceTree = ""; }; 822B85D821B941A200715691 /* NotificationName+Ext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NotificationName+Ext.swift"; sourceTree = ""; }; 822BC6892A7CF3A700C733DF /* Decodable+Ext.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Decodable+Ext.swift"; sourceTree = ""; }; + 822EBCA12C91947700E708F6 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; + 822EBCA32C91AADA00E708F6 /* PrivacyInfo-IVPNWidget.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = "PrivacyInfo-IVPNWidget.xcprivacy"; sourceTree = ""; }; + 822EBCA52C91AB3800E708F6 /* PrivacyInfo-openvpn-tunnel-provider.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = "PrivacyInfo-openvpn-tunnel-provider.xcprivacy"; sourceTree = ""; }; + 822EBCA72C91AB5900E708F6 /* PrivacyInfo-wireguard-tunnel-provider.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = "PrivacyInfo-wireguard-tunnel-provider.xcprivacy"; sourceTree = ""; }; 8232FBF32240DE19006B81D2 /* ErrorResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorResult.swift; sourceTree = ""; }; 8232FBF52240E40F006B81D2 /* Error+Ext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Error+Ext.swift"; sourceTree = ""; }; 8234E0D62AB23E5C0015C9A2 /* V2RayControl.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = V2RayControl.xcframework; path = Frameworks/V2RayControl.xcframework; sourceTree = ""; }; @@ -587,6 +594,7 @@ 828772F6221C008100D5E330 /* ServerConfigurationCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerConfigurationCell.swift; sourceTree = ""; }; 828772F8221C01C300D5E330 /* ServersConfigurationTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServersConfigurationTableViewController.swift; sourceTree = ""; }; 828772FA221C28E000D5E330 /* FlagImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlagImageView.swift; sourceTree = ""; }; + 828C45682C8877290064F365 /* AppIntentsHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppIntentsHandler.swift; sourceTree = ""; }; 828D8A6C258245AD00CB0E5B /* TwoFactorViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwoFactorViewController.swift; sourceTree = ""; }; 828E9C94231E5780001E1FCF /* Data+Ext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Data+Ext.swift"; sourceTree = ""; }; 8290195E243CB27500777B6E /* ControlPanelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ControlPanelView.swift; sourceTree = ""; }; @@ -674,6 +682,7 @@ 82DB75EB239E75EB0073E846 /* NEVPNStatus+Ext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NEVPNStatus+Ext.swift"; sourceTree = ""; }; 82DB75ED239E766A0073E846 /* NEVPNStatusTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NEVPNStatusTests.swift; sourceTree = ""; }; 82DC75BB22B277D200D3C73C /* APIClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APIClient.swift; sourceTree = ""; }; + 82DE85702C8861CB00501935 /* AppIntents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppIntents.swift; sourceTree = ""; }; 82DEF01D244714D900CCB5CD /* ScannerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScannerViewController.swift; sourceTree = ""; }; 82DEF020244714F000CCB5CD /* ScannerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScannerView.swift; sourceTree = ""; }; 82DEF0252447285F00CCB5CD /* CreateAccountViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateAccountViewController.swift; sourceTree = ""; }; @@ -925,6 +934,7 @@ 82C1D5BD23FE8BD90059A915 /* ControlPanel */, 8208525723FD5EB20008C112 /* MainViewController.swift */, 8208525B23FD64160008C112 /* MainViewController+Ext.swift */, + 828C45682C8877290064F365 /* AppIntentsHandler.swift */, ); path = MainScreen; sourceTree = ""; @@ -1032,6 +1042,7 @@ 827694F2263C04C40058B4DC /* LoginConfirmation.swift */, 821CA2DE288143470067F70D /* PortRange.swift */, 825ECB2B2A5582570032E986 /* AntiTrackerDns.swift */, + 82DE85702C8861CB00501935 /* AppIntents.swift */, ); path = Models; sourceTree = ""; @@ -1192,8 +1203,6 @@ 82E716832181E8E100D6B7C2 /* ProviderConfigurationKeys.swift */, 82D598B321A5A7A3000FABDE /* NetworkTrust.swift */, 82D598C721A6ADF1000FABDE /* NetworkType.swift */, - 8206E5CF22967E37003119AF /* UserActivityType.swift */, - 8206E5D122967EAF003119AF /* UserActivityTitle.swift */, 823FFB062338DF1800F91A5D /* Capability.swift */, 8229209F2480FA3600476FC1 /* ServersSort.swift */, 826FBDA22461847D00B9E464 /* ServiceType.swift */, @@ -1360,6 +1369,7 @@ 824B86C326D3D7B600D0101A /* TimerManager.swift */, 82B605272170840C004B40E6 /* Info.plist */, 82B605282170840C004B40E6 /* wireguard_tunnel_provider.entitlements */, + 822EBCA72C91AB5900E708F6 /* PrivacyInfo-wireguard-tunnel-provider.xcprivacy */, ); path = "wireguard-tunnel-provider"; sourceTree = ""; @@ -1536,6 +1546,7 @@ 82E3B21229DDCC6500998F67 /* Assets.xcassets */, 82E3B21429DDCC6500998F67 /* Info.plist */, 82C61DA829E6C4CF00AF972A /* Widget-Bridging-Header.h */, + 822EBCA32C91AADA00E708F6 /* PrivacyInfo-IVPNWidget.xcprivacy */, ); path = IVPNWidget; sourceTree = ""; @@ -1606,6 +1617,7 @@ 9C7840AC20CD8A8A00335736 /* Info.plist */, 82ED17452A1259CB00E7926D /* OpenVPNNetworkExtension-Bridging-Header.h */, 9C7840AD20CD8A8A00335736 /* openvpn_tunnel_provider.entitlements */, + 822EBCA52C91AB3800E708F6 /* PrivacyInfo-openvpn-tunnel-provider.xcprivacy */, ); path = "openvpn-tunnel-provider"; sourceTree = ""; @@ -1657,6 +1669,7 @@ 9CB2CE261DAA6C1B007A4D2D /* IVPNClient.entitlements */, 9CB2CE321DAF9283007A4D2D /* Model.xcdatamodeld */, 825443972B2A1B8F00D77095 /* Store.storekit */, + 822EBCA12C91947700E708F6 /* PrivacyInfo.xcprivacy */, ); path = IVPNClient; sourceTree = ""; @@ -1922,7 +1935,7 @@ mainGroup = 9CDDD5A21D9D2F9E00D39924; packageReferences = ( 824B86DD26D42A4600D0101A /* XCRemoteSwiftPackageReference "wireguard-apple" */, - 82968A30298A970500077E0A /* XCRemoteSwiftPackageReference "tunnelkit" */, + 82968A30298A970500077E0A /* XCRemoteSwiftPackageReference "Tunnelkit" */, 82EC883329A12BD30024CC40 /* XCRemoteSwiftPackageReference "JGProgressHUD" */, 82EC883629A12C1F0024CC40 /* XCRemoteSwiftPackageReference "Reachability" */, 82EC883929A12C7D0024CC40 /* XCRemoteSwiftPackageReference "SwiftyStoreKit" */, @@ -1958,6 +1971,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 822EBCA92C91AB5900E708F6 /* PrivacyInfo-wireguard-tunnel-provider.xcprivacy in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1972,6 +1986,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 822EBCA42C91AADA00E708F6 /* PrivacyInfo-IVPNWidget.xcprivacy in Resources */, 82C61D9629E6ADEF00AF972A /* Assets.xcassets in Resources */, 82E3B21329DDCC6500998F67 /* Assets.xcassets in Resources */, ); @@ -1981,6 +1996,8 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 822EBCA82C91AB5900E708F6 /* PrivacyInfo-wireguard-tunnel-provider.xcprivacy in Resources */, + 822EBCA62C91AB3800E708F6 /* PrivacyInfo-openvpn-tunnel-provider.xcprivacy in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1989,6 +2006,7 @@ buildActionMask = 2147483647; files = ( 9CDDD5B91D9D2F9F00D39924 /* LaunchScreen.storyboard in Resources */, + 822EBCA22C91947700E708F6 /* PrivacyInfo.xcprivacy in Resources */, 9CDDD5B61D9D2F9F00D39924 /* Assets.xcassets in Resources */, 821E355A2A95F77700AEE5C7 /* config.json in Resources */, 9CB2CE541DB2A999007A4D2D /* servers.json in Resources */, @@ -2285,7 +2303,6 @@ 82D598BC21A6949F000FABDE /* StorageManager.swift in Sources */, 826FBDA32461847D00B9E464 /* ServiceType.swift in Sources */, 821429B922FC2EA40056B8FF /* ApiService+Ext.swift in Sources */, - 8206E5D222967EAF003119AF /* UserActivityTitle.swift in Sources */, 82E716902181E90500D6B7C2 /* ConnectionSettings.swift in Sources */, 8223C54C22E9E93A00CD283D /* Session.swift in Sources */, 822563922431E03A00AE7F8D /* AccountView.swift in Sources */, @@ -2334,6 +2351,7 @@ 8292E1A92174C11600123538 /* Interface.swift in Sources */, 82F638CC217DC25600410318 /* CIDRAddress.swift in Sources */, 824B86D226D40E7800D0101A /* FileManager+Extension.swift in Sources */, + 828C45692C88772E0064F365 /* AppIntentsHandler.swift in Sources */, 8208525A23FD5F670008C112 /* FloatingPanelController+Ext.swift in Sources */, 821429B722FC2BE90056B8FF /* Result.swift in Sources */, 827855B92472B27F00B3B6BD /* Account.swift in Sources */, @@ -2357,7 +2375,6 @@ 82A3422524AB6AF700761AB0 /* Double+Ext.swift in Sources */, 8221377B2227E75E001E1BF5 /* CustomDNSViewController.swift in Sources */, 9C3031351DB42EF900C38B0C /* Application.swift in Sources */, - 8206E5D022967E37003119AF /* UserActivityType.swift in Sources */, 82A6D74A24A3780B00D6C0E1 /* ConnectToServerPopupView.swift in Sources */, 828772FB221C28E000D5E330 /* FlagImageView.swift in Sources */, 8228C8D22B1DE906005977D3 /* PurchaseManager.swift in Sources */, @@ -2392,6 +2409,7 @@ 82DEF01E244714D900CCB5CD /* ScannerViewController.swift in Sources */, 8270D268241BB3D100B17B65 /* InfoAlertViewModel.swift in Sources */, 826E614A242A1CA80064F195 /* AccountViewModel.swift in Sources */, + 82DE85712C8861CB00501935 /* AppIntents.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2812,7 +2830,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = IVPNClient/IVPNClient.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 13; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = WQXXM75BYN; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -2830,7 +2848,7 @@ "$(inherited)", "$(PROJECT_DIR)/IVPNClient/liboqs", ); - MARKETING_VERSION = 2.12.2; + MARKETING_VERSION = 2.12.4; ONLY_ACTIVE_ARCH = YES; OTHER_LDFLAGS = "$(inherited)"; OTHER_SWIFT_FLAGS = "-D DEBUG"; @@ -3301,7 +3319,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = IVPNClient/IVPNClient.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 13; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = WQXXM75BYN; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -3319,7 +3337,7 @@ "$(inherited)", "$(PROJECT_DIR)/IVPNClient/liboqs", ); - MARKETING_VERSION = 2.12.2; + MARKETING_VERSION = 2.12.4; ONLY_ACTIVE_ARCH = YES; OTHER_LDFLAGS = "$(inherited)"; OTHER_SWIFT_FLAGS = "-D DEBUG"; @@ -3340,7 +3358,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = IVPNClient/IVPNClient.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 13; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = WQXXM75BYN; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -3358,7 +3376,7 @@ "$(inherited)", "$(PROJECT_DIR)/IVPNClient/liboqs", ); - MARKETING_VERSION = 2.12.2; + MARKETING_VERSION = 2.12.4; ONLY_ACTIVE_ARCH = YES; OTHER_LDFLAGS = "$(inherited)"; OTHER_SWIFT_FLAGS = "-D RELEASE"; @@ -3463,12 +3481,12 @@ revision = ccc7472fd7d1c7c19584e6a30c45a56b8ba57790; }; }; - 82968A30298A970500077E0A /* XCRemoteSwiftPackageReference "tunnelkit" */ = { + 82968A30298A970500077E0A /* XCRemoteSwiftPackageReference "Tunnelkit" */ = { isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/passepartoutvpn/tunnelkit"; + repositoryURL = "https://github.com/mrstao/Tunnelkit"; requirement = { - kind = exactVersion; - version = 6.2.0; + branch = main; + kind = branch; }; }; 829F5FC529A13CAE009E1AD3 /* XCRemoteSwiftPackageReference "KeychainAccess" */ = { @@ -3516,7 +3534,7 @@ repositoryURL = "https://github.com/scenee/FloatingPanel"; requirement = { kind = exactVersion; - version = 2.6.3; + version = 2.8.3; }; }; 82EC884529A12D510024CC40 /* XCRemoteSwiftPackageReference "SnapKit" */ = { @@ -3542,12 +3560,12 @@ }; 82968A31298A970500077E0A /* TunnelKitOpenVPN */ = { isa = XCSwiftPackageProductDependency; - package = 82968A30298A970500077E0A /* XCRemoteSwiftPackageReference "tunnelkit" */; + package = 82968A30298A970500077E0A /* XCRemoteSwiftPackageReference "Tunnelkit" */; productName = TunnelKitOpenVPN; }; 82968A33298A970500077E0A /* TunnelKitOpenVPNAppExtension */ = { isa = XCSwiftPackageProductDependency; - package = 82968A30298A970500077E0A /* XCRemoteSwiftPackageReference "tunnelkit" */; + package = 82968A30298A970500077E0A /* XCRemoteSwiftPackageReference "Tunnelkit" */; productName = TunnelKitOpenVPNAppExtension; }; 829F5FC629A13CAE009E1AD3 /* KeychainAccess */ = { diff --git a/IVPNClient/AppDelegate.swift b/IVPNClient/AppDelegate.swift index 1753b0197..07c48ef1f 100644 --- a/IVPNClient/AppDelegate.swift +++ b/IVPNClient/AppDelegate.swift @@ -96,16 +96,9 @@ class AppDelegate: UIResponder { private func showSecurityScreen() { var showWindow = false + let topVC = UIApplication.topViewController() - if UIApplication.topViewController() as? AccountViewController != nil { - showWindow = true - } - - if UIApplication.topViewController() as? LoginViewController != nil { - showWindow = true - } - - if UIApplication.topViewController() as? CreateAccountViewController != nil { + if topVC is AccountViewController || topVC is LoginViewController || topVC is CreateAccountViewController { showWindow = true } @@ -439,3 +432,12 @@ extension AppDelegate: PurchaseManagerDelegate { } } + +enum UserActivityType { + static let Connect = "net.ivpn.clients.ios.Connect" + static let Disconnect = "net.ivpn.clients.ios.Disconnect" + static let AntiTrackerEnable = "net.ivpn.clients.ios.AntiTracker.enable" + static let AntiTrackerDisable = "net.ivpn.clients.ios.AntiTracker.disable" + static let CustomDNSEnable = "net.ivpn.clients.ios.CustomDNS.enable" + static let CustomDNSDisable = "net.ivpn.clients.ios.CustomDNS.disable" +} diff --git a/IVPNClient/Enums/UserActivityTitle.swift b/IVPNClient/Enums/UserActivityTitle.swift deleted file mode 100644 index 74c4590fb..000000000 --- a/IVPNClient/Enums/UserActivityTitle.swift +++ /dev/null @@ -1,33 +0,0 @@ -// -// UserActivityTitle.swift -// IVPN iOS app -// https://github.com/ivpn/ios-app -// -// Created by Juraj Hilje on 2019-05-23. -// Copyright (c) 2023 IVPN Limited. -// -// This file is part of the IVPN iOS app. -// -// The IVPN iOS app 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. -// -// The IVPN iOS app 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 the IVPN iOS app. If not, see . -// - -import Foundation - -enum UserActivityTitle { - static let Connect = "Connect" - static let Disconnect = "Disconnect" - static let AntiTrackerEnable = "Enable AntiTracker" - static let AntiTrackerDisable = "Disable AntiTracker" - static let CustomDNSEnable = "Enable CustomDNS" - static let CustomDNSDisable = "Disable CustomDNS" -} diff --git a/IVPNClient/Enums/UserActivityType.swift b/IVPNClient/Enums/UserActivityType.swift deleted file mode 100644 index d0be60601..000000000 --- a/IVPNClient/Enums/UserActivityType.swift +++ /dev/null @@ -1,33 +0,0 @@ -// -// UserActivityType.swift -// IVPN iOS app -// https://github.com/ivpn/ios-app -// -// Created by Juraj Hilje on 2019-05-23. -// Copyright (c) 2023 IVPN Limited. -// -// This file is part of the IVPN iOS app. -// -// The IVPN iOS app 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. -// -// The IVPN iOS app 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 the IVPN iOS app. If not, see . -// - -import Foundation - -enum UserActivityType { - static let Connect = "net.ivpn.clients.ios.Connect" - static let Disconnect = "net.ivpn.clients.ios.Disconnect" - static let AntiTrackerEnable = "net.ivpn.clients.ios.AntiTracker.enable" - static let AntiTrackerDisable = "net.ivpn.clients.ios.AntiTracker.disable" - static let CustomDNSEnable = "net.ivpn.clients.ios.CustomDNS.enable" - static let CustomDNSDisable = "net.ivpn.clients.ios.CustomDNS.disable" -} diff --git a/IVPNClient/Managers/ConnectionManager.swift b/IVPNClient/Managers/ConnectionManager.swift index be4ed03d2..bd52b54fc 100644 --- a/IVPNClient/Managers/ConnectionManager.swift +++ b/IVPNClient/Managers/ConnectionManager.swift @@ -96,9 +96,6 @@ class ConnectionManager { self.updateOpenVPNLogFile() self.updateWireGuardLogFile() self.reconnectAutomatically = false - if self.actionType == .connect { - self.evaluateCloseApp() - } } DispatchQueue.delay(2.5) { if UserDefaults.shared.isV2ray && !V2RayCore.shared.reconnectWithV2ray { @@ -128,10 +125,6 @@ class ConnectionManager { } } } - - if status == .disconnected && self.actionType == .disconnect { - self.evaluateCloseApp() - } completion(status) } @@ -575,12 +568,10 @@ class ConnectionManager { } } - private func evaluateCloseApp() { + func evaluateCloseApp() { if closeApp { closeApp = false - DispatchQueue.delay(1.5) { - UIControl().sendAction(#selector(NSXPCConnection.suspend), to: UIApplication.shared, for: nil) - } + UIControl().sendAction(#selector(NSXPCConnection.suspend), to: UIApplication.shared, for: nil) } } diff --git a/IVPNClient/Managers/PurchaseManager.swift b/IVPNClient/Managers/PurchaseManager.swift index f0fe61c43..190761b17 100644 --- a/IVPNClient/Managers/PurchaseManager.swift +++ b/IVPNClient/Managers/PurchaseManager.swift @@ -86,11 +86,11 @@ class PurchaseManager: NSObject { log(.info, message: "[Store] Completing successful in-app purchase \(productId)") self.complete(transaction) break - case .success(.unverified(_, _)): + case .success(.unverified(_, let result)): // Successful purchase but transaction/receipt can't be verified // Could be a jailbroken phone log(.info, message: "[Store] Purchase \(productId): success, unverified") - delegate?.purchaseError(error: ErrorResult(status: 500, message: "Purchase is unverified.")) + delegate?.purchaseError(error: ErrorResult(status: 500, message: "Purchase is unverified: \(result.localizedDescription).")) break case .pending: // Transaction waiting on SCA (Strong Customer Authentication) or @@ -117,6 +117,10 @@ class PurchaseManager: NSObject { continue } + guard ProductId.all.contains(transaction.productID) else { + continue + } + if transaction.revocationDate == nil { log(.info, message: "[Store] Completing unfinished purchase \(transaction.productID)") complete(transaction) diff --git a/IVPNClient/Models/AppIntents.swift b/IVPNClient/Models/AppIntents.swift new file mode 100644 index 000000000..49d890d5a --- /dev/null +++ b/IVPNClient/Models/AppIntents.swift @@ -0,0 +1,97 @@ +// +// AddNoteIntent.swift +// IVPN iOS app +// https://github.com/ivpn/ios-app +// +// Created by Juraj Hilje on 2024-09-04. +// Copyright (c) 2024 IVPN Limited. +// +// This file is part of the IVPN iOS app. +// +// The IVPN iOS app 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. +// +// The IVPN iOS app 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 the IVPN iOS app. If not, see . +// + + +import AppIntents + +@available(iOS 16, *) +struct Connect: AppIntent { + static var title = LocalizedStringResource("Connect VPN") + static var description = IntentDescription("Connect to the VPN") + + func perform() async throws -> some IntentResult { + log(.info, message: "App Intent handler: Connect") + NotificationCenter.default.post(name: Notification.Name.IntentConnect, object: nil) + return .result() + } +} + +@available(iOS 16, *) +struct Disconnect: AppIntent { + static var title = LocalizedStringResource("Disconnect VPN") + static var description = IntentDescription("Disconnect from the VPN") + + func perform() async throws -> some IntentResult { + log(.info, message: "App Intent handler: Disconnect") + NotificationCenter.default.post(name: Notification.Name.IntentDisconnect, object: nil) + return .result() + } +} + +@available(iOS 16, *) +struct AntiTrackerEnable: AppIntent { + static var title = LocalizedStringResource("Enable AntiTracker") + static var description = IntentDescription("Enables the AntiTracker") + + func perform() async throws -> some IntentResult { + log(.info, message: "App Intent handler: EnableAntiTracker") + NotificationCenter.default.post(name: Notification.Name.IntentAntiTrackerEnable, object: nil) + return .result() + } +} + +@available(iOS 16, *) +struct AntiTrackerDisable: AppIntent { + static var title = LocalizedStringResource("Disable AntiTracker") + static var description = IntentDescription("Disables the AntiTracker") + + func perform() async throws -> some IntentResult { + log(.info, message: "App Intent handler: DisableAntiTracker") + NotificationCenter.default.post(name: Notification.Name.IntentAntiTrackerDisable, object: nil) + return .result() + } +} + +@available(iOS 16, *) +struct CustomDNSEnable: AppIntent { + static var title = LocalizedStringResource("Enable Custom DNS") + static var description = IntentDescription("Enables the Custom DNS") + + func perform() async throws -> some IntentResult { + log(.info, message: "App Intent handler: EnableCustomDNS") + NotificationCenter.default.post(name: Notification.Name.IntentCustomDNSEnable, object: nil) + return .result() + } +} + +@available(iOS 16, *) +struct CustomDNSDisable: AppIntent { + static var title = LocalizedStringResource("Disable Custom DNS") + static var description = IntentDescription("Disables the Custom DNS") + + func perform() async throws -> some IntentResult { + log(.info, message: "App Intent handler: DisableCustomDNS") + NotificationCenter.default.post(name: Notification.Name.IntentCustomDNSDisable, object: nil) + return .result() + } +} diff --git a/IVPNClient/PrivacyInfo.xcprivacy b/IVPNClient/PrivacyInfo.xcprivacy new file mode 100644 index 000000000..9ed00cce6 --- /dev/null +++ b/IVPNClient/PrivacyInfo.xcprivacy @@ -0,0 +1,34 @@ + + + + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryFileTimestamp + NSPrivacyAccessedAPITypeReasons + + C617.1 + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategorySystemBootTime + NSPrivacyAccessedAPITypeReasons + + 35F9.1 + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryUserDefaults + NSPrivacyAccessedAPITypeReasons + + CA92.1 + 1C8F.1 + + + + + diff --git a/IVPNClient/Scenes/AccountScreen/AccountViewController.swift b/IVPNClient/Scenes/AccountScreen/AccountViewController.swift index 36072ab40..48992e634 100644 --- a/IVPNClient/Scenes/AccountScreen/AccountViewController.swift +++ b/IVPNClient/Scenes/AccountScreen/AccountViewController.swift @@ -77,11 +77,18 @@ class AccountViewController: UITableViewController { } } + @IBAction func toggleAccountHidden(_ sender: Any) { + let hidden = accountView.isAccountHidden + accountView.toggleAccountVisibility(hide: !hidden) + accountView.isAccountHidden = !hidden + } + // MARK: - View Lifecycle - override func viewDidLoad() { super.viewDidLoad() tableView.backgroundColor = UIColor.init(named: Theme.ivpnBackgroundQuaternary) + NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil) initNavigationBar() addObservers() accountView.setupView(viewModel: viewModel) @@ -93,6 +100,10 @@ class AccountViewController: UITableViewController { sessionManager.getSessionStatus() } + @objc func willEnterForeground(notification: NSNotification) { + accountView.setupView(viewModel: viewModel) + } + // MARK: - Observers - func addObservers() { diff --git a/IVPNClient/Scenes/AccountScreen/View/AccountView.swift b/IVPNClient/Scenes/AccountScreen/View/AccountView.swift index a7e7d5066..eaf74bc7e 100644 --- a/IVPNClient/Scenes/AccountScreen/View/AccountView.swift +++ b/IVPNClient/Scenes/AccountScreen/View/AccountView.swift @@ -37,9 +37,11 @@ class AccountView: UITableView { @IBOutlet weak var deviceNameTitle: UILabel! @IBOutlet weak var deviceName: UILabel! @IBOutlet weak var header: UIView! + @IBOutlet weak var hideAccountButton: UIButton! // MARK: - Properties - + var isAccountHidden = true private var serviceType = ServiceType.getType(currentPlan: Application.shared.serviceStatus.currentPlan) // MARK: - Methods - @@ -58,10 +60,30 @@ class AccountView: UITableView { header.frame = CGRect(x: 0, y: 0, width: Int(header.frame.width), height: headerHeight) reloadData() layoutIfNeeded() + toggleAccountVisibility(hide: isAccountHidden) } func initQRCode(viewModel: AccountViewModel) { qrCodeImage.image = UIImage.generateQRCode(from: viewModel.accountId) + toggleAccountVisibility(hide: isAccountHidden) + } + + func toggleAccountVisibility(hide: Bool) { + if hide { + hideAccountButton.setImage(UIImage.init(systemName: "eye.slash.fill"), for: .normal) + accountIdLabel.removeBlur() + accountIdLabel.addBlur(2) + accountIdLabel.alpha = 0.7 + qrCodeImage.removeBlur() + qrCodeImage.addBlur(2) + qrCodeImage.alpha = 0.5 + } else { + hideAccountButton.setImage(UIImage.init(systemName: "eye.fill"), for: .normal) + accountIdLabel.removeBlur() + accountIdLabel.alpha = 1 + qrCodeImage.removeBlur() + qrCodeImage.alpha = 1 + } } } diff --git a/IVPNClient/Scenes/Base.lproj/Main.storyboard b/IVPNClient/Scenes/Base.lproj/Main.storyboard index d360ed775..24fdd99ef 100644 --- a/IVPNClient/Scenes/Base.lproj/Main.storyboard +++ b/IVPNClient/Scenes/Base.lproj/Main.storyboard @@ -1,9 +1,9 @@ - + - + @@ -3069,13 +3069,13 @@ - @@ -4501,6 +4514,8 @@ + + @@ -4510,7 +4525,6 @@ - @@ -4641,6 +4655,7 @@ + @@ -4894,6 +4909,7 @@ + diff --git a/IVPNClient/Scenes/MainScreen/AppIntentsHandler.swift b/IVPNClient/Scenes/MainScreen/AppIntentsHandler.swift new file mode 100644 index 000000000..be2e035ee --- /dev/null +++ b/IVPNClient/Scenes/MainScreen/AppIntentsHandler.swift @@ -0,0 +1,72 @@ +// +// AppIntentsHandler.swift +// IVPNClient +// +// Created by Juraj Hilje on 04.09.2024.. +// Copyright © 2024 IVPN. All rights reserved. +// + +import UIKit + +extension MainViewController { + + // MARK: - App Intents - + + @objc func intentConnect() { + Application.shared.connectionManager.resetRulesAndConnect() + } + + @objc func intentDisconnect() { + Application.shared.connectionManager.resetRulesAndDisconnect() + } + + @objc func intentAntiTrackerEnable() { + DispatchQueue.async { + if Application.shared.settings.connectionProtocol.tunnelType() == .ipsec { + self.showAlert(title: "IKEv2 not supported", message: "AntiTracker is supported only for OpenVPN and WireGuard protocols.") { _ in + } + return + } + + UserDefaults.shared.set(true, forKey: UserDefaults.Key.isAntiTracker) + NotificationCenter.default.post(name: Notification.Name.AntiTrackerUpdated, object: nil) + self.evaluateReconnect(sender: self.view) + } + } + + @objc func intentAntiTrackerDisable() { + DispatchQueue.async { + UserDefaults.shared.set(false, forKey: UserDefaults.Key.isAntiTracker) + NotificationCenter.default.post(name: Notification.Name.AntiTrackerUpdated, object: nil) + self.evaluateReconnect(sender: self.view) + } + } + + @objc func intentCustomDNSEnable() { + DispatchQueue.async { + if Application.shared.settings.connectionProtocol.tunnelType() == .ipsec { + self.showAlert(title: "IKEv2 not supported", message: "Custom DNS is supported only for OpenVPN and WireGuard protocols.") { _ in + } + return + } + + guard !UserDefaults.shared.customDNS.isEmpty else { + self.showAlert(title: "", message: "Please enter DNS server info") + return + } + + UserDefaults.shared.set(true, forKey: UserDefaults.Key.isCustomDNS) + NotificationCenter.default.post(name: Notification.Name.CustomDNSUpdated, object: nil) + self.evaluateReconnect(sender: self.view) + } + } + + @objc func intentCustomDNSDisable() { + DispatchQueue.async { + UserDefaults.shared.set(false, forKey: UserDefaults.Key.isCustomDNS) + NotificationCenter.default.post(name: Notification.Name.CustomDNSUpdated, object: nil) + self.evaluateReconnect(sender: self.view) + } + } + +} diff --git a/IVPNClient/Scenes/MainScreen/ControlPanel/ControlPanelViewController.swift b/IVPNClient/Scenes/MainScreen/ControlPanel/ControlPanelViewController.swift index 12ec8e37d..dbfb5043f 100644 --- a/IVPNClient/Scenes/MainScreen/ControlPanel/ControlPanelViewController.swift +++ b/IVPNClient/Scenes/MainScreen/ControlPanel/ControlPanelViewController.swift @@ -108,12 +108,6 @@ class ControlPanelViewController: UITableViewController { WidgetCenter.shared.reloadTimelines(ofKind: "IVPNWidget") evaluateReconnect(sender: sender as UIView) controlPanelView.updateAntiTracker(viewModel: vpnStatusViewModel) - - if sender.isOn { - registerUserActivity(type: UserActivityType.AntiTrackerEnable, title: UserActivityTitle.AntiTrackerEnable) - } else { - registerUserActivity(type: UserActivityType.AntiTrackerDisable, title: UserActivityTitle.AntiTrackerDisable) - } } @IBAction func selectIpProtocol(_ sender: UISegmentedControl) { @@ -223,8 +217,6 @@ class ControlPanelViewController: UITableViewController { manager.resetRulesAndConnect() } - registerUserActivity(type: UserActivityType.Connect, title: UserActivityTitle.Connect) - NotificationCenter.default.removeObserver(self, name: Notification.Name.ServiceAuthorized, object: nil) NotificationCenter.default.removeObserver(self, name: Notification.Name.SubscriptionActivated, object: nil) } @@ -240,8 +232,6 @@ class ControlPanelViewController: UITableViewController { manager.resetRulesAndDisconnect() } - registerUserActivity(type: UserActivityType.Disconnect, title: UserActivityTitle.Disconnect) - DispatchQueue.delay(0.5) { if Application.shared.connectionManager.status.isDisconnected() { Pinger.shared.ping() diff --git a/IVPNClient/Scenes/MainScreen/MainViewController.swift b/IVPNClient/Scenes/MainScreen/MainViewController.swift index efaa9804d..db4f524d9 100644 --- a/IVPNClient/Scenes/MainScreen/MainViewController.swift +++ b/IVPNClient/Scenes/MainScreen/MainViewController.swift @@ -167,6 +167,9 @@ class MainViewController: UIViewController { if !model.isIvpnServer { Application.shared.geoLookup = model } + + WidgetCenter.shared.reloadTimelines(ofKind: "IVPNWidget") + Application.shared.connectionManager.evaluateCloseApp() case .failure: controlPanel.controlPanelView.ipv4ViewModel = ProofsViewModel(displayMode: .error) mainView.infoAlertViewModel.infoAlert = .connectionInfoFailure @@ -180,6 +183,8 @@ class MainViewController: UIViewController { case .success(let model): controlPanel.controlPanelView.ipv6ViewModel = ProofsViewModel(model: model, displayMode: .content) mainView.ipv6ViewModel = ProofsViewModel(model: model) + WidgetCenter.shared.reloadTimelines(ofKind: "IVPNWidget") + Application.shared.connectionManager.evaluateCloseApp() case .failure: controlPanel.controlPanelView.ipv6ViewModel = ProofsViewModel(displayMode: .error) mainView.ipv6ViewModel = ProofsViewModel(displayMode: .error) @@ -198,6 +203,12 @@ class MainViewController: UIViewController { NotificationCenter.default.addObserver(self, selector: #selector(vpnConfigurationDisabled), name: Notification.Name.VPNConfigurationDisabled, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(subscriptionActivated), name: Notification.Name.SubscriptionActivated, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(updateGeoLocation), name: Notification.Name.UpdateGeoLocation, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(intentConnect), name: Notification.Name.IntentConnect, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(intentDisconnect), name: Notification.Name.IntentDisconnect, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(intentAntiTrackerEnable), name: Notification.Name.IntentAntiTrackerEnable, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(intentAntiTrackerDisable), name: Notification.Name.IntentAntiTrackerDisable, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(intentCustomDNSEnable), name: Notification.Name.IntentCustomDNSEnable, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(intentCustomDNSDisable), name: Notification.Name.IntentCustomDNSDisable, object: nil) } // MARK: - Private methods - diff --git a/IVPNClient/Scenes/MainScreen/Map/MapScrollView.swift b/IVPNClient/Scenes/MainScreen/Map/MapScrollView.swift index 24c190c54..c16a8cb0a 100644 --- a/IVPNClient/Scenes/MainScreen/Map/MapScrollView.swift +++ b/IVPNClient/Scenes/MainScreen/Map/MapScrollView.swift @@ -118,6 +118,9 @@ class MapScrollView: UIScrollView { func updateMapMarkers() { markerLocalView.updateView() markerGatewayView.updateView() + if let viewModel = viewModel { + updateMapPosition(viewModel: viewModel, animated: true) + } } func updateMapPosition(latitude: Double, longitude: Double, animated: Bool = false, isLocalPosition: Bool, updateMarkers: Bool = true) { @@ -136,7 +139,7 @@ class MapScrollView: UIScrollView { } if updateMarkers { - updateMarkerPosition(x: point.0 - 49, y: point.1 - 49, isLocalPosition: isLocalPosition) + updateMarkerPosition(x: point.0, y: point.1, isLocalPosition: isLocalPosition) } currentCoordinates = (latitude, longitude) @@ -249,7 +252,7 @@ class MapScrollView: UIScrollView { private func updateMarkerPosition(x: Double, y: Double, isLocalPosition: Bool) { if isLocalPosition { - markerLocalView.snp.updateConstraints { make in + markerLocalView.snp.remakeConstraints { make in make.left.equalTo(x) make.top.equalTo(y) } @@ -258,7 +261,7 @@ class MapScrollView: UIScrollView { self.layoutIfNeeded() } } else { - markerGatewayView.snp.updateConstraints { make in + markerGatewayView.snp.remakeConstraints { make in make.left.equalTo(x) make.top.equalTo(y) } diff --git a/IVPNClient/Scenes/Signup/LoginViewController.swift b/IVPNClient/Scenes/Signup/LoginViewController.swift index 5a77a0787..b52461e12 100644 --- a/IVPNClient/Scenes/Signup/LoginViewController.swift +++ b/IVPNClient/Scenes/Signup/LoginViewController.swift @@ -115,7 +115,7 @@ class LoginViewController: UIViewController { if let account = account { self.userName.text = account.accountId - self.sessionManager.createSession() + self.startLoginProcess() } } } diff --git a/IVPNClient/Scenes/ViewControllers/AntiTrackerViewController.swift b/IVPNClient/Scenes/ViewControllers/AntiTrackerViewController.swift index 4b4a518e5..3c35b036f 100644 --- a/IVPNClient/Scenes/ViewControllers/AntiTrackerViewController.swift +++ b/IVPNClient/Scenes/ViewControllers/AntiTrackerViewController.swift @@ -46,12 +46,6 @@ class AntiTrackerViewController: UITableViewController { antiTrackerHardcoreSwitch.isEnabled = sender.isOn evaluateReconnect(sender: sender as UIView) NotificationCenter.default.post(name: Notification.Name.UpdateControlPanel, object: nil) - - if sender.isOn { - registerUserActivity(type: UserActivityType.AntiTrackerEnable, title: UserActivityTitle.AntiTrackerEnable) - } else { - registerUserActivity(type: UserActivityType.AntiTrackerDisable, title: UserActivityTitle.AntiTrackerDisable) - } } @IBAction func toggleAntiTrackerHardcore(_ sender: UISwitch) { diff --git a/IVPNClient/Scenes/ViewControllers/CustomDNSViewController.swift b/IVPNClient/Scenes/ViewControllers/CustomDNSViewController.swift index bf86e317a..2fcbe5a3d 100644 --- a/IVPNClient/Scenes/ViewControllers/CustomDNSViewController.swift +++ b/IVPNClient/Scenes/ViewControllers/CustomDNSViewController.swift @@ -53,12 +53,6 @@ class CustomDNSViewController: UITableViewController { UserDefaults.shared.set(sender.isOn, forKey: UserDefaults.Key.isCustomDNS) evaluateReconnect(sender: sender) - - if sender.isOn { - registerUserActivity(type: UserActivityType.CustomDNSEnable, title: UserActivityTitle.CustomDNSEnable) - } else { - registerUserActivity(type: UserActivityType.CustomDNSDisable, title: UserActivityTitle.CustomDNSDisable) - } } @IBAction func enableSecureDNS(_ sender: UISwitch) { diff --git a/IVPNClient/Utilities/Extensions/NotificationName+Ext.swift b/IVPNClient/Utilities/Extensions/NotificationName+Ext.swift index dd63512ec..0d8565aa7 100644 --- a/IVPNClient/Utilities/Extensions/NotificationName+Ext.swift +++ b/IVPNClient/Utilities/Extensions/NotificationName+Ext.swift @@ -58,5 +58,11 @@ extension Notification.Name { public static let CustomDNSUpdated = Notification.Name("customDNSUpdatedUpdated") public static let EvaluateReconnect = Notification.Name("evaluateReconnect") public static let EvaluatePlanUpdate = Notification.Name("evaluatePlanUpdate") + public static let IntentConnect = Notification.Name("intentConnect") + public static let IntentDisconnect = Notification.Name("intentDisconnect") + public static let IntentAntiTrackerEnable = Notification.Name("intentAntiTrackerEnable") + public static let IntentAntiTrackerDisable = Notification.Name("intentAntiTrackerDisable") + public static let IntentCustomDNSEnable = Notification.Name("intentCustomDNSEnable") + public static let IntentCustomDNSDisable = Notification.Name("intentCustomDNSDisable") } diff --git a/IVPNClient/Utilities/Extensions/UIApplication+Ext.swift b/IVPNClient/Utilities/Extensions/UIApplication+Ext.swift index f78fff72f..398d3f0d1 100644 --- a/IVPNClient/Utilities/Extensions/UIApplication+Ext.swift +++ b/IVPNClient/Utilities/Extensions/UIApplication+Ext.swift @@ -27,7 +27,7 @@ extension UIApplication { var keyWindow: UIWindow? { return self.connectedScenes - .filter { $0.activationState == .foregroundActive } + .filter { $0.activationState == .foregroundActive || $0.activationState == .foregroundInactive } .first(where: { $0 is UIWindowScene }) .flatMap({ $0 as? UIWindowScene })?.windows .first(where: \.isKeyWindow) diff --git a/IVPNClient/Utilities/Extensions/UIView+Ext.swift b/IVPNClient/Utilities/Extensions/UIView+Ext.swift index b6f721a43..7df47390e 100644 --- a/IVPNClient/Utilities/Extensions/UIView+Ext.swift +++ b/IVPNClient/Utilities/Extensions/UIView+Ext.swift @@ -48,3 +48,65 @@ extension UIView { } } + +extension UIView { + + func addBlur(_ intensity: Double = 1.0) { + let blurEffectView = BlurEffectView() + blurEffectView.intensity = intensity + self.addSubview(blurEffectView) + } + + func removeBlur() { + for subview in self.subviews { + if subview is UIVisualEffectView { + subview.removeFromSuperview() + } + } + } + +} + +class BlurEffectView: UIVisualEffectView { + + var animator = UIViewPropertyAnimator(duration: 1, curve: .linear) + + var intensity = 1.0 + + override func layoutSubviews() { + super.layoutSubviews() + frame = superview?.bounds ?? CGRect.zero + setupBlur() + } + + override func didMoveToSuperview() { + guard superview != nil else { return } + backgroundColor = .clear + setupBlur() + } + + private func setupBlur() { + animator.stopAnimation(true) + effect = nil + + animator.addAnimations { [weak self] in + self?.effect = UIBlurEffect(style: .regular) + } + + if intensity > 0 && intensity <= 10 { + + let value = CGFloat(intensity)/10 + animator.fractionComplete = value + + } + else { + animator.fractionComplete = 0.05 + } + + } + + deinit { + animator.stopAnimation(true) + } + +} diff --git a/IVPNClient/Utilities/Extensions/UIViewController+Ext.swift b/IVPNClient/Utilities/Extensions/UIViewController+Ext.swift index 362af3e8c..9f1705d21 100644 --- a/IVPNClient/Utilities/Extensions/UIViewController+Ext.swift +++ b/IVPNClient/Utilities/Extensions/UIViewController+Ext.swift @@ -95,16 +95,6 @@ extension UIViewController { openWebPage("https://www.ivpn.net/privacy-mobile-app/") } - func registerUserActivity(type: String, title: String) { - let activity = NSUserActivity(activityType: type) - activity.title = title - activity.isEligibleForSearch = true - activity.isEligibleForPrediction = true - - userActivity = activity - userActivity?.becomeCurrent() - } - func hideKeyboardOnTap() { let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(UIViewController.dismissKeyboard)) tap.cancelsTouchesInView = false diff --git a/IVPNWidget/PrivacyInfo-IVPNWidget.xcprivacy b/IVPNWidget/PrivacyInfo-IVPNWidget.xcprivacy new file mode 100644 index 000000000..dd6881b47 --- /dev/null +++ b/IVPNWidget/PrivacyInfo-IVPNWidget.xcprivacy @@ -0,0 +1,17 @@ + + + + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryUserDefaults + NSPrivacyAccessedAPITypeReasons + + 1C8F.1 + + + + + diff --git a/README.md b/README.md index 2340547f5..2bffd6bbd 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,7 @@ Build `V2RayControl.xcframework`: To compile [liboqs](https://github.com/open-quantum-safe/liboqs), additional packages are required: -``` +```sh brew install cmake ninja openssl@1.1 wget doxygen graphviz astyle valgrind pip3 install pytest pytest-xdist pyyaml ``` @@ -194,4 +194,4 @@ See the [Authors](/AUTHORS) file for the list of contributors who participated i ## Acknowledgements -See the [Acknowledgements](/ACKNOWLEDGEMENTS.md) file for the list of third party libraries used in this project. \ No newline at end of file +See the [Acknowledgements](/ACKNOWLEDGEMENTS.md) file for the list of third party libraries used in this project. diff --git a/openvpn-tunnel-provider/PrivacyInfo-openvpn-tunnel-provider.xcprivacy b/openvpn-tunnel-provider/PrivacyInfo-openvpn-tunnel-provider.xcprivacy new file mode 100644 index 000000000..f016e521e --- /dev/null +++ b/openvpn-tunnel-provider/PrivacyInfo-openvpn-tunnel-provider.xcprivacy @@ -0,0 +1,17 @@ + + + + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryUserDefaults + NSPrivacyAccessedAPITypeReasons + + 1C8F.1 + + + + + \ No newline at end of file diff --git a/wireguard-tunnel-provider/PrivacyInfo-wireguard-tunnel-provider.xcprivacy b/wireguard-tunnel-provider/PrivacyInfo-wireguard-tunnel-provider.xcprivacy new file mode 100644 index 000000000..325a4f28e --- /dev/null +++ b/wireguard-tunnel-provider/PrivacyInfo-wireguard-tunnel-provider.xcprivacy @@ -0,0 +1,25 @@ + + + + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryFileTimestamp + NSPrivacyAccessedAPITypeReasons + + C617.1 + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryUserDefaults + NSPrivacyAccessedAPITypeReasons + + 1C8F.1 + + + + +