Files
omnivore/apple/OmnivoreKit/Sources/Services/Authentication/GoogleAuth.swift
2022-08-01 21:54:10 -07:00

97 lines
2.8 KiB
Swift

import Foundation
import GoogleSignIn
import Models
import Utils
public enum GoogleAuthResponse {
case loginError(error: LoginError)
case newOmnivoreUser
case existingOmnivoreUser
}
extension Authenticator {
public func handleGoogleAuth() async -> GoogleAuthResponse {
let idToken = await withCheckedContinuation { continuation in
googleSignIn { continuation.resume(returning: $0) }
}
guard let idToken = idToken else { return .loginError(error: .unauthorized) }
do {
let authPayload = try await networker.submitGoogleToken(idToken: idToken)
try ValetKey.authCookieString.setValue(authPayload.commentedAuthCookieString)
try ValetKey.authToken.setValue(authPayload.authToken)
DispatchQueue.main.async {
self.isLoggedIn = true
}
return .existingOmnivoreUser
} catch {
let loginError = (error as? LoginError) ?? .unknown
switch loginError {
case .unauthorized, .unknown:
return await createPendingUser(idToken: idToken)
case .network, .pendingEmailVerification:
return .loginError(error: .network)
}
}
}
func createPendingUser(idToken: String) async -> GoogleAuthResponse {
do {
let params = CreatePendingAccountParams(token: idToken, provider: .google, fullName: nil)
let encodedParams = (try? JSONEncoder().encode(params)) ?? Data()
let pendingUserAuthPayload = try await networker.createPendingUser(params: encodedParams)
pendingUserToken = pendingUserAuthPayload.pendingUserToken
return .newOmnivoreUser
} catch {
let loginError = LoginError.make(serverError: (error as? ServerError) ?? .unknown)
return .loginError(error: loginError)
}
}
func googleSignIn(completion: @escaping (String?) -> Void) {
#if os(iOS)
let presenting = presentingViewController()
#else
let presenting = NSApplication.shared.windows.first
#endif
guard let presenting = presenting else {
completion(nil)
return
}
let clientID = "\(AppKeys.sharedInstance?.iosClientGoogleId ?? "").apps.googleusercontent.com"
GIDSignIn.sharedInstance.signIn(
with: GIDConfiguration(clientID: clientID),
presenting: presenting
) { user, error in
guard let user = user, error == nil else {
completion(nil)
return
}
user.authentication.do { authentication, error in
guard let idToken = authentication?.idToken, error == nil else {
completion(nil)
return
}
completion(idToken)
}
}
}
}
private func presentingViewController() -> PlatformViewController? {
#if os(iOS)
let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene
return scene?.windows
.filter(\.isKeyWindow)
.first?
.rootViewController
#elseif os(macOS)
return nil
#endif
}