Lock network settings for builds >= 3000

This commit is contained in:
Davide De Rosa 2022-04-13 20:12:25 +02:00
parent 320513dd38
commit 2565b9f3d0
12 changed files with 78 additions and 14 deletions

View File

@ -126,7 +126,7 @@
<EnvironmentVariables> <EnvironmentVariables>
<EnvironmentVariable <EnvironmentVariable
key = "APP_TYPE" key = "APP_TYPE"
value = "2" value = "0"
isEnabled = "YES"> isEnabled = "YES">
</EnvironmentVariable> </EnvironmentVariable>
<EnvironmentVariable <EnvironmentVariable

View File

@ -114,7 +114,8 @@ class AppContext {
productManager = ProductManager(.init( productManager = ProductManager(.init(
appType: Constants.InApp.appType, appType: Constants.InApp.appType,
lastFullVersionBuild: Constants.InApp.lastFullVersionBuild lastFullVersionBuild: Constants.InApp.lastFullVersionBuild,
lastNetworkSettingsBuild: Constants.InApp.lastNetworkSettingsBuild
)) ))
intentsManager = IntentsManager() intentsManager = IntentsManager()
reviewer = Reviewer() reviewer = Reviewer()
@ -163,6 +164,15 @@ class AppContext {
return true return true
} }
// eligibility: ignore network settings if ineligible
private func isEligibleForNetworkSettings() -> Bool {
guard productManager.isEligible(forFeature: .networkSettings) else {
pp_log.warning("Ignore network settings, not eligible")
return false
}
return true
}
// eligibility: reset on-demand rules if no trusted networks // eligibility: reset on-demand rules if no trusted networks
private func isEligibleForOnDemandRules() -> Bool { private func isEligibleForOnDemandRules() -> Bool {
guard productManager.isEligible(forFeature: .trustedNetworks) else { guard productManager.isEligible(forFeature: .trustedNetworks) else {

View File

@ -75,6 +75,8 @@ extension Constants {
#else #else
static let lastFullVersionBuild: (Int, LocalProduct) = (0, .fullVersion_macOS) static let lastFullVersionBuild: (Int, LocalProduct) = (0, .fullVersion_macOS)
#endif #endif
static let lastNetworkSettingsBuild = 2999
private static var isBeta: Bool { private static var isBeta: Bool {
#if os(iOS) #if os(iOS)

View File

@ -68,6 +68,8 @@ struct LocalProduct: RawRepresentable, Equatable, Hashable {
// MARK: Features // MARK: Features
static let allProviders = LocalProduct(featureId: "all_providers") static let allProviders = LocalProduct(featureId: "all_providers")
static let networkSettings = LocalProduct(featureId: "network_settings")
static let trustedNetworks = LocalProduct(featureId: "trusted_networks") static let trustedNetworks = LocalProduct(featureId: "trusted_networks")
@ -81,6 +83,7 @@ struct LocalProduct: RawRepresentable, Equatable, Hashable {
static let allFeatures: [LocalProduct] = [ static let allFeatures: [LocalProduct] = [
.allProviders, .allProviders,
.networkSettings,
.trustedNetworks, .trustedNetworks,
.siriShortcuts, .siriShortcuts,
.fullVersion_iOS, .fullVersion_iOS,

View File

@ -49,12 +49,16 @@ class ProductManager: NSObject, ObservableObject {
let lastFullVersionBuild: (Int, LocalProduct) let lastFullVersionBuild: (Int, LocalProduct)
let lastNetworkSettingsBuild: Int
init( init(
appType: AppType, appType: AppType,
lastFullVersionBuild: (Int, LocalProduct) lastFullVersionBuild: (Int, LocalProduct),
lastNetworkSettingsBuild: Int
) { ) {
self.appType = appType self.appType = appType
self.lastFullVersionBuild = lastFullVersionBuild self.lastFullVersionBuild = lastFullVersionBuild
self.lastNetworkSettingsBuild = lastNetworkSettingsBuild
} }
} }
@ -193,6 +197,11 @@ class ProductManager: NSObject, ObservableObject {
} }
func isEligible(forFeature feature: LocalProduct) -> Bool { func isEligible(forFeature feature: LocalProduct) -> Bool {
if let purchasedAppBuild = purchasedAppBuild {
if feature == .networkSettings && purchasedAppBuild <= cfg.lastNetworkSettingsBuild {
return true
}
}
#if os(iOS) #if os(iOS)
return isFullVersion() || purchasedFeatures.contains(feature) return isFullVersion() || purchasedFeatures.contains(feature)
#else #else

View File

@ -34,6 +34,10 @@ extension ProfileView {
@Binding private var modalType: ModalType? @Binding private var modalType: ModalType?
private var isEligibleForNetworkSettings: Bool {
productManager.isEligible(forFeature: .networkSettings)
}
private var isEligibleForTrustedNetworks: Bool { private var isEligibleForTrustedNetworks: Bool {
productManager.isEligible(forFeature: .trustedNetworks) productManager.isEligible(forFeature: .trustedNetworks)
} }
@ -75,10 +79,20 @@ extension ProfileView {
Label(L10n.Account.title, systemImage: themeAccountImage) Label(L10n.Account.title, systemImage: themeAccountImage)
} }
} }
NavigationLink {
NetworkSettingsView(currentProfile: currentProfile) // eligibility: enter network settings or present paywall
} label: { if isEligibleForNetworkSettings {
Label(L10n.NetworkSettings.title, systemImage: themeNetworkSettingsImage) NavigationLink {
NetworkSettingsView(currentProfile: currentProfile)
} label: {
networkSettingsRow
}
} else {
Button {
modalType = .paywallNetworkSettings
} label: {
networkSettingsRow
}
} }
// eligibility: enter trusted networks or present paywall // eligibility: enter trusted networks or present paywall
@ -97,6 +111,10 @@ extension ProfileView {
} }
} }
} }
private var networkSettingsRow: some View {
Label(L10n.NetworkSettings.title, systemImage: themeNetworkSettingsImage)
}
private var onDemandRow: some View { private var onDemandRow: some View {
Label(L10n.OnDemand.title, systemImage: themeOnDemandImage) Label(L10n.OnDemand.title, systemImage: themeOnDemandImage)

View File

@ -31,6 +31,8 @@ struct ProfileView: View {
enum ModalType: Int, Identifiable { enum ModalType: Int, Identifiable {
case rename case rename
case paywallNetworkSettings
case paywallTrustedNetworks case paywallTrustedNetworks
var id: Int { var id: Int {
@ -123,6 +125,14 @@ struct ProfileView: View {
RenameView(currentProfile: profileManager.currentProfile) RenameView(currentProfile: profileManager.currentProfile)
}.themeGlobal() }.themeGlobal()
case .paywallNetworkSettings:
NavigationView {
PaywallView(
modalType: $modalType,
feature: .networkSettings
)
}.themeGlobal()
case .paywallTrustedNetworks: case .paywallTrustedNetworks:
NavigationView { NavigationView {
PaywallView( PaywallView(

View File

@ -41,10 +41,12 @@ extension Profile.OpenVPNSettings: VPNConfigurationProviding {
} }
// network settings // network settings
customBuilder.applyGateway(from: parameters.networkSettings.gateway) if parameters.withNetworkSettings {
customBuilder.applyDNS(from: parameters.networkSettings.dns) customBuilder.applyGateway(from: parameters.networkSettings.gateway)
customBuilder.applyProxy(from: parameters.networkSettings.proxy) customBuilder.applyDNS(from: parameters.networkSettings.dns)
customBuilder.applyMTU(from: parameters.networkSettings.mtu) customBuilder.applyProxy(from: parameters.networkSettings.proxy)
customBuilder.applyMTU(from: parameters.networkSettings.mtu)
}
let customConfiguration = customBuilder.build() let customConfiguration = customBuilder.build()

View File

@ -33,9 +33,11 @@ extension Profile.WireGuardSettings: VPNConfigurationProviding {
var customBuilder = configuration.builder() var customBuilder = configuration.builder()
// network settings // network settings
customBuilder.applyGateway(from: parameters.networkSettings.gateway) if parameters.withNetworkSettings {
customBuilder.applyDNS(from: parameters.networkSettings.dns) customBuilder.applyGateway(from: parameters.networkSettings.gateway)
customBuilder.applyMTU(from: parameters.networkSettings.mtu) customBuilder.applyDNS(from: parameters.networkSettings.dns)
customBuilder.applyMTU(from: parameters.networkSettings.mtu)
}
let customConfiguration = customBuilder.build() let customConfiguration = customBuilder.build()

View File

@ -54,6 +54,7 @@ extension VPNManager {
appGroup: profileManager.appGroup, appGroup: profileManager.appGroup,
preferences: appManager.preferences, preferences: appManager.preferences,
passwordReference: profileManager.passwordReference(forProfile: profile), passwordReference: profileManager.passwordReference(forProfile: profile),
withNetworkSettings: isNetworkSettingsSupported(),
withCustomRules: isOnDemandRulesSupported() withCustomRules: isOnDemandRulesSupported()
) )

View File

@ -41,6 +41,8 @@ public class VPNManager: ObservableObject, RateLimited {
private let strategy: VPNManagerStrategy private let strategy: VPNManagerStrategy
public var isNetworkSettingsSupported: () -> Bool
public var isOnDemandRulesSupported: () -> Bool public var isOnDemandRulesSupported: () -> Bool
// MARK: State // MARK: State
@ -72,6 +74,7 @@ public class VPNManager: ObservableObject, RateLimited {
self.profileManager = profileManager self.profileManager = profileManager
self.providerManager = providerManager self.providerManager = providerManager
self.strategy = strategy self.strategy = strategy
isNetworkSettingsSupported = { true }
isOnDemandRulesSupported = { true } isOnDemandRulesSupported = { true }
currentState = ObservableState() currentState = ObservableState()

View File

@ -47,6 +47,8 @@ struct VPNConfigurationParameters {
let passwordReference: Data? let passwordReference: Data?
let withNetworkSettings: Bool
let onDemandRules: [NEOnDemandRule] let onDemandRules: [NEOnDemandRule]
init( init(
@ -54,6 +56,7 @@ struct VPNConfigurationParameters {
appGroup: String, appGroup: String,
preferences: AppPreferences, preferences: AppPreferences,
passwordReference: Data?, passwordReference: Data?,
withNetworkSettings: Bool,
withCustomRules: Bool withCustomRules: Bool
) { ) {
title = profile.header.name title = profile.header.name
@ -62,6 +65,7 @@ struct VPNConfigurationParameters {
networkSettings = profile.networkSettings networkSettings = profile.networkSettings
username = !profile.account.username.isEmpty ? profile.account.username : nil username = !profile.account.username.isEmpty ? profile.account.username : nil
self.passwordReference = passwordReference self.passwordReference = passwordReference
self.withNetworkSettings = withNetworkSettings
onDemandRules = profile.onDemand.rules(withCustomRules: withCustomRules) onDemandRules = profile.onDemand.rules(withCustomRules: withCustomRules)
} }
} }