amplify-swift/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/RefreshAuthorizationSession/UserPool/RefreshHostedUITokens.swift

133 lines
5.2 KiB
Swift

//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//
import Amplify
import Foundation
struct RefreshHostedUITokens: Action {
let identifier = "RefreshHostedUITokens"
let existingSignedIndata: SignedInData
func execute(withDispatcher dispatcher: EventDispatcher, environment: Environment) {
Task {
await refresh(
withDispatcher: dispatcher,
environment: environment
)
}
}
func refresh(withDispatcher dispatcher: EventDispatcher, environment: Environment) async {
do {
logVerbose("\(#fileID) Starting execution", environment: environment)
guard let environment = environment as? AuthEnvironment,
let hostedUIEnvironment = environment.hostedUIEnvironment else {
let event = RefreshSessionEvent.init(eventType: .throwError(.noUserPool))
await dispatcher.send(event)
return
}
let configuration = environment.userPoolConfiguration
let existingTokens = existingSignedIndata.cognitoUserPoolTokens
let request = try HostedUIRequestHelper.createRefreshTokenRequest(
refreshToken: existingTokens.refreshToken,
configuration: hostedUIEnvironment.configuration)
let data = try await withCheckedThrowingContinuation {
(continuation: CheckedContinuation<Data, Error>) in
let task = hostedUIEnvironment.urlSessionFactory().dataTask(with: request) {
data, _, error in
if let error = error {
continuation.resume(with: .failure(FetchSessionError.service(error)))
} else if let data = data {
continuation.resume(with: .success(data))
} else {
continuation.resume(with: .failure(FetchSessionError.invalidTokens))
}
}
task.resume()
}
let signedInData = try await handleData(data,
configuration: configuration)
let event: RefreshSessionEvent
if (environment.identityPoolConfigData) != nil {
let provider = CognitoUserPoolLoginsMap(
idToken: signedInData.cognitoUserPoolTokens.idToken,
region: configuration.region,
poolId: configuration.poolId)
event = .init(eventType: .refreshIdentityInfo(signedInData, provider))
} else {
event = .init(eventType: .refreshedCognitoUserPool(signedInData))
}
logVerbose("\(#fileID) Sending event \(event.type)", environment: environment)
await dispatcher.send(event)
} catch let fetchError as FetchSessionError {
let event = RefreshSessionEvent(eventType: .throwError(fetchError))
logVerbose("\(#fileID) Sending event \(event.type)", environment: environment)
await dispatcher.send(event)
} catch {
let event = RefreshSessionEvent(eventType: .throwError(.service(error)))
logVerbose("\(#fileID) Sending event \(event.type)", environment: environment)
await dispatcher.send(event)
}
logVerbose("\(#fileID) Refresh hostedUI token complete", environment: environment)
}
func handleData(_ data: Data,
configuration: UserPoolConfigurationData) async throws -> SignedInData {
guard let json = try JSONSerialization.jsonObject(
with: data,
options: []) as? [String: Any] else {
throw FetchSessionError.invalidTokens
}
if let errorString = json["error"] as? String {
let description = json["error_description"] as? String ?? ""
let error = HostedUIError.serviceMessage("\(errorString) \(description)")
throw FetchSessionError.service(error)
} else if let idToken = json["id_token"] as? String,
let accessToken = json["access_token"] as? String,
let expiresIn = json["expires_in"] as? Int {
let userPoolTokens = AWSCognitoUserPoolTokens(
idToken: idToken,
accessToken: accessToken,
refreshToken: existingSignedIndata.cognitoUserPoolTokens.refreshToken,
expiresIn: expiresIn)
return SignedInData(
signedInDate: existingSignedIndata.signedInDate,
signInMethod: existingSignedIndata.signInMethod,
cognitoUserPoolTokens: userPoolTokens)
} else {
throw FetchSessionError.invalidTokens
}
}
}
extension RefreshHostedUITokens: DefaultLogger { }
extension RefreshHostedUITokens: CustomDebugDictionaryConvertible {
var debugDictionary: [String: Any] {
[
"identifier": identifier,
"existingSignedInData": existingSignedIndata
]
}
}
extension RefreshHostedUITokens: CustomDebugStringConvertible {
var debugDescription: String {
debugDictionary.debugDescription
}
}