diff --git a/DevLog/Data/Repository/AuthenticationRepositoryImpl.swift b/DevLog/Data/Repository/AuthenticationRepositoryImpl.swift index ce02d5d6..a96b2862 100644 --- a/DevLog/Data/Repository/AuthenticationRepositoryImpl.swift +++ b/DevLog/Data/Repository/AuthenticationRepositoryImpl.swift @@ -27,16 +27,29 @@ final class AuthenticationRepositoryImpl: AuthenticationRepository { } func signIn(_ provider: AuthProvider) async throws { - let response: AuthDataResponse - switch provider { - case .apple: - response = try await appleAuthService.signIn() - case .github: - response = try await githubAuthService.signIn() - case .google: - response = try await googleAuthService.signIn() + authService.beginSignIn() + + do { + let response: AuthDataResponse + switch provider { + case .apple: + response = try await appleAuthService.signIn() + case .github: + response = try await githubAuthService.signIn() + case .google: + response = try await googleAuthService.signIn() + } + + try await userService.upsertUser(response) + authService.completeSignIn() + } catch { + if authService.uid != nil { + try? await authService.clearCurrentSession() + } + + authService.cancelSignIn() + throw error } - try await userService.upsertUser(response) } func signOut() async throws { diff --git a/DevLog/Infra/Service/AuthService.swift b/DevLog/Infra/Service/AuthService.swift index e0a27b9a..6b5cd59a 100644 --- a/DevLog/Infra/Service/AuthService.swift +++ b/DevLog/Infra/Service/AuthService.swift @@ -16,6 +16,7 @@ final class AuthService { private let logger = Logger(category: "AuthService") private let subject = CurrentValueSubject(Auth.auth().currentUser != nil) private var handler: AuthStateDidChangeListenerHandle? + private var isCompletingSignIn = false var uid: String? { Auth.auth().currentUser?.uid @@ -27,9 +28,16 @@ final class AuthService { init() { handler = Auth.auth().addStateDidChangeListener { [weak self] _, user in + guard let self else { return } let signedIn = user != nil - self?.logger.info("Firebase auth state changed. signedIn: \(signedIn)") - self?.subject.send(signedIn) + self.logger.info("Firebase auth state changed. signedIn: \(signedIn)") + + if signedIn && self.isCompletingSignIn { + self.logger.info("Delaying signed-in publication until user bootstrap finishes") + return + } + + self.subject.send(signedIn) } } @@ -42,6 +50,24 @@ final class AuthService { subject.eraseToAnyPublisher() } + func beginSignIn() { + logger.info("Beginning sign-in bootstrap") + isCompletingSignIn = true + subject.send(false) + } + + func completeSignIn() { + logger.info("Completing sign-in bootstrap") + isCompletingSignIn = false + subject.send(Auth.auth().currentUser != nil) + } + + func cancelSignIn() { + logger.info("Cancelling sign-in bootstrap") + isCompletingSignIn = false + subject.send(Auth.auth().currentUser != nil) + } + func getProviderID() async throws -> String? { logger.info("Fetching current provider ID")