Move some profile integrity checks to library (#739)
They really belong to Profile.Builder
This commit is contained in:
parent
3de75e476b
commit
0221aea6b6
|
@ -41,7 +41,7 @@
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "git@github.com:passepartoutvpn/passepartoutkit-source",
|
"location" : "git@github.com:passepartoutvpn/passepartoutkit-source",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "5c402931e0628f3280c603cce5c8c3d05b1cfa1f"
|
"revision" : "046a7594fa9823407dd405ba700b1b81506ce9af"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -28,7 +28,7 @@ let package = Package(
|
||||||
],
|
],
|
||||||
dependencies: [
|
dependencies: [
|
||||||
// .package(url: "git@github.com:passepartoutvpn/passepartoutkit-source", from: "0.9.0"),
|
// .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(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", from: "0.9.1"),
|
||||||
// .package(url: "git@github.com:passepartoutvpn/passepartoutkit-source-openvpn-openssl", revision: "031863a1cd683962a7dfe68e20b91fa820a1ecce"),
|
// .package(url: "git@github.com:passepartoutvpn/passepartoutkit-source-openvpn-openssl", revision: "031863a1cd683962a7dfe68e20b91fa820a1ecce"),
|
||||||
|
|
|
@ -31,10 +31,6 @@ enum AppError {
|
||||||
|
|
||||||
case malformedModule(any ModuleBuilder, error: Error)
|
case malformedModule(any ModuleBuilder, error: Error)
|
||||||
|
|
||||||
case multipleConnectionModules([any ModuleBuilder])
|
|
||||||
|
|
||||||
case ipModuleRequiresConnection(any ModuleBuilder)
|
|
||||||
|
|
||||||
case permissionDenied
|
case permissionDenied
|
||||||
|
|
||||||
case generic(PassepartoutError)
|
case generic(PassepartoutError)
|
||||||
|
|
|
@ -38,8 +38,6 @@ struct EditableProfile: MutableProfileType {
|
||||||
var modulesMetadata: [UUID: ModuleMetadata]?
|
var modulesMetadata: [UUID: ModuleMetadata]?
|
||||||
|
|
||||||
func builder() throws -> Profile.Builder {
|
func builder() throws -> Profile.Builder {
|
||||||
try checkConstraints()
|
|
||||||
|
|
||||||
var builder = Profile.Builder(id: id)
|
var builder = Profile.Builder(id: id)
|
||||||
builder.modules = try modules.compactMap {
|
builder.modules = try modules.compactMap {
|
||||||
do {
|
do {
|
||||||
|
@ -97,19 +95,4 @@ private extension EditableProfile {
|
||||||
isActiveModule(withId: $0.id) && $0.buildsConnectionModule
|
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,12 +38,6 @@ extension AppError: LocalizedError {
|
||||||
case .malformedModule(let module, let error):
|
case .malformedModule(let module, let error):
|
||||||
return V.malformedModule(module.typeDescription, error.localizedDescription)
|
return V.malformedModule(module.typeDescription, error.localizedDescription)
|
||||||
|
|
||||||
case .ipModuleRequiresConnection:
|
|
||||||
return V.ipModuleRequiresConnection
|
|
||||||
|
|
||||||
case .multipleConnectionModules:
|
|
||||||
return V.multipleConnectionModules
|
|
||||||
|
|
||||||
case .permissionDenied:
|
case .permissionDenied:
|
||||||
return V.default
|
return V.default
|
||||||
|
|
||||||
|
@ -58,6 +52,15 @@ extension AppError: LocalizedError {
|
||||||
extension PassepartoutError: LocalizedError {
|
extension PassepartoutError: LocalizedError {
|
||||||
public var errorDescription: String? {
|
public var errorDescription: String? {
|
||||||
switch code {
|
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:
|
case .invalidFields:
|
||||||
guard let fields = userInfo as? [String: String?] else {
|
guard let fields = userInfo as? [String: String?] else {
|
||||||
return nil
|
return nil
|
||||||
|
@ -73,9 +76,6 @@ extension PassepartoutError: LocalizedError {
|
||||||
case .parsing:
|
case .parsing:
|
||||||
return reason?.localizedDescription ?? Strings.Errors.App.Passepartout.parsing
|
return reason?.localizedDescription ?? Strings.Errors.App.Passepartout.parsing
|
||||||
|
|
||||||
case .corruptProviderModule:
|
|
||||||
return Strings.Errors.App.Passepartout.corruptProviderModule(reason?.localizedDescription ?? "")
|
|
||||||
|
|
||||||
case .unhandled:
|
case .unhandled:
|
||||||
return reason?.localizedDescription
|
return reason?.localizedDescription
|
||||||
|
|
||||||
|
|
|
@ -104,15 +104,13 @@ public enum Strings {
|
||||||
public static let `default` = Strings.tr("Localizable", "errors.app.default", fallback: "Unable to complete operation.")
|
public static let `default` = Strings.tr("Localizable", "errors.app.default", fallback: "Unable to complete operation.")
|
||||||
/// Profile name is empty.
|
/// Profile name is empty.
|
||||||
public static let emptyProfileName = Strings.tr("Localizable", "errors.app.empty_profile_name", fallback: "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. %@
|
/// Module %@ is malformed. %@
|
||||||
public static func malformedModule(_ p1: Any, _ p2: Any) -> String {
|
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. %@")
|
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 {
|
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=%@).
|
/// Unable to connect to provider server (reason=%@).
|
||||||
public static func corruptProviderModule(_ p1: Any) -> String {
|
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=%@).")
|
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 {
|
public static func `default`(_ p1: Any) -> String {
|
||||||
return Strings.tr("Localizable", "errors.app.passepartout.default", String(describing: p1), fallback: "Unable to complete operation (code=%@).")
|
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 (%@).
|
/// Invalid fields (%@).
|
||||||
public static func invalidFields(_ p1: Any) -> String {
|
public static func invalidFields(_ p1: Any) -> String {
|
||||||
return Strings.tr("Localizable", "errors.app.passepartout.invalid_fields", String(describing: p1), fallback: "Invalid fields (%@).")
|
return Strings.tr("Localizable", "errors.app.passepartout.invalid_fields", String(describing: p1), fallback: "Invalid fields (%@).")
|
||||||
|
|
|
@ -248,12 +248,12 @@
|
||||||
|
|
||||||
"errors.app.empty_profile_name" = "Profile name is empty.";
|
"errors.app.empty_profile_name" = "Profile name is empty.";
|
||||||
"errors.app.malformed_module" = "Module %@ is malformed. %@";
|
"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.default" = "Unable to complete operation.";
|
||||||
"errors.app.passepartout.invalid_fields" = "Invalid fields (%@).";
|
"errors.app.passepartout.connection_module_required" = "Routing module can only be enabled together with a connection.";
|
||||||
"errors.app.passepartout.parsing" = "Unable to parse file.";
|
|
||||||
"errors.app.passepartout.corrupt_provider_module" = "Unable to connect to provider server (reason=%@).";
|
"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.app.passepartout.default" = "Unable to complete operation (code=%@).";
|
||||||
|
|
||||||
"errors.tunnel.auth" = "Auth failed";
|
"errors.tunnel.auth" = "Auth failed";
|
||||||
|
|
|
@ -41,15 +41,29 @@ struct ProfileSaveButton: View {
|
||||||
try await action()
|
try await action()
|
||||||
errorModuleIds = []
|
errorModuleIds = []
|
||||||
} catch {
|
} catch {
|
||||||
switch error as? AppError {
|
switch AppError(error) {
|
||||||
case .malformedModule(let module, _):
|
case .malformedModule(let module, _):
|
||||||
errorModuleIds = [module.id]
|
errorModuleIds = [module.id]
|
||||||
|
|
||||||
case .multipleConnectionModules(let modules):
|
case .generic(let ppError):
|
||||||
errorModuleIds = modules.map(\.id)
|
switch ppError.code {
|
||||||
|
case .connectionModuleRequired:
|
||||||
|
guard let module = ppError.userInfo as? Module else {
|
||||||
|
errorModuleIds = []
|
||||||
|
return
|
||||||
|
}
|
||||||
|
errorModuleIds = [module.id]
|
||||||
|
|
||||||
case .ipModuleRequiresConnection(let module):
|
case .incompatibleModules:
|
||||||
errorModuleIds = [module.id]
|
guard let modules = ppError.userInfo as? [Module] else {
|
||||||
|
errorModuleIds = []
|
||||||
|
return
|
||||||
|
}
|
||||||
|
errorModuleIds = modules.map(\.id)
|
||||||
|
|
||||||
|
default:
|
||||||
|
errorModuleIds = []
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
errorModuleIds = []
|
errorModuleIds = []
|
||||||
|
|
Loading…
Reference in New Issue