FIRAuthBackend.m 68 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583
  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 "FirebaseAuth/Sources/Backend/FIRAuthBackend.h"
  17. #if SWIFT_PACKAGE
  18. @import GTMSessionFetcherCore;
  19. #else
  20. #import <GTMSessionFetcher/GTMSessionFetcher.h>
  21. #import <GTMSessionFetcher/GTMSessionFetcherService.h>
  22. #endif
  23. #import "FirebaseAuth/Sources/Public/FirebaseAuth/FirebaseAuth.h"
  24. #import "FirebaseAuth/Sources/Auth/FIRAuthGlobalWorkQueue.h"
  25. #import "FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthCredential_Internal.h"
  26. #import "FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIRequest.h"
  27. #import "FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIResponse.h"
  28. #import "FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountRequest.h"
  29. #import "FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountResponse.h"
  30. #import "FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInRequest.h"
  31. #import "FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInResponse.h"
  32. #import "FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoRequest.h"
  33. #import "FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoResponse.h"
  34. #import "FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeRequest.h"
  35. #import "FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeResponse.h"
  36. #import "FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigRequest.h"
  37. #import "FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigResponse.h"
  38. #import "FirebaseAuth/Sources/Backend/RPC/FIRGetRecaptchaConfigRequest.h"
  39. #import "FirebaseAuth/Sources/Backend/RPC/FIRGetRecaptchaConfigResponse.h"
  40. #import "FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordRequest.h"
  41. #import "FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordResponse.h"
  42. #import "FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenRequest.h"
  43. #import "FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenResponse.h"
  44. #import "FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeRequest.h"
  45. #import "FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeResponse.h"
  46. #import "FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoRequest.h"
  47. #import "FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoResponse.h"
  48. #import "FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterRequest.h"
  49. #import "FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterResponse.h"
  50. #import "FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.h"
  51. #import "FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserResponse.h"
  52. #import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h"
  53. #import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionResponse.h"
  54. #import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientRequest.h"
  55. #import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientResponse.h"
  56. #import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenRequest.h"
  57. #import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenResponse.h"
  58. #import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordRequest.h"
  59. #import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordResponse.h"
  60. #import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberRequest.h"
  61. #import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberResponse.h"
  62. #import "FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h"
  63. #import "FirebaseCore/Extension/FirebaseCoreInternal.h"
  64. #if TARGET_OS_IOS
  65. #import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneAuthProvider.h"
  66. #import "FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthCredential_Internal.h"
  67. #import "FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorInfo+Internal.h"
  68. #endif
  69. NS_ASSUME_NONNULL_BEGIN
  70. /** @var kClientVersionHeader
  71. @brief HTTP header name for the client version.
  72. */
  73. static NSString *const kClientVersionHeader = @"X-Client-Version";
  74. /** @var kIosBundleIdentifierHeader
  75. @brief HTTP header name for iOS bundle ID.
  76. */
  77. static NSString *const kIosBundleIdentifierHeader = @"X-Ios-Bundle-Identifier";
  78. /** @var kFirebaseLocalHeader
  79. @brief HTTP header name for the firebase locale.
  80. */
  81. static NSString *const kFirebaseLocalHeader = @"X-Firebase-Locale";
  82. /** @var kFirebaseAppIDHeader
  83. @brief HTTP header name for the Firebase app ID.
  84. */
  85. static NSString *const kFirebaseAppIDHeader = @"X-Firebase-GMPID";
  86. /** @var kFirebaseHeartbeatHeader
  87. @brief HTTP header name for a Firebase heartbeats payload.
  88. */
  89. static NSString *const kFirebaseHeartbeatHeader = @"X-Firebase-Client";
  90. /** @var kFirebaseAuthCoreFrameworkMarker
  91. @brief The marker in the HTTP header that indicates the request comes from Firebase Auth Core.
  92. */
  93. static NSString *const kFirebaseAuthCoreFrameworkMarker = @"FirebaseCore-iOS";
  94. /** @var kJSONContentType
  95. @brief The value of the HTTP content-type header for JSON payloads.
  96. */
  97. static NSString *const kJSONContentType = @"application/json";
  98. /** @var kErrorDataKey
  99. @brief Key for error data in NSError returned by @c GTMSessionFetcher.
  100. */
  101. static NSString *const kErrorDataKey = @"data";
  102. /** @var kErrorKey
  103. @brief The key for the "error" value in JSON responses from the server.
  104. */
  105. static NSString *const kErrorKey = @"error";
  106. /** @var kErrorsKey
  107. @brief The key for the "errors" value in JSON responses from the server.
  108. */
  109. static NSString *const kErrorsKey = @"errors";
  110. /** @var kReasonKey
  111. @brief The key for the "reason" value in JSON responses from the server.
  112. */
  113. static NSString *const kReasonKey = @"reason";
  114. /** @var kInvalidKeyReasonValue
  115. @brief The value for the "reason" key indicating an invalid API Key was received by the server.
  116. */
  117. static NSString *const kInvalidKeyReasonValue = @"keyInvalid";
  118. /** @var kAppNotAuthorizedReasonValue
  119. @brief The value for the "reason" key indicating the App is not authorized to use Firebase
  120. Authentication.
  121. */
  122. static NSString *const kAppNotAuthorizedReasonValue = @"ipRefererBlocked";
  123. /** @var kErrorMessageKey
  124. @brief The key for an error's "message" value in JSON responses from the server.
  125. */
  126. static NSString *const kErrorMessageKey = @"message";
  127. /** @var kReturnIDPCredentialErrorMessageKey
  128. @brief The key for "errorMessage" value in JSON responses from the server, In case
  129. returnIDPCredential of a verifyAssertion request is set to @YES.
  130. */
  131. static NSString *const kReturnIDPCredentialErrorMessageKey = @"errorMessage";
  132. /** @var kUserNotFoundErrorMessage
  133. @brief This is the error message returned when the user is not found, which means the user
  134. account has been deleted given the token was once valid.
  135. */
  136. static NSString *const kUserNotFoundErrorMessage = @"USER_NOT_FOUND";
  137. /** @var kUserDeletedErrorMessage
  138. @brief This is the error message the server will respond with if the user entered an invalid
  139. email address.
  140. */
  141. static NSString *const kUserDeletedErrorMessage = @"EMAIL_NOT_FOUND";
  142. /** @var kInvalidLocalIDErrorMessage
  143. @brief This is the error message the server responds with if the user local id in the id token
  144. does not exit.
  145. */
  146. static NSString *const kInvalidLocalIDErrorMessage = @"INVALID_LOCAL_ID";
  147. /** @var kUserTokenExpiredErrorMessage
  148. @brief The error returned by the server if the token issue time is older than the account's
  149. valid_since time.
  150. */
  151. static NSString *const kUserTokenExpiredErrorMessage = @"TOKEN_EXPIRED";
  152. /** @var kTooManyRequestsErrorMessage
  153. @brief This is the error message the server will respond with if too many requests were made to
  154. a server method.
  155. */
  156. static NSString *const kTooManyRequestsErrorMessage = @"TOO_MANY_ATTEMPTS_TRY_LATER";
  157. /** @var kInvalidCustomTokenErrorMessage
  158. @brief This is the error message the server will respond with if there is a validation error
  159. with the custom token.
  160. */
  161. static NSString *const kInvalidCustomTokenErrorMessage = @"INVALID_CUSTOM_TOKEN";
  162. /** @var kCustomTokenMismatch
  163. @brief This is the error message the server will respond with if the service account and API key
  164. belong to different projects.
  165. */
  166. static NSString *const kCustomTokenMismatch = @"CREDENTIAL_MISMATCH";
  167. /** @var kInvalidCredentialErrorMessage
  168. @brief This is the error message the server responds with if the IDP token or requestUri is
  169. invalid.
  170. */
  171. static NSString *const kInvalidCredentialErrorMessage = @"INVALID_IDP_RESPONSE";
  172. /** @var kUserDisabledErrorMessage
  173. @brief The error returned by the server if the user account is diabled.
  174. */
  175. static NSString *const kUserDisabledErrorMessage = @"USER_DISABLED";
  176. /** @var kOperationNotAllowedErrorMessage
  177. @brief This is the error message the server will respond with if Admin disables IDP specified by
  178. provider.
  179. */
  180. static NSString *const kOperationNotAllowedErrorMessage = @"OPERATION_NOT_ALLOWED";
  181. /** @var kPasswordLoginDisabledErrorMessage
  182. @brief This is the error message the server responds with if password login is disabled.
  183. */
  184. static NSString *const kPasswordLoginDisabledErrorMessage = @"PASSWORD_LOGIN_DISABLED";
  185. /** @var kEmailAlreadyInUseErrorMessage
  186. @brief This is the error message the server responds with if the email address already exists.
  187. */
  188. static NSString *const kEmailAlreadyInUseErrorMessage = @"EMAIL_EXISTS";
  189. /** @var kInvalidEmailErrorMessage
  190. @brief The error returned by the server if the email is invalid.
  191. */
  192. static NSString *const kInvalidEmailErrorMessage = @"INVALID_EMAIL";
  193. /** @var kInvalidIdentifierErrorMessage
  194. @brief The error returned by the server if the identifier is invalid.
  195. */
  196. static NSString *const kInvalidIdentifierErrorMessage = @"INVALID_IDENTIFIER";
  197. /** @var kWrongPasswordErrorMessage
  198. @brief This is the error message the server will respond with if the user entered a wrong
  199. password.
  200. */
  201. static NSString *const kWrongPasswordErrorMessage = @"INVALID_PASSWORD";
  202. /** @var kCredentialTooOldErrorMessage
  203. @brief This is the error message the server responds with if account change is attempted 5
  204. minutes after signing in.
  205. */
  206. static NSString *const kCredentialTooOldErrorMessage = @"CREDENTIAL_TOO_OLD_LOGIN_AGAIN";
  207. /** @var kFederatedUserIDAlreadyLinkedMessage
  208. @brief This is the error message the server will respond with if the federated user ID has been
  209. already linked with another account.
  210. */
  211. static NSString *const kFederatedUserIDAlreadyLinkedMessage = @"FEDERATED_USER_ID_ALREADY_LINKED";
  212. /** @var kInvalidUserTokenErrorMessage
  213. @brief This is the error message the server responds with if user's saved auth credential is
  214. invalid, and the user needs to sign in again.
  215. */
  216. static NSString *const kInvalidUserTokenErrorMessage = @"INVALID_ID_TOKEN";
  217. /** @var kWeakPasswordErrorMessagePrefix
  218. @brief This is the prefix for the error message the server responds with if user's new password
  219. to be set is too weak.
  220. */
  221. static NSString *const kWeakPasswordErrorMessagePrefix = @"WEAK_PASSWORD";
  222. /** @var kExpiredActionCodeErrorMessage
  223. @brief This is the error message the server will respond with if the action code is expired.
  224. */
  225. static NSString *const kExpiredActionCodeErrorMessage = @"EXPIRED_OOB_CODE";
  226. /** @var kInvalidActionCodeErrorMessage
  227. @brief This is the error message the server will respond with if the action code is invalid.
  228. */
  229. static NSString *const kInvalidActionCodeErrorMessage = @"INVALID_OOB_CODE";
  230. /** @var kMissingEmailErrorMessage
  231. @brief This is the error message the server will respond with if the email address is missing
  232. during a "send password reset email" attempt.
  233. */
  234. static NSString *const kMissingEmailErrorMessage = @"MISSING_EMAIL";
  235. /** @var kInvalidSenderEmailErrorMessage
  236. @brief This is the error message the server will respond with if the sender email is invalid
  237. during a "send password reset email" attempt.
  238. */
  239. static NSString *const kInvalidSenderEmailErrorMessage = @"INVALID_SENDER";
  240. /** @var kInvalidMessagePayloadErrorMessage
  241. @brief This is the error message the server will respond with if there are invalid parameters in
  242. the payload during a "send password reset email" attempt.
  243. */
  244. static NSString *const kInvalidMessagePayloadErrorMessage = @"INVALID_MESSAGE_PAYLOAD";
  245. /** @var kInvalidRecipientEmailErrorMessage
  246. @brief This is the error message the server will respond with if the recipient email is invalid.
  247. */
  248. static NSString *const kInvalidRecipientEmailErrorMessage = @"INVALID_RECIPIENT_EMAIL";
  249. /** @var kMissingIosBundleIDErrorMessage
  250. @brief This is the error message the server will respond with if iOS bundle ID is missing but
  251. the iOS App store ID is provided.
  252. */
  253. static NSString *const kMissingIosBundleIDErrorMessage = @"MISSING_IOS_BUNDLE_ID";
  254. /** @var kMissingAndroidPackageNameErrorMessage
  255. @brief This is the error message the server will respond with if Android Package Name is missing
  256. but the flag indicating the app should be installed is set to true.
  257. */
  258. static NSString *const kMissingAndroidPackageNameErrorMessage = @"MISSING_ANDROID_PACKAGE_NAME";
  259. /** @var kUnauthorizedDomainErrorMessage
  260. @brief This is the error message the server will respond with if the domain of the continue URL
  261. specified is not allowlisted in the Firebase console.
  262. */
  263. static NSString *const kUnauthorizedDomainErrorMessage = @"UNAUTHORIZED_DOMAIN";
  264. /** @var kInvalidProviderIDErrorMessage
  265. @brief This is the error message the server will respond with if the provider id given for the
  266. web operation is invalid.
  267. */
  268. static NSString *const kInvalidProviderIDErrorMessage = @"INVALID_PROVIDER_ID";
  269. /** @var kInvalidDynamicLinkDomainErrorMessage
  270. @brief This is the error message the server will respond with if the dynamic link domain
  271. provided in the request is invalid.
  272. */
  273. static NSString *const kInvalidDynamicLinkDomainErrorMessage = @"INVALID_DYNAMIC_LINK_DOMAIN";
  274. /** @var kInvalidContinueURIErrorMessage
  275. @brief This is the error message the server will respond with if the continue URL provided in
  276. the request is invalid.
  277. */
  278. static NSString *const kInvalidContinueURIErrorMessage = @"INVALID_CONTINUE_URI";
  279. /** @var kMissingContinueURIErrorMessage
  280. @brief This is the error message the server will respond with if there was no continue URI
  281. present in a request that required one.
  282. */
  283. static NSString *const kMissingContinueURIErrorMessage = @"MISSING_CONTINUE_URI";
  284. /** @var kInvalidPhoneNumberErrorMessage
  285. @brief This is the error message the server will respond with if an incorrectly formatted phone
  286. number is provided.
  287. */
  288. static NSString *const kInvalidPhoneNumberErrorMessage = @"INVALID_PHONE_NUMBER";
  289. /** @var kInvalidVerificationCodeErrorMessage
  290. @brief This is the error message the server will respond with if an invalid verification code is
  291. provided.
  292. */
  293. static NSString *const kInvalidVerificationCodeErrorMessage = @"INVALID_CODE";
  294. /** @var kInvalidSessionInfoErrorMessage
  295. @brief This is the error message the server will respond with if an invalid session info
  296. (verification ID) is provided.
  297. */
  298. static NSString *const kInvalidSessionInfoErrorMessage = @"INVALID_SESSION_INFO";
  299. /** @var kSessionExpiredErrorMessage
  300. @brief This is the error message the server will respond with if the SMS code has expired before
  301. it is used.
  302. */
  303. static NSString *const kSessionExpiredErrorMessage = @"SESSION_EXPIRED";
  304. /** @var kMissingOrInvalidNonceErrorMessage
  305. @brief This is the error message the server will respond with if the nonce is missing or
  306. invalid.
  307. */
  308. static NSString *const kMissingOrInvalidNonceErrorMessage = @"MISSING_OR_INVALID_NONCE";
  309. /** @var kMissingAppTokenErrorMessage
  310. @brief This is the error message the server will respond with if the APNS token is missing in a
  311. verifyClient request.
  312. */
  313. static NSString *const kMissingAppTokenErrorMessage = @"MISSING_IOS_APP_TOKEN";
  314. /** @var kMissingAppCredentialErrorMessage
  315. @brief This is the error message the server will respond with if the app token is missing in a
  316. sendVerificationCode request.
  317. */
  318. static NSString *const kMissingAppCredentialErrorMessage = @"MISSING_APP_CREDENTIAL";
  319. /** @var kInvalidAppCredentialErrorMessage
  320. @brief This is the error message the server will respond with if the app credential in a
  321. sendVerificationCode request is invalid.
  322. */
  323. static NSString *const kInvalidAppCredentialErrorMessage = @"INVALID_APP_CREDENTIAL";
  324. /** @var kQuoutaExceededErrorMessage
  325. @brief This is the error message the server will respond with if the quota for SMS text messages
  326. has been exceeded for the project.
  327. */
  328. static NSString *const kQuoutaExceededErrorMessage = @"QUOTA_EXCEEDED";
  329. /** @var kAppNotVerifiedErrorMessage
  330. @brief This is the error message the server will respond with if Firebase could not verify the
  331. app during a phone authentication flow.
  332. */
  333. static NSString *const kAppNotVerifiedErrorMessage = @"APP_NOT_VERIFIED";
  334. /** @var kMissingClientIdentifier
  335. @brief This is the error message the server will respond with if Firebase could not verify the
  336. app during a phone authentication flow when a real phone number is used and app verification
  337. is disabled for testing.
  338. */
  339. static NSString *const kMissingClientIdentifier = @"MISSING_CLIENT_IDENTIFIER";
  340. /** @var kCaptchaCheckFailedErrorMessage
  341. @brief This is the error message the server will respond with if the reCAPTCHA token provided is
  342. invalid.
  343. */
  344. static NSString *const kCaptchaCheckFailedErrorMessage = @"CAPTCHA_CHECK_FAILED";
  345. /** @var kTenantIDMismatch
  346. @brief This is the error message the server will respond with if the tenant id mismatches.
  347. */
  348. static NSString *const kTenantIDMismatch = @"TENANT_ID_MISMATCH";
  349. /** @var kUnsupportedTenantOperation
  350. @brief This is the error message the server will respond with if the operation does not support
  351. multi-tenant.
  352. */
  353. static NSString *const kUnsupportedTenantOperation = @"UNSUPPORTED_TENANT_OPERATION";
  354. /** @var kMissingMFAPendingCredentialErrorMessage
  355. @brief This is the error message the server will respond with if the MFA pending credential is
  356. missing.
  357. */
  358. static NSString *const kMissingMFAPendingCredentialErrorMessage = @"MISSING_MFA_PENDING_CREDENTIAL";
  359. /** @var kMissingMFAEnrollmentIDErrorMessage
  360. @brief This is the error message the server will respond with if the MFA enrollment ID is missing.
  361. */
  362. static NSString *const kMissingMFAEnrollmentIDErrorMessage = @"MISSING_MFA_ENROLLMENT_ID";
  363. /** @var kInvalidMFAPendingCredentialErrorMessage
  364. @brief This is the error message the server will respond with if the MFA pending credential is
  365. invalid.
  366. */
  367. static NSString *const kInvalidMFAPendingCredentialErrorMessage = @"INVALID_MFA_PENDING_CREDENTIAL";
  368. /** @var kMFAEnrollmentNotFoundErrorMessage
  369. @brief This is the error message the server will respond with if the MFA enrollment info is not
  370. found.
  371. */
  372. static NSString *const kMFAEnrollmentNotFoundErrorMessage = @"MFA_ENROLLMENT_NOT_FOUND";
  373. /** @var kAdminOnlyOperationErrorMessage
  374. @brief This is the error message the server will respond with if the operation is admin only.
  375. */
  376. static NSString *const kAdminOnlyOperationErrorMessage = @"ADMIN_ONLY_OPERATION";
  377. /** @var kUnverifiedEmailErrorMessage
  378. @brief This is the error message the server will respond with if the email is unverified.
  379. */
  380. static NSString *const kUnverifiedEmailErrorMessage = @"UNVERIFIED_EMAIL";
  381. /** @var kSecondFactorExistsErrorMessage
  382. @brief This is the error message the server will respond with if the second factor already exsists.
  383. */
  384. static NSString *const kSecondFactorExistsErrorMessage = @"SECOND_FACTOR_EXISTS";
  385. /** @var kSecondFactorLimitExceededErrorMessage
  386. @brief This is the error message the server will respond with if the number of second factor
  387. reaches the limit.
  388. */
  389. static NSString *const kSecondFactorLimitExceededErrorMessage = @"SECOND_FACTOR_LIMIT_EXCEEDED";
  390. /** @var kUnsupportedFirstFactorErrorMessage
  391. @brief This is the error message the server will respond with if the first factor doesn't support
  392. MFA.
  393. */
  394. static NSString *const kUnsupportedFirstFactorErrorMessage = @"UNSUPPORTED_FIRST_FACTOR";
  395. /** @var kBlockingCloudFunctionErrorResponse
  396. @brief This is the error message blocking Cloud Functions.
  397. */
  398. static NSString *const kBlockingCloudFunctionErrorResponse = @"BLOCKING_FUNCTION_ERROR_RESPONSE";
  399. /** @var kEmailChangeNeedsVerificationErrorMessage
  400. @brief This is the error message the server will respond with if changing an unverified email.
  401. */
  402. static NSString *const kEmailChangeNeedsVerificationErrorMessage =
  403. @"EMAIL_CHANGE_NEEDS_VERIFICATION";
  404. /** @var kInvalidPendingToken
  405. @brief Generic IDP error codes.
  406. */
  407. static NSString *const kInvalidPendingToken = @"INVALID_PENDING_TOKEN";
  408. /** @var kMissingRecaptchaToken
  409. @brief This is the error message the server will respond with if the recaptcha token is missing
  410. in the request.
  411. */
  412. static NSString *const kInvalidRecaptchaScore = @"INVALID_RECAPTCHA_SCORE";
  413. /** @var kMissingRecaptchaToken
  414. @brief This is the error message the server will respond with if the recaptcha token is missing
  415. in the request.
  416. */
  417. static NSString *const kMissingRecaptchaToken = @"MISSING_RECAPTCHA_TOKEN";
  418. /** @var kMissingRecaptchaToken
  419. @brief This is the error message the server will respond with if the recaptcha token is missing
  420. in the request.
  421. */
  422. static NSString *const kInvalidRecaptchaToken = @"INVALID_RECAPTCHA_TOKEN";
  423. /** @var kMissingRecaptchaToken
  424. @brief This is the error message the server will respond with if the recaptcha token is missing
  425. in the request.
  426. */
  427. static NSString *const kInvalidRecaptchaAction = @"INVALID_RECAPTCHA_ACTION";
  428. /** @var kMissingRecaptchaToken
  429. @brief This is the error message the server will respond with if the recaptcha token is missing
  430. in the request.
  431. */
  432. static NSString *const kInvalidRecaptchaEnforcementState = @"INVALID_RECAPTCHA_ENFORCEMENT_STATE";
  433. /** @var kMissingRecaptchaToken
  434. @brief This is the error message the server will respond with if the recaptcha token is missing
  435. in the request.
  436. */
  437. static NSString *const kRecaptchaNotEnabled = @"RECAPTCHA_NOT_ENABLED";
  438. /** @var kMissingRecaptchaToken
  439. @brief This is the error message the server will respond with if the recaptcha token is missing
  440. in the request.
  441. */
  442. static NSString *const kMissingClientType = @"MISSING_CLIENT_TYPE";
  443. /** @var kMissingRecaptchaToken
  444. @brief This is the error message the server will respond with if the recaptcha token is missing
  445. in the request.
  446. */
  447. static NSString *const kMissingRecaptchaVersion = @"MISSING_RECAPTCHA_VERSION";
  448. /** @var kMissingRecaptchaToken
  449. @brief This is the error message the server will respond with if the recaptcha token is missing
  450. in the request.
  451. */
  452. static NSString *const kMissingInvalidReqType = @"INVALID_REQ_TYPE";
  453. /** @var kMissingRecaptchaToken
  454. @brief This is the error message the server will respond with if the recaptcha token is missing
  455. in the request.
  456. */
  457. static NSString *const kInvalidRecaptchaVersion = @"INVALID_RECAPTCHA_VERSION";
  458. /** @var gBackendImplementation
  459. @brief The singleton FIRAuthBackendImplementation instance to use.
  460. */
  461. static id<FIRAuthBackendImplementation> gBackendImplementation;
  462. /** @class FIRAuthBackendRPCImplementation
  463. @brief The default RPC-based backend implementation.
  464. */
  465. @interface FIRAuthBackendRPCImplementation : NSObject <FIRAuthBackendImplementation>
  466. /** @property RPCIssuer
  467. @brief An instance of FIRAuthBackendRPCIssuer for making RPC requests. Allows the RPC
  468. requests/responses to be easily faked.
  469. */
  470. @property(nonatomic, strong) id<FIRAuthBackendRPCIssuer> RPCIssuer;
  471. @end
  472. @implementation FIRAuthBackend
  473. + (id<FIRAuthBackendImplementation>)implementation {
  474. if (!gBackendImplementation) {
  475. gBackendImplementation = [[FIRAuthBackendRPCImplementation alloc] init];
  476. }
  477. return gBackendImplementation;
  478. }
  479. + (void)setBackendImplementation:(id<FIRAuthBackendImplementation>)backendImplementation {
  480. gBackendImplementation = backendImplementation;
  481. }
  482. + (void)setDefaultBackendImplementationWithRPCIssuer:
  483. (nullable id<FIRAuthBackendRPCIssuer>)RPCIssuer {
  484. FIRAuthBackendRPCImplementation *defaultImplementation =
  485. [[FIRAuthBackendRPCImplementation alloc] init];
  486. if (RPCIssuer) {
  487. defaultImplementation.RPCIssuer = RPCIssuer;
  488. }
  489. gBackendImplementation = defaultImplementation;
  490. }
  491. + (void)createAuthURI:(FIRCreateAuthURIRequest *)request
  492. callback:(FIRCreateAuthURIResponseCallback)callback {
  493. [[self implementation] createAuthURI:request callback:callback];
  494. }
  495. + (void)getAccountInfo:(FIRGetAccountInfoRequest *)request
  496. callback:(FIRGetAccountInfoResponseCallback)callback {
  497. [[self implementation] getAccountInfo:request callback:callback];
  498. }
  499. + (void)getProjectConfig:(FIRGetProjectConfigRequest *)request
  500. callback:(FIRGetProjectConfigResponseCallback)callback {
  501. [[self implementation] getProjectConfig:request callback:callback];
  502. }
  503. + (void)setAccountInfo:(FIRSetAccountInfoRequest *)request
  504. callback:(FIRSetAccountInfoResponseCallback)callback {
  505. [[self implementation] setAccountInfo:request callback:callback];
  506. }
  507. + (void)verifyAssertion:(FIRVerifyAssertionRequest *)request
  508. callback:(FIRVerifyAssertionResponseCallback)callback {
  509. [[self implementation] verifyAssertion:request callback:callback];
  510. }
  511. + (void)verifyCustomToken:(FIRVerifyCustomTokenRequest *)request
  512. callback:(FIRVerifyCustomTokenResponseCallback)callback {
  513. [[self implementation] verifyCustomToken:request callback:callback];
  514. }
  515. + (void)verifyPassword:(FIRVerifyPasswordRequest *)request
  516. callback:(FIRVerifyPasswordResponseCallback)callback {
  517. [[self implementation] verifyPassword:request callback:callback];
  518. }
  519. + (void)emailLinkSignin:(FIREmailLinkSignInRequest *)request
  520. callback:(FIREmailLinkSigninResponseCallback)callback {
  521. [[self implementation] emailLinkSignin:request callback:callback];
  522. }
  523. + (void)secureToken:(FIRSecureTokenRequest *)request
  524. callback:(FIRSecureTokenResponseCallback)callback {
  525. [[self implementation] secureToken:request callback:callback];
  526. }
  527. + (void)getOOBConfirmationCode:(FIRGetOOBConfirmationCodeRequest *)request
  528. callback:(FIRGetOOBConfirmationCodeResponseCallback)callback {
  529. [[self implementation] getOOBConfirmationCode:request callback:callback];
  530. }
  531. + (void)signUpNewUser:(FIRSignUpNewUserRequest *)request
  532. callback:(FIRSignupNewUserCallback)callback {
  533. [[self implementation] signUpNewUser:request callback:callback];
  534. }
  535. + (void)deleteAccount:(FIRDeleteAccountRequest *)request callback:(FIRDeleteCallBack)callback {
  536. [[self implementation] deleteAccount:request callback:callback];
  537. }
  538. + (void)signInWithGameCenter:(FIRSignInWithGameCenterRequest *)request
  539. callback:(FIRSignInWithGameCenterResponseCallback)callback {
  540. [[self implementation] signInWithGameCenter:request callback:callback];
  541. }
  542. #if TARGET_OS_IOS
  543. + (void)sendVerificationCode:(FIRSendVerificationCodeRequest *)request
  544. callback:(FIRSendVerificationCodeResponseCallback)callback {
  545. [[self implementation] sendVerificationCode:request callback:callback];
  546. }
  547. + (void)verifyPhoneNumber:(FIRVerifyPhoneNumberRequest *)request
  548. callback:(FIRVerifyPhoneNumberResponseCallback)callback {
  549. [[self implementation] verifyPhoneNumber:request callback:callback];
  550. }
  551. + (void)verifyClient:(id)request callback:(FIRVerifyClientResponseCallback)callback {
  552. [[self implementation] verifyClient:request callback:callback];
  553. }
  554. #endif
  555. + (void)resetPassword:(FIRResetPasswordRequest *)request
  556. callback:(FIRResetPasswordCallback)callback {
  557. [[self implementation] resetPassword:request callback:callback];
  558. }
  559. + (void)getRecaptchaConfig:(FIRGetRecaptchaConfigRequest *)request
  560. callback:(FIRGetRecaptchaConfigResponseCallback)callback {
  561. [[self implementation] getRecaptchaConfig:request callback:callback];
  562. }
  563. + (NSString *)authUserAgent {
  564. return [NSString stringWithFormat:@"FirebaseAuth.iOS/%@ %@", FIRFirebaseVersion(),
  565. GTMFetcherStandardUserAgentString(nil)];
  566. }
  567. + (NSMutableURLRequest *)requestWithURL:(NSURL *)URL
  568. contentType:(NSString *)contentType
  569. requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration {
  570. NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
  571. [request setValue:contentType forHTTPHeaderField:@"Content-Type"];
  572. NSString *additionalFrameworkMarker =
  573. requestConfiguration.additionalFrameworkMarker ?: kFirebaseAuthCoreFrameworkMarker;
  574. NSString *clientVersion = [NSString
  575. stringWithFormat:@"iOS/FirebaseSDK/%@/%@", FIRFirebaseVersion(), additionalFrameworkMarker];
  576. [request setValue:clientVersion forHTTPHeaderField:kClientVersionHeader];
  577. NSString *bundleID = [[NSBundle mainBundle] bundleIdentifier];
  578. [request setValue:bundleID forHTTPHeaderField:kIosBundleIdentifierHeader];
  579. NSString *appID = requestConfiguration.appID;
  580. [request setValue:appID forHTTPHeaderField:kFirebaseAppIDHeader];
  581. [request setValue:FIRHeaderValueFromHeartbeatsPayload(
  582. [requestConfiguration.heartbeatLogger flushHeartbeatsIntoPayload])
  583. forHTTPHeaderField:kFirebaseHeartbeatHeader];
  584. NSArray<NSString *> *preferredLocalizations = [NSBundle mainBundle].preferredLocalizations;
  585. if (preferredLocalizations.count) {
  586. NSString *acceptLanguage = preferredLocalizations.firstObject;
  587. [request setValue:acceptLanguage forHTTPHeaderField:@"Accept-Language"];
  588. }
  589. NSString *languageCode = requestConfiguration.languageCode;
  590. if (languageCode.length) {
  591. [request setValue:languageCode forHTTPHeaderField:kFirebaseLocalHeader];
  592. }
  593. NSString *HTTPMethod = requestConfiguration.HTTPMethod;
  594. [request setValue:HTTPMethod forKey:@"HTTPMethod"];
  595. return request;
  596. }
  597. @end
  598. @interface FIRAuthBackendRPCIssuerImplementation : NSObject <FIRAuthBackendRPCIssuer>
  599. @end
  600. @implementation FIRAuthBackendRPCIssuerImplementation {
  601. /** @var The session fetcher service.
  602. */
  603. GTMSessionFetcherService *_fetcherService;
  604. }
  605. - (instancetype)init {
  606. self = [super init];
  607. if (self) {
  608. _fetcherService = [[GTMSessionFetcherService alloc] init];
  609. _fetcherService.userAgent = [FIRAuthBackend authUserAgent];
  610. _fetcherService.callbackQueue = FIRAuthGlobalWorkQueue();
  611. // Avoid reusing the session to prevent
  612. // https://github.com/firebase/firebase-ios-sdk/issues/1261
  613. _fetcherService.reuseSession = NO;
  614. }
  615. return self;
  616. }
  617. - (void)asyncCallToURLWithRequestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration
  618. URL:(NSURL *)URL
  619. body:(nullable NSData *)body
  620. contentType:(NSString *)contentType
  621. completionHandler:
  622. (void (^)(NSData *_Nullable, NSError *_Nullable))handler {
  623. NSMutableURLRequest *request = [FIRAuthBackend requestWithURL:URL
  624. contentType:contentType
  625. requestConfiguration:requestConfiguration];
  626. GTMSessionFetcher *fetcher = [_fetcherService fetcherWithRequest:request];
  627. NSString *emulatorHostAndPort = requestConfiguration.emulatorHostAndPort;
  628. if (emulatorHostAndPort) {
  629. fetcher.allowLocalhostRequest = YES;
  630. fetcher.allowedInsecureSchemes = @[ @"http" ];
  631. }
  632. fetcher.bodyData = body;
  633. [fetcher beginFetchWithCompletionHandler:handler];
  634. }
  635. @end
  636. @implementation FIRAuthBackendRPCImplementation
  637. - (instancetype)init {
  638. self = [super init];
  639. if (self) {
  640. _RPCIssuer = [[FIRAuthBackendRPCIssuerImplementation alloc] init];
  641. }
  642. return self;
  643. }
  644. - (void)createAuthURI:(FIRCreateAuthURIRequest *)request
  645. callback:(FIRCreateAuthURIResponseCallback)callback {
  646. FIRCreateAuthURIResponse *response = [[FIRCreateAuthURIResponse alloc] init];
  647. [self callWithRequest:request
  648. response:response
  649. callback:^(NSError *error) {
  650. if (error) {
  651. callback(nil, error);
  652. } else {
  653. callback(response, nil);
  654. }
  655. }];
  656. }
  657. - (void)getAccountInfo:(FIRGetAccountInfoRequest *)request
  658. callback:(FIRGetAccountInfoResponseCallback)callback {
  659. FIRGetAccountInfoResponse *response = [[FIRGetAccountInfoResponse alloc] init];
  660. [self callWithRequest:request
  661. response:response
  662. callback:^(NSError *error) {
  663. if (error) {
  664. callback(nil, error);
  665. } else {
  666. callback(response, nil);
  667. }
  668. }];
  669. }
  670. - (void)getProjectConfig:(FIRGetProjectConfigRequest *)request
  671. callback:(FIRGetProjectConfigResponseCallback)callback {
  672. FIRGetProjectConfigResponse *response = [[FIRGetProjectConfigResponse alloc] init];
  673. [self callWithRequest:request
  674. response:response
  675. callback:^(NSError *error) {
  676. if (error) {
  677. callback(nil, error);
  678. } else {
  679. callback(response, nil);
  680. }
  681. }];
  682. }
  683. - (void)setAccountInfo:(FIRSetAccountInfoRequest *)request
  684. callback:(FIRSetAccountInfoResponseCallback)callback {
  685. FIRSetAccountInfoResponse *response = [[FIRSetAccountInfoResponse alloc] init];
  686. [self callWithRequest:request
  687. response:response
  688. callback:^(NSError *error) {
  689. if (error) {
  690. callback(nil, error);
  691. } else {
  692. callback(response, nil);
  693. }
  694. }];
  695. }
  696. - (void)verifyAssertion:(FIRVerifyAssertionRequest *)request
  697. callback:(FIRVerifyAssertionResponseCallback)callback {
  698. FIRVerifyAssertionResponse *response = [[FIRVerifyAssertionResponse alloc] init];
  699. [self
  700. callWithRequest:request
  701. response:response
  702. callback:^(NSError *error) {
  703. if (error) {
  704. callback(nil, error);
  705. } else {
  706. if (!response.IDToken && response.MFAInfo) {
  707. #if TARGET_OS_IOS
  708. NSMutableArray<FIRMultiFactorInfo *> *multiFactorInfo = [NSMutableArray array];
  709. for (FIRAuthProtoMFAEnrollment *MFAEnrollment in response.MFAInfo) {
  710. FIRPhoneMultiFactorInfo *info =
  711. [[FIRPhoneMultiFactorInfo alloc] initWithProto:MFAEnrollment];
  712. [multiFactorInfo addObject:info];
  713. }
  714. NSError *multiFactorRequiredError = [FIRAuthErrorUtils
  715. secondFactorRequiredErrorWithPendingCredential:response.MFAPendingCredential
  716. hints:multiFactorInfo];
  717. callback(nil, multiFactorRequiredError);
  718. #endif
  719. } else {
  720. callback(response, nil);
  721. }
  722. }
  723. }];
  724. }
  725. - (void)verifyCustomToken:(FIRVerifyCustomTokenRequest *)request
  726. callback:(FIRVerifyCustomTokenResponseCallback)callback {
  727. FIRVerifyCustomTokenResponse *response = [[FIRVerifyCustomTokenResponse alloc] init];
  728. [self callWithRequest:request
  729. response:response
  730. callback:^(NSError *error) {
  731. if (error) {
  732. callback(nil, error);
  733. } else {
  734. callback(response, nil);
  735. }
  736. }];
  737. }
  738. - (void)verifyPassword:(FIRVerifyPasswordRequest *)request
  739. callback:(FIRVerifyPasswordResponseCallback)callback {
  740. FIRVerifyPasswordResponse *response = [[FIRVerifyPasswordResponse alloc] init];
  741. [self
  742. callWithRequest:request
  743. response:response
  744. callback:^(NSError *error) {
  745. if (error) {
  746. callback(nil, error);
  747. } else {
  748. if (!response.IDToken && response.MFAInfo) {
  749. #if TARGET_OS_IOS
  750. NSMutableArray<FIRMultiFactorInfo *> *multiFactorInfo = [NSMutableArray array];
  751. for (FIRAuthProtoMFAEnrollment *MFAEnrollment in response.MFAInfo) {
  752. FIRPhoneMultiFactorInfo *info =
  753. [[FIRPhoneMultiFactorInfo alloc] initWithProto:MFAEnrollment];
  754. [multiFactorInfo addObject:info];
  755. }
  756. NSError *multiFactorRequiredError = [FIRAuthErrorUtils
  757. secondFactorRequiredErrorWithPendingCredential:response.MFAPendingCredential
  758. hints:multiFactorInfo];
  759. callback(nil, multiFactorRequiredError);
  760. #endif
  761. } else {
  762. callback(response, nil);
  763. }
  764. }
  765. }];
  766. }
  767. - (void)emailLinkSignin:(FIREmailLinkSignInRequest *)request
  768. callback:(FIREmailLinkSigninResponseCallback)callback {
  769. FIREmailLinkSignInResponse *response = [[FIREmailLinkSignInResponse alloc] init];
  770. [self
  771. callWithRequest:request
  772. response:response
  773. callback:^(NSError *error) {
  774. if (error) {
  775. callback(nil, error);
  776. } else {
  777. if (!response.IDToken && response.MFAInfo) {
  778. #if TARGET_OS_IOS
  779. NSMutableArray<FIRMultiFactorInfo *> *multiFactorInfo = [NSMutableArray array];
  780. for (FIRAuthProtoMFAEnrollment *MFAEnrollment in response.MFAInfo) {
  781. FIRPhoneMultiFactorInfo *info =
  782. [[FIRPhoneMultiFactorInfo alloc] initWithProto:MFAEnrollment];
  783. [multiFactorInfo addObject:info];
  784. }
  785. NSError *multiFactorRequiredError = [FIRAuthErrorUtils
  786. secondFactorRequiredErrorWithPendingCredential:response.MFAPendingCredential
  787. hints:multiFactorInfo];
  788. callback(nil, multiFactorRequiredError);
  789. #endif
  790. } else {
  791. callback(response, nil);
  792. }
  793. }
  794. }];
  795. }
  796. - (void)secureToken:(FIRSecureTokenRequest *)request
  797. callback:(FIRSecureTokenResponseCallback)callback {
  798. FIRSecureTokenResponse *response = [[FIRSecureTokenResponse alloc] init];
  799. [self callWithRequest:request
  800. response:response
  801. callback:^(NSError *error) {
  802. if (error) {
  803. callback(nil, error);
  804. } else {
  805. callback(response, nil);
  806. }
  807. }];
  808. }
  809. - (void)getOOBConfirmationCode:(FIRGetOOBConfirmationCodeRequest *)request
  810. callback:(FIRGetOOBConfirmationCodeResponseCallback)callback {
  811. FIRGetOOBConfirmationCodeResponse *response = [[FIRGetOOBConfirmationCodeResponse alloc] init];
  812. [self callWithRequest:request
  813. response:response
  814. callback:^(NSError *error) {
  815. if (error) {
  816. callback(nil, error);
  817. } else {
  818. callback(response, nil);
  819. }
  820. }];
  821. }
  822. - (void)signUpNewUser:(FIRSignUpNewUserRequest *)request
  823. callback:(FIRSignupNewUserCallback)callback {
  824. FIRSignUpNewUserResponse *response = [[FIRSignUpNewUserResponse alloc] init];
  825. [self callWithRequest:request
  826. response:response
  827. callback:^(NSError *error) {
  828. if (error) {
  829. callback(nil, error);
  830. } else {
  831. callback(response, nil);
  832. }
  833. }];
  834. }
  835. - (void)deleteAccount:(FIRDeleteAccountRequest *)request callback:(FIRDeleteCallBack)callback {
  836. FIRDeleteAccountResponse *response = [[FIRDeleteAccountResponse alloc] init];
  837. [self callWithRequest:request response:response callback:callback];
  838. }
  839. #if TARGET_OS_IOS
  840. - (void)sendVerificationCode:(FIRSendVerificationCodeRequest *)request
  841. callback:(FIRSendVerificationCodeResponseCallback)callback {
  842. FIRSendVerificationCodeResponse *response = [[FIRSendVerificationCodeResponse alloc] init];
  843. [self callWithRequest:request
  844. response:response
  845. callback:^(NSError *error) {
  846. if (error) {
  847. callback(nil, error);
  848. } else {
  849. callback(response, error);
  850. }
  851. }];
  852. }
  853. - (void)verifyPhoneNumber:(FIRVerifyPhoneNumberRequest *)request
  854. callback:(FIRVerifyPhoneNumberResponseCallback)callback {
  855. FIRVerifyPhoneNumberResponse *response = [[FIRVerifyPhoneNumberResponse alloc] init];
  856. [self
  857. callWithRequest:request
  858. response:response
  859. callback:^(NSError *error) {
  860. if (error) {
  861. callback(nil, error);
  862. return;
  863. }
  864. // Check whether or not the successful response is actually the special case phone
  865. // auth flow that returns a temporary proof and phone number.
  866. if (response.phoneNumber.length && response.temporaryProof.length) {
  867. FIRPhoneAuthCredential *credential =
  868. [[FIRPhoneAuthCredential alloc] initWithTemporaryProof:response.temporaryProof
  869. phoneNumber:response.phoneNumber
  870. providerID:FIRPhoneAuthProviderID];
  871. callback(nil, [FIRAuthErrorUtils credentialAlreadyInUseErrorWithMessage:nil
  872. credential:credential
  873. email:nil]);
  874. return;
  875. }
  876. callback(response, nil);
  877. }];
  878. }
  879. - (void)verifyClient:(id)request callback:(FIRVerifyClientResponseCallback)callback {
  880. FIRVerifyClientResponse *response = [[FIRVerifyClientResponse alloc] init];
  881. [self callWithRequest:request
  882. response:response
  883. callback:^(NSError *error) {
  884. if (error) {
  885. callback(nil, error);
  886. return;
  887. }
  888. callback(response, nil);
  889. }];
  890. }
  891. #endif
  892. - (void)resetPassword:(FIRResetPasswordRequest *)request
  893. callback:(FIRResetPasswordCallback)callback {
  894. FIRResetPasswordResponse *response = [[FIRResetPasswordResponse alloc] init];
  895. [self callWithRequest:request
  896. response:response
  897. callback:^(NSError *error) {
  898. if (error) {
  899. callback(nil, error);
  900. return;
  901. }
  902. callback(response, nil);
  903. }];
  904. }
  905. - (void)signInWithGameCenter:(FIRSignInWithGameCenterRequest *)request
  906. callback:(FIRSignInWithGameCenterResponseCallback)callback {
  907. FIRSignInWithGameCenterResponse *response = [[FIRSignInWithGameCenterResponse alloc] init];
  908. [self callWithRequest:request
  909. response:response
  910. callback:^(NSError *error) {
  911. if (error) {
  912. if (callback) {
  913. callback(nil, error);
  914. }
  915. } else {
  916. if (callback) {
  917. callback(response, nil);
  918. }
  919. }
  920. }];
  921. }
  922. - (void)getRecaptchaConfig:(FIRGetRecaptchaConfigRequest *)request
  923. callback:(FIRGetRecaptchaConfigResponseCallback)callback {
  924. FIRGetRecaptchaConfigResponse *response = [[FIRGetRecaptchaConfigResponse alloc] init];
  925. [self callWithRequest:request
  926. response:response
  927. callback:^(NSError *error) {
  928. if (error) {
  929. if (callback) {
  930. callback(nil, error);
  931. }
  932. } else {
  933. if (callback) {
  934. callback(response, nil);
  935. }
  936. }
  937. }];
  938. }
  939. #pragma mark - Generic RPC handling methods
  940. /** @fn callWithRequest:response:callback:
  941. @brief Calls the RPC using HTTP request.
  942. @remarks Possible error responses:
  943. @see FIRAuthInternalErrorCodeRPCRequestEncodingError
  944. @see FIRAuthInternalErrorCodeJSONSerializationError
  945. @see FIRAuthInternalErrorCodeNetworkError
  946. @see FIRAuthInternalErrorCodeUnexpectedErrorResponse
  947. @see FIRAuthInternalErrorCodeUnexpectedResponse
  948. @see FIRAuthInternalErrorCodeRPCResponseDecodingError
  949. @param request The request.
  950. @param response The empty response to be filled.
  951. @param callback The callback for both success and failure.
  952. */
  953. - (void)callWithRequest:(id<FIRAuthRPCRequest>)request
  954. response:(id<FIRAuthRPCResponse>)response
  955. callback:(void (^)(NSError *_Nullable error))callback {
  956. NSError *error;
  957. NSData *bodyData;
  958. if ([request containsPostBody]) {
  959. id postBody = [request unencodedHTTPRequestBodyWithError:&error];
  960. if (!postBody) {
  961. callback([FIRAuthErrorUtils RPCRequestEncodingErrorWithUnderlyingError:error]);
  962. return;
  963. }
  964. NSJSONWritingOptions JSONWritingOptions = 0;
  965. #if DEBUG
  966. JSONWritingOptions |= NSJSONWritingPrettyPrinted;
  967. #endif
  968. if ([NSJSONSerialization isValidJSONObject:postBody]) {
  969. bodyData = [NSJSONSerialization dataWithJSONObject:postBody
  970. options:JSONWritingOptions
  971. error:&error];
  972. if (!bodyData) {
  973. // This is an untested case. This happens exclusively when there is an error in the
  974. // framework implementation of dataWithJSONObject:options:error:. This shouldn't normally
  975. // occur as isValidJSONObject: should return NO in any case we should encounter an error.
  976. error = [FIRAuthErrorUtils JSONSerializationErrorWithUnderlyingError:error];
  977. }
  978. } else {
  979. error = [FIRAuthErrorUtils JSONSerializationErrorForUnencodableType];
  980. }
  981. if (!bodyData) {
  982. callback(error);
  983. return;
  984. }
  985. }
  986. [_RPCIssuer
  987. asyncCallToURLWithRequestConfiguration:[request requestConfiguration]
  988. URL:[request requestURL]
  989. body:bodyData
  990. contentType:kJSONContentType
  991. completionHandler:^(NSData *data, NSError *error) {
  992. // If there is an error with no body data at all, then this must be a
  993. // network error.
  994. if (error && !data) {
  995. callback([FIRAuthErrorUtils networkErrorWithUnderlyingError:error]);
  996. return;
  997. }
  998. // Try to decode the HTTP response data which may contain either a
  999. // successful response or error message.
  1000. NSError *jsonError;
  1001. NSDictionary *dictionary =
  1002. [NSJSONSerialization JSONObjectWithData:data
  1003. options:NSJSONReadingMutableLeaves
  1004. error:&jsonError];
  1005. if (!dictionary) {
  1006. if (error) {
  1007. // We have an error, but we couldn't decode the body, so we have no
  1008. // additional information other than the raw response and the
  1009. // original NSError (the jsonError is infered by the error code
  1010. // (FIRAuthErrorCodeUnexpectedHTTPResponse, and is irrelevant.)
  1011. callback([FIRAuthErrorUtils
  1012. unexpectedErrorResponseWithData:data
  1013. underlyingError:error]);
  1014. } else {
  1015. // This is supposed to be a "successful" response, but we couldn't
  1016. // deserialize the body.
  1017. callback([FIRAuthErrorUtils unexpectedResponseWithData:data
  1018. underlyingError:jsonError]);
  1019. }
  1020. return;
  1021. }
  1022. if (![dictionary isKindOfClass:[NSDictionary class]]) {
  1023. if (error) {
  1024. callback([FIRAuthErrorUtils
  1025. unexpectedErrorResponseWithDeserializedResponse:dictionary
  1026. underlyingError:error]);
  1027. } else {
  1028. callback([FIRAuthErrorUtils
  1029. unexpectedResponseWithDeserializedResponse:dictionary]);
  1030. }
  1031. return;
  1032. }
  1033. // At this point we either have an error with successfully decoded
  1034. // details in the body, or we have a response which must pass further
  1035. // validation before we know it's truly successful. We deal with the
  1036. // case where we have an error with successfully decoded error details
  1037. // first:
  1038. if (error) {
  1039. NSDictionary *errorDictionary = dictionary[kErrorKey];
  1040. if ([errorDictionary isKindOfClass:[NSDictionary class]]) {
  1041. id<NSObject> errorMessage = errorDictionary[kErrorMessageKey];
  1042. if ([errorMessage isKindOfClass:[NSString class]]) {
  1043. NSString *errorMessageString = (NSString *)errorMessage;
  1044. // Contruct client error.
  1045. NSError *clientError = [[self class]
  1046. clientErrorWithServerErrorMessage:errorMessageString
  1047. errorDictionary:errorDictionary
  1048. response:response];
  1049. if (clientError) {
  1050. callback(clientError);
  1051. return;
  1052. }
  1053. }
  1054. // Not a message we know, return the message directly.
  1055. if (errorMessage) {
  1056. NSError *unexpecterErrorResponse = [FIRAuthErrorUtils
  1057. unexpectedErrorResponseWithDeserializedResponse:
  1058. errorDictionary
  1059. underlyingError:error];
  1060. callback(unexpecterErrorResponse);
  1061. return;
  1062. }
  1063. }
  1064. // No error message at all, return the decoded response.
  1065. callback([FIRAuthErrorUtils
  1066. unexpectedErrorResponseWithDeserializedResponse:dictionary
  1067. underlyingError:error]);
  1068. return;
  1069. }
  1070. // Finally, we try to populate the response object with the JSON
  1071. // values.
  1072. if (![response setWithDictionary:dictionary error:&error]) {
  1073. callback([FIRAuthErrorUtils
  1074. RPCResponseDecodingErrorWithDeserializedResponse:dictionary
  1075. underlyingError:error]);
  1076. return;
  1077. }
  1078. // In case returnIDPCredential of a verifyAssertion request is set to
  1079. // @YES, the server may return a 200 with a response that may contain a
  1080. // server error.
  1081. if ([request isKindOfClass:[FIRVerifyAssertionRequest class]]) {
  1082. FIRVerifyAssertionRequest *verifyAssertionRequest =
  1083. (FIRVerifyAssertionRequest *)request;
  1084. if (verifyAssertionRequest.returnIDPCredential) {
  1085. NSString *errorMessage =
  1086. dictionary[kReturnIDPCredentialErrorMessageKey];
  1087. if ([errorMessage isKindOfClass:[NSString class]]) {
  1088. NSString *errorString = (NSString *)errorMessage;
  1089. NSError *clientError =
  1090. [[self class] clientErrorWithServerErrorMessage:errorString
  1091. errorDictionary:@{}
  1092. response:response];
  1093. if (clientError) {
  1094. callback(clientError);
  1095. return;
  1096. }
  1097. }
  1098. }
  1099. }
  1100. // Success! The response object originally passed in can be used by the
  1101. // caller.
  1102. callback(nil);
  1103. }];
  1104. }
  1105. /** @fn clientErrorWithServerErrorMessage:errorDictionary:
  1106. @brief Translates known server errors to client errors.
  1107. @param serverErrorMessage The error message from the server.
  1108. @param errorDictionary The error part of the response from the server.
  1109. @param response The response from the server RPC.
  1110. @return A client error, if any.
  1111. */
  1112. + (nullable NSError *)clientErrorWithServerErrorMessage:(NSString *)serverErrorMessage
  1113. errorDictionary:(NSDictionary *)errorDictionary
  1114. response:(id<FIRAuthRPCResponse>)response {
  1115. NSString *shortErrorMessage = serverErrorMessage;
  1116. NSString *serverDetailErrorMessage;
  1117. NSRange colonRange = [serverErrorMessage rangeOfString:@":"];
  1118. if (colonRange.location != NSNotFound) {
  1119. shortErrorMessage = [serverErrorMessage substringToIndex:colonRange.location];
  1120. shortErrorMessage =
  1121. [shortErrorMessage stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
  1122. serverDetailErrorMessage = [serverErrorMessage substringFromIndex:colonRange.location + 1];
  1123. serverDetailErrorMessage = [serverDetailErrorMessage
  1124. stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
  1125. }
  1126. // Delegate the responsibility for constructing the client error to the response object,
  1127. // if possible.
  1128. SEL clientErrorWithServerErrorMessageSelector = @selector(clientErrorWithShortErrorMessage:
  1129. detailErrorMessage:);
  1130. if ([response respondsToSelector:clientErrorWithServerErrorMessageSelector]) {
  1131. NSError *error = [response clientErrorWithShortErrorMessage:shortErrorMessage
  1132. detailErrorMessage:serverDetailErrorMessage];
  1133. if (error) {
  1134. return error;
  1135. }
  1136. }
  1137. if ([shortErrorMessage isEqualToString:kUserNotFoundErrorMessage]) {
  1138. return [FIRAuthErrorUtils userNotFoundErrorWithMessage:serverDetailErrorMessage];
  1139. }
  1140. if ([shortErrorMessage isEqualToString:kUserDeletedErrorMessage]) {
  1141. return [FIRAuthErrorUtils userNotFoundErrorWithMessage:serverDetailErrorMessage];
  1142. }
  1143. if ([shortErrorMessage isEqualToString:kInvalidLocalIDErrorMessage]) {
  1144. // This case shouldn't be necessary but it is for now: b/27908364 .
  1145. return [FIRAuthErrorUtils userNotFoundErrorWithMessage:serverDetailErrorMessage];
  1146. }
  1147. if ([shortErrorMessage isEqualToString:kUserTokenExpiredErrorMessage]) {
  1148. return [FIRAuthErrorUtils userTokenExpiredErrorWithMessage:serverDetailErrorMessage];
  1149. }
  1150. if ([shortErrorMessage isEqualToString:kTooManyRequestsErrorMessage]) {
  1151. return [FIRAuthErrorUtils tooManyRequestsErrorWithMessage:serverDetailErrorMessage];
  1152. }
  1153. if ([shortErrorMessage isEqualToString:kInvalidCustomTokenErrorMessage]) {
  1154. return [FIRAuthErrorUtils invalidCustomTokenErrorWithMessage:serverDetailErrorMessage];
  1155. }
  1156. if ([shortErrorMessage isEqualToString:kCustomTokenMismatch]) {
  1157. return [FIRAuthErrorUtils customTokenMistmatchErrorWithMessage:serverDetailErrorMessage];
  1158. }
  1159. if ([shortErrorMessage isEqualToString:kInvalidCredentialErrorMessage] ||
  1160. [shortErrorMessage isEqualToString:kInvalidPendingToken]) {
  1161. return [FIRAuthErrorUtils invalidCredentialErrorWithMessage:serverDetailErrorMessage];
  1162. }
  1163. if ([shortErrorMessage isEqualToString:kUserDisabledErrorMessage]) {
  1164. return [FIRAuthErrorUtils userDisabledErrorWithMessage:serverDetailErrorMessage];
  1165. }
  1166. if ([shortErrorMessage isEqualToString:kOperationNotAllowedErrorMessage]) {
  1167. return [FIRAuthErrorUtils operationNotAllowedErrorWithMessage:serverDetailErrorMessage];
  1168. }
  1169. if ([shortErrorMessage isEqualToString:kPasswordLoginDisabledErrorMessage]) {
  1170. return [FIRAuthErrorUtils operationNotAllowedErrorWithMessage:serverDetailErrorMessage];
  1171. }
  1172. if ([shortErrorMessage isEqualToString:kEmailAlreadyInUseErrorMessage]) {
  1173. return [FIRAuthErrorUtils emailAlreadyInUseErrorWithEmail:nil];
  1174. }
  1175. if ([shortErrorMessage isEqualToString:kInvalidEmailErrorMessage]) {
  1176. return [FIRAuthErrorUtils invalidEmailErrorWithMessage:serverDetailErrorMessage];
  1177. }
  1178. // "INVALID_IDENTIFIER" can be returned by createAuthURI RPC. Considering email addresses are
  1179. // currently the only identifiers, we surface the FIRAuthErrorCodeInvalidEmail error code in this
  1180. // case.
  1181. if ([shortErrorMessage isEqualToString:kInvalidIdentifierErrorMessage]) {
  1182. return [FIRAuthErrorUtils invalidEmailErrorWithMessage:serverDetailErrorMessage];
  1183. }
  1184. if ([shortErrorMessage isEqualToString:kWrongPasswordErrorMessage]) {
  1185. return [FIRAuthErrorUtils wrongPasswordErrorWithMessage:serverDetailErrorMessage];
  1186. }
  1187. if ([shortErrorMessage isEqualToString:kCredentialTooOldErrorMessage]) {
  1188. return [FIRAuthErrorUtils requiresRecentLoginErrorWithMessage:serverDetailErrorMessage];
  1189. }
  1190. if ([shortErrorMessage isEqualToString:kInvalidUserTokenErrorMessage]) {
  1191. return [FIRAuthErrorUtils invalidUserTokenErrorWithMessage:serverDetailErrorMessage];
  1192. }
  1193. if ([shortErrorMessage isEqualToString:kFederatedUserIDAlreadyLinkedMessage]) {
  1194. FIROAuthCredential *credential;
  1195. NSString *email;
  1196. if ([response isKindOfClass:[FIRVerifyAssertionResponse class]]) {
  1197. FIRVerifyAssertionResponse *verifyAssertion = (FIRVerifyAssertionResponse *)response;
  1198. credential = [[FIROAuthCredential alloc] initWithVerifyAssertionResponse:verifyAssertion];
  1199. email = verifyAssertion.email;
  1200. }
  1201. return [FIRAuthErrorUtils credentialAlreadyInUseErrorWithMessage:serverDetailErrorMessage
  1202. credential:credential
  1203. email:email];
  1204. }
  1205. if ([shortErrorMessage isEqualToString:kWeakPasswordErrorMessagePrefix]) {
  1206. return [FIRAuthErrorUtils weakPasswordErrorWithServerResponseReason:serverDetailErrorMessage];
  1207. }
  1208. if ([shortErrorMessage isEqualToString:kExpiredActionCodeErrorMessage]) {
  1209. return [FIRAuthErrorUtils expiredActionCodeErrorWithMessage:serverDetailErrorMessage];
  1210. }
  1211. if ([shortErrorMessage isEqualToString:kInvalidActionCodeErrorMessage]) {
  1212. return [FIRAuthErrorUtils invalidActionCodeErrorWithMessage:serverDetailErrorMessage];
  1213. }
  1214. if ([shortErrorMessage isEqualToString:kMissingEmailErrorMessage]) {
  1215. return [FIRAuthErrorUtils missingEmailErrorWithMessage:serverDetailErrorMessage];
  1216. }
  1217. if ([shortErrorMessage isEqualToString:kInvalidSenderEmailErrorMessage]) {
  1218. return [FIRAuthErrorUtils invalidSenderErrorWithMessage:serverDetailErrorMessage];
  1219. }
  1220. if ([shortErrorMessage isEqualToString:kInvalidMessagePayloadErrorMessage]) {
  1221. return [FIRAuthErrorUtils invalidMessagePayloadErrorWithMessage:serverDetailErrorMessage];
  1222. }
  1223. if ([shortErrorMessage isEqualToString:kInvalidRecipientEmailErrorMessage]) {
  1224. return [FIRAuthErrorUtils invalidRecipientEmailErrorWithMessage:serverDetailErrorMessage];
  1225. }
  1226. if ([shortErrorMessage isEqualToString:kMissingIosBundleIDErrorMessage]) {
  1227. return [FIRAuthErrorUtils missingIosBundleIDErrorWithMessage:serverDetailErrorMessage];
  1228. }
  1229. if ([shortErrorMessage isEqualToString:kMissingAndroidPackageNameErrorMessage]) {
  1230. return [FIRAuthErrorUtils missingAndroidPackageNameErrorWithMessage:serverDetailErrorMessage];
  1231. }
  1232. if ([shortErrorMessage isEqualToString:kUnauthorizedDomainErrorMessage]) {
  1233. return [FIRAuthErrorUtils unauthorizedDomainErrorWithMessage:serverDetailErrorMessage];
  1234. }
  1235. if ([shortErrorMessage isEqualToString:kInvalidContinueURIErrorMessage]) {
  1236. return [FIRAuthErrorUtils invalidContinueURIErrorWithMessage:serverDetailErrorMessage];
  1237. }
  1238. if ([shortErrorMessage isEqualToString:kInvalidProviderIDErrorMessage]) {
  1239. return [FIRAuthErrorUtils invalidProviderIDErrorWithMessage:serverDetailErrorMessage];
  1240. }
  1241. if ([shortErrorMessage isEqualToString:kInvalidDynamicLinkDomainErrorMessage]) {
  1242. return [FIRAuthErrorUtils invalidDynamicLinkDomainErrorWithMessage:serverDetailErrorMessage];
  1243. }
  1244. if ([shortErrorMessage isEqualToString:kMissingContinueURIErrorMessage]) {
  1245. return [FIRAuthErrorUtils missingContinueURIErrorWithMessage:serverDetailErrorMessage];
  1246. }
  1247. if ([shortErrorMessage isEqualToString:kInvalidPhoneNumberErrorMessage]) {
  1248. return [FIRAuthErrorUtils invalidPhoneNumberErrorWithMessage:serverDetailErrorMessage];
  1249. }
  1250. if ([shortErrorMessage isEqualToString:kInvalidSessionInfoErrorMessage]) {
  1251. return [FIRAuthErrorUtils invalidVerificationIDErrorWithMessage:serverDetailErrorMessage];
  1252. }
  1253. if ([shortErrorMessage isEqualToString:kInvalidVerificationCodeErrorMessage]) {
  1254. return [FIRAuthErrorUtils invalidVerificationCodeErrorWithMessage:serverDetailErrorMessage];
  1255. }
  1256. if ([shortErrorMessage isEqualToString:kSessionExpiredErrorMessage]) {
  1257. return [FIRAuthErrorUtils sessionExpiredErrorWithMessage:serverDetailErrorMessage];
  1258. }
  1259. if ([shortErrorMessage isEqualToString:kMissingAppTokenErrorMessage]) {
  1260. return [FIRAuthErrorUtils missingAppTokenErrorWithUnderlyingError:nil];
  1261. }
  1262. if ([shortErrorMessage isEqualToString:kMissingAppCredentialErrorMessage]) {
  1263. return [FIRAuthErrorUtils missingAppCredentialWithMessage:serverDetailErrorMessage];
  1264. }
  1265. if ([shortErrorMessage isEqualToString:kInvalidAppCredentialErrorMessage]) {
  1266. return [FIRAuthErrorUtils invalidAppCredentialWithMessage:serverDetailErrorMessage];
  1267. }
  1268. if ([shortErrorMessage isEqualToString:kQuoutaExceededErrorMessage]) {
  1269. return [FIRAuthErrorUtils quotaExceededErrorWithMessage:serverErrorMessage];
  1270. }
  1271. if ([shortErrorMessage isEqualToString:kAppNotVerifiedErrorMessage]) {
  1272. return [FIRAuthErrorUtils appNotVerifiedErrorWithMessage:serverErrorMessage];
  1273. }
  1274. if ([shortErrorMessage isEqualToString:kMissingClientIdentifier]) {
  1275. return [FIRAuthErrorUtils missingClientIdentifierErrorWithMessage:serverErrorMessage];
  1276. }
  1277. if ([shortErrorMessage isEqualToString:kCaptchaCheckFailedErrorMessage]) {
  1278. return [FIRAuthErrorUtils captchaCheckFailedErrorWithMessage:serverErrorMessage];
  1279. }
  1280. if ([shortErrorMessage isEqualToString:kMissingOrInvalidNonceErrorMessage]) {
  1281. return [FIRAuthErrorUtils missingOrInvalidNonceErrorWithMessage:serverDetailErrorMessage];
  1282. }
  1283. if ([shortErrorMessage isEqualToString:kMissingMFAPendingCredentialErrorMessage]) {
  1284. return [FIRAuthErrorUtils errorWithCode:FIRAuthInternalErrorCodeMissingMultiFactorSession
  1285. message:serverErrorMessage];
  1286. }
  1287. if ([shortErrorMessage isEqualToString:kMissingMFAEnrollmentIDErrorMessage]) {
  1288. return [FIRAuthErrorUtils errorWithCode:FIRAuthInternalErrorCodeMissingMultiFactorInfo
  1289. message:serverErrorMessage];
  1290. }
  1291. if ([shortErrorMessage isEqualToString:kInvalidMFAPendingCredentialErrorMessage]) {
  1292. return [FIRAuthErrorUtils errorWithCode:FIRAuthInternalErrorCodeInvalidMultiFactorSession
  1293. message:serverErrorMessage];
  1294. }
  1295. if ([shortErrorMessage isEqualToString:kMFAEnrollmentNotFoundErrorMessage]) {
  1296. return [FIRAuthErrorUtils errorWithCode:FIRAuthInternalErrorCodeMultiFactorInfoNotFound
  1297. message:serverErrorMessage];
  1298. }
  1299. if ([shortErrorMessage isEqualToString:kAdminOnlyOperationErrorMessage]) {
  1300. return [FIRAuthErrorUtils errorWithCode:FIRAuthInternalErrorCodeAdminRestrictedOperation
  1301. message:serverErrorMessage];
  1302. }
  1303. if ([shortErrorMessage isEqualToString:kUnverifiedEmailErrorMessage]) {
  1304. return [FIRAuthErrorUtils errorWithCode:FIRAuthInternalErrorCodeUnverifiedEmail
  1305. message:serverErrorMessage];
  1306. }
  1307. if ([shortErrorMessage isEqualToString:kSecondFactorExistsErrorMessage]) {
  1308. return [FIRAuthErrorUtils errorWithCode:FIRAuthInternalErrorCodeSecondFactorAlreadyEnrolled
  1309. message:serverErrorMessage];
  1310. }
  1311. if ([shortErrorMessage isEqualToString:kSecondFactorLimitExceededErrorMessage]) {
  1312. return [FIRAuthErrorUtils errorWithCode:FIRAuthInternalErrorCodeMaximumSecondFactorCountExceeded
  1313. message:serverErrorMessage];
  1314. }
  1315. if ([shortErrorMessage isEqualToString:kUnsupportedFirstFactorErrorMessage]) {
  1316. return [FIRAuthErrorUtils errorWithCode:FIRAuthInternalErrorCodeUnsupportedFirstFactor
  1317. message:serverErrorMessage];
  1318. }
  1319. if ([shortErrorMessage isEqualToString:kEmailChangeNeedsVerificationErrorMessage]) {
  1320. return [FIRAuthErrorUtils errorWithCode:FIRAuthInternalErrorCodeEmailChangeNeedsVerification
  1321. message:serverErrorMessage];
  1322. }
  1323. if ([shortErrorMessage isEqualToString:kTenantIDMismatch]) {
  1324. return [FIRAuthErrorUtils tenantIDMismatchError];
  1325. }
  1326. if ([shortErrorMessage isEqualToString:kUnsupportedTenantOperation]) {
  1327. return [FIRAuthErrorUtils unsupportedTenantOperationError];
  1328. }
  1329. if ([shortErrorMessage isEqualToString:kInvalidRecaptchaScore]) {
  1330. return [FIRAuthErrorUtils errorWithCode:FIRAuthInternalErrorCodeCaptchaCheckFailed
  1331. message:serverErrorMessage];
  1332. }
  1333. if ([shortErrorMessage isEqualToString:kRecaptchaNotEnabled]) {
  1334. return [FIRAuthErrorUtils errorWithCode:FIRAuthInternalErrorCodeRecaptchaNotEnabled
  1335. message:serverErrorMessage];
  1336. }
  1337. if ([shortErrorMessage isEqualToString:kBlockingCloudFunctionErrorResponse]) {
  1338. return
  1339. [FIRAuthErrorUtils blockingCloudFunctionServerResponseWithMessage:serverDetailErrorMessage];
  1340. }
  1341. // In this case we handle an error that might be specified in the underlying errors dictionary,
  1342. // the error message in determined based on the @c reason key in the dictionary.
  1343. if (errorDictionary[kErrorsKey]) {
  1344. // Check for underlying error with reason = keyInvalid;
  1345. id underlyingErrors = errorDictionary[kErrorsKey];
  1346. if ([underlyingErrors isKindOfClass:[NSArray class]]) {
  1347. NSArray *underlyingErrorsArray = (NSArray *)underlyingErrors;
  1348. for (id underlyingError in underlyingErrorsArray) {
  1349. if ([underlyingError isKindOfClass:[NSDictionary class]]) {
  1350. NSDictionary *underlyingErrorDictionary = (NSDictionary *)underlyingError;
  1351. NSString *reason = underlyingErrorDictionary[kReasonKey];
  1352. if ([reason hasPrefix:kInvalidKeyReasonValue]) {
  1353. return [FIRAuthErrorUtils invalidAPIKeyError];
  1354. }
  1355. if ([reason isEqualToString:kAppNotAuthorizedReasonValue]) {
  1356. return [FIRAuthErrorUtils appNotAuthorizedError];
  1357. }
  1358. }
  1359. }
  1360. }
  1361. }
  1362. return nil;
  1363. }
  1364. @end
  1365. NS_ASSUME_NONNULL_END