Skip to content

Commit

Permalink
Import OpenVPN configuration (#765)
Browse files Browse the repository at this point in the history
At module creation time, choose whether to use a provider or import a
configuration file. After the import, the provider picker is hidden for
mutual exclusion.

For clarity, refactor the configuration part of OpenVPNView into a
ConfigurationView subview.
  • Loading branch information
keeshux authored Oct 28, 2024
1 parent ecb0348 commit 0ec06c2
Show file tree
Hide file tree
Showing 10 changed files with 402 additions and 289 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
"kind" : "remoteSourceControl",
"location" : "git@github.com:passepartoutvpn/passepartoutkit-source",
"state" : {
"revision" : "efbf2e135b04e9c0f67b5d2b517c5e13a75c50f6"
"revision" : "d21f1b362dfe667c36483e18b2dbb494bba54660"
}
},
{
Expand Down
2 changes: 1 addition & 1 deletion Passepartout/Library/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ let package = Package(
],
dependencies: [
// .package(url: "git@github.com:passepartoutvpn/passepartoutkit-source", from: "0.9.0"),
.package(url: "git@github.com:passepartoutvpn/passepartoutkit-source", revision: "efbf2e135b04e9c0f67b5d2b517c5e13a75c50f6"),
.package(url: "git@github.com:passepartoutvpn/passepartoutkit-source", revision: "d21f1b362dfe667c36483e18b2dbb494bba54660"),
// .package(path: "../../../passepartoutkit-source"),
.package(url: "git@github.com:passepartoutvpn/passepartoutkit-source-openvpn-openssl", from: "0.9.1"),
// .package(url: "git@github.com:passepartoutvpn/passepartoutkit-source-openvpn-openssl", revision: "031863a1cd683962a7dfe68e20b91fa820a1ecce"),
Expand Down
21 changes: 13 additions & 8 deletions Passepartout/Library/Sources/AppUI/L10n/AppError+L10n.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,19 +65,24 @@ extension PassepartoutError: LocalizedError {
return Strings.Errors.App.Passepartout.incompatibleModules

case .invalidFields:
guard let fields = userInfo as? [String: String?] else {
return nil
}
let fieldsDescription = fields
let fields = (userInfo as? [String: String?])
.map {
"\($0)=\($1?.description ?? "")"
$0.map {
"\($0)=\($1?.description ?? "")"
}
.joined(separator: ",")
}
.joined(separator: ",")

return Strings.Errors.App.Passepartout.invalidFields(fieldsDescription)
return [Strings.Errors.App.Passepartout.invalidFields, fields]
.compactMap { $0 }
.joined(separator: " ")

case .parsing:
return reason?.localizedDescription ?? Strings.Errors.App.Passepartout.parsing
let message = userInfo as? String ?? reason?.localizedDescription

return [Strings.Errors.App.Passepartout.parsing, message]
.compactMap { $0 }
.joined(separator: " ")

case .unhandled:
return reason?.localizedDescription
Expand Down
30 changes: 14 additions & 16 deletions Passepartout/Library/Sources/AppUI/L10n/SwiftGen+Strings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,16 @@ public enum Strings {
public static let title = Strings.tr("Localizable", "alerts.iap.restricted.title", fallback: "Restricted")
}
}
public enum Import {
public enum Passphrase {
/// Enter passphrase for '%@'.
public static func message(_ p1: Any) -> String {
return Strings.tr("Localizable", "alerts.import.passphrase.message", String(describing: p1), fallback: "Enter passphrase for '%@'.")
}
/// Decrypt
public static let ok = Strings.tr("Localizable", "alerts.import.passphrase.ok", fallback: "Decrypt")
}
}
}
public enum Entities {
public enum ConnectionStatus {
Expand Down Expand Up @@ -121,10 +131,8 @@ public enum Strings {
}
/// Some active modules are incompatible, try to only activate one of them.
public static let incompatibleModules = Strings.tr("Localizable", "errors.app.passepartout.incompatible_modules", fallback: "Some active modules are incompatible, try to only activate one of them.")
/// Invalid fields (%@).
public static func invalidFields(_ p1: Any) -> String {
return Strings.tr("Localizable", "errors.app.passepartout.invalid_fields", String(describing: p1), fallback: "Invalid fields (%@).")
}
/// Invalid fields.
public static let invalidFields = Strings.tr("Localizable", "errors.app.passepartout.invalid_fields", fallback: "Invalid fields.")
/// Unable to parse file.
public static let parsing = Strings.tr("Localizable", "errors.app.passepartout.parsing", fallback: "Unable to parse file.")
}
Expand Down Expand Up @@ -313,6 +321,8 @@ public enum Strings {
public enum Rows {
/// Shared on iCloud
public static let icloudSharing = Strings.tr("Localizable", "modules.general.rows.icloud_sharing", fallback: "Shared on iCloud")
/// Import from file...
public static let importFromFile = Strings.tr("Localizable", "modules.general.rows.import_from_file", fallback: "Import from file...")
public enum IcloudSharing {
/// Share on iCloud
public static let purchase = Strings.tr("Localizable", "modules.general.rows.icloud_sharing.purchase", fallback: "Share on iCloud")
Expand Down Expand Up @@ -598,18 +608,6 @@ public enum Strings {
}
}
public enum Profiles {
public enum Alerts {
public enum Import {
public enum Passphrase {
/// Enter passphrase for '%@'.
public static func message(_ p1: Any) -> String {
return Strings.tr("Localizable", "views.profiles.alerts.import.passphrase.message", String(describing: p1), fallback: "Enter passphrase for '%@'.")
}
/// Decrypt
public static let ok = Strings.tr("Localizable", "views.profiles.alerts.import.passphrase.ok", fallback: "Decrypt")
}
}
}
public enum Errors {
/// Unable to duplicate profile '%@'.
public static func duplicate(_ p1: Any) -> String {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,6 @@
"views.profiles.folders.no_profiles" = "No profiles";
"views.profiles.toolbar.new_profile" = "New profile";
"views.profiles.toolbar.import_profile" = "Import profile";
"views.profiles.alerts.import.passphrase.message" = "Enter passphrase for '%@'.";
"views.profiles.alerts.import.passphrase.ok" = "Decrypt";
"views.profiles.errors.tunnel" = "Unable to execute tunnel operation.";
"views.profiles.errors.duplicate" = "Unable to duplicate profile '%@'.";
"views.profiles.errors.import" = "Unable to import profiles.";
Expand Down Expand Up @@ -175,6 +173,7 @@

"modules.general.sections.storage.footer" = "Profiles are stored to iCloud encrypted.";
"modules.general.rows.icloud_sharing" = "Shared on iCloud";
"modules.general.rows.import_from_file" = "Import from file...";

"modules.dns.servers.add" = "Add address";
"modules.dns.search_domains.add" = "Add domain";
Expand Down Expand Up @@ -248,6 +247,9 @@

// MARK: - Alerts

"alerts.import.passphrase.message" = "Enter passphrase for '%@'.";
"alerts.import.passphrase.ok" = "Decrypt";

"alerts.iap.restricted.title" = "Restricted";
"alerts.iap.restricted.message" = "The requested feature is unavailable in this build.";

Expand All @@ -262,7 +264,7 @@
"errors.app.default" = "Unable to complete operation.";
"errors.app.passepartout.connection_module_required" = "Routing module can only be enabled together with a connection.";
"errors.app.passepartout.corrupt_provider_module" = "Unable to connect to provider server (reason=%@).";
"errors.app.passepartout.invalid_fields" = "Invalid fields (%@).";
"errors.app.passepartout.invalid_fields" = "Invalid fields.";
"errors.app.passepartout.incompatible_modules" = "Some active modules are incompatible, try to only activate one of them.";
"errors.app.passepartout.parsing" = "Unable to parse file.";
"errors.app.passepartout.default" = "Unable to complete operation (code=%@).";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ private extension ProfileImporterModifier {
Strings.Placeholders.secret,
text: $importer.currentPassphrase
)
Button(Strings.Views.Profiles.Alerts.Import.Passphrase.ok) {
Button(Strings.Alerts.Import.Passphrase.ok) {
Task {
try await importer.reImport(
url: url,
Expand All @@ -85,7 +85,7 @@ private extension ProfileImporterModifier {
}

func message(for url: URL) -> some View {
Text(Strings.Views.Profiles.Alerts.Import.Passphrase.message(url.lastPathComponent))
Text(Strings.Alerts.Import.Passphrase.message(url.lastPathComponent))
}

func handleResult(_ result: Result<[URL], Error>) {
Expand Down
Loading

0 comments on commit 0ec06c2

Please sign in to comment.