Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FronteggError Enum Granularity #52

Merged
merged 2 commits into from
Jul 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 10 additions & 11 deletions Sources/FronteggSwift/FronteggAuth.swift
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ public class FronteggAuth: ObservableObject {
}

guard let data = responseData else {
completion(.failure(FronteggError.authError("Failed to authenticate with frontegg")))
completion(.failure(FronteggError.authError(.failedToAuthenticate)))
setIsLoading(false)
return
}
Expand All @@ -296,7 +296,7 @@ public class FronteggAuth: ObservableObject {
completion(.success(user!))
} catch {
logger.error("Failed to load user data: \(error.localizedDescription)")
completion(.failure(FronteggError.authError("Failed to load user data: \(error.localizedDescription)")))
completion(.failure(FronteggError.authError(.failedToLoadUserData(error.localizedDescription))))
setIsLoading(false)
return
}
Expand All @@ -315,27 +315,26 @@ public class FronteggAuth: ObservableObject {

return { callbackUrl, error in

if error != nil {
completion(.failure(FronteggError.authError(error!.localizedDescription)))
if let error {
completion(.failure(FronteggError.authError(.other(error))))
return
}

guard let url = callbackUrl else {
let errorMessage = "Unknown error occurred"
completion(.failure(FronteggError.authError(errorMessage)))
completion(.failure(FronteggError.authError(.unknown)))
return
}


self.logger.trace("handleHostedLoginCallback, url: \(url)")
guard let queryItems = getQueryItems(url.absoluteString), let code = queryItems["code"] else {
let error = FronteggError.authError("Failed to get extract code from hostedLoginCallback url")
let error = FronteggError.authError(.failedToExtractCode)
completion(.failure(error))
return
}

guard let codeVerifier = CredentialManager.getCodeVerifier() else {
let error = FronteggError.authError("IlligalState, codeVerifier not found")
let error = FronteggError.authError(.codeVerifierNotFound)
completion(.failure(error))
return
}
Expand Down Expand Up @@ -512,7 +511,7 @@ public class FronteggAuth: ObservableObject {
rootVC.present(hostingController, animated: false, completion: nil)

} else {
logger.critical(FronteggError.authError("Unable to find root viewController").localizedDescription)
logger.critical(FronteggError.authError(.couldNotFindRootViewController).localizedDescription)
exit(500)
}
}
Expand All @@ -524,7 +523,7 @@ public class FronteggAuth: ObservableObject {
}

guard let rootVC = self.getRootVC(useAppRootVC) else {
logger.error(FronteggError.authError("Unable to find root viewController").localizedDescription)
logger.error(FronteggError.authError(.couldNotFindRootViewController).localizedDescription)
return false;
}

Expand Down Expand Up @@ -574,7 +573,7 @@ public class FronteggAuth: ObservableObject {
if let user = self.user, await self.refreshTokenIfNeeded() && completion != nil {
completion?(.success(user))
} else {
completion?(.failure(FronteggError.authError("Failed to swift tenant")))
completion?(.failure(FronteggError.authError(.failedToSwitchTenant)))
}

}
Expand Down
42 changes: 42 additions & 0 deletions Sources/FronteggSwift/models/errors/AuthenticationError.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//
// AuthenticationError.swift
//
//
// Created by Nick Hagi on 17/07/2024.
//

import Foundation

// MARK: - AuthenticationError
extension FronteggError {

public enum Authentication: LocalizedError {
case couldNotExchangeToken(_ message: String)
case failedToAuthenticate
case failedToLoadUserData(_ message: String)
case failedToExtractCode
case failedToSwitchTenant
case codeVerifierNotFound
case couldNotFindRootViewController
case unknown
case other(Error)
}
}

// MARK: - LocalizedError
extension FronteggError.Authentication {

public var errorDescription: String? {
switch self {
case let .couldNotExchangeToken(message): message
case .failedToAuthenticate: "Failed to authenticate with frontegg"
case let .failedToLoadUserData(message): "Failed to load user data: \(message)"
case .failedToExtractCode: "Failed to get extract code from hostedLoginCallback url"
case .failedToSwitchTenant: "Failed to switch tenant"
case .codeVerifierNotFound: "Code verifier not found"
case .couldNotFindRootViewController: "Unable to find root viewController"
case .unknown: "Unknown error occurred"
case let .other(error): error.localizedDescription
}
}
}
32 changes: 32 additions & 0 deletions Sources/FronteggSwift/models/errors/ConfigurationError.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//
// ConfigurationError.swift
//
//
// Created by Nick Hagi on 17/07/2024.
//

import Foundation

// MARK: - ConfigurationError
extension FronteggError {

public enum Configuration: LocalizedError {
case missingPlist
case missingClientIdOrBaseURL(_ atPath: String)
case missingRegions
case invalidRegions(_ atPath: String)
}
}

// MARK: - LocalizedError
extension FronteggError.Configuration {

public var errorDescription: String? {
switch self {
case .missingPlist: "Missing Frontegg.plist file with 'clientId' and 'baseUrl' entries in main bundle!"
case let .missingClientIdOrBaseURL(path): "Frontegg.plist file at \(path) is missing 'clientId' and/or 'baseUrl' entries!"
case .missingRegions: "no regions in Frontegg.plist"
case let .invalidRegions(path): "Frontegg.plist file at \(path) has invalid regions data, regions must be array of (key, baseUrl, clientId)"
}
}
}
13 changes: 13 additions & 0 deletions Sources/FronteggSwift/models/errors/FronteggError.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//
// FronteggError.swift
//
//
// Created by Nick Hagi on 17/07/2024.
//

import Foundation

public enum FronteggError: Error {
case configError(Configuration)
case authError(Authentication)
}
2 changes: 1 addition & 1 deletion Sources/FronteggSwift/services/Api.swift
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ public class Api {

return (try JSONDecoder().decode(AuthResponse.self, from: data), nil)
}catch {
return (nil, FronteggError.authError(error.localizedDescription))
return (nil, FronteggError.authError(.couldNotExchangeToken(error.localizedDescription)))
}
}

Expand Down
56 changes: 28 additions & 28 deletions Sources/FronteggSwift/utils/PlistHelper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,6 @@

import Foundation


public enum FronteggError: Error {
case configError(String)
case authError(String)
}


public struct RegionConfig {
public var key: String
public var baseUrl: String
Expand All @@ -31,23 +24,24 @@ public struct RegionConfig {
struct PlistHelper {

private static var logLevelCache: Logger.Level? = nil

private static var logger = getLogger("PlistHelper")

public static func fronteggConfig() throws -> (clientId: String, baseUrl: String, applicationId: String?, keychainService: String, bundleIdentifier: String) {
let bundle = Bundle.main;

let resourceName = (getenv("frontegg-testing") != nil) ? "FronteggTest" : "Frontegg"

guard let path = bundle.path(forResource: resourceName, ofType: "plist"),
let values = NSDictionary(contentsOfFile: path) as? [String: Any] else {
let errorMessage = "Missing Frontegg.plist file with 'clientId' and 'baseUrl' entries in main bundle!"
print(errorMessage)
throw FronteggError.configError(errorMessage)
let error = FronteggError.configError(.missingPlist)
logger.debug(error.localizedDescription)
throw error
}

guard let clientId = values["clientId"] as? String, let baseUrl = values["baseUrl"] as? String else {
let errorMessage = "Frontegg.plist file at \(path) is missing 'clientId' and/or 'baseUrl' entries!"
print(errorMessage)
throw FronteggError.configError(errorMessage)
let error = FronteggError.configError(.missingClientIdOrBaseURL(path))
logger.debug(error.localizedDescription)
throw error
}

let applicationId = values["applicationId"] as? String
Expand All @@ -64,28 +58,34 @@ struct PlistHelper {

guard let path = bundle.path(forResource: resourceName, ofType: "plist"),
let values = NSDictionary(contentsOfFile: path) as? [String: Any] else {
let errorMessage = "Missing Frontegg.plist file with 'clientId' and 'baseUrl' entries in main bundle!"
print(errorMessage)
throw FronteggError.configError(errorMessage)
}

guard let regions = values["regions"] as? [[String: String]] else {
throw FronteggError.configError("no regions in Frontegg.plist")
let error = FronteggError.configError(.missingPlist)
logger.debug(error.localizedDescription)
throw error
}

if ( regions.count == 0 ) {
throw FronteggError.configError("no regions in Frontegg.plist")
guard
let regions = values["regions"] as? [[String: String]],
!regions.isEmpty
else {
let error = FronteggError.configError(.missingRegions)
logger.debug(error.localizedDescription)
throw error
}

let keychainService = values["keychainService"] as? String ?? "frontegg"

let regionConfigs = try regions.map { dict in
guard let key = dict["key"],
let baseUrl = dict["baseUrl"],
let clientId = dict["clientId"] else {
throw FronteggError.configError("Frontegg.plist file at \(path) has invalid regions data, regions must be array of (key, baseUrl, clientId)")
guard
let key = dict["key"],
let baseUrl = dict["baseUrl"],
let clientId = dict["clientId"]
else {
let error = FronteggError.configError(.invalidRegions(path))
logger.debug(error.localizedDescription)
throw error
}
let applicationId = dict["applicationId"]

let applicationId = dict["applicationId"]
return RegionConfig(key: key, baseUrl: baseUrl, clientId: clientId, applicationId: applicationId)
}
return (regions: regionConfigs, keychainService: keychainService, bundleIdentifier: bundle.bundleIdentifier!)
Expand Down
Loading