Improve alerts on configuration import error

Issue reporting is currently disabled because un unparsed .ovpn
may contain sensitive data.
This commit is contained in:
Davide De Rosa 2018-10-23 10:49:35 +02:00
parent 73e09fefb1
commit 4b075bcc95
7 changed files with 69 additions and 31 deletions

View File

@ -118,17 +118,29 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDele
} }
nav.modalPresentationStyle = .formSheet nav.modalPresentationStyle = .formSheet
root.present(nav, animated: true, completion: nil) root.present(nav, animated: true, completion: nil)
} catch ApplicationError.missingConfiguration(let option) {
let message = L10n.Wizards.Host.Alerts.Missing.message(option)
alertConfigurationImportError(url: url, in: root, withMessage: message)
} catch ApplicationError.unsupportedConfiguration(let option) { } catch ApplicationError.unsupportedConfiguration(let option) {
let alert = Macros.alert(L10n.Organizer.Sections.Hosts.header, L10n.Wizards.Host.Alerts.unsupported(option)) let message = L10n.Wizards.Host.Alerts.Unsupported.message(option)
alert.addCancelAction(L10n.Global.ok) alertConfigurationImportError(url: url, in: root, withMessage: message)
root.present(alert, animated: true, completion: nil)
} catch let e { } catch let e {
let alert = Macros.alert(L10n.Organizer.Sections.Hosts.header, L10n.Wizards.Host.Alerts.parsing(e.localizedDescription)) let message = L10n.Wizards.Host.Alerts.Parsing.message(e.localizedDescription)
alert.addCancelAction(L10n.Global.ok) alertConfigurationImportError(url: url, in: root, withMessage: message)
root.present(alert, animated: true, completion: nil)
} }
return true return true
} }
private func alertConfigurationImportError(url: URL, in vc: UIViewController, withMessage message: String) {
let alert = Macros.alert(L10n.Organizer.Sections.Hosts.header, message)
// alert.addDefaultAction(L10n.Wizards.Host.Alerts.Buttons.report) {
// var attach = IssueReporter.Attachments(debugLog: false, configurationURL: url)
// attach.description = message
// IssueReporter.shared.present(in: vc, withAttachments: attach)
// }
alert.addCancelAction(L10n.Global.cancel)
vc.present(alert, animated: true, completion: nil)
}
} }
extension UISplitViewController { extension UISplitViewController {

View File

@ -33,6 +33,8 @@ class IssueReporter: NSObject {
let configurationURL: URL? let configurationURL: URL?
var description: String?
init(debugLog: Bool, configurationURL: URL?) { init(debugLog: Bool, configurationURL: URL?) {
self.debugLog = debugLog self.debugLog = debugLog
self.configurationURL = configurationURL self.configurationURL = configurationURL
@ -66,23 +68,23 @@ class IssueReporter: NSObject {
let alert = Macros.alert(L10n.IssueReporter.title, L10n.IssueReporter.message) let alert = Macros.alert(L10n.IssueReporter.title, L10n.IssueReporter.message)
alert.addDefaultAction(L10n.IssueReporter.Buttons.accept) { alert.addDefaultAction(L10n.IssueReporter.Buttons.accept) {
VPN.shared.requestDebugLog(fallback: AppConstants.Log.debugSnapshot) { VPN.shared.requestDebugLog(fallback: AppConstants.Log.debugSnapshot) {
self.composeEmail(withDebugLog: $0, configurationURL: attachments.configurationURL) self.composeEmail(withDebugLog: $0, configurationURL: attachments.configurationURL, description: attachments.description)
} }
} }
alert.addCancelAction(L10n.Global.cancel) alert.addCancelAction(L10n.Global.cancel)
viewController.present(alert, animated: true, completion: nil) viewController.present(alert, animated: true, completion: nil)
} else { } else {
composeEmail(withDebugLog: nil, configurationURL: attachments.configurationURL) composeEmail(withDebugLog: nil, configurationURL: attachments.configurationURL, description: attachments.description)
} }
} }
private func composeEmail(withDebugLog debugLog: String?, configurationURL: URL?) { private func composeEmail(withDebugLog debugLog: String?, configurationURL: URL?, description: String?) {
let metadata = DebugLog(raw: "--").decoratedString() let metadata = DebugLog(raw: "--").decoratedString()
let vc = MFMailComposeViewController() let vc = MFMailComposeViewController()
vc.setToRecipients([AppConstants.IssueReporter.recipient]) vc.setToRecipients([AppConstants.IssueReporter.recipient])
vc.setSubject(L10n.IssueReporter.Email.subject(GroupConstants.App.name)) vc.setSubject(L10n.IssueReporter.Email.subject(GroupConstants.App.name))
vc.setMessageBody(L10n.IssueReporter.Email.body(metadata), isHTML: false) vc.setMessageBody(L10n.IssueReporter.Email.body(description ?? L10n.IssueReporter.Email.description, metadata), isHTML: false)
if let raw = debugLog { if let raw = debugLog {
let attachment = DebugLog(raw: raw).decoratedData() let attachment = DebugLog(raw: raw).decoratedData()
vc.addAttachmentData(attachment, mimeType: AppConstants.IssueReporter.MIME.debugLog, fileName: AppConstants.IssueReporter.Filenames.debugLog) vc.addAttachmentData(attachment, mimeType: AppConstants.IssueReporter.MIME.debugLog, fileName: AppConstants.IssueReporter.Filenames.debugLog)

View File

@ -134,7 +134,7 @@ class WizardHostViewController: UITableViewController, TableModelHost, Wizard {
profile.parameters = file.configuration profile.parameters = file.configuration
guard !TransientStore.shared.service.containsProfile(profile) else { guard !TransientStore.shared.service.containsProfile(profile) else {
let alert = Macros.alert(title, L10n.Wizards.Host.Alerts.existing) let alert = Macros.alert(title, L10n.Wizards.Host.Alerts.Existing.message)
alert.addDefaultAction(L10n.Global.ok) { alert.addDefaultAction(L10n.Global.ok) {
self.next(withProfile: profile) self.next(withProfile: profile)
} }

View File

@ -51,9 +51,11 @@
"wizards.host.cells.title_input.caption" = "Title"; "wizards.host.cells.title_input.caption" = "Title";
"wizards.host.cells.title_input.placeholder" = "My Profile"; "wizards.host.cells.title_input.placeholder" = "My Profile";
"wizards.host.sections.existing.header" = "Existing profiles"; "wizards.host.sections.existing.header" = "Existing profiles";
"wizards.host.alerts.existing" = "A host profile with the same title already exists. Replace it?"; "wizards.host.alerts.existing.message" = "A host profile with the same title already exists. Replace it?";
"wizards.host.alerts.unsupported" = "The configuration file contains an unsupported option (%@)."; "wizards.host.alerts.missing.message" = "The configuration file lacks a required option (%@).";
"wizards.host.alerts.parsing" = "Unable to parse the provided configuration file (%@)."; "wizards.host.alerts.unsupported.message" = "The configuration file contains an unsupported option (%@).";
"wizards.host.alerts.parsing.message" = "Unable to parse the provided configuration file (%@).";
"wizards.host.alerts.buttons.report" = "Report an issue";
"service.welcome.message" = "Welcome to Passepartout!\n\nUse the organizer to add a new profile."; "service.welcome.message" = "Welcome to Passepartout!\n\nUse the organizer to add a new profile.";
"service.sections.general.header" = "General"; "service.sections.general.header" = "General";
@ -175,7 +177,8 @@
"issue_reporter.buttons.accept" = "I understand"; "issue_reporter.buttons.accept" = "I understand";
"issue_reporter.alerts.email_not_configured.message" = "No e-mail account is configured."; "issue_reporter.alerts.email_not_configured.message" = "No e-mail account is configured.";
"issue_reporter.email.subject" = "%@ - Report issue"; "issue_reporter.email.subject" = "%@ - Report issue";
"issue_reporter.email.body" = "Hi,\n\ndescription of the issue:\n\n%@\n\nRegards"; "issue_reporter.email.body" = "Hi,\n\n%@\n\n%@\n\nRegards";
"issue_reporter.email.description" = "description of the issue:";
"about.title" = "About"; "about.title" = "About";
"about.sections.info.header" = "General"; "about.sections.info.header" = "General";

View File

@ -30,9 +30,7 @@ enum ApplicationError: Error {
case missingCredentials case missingCredentials
case missingCA case missingConfiguration(option: String)
case emptyRemotes
case unsupportedConfiguration(option: String) case unsupportedConfiguration(option: String)

View File

@ -320,10 +320,12 @@ internal enum L10n {
} }
internal enum Email { internal enum Email {
/// Hi,\n\ndescription of the issue:\n\n%@\n\nRegards /// Hi,\n\n%@\n\n%@\n\nRegards
internal static func body(_ p1: String) -> String { internal static func body(_ p1: String, _ p2: String) -> String {
return L10n.tr("Localizable", "issue_reporter.email.body", p1) return L10n.tr("Localizable", "issue_reporter.email.body", p1, p2)
} }
/// description of the issue:
internal static let description = L10n.tr("Localizable", "issue_reporter.email.description")
/// %@ - Report issue /// %@ - Report issue
internal static func subject(_ p1: String) -> String { internal static func subject(_ p1: String) -> String {
return L10n.tr("Localizable", "issue_reporter.email.subject", p1) return L10n.tr("Localizable", "issue_reporter.email.subject", p1)
@ -731,15 +733,36 @@ internal enum L10n {
internal enum Host { internal enum Host {
internal enum Alerts { internal enum Alerts {
/// A host profile with the same title already exists. Replace it?
internal static let existing = L10n.tr("Localizable", "wizards.host.alerts.existing") internal enum Buttons {
/// Unable to parse the provided configuration file (%@). /// Report an issue
internal static func parsing(_ p1: String) -> String { internal static let report = L10n.tr("Localizable", "wizards.host.alerts.buttons.report")
return L10n.tr("Localizable", "wizards.host.alerts.parsing", p1)
} }
internal enum Existing {
/// A host profile with the same title already exists. Replace it?
internal static let message = L10n.tr("Localizable", "wizards.host.alerts.existing.message")
}
internal enum Missing {
/// The configuration file lacks a required option (%@).
internal static func message(_ p1: String) -> String {
return L10n.tr("Localizable", "wizards.host.alerts.missing.message", p1)
}
}
internal enum Parsing {
/// Unable to parse the provided configuration file (%@).
internal static func message(_ p1: String) -> String {
return L10n.tr("Localizable", "wizards.host.alerts.parsing.message", p1)
}
}
internal enum Unsupported {
/// The configuration file contains an unsupported option (%@). /// The configuration file contains an unsupported option (%@).
internal static func unsupported(_ p1: String) -> String { internal static func message(_ p1: String) -> String {
return L10n.tr("Localizable", "wizards.host.alerts.unsupported", p1) return L10n.tr("Localizable", "wizards.host.alerts.unsupported.message", p1)
}
} }
} }

View File

@ -255,13 +255,13 @@ extension TunnelKitProvider.Configuration {
} }
guard let ca = optCA else { guard let ca = optCA else {
throw ApplicationError.missingCA throw ApplicationError.missingConfiguration(option: "ca")
} }
// XXX: only reads first remote // XXX: only reads first remote
// hostnames = remotes.map { $0.0 } // hostnames = remotes.map { $0.0 }
guard !remotes.isEmpty else { guard !remotes.isEmpty else {
throw ApplicationError.emptyRemotes throw ApplicationError.missingConfiguration(option: "remote")
} }
let hostname = remotes[0].0 let hostname = remotes[0].0