Added validation before saving any tunnels
Signed-off-by: Eric Kuck <eric@bluelinelabs.com>
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
//
|
||||
// Interface+Extension.swift
|
||||
// WireGuard
|
||||
//
|
||||
// Created by Eric Kuck on 8/15/18.
|
||||
// Copyright © 2018 Jason A. Donenfeld <Jason@zx2c4.com>. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Interface {
|
||||
|
||||
func validate() throws {
|
||||
guard let privateKey = privateKey, !privateKey.isEmpty else {
|
||||
throw InterfaceValidationError.emptyPrivateKey
|
||||
}
|
||||
|
||||
guard privateKey.isBase64() else {
|
||||
throw InterfaceValidationError.invalidPrivateKey
|
||||
}
|
||||
|
||||
try? addresses?.commaSeparatedToArray().forEach { address in
|
||||
do {
|
||||
try _ = CIDRAddress(stringRepresentation: address)
|
||||
} catch {
|
||||
throw InterfaceValidationError.invalidAddress(cause: error)
|
||||
}
|
||||
}
|
||||
|
||||
try? dns?.commaSeparatedToArray().forEach { address in
|
||||
do {
|
||||
try _ = Endpoint(endpointString: address)
|
||||
} catch {
|
||||
throw InterfaceValidationError.invalidDNSServer(cause: error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
enum InterfaceValidationError: Error {
|
||||
case emptyPrivateKey
|
||||
case invalidPrivateKey
|
||||
case invalidAddress(cause: Error)
|
||||
case invalidDNSServer(cause: Error)
|
||||
}
|
||||
@@ -19,7 +19,7 @@ extension Peer {
|
||||
@NSManaged public var presharedKey: String?
|
||||
@NSManaged public var allowedIPs: String?
|
||||
@NSManaged public var endpoint: String?
|
||||
@NSManaged public var persistentKeepalive: Int16
|
||||
@NSManaged public var persistentKeepalive: Int32
|
||||
@NSManaged public var tunnel: Tunnel?
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
//
|
||||
// Peer+Extension.swift
|
||||
// WireGuard
|
||||
//
|
||||
// Created by Eric Kuck on 8/15/18.
|
||||
// Copyright © 2018 Jason A. Donenfeld <Jason@zx2c4.com>. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Peer {
|
||||
|
||||
func validate() throws {
|
||||
guard let publicKey = publicKey, !publicKey.isEmpty else {
|
||||
throw PeerValidationError.emptyPublicKey
|
||||
}
|
||||
|
||||
guard publicKey.isBase64() else {
|
||||
throw PeerValidationError.invalidPublicKey
|
||||
}
|
||||
|
||||
guard let allowedIPs = allowedIPs, !allowedIPs.isEmpty else {
|
||||
throw PeerValidationError.nilAllowedIps
|
||||
}
|
||||
|
||||
try allowedIPs.commaSeparatedToArray().forEach { address in
|
||||
do {
|
||||
try _ = CIDRAddress(stringRepresentation: address)
|
||||
} catch {
|
||||
throw PeerValidationError.invalidAllowedIPs(cause: error)
|
||||
}
|
||||
}
|
||||
|
||||
if let endpoint = endpoint {
|
||||
do {
|
||||
try _ = Endpoint(endpointString: endpoint)
|
||||
} catch {
|
||||
throw PeerValidationError.invalidEndpoint(cause: error)
|
||||
}
|
||||
}
|
||||
|
||||
guard persistentKeepalive >= 0, persistentKeepalive <= 65535 else {
|
||||
throw PeerValidationError.invalidPersistedKeepAlive
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
enum PeerValidationError: Error {
|
||||
case emptyPublicKey
|
||||
case invalidPublicKey
|
||||
case nilAllowedIps
|
||||
case invalidAllowedIPs(cause: Error)
|
||||
case invalidEndpoint(cause: Error)
|
||||
case invalidPersistedKeepAlive
|
||||
}
|
||||
@@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreData
|
||||
|
||||
extension Tunnel {
|
||||
public func generateProviderConfiguration() -> [String: Any] {
|
||||
@@ -38,7 +39,7 @@ extension Tunnel {
|
||||
return providerConfiguration
|
||||
}
|
||||
|
||||
private func generateInterfaceProviderConfiguration(_ interface: Interface) -> String {
|
||||
private func generateInterfaceProviderConfiguration(_ interface: Interface) -> String {
|
||||
var settingsString = ""
|
||||
|
||||
if let hexPrivateKey = base64KeyToHex(interface.privateKey) {
|
||||
@@ -54,7 +55,7 @@ extension Tunnel {
|
||||
return settingsString
|
||||
}
|
||||
|
||||
private func generatePeerProviderConfiguration(_ peer: Peer) -> String {
|
||||
private func generatePeerProviderConfiguration(_ peer: Peer) -> String {
|
||||
var settingsString = ""
|
||||
|
||||
if let hexPublicKey = base64KeyToHex(peer.publicKey) {
|
||||
@@ -77,6 +78,39 @@ extension Tunnel {
|
||||
|
||||
return settingsString
|
||||
}
|
||||
|
||||
func validate() throws {
|
||||
let nameRegex = "[a-zA-Z0-9_=+.-]{1,15}"
|
||||
let nameTest = NSPredicate(format: "SELF MATCHES %@", nameRegex)
|
||||
guard let title = title, nameTest.evaluate(with: title) else {
|
||||
throw TunnelValidationError.invalidTitle
|
||||
}
|
||||
|
||||
let fetchRequest: NSFetchRequest<Tunnel> = Tunnel.fetchRequest()
|
||||
fetchRequest.predicate = NSPredicate(format: "title == %@", title)
|
||||
guard (try? managedObjectContext?.count(for: fetchRequest)) == 1 else {
|
||||
throw TunnelValidationError.titleExists
|
||||
}
|
||||
|
||||
guard let interface = interface else {
|
||||
throw TunnelValidationError.nilInterface
|
||||
}
|
||||
|
||||
try interface.validate()
|
||||
|
||||
guard let peers = peers else {
|
||||
throw TunnelValidationError.nilPeers
|
||||
}
|
||||
|
||||
try peers.forEach {
|
||||
guard let peer = $0 as? Peer else {
|
||||
throw TunnelValidationError.invalidPeer
|
||||
}
|
||||
|
||||
try peer.validate()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private func base64KeyToHex(_ base64: String?) -> String? {
|
||||
@@ -104,3 +138,11 @@ private func base64KeyToHex(_ base64: String?) -> String? {
|
||||
|
||||
return hexKey
|
||||
}
|
||||
|
||||
enum TunnelValidationError: Error {
|
||||
case invalidTitle
|
||||
case titleExists
|
||||
case nilInterface
|
||||
case nilPeers
|
||||
case invalidPeer
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="14135" systemVersion="17G65" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
|
||||
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="14315.12.1" systemVersion="17G2208" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
|
||||
<entity name="Interface" representedClassName="Interface" syncable="YES">
|
||||
<attribute name="addresses" optional="YES" attributeType="String" syncable="YES"/>
|
||||
<attribute name="dns" optional="YES" attributeType="String" syncable="YES"/>
|
||||
@@ -11,7 +11,7 @@
|
||||
<entity name="Peer" representedClassName="Peer" syncable="YES">
|
||||
<attribute name="allowedIPs" attributeType="String" syncable="YES"/>
|
||||
<attribute name="endpoint" optional="YES" attributeType="String" syncable="YES"/>
|
||||
<attribute name="persistentKeepalive" attributeType="Integer 16" minValueString="0" maxValueString="65535" defaultValueString="0" usesScalarValueType="YES" syncable="YES"/>
|
||||
<attribute name="persistentKeepalive" attributeType="Integer 32" minValueString="0" maxValueString="65535" defaultValueString="0" usesScalarValueType="YES" syncable="YES"/>
|
||||
<attribute name="presharedKey" optional="YES" attributeType="String" syncable="YES"/>
|
||||
<attribute name="publicKey" attributeType="String" syncable="YES"/>
|
||||
<relationship name="tunnel" maxCount="1" deletionRule="Nullify" destinationEntity="Tunnel" inverseName="peers" inverseEntity="Tunnel" syncable="YES"/>
|
||||
|
||||
Reference in New Issue
Block a user