Add import and export logic.
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import os.log
|
||||
|
||||
@UIApplicationMain
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
@@ -22,4 +23,23 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey: Any] = [:]) -> Bool {
|
||||
defer {
|
||||
do {
|
||||
try FileManager.default.removeItem(at: url)
|
||||
} catch {
|
||||
os_log("Failed to remove item from Inbox: %{public}@", log: Log.general, type: .error, url.absoluteString)
|
||||
}
|
||||
}
|
||||
guard url.pathExtension == "conf" else { return false }
|
||||
|
||||
do {
|
||||
try appCoordinator.importConfig(config: url)
|
||||
} catch {
|
||||
os_log("Unable to import config: %{public}@", log: Log.general, type: .error, url.absoluteString)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
<outlet property="delegate" destination="kTU-BV-32R" id="b6T-ZR-cmO"/>
|
||||
</connections>
|
||||
</tableView>
|
||||
<navigationItem key="navigationItem" title="WireGuard Tunnels" id="j0L-5U-jDs">
|
||||
<navigationItem key="navigationItem" title="WireGuard Tunnels" largeTitleDisplayMode="always" id="j0L-5U-jDs">
|
||||
<barButtonItem key="rightBarButtonItem" systemItem="add" id="h2H-H8-3Tn">
|
||||
<connections>
|
||||
<action selector="addProvider:" destination="kTU-BV-32R" id="xSg-ap-3Fx"/>
|
||||
@@ -486,14 +486,22 @@
|
||||
</connections>
|
||||
</tableView>
|
||||
<navigationItem key="navigationItem" title="Tunnel settings" id="PPu-rX-T38">
|
||||
<barButtonItem key="rightBarButtonItem" systemItem="save" id="mft-1l-bWa">
|
||||
<connections>
|
||||
<action selector="saveTunnelConfiguration:" destination="0VM-73-EPX" id="Hni-0w-hFF"/>
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
<rightBarButtonItems>
|
||||
<barButtonItem systemItem="save" id="mft-1l-bWa">
|
||||
<connections>
|
||||
<action selector="saveTunnelConfiguration:" destination="0VM-73-EPX" id="Hni-0w-hFF"/>
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
<barButtonItem systemItem="action" id="uim-Mz-omJ">
|
||||
<connections>
|
||||
<action selector="exportTunnel:" destination="0VM-73-EPX" id="oVI-TL-4o9"/>
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
</rightBarButtonItems>
|
||||
</navigationItem>
|
||||
<simulatedNavigationBarMetrics key="simulatedTopBarMetrics" prompted="NO"/>
|
||||
<connections>
|
||||
<outlet property="exportButton" destination="uim-Mz-omJ" id="1Tq-ie-xo7"/>
|
||||
<outlet property="saveButton" destination="mft-1l-bWa" id="Uif-KZ-isx"/>
|
||||
</connections>
|
||||
</tableViewController>
|
||||
@@ -524,7 +532,7 @@
|
||||
</constraints>
|
||||
<viewLayoutGuide key="safeArea" id="Soo-c9-MsX"/>
|
||||
</view>
|
||||
<navigationItem key="navigationItem" title="Scan Code" largeTitleDisplayMode="never" id="WGY-tY-ySz"/>
|
||||
<navigationItem key="navigationItem" title="Scan Code" largeTitleDisplayMode="always" id="WGY-tY-ySz"/>
|
||||
<simulatedNavigationBarMetrics key="simulatedTopBarMetrics" prompted="NO"/>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="TQ2-zp-o40" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
|
||||
@@ -13,6 +13,10 @@ import os.log
|
||||
import CoreData
|
||||
import BNRCoreDataStack
|
||||
|
||||
enum AppCoordinatorError: Error {
|
||||
case configImportError(msg: String)
|
||||
}
|
||||
|
||||
extension UINavigationController: Identifyable {}
|
||||
|
||||
let APPGROUP = "group.com.wireguard.ios.WireGuard"
|
||||
@@ -92,6 +96,46 @@ class AppCoordinator: RootViewCoordinator {
|
||||
}
|
||||
}
|
||||
|
||||
func importConfig(config: URL) throws {
|
||||
do {
|
||||
let configString = try String(contentsOf: config)
|
||||
let addContext = persistentContainer.newBackgroundContext()
|
||||
let tunnel = try Tunnel.fromConfig(configString, context: addContext)
|
||||
let title = config.deletingPathExtension().lastPathComponent
|
||||
tunnel.title = title
|
||||
addContext.saveContext()
|
||||
self.saveTunnel(tunnel)
|
||||
} catch {
|
||||
throw AppCoordinatorError.configImportError(msg: "Failed")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func exportConfig(tunnel: Tunnel, barButtonItem: UIBarButtonItem) {
|
||||
let exportString = tunnel.export()
|
||||
|
||||
guard let path = FileManager.default
|
||||
.urls(for: .documentDirectory, in: .userDomainMask).first else {
|
||||
return
|
||||
}
|
||||
let saveFileURL = path.appendingPathComponent("/\(tunnel.title ?? "wireguard").conf")
|
||||
do {
|
||||
try exportString.write(to: saveFileURL, atomically: true, encoding: .utf8)
|
||||
} catch {
|
||||
os_log("Failed to export tunnelto: %{public}@", log: Log.general, type: .error, saveFileURL.absoluteString)
|
||||
return
|
||||
}
|
||||
|
||||
let activityViewController = UIActivityViewController(
|
||||
activityItems: [saveFileURL],
|
||||
applicationActivities: nil)
|
||||
if let popoverPresentationController = activityViewController.popoverPresentationController {
|
||||
popoverPresentationController.barButtonItem = barButtonItem
|
||||
}
|
||||
self.navigationController.present(activityViewController, animated: true) {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - NEVPNManager handling
|
||||
|
||||
@objc private func VPNStatusDidChange(notification: NSNotification) {
|
||||
@@ -151,7 +195,6 @@ class AppCoordinator: RootViewCoordinator {
|
||||
}
|
||||
|
||||
extension AppCoordinator: TunnelsTableViewControllerDelegate {
|
||||
|
||||
func status(for tunnel: Tunnel, tunnelsTableViewController: TunnelsTableViewController) -> NEVPNStatus {
|
||||
let session = self.providerManager(for: tunnel)?.connection as? NETunnelProviderSession
|
||||
return session?.status ?? .invalid
|
||||
@@ -330,6 +373,10 @@ extension AppCoordinator: TunnelsTableViewControllerDelegate {
|
||||
}
|
||||
|
||||
extension AppCoordinator: TunnelConfigurationTableViewControllerDelegate {
|
||||
func export(tunnel: Tunnel, barButtonItem: UIBarButtonItem) {
|
||||
exportConfig(tunnel: tunnel, barButtonItem: barButtonItem)
|
||||
}
|
||||
|
||||
func didSave(tunnel: Tunnel, tunnelConfigurationTableViewController: TunnelConfigurationTableViewController) {
|
||||
saveTunnel(tunnel)
|
||||
}
|
||||
|
||||
+79
-2
@@ -2,10 +2,35 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>Camera is used to scan QR codes</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleDocumentTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string></string>
|
||||
</array>
|
||||
<key>CFBundleTypeIconFiles</key>
|
||||
<array>
|
||||
<string>icon_20pt</string>
|
||||
<string>icon_20pt@3x</string>
|
||||
<string>icon_60pt@3x</string>
|
||||
</array>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>WireGuard configuration</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
<key>LSHandlerRank</key>
|
||||
<string>Owner</string>
|
||||
<key>LSItemContentTypes</key>
|
||||
<array>
|
||||
<string>com.wireguard.config.quick</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
@@ -22,6 +47,12 @@
|
||||
<string>auto-generated</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>LSSupportsOpeningDocumentsInPlace</key>
|
||||
<false/>
|
||||
<key>UIFileSharingEnabled</key>
|
||||
<true/>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>Camera is used to scan QR codes</string>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
@@ -45,5 +76,51 @@
|
||||
</array>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
<key>UTExportedTypeDeclarations</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>UTTypeTagSpecification</key>
|
||||
<dict>
|
||||
<key>public.filename-extension</key>
|
||||
<string>conf</string>
|
||||
</dict>
|
||||
<key>UTTypeConformsTo</key>
|
||||
<array>
|
||||
<string>public.data</string>
|
||||
</array>
|
||||
<key>UTTypeDescription</key>
|
||||
<string>WireGuard configuration</string>
|
||||
<key>UTTypeIconFiles</key>
|
||||
<array>
|
||||
<string>icon_20pt@3x</string>
|
||||
<string>icon_60pt@3x</string>
|
||||
</array>
|
||||
<key>UTTypeIdentifier</key>
|
||||
<string>com.wireguard.config.quick</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>UTImportedTypeDeclarations</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>UTTypeTagSpecification</key>
|
||||
<dict>
|
||||
<key>public.filename-extension</key>
|
||||
<string>conf</string>
|
||||
</dict>
|
||||
<key>UTTypeConformsTo</key>
|
||||
<array>
|
||||
<string>public.data</string>
|
||||
</array>
|
||||
<key>UTTypeDescription</key>
|
||||
<string>WireGuard configuration</string>
|
||||
<key>UTTypeIconFiles</key>
|
||||
<array>
|
||||
<string>icon_20pt@3x</string>
|
||||
<string>icon_60pt@3x</string>
|
||||
</array>
|
||||
<key>UTTypeIdentifier</key>
|
||||
<string>com.wireguard.config.quick</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -13,11 +13,13 @@ import PromiseKit
|
||||
|
||||
protocol TunnelConfigurationTableViewControllerDelegate: class {
|
||||
func didSave(tunnel: Tunnel, tunnelConfigurationTableViewController: TunnelConfigurationTableViewController)
|
||||
func export(tunnel: Tunnel, barButtonItem: UIBarButtonItem)
|
||||
}
|
||||
|
||||
class TunnelConfigurationTableViewController: UITableViewController {
|
||||
|
||||
@IBOutlet weak var saveButton: UIBarButtonItem!
|
||||
@IBOutlet weak var exportButton: UIBarButtonItem!
|
||||
|
||||
private var viewContext: NSManagedObjectContext!
|
||||
private weak var delegate: TunnelConfigurationTableViewControllerDelegate?
|
||||
@@ -61,6 +63,10 @@ class TunnelConfigurationTableViewController: UITableViewController {
|
||||
}
|
||||
}
|
||||
|
||||
@IBAction func exportTunnel(_ sender: UIBarButtonItem) {
|
||||
self.delegate?.export(tunnel: tunnel, barButtonItem: sender)
|
||||
}
|
||||
|
||||
override func numberOfSections(in tableView: UITableView) -> Int {
|
||||
return 3
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user