Importing: Refactor out zip importing into a separate class
This commit is contained in:
parent
ed1bae8ad0
commit
b2b2818e2e
|
@ -38,6 +38,7 @@
|
||||||
6FDEF802218646BA00D8FBF6 /* ZipArchive.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FDEF801218646B900D8FBF6 /* ZipArchive.swift */; };
|
6FDEF802218646BA00D8FBF6 /* ZipArchive.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FDEF801218646B900D8FBF6 /* ZipArchive.swift */; };
|
||||||
6FDEF806218725D200D8FBF6 /* SettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FDEF805218725D200D8FBF6 /* SettingsTableViewController.swift */; };
|
6FDEF806218725D200D8FBF6 /* SettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FDEF805218725D200D8FBF6 /* SettingsTableViewController.swift */; };
|
||||||
6FDEF8082187442100D8FBF6 /* WgQuickConfigFileWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FDEF8072187442100D8FBF6 /* WgQuickConfigFileWriter.swift */; };
|
6FDEF8082187442100D8FBF6 /* WgQuickConfigFileWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FDEF8072187442100D8FBF6 /* WgQuickConfigFileWriter.swift */; };
|
||||||
|
6FE254FB219C10800028284D /* ZipImporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FE254FA219C10800028284D /* ZipImporter.swift */; };
|
||||||
6FF4AC1F211EC472002C96EB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6FF4AC1E211EC472002C96EB /* Assets.xcassets */; };
|
6FF4AC1F211EC472002C96EB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6FF4AC1E211EC472002C96EB /* Assets.xcassets */; };
|
||||||
6FF4AC22211EC472002C96EB /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6FF4AC20211EC472002C96EB /* LaunchScreen.storyboard */; };
|
6FF4AC22211EC472002C96EB /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6FF4AC20211EC472002C96EB /* LaunchScreen.storyboard */; };
|
||||||
6FFA5D8921942F320001E2F7 /* PacketTunnelSettingsGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F5D0C472183C6A3000F85AD /* PacketTunnelSettingsGenerator.swift */; };
|
6FFA5D8921942F320001E2F7 /* PacketTunnelSettingsGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F5D0C472183C6A3000F85AD /* PacketTunnelSettingsGenerator.swift */; };
|
||||||
|
@ -125,6 +126,7 @@
|
||||||
6FDEF801218646B900D8FBF6 /* ZipArchive.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ZipArchive.swift; sourceTree = "<group>"; };
|
6FDEF801218646B900D8FBF6 /* ZipArchive.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ZipArchive.swift; sourceTree = "<group>"; };
|
||||||
6FDEF805218725D200D8FBF6 /* SettingsTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsTableViewController.swift; sourceTree = "<group>"; };
|
6FDEF805218725D200D8FBF6 /* SettingsTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsTableViewController.swift; sourceTree = "<group>"; };
|
||||||
6FDEF8072187442100D8FBF6 /* WgQuickConfigFileWriter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WgQuickConfigFileWriter.swift; sourceTree = "<group>"; };
|
6FDEF8072187442100D8FBF6 /* WgQuickConfigFileWriter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WgQuickConfigFileWriter.swift; sourceTree = "<group>"; };
|
||||||
|
6FE254FA219C10800028284D /* ZipImporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZipImporter.swift; sourceTree = "<group>"; };
|
||||||
6FF4AC14211EC46F002C96EB /* WireGuard.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WireGuard.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
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 = "<group>"; };
|
6FF4AC1E211EC472002C96EB /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
6FF4AC21211EC472002C96EB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
6FF4AC21211EC472002C96EB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||||
|
@ -266,6 +268,7 @@
|
||||||
6FDEF7E72186320E00D8FBF6 /* ZipArchive */ = {
|
6FDEF7E72186320E00D8FBF6 /* ZipArchive */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
6FE254FA219C10800028284D /* ZipImporter.swift */,
|
||||||
6FDEF801218646B900D8FBF6 /* ZipArchive.swift */,
|
6FDEF801218646B900D8FBF6 /* ZipArchive.swift */,
|
||||||
6FDEF7F421863B6100D8FBF6 /* 3rdparty */,
|
6FDEF7F421863B6100D8FBF6 /* 3rdparty */,
|
||||||
);
|
);
|
||||||
|
@ -529,6 +532,7 @@
|
||||||
6F628C3D217F09E9003482A3 /* TunnelViewModel.swift in Sources */,
|
6F628C3D217F09E9003482A3 /* TunnelViewModel.swift in Sources */,
|
||||||
6F919EC3218A2AE90023B400 /* ErrorPresenter.swift in Sources */,
|
6F919EC3218A2AE90023B400 /* ErrorPresenter.swift in Sources */,
|
||||||
6FDEF8082187442100D8FBF6 /* WgQuickConfigFileWriter.swift in Sources */,
|
6FDEF8082187442100D8FBF6 /* WgQuickConfigFileWriter.swift in Sources */,
|
||||||
|
6FE254FB219C10800028284D /* ZipImporter.swift in Sources */,
|
||||||
6F7774EA217229DB006A79B3 /* IPAddressRange.swift in Sources */,
|
6F7774EA217229DB006A79B3 /* IPAddressRange.swift in Sources */,
|
||||||
6F7774E82172020C006A79B3 /* Configuration.swift in Sources */,
|
6F7774E82172020C006A79B3 /* Configuration.swift in Sources */,
|
||||||
6FDEF7FB21863B6100D8FBF6 /* unzip.c in Sources */,
|
6FDEF7FB21863B6100D8FBF6 /* unzip.c in Sources */,
|
||||||
|
|
|
@ -24,6 +24,14 @@ class ErrorPresenter {
|
||||||
case TunnelActivationError.tunnelActivationFailed:
|
case TunnelActivationError.tunnelActivationFailed:
|
||||||
return ("Activation failure", "The tunnel could not be activated due to an internal error")
|
return ("Activation failure", "The tunnel could not be activated due to an internal error")
|
||||||
|
|
||||||
|
// Importing a zip file
|
||||||
|
case ZipArchiveError.cantOpenInputZipFile:
|
||||||
|
return ("Unable to read zip archive", "The zip archive could not be read.")
|
||||||
|
case ZipArchiveError.badArchive:
|
||||||
|
return ("Unable to read zip archive", "Bad or corrupt zip archive.")
|
||||||
|
case ZipImporterError.noTunnelsInZipArchive:
|
||||||
|
return ("No tunnels in zip archive", "No .conf tunnel files were found inside the zip archive.")
|
||||||
|
|
||||||
default:
|
default:
|
||||||
os_log("ErrorPresenter: Error not presented: %{public}@", log: OSLog.default, type: .error, "\(error)")
|
os_log("ErrorPresenter: Error not presented: %{public}@", log: OSLog.default, type: .error, "\(error)")
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -158,62 +158,28 @@ class TunnelsListTableViewController: UIViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
func importFromFile(url: URL) {
|
func importFromFile(url: URL) {
|
||||||
if (url.pathExtension == "zip") {
|
|
||||||
var unarchivedFiles: [(fileName: String, contents: Data)] = []
|
|
||||||
do {
|
|
||||||
unarchivedFiles = try ZipArchive.unarchive(url: url, requiredFileExtensions: ["conf"])
|
|
||||||
} catch ZipArchiveError.cantOpenInputZipFile {
|
|
||||||
showErrorAlert(title: "Unable to read zip archive", message: "The zip archive could not be read.")
|
|
||||||
return
|
|
||||||
} catch ZipArchiveError.badArchive {
|
|
||||||
showErrorAlert(title: "Unable to read zip archive", message: "Bad or corrupt zip archive.")
|
|
||||||
return
|
|
||||||
} catch (let error) {
|
|
||||||
showErrorAlert(title: "Unable to read zip archive", message: "Unexpected error: \(String(describing: error))")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i, unarchivedFile) in unarchivedFiles.enumerated().reversed() {
|
|
||||||
let fileBaseName = URL(string: unarchivedFile.fileName)?.deletingPathExtension().lastPathComponent
|
|
||||||
if let trimmedName = fileBaseName?.trimmingCharacters(in: .whitespacesAndNewlines), !trimmedName.isEmpty {
|
|
||||||
unarchivedFiles[i].fileName = trimmedName
|
|
||||||
} else {
|
|
||||||
unarchivedFiles.remove(at: i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (unarchivedFiles.isEmpty) {
|
|
||||||
showErrorAlert(title: "No tunnels in zip archive", message: "No .conf tunnel files were found inside the zip archive.")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
guard let tunnelsManager = tunnelsManager else { return }
|
guard let tunnelsManager = tunnelsManager else { return }
|
||||||
unarchivedFiles.sort { $0.fileName < $1.fileName }
|
if (url.pathExtension == "zip") {
|
||||||
var lastFileName: String?
|
let zipImporter = ZipImporter(url: url)
|
||||||
var configs: [TunnelConfiguration] = []
|
let configs: [TunnelConfiguration?]
|
||||||
for file in unarchivedFiles {
|
do {
|
||||||
if file.fileName == lastFileName {
|
configs = try zipImporter.importConfigFiles()
|
||||||
continue
|
} catch (let error) {
|
||||||
|
ErrorPresenter.showErrorAlert(error: error, from: self)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
lastFileName = file.fileName
|
tunnelsManager.addMultiple(tunnelConfigurations: configs.compactMap { $0 }) { [weak self] (numberSuccessful) in
|
||||||
guard let fileContents = String(data: file.contents, encoding: .utf8) else {
|
if numberSuccessful == configs.count {
|
||||||
continue
|
|
||||||
}
|
|
||||||
guard let tunnelConfig = try? WgQuickConfigFileParser.parse(fileContents, name: file.fileName) else {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
configs.append(tunnelConfig)
|
|
||||||
}
|
|
||||||
tunnelsManager.addMultiple(tunnelConfigurations: configs) { [weak self] (numberSuccessful) in
|
|
||||||
if numberSuccessful == unarchivedFiles.count {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self?.showErrorAlert(title: "Created \(numberSuccessful) tunnels",
|
self?.showErrorAlert(title: "Created \(numberSuccessful) tunnels",
|
||||||
message: "Created \(numberSuccessful) of \(unarchivedFiles.count) tunnels from zip archive")
|
message: "Created \(numberSuccessful) of \(configs.count) tunnels from zip archive")
|
||||||
}
|
}
|
||||||
} else /* if (url.pathExtension == "conf") -- we assume everything else is a conf */ {
|
} else /* if (url.pathExtension == "conf") -- we assume everything else is a conf */ {
|
||||||
let fileBaseName = url.deletingPathExtension().lastPathComponent.trimmingCharacters(in: .whitespacesAndNewlines)
|
let fileBaseName = url.deletingPathExtension().lastPathComponent.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||||
if let fileContents = try? String(contentsOf: url),
|
if let fileContents = try? String(contentsOf: url),
|
||||||
let tunnelConfiguration = try? WgQuickConfigFileParser.parse(fileContents, name: fileBaseName) {
|
let tunnelConfiguration = try? WgQuickConfigFileParser.parse(fileContents, name: fileBaseName) {
|
||||||
tunnelsManager?.add(tunnelConfiguration: tunnelConfiguration) { (_, error) in
|
tunnelsManager.add(tunnelConfiguration: tunnelConfiguration) { (_, error) in
|
||||||
if let error = error {
|
if let error = error {
|
||||||
ErrorPresenter.showErrorAlert(error: error, from: self)
|
ErrorPresenter.showErrorAlert(error: error, from: self)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
// Copyright © 2018 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
enum ZipImporterError: Error {
|
||||||
|
case noTunnelsInZipArchive
|
||||||
|
}
|
||||||
|
|
||||||
|
class ZipImporter {
|
||||||
|
let url: URL
|
||||||
|
init(url: URL) {
|
||||||
|
self.url = url
|
||||||
|
}
|
||||||
|
|
||||||
|
func importConfigFiles() throws -> [TunnelConfiguration?] {
|
||||||
|
var unarchivedFiles: [(fileName: String, contents: Data)] = try ZipArchive.unarchive(url: url, requiredFileExtensions: ["conf"])
|
||||||
|
|
||||||
|
for (i, unarchivedFile) in unarchivedFiles.enumerated().reversed() {
|
||||||
|
let fileBaseName = URL(string: unarchivedFile.fileName)?.deletingPathExtension().lastPathComponent
|
||||||
|
if let trimmedName = fileBaseName?.trimmingCharacters(in: .whitespacesAndNewlines), !trimmedName.isEmpty {
|
||||||
|
unarchivedFiles[i].fileName = trimmedName
|
||||||
|
} else {
|
||||||
|
unarchivedFiles.remove(at: i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unarchivedFiles.isEmpty) {
|
||||||
|
throw ZipImporterError.noTunnelsInZipArchive
|
||||||
|
}
|
||||||
|
|
||||||
|
unarchivedFiles.sort { $0.fileName < $1.fileName }
|
||||||
|
var configs = Array<TunnelConfiguration?>(repeating: nil, count: unarchivedFiles.count)
|
||||||
|
for (i, file) in unarchivedFiles.enumerated() {
|
||||||
|
if (i > 0 && file == unarchivedFiles[i - 1]) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
guard let fileContents = String(data: file.contents, encoding: .utf8) else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
guard let tunnelConfig = try? WgQuickConfigFileParser.parse(fileContents, name: file.fileName) else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
configs[i] = tunnelConfig
|
||||||
|
}
|
||||||
|
return configs
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue