Added ability to add tunnels with a QR code scan. Logic in place to parse conf files as well.
Signed-off-by: Eric Kuck <eric@bluelinelabs.com>
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// Attribute.swift
|
||||
// WireGuard
|
||||
//
|
||||
// Created by Eric Kuck on 8/20/18.
|
||||
// Copyright © 2018 Jason A. Donenfeld <Jason@zx2c4.com>. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct Attribute {
|
||||
|
||||
enum Key: String, CaseIterable {
|
||||
case address = "Address"
|
||||
case allowedIPs = "AllowedIPs"
|
||||
case dns = "DNS"
|
||||
case endpoint = "Endpoint"
|
||||
case listenPort = "ListenPort"
|
||||
case mtu = "MTU"
|
||||
case persistentKeepalive = "PersistentKeepalive"
|
||||
case presharedKey = "PresharedKey"
|
||||
case privateKey = "PrivateKey"
|
||||
case publicKey = "PublicKey"
|
||||
}
|
||||
|
||||
private static let separatorPattern = (try? NSRegularExpression(pattern: "\\s|=", options: []))!
|
||||
|
||||
let line: String
|
||||
let key: Key
|
||||
let stringValue: String
|
||||
var arrayValue: [String] {
|
||||
return stringValue.commaSeparatedToArray()
|
||||
}
|
||||
|
||||
static func match(line: String) -> Attribute? {
|
||||
guard let equalsIndex = line.firstIndex(of: "=") else { return nil }
|
||||
let keyString = line[..<equalsIndex].trimmingCharacters(in: .whitespaces)
|
||||
let value = line[line.index(equalsIndex, offsetBy: 1)...].trimmingCharacters(in: .whitespaces)
|
||||
guard let key = Key.allCases.first(where: { $0.rawValue.lowercased() == keyString.lowercased() }) else { return nil }
|
||||
|
||||
return Attribute(line: line, key: key, stringValue: value)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -36,6 +36,27 @@ extension Interface {
|
||||
}
|
||||
}
|
||||
|
||||
func parse(attribute: Attribute) throws {
|
||||
switch attribute.key {
|
||||
case .address:
|
||||
addresses = attribute.stringValue
|
||||
case .dns:
|
||||
dns = attribute.stringValue
|
||||
case .listenPort:
|
||||
if let port = Int16(attribute.stringValue) {
|
||||
listenPort = port
|
||||
}
|
||||
case .mtu:
|
||||
if let mtu = Int32(attribute.stringValue) {
|
||||
self.mtu = mtu
|
||||
}
|
||||
case .privateKey:
|
||||
privateKey = attribute.stringValue
|
||||
default:
|
||||
throw TunnelParseError.invalidLine(attribute.line)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
enum InterfaceValidationError: Error {
|
||||
|
||||
@@ -44,6 +44,25 @@ extension Peer {
|
||||
}
|
||||
}
|
||||
|
||||
func parse(attribute: Attribute) throws {
|
||||
switch attribute.key {
|
||||
case .allowedIPs:
|
||||
allowedIPs = attribute.stringValue
|
||||
case .endpoint:
|
||||
endpoint = attribute.stringValue
|
||||
case .persistentKeepalive:
|
||||
if let keepAlive = Int32(attribute.stringValue) {
|
||||
persistentKeepalive = keepAlive
|
||||
}
|
||||
case .presharedKey:
|
||||
presharedKey = attribute.stringValue
|
||||
case .publicKey:
|
||||
publicKey = attribute.stringValue
|
||||
default:
|
||||
throw TunnelParseError.invalidLine(attribute.line)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
enum PeerValidationError: Error {
|
||||
|
||||
@@ -111,6 +111,54 @@ extension Tunnel {
|
||||
}
|
||||
}
|
||||
|
||||
static func fromConfig(_ text: String, context: NSManagedObjectContext) throws -> Tunnel {
|
||||
let lines = text.split(separator: "\n")
|
||||
|
||||
var currentPeer: Peer?
|
||||
var isInInterfaceSection = false
|
||||
|
||||
var tunnel: Tunnel!
|
||||
context.performAndWait {
|
||||
tunnel = Tunnel(context: context)
|
||||
tunnel.interface = Interface(context: context)
|
||||
}
|
||||
tunnel.tunnelIdentifier = UUID().uuidString
|
||||
|
||||
for line in lines {
|
||||
var trimmedLine: String
|
||||
if let commentRange = line.range(of: "#") {
|
||||
trimmedLine = String(line[..<commentRange.lowerBound])
|
||||
} else {
|
||||
trimmedLine = String(line)
|
||||
}
|
||||
|
||||
trimmedLine = trimmedLine.trimmingCharacters(in: .whitespaces)
|
||||
|
||||
guard trimmedLine.count > 0 else { continue }
|
||||
|
||||
if "[interface]" == line.lowercased() {
|
||||
currentPeer = nil
|
||||
isInInterfaceSection = true
|
||||
} else if "[peer]" == line.lowercased() {
|
||||
context.performAndWait { currentPeer = Peer(context: context) }
|
||||
tunnel.insertIntoPeers(currentPeer!, at: tunnel.peers?.count ?? 0)
|
||||
isInInterfaceSection = false
|
||||
} else if isInInterfaceSection, let attribute = Attribute.match(line: String(line)) {
|
||||
try tunnel.interface!.parse(attribute: attribute)
|
||||
} else if let currentPeer = currentPeer, let attribute = Attribute.match(line: String(line)) {
|
||||
try currentPeer.parse(attribute: attribute)
|
||||
} else {
|
||||
throw TunnelParseError.invalidLine(String(line))
|
||||
}
|
||||
}
|
||||
|
||||
if !isInInterfaceSection && currentPeer == nil {
|
||||
throw TunnelParseError.noConfigInfo
|
||||
}
|
||||
|
||||
return tunnel
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private func base64KeyToHex(_ base64: String?) -> String? {
|
||||
@@ -146,3 +194,8 @@ enum TunnelValidationError: Error {
|
||||
case nilPeers
|
||||
case invalidPeer
|
||||
}
|
||||
|
||||
enum TunnelParseError: Error {
|
||||
case invalidLine(_ line: String)
|
||||
case noConfigInfo
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user