No Description

FIRAuthBackend.m 48KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214
  1. /*
  2. * Copyright 2017 Google
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #import "FIRAuthBackend.h"
  17. #import <GTMSessionFetcher/GTMSessionFetcher.h>
  18. #import <GTMSessionFetcher/GTMSessionFetcherService.h>
  19. #import "FIRAuthErrorUtils.h"
  20. #import "FIRAuthGlobalWorkQueue.h"
  21. #import "FirebaseAuth.h"
  22. #import "FIRAuthRPCRequest.h"
  23. #import "FIRAuthRPCResponse.h"
  24. #import "FIRCreateAuthURIRequest.h"
  25. #import "FIRCreateAuthURIResponse.h"
  26. #import "FIRDeleteAccountRequest.h"
  27. #import "FIRDeleteAccountResponse.h"
  28. #import "FIRGetAccountInfoRequest.h"
  29. #import "FIRGetAccountInfoResponse.h"
  30. #import "FIRSignInWithGameCenterRequest.h"
  31. #import "FIRSignInWithGameCenterResponse.h"
  32. #import "FIRGetOOBConfirmationCodeRequest.h"
  33. #import "FIRGetOOBConfirmationCodeResponse.h"
  34. #import "FIRGetProjectConfigRequest.h"
  35. #import "FIRGetProjectConfigResponse.h"
  36. #import "FIRResetPasswordRequest.h"
  37. #import "FIRResetPasswordResponse.h"
  38. #import "FIRSendVerificationCodeRequest.h"
  39. #import "FIRSendVerificationCodeResponse.h"
  40. #import "FIRSecureTokenRequest.h"
  41. #import "FIRSecureTokenResponse.h"
  42. #import "FIRSetAccountInfoRequest.h"
  43. #import "FIRSetAccountInfoResponse.h"
  44. #import "FIRSignUpNewUserRequest.h"
  45. #import "FIRSignUpNewUserResponse.h"
  46. #import "FIRVerifyAssertionRequest.h"
  47. #import "FIRVerifyAssertionResponse.h"
  48. #import "FIRVerifyClientRequest.h"
  49. #import "FIRVerifyClientResponse.h"
  50. #import "FIRVerifyCustomTokenRequest.h"
  51. #import "FIRVerifyCustomTokenResponse.h"
  52. #import "FIRVerifyPasswordRequest.h"
  53. #import "FIRVerifyPasswordResponse.h"
  54. #import "FIREmailLinkSignInRequest.h"
  55. #import "FIREmailLinkSignInResponse.h"
  56. #import "FIRVerifyPhoneNumberRequest.h"
  57. #import "FIRVerifyPhoneNumberResponse.h"
  58. #import "FIROAuthCredential_Internal.h"
  59. #if TARGET_OS_IOS
  60. #import "FIRPhoneAuthCredential_Internal.h"
  61. #import "FIRPhoneAuthProvider.h"
  62. #endif
  63. NS_ASSUME_NONNULL_BEGIN
  64. /** @var kClientVersionHeader
  65. @brief HTTP header name for the client version.
  66. */
  67. static NSString *const kClientVersionHeader = @"X-Client-Version";
  68. /** @var kIosBundleIdentifierHeader
  69. @brief HTTP header name for iOS bundle ID.
  70. */
  71. static NSString *const kIosBundleIdentifierHeader = @"X-Ios-Bundle-Identifier";
  72. /** @var kFirebaseLocalHeader
  73. @brief HTTP header name for the firebase locale.
  74. */
  75. static NSString *const kFirebaseLocalHeader = @"X-Firebase-Locale";
  76. /** @var kFirebaseAuthCoreFrameworkMarker
  77. @brief The marker in the HTTP header that indicates the request comes from Firebase Auth Core.
  78. */
  79. static NSString *const kFirebaseAuthCoreFrameworkMarker = @"FirebaseCore-iOS";
  80. /** @var kJSONContentType
  81. @brief The value of the HTTP content-type header for JSON payloads.
  82. */
  83. static NSString *const kJSONContentType = @"application/json";
  84. /** @var kErrorDataKey
  85. @brief Key for error data in NSError returned by @c GTMSessionFetcher.
  86. */
  87. static NSString * const kErrorDataKey = @"data";
  88. /** @var kErrorKey
  89. @brief The key for the "error" value in JSON responses from the server.
  90. */
  91. static NSString *const kErrorKey = @"error";
  92. /** @var kErrorsKey
  93. @brief The key for the "errors" value in JSON responses from the server.
  94. */
  95. static NSString *const kErrorsKey = @"errors";
  96. /** @var kReasonKey
  97. @brief The key for the "reason" value in JSON responses from the server.
  98. */
  99. static NSString *const kReasonKey = @"reason";
  100. /** @var kInvalidKeyReasonValue
  101. @brief The value for the "reason" key indicating an invalid API Key was received by the server.
  102. */
  103. static NSString *const kInvalidKeyReasonValue = @"keyInvalid";
  104. /** @var kAppNotAuthorizedReasonValue
  105. @brief The value for the "reason" key indicating the App is not authorized to use Firebase
  106. Authentication.
  107. */
  108. static NSString *const kAppNotAuthorizedReasonValue = @"ipRefererBlocked";
  109. /** @var kErrorMessageKey
  110. @brief The key for an error's "message" value in JSON responses from the server.
  111. */
  112. static NSString *const kErrorMessageKey = @"message";
  113. /** @var kReturnIDPCredentialErrorMessageKey
  114. @brief The key for "errorMessage" value in JSON responses from the server, In case
  115. returnIDPCredential of a verifyAssertion request is set to @YES.
  116. */
  117. static NSString *const kReturnIDPCredentialErrorMessageKey = @"errorMessage";
  118. /** @var kUserNotFoundErrorMessage
  119. @brief This is the error message returned when the user is not found, which means the user
  120. account has been deleted given the token was once valid.
  121. */
  122. static NSString *const kUserNotFoundErrorMessage = @"USER_NOT_FOUND";
  123. /** @var kUserDeletedErrorMessage
  124. @brief This is the error message the server will respond with if the user entered an invalid
  125. email address.
  126. */
  127. static NSString *const kUserDeletedErrorMessage = @"EMAIL_NOT_FOUND";
  128. /** @var kInvalidLocalIDErrorMessage
  129. @brief This is the error message the server responds with if the user local id in the id token
  130. does not exit.
  131. */
  132. static NSString *const kInvalidLocalIDErrorMessage = @"INVALID_LOCAL_ID";
  133. /** @var kUserTokenExpiredErrorMessage
  134. @brief The error returned by the server if the token issue time is older than the account's
  135. valid_since time.
  136. */
  137. static NSString *const kUserTokenExpiredErrorMessage = @"TOKEN_EXPIRED";
  138. /** @var kTooManyRequestsErrorMessage
  139. @brief This is the error message the server will respond with if too many requests were made to
  140. a server method.
  141. */
  142. static NSString *const kTooManyRequestsErrorMessage = @"TOO_MANY_ATTEMPTS_TRY_LATER";
  143. /** @var kInvalidTokenCustomErrorMessage
  144. @brief This is the error message the server will respond with if there is a validation error
  145. with the custom token.
  146. */
  147. static NSString *const kInvalidCustomTokenErrorMessage = @"INVALID_CUSTOM_TOKEN";
  148. /** @var kCustomTokenMismatch
  149. @brief This is the error message the server will respond with if the service account and API key
  150. belong to different projects.
  151. */
  152. static NSString *const kCustomTokenMismatch = @"CREDENTIAL_MISMATCH";
  153. /** @var kInvalidCredentialErrorMessage
  154. @brief This is the error message the server responds with if the IDP token or requestUri is
  155. invalid.
  156. */
  157. static NSString *const kInvalidCredentialErrorMessage = @"INVALID_IDP_RESPONSE";
  158. /** @var kUserDisabledErrorMessage
  159. @brief The error returned by the server if the user account is diabled.
  160. */
  161. static NSString *const kUserDisabledErrorMessage = @"USER_DISABLED";
  162. /** @var kOperationNotAllowedErrorMessage
  163. @brief This is the error message the server will respond with if Admin disables IDP specified by
  164. provider.
  165. */
  166. static NSString *const kOperationNotAllowedErrorMessage = @"OPERATION_NOT_ALLOWED";
  167. /** @var kPasswordLoginDisabledErrorMessage
  168. @brief This is the error message the server responds with if password login is disabled.
  169. */
  170. static NSString *const kPasswordLoginDisabledErrorMessage = @"PASSWORD_LOGIN_DISABLED";
  171. /** @var kEmailAlreadyInUseErrorMessage
  172. @brief This is the error message the server responds with if the email address already exists.
  173. */
  174. static NSString *const kEmailAlreadyInUseErrorMessage = @"EMAIL_EXISTS";
  175. /** @var kInvalidEmailErrorMessage
  176. @brief The error returned by the server if the email is invalid.
  177. */
  178. static NSString *const kInvalidEmailErrorMessage = @"INVALID_EMAIL";
  179. /** @var kInvalidIdentifierErrorMessage
  180. @brief The error returned by the server if the identifier is invalid.
  181. */
  182. static NSString *const kInvalidIdentifierErrorMessage = @"INVALID_IDENTIFIER";
  183. /** @var kWrongPasswordErrorMessage
  184. @brief This is the error message the server will respond with if the user entered a wrong
  185. password.
  186. */
  187. static NSString *const kWrongPasswordErrorMessage = @"INVALID_PASSWORD";
  188. /** @var kCredentialTooOldErrorMessage
  189. @brief This is the error message the server responds with if account change is attempted 5
  190. minutes after signing in.
  191. */
  192. static NSString *const kCredentialTooOldErrorMessage = @"CREDENTIAL_TOO_OLD_LOGIN_AGAIN";
  193. /** @var kFederatedUserIDAlreadyLinkedMessage
  194. @brief This is the error message the server will respond with if the federated user ID has been
  195. already linked with another account.
  196. */
  197. static NSString *const kFederatedUserIDAlreadyLinkedMessage = @"FEDERATED_USER_ID_ALREADY_LINKED";
  198. /** @var kInvalidUserTokenErrorMessage
  199. @brief This is the error message the server responds with if user's saved auth credential is
  200. invalid, and the user needs to sign in again.
  201. */
  202. static NSString *const kInvalidUserTokenErrorMessage = @"INVALID_ID_TOKEN";
  203. /** @var kWeakPasswordErrorMessagePrefix
  204. @brief This is the prefix for the error message the server responds with if user's new password
  205. to be set is too weak.
  206. */
  207. static NSString *const kWeakPasswordErrorMessagePrefix = @"WEAK_PASSWORD";
  208. /** @var kExpiredActionCodeErrorMessage
  209. @brief This is the error message the server will respond with if the action code is expired.
  210. */
  211. static NSString *const kExpiredActionCodeErrorMessage = @"EXPIRED_OOB_CODE";
  212. /** @var kInvalidActionCodeErrorMessage
  213. @brief This is the error message the server will respond with if the action code is invalid.
  214. */
  215. static NSString *const kInvalidActionCodeErrorMessage = @"INVALID_OOB_CODE";
  216. /** @var kMissingEmailErrorMessage
  217. @brief This is the error message the server will respond with if the email address is missing
  218. during a "send password reset email" attempt.
  219. */
  220. static NSString *const kMissingEmailErrorMessage = @"MISSING_EMAIL";
  221. /** @var kInvalidSenderEmailErrorMessage
  222. @brief This is the error message the server will respond with if the sender email is invalid
  223. during a "send password reset email" attempt.
  224. */
  225. static NSString *const kInvalidSenderEmailErrorMessage = @"INVALID_SENDER";
  226. /** @var kInvalidMessagePayloadErrorMessage
  227. @brief This is the error message the server will respond with if there are invalid parameters in
  228. the payload during a "send password reset email" attempt.
  229. */
  230. static NSString *const kInvalidMessagePayloadErrorMessage = @"INVALID_MESSAGE_PAYLOAD";
  231. /** @var kInvalidRecipientEmailErrorMessage
  232. @brief This is the error message the server will respond with if the recipient email is invalid.
  233. */
  234. static NSString *const kInvalidRecipientEmailErrorMessage = @"INVALID_RECIPIENT_EMAIL";
  235. /** @var kMissingIosBundleIDErrorMessage
  236. @brief This is the error message the server will respond with if iOS bundle ID is missing but
  237. the iOS App store ID is provided.
  238. */
  239. static NSString *const kMissingIosBundleIDErrorMessage = @"MISSING_IOS_BUNDLE_ID";
  240. /** @var kMissingAndroidPackageNameErrorMessage
  241. @brief This is the error message the server will respond with if Android Package Name is missing
  242. but the flag indicating the app should be installed is set to true.
  243. */
  244. static NSString *const kMissingAndroidPackageNameErrorMessage = @"MISSING_ANDROID_PACKAGE_NAME";
  245. /** @var kUnauthorizedDomainErrorMessage
  246. @brief This is the error message the server will respond with if the domain of the continue URL
  247. specified is not whitelisted in the firebase console.
  248. */
  249. static NSString *const kUnauthorizedDomainErrorMessage = @"UNAUTHORIZED_DOMAIN";
  250. /** @var kInvalidProviderIDErrorMessage
  251. @brief This is the error message the server will respond with if the provider id given for the
  252. web operation is invalid.
  253. */
  254. static NSString *const kInvalidProviderIDErrorMessage = @"INVALID_PROVIDER_ID";
  255. /** @var kInvalidDynamicLinkDomainErrorMessage
  256. @brief This is the error message the server will respond with if the dynamic link domain
  257. provided in the request is invalid.
  258. */
  259. static NSString *const kInvalidDynamicLinkDomainErrorMessage = @"INVALID_DYNAMIC_LINK_DOMAIN";
  260. /** @var kInvalidContinueURIErrorMessage
  261. @brief This is the error message the server will respond with if the continue URL provided in
  262. the request is invalid.
  263. */
  264. static NSString *const kInvalidContinueURIErrorMessage = @"INVALID_CONTINUE_URI";
  265. /** @var kMissingContinueURIErrorMessage
  266. @brief This is the error message the server will respond with if there was no continue URI
  267. present in a request that required one.
  268. */
  269. static NSString *const kMissingContinueURIErrorMessage = @"MISSING_CONTINUE_URI";
  270. /** @var kInvalidPhoneNumberErrorMessage
  271. @brief This is the error message the server will respond with if an incorrectly formatted phone
  272. number is provided.
  273. */
  274. static NSString *const kInvalidPhoneNumberErrorMessage = @"INVALID_PHONE_NUMBER";
  275. /** @var kInvalidVerificationCodeErrorMessage
  276. @brief This is the error message the server will respond with if an invalid verification code is
  277. provided.
  278. */
  279. static NSString *const kInvalidVerificationCodeErrorMessage = @"INVALID_CODE";
  280. /** @var kInvalidSessionInfoErrorMessage
  281. @brief This is the error message the server will respond with if an invalid session info
  282. (verification ID) is provided.
  283. */
  284. static NSString *const kInvalidSessionInfoErrorMessage = @"INVALID_SESSION_INFO";
  285. /** @var kSessionExpiredErrorMessage
  286. @brief This is the error message the server will respond with if the SMS code has expired before
  287. it is used.
  288. */
  289. static NSString *const kSessionExpiredErrorMessage = @"SESSION_EXPIRED";
  290. /** @var kMissingOrInvalidNonceErrorMessage
  291. @brief This is the error message the server will respond with if the nonce is missing or invalid.
  292. */
  293. static NSString *const kMissingOrInvalidNonceErrorMessage = @"MISSING_OR_INVALID_NONCE";
  294. /** @var kMissingAppTokenErrorMessage
  295. @brief This is the error message the server will respond with if the APNS token is missing in a
  296. verifyClient request.
  297. */
  298. static NSString *const kMissingAppTokenErrorMessage = @"MISSING_IOS_APP_TOKEN";
  299. /** @var kMissingAppCredentialErrorMessage
  300. @brief This is the error message the server will respond with if the app token is missing in a
  301. sendVerificationCode request.
  302. */
  303. static NSString *const kMissingAppCredentialErrorMessage = @"MISSING_APP_CREDENTIAL";
  304. /** @var kInvalidAppCredentialErrorMessage
  305. @brief This is the error message the server will respond with if the app credential in a
  306. sendVerificationCode request is invalid.
  307. */
  308. static NSString *const kInvalidAppCredentialErrorMessage = @"INVALID_APP_CREDENTIAL";
  309. /** @var kQuoutaExceededErrorMessage
  310. @brief This is the error message the server will respond with if the quota for SMS text messages
  311. has been exceeded for the project.
  312. */
  313. static NSString *const kQuoutaExceededErrorMessage = @"QUOTA_EXCEEDED";
  314. /** @var kAppNotVerifiedErrorMessage
  315. @brief This is the error message the server will respond with if Firebase could not verify the
  316. app during a phone authentication flow.
  317. */
  318. static NSString *const kAppNotVerifiedErrorMessage = @"APP_NOT_VERIFIED";
  319. /** @var kMissingClientIdentifier
  320. @brief This is the error message the server will respond with if Firebase could not verify the
  321. app during a phone authentication flow when a real phone number is used and app verification
  322. is disabled for testing.
  323. */
  324. static NSString *const kMissingClientIdentifier = @"MISSING_CLIENT_IDENTIFIER";
  325. /** @var kCaptchaCheckFailedErrorMessage
  326. @brief This is the error message the server will respond with if the reCAPTCHA token provided is
  327. invalid.
  328. */
  329. static NSString *const kCaptchaCheckFailedErrorMessage = @"CAPTCHA_CHECK_FAILED";
  330. /** @var kInvalidPendingToken
  331. @brief Generic IDP error codes.
  332. */
  333. static NSString *const kInvalidPendingToken = @"INVALID_PENDING_TOKEN";
  334. /** @var gBackendImplementation
  335. @brief The singleton FIRAuthBackendImplementation instance to use.
  336. */
  337. static id<FIRAuthBackendImplementation> gBackendImplementation;
  338. /** @class FIRAuthBackendRPCImplementation
  339. @brief The default RPC-based backend implementation.
  340. */
  341. @interface FIRAuthBackendRPCImplementation : NSObject <FIRAuthBackendImplementation>
  342. /** @property RPCIssuer
  343. @brief An instance of FIRAuthBackendRPCIssuer for making RPC requests. Allows the RPC
  344. requests/responses to be easily faked.
  345. */
  346. @property(nonatomic, strong) id<FIRAuthBackendRPCIssuer> RPCIssuer;
  347. @end
  348. @implementation FIRAuthBackend
  349. + (id<FIRAuthBackendImplementation>)implementation {
  350. if (!gBackendImplementation) {
  351. gBackendImplementation = [[FIRAuthBackendRPCImplementation alloc] init];
  352. }
  353. return gBackendImplementation;
  354. }
  355. + (void)setBackendImplementation:(id<FIRAuthBackendImplementation>)backendImplementation {
  356. gBackendImplementation = backendImplementation;
  357. }
  358. + (void)setDefaultBackendImplementationWithRPCIssuer:
  359. (nullable id<FIRAuthBackendRPCIssuer>)RPCIssuer {
  360. FIRAuthBackendRPCImplementation *defaultImplementation =
  361. [[FIRAuthBackendRPCImplementation alloc] init];
  362. if (RPCIssuer) {
  363. defaultImplementation.RPCIssuer = RPCIssuer;
  364. }
  365. gBackendImplementation = defaultImplementation;
  366. }
  367. + (void)createAuthURI:(FIRCreateAuthURIRequest *)request
  368. callback:(FIRCreateAuthURIResponseCallback)callback {
  369. [[self implementation] createAuthURI:request callback:callback];
  370. }
  371. + (void)getAccountInfo:(FIRGetAccountInfoRequest *)request
  372. callback:(FIRGetAccountInfoResponseCallback)callback {
  373. [[self implementation] getAccountInfo:request callback:callback];
  374. }
  375. + (void)getProjectConfig:(FIRGetProjectConfigRequest *)request
  376. callback:(FIRGetProjectConfigResponseCallback)callback {
  377. [[self implementation] getProjectConfig:request callback:callback];
  378. }
  379. + (void)setAccountInfo:(FIRSetAccountInfoRequest *)request
  380. callback:(FIRSetAccountInfoResponseCallback)callback {
  381. [[self implementation] setAccountInfo:request callback:callback];
  382. }
  383. + (void)verifyAssertion:(FIRVerifyAssertionRequest *)request
  384. callback:(FIRVerifyAssertionResponseCallback)callback {
  385. [[self implementation] verifyAssertion:request callback:callback];
  386. }
  387. + (void)verifyCustomToken:(FIRVerifyCustomTokenRequest *)request
  388. callback:(FIRVerifyCustomTokenResponseCallback)callback {
  389. [[self implementation] verifyCustomToken:request callback:callback];
  390. }
  391. + (void)verifyPassword:(FIRVerifyPasswordRequest *)request
  392. callback:(FIRVerifyPasswordResponseCallback)callback {
  393. [[self implementation] verifyPassword:request callback:callback];
  394. }
  395. + (void)emailLinkSignin:(FIREmailLinkSignInRequest *)request
  396. callback:(FIREmailLinkSigninResponseCallback)callback {
  397. [[self implementation] emailLinkSignin:request callback:callback];
  398. }
  399. + (void)secureToken:(FIRSecureTokenRequest *)request
  400. callback:(FIRSecureTokenResponseCallback)callback {
  401. [[self implementation] secureToken:request callback:callback];
  402. }
  403. + (void)getOOBConfirmationCode:(FIRGetOOBConfirmationCodeRequest *)request
  404. callback:(FIRGetOOBConfirmationCodeResponseCallback)callback {
  405. [[self implementation] getOOBConfirmationCode:request callback:callback];
  406. }
  407. + (void)signUpNewUser:(FIRSignUpNewUserRequest *)request
  408. callback:(FIRSignupNewUserCallback)callback {
  409. [[self implementation] signUpNewUser:request callback:callback];
  410. }
  411. + (void)deleteAccount:(FIRDeleteAccountRequest *)request callback:(FIRDeleteCallBack)callback {
  412. [[self implementation] deleteAccount:request callback:callback];
  413. }
  414. + (void)signInWithGameCenter:(FIRSignInWithGameCenterRequest *)request
  415. callback:(FIRSignInWithGameCenterResponseCallback)callback {
  416. [[self implementation] signInWithGameCenter:request callback:callback];
  417. }
  418. #if TARGET_OS_IOS
  419. + (void)sendVerificationCode:(FIRSendVerificationCodeRequest *)request
  420. callback:(FIRSendVerificationCodeResponseCallback)callback {
  421. [[self implementation] sendVerificationCode:request callback:callback];
  422. }
  423. + (void)verifyPhoneNumber:(FIRVerifyPhoneNumberRequest *)request
  424. callback:(FIRVerifyPhoneNumberResponseCallback)callback {
  425. [[self implementation] verifyPhoneNumber:request callback:callback];
  426. }
  427. + (void)verifyClient:(id)request callback:(FIRVerifyClientResponseCallback)callback {
  428. [[self implementation] verifyClient:request callback:callback];
  429. }
  430. #endif
  431. + (void)resetPassword:(FIRResetPasswordRequest *)request
  432. callback:(FIRResetPasswordCallback)callback {
  433. [[self implementation] resetPassword:request callback:callback];
  434. }
  435. + (NSString *)authUserAgent {
  436. return [NSString stringWithFormat:@"FirebaseAuth.iOS/%s %@",
  437. FirebaseAuthVersionStr, GTMFetcherStandardUserAgentString(nil)];
  438. }
  439. @end
  440. @interface FIRAuthBackendRPCIssuerImplementation : NSObject <FIRAuthBackendRPCIssuer>
  441. @end
  442. @implementation FIRAuthBackendRPCIssuerImplementation {
  443. /** @var The session fetcher service.
  444. */
  445. GTMSessionFetcherService *_fetcherService;
  446. }
  447. - (instancetype)init {
  448. self = [super init];
  449. if (self) {
  450. _fetcherService = [[GTMSessionFetcherService alloc] init];
  451. _fetcherService.userAgent = [FIRAuthBackend authUserAgent];
  452. _fetcherService.callbackQueue = FIRAuthGlobalWorkQueue();
  453. // Avoid reusing the session to prevent
  454. // https://github.com/firebase/firebase-ios-sdk/issues/1261
  455. _fetcherService.reuseSession = NO;
  456. }
  457. return self;
  458. }
  459. - (void)asyncPostToURLWithRequestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration
  460. URL:(NSURL *)URL
  461. body:(nullable NSData *)body
  462. contentType:(NSString *)contentType
  463. completionHandler:(void (^)(NSData *_Nullable,
  464. NSError *_Nullable))handler {
  465. NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
  466. [request setValue:contentType forHTTPHeaderField:@"Content-Type"];
  467. NSString *additionalFrameworkMarker = requestConfiguration.additionalFrameworkMarker ?:
  468. kFirebaseAuthCoreFrameworkMarker;
  469. NSString *clientVersion = [NSString stringWithFormat:@"iOS/FirebaseSDK/%s/%@",
  470. FirebaseAuthVersionStr,
  471. additionalFrameworkMarker];
  472. [request setValue:clientVersion forHTTPHeaderField:kClientVersionHeader];
  473. NSString *bundleID = [[NSBundle mainBundle] bundleIdentifier];
  474. [request setValue:bundleID forHTTPHeaderField:kIosBundleIdentifierHeader];
  475. NSArray<NSString *> *preferredLocalizations = [NSBundle mainBundle].preferredLocalizations;
  476. if (preferredLocalizations.count) {
  477. NSString *acceptLanguage = preferredLocalizations.firstObject;
  478. [request setValue:acceptLanguage forHTTPHeaderField:@"Accept-Language"];
  479. }
  480. NSString *languageCode = requestConfiguration.languageCode;
  481. if (languageCode.length) {
  482. [request setValue:languageCode forHTTPHeaderField:kFirebaseLocalHeader];
  483. }
  484. GTMSessionFetcher *fetcher = [_fetcherService fetcherWithRequest:request];
  485. fetcher.bodyData = body;
  486. [fetcher beginFetchWithCompletionHandler:handler];
  487. }
  488. @end
  489. @implementation FIRAuthBackendRPCImplementation
  490. - (instancetype)init {
  491. self = [super init];
  492. if (self) {
  493. _RPCIssuer = [[FIRAuthBackendRPCIssuerImplementation alloc] init];
  494. }
  495. return self;
  496. }
  497. - (void)createAuthURI:(FIRCreateAuthURIRequest *)request
  498. callback:(FIRCreateAuthURIResponseCallback)callback {
  499. FIRCreateAuthURIResponse *response = [[FIRCreateAuthURIResponse alloc] init];
  500. [self postWithRequest:request response:response callback:^(NSError *error) {
  501. if (error) {
  502. callback(nil, error);
  503. } else {
  504. callback(response, nil);
  505. }
  506. }];
  507. }
  508. - (void)getAccountInfo:(FIRGetAccountInfoRequest *)request
  509. callback:(FIRGetAccountInfoResponseCallback)callback {
  510. FIRGetAccountInfoResponse *response = [[FIRGetAccountInfoResponse alloc] init];
  511. [self postWithRequest:request response:response callback:^(NSError *error) {
  512. if (error) {
  513. callback(nil, error);
  514. } else {
  515. callback(response, nil);
  516. }
  517. }];
  518. }
  519. - (void)getProjectConfig:(FIRGetProjectConfigRequest *)request
  520. callback:(FIRGetProjectConfigResponseCallback)callback {
  521. FIRGetProjectConfigResponse *response = [[FIRGetProjectConfigResponse alloc] init];
  522. [self postWithRequest:request response:response callback:^(NSError *error) {
  523. if (error) {
  524. callback(nil, error);
  525. } else {
  526. callback(response, nil);
  527. }
  528. }];
  529. }
  530. - (void)setAccountInfo:(FIRSetAccountInfoRequest *)request
  531. callback:(FIRSetAccountInfoResponseCallback)callback {
  532. FIRSetAccountInfoResponse *response = [[FIRSetAccountInfoResponse alloc] init];
  533. [self postWithRequest:request response:response callback:^(NSError *error) {
  534. if (error) {
  535. callback(nil, error);
  536. } else {
  537. callback(response, nil);
  538. }
  539. }];
  540. }
  541. - (void)verifyAssertion:(FIRVerifyAssertionRequest *)request
  542. callback:(FIRVerifyAssertionResponseCallback)callback {
  543. FIRVerifyAssertionResponse *response = [[FIRVerifyAssertionResponse alloc] init];
  544. [self postWithRequest:request response:response callback:^(NSError *error) {
  545. if (error) {
  546. callback(nil, error);
  547. return;
  548. }
  549. callback(response, nil);
  550. }];
  551. }
  552. - (void)verifyCustomToken:(FIRVerifyCustomTokenRequest *)request
  553. callback:(FIRVerifyCustomTokenResponseCallback)callback {
  554. FIRVerifyCustomTokenResponse *response = [[FIRVerifyCustomTokenResponse alloc] init];
  555. [self postWithRequest:request response:response callback:^(NSError *error) {
  556. if (error) {
  557. callback(nil, error);
  558. } else {
  559. callback(response, nil);
  560. }
  561. }];
  562. }
  563. - (void)verifyPassword:(FIRVerifyPasswordRequest *)request
  564. callback:(FIRVerifyPasswordResponseCallback)callback {
  565. FIRVerifyPasswordResponse *response = [[FIRVerifyPasswordResponse alloc] init];
  566. [self postWithRequest:request response:response callback:^(NSError *error) {
  567. if (error) {
  568. callback(nil, error);
  569. } else {
  570. callback(response, nil);
  571. }
  572. }];
  573. }
  574. - (void)emailLinkSignin:(FIREmailLinkSignInRequest *)request
  575. callback:(FIREmailLinkSigninResponseCallback)callback {
  576. FIREmailLinkSignInResponse *response = [[FIREmailLinkSignInResponse alloc] init];
  577. [self postWithRequest:request response:response callback:^(NSError *error) {
  578. if (error) {
  579. callback(nil, error);
  580. } else {
  581. callback(response, nil);
  582. }
  583. }];
  584. }
  585. - (void)secureToken:(FIRSecureTokenRequest *)request
  586. callback:(FIRSecureTokenResponseCallback)callback {
  587. FIRSecureTokenResponse *response = [[FIRSecureTokenResponse alloc] init];
  588. [self postWithRequest:request response:response callback:^(NSError *error) {
  589. if (error) {
  590. callback(nil, error);
  591. } else {
  592. callback(response, nil);
  593. }
  594. }];
  595. }
  596. - (void)getOOBConfirmationCode:(FIRGetOOBConfirmationCodeRequest *)request
  597. callback:(FIRGetOOBConfirmationCodeResponseCallback)callback {
  598. FIRGetOOBConfirmationCodeResponse *response = [[FIRGetOOBConfirmationCodeResponse alloc] init];
  599. [self postWithRequest:request response:response callback:^(NSError *error) {
  600. if (error) {
  601. callback(nil, error);
  602. } else {
  603. callback(response, nil);
  604. }
  605. }];
  606. }
  607. - (void)signUpNewUser:(FIRSignUpNewUserRequest *)request
  608. callback:(FIRSignupNewUserCallback)callback{
  609. FIRSignUpNewUserResponse *response = [[FIRSignUpNewUserResponse alloc] init];
  610. [self postWithRequest:request response:response callback:^(NSError *error) {
  611. if (error) {
  612. callback(nil, error);
  613. } else {
  614. callback(response, nil);
  615. }
  616. }];
  617. }
  618. - (void)deleteAccount:(FIRDeleteAccountRequest *)request callback:(FIRDeleteCallBack)callback {
  619. FIRDeleteAccountResponse *response = [[FIRDeleteAccountResponse alloc] init];
  620. [self postWithRequest:request response:response callback:callback];
  621. }
  622. #if TARGET_OS_IOS
  623. - (void)sendVerificationCode:(FIRSendVerificationCodeRequest *)request
  624. callback:(FIRSendVerificationCodeResponseCallback)callback {
  625. FIRSendVerificationCodeResponse *response = [[FIRSendVerificationCodeResponse alloc] init];
  626. [self postWithRequest:request response:response callback:^(NSError *error) {
  627. if (error) {
  628. callback(nil, error);
  629. } else {
  630. callback(response, error);
  631. }
  632. }];
  633. }
  634. - (void)verifyPhoneNumber:(FIRVerifyPhoneNumberRequest *)request
  635. callback:(FIRVerifyPhoneNumberResponseCallback)callback {
  636. FIRVerifyPhoneNumberResponse *response = [[FIRVerifyPhoneNumberResponse alloc] init];
  637. [self postWithRequest:request response:response callback:^(NSError *error) {
  638. if (error) {
  639. callback(nil, error);
  640. return;
  641. }
  642. // Check whether or not the successful response is actually the special case phone auth flow
  643. // that returns a temporary proof and phone number.
  644. if (response.phoneNumber.length && response.temporaryProof.length) {
  645. FIRPhoneAuthCredential *credential =
  646. [[FIRPhoneAuthCredential alloc] initWithTemporaryProof:response.temporaryProof
  647. phoneNumber:response.phoneNumber
  648. providerID:FIRPhoneAuthProviderID];
  649. callback(nil,
  650. [FIRAuthErrorUtils credentialAlreadyInUseErrorWithMessage:nil
  651. credential:credential
  652. email:nil]);
  653. return;
  654. }
  655. callback(response, nil);
  656. }];
  657. }
  658. - (void)verifyClient:(id)request callback:(FIRVerifyClientResponseCallback)callback {
  659. FIRVerifyClientResponse *response = [[FIRVerifyClientResponse alloc] init];
  660. [self postWithRequest:request response:response callback:^(NSError *error) {
  661. if (error) {
  662. callback(nil, error);
  663. return;
  664. }
  665. callback(response, nil);
  666. }];
  667. }
  668. #endif
  669. - (void)resetPassword:(FIRResetPasswordRequest *)request
  670. callback:(FIRResetPasswordCallback)callback {
  671. FIRResetPasswordResponse *response = [[FIRResetPasswordResponse alloc] init];
  672. [self postWithRequest:request response:response callback:^(NSError *error) {
  673. if (error) {
  674. callback(nil, error);
  675. return;
  676. }
  677. callback(response, nil);
  678. }];
  679. }
  680. - (void)signInWithGameCenter:(FIRSignInWithGameCenterRequest *)request
  681. callback:(FIRSignInWithGameCenterResponseCallback)callback {
  682. FIRSignInWithGameCenterResponse *response = [[FIRSignInWithGameCenterResponse alloc] init];
  683. [self postWithRequest:request response:response callback:^(NSError *error) {
  684. if (error) {
  685. if (callback) {
  686. callback(nil, error);
  687. }
  688. } else {
  689. if (callback) {
  690. callback(response, nil);
  691. }
  692. }
  693. }];
  694. }
  695. #pragma mark - Generic RPC handling methods
  696. /** @fn postWithRequest:response:callback:
  697. @brief Calls the RPC using HTTP POST.
  698. @remarks Possible error responses:
  699. @see FIRAuthInternalErrorCodeRPCRequestEncodingError
  700. @see FIRAuthInternalErrorCodeJSONSerializationError
  701. @see FIRAuthInternalErrorCodeNetworkError
  702. @see FIRAuthInternalErrorCodeUnexpectedErrorResponse
  703. @see FIRAuthInternalErrorCodeUnexpectedResponse
  704. @see FIRAuthInternalErrorCodeRPCResponseDecodingError
  705. @param request The request.
  706. @param response The empty response to be filled.
  707. @param callback The callback for both success and failure.
  708. */
  709. - (void)postWithRequest:(id<FIRAuthRPCRequest>)request
  710. response:(id<FIRAuthRPCResponse>)response
  711. callback:(void (^)(NSError * _Nullable error))callback {
  712. NSError *error;
  713. NSData *bodyData;
  714. if ([request containsPostBody]) {
  715. id postBody = [request unencodedHTTPRequestBodyWithError:&error];
  716. if (!postBody) {
  717. callback([FIRAuthErrorUtils RPCRequestEncodingErrorWithUnderlyingError:error]);
  718. return;
  719. }
  720. NSJSONWritingOptions JSONWritingOptions = 0;
  721. #if DEBUG
  722. JSONWritingOptions |= NSJSONWritingPrettyPrinted;
  723. #endif
  724. if ([NSJSONSerialization isValidJSONObject:postBody]) {
  725. bodyData = [NSJSONSerialization dataWithJSONObject:postBody
  726. options:JSONWritingOptions
  727. error:&error];
  728. if (!bodyData) {
  729. // This is an untested case. This happens exclusively when there is an error in the framework
  730. // implementation of dataWithJSONObject:options:error:. This shouldn't normally occur as
  731. // isValidJSONObject: should return NO in any case we should encounter an error.
  732. error = [FIRAuthErrorUtils JSONSerializationErrorWithUnderlyingError:error];
  733. }
  734. } else {
  735. error = [FIRAuthErrorUtils JSONSerializationErrorForUnencodableType];
  736. }
  737. if (!bodyData) {
  738. callback(error);
  739. return;
  740. }
  741. }
  742. [_RPCIssuer asyncPostToURLWithRequestConfiguration:[request requestConfiguration]
  743. URL:[request requestURL]
  744. body:bodyData
  745. contentType:kJSONContentType
  746. completionHandler:^(NSData *data, NSError *error) {
  747. // If there is an error with no body data at all, then this must be a network error.
  748. if (error && !data) {
  749. callback([FIRAuthErrorUtils networkErrorWithUnderlyingError:error]);
  750. return;
  751. }
  752. // Try to decode the HTTP response data which may contain either a successful response or error
  753. // message.
  754. NSError *jsonError;
  755. NSDictionary * dictionary =
  756. [NSJSONSerialization JSONObjectWithData:data
  757. options:NSJSONReadingMutableLeaves
  758. error:&jsonError];
  759. if (!dictionary) {
  760. if (error) {
  761. // We have an error, but we couldn't decode the body, so we have no additional information
  762. // other than the raw response and the original NSError (the jsonError is infered by the
  763. // error code (FIRAuthErrorCodeUnexpectedHTTPResponse, and is irrelevant.)
  764. callback([FIRAuthErrorUtils unexpectedErrorResponseWithData:data underlyingError:error]);
  765. } else {
  766. // This is supposed to be a "successful" response, but we couldn't deserialize the body.
  767. callback([FIRAuthErrorUtils unexpectedResponseWithData:data underlyingError:jsonError]);
  768. }
  769. return;
  770. }
  771. if (![dictionary isKindOfClass:[NSDictionary class]]) {
  772. if (error) {
  773. callback([FIRAuthErrorUtils unexpectedErrorResponseWithDeserializedResponse:dictionary]);
  774. } else {
  775. callback([FIRAuthErrorUtils unexpectedResponseWithDeserializedResponse:dictionary]);
  776. }
  777. return;
  778. }
  779. // At this point we either have an error with successfully decoded details in the body, or we
  780. // have a response which must pass further validation before we know it's truly successful.
  781. // We deal with the case where we have an error with successfully decoded error details first:
  782. if (error) {
  783. NSDictionary *errorDictionary = dictionary[kErrorKey];
  784. if ([errorDictionary isKindOfClass:[NSDictionary class]]) {
  785. id<NSObject> errorMessage = errorDictionary[kErrorMessageKey];
  786. if ([errorMessage isKindOfClass:[NSString class]]) {
  787. NSString *errorMessageString = (NSString *)errorMessage;
  788. // Contruct client error.
  789. NSError *clientError = [[self class] clientErrorWithServerErrorMessage:errorMessageString
  790. errorDictionary:errorDictionary
  791. response:response];
  792. if (clientError) {
  793. callback(clientError);
  794. return;
  795. }
  796. }
  797. // Not a message we know, return the message directly.
  798. if (errorMessage) {
  799. NSError *unexpecterErrorResponse =
  800. [FIRAuthErrorUtils unexpectedErrorResponseWithDeserializedResponse:errorDictionary];
  801. callback(unexpecterErrorResponse);
  802. return;
  803. }
  804. }
  805. // No error message at all, return the decoded response.
  806. callback([FIRAuthErrorUtils unexpectedErrorResponseWithDeserializedResponse:dictionary]);
  807. return;
  808. }
  809. // Finally, we try to populate the response object with the JSON values.
  810. if (![response setWithDictionary:dictionary error:&error]) {
  811. callback([FIRAuthErrorUtils RPCResponseDecodingErrorWithDeserializedResponse:dictionary
  812. underlyingError:error]);
  813. return;
  814. }
  815. // In case returnIDPCredential of a verifyAssertion request is set to @YES, the server may
  816. // return a 200 with a response that may contain a server error.
  817. if ([request isKindOfClass:[FIRVerifyAssertionRequest class]]) {
  818. FIRVerifyAssertionRequest *verifyAssertionRequest = (FIRVerifyAssertionRequest *)request;
  819. if (verifyAssertionRequest.returnIDPCredential) {
  820. NSString *errorMessage = dictionary[kReturnIDPCredentialErrorMessageKey];
  821. if ([errorMessage isKindOfClass:[NSString class]]) {
  822. NSString *errorString = (NSString *)errorMessage;
  823. NSError *clientError = [[self class] clientErrorWithServerErrorMessage:errorString
  824. errorDictionary:@{}
  825. response:response];
  826. if (clientError) {
  827. callback(clientError);
  828. return;
  829. }
  830. }
  831. }
  832. }
  833. // Success! The response object originally passed in can be used by the caller.
  834. callback(nil);
  835. }];
  836. }
  837. /** @fn clientErrorWithServerErrorMessage:errorDictionary:
  838. @brief Translates known server errors to client errors.
  839. @param serverErrorMessage The error message from the server.
  840. @param errorDictionary The error part of the response from the server.
  841. @param response The response from the server RPC.
  842. @return A client error, if any.
  843. */
  844. + (nullable NSError *)clientErrorWithServerErrorMessage:(NSString *)serverErrorMessage
  845. errorDictionary:(NSDictionary *)errorDictionary
  846. response:(id<FIRAuthRPCResponse>)response {
  847. NSString *shortErrorMessage = serverErrorMessage;
  848. NSString *serverDetailErrorMessage;
  849. NSRange colonRange = [serverErrorMessage rangeOfString:@":"];
  850. if (colonRange.location != NSNotFound) {
  851. shortErrorMessage = [serverErrorMessage substringToIndex:colonRange.location];
  852. shortErrorMessage =
  853. [shortErrorMessage stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
  854. serverDetailErrorMessage = [serverErrorMessage substringFromIndex:colonRange.location + 1];
  855. serverDetailErrorMessage = [serverDetailErrorMessage stringByTrimmingCharactersInSet:
  856. [NSCharacterSet whitespaceCharacterSet]];
  857. }
  858. // Delegate the responsibility for constructing the client error to the response object,
  859. // if possible.
  860. SEL clientErrorWithServerErrorMessageSelector =
  861. @selector(clientErrorWithShortErrorMessage:detailErrorMessage:);
  862. if ([response respondsToSelector:clientErrorWithServerErrorMessageSelector]) {
  863. NSError *error = [response clientErrorWithShortErrorMessage:shortErrorMessage
  864. detailErrorMessage:serverDetailErrorMessage];
  865. if (error) {
  866. return error;
  867. }
  868. }
  869. if ([shortErrorMessage isEqualToString:kUserNotFoundErrorMessage]) {
  870. return [FIRAuthErrorUtils userNotFoundErrorWithMessage:serverDetailErrorMessage];
  871. }
  872. if ([shortErrorMessage isEqualToString:kUserDeletedErrorMessage]) {
  873. return [FIRAuthErrorUtils userNotFoundErrorWithMessage:serverDetailErrorMessage];
  874. }
  875. if ([shortErrorMessage isEqualToString:kInvalidLocalIDErrorMessage]) {
  876. // This case shouldn't be necessary but it is for now: b/27908364 .
  877. return [FIRAuthErrorUtils userNotFoundErrorWithMessage:serverDetailErrorMessage];
  878. }
  879. if ([shortErrorMessage isEqualToString:kUserTokenExpiredErrorMessage]) {
  880. return [FIRAuthErrorUtils userTokenExpiredErrorWithMessage:serverDetailErrorMessage];
  881. }
  882. if ([shortErrorMessage isEqualToString:kTooManyRequestsErrorMessage]) {
  883. return [FIRAuthErrorUtils tooManyRequestsErrorWithMessage:serverDetailErrorMessage];
  884. }
  885. if ([shortErrorMessage isEqualToString:kInvalidCustomTokenErrorMessage]) {
  886. return [FIRAuthErrorUtils invalidCustomTokenErrorWithMessage:serverDetailErrorMessage];
  887. }
  888. if ([shortErrorMessage isEqualToString:kCustomTokenMismatch]) {
  889. return [FIRAuthErrorUtils customTokenMistmatchErrorWithMessage:serverDetailErrorMessage];
  890. }
  891. if ([shortErrorMessage isEqualToString:kInvalidCredentialErrorMessage] ||
  892. [shortErrorMessage isEqualToString:kInvalidPendingToken]) {
  893. return [FIRAuthErrorUtils invalidCredentialErrorWithMessage:serverDetailErrorMessage];
  894. }
  895. if ([shortErrorMessage isEqualToString:kUserDisabledErrorMessage]) {
  896. return [FIRAuthErrorUtils userDisabledErrorWithMessage:serverDetailErrorMessage];
  897. }
  898. if ([shortErrorMessage isEqualToString:kOperationNotAllowedErrorMessage]) {
  899. return [FIRAuthErrorUtils operationNotAllowedErrorWithMessage:serverDetailErrorMessage];
  900. }
  901. if ([shortErrorMessage isEqualToString:kPasswordLoginDisabledErrorMessage]) {
  902. return [FIRAuthErrorUtils operationNotAllowedErrorWithMessage:serverDetailErrorMessage];
  903. }
  904. if ([shortErrorMessage isEqualToString:kEmailAlreadyInUseErrorMessage]) {
  905. return [FIRAuthErrorUtils emailAlreadyInUseErrorWithEmail:nil];
  906. }
  907. if ([shortErrorMessage isEqualToString:kInvalidEmailErrorMessage]) {
  908. return [FIRAuthErrorUtils invalidEmailErrorWithMessage:serverDetailErrorMessage];
  909. }
  910. // "INVALID_IDENTIFIER" can be returned by createAuthURI RPC. Considering email addresses are
  911. // currently the only identifiers, we surface the FIRAuthErrorCodeInvalidEmail error code in this
  912. // case.
  913. if ([shortErrorMessage isEqualToString:kInvalidIdentifierErrorMessage]) {
  914. return [FIRAuthErrorUtils invalidEmailErrorWithMessage:serverDetailErrorMessage];
  915. }
  916. if ([shortErrorMessage isEqualToString:kWrongPasswordErrorMessage]) {
  917. return [FIRAuthErrorUtils wrongPasswordErrorWithMessage:serverDetailErrorMessage];
  918. }
  919. if ([shortErrorMessage isEqualToString:kCredentialTooOldErrorMessage]) {
  920. return [FIRAuthErrorUtils requiresRecentLoginErrorWithMessage:serverDetailErrorMessage];
  921. }
  922. if ([shortErrorMessage isEqualToString:kInvalidUserTokenErrorMessage]) {
  923. return [FIRAuthErrorUtils invalidUserTokenErrorWithMessage:serverDetailErrorMessage];
  924. }
  925. if ([shortErrorMessage isEqualToString:kFederatedUserIDAlreadyLinkedMessage]) {
  926. FIROAuthCredential *credential;
  927. NSString *email;
  928. if ([response isKindOfClass:[FIRVerifyAssertionResponse class]]) {
  929. FIRVerifyAssertionResponse *verifyAssertion = (FIRVerifyAssertionResponse *)response;
  930. credential =
  931. [[FIROAuthCredential alloc] initWithVerifyAssertionResponse:verifyAssertion];
  932. email = verifyAssertion.email;
  933. }
  934. return [FIRAuthErrorUtils credentialAlreadyInUseErrorWithMessage:serverDetailErrorMessage
  935. credential:credential
  936. email:email];
  937. }
  938. if ([shortErrorMessage isEqualToString:kWeakPasswordErrorMessagePrefix]) {
  939. return [FIRAuthErrorUtils weakPasswordErrorWithServerResponseReason:serverDetailErrorMessage];
  940. }
  941. if ([shortErrorMessage isEqualToString:kExpiredActionCodeErrorMessage]) {
  942. return [FIRAuthErrorUtils expiredActionCodeErrorWithMessage:serverDetailErrorMessage];
  943. }
  944. if ([shortErrorMessage isEqualToString:kInvalidActionCodeErrorMessage]) {
  945. return [FIRAuthErrorUtils invalidActionCodeErrorWithMessage:serverDetailErrorMessage];
  946. }
  947. if ([shortErrorMessage isEqualToString:kMissingEmailErrorMessage]) {
  948. return [FIRAuthErrorUtils missingEmailErrorWithMessage:serverDetailErrorMessage];
  949. }
  950. if ([shortErrorMessage isEqualToString:kInvalidSenderEmailErrorMessage]) {
  951. return [FIRAuthErrorUtils invalidSenderErrorWithMessage:serverDetailErrorMessage];
  952. }
  953. if ([shortErrorMessage isEqualToString:kInvalidMessagePayloadErrorMessage]) {
  954. return [FIRAuthErrorUtils invalidMessagePayloadErrorWithMessage:serverDetailErrorMessage];
  955. }
  956. if ([shortErrorMessage isEqualToString:kInvalidRecipientEmailErrorMessage]) {
  957. return [FIRAuthErrorUtils invalidRecipientEmailErrorWithMessage:serverDetailErrorMessage];
  958. }
  959. if ([shortErrorMessage isEqualToString:kMissingIosBundleIDErrorMessage]) {
  960. return [FIRAuthErrorUtils missingIosBundleIDErrorWithMessage:serverDetailErrorMessage];
  961. }
  962. if ([shortErrorMessage isEqualToString:kMissingAndroidPackageNameErrorMessage]) {
  963. return [FIRAuthErrorUtils missingAndroidPackageNameErrorWithMessage:serverDetailErrorMessage];
  964. }
  965. if ([shortErrorMessage isEqualToString:kUnauthorizedDomainErrorMessage]) {
  966. return [FIRAuthErrorUtils unauthorizedDomainErrorWithMessage:serverDetailErrorMessage];
  967. }
  968. if ([shortErrorMessage isEqualToString:kInvalidContinueURIErrorMessage]) {
  969. return [FIRAuthErrorUtils invalidContinueURIErrorWithMessage:serverDetailErrorMessage];
  970. }
  971. if ([shortErrorMessage isEqualToString:kInvalidProviderIDErrorMessage]) {
  972. return [FIRAuthErrorUtils invalidProviderIDErrorWithMessage:serverDetailErrorMessage];
  973. }
  974. if ([shortErrorMessage isEqualToString:kInvalidDynamicLinkDomainErrorMessage]) {
  975. return [FIRAuthErrorUtils invalidDynamicLinkDomainErrorWithMessage:serverDetailErrorMessage];
  976. }
  977. if ([shortErrorMessage isEqualToString:kMissingContinueURIErrorMessage]) {
  978. return [FIRAuthErrorUtils missingContinueURIErrorWithMessage:serverDetailErrorMessage];
  979. }
  980. if ([shortErrorMessage isEqualToString:kInvalidPhoneNumberErrorMessage]) {
  981. return [FIRAuthErrorUtils invalidPhoneNumberErrorWithMessage:serverDetailErrorMessage];
  982. }
  983. if ([shortErrorMessage isEqualToString:kInvalidSessionInfoErrorMessage]) {
  984. return [FIRAuthErrorUtils invalidVerificationIDErrorWithMessage:serverDetailErrorMessage];
  985. }
  986. if ([shortErrorMessage isEqualToString:kInvalidVerificationCodeErrorMessage]) {
  987. return [FIRAuthErrorUtils invalidVerificationCodeErrorWithMessage:serverDetailErrorMessage];
  988. }
  989. if ([shortErrorMessage isEqualToString:kSessionExpiredErrorMessage]) {
  990. return [FIRAuthErrorUtils sessionExpiredErrorWithMessage:serverDetailErrorMessage];
  991. }
  992. if ([shortErrorMessage isEqualToString:kMissingAppTokenErrorMessage]) {
  993. return [FIRAuthErrorUtils missingAppTokenErrorWithUnderlyingError:nil];
  994. }
  995. if ([shortErrorMessage isEqualToString:kMissingAppCredentialErrorMessage]) {
  996. return [FIRAuthErrorUtils missingAppCredentialWithMessage:serverDetailErrorMessage];
  997. }
  998. if ([shortErrorMessage isEqualToString:kInvalidAppCredentialErrorMessage]) {
  999. return [FIRAuthErrorUtils invalidAppCredentialWithMessage:serverDetailErrorMessage];
  1000. }
  1001. if ([shortErrorMessage isEqualToString:kQuoutaExceededErrorMessage]) {
  1002. return [FIRAuthErrorUtils quotaExceededErrorWithMessage:serverErrorMessage];
  1003. }
  1004. if ([shortErrorMessage isEqualToString:kAppNotVerifiedErrorMessage]) {
  1005. return [FIRAuthErrorUtils appNotVerifiedErrorWithMessage:serverErrorMessage];
  1006. }
  1007. if ([shortErrorMessage isEqualToString:kMissingClientIdentifier]) {
  1008. return [FIRAuthErrorUtils missingClientIdentifierErrorWithMessage:serverErrorMessage];
  1009. }
  1010. if ([shortErrorMessage isEqualToString:kCaptchaCheckFailedErrorMessage]) {
  1011. return [FIRAuthErrorUtils captchaCheckFailedErrorWithMessage:serverErrorMessage];
  1012. }
  1013. if ([shortErrorMessage isEqualToString:kMissingOrInvalidNonceErrorMessage]) {
  1014. return [FIRAuthErrorUtils missingOrInvalidNonceErrorWithMessage:serverDetailErrorMessage];
  1015. }
  1016. // In this case we handle an error that might be specified in the underlying errors dictionary,
  1017. // the error message in determined based on the @c reason key in the dictionary.
  1018. if (errorDictionary[kErrorsKey]) {
  1019. // Check for underlying error with reason = keyInvalid;
  1020. id underlyingErrors = errorDictionary[kErrorsKey];
  1021. if ([underlyingErrors isKindOfClass:[NSArray class]]) {
  1022. NSArray *underlyingErrorsArray = (NSArray *)underlyingErrors;
  1023. for (id underlyingError in underlyingErrorsArray) {
  1024. if ([underlyingError isKindOfClass:[NSDictionary class]]) {
  1025. NSDictionary *underlyingErrorDictionary = (NSDictionary *)underlyingError;
  1026. NSString *reason = underlyingErrorDictionary[kReasonKey];
  1027. if ([reason hasPrefix:kInvalidKeyReasonValue]) {
  1028. return [FIRAuthErrorUtils invalidAPIKeyError];
  1029. }
  1030. if ([reason isEqualToString:kAppNotAuthorizedReasonValue]) {
  1031. return [FIRAuthErrorUtils appNotAuthorizedError];
  1032. }
  1033. }
  1034. }
  1035. }
  1036. }
  1037. return nil;
  1038. }
  1039. @end
  1040. NS_ASSUME_NONNULL_END