From 815f12c9a392a46de2b64efaa9d79fa804068abd Mon Sep 17 00:00:00 2001 From: Jeroen Leenarts Date: Fri, 31 Aug 2018 23:06:40 +0200 Subject: [PATCH] Add import and export logic. --- Resources/icon_20pt.png | Bin 0 -> 730 bytes Resources/icon_20pt@3x.png | Bin 0 -> 2318 bytes WireGuard.xcodeproj/project.pbxproj | 10 +++ WireGuard/AppDelegate.swift | 20 +++++ WireGuard/Base.lproj/Main.storyboard | 22 +++-- WireGuard/Coordinators/AppCoordinator.swift | 49 ++++++++++- WireGuard/Info.plist | 81 +++++++++++++++++- ...nnelConfigurationTableViewController.swift | 6 ++ icon_20pt.png | Bin 0 -> 730 bytes 9 files changed, 178 insertions(+), 10 deletions(-) create mode 100644 Resources/icon_20pt.png create mode 100644 Resources/icon_20pt@3x.png create mode 100644 icon_20pt.png diff --git a/Resources/icon_20pt.png b/Resources/icon_20pt.png new file mode 100644 index 0000000000000000000000000000000000000000..78f07921867072e97b356b796f199e9de20a33a2 GIT binary patch literal 730 zcmV<00ww*4P)Px%lu1NER5%f>R9#3@Q5^qmZEd6pc*1(MDA+t@%q=X#YlV0}pmj&^n6^jjA;+N^*`Bq%OQ7&1dF zyLtsX&Ys}~LViDHN5|kecL83vo8M;*Nz6)Mu~wmALe1e%2Al6uJ>J>vm>zg7fCdugP_EIS;9w=bkBs2e&0CPEl&I_O zM2^KGD7az{Gq)9?*8UJOrIL^%kqAbgIAAC*2fY+VlW{AkU@%5Fu7_f&6gBM+z~<0( z?>+|ZG!b%s#eR5(hapQzfi^EMMvPs=ElOr#A(EJI-93-dd#!;GS+C3|>PgGc6ovV( zUzQ2R^)MU=5U@Nol_${@jhQztWNk0TWN#l9=YH^KoDsLmey7xEjAtsSbUI8te}T4A3%~tcHsbqLz z5uL~D@pEbl&n{iYWM4nD1_LzA_wNu4IlQodc54;EZaG{7DinlRB4K)O=@0+!!ypnb ze;@=sjQ*>;tD9UqYikR#ExTa3cpe*eml1F0#wVho#9r~Hun0wZIu0=nt}_{Va=_<9 zN8K^ZxLo`mXCxG4ffBi#+-IH1gxT?Nj5(f?*5O2==T!+t6B60K0kHef-S6y#EdT%j M07*qoM6N<$g6rQ%^Z)<= literal 0 HcmV?d00001 diff --git a/Resources/icon_20pt@3x.png b/Resources/icon_20pt@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..f7b6c661da4b996201ccdddac2f5b9853c4f4069 GIT binary patch literal 2318 zcmV+p3Gw!cP)Px-$Vo&&RA>e5S_@QFRT};Pk%u7;726{3?0nhK?&=KGOas~Iy#F*Qw18S_b{ zw3;caX?l#0(HRR}tE|RS(|Ea~M>M!?7s zaB%F1+R924=j0&o+mk5E&9$0Z?Lyee-5vK&nutz5-khMTmlpy?jYRmW=Qz>4Q>T#j z&)vv6d<3|y?2P#$kyf=hI|rXfK8=z~m!v*R0f%w-xW!od zu({6>!9HWhz#}jaE?%B!tgA!)Ed%^RL*dl9v-CRGE?&5A{5V`qO+{5FLg^Q=B0yVj&@7asw zO)+R-Tag}O^A#4AzVg-Ah@CJA1sUIoUA!GSe;(!@KE(WPAJu+yL7T2HxsN@D4}&Lj zEjze4qprFd#TT>j!~f5KoQVlrUd6yCXRC53%e{(EX3s(C<;$x5T0xr-CX(T+R-*Ul z2vxU|$mS#_A@%QD;TIBu@vr@b?Yr^@Qgq=W{~Frzd0Uk*#k`Z=d>s$`{s~PBK+ZghX8UG7eMU zdq?uQ8(4(3Eo3liic5^+&AG9P(V}Q*=I&h~Uf2i0*8E?$Jo$zQR6p+V~J+P}YqX$54;oSmil zDP8m7jF~I~DmC^Imi5J9Zj}cwh&1BLjc1?UD9Xx`2verSQqldB4w^DaRhI(`7d0Vk zI_T)e7eM4isVuk-S8s0-Mp<5-glPqIC+yyQ1;IBSV_g&Cd@J8#hR}0#N#glJVJziHM6@jfm)tJS(E~D_61w zxyOzxO^dF&C*rG%i!o^KQ<5?iKzIiQfwCEfvNB^o`P)I$rXV-vIGjB^Fml~mel-rb zb3-ft*}O=e*c1EAXPcj{EO{d6%MBHe$nbQ#Vc zJS5@f0=hdMq(EHMpD>@1R&ziyKH7&H=d&(;8i3^&noRfKFuk-W z>jI8OzsRzzKUe-J%1KzW4juskc;uCrHIcn_^ClA4uHzX@OUg5(izrrEVVZp9D`xYmNuK7HC2q#v}Zot2Sa%o#=aZ_CpS0rd?*}8R;*M_-(C z`Quy!vLZLFay~0?la+2x^3&3I0X+ZoX-wa-t=Z5r?70=lj!)p0zPWd`hU>nH5ePSN!5v1?ze>Git$T(ImvF6sE`;6u{SonE zv~f<_f(kP;`JohV!SK+a@0ok3=5rfgaOWoT-}_ZlJiZnr29vg;rjRRNc72i|15PG!;7bV5#Urm~zSVyAy@HByv8)I7uxr zCqApR9aRjMmT*&fUcBn^NjDpxGO`p*h~hh7fC#C!omqj+*I+vx|$kEAO9hP!NW-5%m>BC1Lr)6KYaQz_o2lHsk~aAmoLJa z+q!#NYBN*CpRyRu38iRDE?;8BGbi}5>c0y+d#NVmi0qv_jfIz%f6_J~OxsiB(F9&; zP$QxhOWF{P^w>RGhpUdW`X^1Zl4tel?5Emv3Mcck&)ZCvbg>CxnyB*nb?kfW2~b32 zjx^NPvU>1l99jO;(PDF+RU4~&5>IUs1*1e<#=cMZAyGeeg4WShJ~FI~r7MMv2cBNU zLqb!$E%!G04XY_g-Vz;w2%0jPr+wV~{rE{8im)g}bawy#R?9PL?`;ihH^QwcX03jk o{f4bYz})x#M%di{*e`ATkCzM%f0ZjQ7XSbN07*qoM6N<$f-*jeaR2}S literal 0 HcmV?d00001 diff --git a/WireGuard.xcodeproj/project.pbxproj b/WireGuard.xcodeproj/project.pbxproj index c2c2713..fead2ea 100644 --- a/WireGuard.xcodeproj/project.pbxproj +++ b/WireGuard.xcodeproj/project.pbxproj @@ -8,6 +8,8 @@ /* Begin PBXBuildFile section */ 48CF751B34E9703133F1B1AF /* Pods_WireGuard.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 861983CAE8FDC13BC83E7E04 /* Pods_WireGuard.framework */; }; + 4A430E802139DC8F0078172C /* icon_20pt@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4A430E7F2139DC8F0078172C /* icon_20pt@3x.png */; }; + 4A430E842139DCFB0078172C /* icon_60pt@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4A430E832139DCFB0078172C /* icon_60pt@3x.png */; }; 4A4351592124956200261999 /* Validators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A4351582124956200261999 /* Validators.swift */; }; 4A43515A2124956200261999 /* Validators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A4351582124956200261999 /* Validators.swift */; }; 4A43515C21249E5700261999 /* ValidatorsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A43515B21249E5700261999 /* ValidatorsTests.swift */; }; @@ -85,6 +87,9 @@ /* Begin PBXFileReference section */ 0CE52E030FAA93F3BF5747B2 /* Pods-WireGuard.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WireGuard.release.xcconfig"; path = "Pods/Target Support Files/Pods-WireGuard/Pods-WireGuard.release.xcconfig"; sourceTree = ""; }; 25E2BE31A33C8CCE6E79B6EF /* Pods-WireGuard.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WireGuard.debug.xcconfig"; path = "Pods/Target Support Files/Pods-WireGuard/Pods-WireGuard.debug.xcconfig"; sourceTree = ""; }; + 4A430E7F2139DC8F0078172C /* icon_20pt@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon_20pt@3x.png"; sourceTree = ""; }; + 4A430E812139DCCB0078172C /* icon_20pt.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon_20pt.png; sourceTree = ""; }; + 4A430E832139DCFB0078172C /* icon_60pt@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon_60pt@3x.png"; path = "WireGuard/Assets.xcassets/AppIcon.appiconset/icon_60pt@3x.png"; sourceTree = SOURCE_ROOT; }; 4A4351582124956200261999 /* Validators.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Validators.swift; sourceTree = ""; }; 4A43515B21249E5700261999 /* ValidatorsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValidatorsTests.swift; sourceTree = ""; }; 4A4BA6D720B73CBA00223AB8 /* TunnelConfigurationTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelConfigurationTableViewController.swift; sourceTree = ""; }; @@ -223,6 +228,9 @@ 4A4BAD0720B5F4BC00F12B28 /* Resources */ = { isa = PBXGroup; children = ( + 4A430E7F2139DC8F0078172C /* icon_20pt@3x.png */, + 4A430E812139DCCB0078172C /* icon_20pt.png */, + 4A430E832139DCFB0078172C /* icon_60pt@3x.png */, 4A4BAD0520B5F4B500F12B28 /* Settings.bundle */, ); path = Resources; @@ -468,6 +476,8 @@ files = ( 4A4BAD0620B5F4B500F12B28 /* Settings.bundle in Resources */, 4A4BACF020B5F1C100F12B28 /* LaunchScreen.storyboard in Resources */, + 4A430E842139DCFB0078172C /* icon_60pt@3x.png in Resources */, + 4A430E802139DC8F0078172C /* icon_20pt@3x.png in Resources */, 4A4BACED20B5F1C100F12B28 /* Assets.xcassets in Resources */, 4A4BACEB20B5F1BF00F12B28 /* Main.storyboard in Resources */, ); diff --git a/WireGuard/AppDelegate.swift b/WireGuard/AppDelegate.swift index e4b8f1e..2460a9f 100644 --- a/WireGuard/AppDelegate.swift +++ b/WireGuard/AppDelegate.swift @@ -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 + } } diff --git a/WireGuard/Base.lproj/Main.storyboard b/WireGuard/Base.lproj/Main.storyboard index 42a8dfe..ccf19f2 100644 --- a/WireGuard/Base.lproj/Main.storyboard +++ b/WireGuard/Base.lproj/Main.storyboard @@ -86,7 +86,7 @@ - + @@ -486,14 +486,22 @@ - - - - - + + + + + + + + + + + + + @@ -524,7 +532,7 @@ - + diff --git a/WireGuard/Coordinators/AppCoordinator.swift b/WireGuard/Coordinators/AppCoordinator.swift index bf42aa8..5bb83e2 100644 --- a/WireGuard/Coordinators/AppCoordinator.swift +++ b/WireGuard/Coordinators/AppCoordinator.swift @@ -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) } diff --git a/WireGuard/Info.plist b/WireGuard/Info.plist index f3073e3..f3d505d 100644 --- a/WireGuard/Info.plist +++ b/WireGuard/Info.plist @@ -2,10 +2,35 @@ - NSCameraUsageDescription - Camera is used to scan QR codes + CFBundleDisplayName + ${PRODUCT_NAME} CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) + CFBundleDocumentTypes + + + CFBundleTypeExtensions + + + + CFBundleTypeIconFiles + + icon_20pt + icon_20pt@3x + icon_60pt@3x + + CFBundleTypeName + WireGuard configuration + CFBundleTypeRole + Viewer + LSHandlerRank + Owner + LSItemContentTypes + + com.wireguard.config.quick + + + CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -22,6 +47,12 @@ auto-generated LSRequiresIPhoneOS + LSSupportsOpeningDocumentsInPlace + + UIFileSharingEnabled + + NSCameraUsageDescription + Camera is used to scan QR codes UILaunchStoryboardName LaunchScreen UIRequiredDeviceCapabilities @@ -45,5 +76,51 @@ UIViewControllerBasedStatusBarAppearance + UTExportedTypeDeclarations + + + UTTypeTagSpecification + + public.filename-extension + conf + + UTTypeConformsTo + + public.data + + UTTypeDescription + WireGuard configuration + UTTypeIconFiles + + icon_20pt@3x + icon_60pt@3x + + UTTypeIdentifier + com.wireguard.config.quick + + + UTImportedTypeDeclarations + + + UTTypeTagSpecification + + public.filename-extension + conf + + UTTypeConformsTo + + public.data + + UTTypeDescription + WireGuard configuration + UTTypeIconFiles + + icon_20pt@3x + icon_60pt@3x + + UTTypeIdentifier + com.wireguard.config.quick + + diff --git a/WireGuard/ViewControllers/TunnelConfigurationTableViewController.swift b/WireGuard/ViewControllers/TunnelConfigurationTableViewController.swift index 77141fe..9a4a7e5 100644 --- a/WireGuard/ViewControllers/TunnelConfigurationTableViewController.swift +++ b/WireGuard/ViewControllers/TunnelConfigurationTableViewController.swift @@ -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 } diff --git a/icon_20pt.png b/icon_20pt.png new file mode 100644 index 0000000000000000000000000000000000000000..78f07921867072e97b356b796f199e9de20a33a2 GIT binary patch literal 730 zcmV<00ww*4P)Px%lu1NER5%f>R9#3@Q5^qmZEd6pc*1(MDA+t@%q=X#YlV0}pmj&^n6^jjA;+N^*`Bq%OQ7&1dF zyLtsX&Ys}~LViDHN5|kecL83vo8M;*Nz6)Mu~wmALe1e%2Al6uJ>J>vm>zg7fCdugP_EIS;9w=bkBs2e&0CPEl&I_O zM2^KGD7az{Gq)9?*8UJOrIL^%kqAbgIAAC*2fY+VlW{AkU@%5Fu7_f&6gBM+z~<0( z?>+|ZG!b%s#eR5(hapQzfi^EMMvPs=ElOr#A(EJI-93-dd#!;GS+C3|>PgGc6ovV( zUzQ2R^)MU=5U@Nol_${@jhQztWNk0TWN#l9=YH^KoDsLmey7xEjAtsSbUI8te}T4A3%~tcHsbqLz z5uL~D@pEbl&n{iYWM4nD1_LzA_wNu4IlQodc54;EZaG{7DinlRB4K)O=@0+!!ypnb ze;@=sjQ*>;tD9UqYikR#ExTa3cpe*eml1F0#wVho#9r~Hun0wZIu0=nt}_{Va=_<9 zN8K^ZxLo`mXCxG4ffBi#+-IH1gxT?Nj5(f?*5O2==T!+t6B60K0kHef-S6y#EdT%j M07*qoM6N<$g6rQ%^Z)<= literal 0 HcmV?d00001