-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathGoogleAuthenticationService.swift
More file actions
131 lines (102 loc) · 4.42 KB
/
GoogleAuthenticationService.swift
File metadata and controls
131 lines (102 loc) · 4.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
//
// GoogleAuthenticationService.swift
// DevLog
//
// Created by opfic on 6/4/25.
//
import FirebaseAuth
import FirebaseFirestore
import FirebaseFunctions
import FirebaseMessaging
import Foundation
import GoogleSignIn
final class GoogleAuthenticationService: AuthenticationService {
private let store = Firestore.firestore()
private let functions = Functions.functions(region: "asia-northeast3")
private let messaging = Messaging.messaging()
private var user: User? { Auth.auth().currentUser }
private let provider = TopViewControllerProvider()
private let logger = Logger(category: "GoogleAuthService")
@MainActor
func signIn() async throws -> AuthDataResponse {
logger.info("Starting Google sign in")
guard let topViewController = provider.topViewController() else {
logger.error("Top view controller not found")
throw UIError.notFoundTopViewController
}
do {
let signIn = try await GIDSignIn.sharedInstance.signIn(withPresenting: topViewController)
guard let idToken = signIn.user.idToken?.tokenString else {
logger.error("ID token not found")
throw URLError(.badServerResponse)
}
let accessToken = signIn.user.accessToken.tokenString
let credential = GoogleAuthProvider.credential(withIDToken: idToken, accessToken: accessToken)
logger.debug("Signing in with Google credential")
let result = try await Auth.auth().signIn(with: credential)
if let photoURL = signIn.user.profile?.imageURL(withDimension: 200) {
let changeRequest = result.user.createProfileChangeRequest()
changeRequest.photoURL = photoURL
changeRequest.displayName = signIn.user.profile?.name
try await changeRequest.commitChanges()
}
let fcmToken = try await messaging.token()
logger.info("Successfully signed in with Google")
return result.user.makeResponse(providerID: .google, fcmToken: fcmToken)
} catch {
logger.error("Failed to sign in with Google", error: error)
throw error
}
}
func signOut(_ uid: String) async throws {
let infoRef = store.document("users/\(uid)/userData/tokens")
let doc = try await infoRef.getDocument()
if doc.exists {
try await infoRef.updateData(["fcmToken": FieldValue.delete()])
}
GIDSignIn.sharedInstance.signOut()
try await GIDSignIn.sharedInstance.disconnect()
try await messaging.deleteToken()
try Auth.auth().signOut()
}
func deleteAuth(_ uid: String) async throws {
GIDSignIn.sharedInstance.signOut()
try await GIDSignIn.sharedInstance.disconnect()
}
func link(uid: String, email: String) async throws {
let topViewController = await MainActor.run {
provider.topViewController()
}
guard let topViewController = topViewController else {
throw UIError.notFoundTopViewController
}
if GIDSignIn.sharedInstance.hasPreviousSignIn() {
GIDSignIn.sharedInstance.signOut()
}
let signIn = try await GIDSignIn.sharedInstance.signIn(withPresenting: topViewController)
guard let googleEmail = signIn.user.profile?.email else {
throw EmailFetchError.emailNotFound
}
if googleEmail != email {
throw EmailFetchError.emailMismatch
}
guard let idToken = signIn.user.idToken?.tokenString else {
throw URLError(.badServerResponse)
}
let accessToken = signIn.user.accessToken.tokenString
let credential = GoogleAuthProvider.credential(withIDToken: idToken, accessToken: accessToken)
try await user?.link(with: credential)
}
func unlink(_ uid: String) async throws {
do {
logger.info("Starting Google disconnect for unlink. uid: \(uid)")
GIDSignIn.sharedInstance.signOut()
try await GIDSignIn.sharedInstance.disconnect()
logger.info("Starting Firebase Google provider unlink. uid: \(uid)")
_ = try await user?.unlink(fromProvider: AuthProviderID.google.rawValue)
} catch {
logger.error("Failed to unlink Google account", error: error)
throw error
}
}
}