@@ -22,82 +22,61 @@ import Foundation
2222#endif
2323
2424@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
7127}
7228
7329@available ( iOS 13 , tvOS 13 , macOS 10 . 15 , macCatalyst 13 , watchOS 7 , * )
74- class AuthBackend {
30+ class AuthBackend : AuthBackendProtocol {
7531 static func authUserAgent( ) -> String {
7632 return " FirebaseAuth.iOS/ \( FirebaseVersion ( ) ) \( GTMFetcherStandardUserAgentString ( nil ) ) "
7733 }
7834
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+ }
8138
82- class func setTestRPCIssuer( issuer: AuthBackendRPCIssuer ) {
83- gBackendImplementation . rpcIssuer = issuer
39+ static func setTestRPCIssuer( issuer: AuthBackendRPCIssuer ) {
40+ shared . rpcIssuer = issuer
8441 }
8542
86- class func resetRPCIssuer( ) {
87- gBackendImplementation . rpcIssuer = realRPCBackend . rpcIssuer
43+ static func resetRPCIssuer( ) {
44+ shared . rpcIssuer = AuthBackendRPCIssuer ( )
8845 }
8946
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
9253 }
9354
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+ }
9675 }
9776
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 {
10180 // Kick off tasks for the async header values.
10281 async let heartbeatsHeaderValue = requestConfiguration. heartbeatLogger? . asyncHeaderValue ( )
10382 async let appCheckTokenHeaderValue = requestConfiguration. appCheck?
@@ -132,41 +111,11 @@ class AuthBackend {
132111 }
133112 return request
134113 }
135- }
136114
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
170119 if let mfaResponse = response as? AuthMFAResponse ,
171120 mfaResponse. idToken == nil ,
172121 let enrollments = mfaResponse. mfaInfo {
@@ -189,17 +138,15 @@ private class AuthBackendRPCImplementation: AuthBackendImplementation {
189138 } else {
190139 return nil
191140 }
192- }
193- #else
194- private class func generateMFAError( response: AuthRPCResponse , auth: Auth ? ) -> Error ? {
195- return nil
196- }
197- #endif
141+ #endif // !os(iOS)
142+ }
198143
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
203150 if let phoneAuthResponse = response as? VerifyPhoneNumberResponse ,
204151 let phoneNumber = phoneAuthResponse. phoneNumber,
205152 phoneNumber. count > 0 ,
@@ -214,12 +161,8 @@ private class AuthBackendRPCImplementation: AuthBackendImplementation {
214161 } else {
215162 return nil
216163 }
217- }
218- #else
219- private class func phoneCredentialInUse( response: AuthRPCResponse ) -> Error ? {
220- return nil
221- }
222- #endif
164+ #endif // !os(iOS)
165+ }
223166
224167 /// Calls the RPC using HTTP request.
225168 ///
@@ -308,7 +251,7 @@ private class AuthBackendRPCImplementation: AuthBackendImplementation {
308251 }
309252 dictionary = decodedDictionary
310253
311- let response = T . Response ( )
254+ var response = T . Response ( )
312255
313256 // At this point we either have an error with successfully decoded
314257 // details in the body, or we have a response which must pass further
@@ -318,7 +261,7 @@ private class AuthBackendRPCImplementation: AuthBackendImplementation {
318261 if error != nil {
319262 if let errorDictionary = dictionary [ " error " ] as? [ String : AnyHashable ] {
320263 if let errorMessage = errorDictionary [ " message " ] as? String {
321- if let clientError = AuthBackendRPCImplementation . clientError (
264+ if let clientError = Self . clientError (
322265 withServerErrorMessage: errorMessage,
323266 errorDictionary: errorDictionary,
324267 response: response,
@@ -351,7 +294,7 @@ private class AuthBackendRPCImplementation: AuthBackendImplementation {
351294 if let verifyAssertionRequest = request as? VerifyAssertionRequest {
352295 if verifyAssertionRequest. returnIDPCredential {
353296 if let errorMessage = dictionary [ " errorMessage " ] as? String {
354- if let clientError = AuthBackendRPCImplementation . clientError (
297+ if let clientError = Self . clientError (
355298 withServerErrorMessage: errorMessage,
356299 errorDictionary: dictionary,
357300 response: response,
@@ -365,10 +308,10 @@ private class AuthBackendRPCImplementation: AuthBackendImplementation {
365308 return response
366309 }
367310
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 ? {
372315 let split = serverErrorMessage. split ( separator: " : " )
373316 let shortErrorMessage = split. first? . trimmingCharacters ( in: . whitespacesAndNewlines)
374317 let serverDetailErrorMessage = String ( split. count > 1 ? split [ 1 ] : " " )
0 commit comments