@@ -22,82 +22,61 @@ import Foundation
22
22
#endif
23
23
24
24
@available ( iOS 13 , tvOS 13 , macOS 10 . 15 , macCatalyst 13 , watchOS 7 , * )
25
- protocol AuthBackendRPCIssuer {
26
- /// Asynchronously send a HTTP request.
27
- /// - Parameter request: The request to be made.
28
- /// - Parameter body: Request body.
29
- /// - Parameter contentType: Content type of the body.
30
- /// - Parameter completionHandler: Handles HTTP response. Invoked asynchronously
31
- /// on the auth global work queue in the future.
32
- func asyncCallToURL< T: AuthRPCRequest > ( with request: T ,
33
- body: Data ? ,
34
- contentType: String ) async -> ( Data ? , Error ? )
35
- }
36
-
37
- @available ( iOS 13 , tvOS 13 , macOS 10 . 15 , macCatalyst 13 , watchOS 7 , * )
38
- class AuthBackendRPCIssuerImplementation : AuthBackendRPCIssuer {
39
- let fetcherService : GTMSessionFetcherService
40
-
41
- init ( ) {
42
- fetcherService = GTMSessionFetcherService ( )
43
- fetcherService. userAgent = AuthBackend . authUserAgent ( )
44
- fetcherService. callbackQueue = kAuthGlobalWorkQueue
45
-
46
- // Avoid reusing the session to prevent
47
- // https://github.com/firebase/firebase-ios-sdk/issues/1261
48
- fetcherService. reuseSession = false
49
- }
50
-
51
- func asyncCallToURL< T: AuthRPCRequest > ( with request: T ,
52
- body: Data ? ,
53
- contentType: String ) async -> ( Data ? , Error ? ) {
54
- let requestConfiguration = request. requestConfiguration ( )
55
- let request = await AuthBackend . request ( withURL: request. requestURL ( ) ,
56
- contentType: contentType,
57
- requestConfiguration: requestConfiguration)
58
- let fetcher = fetcherService. fetcher ( with: request)
59
- if let _ = requestConfiguration. emulatorHostAndPort {
60
- fetcher. allowLocalhostRequest = true
61
- fetcher. allowedInsecureSchemes = [ " http " ]
62
- }
63
- fetcher. bodyData = body
64
-
65
- return await withUnsafeContinuation { continuation in
66
- fetcher. beginFetch { data, error in
67
- continuation. resume ( returning: ( data, error) )
68
- }
69
- }
70
- }
25
+ protocol AuthBackendProtocol {
26
+ func call< T: AuthRPCRequest > ( with request: T ) async throws -> T . Response
71
27
}
72
28
73
29
@available ( iOS 13 , tvOS 13 , macOS 10 . 15 , macCatalyst 13 , watchOS 7 , * )
74
- class AuthBackend {
30
+ class AuthBackend : AuthBackendProtocol {
75
31
static func authUserAgent( ) -> String {
76
32
return " FirebaseAuth.iOS/ \( FirebaseVersion ( ) ) \( GTMFetcherStandardUserAgentString ( nil ) ) "
77
33
}
78
34
79
- private static var realRPCBackend = AuthBackendRPCImplementation ( )
80
- private static var gBackendImplementation = realRPCBackend
35
+ static func call< T: AuthRPCRequest > ( with request: T ) async throws -> T . Response {
36
+ return try await shared. call ( with: request)
37
+ }
81
38
82
- class func setTestRPCIssuer( issuer: AuthBackendRPCIssuer ) {
83
- gBackendImplementation . rpcIssuer = issuer
39
+ static func setTestRPCIssuer( issuer: AuthBackendRPCIssuer ) {
40
+ shared . rpcIssuer = issuer
84
41
}
85
42
86
- class func resetRPCIssuer( ) {
87
- gBackendImplementation . rpcIssuer = realRPCBackend . rpcIssuer
43
+ static func resetRPCIssuer( ) {
44
+ shared . rpcIssuer = AuthBackendRPCIssuer ( )
88
45
}
89
46
90
- class func implementation( ) -> AuthBackendImplementation {
91
- return gBackendImplementation
47
+ private static let shared : AuthBackend = . init( rpcIssuer: AuthBackendRPCIssuer ( ) )
48
+
49
+ private var rpcIssuer : any AuthBackendRPCIssuerProtocol
50
+
51
+ init ( rpcIssuer: any AuthBackendRPCIssuerProtocol ) {
52
+ self . rpcIssuer = rpcIssuer
92
53
}
93
54
94
- class func call< T: AuthRPCRequest > ( with request: T ) async throws -> T . Response {
95
- return try await implementation ( ) . call ( with: request)
55
+ /// Calls the RPC using HTTP request.
56
+ /// Possible error responses:
57
+ /// * See FIRAuthInternalErrorCodeRPCRequestEncodingError
58
+ /// * See FIRAuthInternalErrorCodeJSONSerializationError
59
+ /// * See FIRAuthInternalErrorCodeNetworkError
60
+ /// * See FIRAuthInternalErrorCodeUnexpectedErrorResponse
61
+ /// * See FIRAuthInternalErrorCodeUnexpectedResponse
62
+ /// * See FIRAuthInternalErrorCodeRPCResponseDecodingError
63
+ /// - Parameter request: The request.
64
+ /// - Returns: The response.
65
+ func call< T: AuthRPCRequest > ( with request: T ) async throws -> T . Response {
66
+ let response = try await callInternal ( with: request)
67
+ if let auth = request. requestConfiguration ( ) . auth,
68
+ let mfaError = Self . generateMFAError ( response: response, auth: auth) {
69
+ throw mfaError
70
+ } else if let error = Self . phoneCredentialInUse ( response: response) {
71
+ throw error
72
+ } else {
73
+ return response
74
+ }
96
75
}
97
76
98
- class func request( withURL url: URL ,
99
- contentType: String ,
100
- requestConfiguration: AuthRequestConfiguration ) async -> URLRequest {
77
+ static func request( withURL url: URL ,
78
+ contentType: String ,
79
+ requestConfiguration: AuthRequestConfiguration ) async -> URLRequest {
101
80
// Kick off tasks for the async header values.
102
81
async let heartbeatsHeaderValue = requestConfiguration. heartbeatLogger? . asyncHeaderValue ( )
103
82
async let appCheckTokenHeaderValue = requestConfiguration. appCheck?
@@ -132,41 +111,11 @@ class AuthBackend {
132
111
}
133
112
return request
134
113
}
135
- }
136
114
137
- @available( iOS 13 , tvOS 13 , macOS 10.15 , macCatalyst 13 , watchOS 7 , * )
138
- protocol AuthBackendImplementation {
139
- func call< T: AuthRPCRequest > ( with request: T ) async throws -> T . Response
140
- }
141
-
142
- @available ( iOS 13 , tvOS 13 , macOS 10 . 15 , macCatalyst 13 , watchOS 7 , * )
143
- private class AuthBackendRPCImplementation: AuthBackendImplementation {
144
- var rpcIssuer : AuthBackendRPCIssuer = AuthBackendRPCIssuerImplementation ( )
145
-
146
- /// Calls the RPC using HTTP request.
147
- /// Possible error responses:
148
- /// * See FIRAuthInternalErrorCodeRPCRequestEncodingError
149
- /// * See FIRAuthInternalErrorCodeJSONSerializationError
150
- /// * See FIRAuthInternalErrorCodeNetworkError
151
- /// * See FIRAuthInternalErrorCodeUnexpectedErrorResponse
152
- /// * See FIRAuthInternalErrorCodeUnexpectedResponse
153
- /// * See FIRAuthInternalErrorCodeRPCResponseDecodingError
154
- /// - Parameter request: The request.
155
- /// - Returns: The response.
156
- fileprivate func call< T: AuthRPCRequest > ( with request: T ) async throws -> T . Response {
157
- let response = try await callInternal ( with: request)
158
- if let auth = request. requestConfiguration ( ) . auth,
159
- let mfaError = Self . generateMFAError ( response: response, auth: auth) {
160
- throw mfaError
161
- } else if let error = Self . phoneCredentialInUse ( response: response) {
162
- throw error
163
- } else {
164
- return response
165
- }
166
- }
167
-
168
- #if os(iOS)
169
- private class func generateMFAError( response: AuthRPCResponse , auth: Auth ) -> Error ? {
115
+ private static func generateMFAError( response: AuthRPCResponse, auth: Auth) - > Error? {
116
+ #if !os(iOS)
117
+ return nil
118
+ #else
170
119
if let mfaResponse = response as? AuthMFAResponse ,
171
120
mfaResponse. idToken == nil ,
172
121
let enrollments = mfaResponse. mfaInfo {
@@ -189,17 +138,15 @@ private class AuthBackendRPCImplementation: AuthBackendImplementation {
189
138
} else {
190
139
return nil
191
140
}
192
- }
193
- #else
194
- private class func generateMFAError( response: AuthRPCResponse , auth: Auth ? ) -> Error ? {
195
- return nil
196
- }
197
- #endif
141
+ #endif // !os(iOS)
142
+ }
198
143
199
- #if os(iOS)
200
- // Check whether or not the successful response is actually the special case phone
201
- // auth flow that returns a temporary proof and phone number.
202
- private class func phoneCredentialInUse( response: AuthRPCResponse ) -> Error ? {
144
+ // Check whether or not the successful response is actually the special case phone
145
+ // auth flow that returns a temporary proof and phone number.
146
+ private static func phoneCredentialInUse( response: AuthRPCResponse ) -> Error ? {
147
+ #if !os(iOS)
148
+ return nil
149
+ #else
203
150
if let phoneAuthResponse = response as? VerifyPhoneNumberResponse ,
204
151
let phoneNumber = phoneAuthResponse. phoneNumber,
205
152
phoneNumber. count > 0 ,
@@ -214,12 +161,8 @@ private class AuthBackendRPCImplementation: AuthBackendImplementation {
214
161
} else {
215
162
return nil
216
163
}
217
- }
218
- #else
219
- private class func phoneCredentialInUse( response: AuthRPCResponse ) -> Error ? {
220
- return nil
221
- }
222
- #endif
164
+ #endif // !os(iOS)
165
+ }
223
166
224
167
/// Calls the RPC using HTTP request.
225
168
///
@@ -308,7 +251,7 @@ private class AuthBackendRPCImplementation: AuthBackendImplementation {
308
251
}
309
252
dictionary = decodedDictionary
310
253
311
- let response = T . Response ( )
254
+ var response = T . Response ( )
312
255
313
256
// At this point we either have an error with successfully decoded
314
257
// details in the body, or we have a response which must pass further
@@ -318,7 +261,7 @@ private class AuthBackendRPCImplementation: AuthBackendImplementation {
318
261
if error != nil {
319
262
if let errorDictionary = dictionary [ " error " ] as? [ String : AnyHashable ] {
320
263
if let errorMessage = errorDictionary [ " message " ] as? String {
321
- if let clientError = AuthBackendRPCImplementation . clientError (
264
+ if let clientError = Self . clientError (
322
265
withServerErrorMessage: errorMessage,
323
266
errorDictionary: errorDictionary,
324
267
response: response,
@@ -351,7 +294,7 @@ private class AuthBackendRPCImplementation: AuthBackendImplementation {
351
294
if let verifyAssertionRequest = request as? VerifyAssertionRequest {
352
295
if verifyAssertionRequest. returnIDPCredential {
353
296
if let errorMessage = dictionary [ " errorMessage " ] as? String {
354
- if let clientError = AuthBackendRPCImplementation . clientError (
297
+ if let clientError = Self . clientError (
355
298
withServerErrorMessage: errorMessage,
356
299
errorDictionary: dictionary,
357
300
response: response,
@@ -365,10 +308,10 @@ private class AuthBackendRPCImplementation: AuthBackendImplementation {
365
308
return response
366
309
}
367
310
368
- private class func clientError( withServerErrorMessage serverErrorMessage: String ,
369
- errorDictionary: [ String : Any ] ,
370
- response: AuthRPCResponse ,
371
- error: Error ? ) -> Error ? {
311
+ private static func clientError( withServerErrorMessage serverErrorMessage: String ,
312
+ errorDictionary: [ String : Any ] ,
313
+ response: AuthRPCResponse ,
314
+ error: Error ? ) -> Error ? {
372
315
let split = serverErrorMessage. split ( separator: " : " )
373
316
let shortErrorMessage = split. first? . trimmingCharacters ( in: . whitespacesAndNewlines)
374
317
let serverDetailErrorMessage = String ( split. count > 1 ? split [ 1 ] : " " )
0 commit comments