]> git.ipfire.org Git - thirdparty/wireguard-apple.git/commitdiff
providerConfiguration is now a WgQuickConfig
authorEric Kuck <eric@bluelinelabs.com>
Fri, 21 Dec 2018 21:16:09 +0000 (15:16 -0600)
committerEric Kuck <eric@bluelinelabs.com>
Fri, 21 Dec 2018 22:32:08 +0000 (16:32 -0600)
Signed-off-by: Eric Kuck <eric@bluelinelabs.com>
19 files changed:
WireGuard/Shared/LegacyConfigMigration.swift
WireGuard/Shared/Model/DNSServer.swift
WireGuard/Shared/Model/Endpoint.swift
WireGuard/Shared/Model/IPAddressRange.swift
WireGuard/Shared/Model/InterfaceConfiguration.swift
WireGuard/Shared/Model/PeerConfiguration.swift
WireGuard/Shared/Model/TunnelConfiguration.swift
WireGuard/Shared/NETunnelProviderProtocol+Extension.swift
WireGuard/Shared/String+ArrayConversion.swift [moved from WireGuard/WireGuard/UI/iOS/String+ArrayConversion.swift with 100% similarity]
WireGuard/Shared/TunnelConfiguration+WgQuickConfig.swift [moved from WireGuard/WireGuard/ConfigFile/WgQuickConfigFileParser.swift with 73% similarity]
WireGuard/WireGuard.xcodeproj/project.pbxproj
WireGuard/WireGuard/ConfigFile/WgQuickConfigFileWriter.swift [deleted file]
WireGuard/WireGuard/Tunnel/MockTunnels.swift
WireGuard/WireGuard/Tunnel/TunnelsManager.swift
WireGuard/WireGuard/UI/iOS/ViewController/QRScanViewController.swift
WireGuard/WireGuard/UI/iOS/ViewController/TunnelsListTableViewController.swift
WireGuard/WireGuard/ZipArchive/ZipExporter.swift
WireGuard/WireGuard/ZipArchive/ZipImporter.swift
WireGuard/WireGuardNetworkExtension/PacketTunnelProvider.swift

index bd22ca487a7b39ed9754c97b498ef192d4b6d7c4..e7588a28fd9dab7b04d8e24e952b14892d1ee14e 100644 (file)
@@ -186,11 +186,8 @@ extension NETunnelProviderProtocol {
     
     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 tunnelConfigData = try? JSONEncoder().encode(configuration.migrated) else { return }
-        guard let tunnelConfigDictionary = try? JSONSerialization.jsonObject(with: tunnelConfigData, options: .allowFragments) else { return }
-        
-        providerConfiguration = [Keys.wgQuickConfig.rawValue: tunnelConfigDictionary]
+        guard let configuration = try? JSONDecoder().decode(LegacyTunnelConfiguration.self, from: serializedTunnelConfiguration) else { return }        
+        providerConfiguration = [Keys.wgQuickConfig.rawValue: configuration.migrated.asWgQuickConfig()]
     }
     
 }
index 8703fbba06e0cc5cd6fc174bbd3d0ee650e99ac0..9078b598d4ca35eb093fbbafc5269ea855a38525 100644 (file)
@@ -12,30 +12,6 @@ struct DNSServer {
     }
 }
 
-extension DNSServer: Codable {
-    public func encode(to encoder: Encoder) throws {
-        var container = encoder.singleValueContainer()
-        try container.encode(stringRepresentation)
-    }
-    
-    public init(from decoder: Decoder) throws {
-        let values = try decoder.singleValueContainer()
-        let addressString = try values.decode(String.self)
-        
-        if let address = IPv4Address(addressString) {
-            self.address = address
-        } else if let address = IPv6Address(addressString) {
-            self.address = address
-        } else {
-            throw DecodingError.invalidData
-        }
-    }
-
-    enum DecodingError: Error {
-        case invalidData
-    }
-}
-
 extension DNSServer {
     var stringRepresentation: String {
         return "\(address)"
index 891c5642365ceedad7c03f6d472d8f99deeba1a2..b29a5a8d31d925a165f990102eb08aca965bb01e 100644 (file)
@@ -14,26 +14,6 @@ struct Endpoint {
     }
 }
 
-extension Endpoint: Codable {
-    init(from decoder: Decoder) throws {
-        let container = try decoder.singleValueContainer()
-        let endpointString = try container.decode(String.self)
-        guard let endpoint = Endpoint(from: endpointString) else {
-            throw DecodingError.invalidData
-        }
-        self = endpoint
-    }
-    
-    func encode(to encoder: Encoder) throws {
-        var container = encoder.singleValueContainer()
-        try container.encode(stringRepresentation)
-    }
-    
-    enum DecodingError: Error {
-        case invalidData
-    }
-}
-
 extension Endpoint {
     var stringRepresentation: String {
         switch host {
index da4cbd5eee39cab48856e2543f9a57c096950e30..28f3d005b6eb4be320893900e1f54ce2c3f8e5f2 100644 (file)
@@ -52,22 +52,3 @@ extension IPAddressRange {
         return (address, networkPrefixLength)
     }
 }
-
-extension IPAddressRange: Codable {
-    public func encode(to encoder: Encoder) throws {
-        var container = encoder.singleValueContainer()
-        try container.encode(stringRepresentation)
-    }
-    
-    public init(from decoder: Decoder) throws {
-        let values = try decoder.singleValueContainer()
-        let addressString = try values.decode(String.self)
-        guard let parsed = IPAddressRange.parseAddressString(addressString) else { throw DecodingError.invalidData }
-        address = parsed.0
-        networkPrefixLength = parsed.1
-    }
-    
-    enum DecodingError: Error {
-        case invalidData
-    }
-}
index dfcb1fc78ee110ad35f462265e475f6e1c17d1fb..9094d149b90f92be6020c9efe4f37ff21a7f1bc4 100644 (file)
@@ -4,56 +4,18 @@
 import Foundation
 
 struct InterfaceConfiguration {
-    var name: String
+    var name: String?
     var privateKey: Data
     var addresses = [IPAddressRange]()
     var listenPort: UInt16?
     var mtu: UInt16?
     var dns = [DNSServer]()
     
-    init(name: String, privateKey: Data) {
+    init(name: String?, privateKey: Data) {
         self.name = name
         self.privateKey = privateKey
-        if name.isEmpty {
-            fatalError("Empty name")
-        }
         if privateKey.count != TunnelConfiguration.keyLength {
             fatalError("Invalid private key")
         }
     }
 }
-
-extension InterfaceConfiguration: Codable {
-    enum CodingKeys: String, CodingKey {
-        case name = "Name"
-        case privateKey = "PrivateKey"
-        case addresses = "Address"
-        case listenPort = "ListenPort"
-        case mtu = "MTU"
-        case dns = "DNS"
-    }
-    
-    init(from decoder: Decoder) throws {
-        let values = try decoder.container(keyedBy: CodingKeys.self)
-        name = try values.decode(String.self, forKey: .name)
-        privateKey = try Data(base64Encoded: values.decode(String.self, forKey: .privateKey))!
-        addresses = try values.decode([IPAddressRange].self, forKey: .addresses)
-        listenPort = try? values.decode(UInt16.self, forKey: .listenPort)
-        mtu = try? values.decode(UInt16.self, forKey: .mtu)
-        dns = try values.decode([DNSServer].self, forKey: .dns)
-    }
-    
-    func encode(to encoder: Encoder) throws {
-        var container = encoder.container(keyedBy: CodingKeys.self)
-        try container.encode(name, forKey: .name)
-        try container.encode(privateKey.base64EncodedString(), forKey: .privateKey)
-        try container.encode(addresses, forKey: .addresses)
-        if let listenPort = listenPort {
-            try container.encode(listenPort, forKey: .listenPort)
-        }
-        if let mtu = mtu {
-            try container.encode(mtu, forKey: .mtu)
-        }
-        try container.encode(dns, forKey: .dns)
-    }
-}
index 0fad842a3407d9f0a38c59a9e2bc3bbc4d36d919..a113821d54405e037fb80967325c15402383bbd7 100644 (file)
@@ -25,42 +25,3 @@ struct PeerConfiguration {
         }
     }
 }
-
-extension PeerConfiguration: Codable {
-    enum CodingKeys: String, CodingKey {
-        case publicKey = "PublicKey"
-        case preSharedKey = "PreSharedKey"
-        case allowedIPs = "AllowedIPs"
-        case endpoint = "Endpoint"
-        case persistentKeepAlive = "PersistentKeepAlive"
-    }
-    
-    init(from decoder: Decoder) throws {
-        let values = try decoder.container(keyedBy: CodingKeys.self)
-        publicKey = try Data(base64Encoded: values.decode(String.self, forKey: .publicKey))!
-        if let base64PreSharedKey = try? values.decode(Data.self, forKey: .preSharedKey) {
-            preSharedKey = Data(base64Encoded: base64PreSharedKey)
-        } else {
-            preSharedKey = nil
-        }
-        allowedIPs = try values.decode([IPAddressRange].self, forKey: .allowedIPs)
-        endpoint = try? values.decode(Endpoint.self, forKey: .endpoint)
-        persistentKeepAlive = try? values.decode(UInt16.self, forKey: .persistentKeepAlive)
-    }
-    
-    func encode(to encoder: Encoder) throws {
-        var container = encoder.container(keyedBy: CodingKeys.self)
-        try container.encode(publicKey.base64EncodedString(), forKey: .publicKey)
-        if let preSharedKey = preSharedKey {
-            try container.encode(preSharedKey.base64EncodedString(), forKey: .preSharedKey)
-        }
-        
-        try container.encode(allowedIPs, forKey: .allowedIPs)
-        if let endpoint = endpoint {
-            try container.encode(endpoint, forKey: .endpoint)
-        }
-        if let persistentKeepAlive = persistentKeepAlive {
-            try container.encode(persistentKeepAlive, forKey: .persistentKeepAlive)
-        }
-    }
-}
index 87812cde7fd06f4735773ecadb59caa24967b6bb..2e394eed3b968791d986287a26a3fbbc820b0fa6 100644 (file)
@@ -20,23 +20,3 @@ final class TunnelConfiguration {
         }
     }
 }
-
-extension TunnelConfiguration: Codable {
-    enum CodingKeys: String, CodingKey {
-        case interface = "Interface"
-        case peers = "Peer"
-    }
-    
-    convenience init(from decoder: Decoder) throws {
-        let values = try decoder.container(keyedBy: CodingKeys.self)
-        let interface = try values.decode(InterfaceConfiguration.self, forKey: .interface)
-        let peers = try values.decode([PeerConfiguration].self, forKey: .peers)
-        self.init(interface: interface, peers: peers)
-    }
-    
-    func encode(to encoder: Encoder) throws {
-        var container = encoder.container(keyedBy: CodingKeys.self)
-        try container.encode(interface, forKey: .interface)
-        try container.encode(peers, forKey: .peers)
-    }
-}
index 6f4e3eb03cf1993b760ef2c176fd6419a42c3a4a..4f3e1224009ca5b8e6be7a7e5248035c57f4e676 100644 (file)
@@ -3,38 +3,21 @@
 
 import NetworkExtension
 
+private var tunnelNameKey: Void?
+
 extension NETunnelProviderProtocol {
     
     enum Keys: String {
-        case wgQuickConfig = "WgQuickConfigV1"
-    }
-    
-    var tunnelConfiguration: TunnelConfiguration? {
-        migrateConfigurationIfNeeded()
-
-        let tunnelConfigurationData: Data?
-        if let configurationDictionary = providerConfiguration?[Keys.wgQuickConfig.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!)
+        case wgQuickConfig = "WgQuickConfig"
     }
     
     convenience init?(tunnelConfiguration: TunnelConfiguration) {
-        assert(!tunnelConfiguration.interface.name.isEmpty)
-        
-        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 = [ Keys.wgQuickConfig.rawValue: tunnelConfigDictionary ]
-
+        providerConfiguration = [Keys.wgQuickConfig.rawValue: tunnelConfiguration.asWgQuickConfig()]
+        
         let endpoints = tunnelConfiguration.peers.compactMap { $0.endpoint }
         if endpoints.count == 1 {
             serverAddress = endpoints[0].stringRepresentation
@@ -43,13 +26,14 @@ extension NETunnelProviderProtocol {
         } else {
             serverAddress = "Multiple endpoints"
         }
+        
         username = tunnelConfiguration.interface.name
     }
-
-    func hasTunnelConfiguration(tunnelConfiguration otherTunnelConfiguration: TunnelConfiguration) -> Bool {
-        guard let serializedThisTunnelConfiguration = try? JSONEncoder().encode(tunnelConfiguration) else { return false }
-        guard let serializedOtherTunnelConfiguration = try? JSONEncoder().encode(otherTunnelConfiguration) else { return false }
-        return serializedThisTunnelConfiguration == serializedOtherTunnelConfiguration
+    
+    func tunnelConfiguration(name: String?) -> TunnelConfiguration? {
+        migrateConfigurationIfNeeded()
+        guard let serializedConfig = providerConfiguration?[Keys.wgQuickConfig.rawValue] as? String else { return nil }
+        return try? TunnelConfiguration(serializedConfig, name: name)
     }
     
 }
similarity index 73%
rename from WireGuard/WireGuard/ConfigFile/WgQuickConfigFileParser.swift
rename to WireGuard/Shared/TunnelConfiguration+WgQuickConfig.swift
index f4c52c290166acde528d81edf61e968c1a418e2c..91214261cb7557ab4d372f848bba85344508729d 100644 (file)
@@ -3,14 +3,14 @@
 
 import Foundation
 
-class WgQuickConfigFileParser {
-
+extension TunnelConfiguration {
+    
     enum ParserState {
         case inInterfaceSection
         case inPeerSection
         case notInASection
     }
-
+    
     enum ParseError: Error {
         case invalidLine(_ line: String.SubSequence)
         case noInterface
@@ -19,19 +19,17 @@ class WgQuickConfigFileParser {
         case multiplePeersWithSamePublicKey
         case invalidPeer
     }
-
+    
     //swiftlint:disable:next cyclomatic_complexity function_body_length
-    static func parse(_ text: String, name: String) throws -> TunnelConfiguration {
-        assert(!name.isEmpty)
-
+    convenience init(_ wgQuickConfig: String, name: String?) throws {
         var interfaceConfiguration: InterfaceConfiguration?
         var peerConfigurations = [PeerConfiguration]()
-
-        let lines = text.split(separator: "\n")
-
+        
+        let lines = wgQuickConfig.split(separator: "\n")
+        
         var parserState = ParserState.notInASection
         var attributes = [String: String]()
-
+        
         for (lineIndex, line) in lines.enumerated() {
             var trimmedLine: String
             if let commentRange = line.range(of: "#") {
@@ -39,12 +37,12 @@ class WgQuickConfigFileParser {
             } else {
                 trimmedLine = String(line)
             }
-
+            
             trimmedLine = trimmedLine.trimmingCharacters(in: .whitespaces)
-
+            
             guard !trimmedLine.isEmpty else { continue }
             let lowercasedLine = line.lowercased()
-
+            
             if let equalsIndex = line.firstIndex(of: "=") {
                 // Line contains an attribute
                 let key = line[..<equalsIndex].trimmingCharacters(in: .whitespaces).lowercased()
@@ -58,21 +56,21 @@ class WgQuickConfigFileParser {
             } else if lowercasedLine != "[interface]" && lowercasedLine != "[peer]" {
                 throw ParseError.invalidLine(line)
             }
-
+            
             let isLastLine = lineIndex == lines.count - 1
-
+            
             if isLastLine || lowercasedLine == "[interface]" || lowercasedLine == "[peer]" {
                 // Previous section has ended; process the attributes collected so far
                 if parserState == .inInterfaceSection {
-                    guard let interface = collate(interfaceAttributes: attributes, name: name) else { throw ParseError.invalidInterface }
+                    guard let interface = TunnelConfiguration.collate(interfaceAttributes: attributes, name: name) else { throw ParseError.invalidInterface }
                     guard interfaceConfiguration == nil else { throw ParseError.multipleInterfaces }
                     interfaceConfiguration = interface
                 } else if parserState == .inPeerSection {
-                    guard let peer = collate(peerAttributes: attributes) else { throw ParseError.invalidPeer }
+                    guard let peer = TunnelConfiguration.collate(peerAttributes: attributes) else { throw ParseError.invalidPeer }
                     peerConfigurations.append(peer)
                 }
             }
-
+            
             if lowercasedLine == "[interface]" {
                 parserState = .inInterfaceSection
                 attributes.removeAll()
@@ -81,23 +79,61 @@ class WgQuickConfigFileParser {
                 attributes.removeAll()
             }
         }
-
+        
         let peerPublicKeysArray = peerConfigurations.map { $0.publicKey }
         let peerPublicKeysSet = Set<Data>(peerPublicKeysArray)
         if peerPublicKeysArray.count != peerPublicKeysSet.count {
             throw ParseError.multiplePeersWithSamePublicKey
         }
-
+        
         if let interfaceConfiguration = interfaceConfiguration {
-            let tunnelConfiguration = TunnelConfiguration(interface: interfaceConfiguration, peers: peerConfigurations)
-            return tunnelConfiguration
+            self.init(interface: interfaceConfiguration, peers: peerConfigurations)
         } else {
             throw ParseError.noInterface
         }
     }
-
+    
+    func asWgQuickConfig() -> String {
+        var output = "[Interface]\n"
+        output.append("PrivateKey = \(interface.privateKey.base64EncodedString())\n")
+        if let listenPort = interface.listenPort {
+            output.append("ListenPort = \(listenPort)\n")
+        }
+        if !interface.addresses.isEmpty {
+            let addressString = interface.addresses.map { $0.stringRepresentation }.joined(separator: ", ")
+            output.append("Address = \(addressString)\n")
+        }
+        if !interface.dns.isEmpty {
+            let dnsString = interface.dns.map { $0.stringRepresentation }.joined(separator: ", ")
+            output.append("DNS = \(dnsString)\n")
+        }
+        if let mtu = interface.mtu {
+            output.append("MTU = \(mtu)\n")
+        }
+        
+        for peer in peers {
+            output.append("\n[Peer]\n")
+            output.append("PublicKey = \(peer.publicKey.base64EncodedString())\n")
+            if let preSharedKey = peer.preSharedKey {
+                output.append("PresharedKey = \(preSharedKey.base64EncodedString())\n")
+            }
+            if !peer.allowedIPs.isEmpty {
+                let allowedIPsString = peer.allowedIPs.map { $0.stringRepresentation }.joined(separator: ", ")
+                output.append("AllowedIPs = \(allowedIPsString)\n")
+            }
+            if let endpoint = peer.endpoint {
+                output.append("Endpoint = \(endpoint.stringRepresentation)\n")
+            }
+            if let persistentKeepAlive = peer.persistentKeepAlive {
+                output.append("PersistentKeepalive = \(persistentKeepAlive)\n")
+            }
+        }
+        
+        return output
+    }
+    
     //swiftlint:disable:next cyclomatic_complexity
-    private static func collate(interfaceAttributes attributes: [String: String], name: String) -> InterfaceConfiguration? {
+    private static func collate(interfaceAttributes attributes: [String: String], name: String?) -> InterfaceConfiguration? {
         // required wg fields
         guard let privateKeyString = attributes["privatekey"] else { return nil }
         guard let privateKey = Data(base64Encoded: privateKeyString), privateKey.count == TunnelConfiguration.keyLength else { return nil }
@@ -130,7 +166,7 @@ class WgQuickConfigFileParser {
         }
         return interface
     }
-
+    
     //swiftlint:disable:next cyclomatic_complexity
     private static func collate(peerAttributes attributes: [String: String]) -> PeerConfiguration? {
         // required wg fields
@@ -160,5 +196,5 @@ class WgQuickConfigFileParser {
         }
         return peer
     }
-
+    
 }
index 7574451cc57e7d2e113626c84e8d6196d3b627ef..cd04c0683c3efe4b173d8598173f8e982a49deaf 100644 (file)
@@ -20,6 +20,9 @@
                5F4541B221CBFAEE00994C13 /* String+ArrayConversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F4541B121CBFAEE00994C13 /* String+ArrayConversion.swift */; };
                5F9696AA21CD6AE6008063FE /* LegacyConfigMigration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F9696A921CD6AE6008063FE /* LegacyConfigMigration.swift */; };
                5F9696AB21CD6AE6008063FE /* LegacyConfigMigration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F9696A921CD6AE6008063FE /* LegacyConfigMigration.swift */; };
+               5F9696AE21CD6F72008063FE /* String+ArrayConversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F4541B121CBFAEE00994C13 /* String+ArrayConversion.swift */; };
+               5F9696B021CD7128008063FE /* TunnelConfiguration+WgQuickConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F9696AF21CD7128008063FE /* TunnelConfiguration+WgQuickConfig.swift */; };
+               5F9696B121CD7128008063FE /* TunnelConfiguration+WgQuickConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F9696AF21CD7128008063FE /* TunnelConfiguration+WgQuickConfig.swift */; };
                5FF7B96221CC95DE00A7DD74 /* InterfaceConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FF7B96121CC95DE00A7DD74 /* InterfaceConfiguration.swift */; };
                5FF7B96321CC95DE00A7DD74 /* InterfaceConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FF7B96121CC95DE00A7DD74 /* InterfaceConfiguration.swift */; };
                5FF7B96521CC95FA00A7DD74 /* PeerConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FF7B96421CC95FA00A7DD74 /* PeerConfiguration.swift */; };
@@ -35,7 +38,6 @@
                6F628C41217F47DB003482A3 /* TunnelDetailTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F628C40217F47DB003482A3 /* TunnelDetailTableViewController.swift */; };
                6F6899A62180447E0012E523 /* x25519.c in Sources */ = {isa = PBXBuildFile; fileRef = 6F6899A52180447E0012E523 /* x25519.c */; };
                6F6899A8218044FC0012E523 /* Curve25519.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F6899A7218044FC0012E523 /* Curve25519.swift */; };
-               6F6899AC218099F00012E523 /* WgQuickConfigFileParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F6899AB218099F00012E523 /* WgQuickConfigFileParser.swift */; };
                6F693A562179E556008551C1 /* Endpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F693A552179E556008551C1 /* Endpoint.swift */; };
                6F7774E1217181B1006A79B3 /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F7774DF217181B1006A79B3 /* MainViewController.swift */; };
                6F7774E2217181B1006A79B3 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F7774E0217181B1006A79B3 /* AppDelegate.swift */; };
@@ -58,7 +60,6 @@
                6FDEF80021863C0100D8FBF6 /* ioapi.c in Sources */ = {isa = PBXBuildFile; fileRef = 6FDEF7FF21863C0100D8FBF6 /* ioapi.c */; };
                6FDEF802218646BA00D8FBF6 /* ZipArchive.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FDEF801218646B900D8FBF6 /* ZipArchive.swift */; };
                6FDEF806218725D200D8FBF6 /* SettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FDEF805218725D200D8FBF6 /* SettingsTableViewController.swift */; };
-               6FDEF8082187442100D8FBF6 /* WgQuickConfigFileWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FDEF8072187442100D8FBF6 /* WgQuickConfigFileWriter.swift */; };
                6FE1765621C90BBE002690EA /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6FE1765421C90BBE002690EA /* Localizable.strings */; };
                6FE1765A21C90E87002690EA /* LocalizationHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FE1765921C90E87002690EA /* LocalizationHelper.swift */; };
                6FE254FB219C10800028284D /* ZipImporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FE254FA219C10800028284D /* ZipImporter.swift */; };
                5F4541AD21C7704300994C13 /* NEVPNStatus+CustomStringConvertible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NEVPNStatus+CustomStringConvertible.swift"; sourceTree = "<group>"; };
                5F4541B121CBFAEE00994C13 /* String+ArrayConversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+ArrayConversion.swift"; sourceTree = "<group>"; };
                5F9696A921CD6AE6008063FE /* LegacyConfigMigration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyConfigMigration.swift; sourceTree = "<group>"; };
+               5F9696AF21CD7128008063FE /* TunnelConfiguration+WgQuickConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TunnelConfiguration+WgQuickConfig.swift"; sourceTree = "<group>"; };
                5FF7B96121CC95DE00A7DD74 /* InterfaceConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InterfaceConfiguration.swift; sourceTree = "<group>"; };
                5FF7B96421CC95FA00A7DD74 /* PeerConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PeerConfiguration.swift; sourceTree = "<group>"; };
                6F5A2B4421AFDE020081EDD8 /* FileManager+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileManager+Extension.swift"; sourceTree = "<group>"; };
                6F6899A42180447E0012E523 /* x25519.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = x25519.h; sourceTree = "<group>"; };
                6F6899A52180447E0012E523 /* x25519.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = x25519.c; sourceTree = "<group>"; };
                6F6899A7218044FC0012E523 /* Curve25519.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Curve25519.swift; sourceTree = "<group>"; };
-               6F6899AB218099F00012E523 /* WgQuickConfigFileParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WgQuickConfigFileParser.swift; sourceTree = "<group>"; };
                6F693A552179E556008551C1 /* Endpoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Endpoint.swift; sourceTree = "<group>"; };
                6F7774DF217181B1006A79B3 /* MainViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = "<group>"; };
                6F7774E0217181B1006A79B3 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
                6FDEF7FF21863C0100D8FBF6 /* ioapi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ioapi.c; sourceTree = "<group>"; };
                6FDEF801218646B900D8FBF6 /* ZipArchive.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ZipArchive.swift; sourceTree = "<group>"; };
                6FDEF805218725D200D8FBF6 /* SettingsTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsTableViewController.swift; sourceTree = "<group>"; };
-               6FDEF8072187442100D8FBF6 /* WgQuickConfigFileWriter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WgQuickConfigFileWriter.swift; sourceTree = "<group>"; };
                6FE1765521C90BBE002690EA /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = WireGuard/Base.lproj/Localizable.strings; sourceTree = "<group>"; };
                6FE1765921C90E87002690EA /* LocalizationHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizationHelper.swift; sourceTree = "<group>"; };
                6FE254FA219C10800028284D /* ZipImporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZipImporter.swift; sourceTree = "<group>"; };
                                6FFA5D942194454A0001E2F7 /* NETunnelProviderProtocol+Extension.swift */,
                                6F5A2B4421AFDE020081EDD8 /* FileManager+Extension.swift */,
                                5F9696A921CD6AE6008063FE /* LegacyConfigMigration.swift */,
+                               5F4541B121CBFAEE00994C13 /* String+ArrayConversion.swift */,
+                               5F9696AF21CD7128008063FE /* TunnelConfiguration+WgQuickConfig.swift */,
                        );
                        path = Shared;
                        sourceTree = "<group>";
                        path = Crypto;
                        sourceTree = "<group>";
                };
-               6F6899AA218099D00012E523 /* ConfigFile */ = {
-                       isa = PBXGroup;
-                       children = (
-                               6F6899AB218099F00012E523 /* WgQuickConfigFileParser.swift */,
-                               6FDEF8072187442100D8FBF6 /* WgQuickConfigFileWriter.swift */,
-                       );
-                       path = ConfigFile;
-                       sourceTree = "<group>";
-               };
                6F7774DD217181B1006A79B3 /* UI */ = {
                        isa = PBXGroup;
                        children = (
                                6F7774E0217181B1006A79B3 /* AppDelegate.swift */,
                                6F919EC2218A2AE90023B400 /* ErrorPresenter.swift */,
                                5F45417C21C1B23600994C13 /* UITableViewCell+Reuse.swift */,
-                               5F4541B121CBFAEE00994C13 /* String+ArrayConversion.swift */,
                        );
                        path = iOS;
                        sourceTree = "<group>";
                        children = (
                                6F919ED3218C65C50023B400 /* Resources */,
                                6F6899A32180445A0012E523 /* Crypto */,
-                               6F6899AA218099D00012E523 /* ConfigFile */,
                                6F7774DD217181B1006A79B3 /* UI */,
                                6F7774ED21722D0C006A79B3 /* Tunnel */,
                                6FDEF7E72186320E00D8FBF6 /* ZipArchive */,
                                6FF3527121C240160008484E /* Logger.swift in Sources */,
                                6F5A2B4621AFDED40081EDD8 /* FileManager+Extension.swift in Sources */,
                                6FFA5DA021958ECC0001E2F7 /* ErrorNotifier.swift in Sources */,
+                               5F9696B121CD7128008063FE /* TunnelConfiguration+WgQuickConfig.swift in Sources */,
                                6FFA5D96219446380001E2F7 /* NETunnelProviderProtocol+Extension.swift in Sources */,
                                6FFA5D8E2194370D0001E2F7 /* TunnelConfiguration.swift in Sources */,
                                5FF7B96621CC95FA00A7DD74 /* PeerConfiguration.swift in Sources */,
+                               5F9696AE21CD6F72008063FE /* String+ArrayConversion.swift in Sources */,
                                6FFA5D8F2194370D0001E2F7 /* IPAddressRange.swift in Sources */,
                                6FFA5D902194370D0001E2F7 /* Endpoint.swift in Sources */,
                                5FF7B96321CC95DE00A7DD74 /* InterfaceConfiguration.swift in Sources */,
                                6FE1765A21C90E87002690EA /* LocalizationHelper.swift in Sources */,
                                6FF3527221C2616C0008484E /* ringlogger.c in Sources */,
                                6FF3527321C2616C0008484E /* Logger.swift in Sources */,
-                               6F6899AC218099F00012E523 /* WgQuickConfigFileParser.swift in Sources */,
                                6F7774E421718281006A79B3 /* TunnelsListTableViewController.swift in Sources */,
                                6F7774EF21722D97006A79B3 /* TunnelsManager.swift in Sources */,
                                5F45417D21C1B23600994C13 /* UITableViewCell+Reuse.swift in Sources */,
                                5F9696AA21CD6AE6008063FE /* LegacyConfigMigration.swift in Sources */,
                                6F5A2B4821AFF49A0081EDD8 /* FileManager+Extension.swift in Sources */,
                                5F45418C21C2D48200994C13 /* TunnelEditKeyValueCell.swift in Sources */,
-                               6FDEF8082187442100D8FBF6 /* WgQuickConfigFileWriter.swift in Sources */,
                                6FE254FB219C10800028284D /* ZipImporter.swift in Sources */,
                                6F7774EA217229DB006A79B3 /* IPAddressRange.swift in Sources */,
                                5F4541AE21C7704300994C13 /* NEVPNStatus+CustomStringConvertible.swift in Sources */,
                                6FDEF7FB21863B6100D8FBF6 /* unzip.c in Sources */,
                                6F6899A8218044FC0012E523 /* Curve25519.swift in Sources */,
                                5F4541A021C2D6B700994C13 /* TunnelListCell.swift in Sources */,
+                               5F9696B021CD7128008063FE /* TunnelConfiguration+WgQuickConfig.swift in Sources */,
                                6F628C41217F47DB003482A3 /* TunnelDetailTableViewController.swift in Sources */,
                                6F61F1EB21B937EF00483816 /* WireGuardResult.swift in Sources */,
                                6F7774F321774263006A79B3 /* TunnelEditTableViewController.swift in Sources */,
diff --git a/WireGuard/WireGuard/ConfigFile/WgQuickConfigFileWriter.swift b/WireGuard/WireGuard/ConfigFile/WgQuickConfigFileWriter.swift
deleted file mode 100644 (file)
index 2dab266..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-// SPDX-License-Identifier: MIT
-// Copyright © 2018 WireGuard LLC. All Rights Reserved.
-
-import UIKit
-
-class WgQuickConfigFileWriter {
-    static func writeConfigFile(from configuration: TunnelConfiguration) -> Data? {
-        let interface = configuration.interface
-        var output = "[Interface]\n"
-        output.append("PrivateKey = \(interface.privateKey.base64EncodedString())\n")
-        if let listenPort = interface.listenPort {
-            output.append("ListenPort = \(listenPort)\n")
-        }
-        if !interface.addresses.isEmpty {
-            let addressString = interface.addresses.map { $0.stringRepresentation }.joined(separator: ", ")
-            output.append("Address = \(addressString)\n")
-        }
-        if !interface.dns.isEmpty {
-            let dnsString = interface.dns.map { $0.stringRepresentation }.joined(separator: ", ")
-            output.append("DNS = \(dnsString)\n")
-        }
-        if let mtu = interface.mtu {
-            output.append("MTU = \(mtu)\n")
-        }
-
-        for peer in configuration.peers {
-            output.append("\n[Peer]\n")
-            output.append("PublicKey = \(peer.publicKey.base64EncodedString())\n")
-            if let preSharedKey = peer.preSharedKey {
-                output.append("PresharedKey = \(preSharedKey.base64EncodedString())\n")
-            }
-            if !peer.allowedIPs.isEmpty {
-                let allowedIPsString = peer.allowedIPs.map { $0.stringRepresentation }.joined(separator: ", ")
-                output.append("AllowedIPs = \(allowedIPsString)\n")
-            }
-            if let endpoint = peer.endpoint {
-                output.append("Endpoint = \(endpoint.stringRepresentation)\n")
-            }
-            if let persistentKeepAlive = peer.persistentKeepAlive {
-                output.append("PersistentKeepalive = \(persistentKeepAlive)\n")
-            }
-        }
-
-        return output.data(using: .utf8)
-    }
-}
index 764d860739f906d43c2f94dd58d4c84e2545dc93..e61825704f1fc683fe4ffa2a041398c6137af2da 100644 (file)
@@ -38,7 +38,7 @@ class MockTunnels {
 
             let tunnelProviderManager = NETunnelProviderManager()
             tunnelProviderManager.protocolConfiguration = NETunnelProviderProtocol(tunnelConfiguration: tunnelConfiguration)
-            tunnelProviderManager.localizedDescription = tunnelName
+            tunnelProviderManager.localizedDescription = (tunnelConfiguration).interface.name
             tunnelProviderManager.isEnabled = true
 
             return tunnelProviderManager
index 51f0d37c7b30f94d7f850a4d997dbc7e39fda804..903dfadcddc565ce538b91c64ed53f281f6de6ac 100644 (file)
@@ -43,9 +43,9 @@ class TunnelsManager {
             }
             
             let tunnelManagers = managers ?? []
-            tunnelManagers.forEach {
-                if ($0.protocolConfiguration as? NETunnelProviderProtocol)?.migrateConfigurationIfNeeded() == true {
-                    $0.saveToPreferences { _ in }
+            tunnelManagers.forEach { tunnelManager in
+                if (tunnelManager.protocolConfiguration as? NETunnelProviderProtocol)?.migrateConfigurationIfNeeded() == true {
+                    tunnelManager.saveToPreferences { _ in }
                 }
             }
             completionHandler(.success(TunnelsManager(tunnelProviders: tunnelManagers)))
@@ -54,7 +54,7 @@ class TunnelsManager {
     }
 
     func add(tunnelConfiguration: TunnelConfiguration, activateOnDemandSetting: ActivateOnDemandSetting = ActivateOnDemandSetting.defaultSetting, completionHandler: @escaping (WireGuardResult<TunnelContainer>) -> Void) {
-        let tunnelName = tunnelConfiguration.interface.name
+        let tunnelName = tunnelConfiguration.interface.name ?? ""
         if tunnelName.isEmpty {
             completionHandler(.failure(TunnelsManagerError.tunnelNameEmpty))
             return
@@ -67,7 +67,7 @@ class TunnelsManager {
 
         let tunnelProviderManager = NETunnelProviderManager()
         tunnelProviderManager.protocolConfiguration = NETunnelProviderProtocol(tunnelConfiguration: tunnelConfiguration)
-        tunnelProviderManager.localizedDescription = tunnelName
+        tunnelProviderManager.localizedDescription = (tunnelConfiguration).interface.name
         tunnelProviderManager.isEnabled = true
 
         activateOnDemandSetting.apply(on: tunnelProviderManager)
@@ -107,7 +107,7 @@ class TunnelsManager {
     }
 
     func modify(tunnel: TunnelContainer, tunnelConfiguration: TunnelConfiguration, activateOnDemandSetting: ActivateOnDemandSetting, completionHandler: @escaping (TunnelsManagerError?) -> Void) {
-        let tunnelName = tunnelConfiguration.interface.name
+        let tunnelName = tunnelConfiguration.interface.name ?? ""
         if tunnelName.isEmpty {
             completionHandler(TunnelsManagerError.tunnelNameEmpty)
             return
@@ -123,12 +123,10 @@ class TunnelsManager {
             tunnel.name = tunnelName
         }
 
-        let shouldRestartIfActive = !((tunnelProviderManager.protocolConfiguration as? NETunnelProviderProtocol)?.hasTunnelConfiguration(tunnelConfiguration: tunnelConfiguration) ?? false)
-
         tunnelProviderManager.protocolConfiguration = NETunnelProviderProtocol(tunnelConfiguration: tunnelConfiguration)
-        tunnelProviderManager.localizedDescription = tunnelName
+        tunnelProviderManager.localizedDescription = (tunnelConfiguration).interface.name
         tunnelProviderManager.isEnabled = true
-
+        
         let isActivatingOnDemand = !tunnelProviderManager.isOnDemandEnabled && activateOnDemandSetting.isActivateOnDemandEnabled
         activateOnDemandSetting.apply(on: tunnelProviderManager)
 
@@ -148,12 +146,10 @@ class TunnelsManager {
             }
             self.tunnelsListDelegate?.tunnelModified(at: self.tunnels.firstIndex(of: tunnel)!)
 
-            if shouldRestartIfActive {
-                if tunnel.status == .active || tunnel.status == .activating || tunnel.status == .reasserting {
-                    // Turn off the tunnel, and then turn it back on, so the changes are made effective
-                    tunnel.status = .restarting
-                    (tunnel.tunnelProvider.connection as? NETunnelProviderSession)?.stopTunnel()
-                }
+            if tunnel.status == .active || tunnel.status == .activating || tunnel.status == .reasserting {
+                // Turn off the tunnel, and then turn it back on, so the changes are made effective
+                tunnel.status = .restarting
+                (tunnel.tunnelProvider.connection as? NETunnelProviderSession)?.stopTunnel()
             }
 
             if isActivatingOnDemand {
@@ -353,7 +349,7 @@ class TunnelContainer: NSObject {
     private var lastTunnelConnectionStatus: NEVPNStatus?
 
     var tunnelConfiguration: TunnelConfiguration? {
-        return (tunnelProvider.protocolConfiguration as? NETunnelProviderProtocol)?.tunnelConfiguration
+        return (tunnelProvider.protocolConfiguration as? NETunnelProviderProtocol)?.tunnelConfiguration(name: tunnelProvider.localizedDescription)
     }
     
     var activateOnDemandSetting: ActivateOnDemandSetting {
index 1fd6905bcdf97bfd39fa1cd8e20f538191018669..a4f71303747202c7d2559e6e51e92c70c65b849d 100644 (file)
@@ -101,7 +101,7 @@ class QRScanViewController: UIViewController {
     }
 
     func scanDidComplete(withCode code: String) {
-        let scannedTunnelConfiguration = try? WgQuickConfigFileParser.parse(code, name: "Scanned")
+        let scannedTunnelConfiguration = try? TunnelConfiguration(code, name: "Scanned")
         guard let tunnelConfiguration = scannedTunnelConfiguration else {
             scanDidEncounterError(title: tr("alertScanQRCodeInvalidQRCodeTitle"), message: tr("alertScanQRCodeInvalidQRCodeMessage"))
             return
index fff976f949939fe189f0c6dd9ae91e585a730c36..6dd8e9c2749508b9b861d3fefc8ebdff3c6d7ef7 100644 (file)
@@ -180,7 +180,7 @@ class TunnelsListTableViewController: UIViewController {
         } else /* if (url.pathExtension == "conf") -- we assume everything else is a conf */ {
             let fileBaseName = url.deletingPathExtension().lastPathComponent.trimmingCharacters(in: .whitespacesAndNewlines)
             if let fileContents = try? String(contentsOf: url),
-                let tunnelConfiguration = try? WgQuickConfigFileParser.parse(fileContents, name: fileBaseName) {
+                let tunnelConfiguration = try? TunnelConfiguration(fileContents, name: fileBaseName) {
                 tunnelsManager.add(tunnelConfiguration: tunnelConfiguration) { [weak self] result in
                     if let error = result.error {
                         ErrorPresenter.showErrorAlert(error: error, from: self, onPresented: completionHandler)
index 33d62fd94005e041a2f51662b41f49e2f18b3ede..052242ad9ca2551c61db76b11647e19bc984360e 100644 (file)
@@ -22,8 +22,8 @@ class ZipExporter {
             var inputsToArchiver: [(fileName: String, contents: Data)] = []
             var lastTunnelName: String = ""
             for tunnelConfiguration in tunnelConfigurations {
-                if let contents = WgQuickConfigFileWriter.writeConfigFile(from: tunnelConfiguration) {
-                    let name = tunnelConfiguration.interface.name
+                if let contents = tunnelConfiguration.asWgQuickConfig().data(using: .utf8) {
+                    let name = tunnelConfiguration.interface.name ?? ""
                     if name.isEmpty || name == lastTunnelName { continue }
                     inputsToArchiver.append((fileName: "\(name).conf", contents: contents))
                     lastTunnelName = name
index 0178ca0746c258159d0d6a1469c197a6a4cc80d2..a8819e27df1c105fe5df3e9b3c38b6c7670c7610 100644 (file)
@@ -43,12 +43,8 @@ class ZipImporter {
                 if index > 0 && file == unarchivedFiles[index - 1] {
                     continue
                 }
-                guard let fileContents = String(data: file.contents, encoding: .utf8) else {
-                    continue
-                }
-                guard let tunnelConfig = try? WgQuickConfigFileParser.parse(fileContents, name: file.fileBaseName) else {
-                    continue
-                }
+                guard let fileContents = String(data: file.contents, encoding: .utf8) else { continue }
+                guard let tunnelConfig = try? TunnelConfiguration(fileContents, name: file.fileBaseName) else { continue }
                 configs[index] = tunnelConfig
             }
             DispatchQueue.main.async { completion(.success(configs)) }
index 5e994c0c82b4adb50b432ea5750a7e74e95acb8a..b2df44041bcd71c1556023fac281325a3428ef6d 100644 (file)
@@ -29,7 +29,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
         let errorNotifier = ErrorNotifier(activationAttemptId: activationAttemptId, tunnelProvider: self)
 
         guard let tunnelProviderProtocol = protocolConfiguration as? NETunnelProviderProtocol,
-            let tunnelConfiguration = tunnelProviderProtocol.tunnelConfiguration else {
+            let tunnelConfiguration = tunnelProviderProtocol.tunnelConfiguration(name: nil) else {
                 errorNotifier.notify(PacketTunnelProviderError.savedProtocolConfigurationIsInvalid)
                 startTunnelCompletionHandler(PacketTunnelProviderError.savedProtocolConfigurationIsInvalid)
                 return
@@ -132,7 +132,6 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
         if err == -EADDRINUSE && listenPort != nil {
             let endpointString = packetTunnelSettingsGenerator.endpointUapiConfiguration(currentListenPort: 0)
             _ = endpointString.withGoString { return wgSetConfig(handle, $0) }
-
         }
     }
 }