FIRAuthBackend.m 77 KB

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