FIRAuthBackend.m 76 KB

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