FIRAuthBackend.m 64 KB

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