Refactor import logic into HostImporter
Cover the parsing steps + passphrase. Leave name and credentials as is.
This commit is contained in:
parent
0c8ccd8cc3
commit
68da29474b
|
@ -33,6 +33,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDele
|
||||||
|
|
||||||
var window: UIWindow?
|
var window: UIWindow?
|
||||||
|
|
||||||
|
private var importer: HostImporter?
|
||||||
|
|
||||||
override init() {
|
override init() {
|
||||||
AppConstants.Log.configure()
|
AppConstants.Log.configure()
|
||||||
super.init()
|
super.init()
|
||||||
|
@ -101,26 +103,13 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDele
|
||||||
}
|
}
|
||||||
|
|
||||||
private func tryParseURL(_ url: URL, passphrase: String?, target: UIViewController) -> Bool {
|
private func tryParseURL(_ url: URL, passphrase: String?, target: UIViewController) -> Bool {
|
||||||
let passphraseBlock = { (passphrase) in
|
guard let rootViewController = window?.rootViewController else {
|
||||||
_ = self.tryParseURL(url, passphrase: passphrase, target: target)
|
return false
|
||||||
}
|
}
|
||||||
let passphraseCancelBlock = {
|
importer = HostImporter(withConfigurationURL: url, parentViewController: rootViewController)
|
||||||
_ = try? FileManager.default.removeItem(at: url)
|
importer?.importHost(withPassphrase: passphrase, removeOnError: true, removeOnCancel: true) {
|
||||||
|
self.handleParsingResult($0, in: rootViewController)
|
||||||
}
|
}
|
||||||
guard let parsingResult = OpenVPN.ConfigurationParser.Result.from(url, withErrorAlertIn: target, passphrase: passphrase, removeOnError: true, passphraseBlock: passphraseBlock, passphraseCancelBlock: passphraseCancelBlock) else {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if let warning = parsingResult.warning {
|
|
||||||
OpenVPN.ConfigurationParser.Result.alertImportWarning(url: url, in: target, withWarning: warning) {
|
|
||||||
if $0 {
|
|
||||||
self.handleParsingResult(parsingResult, in: target)
|
|
||||||
} else {
|
|
||||||
try? FileManager.default.removeItem(at: url)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
handleParsingResult(parsingResult, in: target)
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,148 +0,0 @@
|
||||||
//
|
|
||||||
// OpenVPN.ConfigurationParserResult+Alerts.swift
|
|
||||||
// Passepartout-iOS
|
|
||||||
//
|
|
||||||
// Created by Davide De Rosa on 10/27/18.
|
|
||||||
// Copyright (c) 2019 Davide De Rosa. All rights reserved.
|
|
||||||
//
|
|
||||||
// https://github.com/passepartoutvpn
|
|
||||||
//
|
|
||||||
// This file is part of Passepartout.
|
|
||||||
//
|
|
||||||
// Passepartout is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// Passepartout is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import UIKit
|
|
||||||
import TunnelKit
|
|
||||||
import SwiftyBeaver
|
|
||||||
import PassepartoutCore
|
|
||||||
|
|
||||||
private let log = SwiftyBeaver.self
|
|
||||||
|
|
||||||
extension OpenVPN.ConfigurationParser.Result {
|
|
||||||
static func from(_ url: URL, withErrorAlertIn viewController: UIViewController, passphrase: String?, removeOnError: Bool,
|
|
||||||
passphraseBlock: @escaping (String) -> Void, passphraseCancelBlock: (() -> Void)?) -> OpenVPN.ConfigurationParser.Result? {
|
|
||||||
|
|
||||||
let result: OpenVPN.ConfigurationParser.Result
|
|
||||||
let fm = FileManager.default
|
|
||||||
|
|
||||||
log.debug("Parsing configuration URL: \(url)")
|
|
||||||
do {
|
|
||||||
result = try OpenVPN.ConfigurationParser.parsed(fromURL: url, passphrase: passphrase)
|
|
||||||
} catch let e as ConfigurationError {
|
|
||||||
switch e {
|
|
||||||
case .encryptionPassphrase, .unableToDecrypt(_):
|
|
||||||
let alert = UIAlertController.asAlert(url.normalizedFilename, L10n.Core.ParsedFile.Alerts.EncryptionPassphrase.message)
|
|
||||||
alert.addTextField { (field) in
|
|
||||||
field.isSecureTextEntry = true
|
|
||||||
}
|
|
||||||
alert.addPreferredAction(L10n.Core.Global.ok) {
|
|
||||||
guard let passphrase = alert.textFields?.first?.text else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
passphraseBlock(passphrase)
|
|
||||||
}
|
|
||||||
alert.addCancelAction(L10n.Core.Global.cancel) {
|
|
||||||
passphraseCancelBlock?()
|
|
||||||
}
|
|
||||||
viewController.present(alert, animated: true, completion: nil)
|
|
||||||
|
|
||||||
default:
|
|
||||||
let message = localizedMessage(forError: e)
|
|
||||||
alertImportError(url: url, in: viewController, withMessage: message)
|
|
||||||
if removeOnError {
|
|
||||||
try? fm.removeItem(at: url)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
} catch let e {
|
|
||||||
let message = localizedMessage(forError: e)
|
|
||||||
alertImportError(url: url, in: viewController, withMessage: message)
|
|
||||||
if removeOnError {
|
|
||||||
try? fm.removeItem(at: url)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
private static func alertImportError(url: URL, in vc: UIViewController, withMessage message: String) {
|
|
||||||
let alert = UIAlertController.asAlert(url.normalizedFilename, message)
|
|
||||||
// alert.addPreferredAction(L10n.Core.ParsedFile.Alerts.Buttons.report) {
|
|
||||||
// var attach = IssueReporter.Attachments(debugLog: false, configurationURL: url)
|
|
||||||
// attach.description = message
|
|
||||||
// IssueReporter.shared.present(in: vc, withAttachments: attach)
|
|
||||||
// }
|
|
||||||
alert.addCancelAction(L10n.Core.Global.ok)
|
|
||||||
vc.present(alert, animated: true, completion: nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
static func alertImportWarning(url: URL, in vc: UIViewController, withWarning warning: ConfigurationError, completionHandler: @escaping (Bool) -> Void) {
|
|
||||||
let message = details(forWarning: warning)
|
|
||||||
let alert = UIAlertController.asAlert(url.normalizedFilename, L10n.Core.ParsedFile.Alerts.PotentiallyUnsupported.message(message))
|
|
||||||
alert.addPreferredAction(L10n.Core.Global.ok) {
|
|
||||||
completionHandler(true)
|
|
||||||
}
|
|
||||||
alert.addCancelAction(L10n.Core.Global.cancel) {
|
|
||||||
completionHandler(false)
|
|
||||||
}
|
|
||||||
vc.present(alert, animated: true, completion: nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
private static func localizedMessage(forError error: Error) -> String {
|
|
||||||
if let appError = error as? ConfigurationError {
|
|
||||||
switch appError {
|
|
||||||
case .malformed(let option):
|
|
||||||
log.error("Could not parse configuration URL: malformed option, \(option)")
|
|
||||||
return L10n.Core.ParsedFile.Alerts.Malformed.message(option)
|
|
||||||
|
|
||||||
case .missingConfiguration(let option):
|
|
||||||
log.error("Could not parse configuration URL: missing configuration, \(option)")
|
|
||||||
return L10n.Core.ParsedFile.Alerts.Missing.message(option)
|
|
||||||
|
|
||||||
case .unsupportedConfiguration(var option):
|
|
||||||
if option.contains("external") {
|
|
||||||
option.append(" - see FAQ")
|
|
||||||
}
|
|
||||||
log.error("Could not parse configuration URL: unsupported configuration, \(option)")
|
|
||||||
return L10n.Core.ParsedFile.Alerts.Unsupported.message(option)
|
|
||||||
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log.error("Could not parse configuration URL: \(error)")
|
|
||||||
return L10n.Core.ParsedFile.Alerts.Parsing.message(error.localizedDescription)
|
|
||||||
}
|
|
||||||
|
|
||||||
private static func details(forWarning warning: ConfigurationError) -> String {
|
|
||||||
switch warning {
|
|
||||||
case .malformed(let option):
|
|
||||||
return option
|
|
||||||
|
|
||||||
case .missingConfiguration(let option):
|
|
||||||
return option
|
|
||||||
|
|
||||||
case .unsupportedConfiguration(var option):
|
|
||||||
if option.contains("external") {
|
|
||||||
option.append(" - see FAQ")
|
|
||||||
}
|
|
||||||
return option
|
|
||||||
|
|
||||||
default:
|
|
||||||
return "" // XXX: should never get here
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,170 @@
|
||||||
|
//
|
||||||
|
// HostImporter.swift
|
||||||
|
// Passepartout-macOS
|
||||||
|
//
|
||||||
|
// Created by Davide De Rosa on 10/22/19.
|
||||||
|
// Copyright (c) 2019 Davide De Rosa. All rights reserved.
|
||||||
|
//
|
||||||
|
// https://github.com/passepartoutvpn
|
||||||
|
//
|
||||||
|
// This file is part of Passepartout.
|
||||||
|
//
|
||||||
|
// Passepartout is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Passepartout is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import PassepartoutCore
|
||||||
|
import TunnelKit
|
||||||
|
import SwiftyBeaver
|
||||||
|
|
||||||
|
private let log = SwiftyBeaver.self
|
||||||
|
|
||||||
|
class HostImporter {
|
||||||
|
private let service = TransientStore.shared.service
|
||||||
|
|
||||||
|
private weak var viewController: UIViewController?
|
||||||
|
|
||||||
|
private let configurationURL: URL
|
||||||
|
|
||||||
|
init(withConfigurationURL configurationURL: URL, parentViewController: UIViewController) {
|
||||||
|
self.configurationURL = configurationURL
|
||||||
|
log.debug("Parsing configuration URL: \(configurationURL)")
|
||||||
|
|
||||||
|
viewController = parentViewController
|
||||||
|
}
|
||||||
|
|
||||||
|
func importHost(withPassphrase passphrase: String?, removeOnError: Bool, removeOnCancel: Bool, completionHandler: @escaping (OpenVPN.ConfigurationParser.Result) -> Void) {
|
||||||
|
let result: OpenVPN.ConfigurationParser.Result
|
||||||
|
do {
|
||||||
|
result = try OpenVPN.ConfigurationParser.parsed(fromURL: configurationURL, passphrase: passphrase)
|
||||||
|
} catch let e as ConfigurationError {
|
||||||
|
switch e {
|
||||||
|
case .encryptionPassphrase, .unableToDecrypt(_):
|
||||||
|
enterPassphraseForHost(at: configurationURL, removeOnError: removeOnError, removeOnCancel: removeOnCancel, completionHandler: completionHandler)
|
||||||
|
|
||||||
|
default:
|
||||||
|
alertImportError(e, removeOnError: removeOnError)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
} catch let e {
|
||||||
|
alertImportError(e, removeOnError: removeOnError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if let warning = result.warning {
|
||||||
|
alertImportWarning(warning, removeOnCancel: removeOnCancel) {
|
||||||
|
completionHandler(result)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
completionHandler(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func alertImportError(_ error: Error, removeOnError: Bool) {
|
||||||
|
let message = HostImporter.localizedMessage(forError: error)
|
||||||
|
let alert = UIAlertController.asAlert(configurationURL.normalizedFilename, message)
|
||||||
|
alert.addCancelAction(L10n.Core.Global.ok)
|
||||||
|
viewController?.present(alert, animated: true, completion: nil)
|
||||||
|
|
||||||
|
if removeOnError {
|
||||||
|
try? FileManager.default.removeItem(at: configurationURL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func alertImportWarning(_ warning: ConfigurationError, removeOnCancel: Bool, completionHandler: @escaping () -> Void) {
|
||||||
|
let message = HostImporter.localizedDetailsMessage(forWarning: warning)
|
||||||
|
let alert = UIAlertController.asAlert(configurationURL.normalizedFilename, L10n.Core.ParsedFile.Alerts.PotentiallyUnsupported.message(message))
|
||||||
|
alert.addPreferredAction(L10n.Core.Global.ok) {
|
||||||
|
completionHandler()
|
||||||
|
}
|
||||||
|
alert.addCancelAction(L10n.Core.Global.cancel) {
|
||||||
|
if removeOnCancel {
|
||||||
|
try? FileManager.default.removeItem(at: self.configurationURL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
viewController?.present(alert, animated: true, completion: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func enterPassphraseForHost(at url: URL, removeOnError: Bool, removeOnCancel: Bool, completionHandler: @escaping (OpenVPN.ConfigurationParser.Result) -> Void) {
|
||||||
|
let alert = UIAlertController.asAlert(configurationURL.normalizedFilename, L10n.Core.ParsedFile.Alerts.EncryptionPassphrase.message)
|
||||||
|
alert.addTextField { (field) in
|
||||||
|
field.isSecureTextEntry = true
|
||||||
|
}
|
||||||
|
alert.addPreferredAction(L10n.Core.Global.ok) {
|
||||||
|
guard let passphrase = alert.textFields?.first?.text else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.importHost(
|
||||||
|
withPassphrase: passphrase,
|
||||||
|
removeOnError: removeOnError,
|
||||||
|
removeOnCancel: removeOnCancel,
|
||||||
|
completionHandler: completionHandler
|
||||||
|
)
|
||||||
|
}
|
||||||
|
alert.addCancelAction(L10n.Core.Global.cancel) {
|
||||||
|
if removeOnCancel {
|
||||||
|
try? FileManager.default.removeItem(at: url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
viewController?.present(alert, animated: true, completion: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: Helpers
|
||||||
|
|
||||||
|
private static func localizedMessage(forError error: Error) -> String {
|
||||||
|
if let appError = error as? ConfigurationError {
|
||||||
|
switch appError {
|
||||||
|
case .malformed(let option):
|
||||||
|
log.error("Could not parse configuration URL: malformed option, \(option)")
|
||||||
|
return L10n.Core.ParsedFile.Alerts.Malformed.message(option)
|
||||||
|
|
||||||
|
case .missingConfiguration(let option):
|
||||||
|
log.error("Could not parse configuration URL: missing configuration, \(option)")
|
||||||
|
return L10n.Core.ParsedFile.Alerts.Missing.message(option)
|
||||||
|
|
||||||
|
case .unsupportedConfiguration(var option):
|
||||||
|
if option.contains("external") {
|
||||||
|
option.append(" (see FAQ)")
|
||||||
|
}
|
||||||
|
log.error("Could not parse configuration URL: unsupported configuration, \(option)")
|
||||||
|
return L10n.Core.ParsedFile.Alerts.Unsupported.message(option)
|
||||||
|
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.error("Could not parse configuration URL: \(error)")
|
||||||
|
return L10n.Core.ParsedFile.Alerts.Parsing.message(error.localizedDescription)
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func localizedDetailsMessage(forWarning warning: ConfigurationError) -> String {
|
||||||
|
switch warning {
|
||||||
|
case .malformed(let option):
|
||||||
|
return option
|
||||||
|
|
||||||
|
case .missingConfiguration(let option):
|
||||||
|
return option
|
||||||
|
|
||||||
|
case .unsupportedConfiguration(var option):
|
||||||
|
if option.contains("external") {
|
||||||
|
option.append(" (see FAQ)")
|
||||||
|
}
|
||||||
|
return option
|
||||||
|
|
||||||
|
default:
|
||||||
|
return "" // XXX: should never get here
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -33,6 +33,8 @@ private let log = SwiftyBeaver.self
|
||||||
class ImportedHostsViewController: UITableViewController {
|
class ImportedHostsViewController: UITableViewController {
|
||||||
private lazy var pendingConfigurationURLs = TransientStore.shared.service.pendingConfigurationURLs().sortedCaseInsensitive()
|
private lazy var pendingConfigurationURLs = TransientStore.shared.service.pendingConfigurationURLs().sortedCaseInsensitive()
|
||||||
|
|
||||||
|
private var importer: HostImporter?
|
||||||
|
|
||||||
private var parsingResult: OpenVPN.ConfigurationParser.Result?
|
private var parsingResult: OpenVPN.ConfigurationParser.Result?
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
|
@ -76,35 +78,20 @@ class ImportedHostsViewController: UITableViewController {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
let url = pendingConfigurationURLs[indexPath.row]
|
let url = pendingConfigurationURLs[indexPath.row]
|
||||||
return tryParseURL(url, passphrase: nil, cell: cell)
|
return tryParseURL(url, cell: cell)
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
private func tryParseURL(_ url: URL, passphrase: String?, cell: UITableViewCell) -> Bool {
|
private func tryParseURL(_ url: URL, cell: UITableViewCell) -> Bool {
|
||||||
let passphraseBlock: (String) -> Void = { (passphrase) in
|
importer = HostImporter(withConfigurationURL: url, parentViewController: self)
|
||||||
guard self.tryParseURL(url, passphrase: passphrase, cell: cell) else {
|
importer?.importHost(withPassphrase: nil, removeOnError: false, removeOnCancel: false) {
|
||||||
return
|
|
||||||
}
|
|
||||||
self.perform(segue: StoryboardSegue.Organizer.importHostSegueIdentifier, sender: cell)
|
|
||||||
}
|
|
||||||
guard let parsingResult = OpenVPN.ConfigurationParser.Result.from(url, withErrorAlertIn: self, passphrase: passphrase, removeOnError: false, passphraseBlock: passphraseBlock, passphraseCancelBlock: nil) else {
|
|
||||||
deselectSelectedRow()
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
self.parsingResult = parsingResult
|
|
||||||
|
|
||||||
// postpone segue until alert dismissal
|
// FIXME: HostImporter, also deselect on error/cancel, or just deselect immediately
|
||||||
if let warning = parsingResult.warning {
|
|
||||||
OpenVPN.ConfigurationParser.Result.alertImportWarning(url: url, in: self, withWarning: warning) {
|
|
||||||
self.deselectSelectedRow()
|
self.deselectSelectedRow()
|
||||||
if $0 {
|
|
||||||
|
self.parsingResult = $0
|
||||||
self.perform(segue: StoryboardSegue.Organizer.importHostSegueIdentifier)
|
self.perform(segue: StoryboardSegue.Organizer.importHostSegueIdentifier)
|
||||||
} else {
|
|
||||||
self.parsingResult = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,7 @@
|
||||||
0E3152DA223FA05800F61841 /* PlaceholderConnectionProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E79D13E21919EC900BB5FB2 /* PlaceholderConnectionProfile.swift */; };
|
0E3152DA223FA05800F61841 /* PlaceholderConnectionProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E79D13E21919EC900BB5FB2 /* PlaceholderConnectionProfile.swift */; };
|
||||||
0E3152DB223FA05800F61841 /* ProfileKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E79D14021919F5600BB5FB2 /* ProfileKey.swift */; };
|
0E3152DB223FA05800F61841 /* ProfileKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E79D14021919F5600BB5FB2 /* ProfileKey.swift */; };
|
||||||
0E3152DC223FA05800F61841 /* ProviderConnectionProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBE3AA4213DC1B000BFA2F5 /* ProviderConnectionProfile.swift */; };
|
0E3152DC223FA05800F61841 /* ProviderConnectionProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBE3AA4213DC1B000BFA2F5 /* ProviderConnectionProfile.swift */; };
|
||||||
|
0E3262D9235EE8DA00B5E470 /* HostImporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3262D8235EE8DA00B5E470 /* HostImporter.swift */; };
|
||||||
0E3419AD2350815E00419E18 /* Donation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3419AC2350815E00419E18 /* Donation.swift */; };
|
0E3419AD2350815E00419E18 /* Donation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3419AC2350815E00419E18 /* Donation.swift */; };
|
||||||
0E3586FE225BD34800509A4D /* ActivityTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3586FD225BD34800509A4D /* ActivityTableViewCell.swift */; };
|
0E3586FE225BD34800509A4D /* ActivityTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3586FD225BD34800509A4D /* ActivityTableViewCell.swift */; };
|
||||||
0E36D24D2240234B006AF062 /* ShortcutsAddViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E36D24C2240234B006AF062 /* ShortcutsAddViewController.swift */; };
|
0E36D24D2240234B006AF062 /* ShortcutsAddViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E36D24C2240234B006AF062 /* ShortcutsAddViewController.swift */; };
|
||||||
|
@ -83,7 +84,6 @@
|
||||||
0E89DFCE213EEDFA00741BA1 /* WizardProviderViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E89DFCD213EEDFA00741BA1 /* WizardProviderViewController.swift */; };
|
0E89DFCE213EEDFA00741BA1 /* WizardProviderViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E89DFCD213EEDFA00741BA1 /* WizardProviderViewController.swift */; };
|
||||||
0E9CD7872257462800D033B4 /* Providers.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0E9CD7862257462800D033B4 /* Providers.xcassets */; };
|
0E9CD7872257462800D033B4 /* Providers.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0E9CD7862257462800D033B4 /* Providers.xcassets */; };
|
||||||
0E9CD789225746B300D033B4 /* Flags.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0E9CD788225746B300D033B4 /* Flags.xcassets */; };
|
0E9CD789225746B300D033B4 /* Flags.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0E9CD788225746B300D033B4 /* Flags.xcassets */; };
|
||||||
0EA068F4218475F800C320AD /* ConfigurationParserResult+Alerts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA068F3218475F800C320AD /* ConfigurationParserResult+Alerts.swift */; };
|
|
||||||
0EAAD71920E6669A0088754A /* GroupConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EDE8DED20C93E4C004C739C /* GroupConstants.swift */; };
|
0EAAD71920E6669A0088754A /* GroupConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EDE8DED20C93E4C004C739C /* GroupConstants.swift */; };
|
||||||
0EB60FDA2111136E00AD27F3 /* UITextView+Search.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB60FD92111136E00AD27F3 /* UITextView+Search.swift */; };
|
0EB60FDA2111136E00AD27F3 /* UITextView+Search.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB60FD92111136E00AD27F3 /* UITextView+Search.swift */; };
|
||||||
0EB67D6B2184581E00BA6200 /* ImportedHostsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB67D6A2184581E00BA6200 /* ImportedHostsViewController.swift */; };
|
0EB67D6B2184581E00BA6200 /* ImportedHostsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB67D6A2184581E00BA6200 /* ImportedHostsViewController.swift */; };
|
||||||
|
@ -179,6 +179,7 @@
|
||||||
0E31529B223F9EF400F61841 /* PassepartoutCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = PassepartoutCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
0E31529B223F9EF400F61841 /* PassepartoutCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = PassepartoutCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
0E31529D223F9EF500F61841 /* PassepartoutCore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PassepartoutCore.h; sourceTree = "<group>"; };
|
0E31529D223F9EF500F61841 /* PassepartoutCore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PassepartoutCore.h; sourceTree = "<group>"; };
|
||||||
0E31529E223F9EF500F61841 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
0E31529E223F9EF500F61841 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
|
0E3262D8235EE8DA00B5E470 /* HostImporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostImporter.swift; sourceTree = "<group>"; };
|
||||||
0E3419AC2350815E00419E18 /* Donation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Donation.swift; sourceTree = "<group>"; };
|
0E3419AC2350815E00419E18 /* Donation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Donation.swift; sourceTree = "<group>"; };
|
||||||
0E3586FD225BD34800509A4D /* ActivityTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityTableViewCell.swift; sourceTree = "<group>"; };
|
0E3586FD225BD34800509A4D /* ActivityTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityTableViewCell.swift; sourceTree = "<group>"; };
|
||||||
0E36D24C2240234B006AF062 /* ShortcutsAddViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShortcutsAddViewController.swift; sourceTree = "<group>"; };
|
0E36D24C2240234B006AF062 /* ShortcutsAddViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShortcutsAddViewController.swift; sourceTree = "<group>"; };
|
||||||
|
@ -247,7 +248,6 @@
|
||||||
0E8D97E121388B52006FB4A0 /* InfrastructurePreset.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfrastructurePreset.swift; sourceTree = "<group>"; };
|
0E8D97E121388B52006FB4A0 /* InfrastructurePreset.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfrastructurePreset.swift; sourceTree = "<group>"; };
|
||||||
0E9CD7862257462800D033B4 /* Providers.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Providers.xcassets; sourceTree = "<group>"; };
|
0E9CD7862257462800D033B4 /* Providers.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Providers.xcassets; sourceTree = "<group>"; };
|
||||||
0E9CD788225746B300D033B4 /* Flags.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Flags.xcassets; sourceTree = "<group>"; };
|
0E9CD788225746B300D033B4 /* Flags.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Flags.xcassets; sourceTree = "<group>"; };
|
||||||
0EA068F3218475F800C320AD /* ConfigurationParserResult+Alerts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ConfigurationParserResult+Alerts.swift"; sourceTree = "<group>"; };
|
|
||||||
0EB60FD92111136E00AD27F3 /* UITextView+Search.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITextView+Search.swift"; sourceTree = "<group>"; };
|
0EB60FD92111136E00AD27F3 /* UITextView+Search.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITextView+Search.swift"; sourceTree = "<group>"; };
|
||||||
0EB67D6A2184581E00BA6200 /* ImportedHostsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImportedHostsViewController.swift; sourceTree = "<group>"; };
|
0EB67D6A2184581E00BA6200 /* ImportedHostsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImportedHostsViewController.swift; sourceTree = "<group>"; };
|
||||||
0EBBE8F42182361700106008 /* ConnectionService+Migration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ConnectionService+Migration.swift"; sourceTree = "<group>"; };
|
0EBBE8F42182361700106008 /* ConnectionService+Migration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ConnectionService+Migration.swift"; sourceTree = "<group>"; };
|
||||||
|
@ -534,8 +534,8 @@
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
0E45E6E222BD793800F19312 /* App.strings */,
|
0E45E6E222BD793800F19312 /* App.strings */,
|
||||||
0EA068F3218475F800C320AD /* ConfigurationParserResult+Alerts.swift */,
|
|
||||||
0E3419AC2350815E00419E18 /* Donation.swift */,
|
0E3419AC2350815E00419E18 /* Donation.swift */,
|
||||||
|
0E3262D8235EE8DA00B5E470 /* HostImporter.swift */,
|
||||||
0EFD943D215BE10800529B64 /* IssueReporter.swift */,
|
0EFD943D215BE10800529B64 /* IssueReporter.swift */,
|
||||||
0E4FD7F020D58618002221FF /* Macros.swift */,
|
0E4FD7F020D58618002221FF /* Macros.swift */,
|
||||||
0E24273F225951B00064A1A3 /* ProductManager.swift */,
|
0E24273F225951B00064A1A3 /* ProductManager.swift */,
|
||||||
|
@ -986,6 +986,7 @@
|
||||||
0E05C5D620D1645F006EE732 /* SwiftGen+Scenes.swift in Sources */,
|
0E05C5D620D1645F006EE732 /* SwiftGen+Scenes.swift in Sources */,
|
||||||
0E773BF8224BF37600CDDC8E /* ShortcutsViewController.swift in Sources */,
|
0E773BF8224BF37600CDDC8E /* ShortcutsViewController.swift in Sources */,
|
||||||
0E3419AD2350815E00419E18 /* Donation.swift in Sources */,
|
0E3419AD2350815E00419E18 /* Donation.swift in Sources */,
|
||||||
|
0E3262D9235EE8DA00B5E470 /* HostImporter.swift in Sources */,
|
||||||
0EFD9440215BED8E00529B64 /* LabelViewController.swift in Sources */,
|
0EFD9440215BED8E00529B64 /* LabelViewController.swift in Sources */,
|
||||||
0ED31C2C20CF2D6F0027975F /* ProviderPoolViewController.swift in Sources */,
|
0ED31C2C20CF2D6F0027975F /* ProviderPoolViewController.swift in Sources */,
|
||||||
0E2B494020FCFF990094784C /* Theme+Titles.swift in Sources */,
|
0E2B494020FCFF990094784C /* Theme+Titles.swift in Sources */,
|
||||||
|
@ -1000,7 +1001,6 @@
|
||||||
0EB67D6B2184581E00BA6200 /* ImportedHostsViewController.swift in Sources */,
|
0EB67D6B2184581E00BA6200 /* ImportedHostsViewController.swift in Sources */,
|
||||||
0E57F63E20C83FC5008323CF /* ServiceViewController.swift in Sources */,
|
0E57F63E20C83FC5008323CF /* ServiceViewController.swift in Sources */,
|
||||||
0E36D24D2240234B006AF062 /* ShortcutsAddViewController.swift in Sources */,
|
0E36D24D2240234B006AF062 /* ShortcutsAddViewController.swift in Sources */,
|
||||||
0EA068F4218475F800C320AD /* ConfigurationParserResult+Alerts.swift in Sources */,
|
|
||||||
0E57F63C20C83FC5008323CF /* AppDelegate.swift in Sources */,
|
0E57F63C20C83FC5008323CF /* AppDelegate.swift in Sources */,
|
||||||
0ED31C2920CF2A340027975F /* AccountViewController.swift in Sources */,
|
0ED31C2920CF2A340027975F /* AccountViewController.swift in Sources */,
|
||||||
0E158ADA20E11B0B00C85A82 /* EndpointViewController.swift in Sources */,
|
0E158ADA20E11B0B00C85A82 /* EndpointViewController.swift in Sources */,
|
||||||
|
|
Loading…
Reference in New Issue