Move some profile integrity checks to library (#739)

They really belong to Profile.Builder
This commit is contained in:
Davide 2024-10-16 09:50:26 +02:00 committed by GitHub
parent 3de75e476b
commit 0221aea6b6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 38 additions and 45 deletions

View File

@ -41,7 +41,7 @@
"kind" : "remoteSourceControl",
"location" : "git@github.com:passepartoutvpn/passepartoutkit-source",
"state" : {
"revision" : "5c402931e0628f3280c603cce5c8c3d05b1cfa1f"
"revision" : "046a7594fa9823407dd405ba700b1b81506ce9af"
}
},
{

View File

@ -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: "5c402931e0628f3280c603cce5c8c3d05b1cfa1f"),
.package(url: "git@github.com:passepartoutvpn/passepartoutkit-source", revision: "046a7594fa9823407dd405ba700b1b81506ce9af"),
// .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"),

View File

@ -31,10 +31,6 @@ enum AppError {
case malformedModule(any ModuleBuilder, error: Error)
case multipleConnectionModules([any ModuleBuilder])
case ipModuleRequiresConnection(any ModuleBuilder)
case permissionDenied
case generic(PassepartoutError)

View File

@ -38,8 +38,6 @@ struct EditableProfile: MutableProfileType {
var modulesMetadata: [UUID: ModuleMetadata]?
func builder() throws -> Profile.Builder {
try checkConstraints()
var builder = Profile.Builder(id: id)
builder.modules = try modules.compactMap {
do {
@ -97,19 +95,4 @@ private extension EditableProfile {
isActiveModule(withId: $0.id) && $0.buildsConnectionModule
}
}
// FIXME: ###, move to library
func checkConstraints() throws {
if activeConnectionModule == nil,
let ipModule = modules.first(where: { activeModulesIds.contains($0.id) && $0 is IPModule.Builder }) {
throw AppError.ipModuleRequiresConnection(ipModule)
}
let connectionModules = modules.filter {
activeModulesIds.contains($0.id) && $0.buildsConnectionModule
}
guard connectionModules.count <= 1 else {
throw AppError.multipleConnectionModules(connectionModules)
}
}
}

View File

@ -38,12 +38,6 @@ extension AppError: LocalizedError {
case .malformedModule(let module, let error):
return V.malformedModule(module.typeDescription, error.localizedDescription)
case .ipModuleRequiresConnection:
return V.ipModuleRequiresConnection
case .multipleConnectionModules:
return V.multipleConnectionModules
case .permissionDenied:
return V.default
@ -58,6 +52,15 @@ extension AppError: LocalizedError {
extension PassepartoutError: LocalizedError {
public var errorDescription: String? {
switch code {
case .connectionModuleRequired:
return Strings.Errors.App.Passepartout.connectionModuleRequired
case .corruptProviderModule:
return Strings.Errors.App.Passepartout.corruptProviderModule(reason?.localizedDescription ?? "")
case .incompatibleModules:
return Strings.Errors.App.Passepartout.incompatibleModules
case .invalidFields:
guard let fields = userInfo as? [String: String?] else {
return nil
@ -73,9 +76,6 @@ extension PassepartoutError: LocalizedError {
case .parsing:
return reason?.localizedDescription ?? Strings.Errors.App.Passepartout.parsing
case .corruptProviderModule:
return Strings.Errors.App.Passepartout.corruptProviderModule(reason?.localizedDescription ?? "")
case .unhandled:
return reason?.localizedDescription

View File

@ -104,15 +104,13 @@ public enum Strings {
public static let `default` = Strings.tr("Localizable", "errors.app.default", fallback: "Unable to complete operation.")
/// Profile name is empty.
public static let emptyProfileName = Strings.tr("Localizable", "errors.app.empty_profile_name", fallback: "Profile name is empty.")
/// IP module can only be enabled together with a connection.
public static let ipModuleRequiresConnection = Strings.tr("Localizable", "errors.app.ip_module_requires_connection", fallback: "IP module can only be enabled together with a connection.")
/// Module %@ is malformed. %@
public static func malformedModule(_ p1: Any, _ p2: Any) -> String {
return Strings.tr("Localizable", "errors.app.malformed_module", String(describing: p1), String(describing: p2), fallback: "Module %@ is malformed. %@")
}
/// Only one connection module can be active at a time.
public static let multipleConnectionModules = Strings.tr("Localizable", "errors.app.multiple_connection_modules", fallback: "Only one connection module can be active at a time.")
public enum Passepartout {
/// Routing module can only be enabled together with a connection.
public static let connectionModuleRequired = Strings.tr("Localizable", "errors.app.passepartout.connection_module_required", fallback: "Routing module can only be enabled together with a connection.")
/// Unable to connect to provider server (reason=%@).
public static func corruptProviderModule(_ p1: Any) -> String {
return Strings.tr("Localizable", "errors.app.passepartout.corrupt_provider_module", String(describing: p1), fallback: "Unable to connect to provider server (reason=%@).")
@ -121,6 +119,8 @@ public enum Strings {
public static func `default`(_ p1: Any) -> String {
return Strings.tr("Localizable", "errors.app.passepartout.default", String(describing: p1), fallback: "Unable to complete operation (code=%@).")
}
/// 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 (%@).")

View File

@ -248,12 +248,12 @@
"errors.app.empty_profile_name" = "Profile name is empty.";
"errors.app.malformed_module" = "Module %@ is malformed. %@";
"errors.app.multiple_connection_modules" = "Only one connection module can be active at a time.";
"errors.app.ip_module_requires_connection" = "IP module can only be enabled together with a connection.";
"errors.app.default" = "Unable to complete operation.";
"errors.app.passepartout.invalid_fields" = "Invalid fields (%@).";
"errors.app.passepartout.parsing" = "Unable to parse file.";
"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.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=%@).";
"errors.tunnel.auth" = "Auth failed";

View File

@ -41,15 +41,29 @@ struct ProfileSaveButton: View {
try await action()
errorModuleIds = []
} catch {
switch error as? AppError {
switch AppError(error) {
case .malformedModule(let module, _):
errorModuleIds = [module.id]
case .multipleConnectionModules(let modules):
errorModuleIds = modules.map(\.id)
case .generic(let ppError):
switch ppError.code {
case .connectionModuleRequired:
guard let module = ppError.userInfo as? Module else {
errorModuleIds = []
return
}
errorModuleIds = [module.id]
case .ipModuleRequiresConnection(let module):
errorModuleIds = [module.id]
case .incompatibleModules:
guard let modules = ppError.userInfo as? [Module] else {
errorModuleIds = []
return
}
errorModuleIds = modules.map(\.id)
default:
errorModuleIds = []
}
default:
errorModuleIds = []