From 8553723e04c4d63b99e669df2e43fc4a914b7f9d Mon Sep 17 00:00:00 2001 From: Eric Kuck Date: Thu, 20 Dec 2018 22:52:45 -0600 Subject: Updated NETunnelProvider save format Signed-off-by: Eric Kuck --- .../NETunnelProviderProtocol+Extension.swift | 87 +++++++++++++++++----- 1 file changed, 70 insertions(+), 17 deletions(-) (limited to 'WireGuard/Shared/NETunnelProviderProtocol+Extension.swift') diff --git a/WireGuard/Shared/NETunnelProviderProtocol+Extension.swift b/WireGuard/Shared/NETunnelProviderProtocol+Extension.swift index 776e03b..e5cfac8 100644 --- a/WireGuard/Shared/NETunnelProviderProtocol+Extension.swift +++ b/WireGuard/Shared/NETunnelProviderProtocol+Extension.swift @@ -3,24 +3,53 @@ import NetworkExtension +let tunnelConfigurationVersion = 2 + extension NETunnelProviderProtocol { + + enum Keys: String { + case tunnelConfiguration = "TunnelConfiguration" + case tunnelConfigurationVersion = "TunnelConfigurationVersion" + case isActivateOnDemandEnabled = "IsActivateOnDemandEnabled" + } + + var tunnelConfiguration: TunnelConfiguration? { + migrateConfigurationIfNeeded() + + let tunnelConfigurationData: Data? + if let configurationDictionary = providerConfiguration?[Keys.tunnelConfiguration.rawValue] { + tunnelConfigurationData = try? JSONSerialization.data(withJSONObject: configurationDictionary, options: []) + } else { + tunnelConfigurationData = nil + } + + guard tunnelConfigurationData != nil else { return nil } + return try? JSONDecoder().decode(TunnelConfiguration.self, from: tunnelConfigurationData!) + } + + var isActivateOnDemandEnabled: Bool { + return providerConfiguration?[Keys.isActivateOnDemandEnabled.rawValue] as? Bool ?? false + } + convenience init?(tunnelConfiguration: TunnelConfiguration, isActivateOnDemandEnabled: Bool) { assert(!tunnelConfiguration.interface.name.isEmpty) - guard let serializedTunnelConfiguration = try? JSONEncoder().encode(tunnelConfiguration) else { return nil } - + + guard let tunnelConfigData = try? JSONEncoder().encode(tunnelConfiguration) else { return nil } + guard let tunnelConfigDictionary = try? JSONSerialization.jsonObject(with: tunnelConfigData, options: .allowFragments) else { return nil } + self.init() let appId = Bundle.main.bundleIdentifier! providerBundleIdentifier = "\(appId).network-extension" providerConfiguration = [ - "tunnelConfiguration": serializedTunnelConfiguration, - "tunnelConfigurationVersion": 1, - "isActivateOnDemandEnabled": isActivateOnDemandEnabled + Keys.tunnelConfiguration.rawValue: tunnelConfigDictionary, + Keys.tunnelConfigurationVersion.rawValue: tunnelConfigurationVersion, + Keys.isActivateOnDemandEnabled.rawValue: isActivateOnDemandEnabled ] - let endpoints = tunnelConfiguration.peers.compactMap {$0.endpoint} + let endpoints = tunnelConfiguration.peers.compactMap { $0.endpoint } if endpoints.count == 1 { - serverAddress = endpoints.first!.stringRepresentation() + serverAddress = endpoints[0].stringRepresentation } else if endpoints.isEmpty { serverAddress = "Unspecified" } else { @@ -29,18 +58,42 @@ extension NETunnelProviderProtocol { username = tunnelConfiguration.interface.name } - func tunnelConfiguration() -> TunnelConfiguration? { - guard let serializedTunnelConfiguration = providerConfiguration?["tunnelConfiguration"] as? Data else { return nil } - return try? JSONDecoder().decode(TunnelConfiguration.self, from: serializedTunnelConfiguration) - } - - var isActivateOnDemandEnabled: Bool { - return (providerConfiguration?["isActivateOnDemandEnabled"] as? Bool) ?? false - } - func hasTunnelConfiguration(tunnelConfiguration otherTunnelConfiguration: TunnelConfiguration) -> Bool { - guard let serializedThisTunnelConfiguration = providerConfiguration?["tunnelConfiguration"] as? Data else { return false } + guard let serializedThisTunnelConfiguration = try? JSONEncoder().encode(tunnelConfiguration) else { return false } guard let serializedOtherTunnelConfiguration = try? JSONEncoder().encode(otherTunnelConfiguration) else { return false } return serializedThisTunnelConfiguration == serializedOtherTunnelConfiguration } + + @discardableResult + func migrateConfigurationIfNeeded() -> Bool { + guard let providerConfiguration = providerConfiguration else { return false } + guard let configurationVersion = providerConfiguration[Keys.tunnelConfigurationVersion.rawValue] as? Int ?? providerConfiguration["tunnelConfigurationVersion"] as? Int else { return false } + + if configurationVersion < tunnelConfigurationVersion { + switch configurationVersion { + case 1: + migrateFromConfigurationV1() + default: + fatalError("No migration from configuration version \(configurationVersion) exists.") + } + return true + } + + return false + } + + private func migrateFromConfigurationV1() { + guard let serializedTunnelConfiguration = providerConfiguration?["tunnelConfiguration"] as? Data else { return } + guard let configuration = try? JSONDecoder().decode(LegacyTunnelConfiguration.self, from: serializedTunnelConfiguration) else { return } + guard let isActivateOnDemandEnabled = providerConfiguration?["isActivateOnDemandEnabled"] as? Bool else { return } + guard let tunnelConfigData = try? JSONEncoder().encode(configuration.migrated) else { return } + guard let tunnelConfigDictionary = try? JSONSerialization.jsonObject(with: tunnelConfigData, options: .allowFragments) else { return } + + providerConfiguration = [ + Keys.tunnelConfiguration.rawValue: tunnelConfigDictionary, + Keys.tunnelConfigurationVersion.rawValue: tunnelConfigurationVersion, + Keys.isActivateOnDemandEnabled.rawValue: isActivateOnDemandEnabled + ] + } + } -- cgit v1.2.3-59-g8ed1b