UserTests.swift 81 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893
  1. // Copyright 2023 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License")
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. import Foundation
  15. import XCTest
  16. @testable import FirebaseAuth
  17. import FirebaseCore
  18. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
  19. class UserTests: RPCBaseTests {
  20. static let kFakeAPIKey = "FAKE_API_KEY"
  21. let kFacebookAccessToken = "FACEBOOK_ACCESS_TOKEN"
  22. let kFacebookID = "FACEBOOK_ID"
  23. let kFacebookEmail = "user@facebook.com"
  24. let kFacebookDisplayName = "Facebook Doe"
  25. let kFacebookIDToken: String? = nil // Facebook id Token is always nil.
  26. let kNewEmail = "newuser@company.com"
  27. let kNewPassword = "newpassword"
  28. let kNewDisplayName = "New User Doe"
  29. let kVerificationCode = "12345678"
  30. let kVerificationID = "55432"
  31. let kPhoneNumber = "555-1234"
  32. var auth: Auth?
  33. override func setUp() {
  34. super.setUp()
  35. let options = FirebaseOptions(googleAppID: "0:0000000000000:ios:0000000000000000",
  36. gcmSenderID: "00000000000000000-00000000000-000000000")
  37. options.apiKey = Self.kFakeAPIKey
  38. options.projectID = "myUserProjectID"
  39. FirebaseApp.configure(name: "test-UserTests", options: options)
  40. #if (os(macOS) && !FIREBASE_AUTH_TESTING_USE_MACOS_KEYCHAIN) || SWIFT_PACKAGE
  41. let keychainStorageProvider = FakeAuthKeychainStorage()
  42. #else
  43. let keychainStorageProvider = AuthKeychainStorageReal.shared
  44. #endif // (os(macOS) && !FIREBASE_AUTH_TESTING_USE_MACOS_KEYCHAIN) || SWIFT_PACKAGE
  45. auth = Auth(
  46. app: FirebaseApp.app(name: "test-UserTests")!,
  47. keychainStorageProvider: keychainStorageProvider,
  48. backend: authBackend
  49. )
  50. }
  51. override func tearDown() {
  52. // Verifies that no tasks are left suspended on the AuthSerialTaskQueue.
  53. try? auth?.signOut()
  54. auth = nil
  55. FirebaseApp.resetApps()
  56. super.tearDown()
  57. }
  58. /** @fn testUserPropertiesAndNSSecureCoding
  59. @brief Tests properties of the @c User instance before and after being
  60. serialized/deserialized.
  61. */
  62. func testUserPropertiesAndNSSecureCoding() throws {
  63. let kProviderUserInfoKey = "providerUserInfo"
  64. let kPhotoUrlKey = "photoUrl"
  65. let kProviderIDkey = "providerId"
  66. let kDisplayNameKey = "displayName"
  67. let kFederatedIDKey = "federatedId"
  68. let kEmailKey = "email"
  69. let kPasswordHashKey = "passwordHash"
  70. let kTestPasswordHash = "testPasswordHash"
  71. let kEmailVerifiedKey = "emailVerified"
  72. let kLocalIDKey = "localId"
  73. let kGoogleID = "GOOGLE_ID"
  74. let kGoogleDisplayName = "Google Doe"
  75. let kGoogleEmail = "user@gmail.com"
  76. let kGooglePhotoURL = "https://googleusercontents.com/user/profile"
  77. let kFacebookID = "FACEBOOK_ID"
  78. let kFacebookEmail = "user@facebook.com"
  79. let kEnrollmentID = "fakeEnrollment"
  80. let kPhoneInfo = "+15555555555"
  81. let kEnrolledAt = "2022-08-01T18:31:15.426458Z"
  82. let kEnrolledAtMatch = "2022-08-01 18:31:15 +0000"
  83. let kTwitterID = "TwitterID"
  84. let kGitHubID = "GitHubID"
  85. let kGameCenterID = "GameCenterID"
  86. var providerUserInfos = [[
  87. kProviderIDkey: EmailAuthProvider.id,
  88. kFederatedIDKey: kEmail,
  89. kEmailKey: kEmail,
  90. ],
  91. [
  92. kProviderIDkey: GoogleAuthProvider.id,
  93. kDisplayNameKey: kGoogleDisplayName,
  94. kPhotoUrlKey: kGooglePhotoURL,
  95. kFederatedIDKey: kGoogleID,
  96. kEmailKey: kGoogleEmail,
  97. ],
  98. [
  99. kProviderIDkey: FacebookAuthProvider.id,
  100. kFederatedIDKey: kFacebookID,
  101. kEmailKey: kFacebookEmail,
  102. ],
  103. [
  104. kProviderIDkey: GitHubAuthProvider.id,
  105. kFederatedIDKey: kGitHubID,
  106. kEmailKey: kGoogleEmail,
  107. ],
  108. [
  109. kProviderIDkey: TwitterAuthProvider.id,
  110. kFederatedIDKey: kTwitterID,
  111. kEmailKey: kFacebookEmail,
  112. ]]
  113. #if !os(watchOS)
  114. providerUserInfos.append([
  115. kProviderIDkey: GameCenterAuthProvider.id,
  116. kFederatedIDKey: kGameCenterID,
  117. kEmailKey: kFacebookEmail,
  118. ])
  119. #endif
  120. #if os(iOS)
  121. providerUserInfos.append([
  122. kProviderIDkey: PhoneAuthProvider.id,
  123. kFederatedIDKey: kPhoneNumber,
  124. "phoneNumber": kPhoneNumber,
  125. ])
  126. #endif
  127. rpcIssuer?.fakeGetAccountProviderJSON = [[
  128. kProviderUserInfoKey: providerUserInfos,
  129. kLocalIDKey: kLocalID,
  130. kDisplayNameKey: kDisplayName,
  131. kEmailKey: kEmail,
  132. kPhotoUrlKey: kTestPhotoURL,
  133. kEmailVerifiedKey: true,
  134. kPasswordHashKey: kTestPasswordHash,
  135. "phoneNumber": kPhoneNumber,
  136. "createdAt": String(Int(kCreationDateTimeIntervalInSeconds) * 1000), // to nanoseconds
  137. "lastLoginAt": String(Int(kLastSignInDateTimeIntervalInSeconds) * 1000),
  138. "mfaInfo": [
  139. [
  140. "phoneInfo": kPhoneInfo,
  141. "mfaEnrollmentId": kEnrollmentID,
  142. "displayName": kDisplayName,
  143. "enrolledAt": kEnrolledAt,
  144. ],
  145. [
  146. // In practice, this will be an empty dictionary.
  147. "totpInfo": [AnyHashable: AnyHashable](),
  148. "mfaEnrollmentId": kEnrollmentID,
  149. "displayName": kDisplayName,
  150. "enrolledAt": kEnrolledAt,
  151. ] as [AnyHashable: AnyHashable],
  152. ],
  153. ]]
  154. let expectation = self.expectation(description: #function)
  155. signInWithEmailPasswordReturnFakeUser { user in
  156. do {
  157. XCTAssertEqual(user.providerID, "Firebase")
  158. XCTAssertEqual(user.uid, self.kLocalID)
  159. XCTAssertEqual(user.displayName, self.kDisplayName)
  160. XCTAssertEqual(user.photoURL, URL(string: self.kTestPhotoURL))
  161. XCTAssertEqual(user.email, self.kEmail)
  162. XCTAssertEqual(user.metadata.creationDate, Date(timeIntervalSince1970:
  163. self.kCreationDateTimeIntervalInSeconds))
  164. XCTAssertEqual(user.metadata.lastSignInDate,
  165. Date(timeIntervalSince1970: self.kLastSignInDateTimeIntervalInSeconds))
  166. // Verify FIRUser properties besides providerData contents.
  167. XCTAssertFalse(user.isAnonymous)
  168. XCTAssertTrue(user.isEmailVerified)
  169. XCTAssertEqual(user.refreshToken, self.kRefreshToken)
  170. XCTAssertEqual(user.providerData.count, providerUserInfos.count)
  171. let providerMap = user.providerData.reduce(into: [String: UserInfo]()) {
  172. $0[$1.providerID] = $1
  173. }
  174. // Verify FIRUserInfo properties from email/password.
  175. let passwordUserInfo = try XCTUnwrap(providerMap[EmailAuthProvider.id])
  176. XCTAssertEqual(passwordUserInfo.uid, self.kEmail)
  177. XCTAssertNil(passwordUserInfo.displayName)
  178. XCTAssertNil(passwordUserInfo.photoURL)
  179. XCTAssertEqual(passwordUserInfo.email, self.kEmail)
  180. // Verify FIRUserInfo properties from the Google auth provider.
  181. let googleUserInfo = try XCTUnwrap(providerMap[GoogleAuthProvider.id])
  182. XCTAssertEqual(googleUserInfo.uid, kGoogleID)
  183. XCTAssertEqual(googleUserInfo.displayName, kGoogleDisplayName)
  184. XCTAssertEqual(googleUserInfo.photoURL, URL(string: kGooglePhotoURL))
  185. XCTAssertEqual(googleUserInfo.email, kGoogleEmail)
  186. // Verify FIRUserInfo properties from the Facebook auth provider.
  187. let facebookUserInfo = try XCTUnwrap(providerMap[FacebookAuthProvider.id])
  188. XCTAssertEqual(facebookUserInfo.uid, kFacebookID)
  189. XCTAssertNil(facebookUserInfo.displayName)
  190. XCTAssertNil(facebookUserInfo.photoURL)
  191. XCTAssertEqual(facebookUserInfo.email, kFacebookEmail)
  192. // Verify FIRUserInfo properties from the GitHub auth provider.
  193. let gitHubUserInfo = try XCTUnwrap(providerMap[GitHubAuthProvider.id])
  194. XCTAssertEqual(gitHubUserInfo.uid, kGitHubID)
  195. XCTAssertNil(gitHubUserInfo.displayName)
  196. XCTAssertNil(gitHubUserInfo.photoURL)
  197. XCTAssertEqual(gitHubUserInfo.email, kGoogleEmail)
  198. // Verify FIRUserInfo properties from the Twitter auth provider.
  199. let twitterUserInfo = try XCTUnwrap(providerMap[TwitterAuthProvider.id])
  200. XCTAssertEqual(twitterUserInfo.uid, kTwitterID)
  201. XCTAssertNil(twitterUserInfo.displayName)
  202. XCTAssertNil(twitterUserInfo.photoURL)
  203. XCTAssertEqual(twitterUserInfo.email, kFacebookEmail)
  204. #if os(iOS)
  205. // Verify UserInfo properties from the phone auth provider.
  206. let phoneUserInfo = try XCTUnwrap(providerMap[PhoneAuthProvider.id])
  207. XCTAssertEqual(phoneUserInfo.phoneNumber, self.kPhoneNumber)
  208. #endif
  209. #if !os(watchOS)
  210. // Verify FIRUserInfo properties from the Game Center auth provider.
  211. let gameCenterUserInfo = try XCTUnwrap(providerMap[GameCenterAuthProvider.id])
  212. XCTAssertEqual(gameCenterUserInfo.uid, kGameCenterID)
  213. XCTAssertNil(gameCenterUserInfo.displayName)
  214. XCTAssertNil(gameCenterUserInfo.photoURL)
  215. XCTAssertEqual(gameCenterUserInfo.email, kFacebookEmail)
  216. #endif
  217. // Test NSSecureCoding
  218. XCTAssertTrue(User.supportsSecureCoding)
  219. let data = try NSKeyedArchiver.archivedData(
  220. withRootObject: user,
  221. requiringSecureCoding: true
  222. )
  223. var encodedClasses = [User.self, NSDictionary.self, NSURL.self, SecureTokenService.self,
  224. UserInfoImpl.self, NSDate.self, UserMetadata.self, NSString.self,
  225. NSArray.self]
  226. #if os(iOS)
  227. encodedClasses.append(MultiFactor.self)
  228. encodedClasses.append(PhoneMultiFactorInfo.self)
  229. #endif
  230. let unarchivedUser = try XCTUnwrap(NSKeyedUnarchiver.unarchivedObject(
  231. ofClasses: encodedClasses, from: data
  232. )
  233. as? User)
  234. // Verify NSSecureCoding for FIRUser
  235. XCTAssertEqual(unarchivedUser.providerID, user.providerID)
  236. XCTAssertEqual(unarchivedUser.uid, user.uid)
  237. XCTAssertEqual(unarchivedUser.email, user.email)
  238. XCTAssertEqual(unarchivedUser.photoURL, user.photoURL)
  239. XCTAssertEqual(unarchivedUser.displayName, user.displayName)
  240. // Verify NSSecureCoding properties besides providerData contents.
  241. XCTAssertEqual(unarchivedUser.isAnonymous, user.isAnonymous)
  242. XCTAssertEqual(unarchivedUser.isEmailVerified, user.isEmailVerified)
  243. XCTAssertEqual(unarchivedUser.refreshToken, user.refreshToken)
  244. XCTAssertEqual(unarchivedUser.metadata.creationDate, user.metadata.creationDate)
  245. XCTAssertEqual(unarchivedUser.metadata.lastSignInDate, user.metadata.lastSignInDate)
  246. XCTAssertEqual(unarchivedUser.providerData.count, user.providerData.count)
  247. let unarchivedProviderMap = unarchivedUser.providerData.reduce(into: [String: UserInfo]()) {
  248. $0[$1.providerID] = $1
  249. }
  250. // Verify NSSecureCoding properties for AuthDataResult
  251. let kFakeProfile = ["email": "user@mail.com", "given_name": "User", "family_name": "Doe"]
  252. let kUserName = "User Doe"
  253. let kProviderID = "PROVIDER_ID"
  254. let userInfo = AdditionalUserInfo(providerID: kProviderID,
  255. profile: kFakeProfile,
  256. username: kUserName,
  257. isNewUser: true)
  258. let authDataResult = AuthDataResult(withUser: user, additionalUserInfo: userInfo)
  259. XCTAssertTrue(AuthDataResult.supportsSecureCoding)
  260. let authDataResultData = try NSKeyedArchiver.archivedData(
  261. withRootObject: authDataResult,
  262. requiringSecureCoding: true
  263. )
  264. encodedClasses.append(AuthDataResult.self)
  265. encodedClasses.append(AdditionalUserInfo.self)
  266. let unarchivedDataResult = try XCTUnwrap(NSKeyedUnarchiver.unarchivedObject(
  267. ofClasses: encodedClasses, from: authDataResultData
  268. ) as? AuthDataResult)
  269. XCTAssertEqual(unarchivedDataResult.user.providerID, user.providerID)
  270. XCTAssertEqual(unarchivedDataResult.user.uid, user.uid)
  271. XCTAssertEqual(unarchivedDataResult.user.email, user.email)
  272. XCTAssertEqual(unarchivedDataResult.user.photoURL, user.photoURL)
  273. XCTAssertEqual(unarchivedDataResult.user.displayName, user.displayName)
  274. XCTAssertEqual(unarchivedDataResult.additionalUserInfo?.providerID, kProviderID)
  275. XCTAssertEqual(unarchivedDataResult.additionalUserInfo?.profile as? [String: String],
  276. kFakeProfile)
  277. XCTAssertEqual(unarchivedDataResult.additionalUserInfo?.username, kUserName)
  278. // Verify NSSecureCoding properties from email/password.
  279. let unarchivedPasswordUserInfo = try XCTUnwrap(unarchivedProviderMap[EmailAuthProvider.id])
  280. XCTAssertEqual(unarchivedPasswordUserInfo.uid, passwordUserInfo.uid)
  281. XCTAssertEqual(unarchivedPasswordUserInfo.displayName, passwordUserInfo.displayName)
  282. XCTAssertEqual(unarchivedPasswordUserInfo.photoURL, passwordUserInfo.photoURL)
  283. XCTAssertEqual(unarchivedPasswordUserInfo.email, passwordUserInfo.email)
  284. // Verify NSSecureCoding properties from the Google auth provider.
  285. let unarchivedGoogleUserInfo = try XCTUnwrap(unarchivedProviderMap[GoogleAuthProvider.id])
  286. XCTAssertEqual(unarchivedGoogleUserInfo.uid, googleUserInfo.uid)
  287. XCTAssertEqual(unarchivedGoogleUserInfo.displayName, googleUserInfo.displayName)
  288. XCTAssertEqual(unarchivedGoogleUserInfo.photoURL, googleUserInfo.photoURL)
  289. XCTAssertEqual(unarchivedGoogleUserInfo.email, googleUserInfo.email)
  290. // Verify NSSecureCoding properties from the Facebook auth provider.
  291. let unarchivedFacebookUserInfo =
  292. try XCTUnwrap(unarchivedProviderMap[FacebookAuthProvider.id])
  293. XCTAssertEqual(unarchivedFacebookUserInfo.uid, facebookUserInfo.uid)
  294. XCTAssertEqual(unarchivedFacebookUserInfo.displayName, facebookUserInfo.displayName)
  295. XCTAssertEqual(unarchivedFacebookUserInfo.photoURL, facebookUserInfo.photoURL)
  296. XCTAssertEqual(unarchivedFacebookUserInfo.email, facebookUserInfo.email)
  297. #if !os(watchOS)
  298. // Verify NSSecureCoding properties from the GameCenter auth provider.
  299. let unarchivedGameCenterUserInfo =
  300. try XCTUnwrap(unarchivedProviderMap[GameCenterAuthProvider.id])
  301. XCTAssertEqual(unarchivedGameCenterUserInfo.uid, gameCenterUserInfo.uid)
  302. XCTAssertEqual(unarchivedGameCenterUserInfo.displayName, gameCenterUserInfo.displayName)
  303. XCTAssertEqual(unarchivedGameCenterUserInfo.photoURL, gameCenterUserInfo.photoURL)
  304. XCTAssertEqual(unarchivedGameCenterUserInfo.email, gameCenterUserInfo.email)
  305. #endif
  306. // Verify NSSecureCoding properties from the GitHub auth provider.
  307. let unarchivedGitHubUserInfo =
  308. try XCTUnwrap(unarchivedProviderMap[GitHubAuthProvider.id])
  309. XCTAssertEqual(unarchivedGitHubUserInfo.uid, gitHubUserInfo.uid)
  310. XCTAssertEqual(unarchivedGitHubUserInfo.displayName, gitHubUserInfo.displayName)
  311. XCTAssertEqual(unarchivedGitHubUserInfo.photoURL, gitHubUserInfo.photoURL)
  312. XCTAssertEqual(unarchivedGitHubUserInfo.email, gitHubUserInfo.email)
  313. // Verify NSSecureCoding properties from the Twitter auth provider.
  314. let unarchivedTwitterUserInfo =
  315. try XCTUnwrap(unarchivedProviderMap[TwitterAuthProvider.id])
  316. XCTAssertEqual(unarchivedTwitterUserInfo.uid, twitterUserInfo.uid)
  317. XCTAssertEqual(unarchivedTwitterUserInfo.displayName, twitterUserInfo.displayName)
  318. XCTAssertEqual(unarchivedTwitterUserInfo.photoURL, twitterUserInfo.photoURL)
  319. XCTAssertEqual(unarchivedTwitterUserInfo.email, twitterUserInfo.email)
  320. #if os(iOS)
  321. // Verify NSSecureCoding properties from the phone auth provider.
  322. let unarchivedPhoneUserInfo = try XCTUnwrap(unarchivedProviderMap[PhoneAuthProvider.id])
  323. XCTAssertEqual(unarchivedPhoneUserInfo.phoneNumber, phoneUserInfo.phoneNumber)
  324. // Verify MultiFactorInfo properties.
  325. let enrolledFactors = try XCTUnwrap(user.multiFactor.enrolledFactors)
  326. XCTAssertEqual(enrolledFactors.count, 2)
  327. XCTAssertEqual(enrolledFactors[0].factorID, PhoneMultiFactorInfo.PhoneMultiFactorID)
  328. XCTAssertEqual(enrolledFactors[1].factorID, PhoneMultiFactorInfo.TOTPMultiFactorID)
  329. for enrolledFactor in enrolledFactors {
  330. XCTAssertEqual(enrolledFactor.uid, kEnrollmentID)
  331. XCTAssertEqual(enrolledFactor.displayName, self.kDisplayName)
  332. let date = try XCTUnwrap(enrolledFactor.enrollmentDate)
  333. XCTAssertEqual("\(date)", kEnrolledAtMatch)
  334. }
  335. #endif
  336. } catch {
  337. XCTFail("Caught an error in \(#function): \(error)")
  338. }
  339. expectation.fulfill()
  340. }
  341. waitForExpectations(timeout: 5)
  342. }
  343. /** @fn testUpdateEmailSuccess
  344. @brief Tests the flow of a successful @c updateEmail:completion: call.
  345. */
  346. func testUpdateEmailSuccess() {
  347. setFakeGetAccountProvider(withPasswordHash: kFakePassword)
  348. let expectation = self.expectation(description: #function)
  349. signInWithEmailPasswordReturnFakeUser { user in
  350. self.changeUserEmail(user: user, changeEmail: true, expectation: expectation)
  351. }
  352. waitForExpectations(timeout: 5)
  353. }
  354. /** @fn testUpdateEmailWithAuthLinkAccountSuccess
  355. @brief Tests a successful @c updateEmail:completion: call updates provider info.
  356. */
  357. func testUpdateEmailWithAuthLinkAccountSuccess() {
  358. setFakeGetAccountProvider()
  359. let expectation = self.expectation(description: #function)
  360. signInWithEmailPasswordReturnFakeUserLink { user in
  361. self.changeUserEmail(user: user, expectation: expectation)
  362. }
  363. waitForExpectations(timeout: 5)
  364. }
  365. /** @fn testUpdateEmailFailure
  366. @brief Tests the flow of a failed @c updateEmail:completion: call.
  367. */
  368. func testUpdateEmailFailure() {
  369. setFakeGetAccountProvider()
  370. let expectation = self.expectation(description: #function)
  371. signInWithEmailPasswordReturnFakeUser { user in
  372. do {
  373. self.rpcIssuer.respondBlock = {
  374. try self.rpcIssuer.respond(serverErrorMessage: "INVALID_EMAIL")
  375. }
  376. user.updateEmail(to: self.kNewEmail) { rawError in
  377. XCTAssertTrue(Thread.isMainThread)
  378. let error = try! XCTUnwrap(rawError)
  379. XCTAssertEqual((error as NSError).code, AuthErrorCode.invalidEmail.rawValue)
  380. // Email should not have changed on the client side.
  381. XCTAssertEqual(user.email, self.kEmail)
  382. // User is still signed in.
  383. XCTAssertEqual(self.auth?.currentUser, user)
  384. expectation.fulfill()
  385. }
  386. }
  387. }
  388. waitForExpectations(timeout: 5)
  389. }
  390. /** @fn testUpdateEmailAutoSignOut
  391. @brief Tests the flow of a failed @c updateEmail:completion: call that automatically signs out.
  392. */
  393. func testUpdateEmailAutoSignOut() {
  394. setFakeGetAccountProvider()
  395. let expectation = self.expectation(description: #function)
  396. signInWithEmailPasswordReturnFakeUser { user in
  397. do {
  398. self.rpcIssuer.respondBlock = {
  399. try self.rpcIssuer.respond(serverErrorMessage: "INVALID_ID_TOKEN")
  400. }
  401. user.updateEmail(to: self.kNewEmail) { rawError in
  402. XCTAssertTrue(Thread.isMainThread)
  403. let error = try! XCTUnwrap(rawError)
  404. XCTAssertEqual((error as NSError).code, AuthErrorCode.invalidUserToken.rawValue)
  405. // Email should not have changed on the client side.
  406. XCTAssertEqual(user.email, self.kEmail)
  407. // User is no longer signed in..
  408. XCTAssertNil(self.auth?.currentUser)
  409. expectation.fulfill()
  410. }
  411. }
  412. }
  413. waitForExpectations(timeout: 5)
  414. }
  415. #if os(iOS)
  416. /** @fn testUpdatePhoneSuccess
  417. @brief Tests the flow of a successful @c updatePhoneNumberCredential:completion: call.
  418. */
  419. func testUpdatePhoneSuccess() throws {
  420. setFakeGetAccountProvider()
  421. let expectation = self.expectation(description: #function)
  422. let auth = try XCTUnwrap(self.auth)
  423. signInWithEmailPasswordReturnFakeUser { user in
  424. do {
  425. self.rpcIssuer.respondBlock = {
  426. try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
  427. "refreshToken": self.kRefreshToken])
  428. }
  429. self.expectVerifyPhoneNumberRequest()
  430. self.rpcIssuer?.fakeGetAccountProviderJSON = [[
  431. "phoneNumber": self.kPhoneNumber,
  432. ]]
  433. let credential = PhoneAuthProvider.provider(auth: auth).credential(
  434. withVerificationID: self.kVerificationID,
  435. verificationCode: self.kVerificationCode
  436. )
  437. user.updatePhoneNumber(credential) { error in
  438. XCTAssertTrue(Thread.isMainThread)
  439. XCTAssertNil(error)
  440. XCTAssertEqual(auth.currentUser?.phoneNumber, self.kPhoneNumber)
  441. expectation.fulfill()
  442. }
  443. }
  444. }
  445. waitForExpectations(timeout: 5)
  446. }
  447. /** @fn testUpdatePhoneNumberFailure
  448. @brief Tests the flow of a failed @c updatePhoneNumberCredential:completion: call.
  449. */
  450. func testUpdatePhoneNumberFailure() throws {
  451. setFakeGetAccountProvider()
  452. let expectation = self.expectation(description: #function)
  453. let auth = try XCTUnwrap(self.auth)
  454. signInWithEmailPasswordReturnFakeUser { user in
  455. do {
  456. self.rpcIssuer.respondBlock = {
  457. try self.rpcIssuer.respond(serverErrorMessage: "INVALID_PHONE_NUMBER")
  458. }
  459. self.expectVerifyPhoneNumberRequest()
  460. let credential = PhoneAuthProvider.provider(auth: auth).credential(
  461. withVerificationID: self.kVerificationID,
  462. verificationCode: self.kVerificationCode
  463. )
  464. user.updatePhoneNumber(credential) { rawError in
  465. XCTAssertTrue(Thread.isMainThread)
  466. let error = try! XCTUnwrap(rawError)
  467. XCTAssertEqual((error as NSError).code, AuthErrorCode.invalidPhoneNumber.rawValue)
  468. XCTAssertEqual(auth.currentUser, user)
  469. expectation.fulfill()
  470. }
  471. }
  472. }
  473. waitForExpectations(timeout: 5)
  474. }
  475. /** @fn testUpdatePhoneNumberFailureAutoSignOut
  476. @brief Tests the flow of a failed @c updatePhoneNumberCredential:completion: call that
  477. automatically signs out.
  478. */
  479. func testUpdatePhoneNumberFailureAutoSignOut() throws {
  480. setFakeGetAccountProvider()
  481. let expectation = self.expectation(description: #function)
  482. let auth = try XCTUnwrap(self.auth)
  483. signInWithEmailPasswordReturnFakeUser { user in
  484. do {
  485. self.rpcIssuer.respondBlock = {
  486. try self.rpcIssuer.respond(serverErrorMessage: "TOKEN_EXPIRED")
  487. }
  488. self.expectVerifyPhoneNumberRequest()
  489. let credential = PhoneAuthProvider.provider(auth: auth).credential(
  490. withVerificationID: self.kVerificationID,
  491. verificationCode: self.kVerificationCode
  492. )
  493. user.updatePhoneNumber(credential) { rawError in
  494. XCTAssertTrue(Thread.isMainThread)
  495. let error = try! XCTUnwrap(rawError)
  496. XCTAssertEqual((error as NSError).code, AuthErrorCode.userTokenExpired.rawValue)
  497. // User is no longer signed in.
  498. XCTAssertNil(self.auth?.currentUser)
  499. expectation.fulfill()
  500. }
  501. }
  502. }
  503. waitForExpectations(timeout: 5)
  504. }
  505. #endif
  506. /** @fn testUpdatePasswordSuccess
  507. @brief Tests the flow of a successful @c updatePassword:completion: call.
  508. */
  509. func testUpdatePasswordSuccess() {
  510. setFakeGetAccountProvider()
  511. let expectation = self.expectation(description: #function)
  512. signInWithEmailPasswordReturnFakeUser { user in
  513. self.changeUserEmail(user: user, expectation: expectation)
  514. }
  515. waitForExpectations(timeout: 5)
  516. }
  517. /** @fn testUpdatePasswordFailure
  518. @brief Tests the flow of a failed @c updatePassword:completion: call.
  519. */
  520. func testUpdatePasswordFailure() {
  521. setFakeGetAccountProvider()
  522. let expectation = self.expectation(description: #function)
  523. signInWithEmailPasswordReturnFakeUser { user in
  524. do {
  525. self.rpcIssuer.respondBlock = {
  526. try self.rpcIssuer.respond(serverErrorMessage: "CREDENTIAL_TOO_OLD_LOGIN_AGAIN")
  527. }
  528. user.updatePassword(to: self.kNewPassword) { rawError in
  529. XCTAssertTrue(Thread.isMainThread)
  530. let error = try! XCTUnwrap(rawError)
  531. XCTAssertEqual((error as NSError).code, AuthErrorCode.requiresRecentLogin.rawValue)
  532. // Email should not have changed on the client side.
  533. XCTAssertEqual(user.email, self.kEmail)
  534. // User is still signed in.
  535. XCTAssertEqual(self.auth?.currentUser, user)
  536. expectation.fulfill()
  537. }
  538. }
  539. }
  540. waitForExpectations(timeout: 5)
  541. }
  542. /** @fn testUpdateEmptyPasswordFailure
  543. @brief Tests the flow of a failed @c updatePassword:completion: call due to an empty password.
  544. */
  545. func testUpdateEmptyPasswordFailure() {
  546. setFakeGetAccountProvider()
  547. let expectation = self.expectation(description: #function)
  548. signInWithEmailPasswordReturnFakeUser { user in
  549. do {
  550. self.rpcIssuer.respondBlock = {
  551. try self.rpcIssuer.respond(serverErrorMessage: "WEAK_PASSWORD")
  552. }
  553. user.updatePassword(to: self.kNewPassword) { rawError in
  554. XCTAssertTrue(Thread.isMainThread)
  555. let error = try! XCTUnwrap(rawError)
  556. XCTAssertEqual((error as NSError).code, AuthErrorCode.weakPassword.rawValue)
  557. // Email should not have changed on the client side.
  558. XCTAssertEqual(user.email, self.kEmail)
  559. // User is still signed in.
  560. XCTAssertEqual(self.auth?.currentUser, user)
  561. expectation.fulfill()
  562. }
  563. }
  564. }
  565. waitForExpectations(timeout: 5)
  566. }
  567. /** @fn testUpdatePasswordFailureAutoSignOut
  568. @brief Tests the flow of a failed @c updatePassword:completion: call that automatically signs
  569. out.
  570. */
  571. func testUpdatePasswordFailureAutoSignOut() {
  572. setFakeGetAccountProvider()
  573. let expectation = self.expectation(description: #function)
  574. signInWithEmailPasswordReturnFakeUser { user in
  575. do {
  576. self.rpcIssuer.respondBlock = {
  577. try self.rpcIssuer.respond(serverErrorMessage: "USER_DISABLED")
  578. }
  579. user.updatePassword(to: self.kNewPassword) { rawError in
  580. XCTAssertTrue(Thread.isMainThread)
  581. let error = try! XCTUnwrap(rawError)
  582. XCTAssertEqual((error as NSError).code, AuthErrorCode.userDisabled.rawValue)
  583. // Email should not have changed on the client side.
  584. XCTAssertEqual(user.email, self.kEmail)
  585. // User is signed out.
  586. XCTAssertNil(self.auth?.currentUser)
  587. expectation.fulfill()
  588. }
  589. }
  590. }
  591. waitForExpectations(timeout: 5)
  592. }
  593. /** @fn testChangeProfileSuccess
  594. @brief Tests a successful user profile change flow.
  595. */
  596. func testChangeProfileSuccess() {
  597. setFakeGetAccountProvider()
  598. let expectation = self.expectation(description: #function)
  599. signInWithEmailPasswordReturnFakeUser { user in
  600. do {
  601. self.rpcIssuer.respondBlock = {
  602. try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
  603. "refreshToken": self.kRefreshToken])
  604. }
  605. let profileChange = user.createProfileChangeRequest()
  606. profileChange.photoURL = URL(string: self.kTestPhotoURL)
  607. profileChange.displayName = self.kNewDisplayName
  608. profileChange.commitChanges { error in
  609. XCTAssertTrue(Thread.isMainThread)
  610. XCTAssertNil(error)
  611. XCTAssertEqual(user.displayName, self.kNewDisplayName)
  612. XCTAssertEqual(user.photoURL, URL(string: self.kTestPhotoURL))
  613. expectation.fulfill()
  614. }
  615. }
  616. }
  617. waitForExpectations(timeout: 5)
  618. }
  619. /** @fn testChangeProfileFailure
  620. @brief Tests a failed user profile change flow.
  621. */
  622. func testChangeProfileFailure() {
  623. setFakeGetAccountProvider()
  624. let expectation = self.expectation(description: #function)
  625. signInWithEmailPasswordReturnFakeUser { user in
  626. do {
  627. self.rpcIssuer.respondBlock = {
  628. try self.rpcIssuer.respond(serverErrorMessage: "TOO_MANY_ATTEMPTS_TRY_LATER")
  629. }
  630. let profileChange = user.createProfileChangeRequest()
  631. profileChange.displayName = self.kNewDisplayName
  632. profileChange.commitChanges { rawError in
  633. XCTAssertTrue(Thread.isMainThread)
  634. let error = try! XCTUnwrap(rawError)
  635. XCTAssertEqual((error as NSError).code, AuthErrorCode.tooManyRequests.rawValue)
  636. // Email should not have changed on the client side.
  637. XCTAssertEqual(user.email, self.kEmail)
  638. XCTAssertEqual(user.displayName, self.kDisplayName)
  639. // User is still signed in.
  640. XCTAssertEqual(self.auth?.currentUser, user)
  641. expectation.fulfill()
  642. }
  643. }
  644. }
  645. waitForExpectations(timeout: 5)
  646. }
  647. /** @fn testChangeProfileFailureAutoSignOut
  648. @brief Tests a failed user profile change flow that automatically signs out.
  649. */
  650. func testChangeProfileFailureAutoSignOut() {
  651. setFakeGetAccountProvider()
  652. let expectation = self.expectation(description: #function)
  653. signInWithEmailPasswordReturnFakeUser { user in
  654. do {
  655. self.rpcIssuer.respondBlock = {
  656. try self.rpcIssuer.respond(serverErrorMessage: "USER_NOT_FOUND")
  657. }
  658. let profileChange = user.createProfileChangeRequest()
  659. profileChange.displayName = self.kNewDisplayName
  660. profileChange.commitChanges { rawError in
  661. XCTAssertTrue(Thread.isMainThread)
  662. let error = try! XCTUnwrap(rawError)
  663. XCTAssertEqual((error as NSError).code, AuthErrorCode.userNotFound.rawValue)
  664. // Email should not have changed on the client side.
  665. XCTAssertEqual(user.email, self.kEmail)
  666. // User is signed out.
  667. XCTAssertNil(self.auth?.currentUser)
  668. expectation.fulfill()
  669. }
  670. }
  671. }
  672. waitForExpectations(timeout: 5)
  673. }
  674. /** @fn testGetIDTokenResultSuccess
  675. @brief Tests the flow of a successful @c getIDTokenResultWithCompletion: call.
  676. */
  677. func testGetIDTokenResultSuccess() {
  678. internalGetIDTokenResult(token: RPCBaseTests.kFakeAccessToken, forceRefresh: false)
  679. }
  680. /** @fn testGetIDTokenResultForcingRefreshSameAccessTokenSuccess
  681. @brief Tests the flow of a successful @c getIDTokenResultForcingRefresh:completion: call when
  682. the returned access token is the same as the stored access token.
  683. */
  684. func testGetIDTokenResultForcingRefreshSameAccessTokenSuccess() {
  685. internalGetIDTokenResult(token: RPCBaseTests.kFakeAccessToken)
  686. }
  687. /** @fn testGetIDTokenResultForcingRefreshSuccess
  688. @brief Tests the flow successful @c getIDTokenResultForcingRefresh:completion: calls.
  689. */
  690. func testGetIDTokenResultForcingRefreshSuccess() {
  691. internalGetIDTokenResult(token: RPCBaseTests.kFakeAccessTokenLength415)
  692. internalGetIDTokenResult(token: RPCBaseTests.kFakeAccessTokenLength416)
  693. internalGetIDTokenResult(token: RPCBaseTests.kFakeAccessTokenLength523,
  694. emailMatch: "aunitestuser4@gmail.com")
  695. }
  696. /** @fn testGetIDTokenResultSuccessWithBase64EncodedURL
  697. @brief Tests the flow of a successful @c getIDTokenResultWithCompletion: call using a base64 url
  698. encoded string.
  699. */
  700. func testGetIDTokenResultSuccessWithBase64EncodedURL() {
  701. internalGetIDTokenResult(token: RPCBaseTests.kFakeAccessTokenWithBase64,
  702. emailMatch: ">>>>>>>>????????@gmail.com",
  703. audMatch: "??????????>>>>>>>>>>")
  704. }
  705. /** @fn testGetIDTokenResultForcingRefreshFailure
  706. @brief Tests the flow of a failed @c getIDTokenResultForcingRefresh:completion: call.
  707. */
  708. func testGetIDTokenResultForcingRefreshFailure() {
  709. setFakeGetAccountProvider()
  710. let expectation = self.expectation(description: #function)
  711. signInWithEmailPasswordReturnFakeUser(fakeAccessToken: RPCBaseTests.kFakeAccessToken) { user in
  712. let underlying = NSError(domain: "Test Error", code: 1)
  713. self.rpcIssuer?.secureTokenNetworkError =
  714. AuthErrorUtils.networkError(underlyingError: underlying) as NSError
  715. user.getIDTokenResult(forcingRefresh: true) { tokenResult, rawError in
  716. do {
  717. XCTAssertTrue(Thread.isMainThread)
  718. XCTAssertNil(tokenResult)
  719. let error = try XCTUnwrap(rawError)
  720. XCTAssertEqual((error as NSError).code, AuthErrorCode.networkError.rawValue)
  721. } catch {
  722. XCTFail("Caught an error in \(#function): \(error)")
  723. }
  724. expectation.fulfill()
  725. }
  726. }
  727. waitForExpectations(timeout: 5)
  728. }
  729. /** @fn testReloadSuccess
  730. @brief Tests the flow of a successful @c reloadWithCompletion: call.
  731. */
  732. func testReloadSuccess() {
  733. setFakeGetAccountProvider()
  734. let expectation = self.expectation(description: #function)
  735. signInWithEmailPasswordReturnFakeUser { user in
  736. user.reload { error in
  737. XCTAssertTrue(Thread.isMainThread)
  738. XCTAssertNil(error)
  739. XCTAssertEqual(user.displayName, self.kDisplayName)
  740. XCTAssertEqual(user.email, self.kEmail)
  741. expectation.fulfill()
  742. }
  743. }
  744. waitForExpectations(timeout: 5)
  745. }
  746. /** @fn testReloadFailure
  747. @brief Tests the flow of a failed @c reloadWithCompletion: call.
  748. */
  749. func testReloadFailure() {
  750. setFakeGetAccountProvider()
  751. let expectation = self.expectation(description: #function)
  752. signInWithEmailPasswordReturnFakeUser { user in
  753. do {
  754. self.rpcIssuer.respondBlock = {
  755. try self.rpcIssuer.respond(serverErrorMessage: "QUOTA_EXCEEDED")
  756. }
  757. // Clear fake so we can inject error
  758. self.rpcIssuer?.fakeGetAccountProviderJSON = nil
  759. user.reload { rawError in
  760. XCTAssertTrue(Thread.isMainThread)
  761. let error = try! XCTUnwrap(rawError)
  762. XCTAssertEqual((error as NSError).code, AuthErrorCode.quotaExceeded.rawValue)
  763. // User is still signed in.
  764. XCTAssertEqual(self.auth?.currentUser, user)
  765. expectation.fulfill()
  766. }
  767. }
  768. }
  769. waitForExpectations(timeout: 5)
  770. }
  771. /** @fn testReloadFailureAutoSignOut
  772. @brief Tests the flow of a failed @c reloadWithCompletion: call that automtatically signs out.
  773. */
  774. func testReloadFailureAutoSignOut() {
  775. setFakeGetAccountProvider()
  776. let expectation = self.expectation(description: #function)
  777. signInWithEmailPasswordReturnFakeUser { user in
  778. do {
  779. self.rpcIssuer.respondBlock = {
  780. try self.rpcIssuer.respond(serverErrorMessage: "TOKEN_EXPIRED")
  781. }
  782. // Clear fake so we can inject error
  783. self.rpcIssuer?.fakeGetAccountProviderJSON = nil
  784. user.reload { rawError in
  785. XCTAssertTrue(Thread.isMainThread)
  786. let error = try! XCTUnwrap(rawError)
  787. XCTAssertEqual((error as NSError).code, AuthErrorCode.userTokenExpired.rawValue)
  788. // User is no longer signed in.
  789. XCTAssertNil(self.auth?.currentUser)
  790. expectation.fulfill()
  791. }
  792. }
  793. }
  794. waitForExpectations(timeout: 5)
  795. }
  796. /** @fn testReauthenticateSuccess
  797. @brief Tests the flow of a successful @c reauthenticateWithCredential:completion: call.
  798. */
  799. func testReauthenticateSuccess() {
  800. setFakeGetAccountProvider()
  801. let expectation = self.expectation(description: #function)
  802. signInWithEmailPasswordReturnFakeUser { user in
  803. do {
  804. self.rpcIssuer.respondBlock = {
  805. try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
  806. "refreshToken": self.kRefreshToken])
  807. }
  808. let emailCredential = EmailAuthProvider.credential(withEmail: self.kEmail,
  809. password: self.kFakePassword)
  810. user.reauthenticate(with: emailCredential) { rawResult, error in
  811. XCTAssertTrue(Thread.isMainThread)
  812. XCTAssertNil(error)
  813. let result = try! XCTUnwrap(rawResult)
  814. XCTAssertEqual(result.user.uid, user.uid)
  815. XCTAssertEqual(result.user.email, user.email)
  816. XCTAssertEqual(result.additionalUserInfo?.isNewUser, false)
  817. // User is still signed in.
  818. XCTAssertEqual(self.auth?.currentUser, user)
  819. expectation.fulfill()
  820. }
  821. }
  822. }
  823. waitForExpectations(timeout: 5)
  824. }
  825. /** @fn testReauthenticateWithCredentialSuccess
  826. @brief Tests the flow of a successful @c reauthenticateWithCredential call.
  827. */
  828. func testReauthenticateWithCredentialSuccess() throws {
  829. let expectation = self.expectation(description: #function)
  830. signInWithGoogleCredential { user in
  831. do {
  832. self.rpcIssuer.respondBlock = {
  833. try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
  834. "refreshToken": self.kRefreshToken,
  835. "federatedId": self.kGoogleID,
  836. "providerId": GoogleAuthProvider.id,
  837. "localId": self.kLocalID,
  838. "displayName": self.kGoogleDisplayName,
  839. "rawUserInfo": self.kGoogleProfile,
  840. "username": self.kUserName])
  841. }
  842. let googleCredential = GoogleAuthProvider.credential(withIDToken: self.kGoogleIDToken,
  843. accessToken: self.kGoogleAccessToken)
  844. user.reauthenticate(with: googleCredential) { reauthenticatedAuthResult, error in
  845. XCTAssertTrue(Thread.isMainThread)
  846. do {
  847. try self.assertUserGoogle(reauthenticatedAuthResult?.user)
  848. } catch {
  849. XCTFail("\(error)")
  850. }
  851. XCTAssertNil(error)
  852. // Verify that the current user is unchanged.
  853. XCTAssertEqual(self.auth?.currentUser, user)
  854. // Verify that the current user and reauthenticated user are not same pointers.
  855. XCTAssertNotEqual(user, reauthenticatedAuthResult?.user)
  856. // Verify that anyway the current user and reauthenticated user have same IDs.
  857. XCTAssertEqual(reauthenticatedAuthResult?.user.uid, user.uid)
  858. XCTAssertEqual(reauthenticatedAuthResult?.user.email, user.email)
  859. XCTAssertEqual(reauthenticatedAuthResult?.user.displayName, user.displayName)
  860. XCTAssertEqual(reauthenticatedAuthResult?.additionalUserInfo?.username, self.kUserName)
  861. XCTAssertEqual(reauthenticatedAuthResult?.additionalUserInfo?.providerID,
  862. GoogleAuthProvider.id)
  863. XCTAssertEqual(
  864. reauthenticatedAuthResult?.additionalUserInfo?.profile as? [String: String],
  865. self.kGoogleProfile
  866. )
  867. expectation.fulfill()
  868. }
  869. }
  870. }
  871. waitForExpectations(timeout: 5)
  872. try assertUserGoogle(auth?.currentUser)
  873. }
  874. /** @fn testReauthenticateFailure
  875. @brief Tests the flow of a failed @c reauthenticateWithCredential:completion: call.
  876. */
  877. func testReauthenticateFailure() {
  878. setFakeGetAccountProvider()
  879. let expectation = self.expectation(description: #function)
  880. signInWithEmailPasswordReturnFakeUser { user in
  881. do {
  882. self.rpcIssuer.respondBlock = {
  883. try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
  884. "refreshToken": self.kRefreshToken])
  885. }
  886. self.setFakeGetAccountProvider(withLocalID: "A different Local ID")
  887. let emailCredential = EmailAuthProvider.credential(withEmail: self.kEmail,
  888. password: self.kFakePassword)
  889. user.reauthenticate(with: emailCredential) { reauthenticatedAuthResult, rawError in
  890. XCTAssertTrue(Thread.isMainThread)
  891. let error = try! XCTUnwrap(rawError)
  892. XCTAssertEqual((error as NSError).code, AuthErrorCode.userMismatch.rawValue)
  893. // Email should not have changed on the client side.
  894. XCTAssertEqual(user.email, self.kEmail)
  895. // User is still signed in.
  896. XCTAssertEqual(self.auth?.currentUser, user)
  897. expectation.fulfill()
  898. }
  899. }
  900. }
  901. waitForExpectations(timeout: 5)
  902. }
  903. /** @fn testReauthenticateUserMismatchFailure
  904. @brief Tests the flow of a failed @c reauthenticateWithCredential:completion: call due to trying
  905. to reauthenticate a user that does not exist.
  906. */
  907. func testReauthenticateUserMismatchFailure() {
  908. setFakeGetAccountProvider()
  909. let expectation = self.expectation(description: #function)
  910. signInWithEmailPasswordReturnFakeUser { user in
  911. do {
  912. self.rpcIssuer.respondBlock = {
  913. try self.rpcIssuer.respond(serverErrorMessage: "USER_NOT_FOUND")
  914. }
  915. let googleCredential = GoogleAuthProvider.credential(withIDToken: self.kGoogleIDToken,
  916. accessToken: self.kGoogleAccessToken)
  917. user.reauthenticate(with: googleCredential) { reauthenticatedAuthResult, rawError in
  918. XCTAssertTrue(Thread.isMainThread)
  919. let error = try! XCTUnwrap(rawError)
  920. XCTAssertEqual((error as NSError).code, AuthErrorCode.userMismatch.rawValue)
  921. // Email should not have changed on the client side.
  922. XCTAssertEqual(user.email, self.kEmail)
  923. // User is still signed in.
  924. XCTAssertEqual(self.auth?.currentUser, user)
  925. expectation.fulfill()
  926. }
  927. }
  928. }
  929. waitForExpectations(timeout: 5)
  930. }
  931. /** @fn testLinkAndRetrieveDataSuccess (and old testLinkCredentialSuccess)
  932. @brief Tests the flow of a successful @c linkWithCredential call.
  933. */
  934. func testLinkAndRetrieveDataSuccess() throws {
  935. setFakeGetAccountProvider()
  936. let expectation = self.expectation(description: #function)
  937. let auth = try XCTUnwrap(self.auth)
  938. signInWithFacebookCredential { user in
  939. XCTAssertNotNil(user)
  940. do {
  941. self.setFakeGoogleGetAccountProvider()
  942. self.rpcIssuer.respondBlock = {
  943. try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
  944. "refreshToken": self.kRefreshToken,
  945. "federatedId": self.kGoogleID,
  946. "providerId": GoogleAuthProvider.id,
  947. "localId": self.kLocalID,
  948. "displayName": self.kGoogleDisplayName,
  949. "rawUserInfo": self.kGoogleProfile,
  950. "username": self.kUserName])
  951. }
  952. let googleCredential = GoogleAuthProvider.credential(withIDToken: self.kGoogleIDToken,
  953. accessToken: self.kGoogleAccessToken)
  954. user.link(with: googleCredential) { linkAuthResult, error in
  955. XCTAssertTrue(Thread.isMainThread)
  956. XCTAssertNil(error)
  957. // Verify that the current user is unchanged.
  958. XCTAssertEqual(auth.currentUser, user)
  959. // Verify that the current user and reauthenticated user are the same pointers.
  960. XCTAssertEqual(user, linkAuthResult?.user)
  961. // Verify that anyway the current user and reauthenticated user have same IDs.
  962. XCTAssertEqual(linkAuthResult?.user.uid, user.uid)
  963. XCTAssertEqual(linkAuthResult?.user.email, user.email)
  964. XCTAssertEqual(linkAuthResult?.user.displayName, user.displayName)
  965. XCTAssertEqual(linkAuthResult?.additionalUserInfo?.username, self.kUserName)
  966. XCTAssertEqual(linkAuthResult?.additionalUserInfo?.providerID,
  967. GoogleAuthProvider.id)
  968. XCTAssertEqual(
  969. linkAuthResult?.additionalUserInfo?.profile as? [String: String],
  970. self.kGoogleProfile
  971. )
  972. XCTAssertEqual(linkAuthResult?.user.providerData.first?.providerID, GoogleAuthProvider.id)
  973. expectation.fulfill()
  974. }
  975. }
  976. }
  977. waitForExpectations(timeout: 5)
  978. try assertUserGoogle(auth.currentUser)
  979. }
  980. /** @fn testLinkAndRetrieveDataError
  981. @brief Tests the flow of an unsuccessful @c linkWithCredential:completion:
  982. call with an error from the backend.
  983. */
  984. func testLinkAndRetrieveDataError() throws {
  985. setFakeGetAccountProvider()
  986. let expectation = self.expectation(description: #function)
  987. signInWithFacebookCredential { user in
  988. XCTAssertNotNil(user)
  989. do {
  990. self.setFakeGetAccountProvider()
  991. self.rpcIssuer.respondBlock = {
  992. try self.rpcIssuer.respond(serverErrorMessage: "CREDENTIAL_TOO_OLD_LOGIN_AGAIN")
  993. }
  994. let googleCredential = GoogleAuthProvider.credential(withIDToken: self.kGoogleIDToken,
  995. accessToken: self.kGoogleAccessToken)
  996. user.link(with: googleCredential) { linkAuthResult, rawError in
  997. XCTAssertTrue(Thread.isMainThread)
  998. XCTAssertNil(linkAuthResult)
  999. let error = try! XCTUnwrap(rawError)
  1000. XCTAssertEqual((error as NSError).code, AuthErrorCode.requiresRecentLogin.rawValue)
  1001. // Email should not have changed on the client side.
  1002. XCTAssertEqual(user.email, self.kFacebookEmail)
  1003. // User is still signed in.
  1004. XCTAssertEqual(self.auth?.currentUser, user)
  1005. expectation.fulfill()
  1006. }
  1007. }
  1008. }
  1009. waitForExpectations(timeout: 5)
  1010. }
  1011. /** @fn testLinkAndRetrieveDataProviderAlreadyLinked and old testLinkCredentialProviderAlreadyLinkedError
  1012. @brief Tests the flow of an unsuccessful @c linkWithCredential:completion:
  1013. call with FIRAuthErrorCodeProviderAlreadyLinked, which is a client side error.
  1014. */
  1015. func testLinkAndRetrieveDataProviderAlreadyLinked() throws {
  1016. setFakeGetAccountProvider()
  1017. let expectation = self.expectation(description: #function)
  1018. signInWithFacebookCredential { user in
  1019. XCTAssertNotNil(user)
  1020. do {
  1021. self.setFakeGetAccountProvider()
  1022. let facebookCredential =
  1023. FacebookAuthProvider.credential(withAccessToken: self.kFacebookAccessToken)
  1024. user.link(with: facebookCredential) { linkAuthResult, rawError in
  1025. XCTAssertTrue(Thread.isMainThread)
  1026. XCTAssertNil(linkAuthResult)
  1027. do {
  1028. let error = try XCTUnwrap(rawError)
  1029. XCTAssertEqual((error as NSError).code, AuthErrorCode.providerAlreadyLinked.rawValue)
  1030. } catch {
  1031. XCTFail("Expected to throw providerAlreadyLinked error.")
  1032. }
  1033. // User is still signed in.
  1034. XCTAssertEqual(self.auth?.currentUser, user)
  1035. expectation.fulfill()
  1036. }
  1037. }
  1038. }
  1039. waitForExpectations(timeout: 5)
  1040. }
  1041. /** @fn testLinkAndRetrieveDataErrorAutoSignOut (and old testLinkCredentialError)
  1042. @brief Tests the flow of an unsuccessful @c linkWithCredential:completion:
  1043. call that automatically signs out.
  1044. */
  1045. func testLinkAndRetrieveDataErrorAutoSignOut() throws {
  1046. setFakeGetAccountProvider()
  1047. let expectation = self.expectation(description: #function)
  1048. signInWithFacebookCredential { user in
  1049. XCTAssertNotNil(user)
  1050. do {
  1051. self.setFakeGetAccountProvider()
  1052. self.rpcIssuer.respondBlock = {
  1053. try self.rpcIssuer.respond(serverErrorMessage: "USER_DISABLED")
  1054. }
  1055. let googleCredential = GoogleAuthProvider.credential(withIDToken: self.kGoogleIDToken,
  1056. accessToken: self.kGoogleAccessToken)
  1057. user.link(with: googleCredential) { linkAuthResult, rawError in
  1058. XCTAssertTrue(Thread.isMainThread)
  1059. XCTAssertNil(linkAuthResult)
  1060. let error = try! XCTUnwrap(rawError)
  1061. XCTAssertEqual((error as NSError).code, AuthErrorCode.userDisabled.rawValue)
  1062. // User is signed out.
  1063. XCTAssertNil(self.auth?.currentUser)
  1064. expectation.fulfill()
  1065. }
  1066. }
  1067. }
  1068. waitForExpectations(timeout: 5)
  1069. }
  1070. /** @fn testLinkEmailAndRetrieveDataSuccess
  1071. @brief Tests the flow of a successful @c linkWithCredential:completion:
  1072. invocation for email credential.
  1073. */
  1074. func testLinkEmailAndRetrieveDataSuccess() throws {
  1075. setFakeGetAccountProvider()
  1076. let expectation = self.expectation(description: #function)
  1077. let auth = try XCTUnwrap(self.auth)
  1078. signInWithFacebookCredential { user in
  1079. XCTAssertNotNil(user)
  1080. do {
  1081. self.rpcIssuer.respondBlock = {
  1082. let request = self.rpcIssuer?.request as? SignUpNewUserRequest
  1083. XCTAssertNotNil(request)
  1084. XCTAssertEqual(request?.email, self.kEmail)
  1085. XCTAssertEqual(request?.password, self.kFakePassword)
  1086. XCTAssertNil(request?.displayName)
  1087. let (data, error) = try self.rpcIssuer.respond(withJSON: [
  1088. "idToken": RPCBaseTests.kFakeAccessToken,
  1089. "refreshToken": self.kRefreshToken,
  1090. ])
  1091. self.setFakeGetAccountProvider(withProviderID: EmailAuthProvider.id)
  1092. return (data, error)
  1093. }
  1094. let emailCredential = EmailAuthProvider.credential(withEmail: self.kEmail,
  1095. password: self.kFakePassword)
  1096. user.link(with: emailCredential) { linkAuthResult, error in
  1097. XCTAssertTrue(Thread.isMainThread)
  1098. XCTAssertNil(error)
  1099. // Verify that the current user is unchanged.
  1100. XCTAssertEqual(auth.currentUser, user)
  1101. // Verify that the current user and reauthenticated user are the same pointers.
  1102. XCTAssertEqual(user, linkAuthResult?.user)
  1103. // Verify that anyway the current user and reauthenticated user have same IDs.
  1104. XCTAssertEqual(linkAuthResult?.user.uid, user.uid)
  1105. XCTAssertEqual(linkAuthResult?.user.email, user.email)
  1106. XCTAssertEqual(linkAuthResult?.user.displayName, user.displayName)
  1107. expectation.fulfill()
  1108. }
  1109. }
  1110. }
  1111. waitForExpectations(timeout: 5)
  1112. }
  1113. /** @fn tesLlinkEmailProviderAlreadyLinkedError
  1114. @brief Tests the flow of an unsuccessful @c linkWithCredential:completion:
  1115. invocation for email credential and FIRAuthErrorCodeProviderAlreadyLinked which is a client
  1116. side error.
  1117. */
  1118. func testLinkEmailProviderAlreadyLinkedError() throws {
  1119. setFakeGetAccountProvider()
  1120. let expectation = self.expectation(description: #function)
  1121. signInWithFacebookCredential { user in
  1122. XCTAssertNotNil(user)
  1123. do {
  1124. self.rpcIssuer.respondBlock = {
  1125. let request = self.rpcIssuer?.request as? SignUpNewUserRequest
  1126. XCTAssertNotNil(request)
  1127. XCTAssertEqual(request?.email, self.kEmail)
  1128. XCTAssertEqual(request?.password, self.kFakePassword)
  1129. let (data, error) = try self.rpcIssuer.respond(withJSON: [
  1130. "idToken": RPCBaseTests.kFakeAccessToken,
  1131. "refreshToken": self.kRefreshToken,
  1132. ])
  1133. self.setFakeGetAccountProvider(withProviderID: EmailAuthProvider.id)
  1134. return (data, error)
  1135. }
  1136. let emailCredential = EmailAuthProvider.credential(withEmail: self.kEmail,
  1137. password: self.kFakePassword)
  1138. user.link(with: emailCredential) { linkAuthResult, error in
  1139. XCTAssertEqual(user, linkAuthResult?.user)
  1140. linkAuthResult?.user.link(with: emailCredential) { linkLinkAuthResult, rawError in
  1141. XCTAssertTrue(Thread.isMainThread)
  1142. XCTAssertNil(linkLinkAuthResult)
  1143. do {
  1144. let error = try XCTUnwrap(rawError)
  1145. XCTAssertEqual((error as NSError).code, AuthErrorCode.providerAlreadyLinked.rawValue)
  1146. } catch {
  1147. XCTFail("Expected to throw providerAlreadyLinked error.")
  1148. }
  1149. // User is still signed in.
  1150. XCTAssertEqual(self.auth?.currentUser, user)
  1151. expectation.fulfill()
  1152. }
  1153. }
  1154. }
  1155. }
  1156. waitForExpectations(timeout: 5)
  1157. }
  1158. /** @fn testLinkEmailAndRetrieveDataError
  1159. @brief Tests the flow of an unsuccessful @c linkWithCredential:completion:
  1160. invocation for email credential and an error from the backend.
  1161. */
  1162. func testLinkEmailAndRetrieveDataError() throws {
  1163. setFakeGetAccountProvider()
  1164. let expectation = self.expectation(description: #function)
  1165. signInWithFacebookCredential { user in
  1166. XCTAssertNotNil(user)
  1167. do {
  1168. self.rpcIssuer.respondBlock = {
  1169. let request = self.rpcIssuer?.request as? SignUpNewUserRequest
  1170. XCTAssertNotNil(request)
  1171. XCTAssertEqual(request?.email, self.kEmail)
  1172. XCTAssertEqual(request?.password, self.kFakePassword)
  1173. return try self.rpcIssuer.respond(serverErrorMessage: "TOO_MANY_ATTEMPTS_TRY_LATER")
  1174. }
  1175. let emailCredential = EmailAuthProvider.credential(withEmail: self.kEmail,
  1176. password: self.kFakePassword)
  1177. user.link(with: emailCredential) { linkAuthResult, rawError in
  1178. XCTAssertTrue(Thread.isMainThread)
  1179. XCTAssertNil(linkAuthResult)
  1180. let error = try! XCTUnwrap(rawError)
  1181. XCTAssertEqual((error as NSError).code, AuthErrorCode.tooManyRequests.rawValue)
  1182. // User is still signed in.
  1183. XCTAssertEqual(self.auth?.currentUser, user)
  1184. expectation.fulfill()
  1185. }
  1186. }
  1187. }
  1188. waitForExpectations(timeout: 5)
  1189. }
  1190. /** @fn testLinkEmailAndRetrieveDataErrorAutoSignOut
  1191. @brief Tests the flow of an unsuccessful @c linkWithCredential:completion:
  1192. invocation that automatically signs out.
  1193. */
  1194. func testLinkEmailAndRetrieveDataErrorAutoSignOut() throws {
  1195. setFakeGetAccountProvider()
  1196. let expectation = self.expectation(description: #function)
  1197. signInWithFacebookCredential { user in
  1198. XCTAssertNotNil(user)
  1199. do {
  1200. self.rpcIssuer.respondBlock = {
  1201. XCTAssertNotNil(self.rpcIssuer?.request as? SignUpNewUserRequest)
  1202. return try self.rpcIssuer.respond(serverErrorMessage: "TOKEN_EXPIRED")
  1203. }
  1204. let emailCredential = EmailAuthProvider.credential(withEmail: self.kEmail,
  1205. password: self.kFakePassword)
  1206. user.link(with: emailCredential) { linkAuthResult, rawError in
  1207. XCTAssertTrue(Thread.isMainThread)
  1208. XCTAssertNil(linkAuthResult)
  1209. let error = try! XCTUnwrap(rawError)
  1210. XCTAssertEqual((error as NSError).code, AuthErrorCode.userTokenExpired.rawValue)
  1211. // User is signed out.
  1212. XCTAssertNil(self.auth?.currentUser)
  1213. expectation.fulfill()
  1214. }
  1215. }
  1216. }
  1217. waitForExpectations(timeout: 5)
  1218. }
  1219. #if os(iOS)
  1220. private class FakeOAuthProvider: OAuthProvider {
  1221. override func credential(with uiDelegate: AuthUIDelegate?) async throws -> AuthCredential {
  1222. return OAuthCredential(
  1223. withProviderID: GoogleAuthProvider.id,
  1224. sessionID: UserTests.kOAuthSessionID,
  1225. OAuthResponseURLString: UserTests.kOAuthRequestURI
  1226. )
  1227. }
  1228. }
  1229. /** @fn testLinkProviderFailure
  1230. @brief Tests the flow of a failed @c linkWithProvider:completion:
  1231. call.
  1232. */
  1233. func testLinkProviderFailure() throws {
  1234. setFakeGetAccountProvider()
  1235. let expectation = self.expectation(description: #function)
  1236. let auth = try XCTUnwrap(self.auth)
  1237. signInWithFacebookCredential { user in
  1238. XCTAssertNotNil(user)
  1239. do {
  1240. self.setFakeGetAccountProvider()
  1241. self.rpcIssuer.respondBlock = {
  1242. try self.rpcIssuer.respond(serverErrorMessage: "TOKEN_EXPIRED")
  1243. }
  1244. user.link(with: FakeOAuthProvider(providerID: "foo", auth: auth),
  1245. uiDelegate: nil) { linkAuthResult, rawError in
  1246. XCTAssertTrue(Thread.isMainThread)
  1247. XCTAssertNil(linkAuthResult)
  1248. let error = try! XCTUnwrap(rawError)
  1249. XCTAssertEqual((error as NSError).code, AuthErrorCode.userTokenExpired.rawValue)
  1250. // User is signed out.
  1251. XCTAssertNil(self.auth?.currentUser)
  1252. expectation.fulfill()
  1253. }
  1254. }
  1255. }
  1256. waitForExpectations(timeout: 5)
  1257. }
  1258. /** @fn testReauthenticateWithProviderFailure
  1259. @brief Tests the flow of a failed @c reauthenticateWithProvider:completion: call.
  1260. */
  1261. func testReauthenticateWithProviderFailure() throws {
  1262. setFakeGetAccountProvider()
  1263. let expectation = self.expectation(description: #function)
  1264. let auth = try XCTUnwrap(self.auth)
  1265. signInWithFacebookCredential { user in
  1266. XCTAssertNotNil(user)
  1267. do {
  1268. self.setFakeGetAccountProvider()
  1269. self.rpcIssuer.respondBlock = {
  1270. try self.rpcIssuer.respond(serverErrorMessage: "TOKEN_EXPIRED")
  1271. }
  1272. user.reauthenticate(with: FakeOAuthProvider(providerID: "foo", auth: auth),
  1273. uiDelegate: nil) { linkAuthResult, rawError in
  1274. XCTAssertTrue(Thread.isMainThread)
  1275. XCTAssertNil(linkAuthResult)
  1276. let error = try! XCTUnwrap(rawError)
  1277. XCTAssertEqual((error as NSError).code, AuthErrorCode.userTokenExpired.rawValue)
  1278. // User is still signed in.
  1279. XCTAssertEqual(self.auth?.currentUser, user)
  1280. expectation.fulfill()
  1281. }
  1282. }
  1283. }
  1284. waitForExpectations(timeout: 5)
  1285. }
  1286. /** @fn testLinkPhoneAuthCredentialSuccess
  1287. @brief Tests the flow of a successful @c linkWithCredential call using a phoneAuthCredential.
  1288. */
  1289. func testLinkPhoneAuthCredentialSuccess() throws {
  1290. setFakeGetAccountProvider()
  1291. let expectation = self.expectation(description: #function)
  1292. let auth = try XCTUnwrap(self.auth)
  1293. signInWithEmailPasswordReturnFakeUser { user in
  1294. XCTAssertNotNil(user)
  1295. self.expectVerifyPhoneNumberRequest(isLink: true)
  1296. do {
  1297. self.setFakeGetAccountProvider(withProviderID: PhoneAuthProvider.id)
  1298. self.rpcIssuer.respondBlock = {
  1299. try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
  1300. "refreshToken": self.kRefreshToken])
  1301. }
  1302. let credential = PhoneAuthProvider.provider(auth: auth).credential(
  1303. withVerificationID: self.kVerificationID,
  1304. verificationCode: self.kVerificationCode
  1305. )
  1306. user.link(with: credential) { linkAuthResult, error in
  1307. XCTAssertTrue(Thread.isMainThread)
  1308. XCTAssertNil(error)
  1309. // Verify that the current user is unchanged.
  1310. XCTAssertEqual(auth.currentUser, user)
  1311. // Verify that the current user and reauthenticated user are the same pointers.
  1312. XCTAssertEqual(user, linkAuthResult?.user)
  1313. // Verify that anyway the current user and reauthenticated user have same IDs.
  1314. XCTAssertEqual(linkAuthResult?.user.uid, user.uid)
  1315. XCTAssertEqual(linkAuthResult?.user.email, user.email)
  1316. XCTAssertEqual(linkAuthResult?.user.displayName, user.displayName)
  1317. XCTAssertEqual(auth.currentUser?.providerData.first?.providerID, PhoneAuthProvider.id)
  1318. XCTAssertEqual(
  1319. linkAuthResult?.user.providerData.first?.providerID,
  1320. PhoneAuthProvider.id
  1321. )
  1322. XCTAssertEqual(auth.currentUser?.phoneNumber, self.kTestPhoneNumber)
  1323. expectation.fulfill()
  1324. }
  1325. }
  1326. }
  1327. waitForExpectations(timeout: 5)
  1328. }
  1329. /** @fn testUnlinkPhoneAuthCredentialSuccess
  1330. @brief Tests the flow of a successful @c unlinkFromProvider:completion: call using a
  1331. @c FIRPhoneAuthProvider.
  1332. */
  1333. func testUnlinkPhoneAuthCredentialSuccess() throws {
  1334. setFakeGetAccountProvider()
  1335. let expectation = self.expectation(description: #function)
  1336. let auth = try XCTUnwrap(self.auth)
  1337. signInWithEmailPasswordReturnFakeUser { user in
  1338. XCTAssertNotNil(user)
  1339. self.expectVerifyPhoneNumberRequest(isLink: true)
  1340. do {
  1341. self.setFakeGetAccountProvider(withProviderID: PhoneAuthProvider.id)
  1342. self.rpcIssuer.respondBlock = {
  1343. try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
  1344. "refreshToken": self.kRefreshToken])
  1345. }
  1346. let credential = PhoneAuthProvider.provider(auth: auth).credential(
  1347. withVerificationID: self.kVerificationID,
  1348. verificationCode: self.kVerificationCode
  1349. )
  1350. user.link(with: credential) { linkAuthResult, error in
  1351. XCTAssertTrue(Thread.isMainThread)
  1352. XCTAssertNil(error)
  1353. // Verify that the current user is unchanged.
  1354. XCTAssertEqual(auth.currentUser, user)
  1355. // Verify that the current user and reauthenticated user are the same pointers.
  1356. XCTAssertEqual(user, linkAuthResult?.user)
  1357. // Verify that anyway the current user and reauthenticated user have same IDs.
  1358. XCTAssertEqual(linkAuthResult?.user.uid, user.uid)
  1359. XCTAssertEqual(linkAuthResult?.user.email, user.email)
  1360. XCTAssertEqual(linkAuthResult?.user.displayName, user.displayName)
  1361. XCTAssertEqual(auth.currentUser?.providerData.first?.providerID, PhoneAuthProvider.id)
  1362. XCTAssertEqual(
  1363. linkAuthResult?.user.providerData.first?.providerID,
  1364. PhoneAuthProvider.id
  1365. )
  1366. XCTAssertEqual(auth.currentUser?.phoneNumber, self.kTestPhoneNumber)
  1367. // Immediately unlink the phone auth provider.
  1368. self.rpcIssuer.respondBlock = {
  1369. let request = try XCTUnwrap(self.rpcIssuer?.request as? SetAccountInfoRequest)
  1370. XCTAssertEqual(request.apiKey, UserTests.kFakeAPIKey)
  1371. XCTAssertEqual(request.accessToken, RPCBaseTests.kFakeAccessToken)
  1372. XCTAssertNil(request.email)
  1373. XCTAssertNil(request.password)
  1374. XCTAssertNil(request.localID)
  1375. XCTAssertNil(request.displayName)
  1376. XCTAssertNil(request.photoURL)
  1377. XCTAssertNil(request.providers)
  1378. XCTAssertNil(request.deleteAttributes)
  1379. XCTAssertEqual(try XCTUnwrap(request.deleteProviders?.first), PhoneAuthProvider.id)
  1380. return try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
  1381. "refreshToken": self.kRefreshToken])
  1382. }
  1383. user.unlink(fromProvider: PhoneAuthProvider.id) { user, error in
  1384. XCTAssertNil(error)
  1385. XCTAssertEqual(auth.currentUser, user)
  1386. XCTAssertNil(auth.currentUser?.phoneNumber)
  1387. expectation.fulfill()
  1388. }
  1389. }
  1390. }
  1391. }
  1392. waitForExpectations(timeout: 5)
  1393. }
  1394. /** @fn testlinkPhoneAuthCredentialFailure
  1395. @brief Tests the flow of a failed call to @c linkWithCredential:completion: due
  1396. to a phone provider already being linked.
  1397. */
  1398. func testlinkPhoneAuthCredentialFailure() throws {
  1399. setFakeGetAccountProvider(withPasswordHash: kFakePassword)
  1400. let expectation = self.expectation(description: #function)
  1401. signInWithEmailPasswordReturnFakeUser { user in
  1402. XCTAssertNotNil(user)
  1403. self.expectVerifyPhoneNumberRequest(isLink: true)
  1404. self.setFakeGetAccountProvider(withProviderID: PhoneAuthProvider.id)
  1405. let credential = EmailAuthCredential(withEmail: self.kEmail, password: self.kFakePassword)
  1406. user.link(with: credential) { linkAuthResult, rawError in
  1407. XCTAssertTrue(Thread.isMainThread)
  1408. XCTAssertNil(linkAuthResult)
  1409. if let error = try? XCTUnwrap(rawError) {
  1410. XCTAssertEqual((error as NSError).code, AuthErrorCode.providerAlreadyLinked.rawValue)
  1411. } else {
  1412. XCTFail("Did not throw expected error")
  1413. }
  1414. expectation.fulfill()
  1415. }
  1416. }
  1417. waitForExpectations(timeout: 5)
  1418. }
  1419. /** @fn testlinkPhoneCredentialAlreadyExistsError
  1420. @brief Tests the flow of @c linkWithCredential:completion:
  1421. call using a phoneAuthCredential and a credential already exists error. In this case we
  1422. should get a AuthCredential in the error object.
  1423. */
  1424. func testlinkPhoneCredentialAlreadyExistsError() throws {
  1425. setFakeGetAccountProvider()
  1426. let expectation = self.expectation(description: #function)
  1427. let auth = try XCTUnwrap(self.auth)
  1428. signInWithEmailPasswordReturnFakeUser { user in
  1429. XCTAssertNotNil(user)
  1430. self.expectVerifyPhoneNumberRequest(isLink: true)
  1431. do {
  1432. self.setFakeGetAccountProvider(withProviderID: PhoneAuthProvider.id)
  1433. self.rpcIssuer.respondBlock = {
  1434. try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
  1435. "refreshToken": self.kRefreshToken,
  1436. "phoneNumber": self.kTestPhoneNumber,
  1437. "temporaryProof": "Fake Temporary Proof"])
  1438. }
  1439. let credential = PhoneAuthProvider.provider(auth: auth).credential(
  1440. withVerificationID: self.kVerificationID,
  1441. verificationCode: self.kVerificationCode
  1442. )
  1443. user.link(with: credential) { linkAuthResult, rawError in
  1444. XCTAssertTrue(Thread.isMainThread)
  1445. XCTAssertNil(linkAuthResult)
  1446. do {
  1447. let error = try XCTUnwrap(rawError)
  1448. XCTAssertEqual((error as NSError).code, AuthErrorCode.credentialAlreadyInUse.rawValue)
  1449. let credential = try XCTUnwrap((error as NSError)
  1450. .userInfo[AuthErrors.userInfoUpdatedCredentialKey] as? PhoneAuthCredential)
  1451. switch credential.credentialKind {
  1452. case let .phoneNumber(phoneNumber, temporaryProof):
  1453. XCTAssertEqual(temporaryProof, "Fake Temporary Proof")
  1454. XCTAssertEqual(phoneNumber, self.kTestPhoneNumber)
  1455. case .verification: XCTFail("Should be phoneNumber case")
  1456. }
  1457. } catch {
  1458. XCTFail("Did not throw expected error \(error)")
  1459. }
  1460. expectation.fulfill()
  1461. }
  1462. }
  1463. }
  1464. waitForExpectations(timeout: 5)
  1465. }
  1466. #endif
  1467. func testRetrieveUserWithInvalidToken() async throws {
  1468. let auth = try XCTUnwrap(self.auth)
  1469. do {
  1470. _ = try await User.retrieveUser(
  1471. withAuth: auth,
  1472. accessToken: nil,
  1473. accessTokenExpirationDate: Date(),
  1474. refreshToken: nil,
  1475. anonymous: false
  1476. )
  1477. XCTFail("Expected an error to be thrown")
  1478. } catch let error as NSError {
  1479. XCTAssertEqual(error.domain, AuthErrors.domain)
  1480. XCTAssertEqual(error.code, AuthErrorCode.invalidUserToken.rawValue)
  1481. }
  1482. }
  1483. // MARK: Private helper functions
  1484. private func expectVerifyPhoneNumberRequest(isLink: Bool = false) {
  1485. rpcIssuer?.verifyPhoneNumberRequester = { request in
  1486. XCTAssertEqual(request.verificationID, self.kVerificationID)
  1487. XCTAssertEqual(request.verificationCode, self.kVerificationCode)
  1488. XCTAssertEqual(request.accessToken, RPCBaseTests.kFakeAccessToken)
  1489. if isLink {
  1490. XCTAssertEqual(request.operation, AuthOperationType.link)
  1491. } else {
  1492. XCTAssertEqual(request.operation, AuthOperationType.update)
  1493. }
  1494. }
  1495. }
  1496. private func internalGetIDTokenResult(token: String, forceRefresh: Bool = true,
  1497. emailMatch: String = "aunitestuser@gmail.com",
  1498. audMatch: String = "test_aud") {
  1499. setFakeGetAccountProvider()
  1500. let expectation = self.expectation(description: #function)
  1501. signInWithEmailPasswordReturnFakeUser(fakeAccessToken: token) { user in
  1502. user.getIDTokenResult(forcingRefresh: forceRefresh) { rawTokenResult, error in
  1503. XCTAssertTrue(Thread.isMainThread)
  1504. XCTAssertNil(error)
  1505. XCTAssertEqual(user.displayName, self.kDisplayName)
  1506. XCTAssertEqual(user.email, self.kEmail)
  1507. let tokenResult = try! XCTUnwrap(rawTokenResult)
  1508. XCTAssertEqual(tokenResult.token, token)
  1509. XCTAssertNotNil(tokenResult.issuedAtDate)
  1510. XCTAssertNotNil(tokenResult.authDate)
  1511. XCTAssertNotNil(tokenResult.expirationDate)
  1512. XCTAssertNotNil(tokenResult.signInProvider)
  1513. // The lowercased is for the base64 test which seems to be an erroneously uppercased
  1514. // "Password"?
  1515. XCTAssertEqual(tokenResult.signInProvider.lowercased(), EmailAuthProvider.id)
  1516. XCTAssertEqual(tokenResult.claims["email"] as! String, emailMatch)
  1517. XCTAssertEqual(tokenResult.claims["aud"] as! String, audMatch)
  1518. XCTAssertEqual(tokenResult.signInSecondFactor, "")
  1519. expectation.fulfill()
  1520. }
  1521. }
  1522. waitForExpectations(timeout: 5)
  1523. }
  1524. private func changeUserEmail(user: User, changeEmail: Bool = false,
  1525. expectation: XCTestExpectation) {
  1526. do {
  1527. XCTAssertEqual(user.providerID, "Firebase")
  1528. XCTAssertEqual(user.uid, kLocalID)
  1529. XCTAssertEqual(user.displayName, kDisplayName)
  1530. XCTAssertEqual(user.photoURL, URL(string: kTestPhotoURL))
  1531. XCTAssertEqual(user.email, kEmail)
  1532. // Pretend that the display name on the server has been changed since the original signin.
  1533. setFakeGetAccountProvider(withNewDisplayName: kNewDisplayName)
  1534. rpcIssuer.respondBlock = {
  1535. let request = try XCTUnwrap(self.rpcIssuer?.request as? SetAccountInfoRequest)
  1536. XCTAssertEqual(request.apiKey, UserTests.kFakeAPIKey)
  1537. XCTAssertEqual(request.accessToken, RPCBaseTests.kFakeAccessToken)
  1538. if changeEmail {
  1539. XCTAssertEqual(request.email, self.kNewEmail)
  1540. XCTAssertNil(request.password)
  1541. } else {
  1542. XCTAssertEqual(request.password, self.kNewPassword)
  1543. XCTAssertNil(request.email)
  1544. }
  1545. XCTAssertNil(request.localID)
  1546. XCTAssertNil(request.displayName)
  1547. XCTAssertNil(request.photoURL)
  1548. XCTAssertNil(request.providers)
  1549. XCTAssertNil(request.deleteAttributes)
  1550. XCTAssertNil(request.deleteProviders)
  1551. return try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
  1552. "email": self.kNewEmail,
  1553. "refreshToken": self.kRefreshToken])
  1554. }
  1555. if changeEmail {
  1556. user.updateEmail(to: kNewEmail) { error in
  1557. XCTAssertNil(error)
  1558. XCTAssertEqual(user.email, self.kNewEmail)
  1559. XCTAssertEqual(user.displayName, self.kNewDisplayName)
  1560. XCTAssertFalse(user.isAnonymous)
  1561. expectation.fulfill()
  1562. }
  1563. } else {
  1564. user.updatePassword(to: kNewPassword) { error in
  1565. XCTAssertNil(error)
  1566. XCTAssertEqual(user.displayName, self.kNewDisplayName)
  1567. XCTAssertFalse(user.isAnonymous)
  1568. expectation.fulfill()
  1569. }
  1570. }
  1571. }
  1572. }
  1573. private func signInWithEmailPasswordReturnFakeUser(fakeAccessToken: String = RPCBaseTests
  1574. .kFakeAccessToken,
  1575. completion: @escaping (User) -> Void) {
  1576. let kRefreshToken = "fakeRefreshToken"
  1577. setFakeSecureTokenService(fakeAccessToken: fakeAccessToken)
  1578. rpcIssuer?.verifyPasswordRequester = { request in
  1579. // 2. Validate the created Request instance.
  1580. XCTAssertEqual(request.email, self.kEmail)
  1581. XCTAssertEqual(request.password, self.kFakePassword)
  1582. XCTAssertEqual(request.apiKey, UserTests.kFakeAPIKey)
  1583. XCTAssertTrue(request.returnSecureToken)
  1584. do {
  1585. // 3. Send the response from the fake backend.
  1586. return try self.rpcIssuer.respond(withJSON: ["idToken": fakeAccessToken,
  1587. "isNewUser": true,
  1588. "refreshToken": kRefreshToken])
  1589. } catch {
  1590. XCTFail("Failure sending response: \(error)")
  1591. return (nil, nil)
  1592. }
  1593. }
  1594. // 1. After setting up fakes, sign out and sign in.
  1595. do {
  1596. try auth?.signOut()
  1597. } catch {
  1598. XCTFail("Sign out failed: \(error)")
  1599. return
  1600. }
  1601. auth?.signIn(withEmail: kEmail, password: kFakePassword) { authResult, error in
  1602. // 4. After the response triggers the callback, verify the returned result.
  1603. XCTAssertTrue(Thread.isMainThread)
  1604. guard let user = authResult?.user else {
  1605. XCTFail("authResult.user is missing")
  1606. return
  1607. }
  1608. XCTAssertEqual(user.refreshToken, kRefreshToken)
  1609. XCTAssertFalse(user.isAnonymous)
  1610. XCTAssertEqual(user.email, self.kEmail)
  1611. guard let additionalUserInfo = authResult?.additionalUserInfo else {
  1612. XCTFail("authResult.additionalUserInfo is missing")
  1613. return
  1614. }
  1615. XCTAssertFalse(additionalUserInfo.isNewUser)
  1616. XCTAssertEqual(additionalUserInfo.providerID, EmailAuthProvider.id)
  1617. XCTAssertNil(error)
  1618. // Clear the password Requester to avoid being called again by reauthenticate tests.
  1619. self.rpcIssuer?.verifyPasswordRequester = nil
  1620. completion(user)
  1621. }
  1622. }
  1623. private func signInWithGoogleCredential(completion: @escaping (User) -> Void) {
  1624. setFakeSecureTokenService(fakeAccessToken: RPCBaseTests.kFakeAccessToken)
  1625. setFakeGoogleGetAccountProvider()
  1626. rpcIssuer.respondBlock = {
  1627. try self.verifyGoogleAssertionRequest(
  1628. XCTUnwrap(self.rpcIssuer?.request as? VerifyAssertionRequest)
  1629. )
  1630. // 3. Send the response from the fake backend.
  1631. return try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
  1632. "providerId": GoogleAuthProvider.id,
  1633. "refreshToken": self.kRefreshToken,
  1634. "localId": self.kLocalID,
  1635. "displayName": self.kDisplayName,
  1636. "rawUserInfo": self.kGoogleProfile,
  1637. "username": self.kUserName])
  1638. }
  1639. do {
  1640. try auth?.signOut()
  1641. let googleCredential = GoogleAuthProvider.credential(withIDToken: kGoogleIDToken,
  1642. accessToken: kGoogleAccessToken)
  1643. auth?.signIn(with: googleCredential) { authResult, error in
  1644. // 4. After the response triggers the callback, verify the returned result.
  1645. XCTAssertTrue(Thread.isMainThread)
  1646. guard let user = authResult?.user else {
  1647. XCTFail("authResult.user is missing")
  1648. return
  1649. }
  1650. XCTAssertEqual(user.refreshToken, self.kRefreshToken)
  1651. XCTAssertFalse(user.isAnonymous)
  1652. XCTAssertEqual(user.email, self.kGoogleEmail)
  1653. guard let additionalUserInfo = authResult?.additionalUserInfo,
  1654. let profile = additionalUserInfo.profile as? [String: String] else {
  1655. XCTFail("authResult.additionalUserInfo and/or profile is missing")
  1656. return
  1657. }
  1658. XCTAssertEqual(profile, self.kGoogleProfile)
  1659. XCTAssertFalse(additionalUserInfo.isNewUser)
  1660. XCTAssertEqual(additionalUserInfo.providerID, GoogleAuthProvider.id)
  1661. XCTAssertEqual(additionalUserInfo.username, self.kUserName)
  1662. XCTAssertNil(error)
  1663. completion(user)
  1664. }
  1665. } catch {
  1666. XCTFail("Throw in \(#function): \(error)")
  1667. }
  1668. }
  1669. private func verifyGoogleAssertionRequest(_ request: VerifyAssertionRequest) {
  1670. XCTAssertEqual(request.providerID, GoogleAuthProvider.id)
  1671. XCTAssertEqual(request.providerIDToken, kGoogleIDToken)
  1672. XCTAssertEqual(request.providerAccessToken, kGoogleAccessToken)
  1673. XCTAssertTrue(request.returnSecureToken)
  1674. XCTAssertEqual(request.apiKey, UserTests.kFakeAPIKey)
  1675. XCTAssertTrue(request.returnSecureToken)
  1676. }
  1677. private func signInWithFacebookCredential(completion: @escaping (User) -> Void) {
  1678. setFakeSecureTokenService(fakeAccessToken: RPCBaseTests.kFakeAccessToken)
  1679. setFakeGetAccountProvider(withNewDisplayName: kFacebookDisplayName,
  1680. withProviderID: FacebookAuthProvider.id,
  1681. withFederatedID: kFacebookID,
  1682. withEmail: kFacebookEmail)
  1683. rpcIssuer.respondBlock = {
  1684. let request = try XCTUnwrap(self.rpcIssuer?.request as? VerifyAssertionRequest)
  1685. XCTAssertEqual(request.providerID, FacebookAuthProvider.id)
  1686. XCTAssertEqual(request.providerIDToken, self.kFacebookIDToken)
  1687. XCTAssertEqual(request.providerAccessToken, self.kFacebookAccessToken)
  1688. XCTAssertTrue(request.returnSecureToken)
  1689. XCTAssertEqual(request.apiKey, UserTests.kFakeAPIKey)
  1690. XCTAssertTrue(request.returnSecureToken)
  1691. // 3. Send the response from the fake backend.
  1692. return try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
  1693. "refreshToken": self.kRefreshToken,
  1694. "federatedId": self.kFacebookID,
  1695. "providerId": FacebookAuthProvider.id,
  1696. "localId": self.kLocalID,
  1697. "displayName": self.kDisplayName,
  1698. "rawUserInfo": self.kGoogleProfile,
  1699. "username": self.kUserName])
  1700. }
  1701. do {
  1702. try auth?.signOut()
  1703. let facebookCredential = FacebookAuthProvider
  1704. .credential(withAccessToken: kFacebookAccessToken)
  1705. auth?.signIn(with: facebookCredential) { authResult, error in
  1706. // 4. After the response triggers the callback, verify the returned result.
  1707. XCTAssertTrue(Thread.isMainThread)
  1708. guard let user = authResult?.user else {
  1709. XCTFail("authResult.user is missing")
  1710. return
  1711. }
  1712. XCTAssertEqual(user.refreshToken, self.kRefreshToken)
  1713. XCTAssertFalse(user.isAnonymous)
  1714. XCTAssertEqual(user.email, self.kFacebookEmail)
  1715. XCTAssertEqual(user.displayName, self.kFacebookDisplayName)
  1716. XCTAssertEqual(user.providerData.count, 1)
  1717. guard let additionalUserInfo = authResult?.additionalUserInfo,
  1718. let facebookUserInfo = user.providerData.first,
  1719. let profile = additionalUserInfo.profile as? [String: String] else {
  1720. XCTFail("authResult.additionalUserInfo and/or profile is missing")
  1721. return
  1722. }
  1723. XCTAssertEqual(facebookUserInfo.providerID, FacebookAuthProvider.id)
  1724. XCTAssertEqual(facebookUserInfo.uid, self.kFacebookID)
  1725. XCTAssertEqual(facebookUserInfo.displayName, self.kFacebookDisplayName)
  1726. XCTAssertEqual(facebookUserInfo.email, self.kFacebookEmail)
  1727. XCTAssertEqual(profile, self.kGoogleProfile)
  1728. XCTAssertFalse(additionalUserInfo.isNewUser)
  1729. XCTAssertEqual(additionalUserInfo.providerID, FacebookAuthProvider.id)
  1730. XCTAssertEqual(additionalUserInfo.username, self.kUserName)
  1731. XCTAssertNil(error)
  1732. completion(user)
  1733. }
  1734. } catch {
  1735. XCTFail("Throw in \(#function): \(error)")
  1736. }
  1737. }
  1738. private func signInWithEmailPasswordReturnFakeUserLink(completion: @escaping (User) -> Void) {
  1739. let kRefreshToken = "fakeRefreshToken"
  1740. setFakeSecureTokenService()
  1741. rpcIssuer.respondBlock = {
  1742. let request = try XCTUnwrap(self.rpcIssuer?.request as? EmailLinkSignInRequest)
  1743. XCTAssertEqual(request.email, self.kEmail)
  1744. XCTAssertEqual(request.apiKey, UserTests.kFakeAPIKey)
  1745. XCTAssertEqual(request.oobCode, "aCode")
  1746. XCTAssertNil(request.idToken)
  1747. // Send the response from the fake backend.
  1748. return try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
  1749. "isNewUser": true,
  1750. "refreshToken": kRefreshToken])
  1751. }
  1752. do {
  1753. try auth?.signOut()
  1754. auth?.signIn(
  1755. withEmail: kEmail,
  1756. link: "https://www.google.com?oobCode=aCode&mode=signIn"
  1757. ) { authResult, error in
  1758. // 4. After the response triggers the callback, verify the returned result.
  1759. XCTAssertTrue(Thread.isMainThread)
  1760. guard let user = authResult?.user else {
  1761. XCTFail("authResult.user is missing")
  1762. return
  1763. }
  1764. XCTAssertEqual(user.refreshToken, kRefreshToken)
  1765. XCTAssertFalse(user.isAnonymous)
  1766. XCTAssertEqual(user.email, self.kEmail)
  1767. guard let additionalUserInfo = authResult?.additionalUserInfo else {
  1768. XCTFail("authResult.additionalUserInfo is missing")
  1769. return
  1770. }
  1771. XCTAssertTrue(additionalUserInfo.isNewUser)
  1772. XCTAssertEqual(additionalUserInfo.providerID, EmailAuthProvider.id)
  1773. XCTAssertNil(error)
  1774. completion(user)
  1775. }
  1776. } catch {
  1777. XCTFail("Throw in \(#function): \(error)")
  1778. }
  1779. }
  1780. }