// // Copyright Amazon.com Inc. or its affiliates. // All Rights Reserved. // // SPDX-License-Identifier: Apache-2.0 // import Foundation import Amplify #if os(iOS) || os(macOS) import AuthenticationServices #endif class HostedUIASWebAuthenticationSession: NSObject, HostedUISessionBehavior { weak var webPresentation: AuthUIPresentationAnchor? func showHostedUI(url: URL, callbackScheme: String, inPrivate: Bool, presentationAnchor: AuthUIPresentationAnchor?, callback: @escaping (Result<[URLQueryItem], HostedUIError>) -> Void) { #if os(iOS) || os(macOS) self.webPresentation = presentationAnchor let aswebAuthenticationSession = ASWebAuthenticationSession( url: url, callbackURLScheme: callbackScheme, completionHandler: { url, error in if let url = url { let urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false) let queryItems = urlComponents?.queryItems ?? [] if let error = queryItems.first(where: { $0.name == "error" })?.value { callback(.failure(.serviceMessage(error))) return } callback(.success(queryItems)) } else if let error = error { callback(.failure(self.convertHostedUIError(error))) } else { callback(.failure(.unknown)) } }) aswebAuthenticationSession.presentationContextProvider = self aswebAuthenticationSession.prefersEphemeralWebBrowserSession = inPrivate DispatchQueue.main.async { aswebAuthenticationSession.start() } #else callback(.failure(.serviceMessage("HostedUI is only available in iOS and macOS"))) #endif } #if os(iOS) || os(macOS) private func convertHostedUIError(_ error: Error) -> HostedUIError { if let asWebAuthError = error as? ASWebAuthenticationSessionError { switch asWebAuthError.code { case .canceledLogin: return .cancelled case .presentationContextNotProvided: return .invalidContext case .presentationContextInvalid: return .invalidContext @unknown default: return .unknown } } return .unknown } #endif } #if os(iOS) || os(macOS) extension HostedUIASWebAuthenticationSession: ASWebAuthenticationPresentationContextProviding { func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor { return webPresentation ?? ASPresentationAnchor() } } #endif