From 6857a579b3281c42fea2a676cabc7680f4cca814 Mon Sep 17 00:00:00 2001 From: Roopesh Chander Date: Thu, 15 Nov 2018 13:29:49 +0530 Subject: [PATCH] Exporting: Refactor out zip exporting into a separate class --- WireGuard/WireGuard.xcodeproj/project.pbxproj | 4 +++ .../WireGuard/UI/iOS/ErrorPresenter.swift | 6 ++++ .../UI/iOS/SettingsTableViewController.swift | 32 +++++++------------ .../WireGuard/ZipArchive/ZipExporter.swift | 28 ++++++++++++++++ 4 files changed, 49 insertions(+), 21 deletions(-) create mode 100644 WireGuard/WireGuard/ZipArchive/ZipExporter.swift diff --git a/WireGuard/WireGuard.xcodeproj/project.pbxproj b/WireGuard/WireGuard.xcodeproj/project.pbxproj index 8630b58..1474a98 100644 --- a/WireGuard/WireGuard.xcodeproj/project.pbxproj +++ b/WireGuard/WireGuard.xcodeproj/project.pbxproj @@ -39,6 +39,7 @@ 6FDEF806218725D200D8FBF6 /* SettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FDEF805218725D200D8FBF6 /* SettingsTableViewController.swift */; }; 6FDEF8082187442100D8FBF6 /* WgQuickConfigFileWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FDEF8072187442100D8FBF6 /* WgQuickConfigFileWriter.swift */; }; 6FE254FB219C10800028284D /* ZipImporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FE254FA219C10800028284D /* ZipImporter.swift */; }; + 6FE254FF219C60290028284D /* ZipExporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FE254FE219C60290028284D /* ZipExporter.swift */; }; 6FF4AC1F211EC472002C96EB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6FF4AC1E211EC472002C96EB /* Assets.xcassets */; }; 6FF4AC22211EC472002C96EB /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6FF4AC20211EC472002C96EB /* LaunchScreen.storyboard */; }; 6FFA5D8921942F320001E2F7 /* PacketTunnelSettingsGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F5D0C472183C6A3000F85AD /* PacketTunnelSettingsGenerator.swift */; }; @@ -127,6 +128,7 @@ 6FDEF805218725D200D8FBF6 /* SettingsTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsTableViewController.swift; sourceTree = ""; }; 6FDEF8072187442100D8FBF6 /* WgQuickConfigFileWriter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WgQuickConfigFileWriter.swift; sourceTree = ""; }; 6FE254FA219C10800028284D /* ZipImporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZipImporter.swift; sourceTree = ""; }; + 6FE254FE219C60290028284D /* ZipExporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZipExporter.swift; sourceTree = ""; }; 6FF4AC14211EC46F002C96EB /* WireGuard.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WireGuard.app; sourceTree = BUILT_PRODUCTS_DIR; }; 6FF4AC1E211EC472002C96EB /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 6FF4AC21211EC472002C96EB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; @@ -269,6 +271,7 @@ isa = PBXGroup; children = ( 6FE254FA219C10800028284D /* ZipImporter.swift */, + 6FE254FE219C60290028284D /* ZipExporter.swift */, 6FDEF801218646B900D8FBF6 /* ZipArchive.swift */, 6FDEF7F421863B6100D8FBF6 /* 3rdparty */, ); @@ -520,6 +523,7 @@ 6F7774E421718281006A79B3 /* TunnelsListTableViewController.swift in Sources */, 6F7774EF21722D97006A79B3 /* TunnelsManager.swift in Sources */, 6BB8400421892C920003598F /* CopyableLabelTableViewCell.swift in Sources */, + 6FE254FF219C60290028284D /* ZipExporter.swift in Sources */, 6F693A562179E556008551C1 /* Endpoint.swift in Sources */, 6F0068572191AFD200419BE9 /* ScrollableLabel.swift in Sources */, 6FDEF7E62185EFB200D8FBF6 /* QRScanViewController.swift in Sources */, diff --git a/WireGuard/WireGuard/UI/iOS/ErrorPresenter.swift b/WireGuard/WireGuard/UI/iOS/ErrorPresenter.swift index abc0083..8aa0c1a 100644 --- a/WireGuard/WireGuard/UI/iOS/ErrorPresenter.swift +++ b/WireGuard/WireGuard/UI/iOS/ErrorPresenter.swift @@ -32,6 +32,12 @@ class ErrorPresenter { case ZipImporterError.noTunnelsInZipArchive: return ("No tunnels in zip archive", "No .conf tunnel files were found inside the zip archive.") + // Exporting a zip file + case ZipArchiveError.cantOpenOutputZipFileForWriting: + return ("Unable to create zip archive", "Could not create a zip file in the app's document directory.") + case ZipExporterError.noTunnelsToExport: + return ("Nothing to export", "There are no tunnels to export") + default: os_log("ErrorPresenter: Error not presented: %{public}@", log: OSLog.default, type: .error, "\(error)") return nil diff --git a/WireGuard/WireGuard/UI/iOS/SettingsTableViewController.swift b/WireGuard/WireGuard/UI/iOS/SettingsTableViewController.swift index 4024213..dc2e27e 100644 --- a/WireGuard/WireGuard/UI/iOS/SettingsTableViewController.swift +++ b/WireGuard/WireGuard/UI/iOS/SettingsTableViewController.swift @@ -63,20 +63,7 @@ class SettingsTableViewController: UITableViewController { } func exportConfigurationsAsZipFile(sourceView: UIView) { - guard let tunnelsManager = tunnelsManager, tunnelsManager.numberOfTunnels() > 0 else { - showErrorAlert(title: "Nothing to export", message: "There are no tunnels to export") - return - } - var inputsToArchiver: [(fileName: String, contents: Data)] = [] - for i in 0 ..< tunnelsManager.numberOfTunnels() { - guard let tunnelConfiguration = tunnelsManager.tunnel(at: i).tunnelConfiguration() else { continue } - if let contents = WgQuickConfigFileWriter.writeConfigFile(from: tunnelConfiguration) { - let name = tunnelConfiguration.interface.name - assert(name != tunnelsManager.tunnel(at: i - 1).name) - inputsToArchiver.append((fileName: "\(name).conf", contents: contents)) - } - } - + guard let tunnelsManager = tunnelsManager else { return } guard let destinationDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return } @@ -87,16 +74,19 @@ class SettingsTableViewController: UITableViewController { os_log("Failed to delete file: %{public}@ : %{public}@", log: OSLog.default, type: .error, destinationURL.absoluteString, error.localizedDescription) } + let count = tunnelsManager.numberOfTunnels() + let tunnelConfigurations = (0 ..< count).compactMap { tunnelsManager.tunnel(at: $0).tunnelConfiguration() } do { - try ZipArchive.archive(inputs: inputsToArchiver, to: destinationURL) - let activityVC = UIActivityViewController(activityItems: [destinationURL], applicationActivities: nil) - // popoverPresentationController shall be non-nil on the iPad - activityVC.popoverPresentationController?.sourceView = sourceView - activityVC.popoverPresentationController?.sourceRect = sourceView.bounds - present(activityVC, animated: true) + try ZipExporter.exportConfigFiles(tunnelConfigurations: tunnelConfigurations, to: destinationURL) } catch (let error) { - showErrorAlert(title: "Unable to export", message: "There was an error exporting the tunnel configuration archive: \(String(describing: error))") + ErrorPresenter.showErrorAlert(error: error, from: self) } + + let activityVC = UIActivityViewController(activityItems: [destinationURL], applicationActivities: nil) + // popoverPresentationController shall be non-nil on the iPad + activityVC.popoverPresentationController?.sourceView = sourceView + activityVC.popoverPresentationController?.sourceRect = sourceView.bounds + present(activityVC, animated: true) } func showErrorAlert(title: String, message: String) { diff --git a/WireGuard/WireGuard/ZipArchive/ZipExporter.swift b/WireGuard/WireGuard/ZipArchive/ZipExporter.swift new file mode 100644 index 0000000..d0cf9a7 --- /dev/null +++ b/WireGuard/WireGuard/ZipArchive/ZipExporter.swift @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT +// Copyright © 2018 WireGuard LLC. All Rights Reserved. + +import UIKit + +enum ZipExporterError: Error { + case noTunnelsToExport +} + +class ZipExporter { + static func exportConfigFiles(tunnelConfigurations: [TunnelConfiguration], to destinationURL: URL) throws { + + guard (!tunnelConfigurations.isEmpty) else { throw ZipExporterError.noTunnelsToExport } + + var inputsToArchiver: [(fileName: String, contents: Data)] = [] + + var lastTunnelName: String = "" + for tunnelConfiguration in tunnelConfigurations { + if let contents = WgQuickConfigFileWriter.writeConfigFile(from: tunnelConfiguration) { + let name = tunnelConfiguration.interface.name + if (name.isEmpty || name == lastTunnelName) { continue } + inputsToArchiver.append((fileName: "\(name).conf", contents: contents)) + lastTunnelName = name + } + } + try ZipArchive.archive(inputs: inputsToArchiver, to: destinationURL) + } +}