From aede9f6e450d25a0a9cbeeea604e08ba76246869 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Sat, 22 Dec 2018 01:36:33 +0100 Subject: Move model helpers to model directory Signed-off-by: Jason A. Donenfeld --- WireGuard/Shared/LegacyConfigMigration.swift | 193 -------------------- WireGuard/Shared/Model/LegacyConfigMigration.swift | 193 ++++++++++++++++++++ .../Model/NETunnelProviderProtocol+Extension.swift | 38 ++++ .../Shared/Model/String+ArrayConversion.swift | 32 ++++ .../Model/TunnelConfiguration+WgQuickConfig.swift | 200 +++++++++++++++++++++ .../NETunnelProviderProtocol+Extension.swift | 40 ----- WireGuard/Shared/String+ArrayConversion.swift | 32 ---- .../Shared/TunnelConfiguration+WgQuickConfig.swift | 200 --------------------- WireGuard/WireGuard.xcodeproj/project.pbxproj | 8 +- 9 files changed, 467 insertions(+), 469 deletions(-) delete mode 100644 WireGuard/Shared/LegacyConfigMigration.swift create mode 100644 WireGuard/Shared/Model/LegacyConfigMigration.swift create mode 100644 WireGuard/Shared/Model/NETunnelProviderProtocol+Extension.swift create mode 100644 WireGuard/Shared/Model/String+ArrayConversion.swift create mode 100644 WireGuard/Shared/Model/TunnelConfiguration+WgQuickConfig.swift delete mode 100644 WireGuard/Shared/NETunnelProviderProtocol+Extension.swift delete mode 100644 WireGuard/Shared/String+ArrayConversion.swift delete mode 100644 WireGuard/Shared/TunnelConfiguration+WgQuickConfig.swift (limited to 'WireGuard') diff --git a/WireGuard/Shared/LegacyConfigMigration.swift b/WireGuard/Shared/LegacyConfigMigration.swift deleted file mode 100644 index b67301f..0000000 --- a/WireGuard/Shared/LegacyConfigMigration.swift +++ /dev/null @@ -1,193 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright © 2018 WireGuard LLC. All Rights Reserved. - -import Foundation -import Network -import NetworkExtension - -protocol LegacyModel: Decodable { - associatedtype Model - - var migrated: Model { get } -} - -struct LegacyDNSServer: LegacyModel { - let address: IPAddress - - var migrated: DNSServer { - return DNSServer(address: address) - } - - init(from decoder: Decoder) throws { - let container = try decoder.singleValueContainer() - var data = try container.decode(Data.self) - let ipAddressFromData: IPAddress? = { - switch data.count { - case 4: return IPv4Address(data) - case 16: return IPv6Address(data) - default: return nil - } - }() - guard let ipAddress = ipAddressFromData else { - throw DecodingError.invalidData - } - address = ipAddress - } - - enum DecodingError: Error { - case invalidData - } -} - -extension Array where Element == LegacyDNSServer { - var migrated: [DNSServer] { - return map { $0.migrated } - } -} - -struct LegacyEndpoint: LegacyModel { - let host: Network.NWEndpoint.Host - let port: Network.NWEndpoint.Port - - var migrated: Endpoint { - return Endpoint(host: host, port: port) - } - - public init(from decoder: Decoder) throws { - let container = try decoder.singleValueContainer() - let endpointString = try container.decode(String.self) - guard !endpointString.isEmpty else { throw DecodingError.invalidData } - let startOfPort: String.Index - let hostString: String - if endpointString.first! == "[" { - // Look for IPv6-style endpoint, like [::1]:80 - let startOfHost = endpointString.index(after: endpointString.startIndex) - guard let endOfHost = endpointString.dropFirst().firstIndex(of: "]") else { throw DecodingError.invalidData } - let afterEndOfHost = endpointString.index(after: endOfHost) - guard endpointString[afterEndOfHost] == ":" else { throw DecodingError.invalidData } - startOfPort = endpointString.index(after: afterEndOfHost) - hostString = String(endpointString[startOfHost ..< endOfHost]) - } else { - // Look for an IPv4-style endpoint, like 127.0.0.1:80 - guard let endOfHost = endpointString.firstIndex(of: ":") else { throw DecodingError.invalidData } - startOfPort = endpointString.index(after: endOfHost) - hostString = String(endpointString[endpointString.startIndex ..< endOfHost]) - } - guard let endpointPort = NWEndpoint.Port(String(endpointString[startOfPort ..< endpointString.endIndex])) else { throw DecodingError.invalidData } - let invalidCharacterIndex = hostString.unicodeScalars.firstIndex { char in - return !CharacterSet.urlHostAllowed.contains(char) - } - guard invalidCharacterIndex == nil else { throw DecodingError.invalidData } - host = NWEndpoint.Host(hostString) - port = endpointPort - } - - enum DecodingError: Error { - case invalidData - } -} - -struct LegacyInterfaceConfiguration: LegacyModel { - let name: String - let privateKey: Data - let addresses: [LegacyIPAddressRange] - let listenPort: UInt16? - let mtu: UInt16? - let dns: [LegacyDNSServer] - - var migrated: InterfaceConfiguration { - var interface = InterfaceConfiguration(privateKey: privateKey) - interface.addresses = addresses.migrated - interface.listenPort = listenPort - interface.mtu = mtu - interface.dns = dns.migrated - return interface - } -} - -struct LegacyIPAddressRange: LegacyModel { - let address: IPAddress - let networkPrefixLength: UInt8 - - var migrated: IPAddressRange { - return IPAddressRange(address: address, networkPrefixLength: networkPrefixLength) - } - - public init(from decoder: Decoder) throws { - let container = try decoder.singleValueContainer() - var data = try container.decode(Data.self) - networkPrefixLength = data.removeLast() - let ipAddressFromData: IPAddress? = { - switch data.count { - case 4: return IPv4Address(data) - case 16: return IPv6Address(data) - default: return nil - } - }() - guard let ipAddress = ipAddressFromData else { throw DecodingError.invalidData } - address = ipAddress - } - - enum DecodingError: Error { - case invalidData - } -} - -extension Array where Element == LegacyIPAddressRange { - var migrated: [IPAddressRange] { - return map { $0.migrated } - } -} - -struct LegacyPeerConfiguration: LegacyModel { - let publicKey: Data - let preSharedKey: Data? - let allowedIPs: [LegacyIPAddressRange] - let endpoint: LegacyEndpoint? - let persistentKeepAlive: UInt16? - - var migrated: PeerConfiguration { - var configuration = PeerConfiguration(publicKey: publicKey) - configuration.preSharedKey = preSharedKey - configuration.allowedIPs = allowedIPs.migrated - configuration.endpoint = endpoint?.migrated - configuration.persistentKeepAlive = persistentKeepAlive - return configuration - } -} - -extension Array where Element == LegacyPeerConfiguration { - var migrated: [PeerConfiguration] { - return map { $0.migrated } - } -} - -final class LegacyTunnelConfiguration: LegacyModel { - let interface: LegacyInterfaceConfiguration - let peers: [LegacyPeerConfiguration] - - var migrated: TunnelConfiguration { - return TunnelConfiguration(name: interface.name, interface: interface.migrated, peers: peers.migrated) - } -} - -extension NETunnelProviderProtocol { - - @discardableResult - func migrateConfigurationIfNeeded() -> Bool { - guard let configurationVersion = providerConfiguration?["tunnelConfigurationVersion"] as? Int else { return false } - if configurationVersion == 1 { - migrateFromConfigurationV1() - } else { - fatalError("No migration from configuration version \(configurationVersion) exists.") - } - return true - } - - private func migrateFromConfigurationV1() { - guard let serializedTunnelConfiguration = providerConfiguration?["tunnelConfiguration"] as? Data else { return } - guard let configuration = try? JSONDecoder().decode(LegacyTunnelConfiguration.self, from: serializedTunnelConfiguration) else { return } - providerConfiguration = [Keys.wgQuickConfig.rawValue: configuration.migrated.asWgQuickConfig()] - } - -} diff --git a/WireGuard/Shared/Model/LegacyConfigMigration.swift b/WireGuard/Shared/Model/LegacyConfigMigration.swift new file mode 100644 index 0000000..b67301f --- /dev/null +++ b/WireGuard/Shared/Model/LegacyConfigMigration.swift @@ -0,0 +1,193 @@ +// SPDX-License-Identifier: MIT +// Copyright © 2018 WireGuard LLC. All Rights Reserved. + +import Foundation +import Network +import NetworkExtension + +protocol LegacyModel: Decodable { + associatedtype Model + + var migrated: Model { get } +} + +struct LegacyDNSServer: LegacyModel { + let address: IPAddress + + var migrated: DNSServer { + return DNSServer(address: address) + } + + init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() + var data = try container.decode(Data.self) + let ipAddressFromData: IPAddress? = { + switch data.count { + case 4: return IPv4Address(data) + case 16: return IPv6Address(data) + default: return nil + } + }() + guard let ipAddress = ipAddressFromData else { + throw DecodingError.invalidData + } + address = ipAddress + } + + enum DecodingError: Error { + case invalidData + } +} + +extension Array where Element == LegacyDNSServer { + var migrated: [DNSServer] { + return map { $0.migrated } + } +} + +struct LegacyEndpoint: LegacyModel { + let host: Network.NWEndpoint.Host + let port: Network.NWEndpoint.Port + + var migrated: Endpoint { + return Endpoint(host: host, port: port) + } + + public init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() + let endpointString = try container.decode(String.self) + guard !endpointString.isEmpty else { throw DecodingError.invalidData } + let startOfPort: String.Index + let hostString: String + if endpointString.first! == "[" { + // Look for IPv6-style endpoint, like [::1]:80 + let startOfHost = endpointString.index(after: endpointString.startIndex) + guard let endOfHost = endpointString.dropFirst().firstIndex(of: "]") else { throw DecodingError.invalidData } + let afterEndOfHost = endpointString.index(after: endOfHost) + guard endpointString[afterEndOfHost] == ":" else { throw DecodingError.invalidData } + startOfPort = endpointString.index(after: afterEndOfHost) + hostString = String(endpointString[startOfHost ..< endOfHost]) + } else { + // Look for an IPv4-style endpoint, like 127.0.0.1:80 + guard let endOfHost = endpointString.firstIndex(of: ":") else { throw DecodingError.invalidData } + startOfPort = endpointString.index(after: endOfHost) + hostString = String(endpointString[endpointString.startIndex ..< endOfHost]) + } + guard let endpointPort = NWEndpoint.Port(String(endpointString[startOfPort ..< endpointString.endIndex])) else { throw DecodingError.invalidData } + let invalidCharacterIndex = hostString.unicodeScalars.firstIndex { char in + return !CharacterSet.urlHostAllowed.contains(char) + } + guard invalidCharacterIndex == nil else { throw DecodingError.invalidData } + host = NWEndpoint.Host(hostString) + port = endpointPort + } + + enum DecodingError: Error { + case invalidData + } +} + +struct LegacyInterfaceConfiguration: LegacyModel { + let name: String + let privateKey: Data + let addresses: [LegacyIPAddressRange] + let listenPort: UInt16? + let mtu: UInt16? + let dns: [LegacyDNSServer] + + var migrated: InterfaceConfiguration { + var interface = InterfaceConfiguration(privateKey: privateKey) + interface.addresses = addresses.migrated + interface.listenPort = listenPort + interface.mtu = mtu + interface.dns = dns.migrated + return interface + } +} + +struct LegacyIPAddressRange: LegacyModel { + let address: IPAddress + let networkPrefixLength: UInt8 + + var migrated: IPAddressRange { + return IPAddressRange(address: address, networkPrefixLength: networkPrefixLength) + } + + public init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() + var data = try container.decode(Data.self) + networkPrefixLength = data.removeLast() + let ipAddressFromData: IPAddress? = { + switch data.count { + case 4: return IPv4Address(data) + case 16: return IPv6Address(data) + default: return nil + } + }() + guard let ipAddress = ipAddressFromData else { throw DecodingError.invalidData } + address = ipAddress + } + + enum DecodingError: Error { + case invalidData + } +} + +extension Array where Element == LegacyIPAddressRange { + var migrated: [IPAddressRange] { + return map { $0.migrated } + } +} + +struct LegacyPeerConfiguration: LegacyModel { + let publicKey: Data + let preSharedKey: Data? + let allowedIPs: [LegacyIPAddressRange] + let endpoint: LegacyEndpoint? + let persistentKeepAlive: UInt16? + + var migrated: PeerConfiguration { + var configuration = PeerConfiguration(publicKey: publicKey) + configuration.preSharedKey = preSharedKey + configuration.allowedIPs = allowedIPs.migrated + configuration.endpoint = endpoint?.migrated + configuration.persistentKeepAlive = persistentKeepAlive + return configuration + } +} + +extension Array where Element == LegacyPeerConfiguration { + var migrated: [PeerConfiguration] { + return map { $0.migrated } + } +} + +final class LegacyTunnelConfiguration: LegacyModel { + let interface: LegacyInterfaceConfiguration + let peers: [LegacyPeerConfiguration] + + var migrated: TunnelConfiguration { + return TunnelConfiguration(name: interface.name, interface: interface.migrated, peers: peers.migrated) + } +} + +extension NETunnelProviderProtocol { + + @discardableResult + func migrateConfigurationIfNeeded() -> Bool { + guard let configurationVersion = providerConfiguration?["tunnelConfigurationVersion"] as? Int else { return false } + if configurationVersion == 1 { + migrateFromConfigurationV1() + } else { + fatalError("No migration from configuration version \(configurationVersion) exists.") + } + return true + } + + private func migrateFromConfigurationV1() { + guard let serializedTunnelConfiguration = providerConfiguration?["tunnelConfiguration"] as? Data else { return } + guard let configuration = try? JSONDecoder().decode(LegacyTunnelConfiguration.self, from: serializedTunnelConfiguration) else { return } + providerConfiguration = [Keys.wgQuickConfig.rawValue: configuration.migrated.asWgQuickConfig()] + } + +} diff --git a/WireGuard/Shared/Model/NETunnelProviderProtocol+Extension.swift b/WireGuard/Shared/Model/NETunnelProviderProtocol+Extension.swift new file mode 100644 index 0000000..98634fd --- /dev/null +++ b/WireGuard/Shared/Model/NETunnelProviderProtocol+Extension.swift @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MIT +// Copyright © 2018 WireGuard LLC. All Rights Reserved. + +import NetworkExtension + +extension NETunnelProviderProtocol { + + enum Keys: String { + case wgQuickConfig = "WgQuickConfig" + } + + convenience init?(tunnelConfiguration: TunnelConfiguration) { + self.init() + + let appId = Bundle.main.bundleIdentifier! + providerBundleIdentifier = "\(appId).network-extension" + providerConfiguration = [Keys.wgQuickConfig.rawValue: tunnelConfiguration.asWgQuickConfig()] + + let endpoints = tunnelConfiguration.peers.compactMap { $0.endpoint } + if endpoints.count == 1 { + serverAddress = endpoints[0].stringRepresentation + } else if endpoints.isEmpty { + serverAddress = "Unspecified" + } else { + serverAddress = "Multiple endpoints" + } + + //TODO(roopc): Why are we doing this? Just for kicks? Is it useful? Seems needless. + username = tunnelConfiguration.name + } + + func asTunnelConfiguration(called name: String? = nil) -> TunnelConfiguration? { + migrateConfigurationIfNeeded() + guard let serializedConfig = providerConfiguration?[Keys.wgQuickConfig.rawValue] as? String else { return nil } + return try? TunnelConfiguration(fromWgQuickConfig: serializedConfig, called: name) + } + +} diff --git a/WireGuard/Shared/Model/String+ArrayConversion.swift b/WireGuard/Shared/Model/String+ArrayConversion.swift new file mode 100644 index 0000000..6a3e794 --- /dev/null +++ b/WireGuard/Shared/Model/String+ArrayConversion.swift @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT +// Copyright © 2018 WireGuard LLC. All Rights Reserved. + +import Foundation + +extension String { + + func splitToArray(separator: Character = ",", trimmingCharacters: CharacterSet? = nil) -> [String] { + return split(separator: separator) + .map { + if let charSet = trimmingCharacters { + return $0.trimmingCharacters(in: charSet) + } else { + return String($0) + } + } + } + +} + +extension Optional where Wrapped == String { + + func splitToArray(separator: Character = ",", trimmingCharacters: CharacterSet? = nil) -> [String] { + switch self { + case .none: + return [] + case .some(let wrapped): + return wrapped.splitToArray(separator: separator, trimmingCharacters: trimmingCharacters) + } + } + +} diff --git a/WireGuard/Shared/Model/TunnelConfiguration+WgQuickConfig.swift b/WireGuard/Shared/Model/TunnelConfiguration+WgQuickConfig.swift new file mode 100644 index 0000000..94e1079 --- /dev/null +++ b/WireGuard/Shared/Model/TunnelConfiguration+WgQuickConfig.swift @@ -0,0 +1,200 @@ +// SPDX-License-Identifier: MIT +// Copyright © 2018 WireGuard LLC. All Rights Reserved. + +import Foundation + +extension TunnelConfiguration { + + enum ParserState { + case inInterfaceSection + case inPeerSection + case notInASection + } + + enum ParseError: Error { + case invalidLine(_ line: String.SubSequence) + case noInterface + case invalidInterface + case multipleInterfaces + case multiplePeersWithSamePublicKey + case invalidPeer + } + + //swiftlint:disable:next function_body_length cyclomatic_complexity + convenience init(fromWgQuickConfig wgQuickConfig: String, called name: String? = nil) throws { + var interfaceConfiguration: InterfaceConfiguration? + var peerConfigurations = [PeerConfiguration]() + + 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: "#") { + trimmedLine = String(line[..(peerPublicKeysArray) + if peerPublicKeysArray.count != peerPublicKeysSet.count { + throw ParseError.multiplePeersWithSamePublicKey + } + + if let interfaceConfiguration = interfaceConfiguration { + self.init(name: name, 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]) -> 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 } + var interface = InterfaceConfiguration(privateKey: privateKey) + // other wg fields + if let listenPortString = attributes["listenport"] { + guard let listenPort = UInt16(listenPortString) else { return nil } + interface.listenPort = listenPort + } + // wg-quick fields + if let addressesString = attributes["address"] { + var addresses = [IPAddressRange]() + for addressString in addressesString.splitToArray(trimmingCharacters: .whitespaces) { + guard let address = IPAddressRange(from: addressString) else { return nil } + addresses.append(address) + } + interface.addresses = addresses + } + if let dnsString = attributes["dns"] { + var dnsServers = [DNSServer]() + for dnsServerString in dnsString.splitToArray(trimmingCharacters: .whitespaces) { + guard let dnsServer = DNSServer(from: dnsServerString) else { return nil } + dnsServers.append(dnsServer) + } + interface.dns = dnsServers + } + if let mtuString = attributes["mtu"] { + guard let mtu = UInt16(mtuString) else { return nil } + interface.mtu = mtu + } + return interface + } + + //swiftlint:disable:next cyclomatic_complexity + private static func collate(peerAttributes attributes: [String: String]) -> PeerConfiguration? { + // required wg fields + guard let publicKeyString = attributes["publickey"] else { return nil } + guard let publicKey = Data(base64Encoded: publicKeyString), publicKey.count == TunnelConfiguration.keyLength else { return nil } + var peer = PeerConfiguration(publicKey: publicKey) + // wg fields + if let preSharedKeyString = attributes["presharedkey"] { + guard let preSharedKey = Data(base64Encoded: preSharedKeyString), preSharedKey.count == TunnelConfiguration.keyLength else { return nil } + peer.preSharedKey = preSharedKey + } + if let allowedIPsString = attributes["allowedips"] { + var allowedIPs = [IPAddressRange]() + for allowedIPString in allowedIPsString.splitToArray(trimmingCharacters: .whitespacesAndNewlines) { + guard let allowedIP = IPAddressRange(from: allowedIPString) else { return nil } + allowedIPs.append(allowedIP) + } + peer.allowedIPs = allowedIPs + } + if let endpointString = attributes["endpoint"] { + guard let endpoint = Endpoint(from: endpointString) else { return nil } + peer.endpoint = endpoint + } + if let persistentKeepAliveString = attributes["persistentkeepalive"] { + guard let persistentKeepAlive = UInt16(persistentKeepAliveString) else { return nil } + peer.persistentKeepAlive = persistentKeepAlive + } + return peer + } + +} diff --git a/WireGuard/Shared/NETunnelProviderProtocol+Extension.swift b/WireGuard/Shared/NETunnelProviderProtocol+Extension.swift deleted file mode 100644 index 258c968..0000000 --- a/WireGuard/Shared/NETunnelProviderProtocol+Extension.swift +++ /dev/null @@ -1,40 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright © 2018 WireGuard LLC. All Rights Reserved. - -import NetworkExtension - -private var tunnelNameKey: Void? - -extension NETunnelProviderProtocol { - - enum Keys: String { - case wgQuickConfig = "WgQuickConfig" - } - - convenience init?(tunnelConfiguration: TunnelConfiguration) { - self.init() - - let appId = Bundle.main.bundleIdentifier! - providerBundleIdentifier = "\(appId).network-extension" - providerConfiguration = [Keys.wgQuickConfig.rawValue: tunnelConfiguration.asWgQuickConfig()] - - let endpoints = tunnelConfiguration.peers.compactMap { $0.endpoint } - if endpoints.count == 1 { - serverAddress = endpoints[0].stringRepresentation - } else if endpoints.isEmpty { - serverAddress = "Unspecified" - } else { - serverAddress = "Multiple endpoints" - } - - //TODO(roopc): Why are we doing this? Just for kicks? Is it useful? Seems needless. - username = tunnelConfiguration.name - } - - func asTunnelConfiguration(called name: String? = nil) -> TunnelConfiguration? { - migrateConfigurationIfNeeded() - guard let serializedConfig = providerConfiguration?[Keys.wgQuickConfig.rawValue] as? String else { return nil } - return try? TunnelConfiguration(fromWgQuickConfig: serializedConfig, called: name) - } - -} diff --git a/WireGuard/Shared/String+ArrayConversion.swift b/WireGuard/Shared/String+ArrayConversion.swift deleted file mode 100644 index 6a3e794..0000000 --- a/WireGuard/Shared/String+ArrayConversion.swift +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright © 2018 WireGuard LLC. All Rights Reserved. - -import Foundation - -extension String { - - func splitToArray(separator: Character = ",", trimmingCharacters: CharacterSet? = nil) -> [String] { - return split(separator: separator) - .map { - if let charSet = trimmingCharacters { - return $0.trimmingCharacters(in: charSet) - } else { - return String($0) - } - } - } - -} - -extension Optional where Wrapped == String { - - func splitToArray(separator: Character = ",", trimmingCharacters: CharacterSet? = nil) -> [String] { - switch self { - case .none: - return [] - case .some(let wrapped): - return wrapped.splitToArray(separator: separator, trimmingCharacters: trimmingCharacters) - } - } - -} diff --git a/WireGuard/Shared/TunnelConfiguration+WgQuickConfig.swift b/WireGuard/Shared/TunnelConfiguration+WgQuickConfig.swift deleted file mode 100644 index 94e1079..0000000 --- a/WireGuard/Shared/TunnelConfiguration+WgQuickConfig.swift +++ /dev/null @@ -1,200 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright © 2018 WireGuard LLC. All Rights Reserved. - -import Foundation - -extension TunnelConfiguration { - - enum ParserState { - case inInterfaceSection - case inPeerSection - case notInASection - } - - enum ParseError: Error { - case invalidLine(_ line: String.SubSequence) - case noInterface - case invalidInterface - case multipleInterfaces - case multiplePeersWithSamePublicKey - case invalidPeer - } - - //swiftlint:disable:next function_body_length cyclomatic_complexity - convenience init(fromWgQuickConfig wgQuickConfig: String, called name: String? = nil) throws { - var interfaceConfiguration: InterfaceConfiguration? - var peerConfigurations = [PeerConfiguration]() - - 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: "#") { - trimmedLine = String(line[..(peerPublicKeysArray) - if peerPublicKeysArray.count != peerPublicKeysSet.count { - throw ParseError.multiplePeersWithSamePublicKey - } - - if let interfaceConfiguration = interfaceConfiguration { - self.init(name: name, 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]) -> 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 } - var interface = InterfaceConfiguration(privateKey: privateKey) - // other wg fields - if let listenPortString = attributes["listenport"] { - guard let listenPort = UInt16(listenPortString) else { return nil } - interface.listenPort = listenPort - } - // wg-quick fields - if let addressesString = attributes["address"] { - var addresses = [IPAddressRange]() - for addressString in addressesString.splitToArray(trimmingCharacters: .whitespaces) { - guard let address = IPAddressRange(from: addressString) else { return nil } - addresses.append(address) - } - interface.addresses = addresses - } - if let dnsString = attributes["dns"] { - var dnsServers = [DNSServer]() - for dnsServerString in dnsString.splitToArray(trimmingCharacters: .whitespaces) { - guard let dnsServer = DNSServer(from: dnsServerString) else { return nil } - dnsServers.append(dnsServer) - } - interface.dns = dnsServers - } - if let mtuString = attributes["mtu"] { - guard let mtu = UInt16(mtuString) else { return nil } - interface.mtu = mtu - } - return interface - } - - //swiftlint:disable:next cyclomatic_complexity - private static func collate(peerAttributes attributes: [String: String]) -> PeerConfiguration? { - // required wg fields - guard let publicKeyString = attributes["publickey"] else { return nil } - guard let publicKey = Data(base64Encoded: publicKeyString), publicKey.count == TunnelConfiguration.keyLength else { return nil } - var peer = PeerConfiguration(publicKey: publicKey) - // wg fields - if let preSharedKeyString = attributes["presharedkey"] { - guard let preSharedKey = Data(base64Encoded: preSharedKeyString), preSharedKey.count == TunnelConfiguration.keyLength else { return nil } - peer.preSharedKey = preSharedKey - } - if let allowedIPsString = attributes["allowedips"] { - var allowedIPs = [IPAddressRange]() - for allowedIPString in allowedIPsString.splitToArray(trimmingCharacters: .whitespacesAndNewlines) { - guard let allowedIP = IPAddressRange(from: allowedIPString) else { return nil } - allowedIPs.append(allowedIP) - } - peer.allowedIPs = allowedIPs - } - if let endpointString = attributes["endpoint"] { - guard let endpoint = Endpoint(from: endpointString) else { return nil } - peer.endpoint = endpoint - } - if let persistentKeepAliveString = attributes["persistentkeepalive"] { - guard let persistentKeepAlive = UInt16(persistentKeepAliveString) else { return nil } - peer.persistentKeepAlive = persistentKeepAlive - } - return peer - } - -} diff --git a/WireGuard/WireGuard.xcodeproj/project.pbxproj b/WireGuard/WireGuard.xcodeproj/project.pbxproj index cd04c06..7bdc5e8 100644 --- a/WireGuard/WireGuard.xcodeproj/project.pbxproj +++ b/WireGuard/WireGuard.xcodeproj/project.pbxproj @@ -255,11 +255,7 @@ children = ( 6FF3526A21C23F720008484E /* Logging */, 6F7774E6217201E0006A79B3 /* Model */, - 6FFA5D942194454A0001E2F7 /* NETunnelProviderProtocol+Extension.swift */, 6F5A2B4421AFDE020081EDD8 /* FileManager+Extension.swift */, - 5F9696A921CD6AE6008063FE /* LegacyConfigMigration.swift */, - 5F4541B121CBFAEE00994C13 /* String+ArrayConversion.swift */, - 5F9696AF21CD7128008063FE /* TunnelConfiguration+WgQuickConfig.swift */, ); path = Shared; sourceTree = ""; @@ -298,6 +294,10 @@ 6F7774E6217201E0006A79B3 /* Model */ = { isa = PBXGroup; children = ( + 5F9696AF21CD7128008063FE /* TunnelConfiguration+WgQuickConfig.swift */, + 6FFA5D942194454A0001E2F7 /* NETunnelProviderProtocol+Extension.swift */, + 5F4541B121CBFAEE00994C13 /* String+ArrayConversion.swift */, + 5F9696A921CD6AE6008063FE /* LegacyConfigMigration.swift */, 6F7774E72172020C006A79B3 /* TunnelConfiguration.swift */, 6F7774E9217229DB006A79B3 /* IPAddressRange.swift */, 6F693A552179E556008551C1 /* Endpoint.swift */, -- cgit v1.2.3-59-g8ed1b