GetOOBConfirmationCodeTests.swift 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  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. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
  18. class GetOOBConfirmationCodeTests: RPCBaseTests {
  19. private let kRequestTypeKey = "requestType"
  20. private let kPasswordResetRequestTypeValue = "PASSWORD_RESET"
  21. private let kVerifyEmailRequestTypeValue = "VERIFY_EMAIL"
  22. private let kEmailLinkSignInTypeValue = "EMAIL_SIGNIN"
  23. private let kEmailKey = "email"
  24. private let kTestEmail = "testgmail.com"
  25. private let kAccessTokenKey = "idToken"
  26. private let kTestAccessToken = "ACCESS_TOKEN"
  27. private let kContinueURLKey = "continueUrl"
  28. private let kIosBundleIDKey = "iOSBundleId"
  29. private let kAndroidPackageNameKey = "androidPackageName"
  30. private let kAndroidInstallAppKey = "androidInstallApp"
  31. private let kAndroidMinimumVersionKey = "androidMinimumVersion"
  32. private let kCanHandleCodeInAppKey = "canHandleCodeInApp"
  33. private let kDynamicLinkDomainKey = "dynamicLinkDomain"
  34. private let kLinkDomainKey = "linkDomain"
  35. private let kExpectedAPIURL =
  36. "https://www.googleapis.com/identitytoolkit/v3/relyingparty/getOobConfirmationCode?key=APIKey"
  37. private let kOOBCodeKey = "oobCode"
  38. private let kTestOOBCode = "OOBCode"
  39. func testOobRequests() async throws {
  40. for (request, requestType) in [
  41. (getPasswordResetRequest, kPasswordResetRequestTypeValue),
  42. (getSignInWithEmailRequest, kEmailLinkSignInTypeValue),
  43. (getEmailVerificationRequest, kVerifyEmailRequestTypeValue),
  44. ] {
  45. let request = try request()
  46. try await checkRequest(
  47. request: request,
  48. expected: kExpectedAPIURL,
  49. key: "should_be_empty_dictionary",
  50. value: nil
  51. )
  52. let decodedRequest = try XCTUnwrap(rpcIssuer.decodedRequest)
  53. XCTAssertEqual(decodedRequest[kRequestTypeKey] as? String, requestType)
  54. if requestType == kVerifyEmailRequestTypeValue {
  55. XCTAssertEqual(decodedRequest[kAccessTokenKey] as? String, kTestAccessToken)
  56. } else {
  57. XCTAssertEqual(decodedRequest[kEmailKey] as? String, kTestEmail)
  58. }
  59. XCTAssertEqual(decodedRequest[kContinueURLKey] as? String, kContinueURL)
  60. XCTAssertEqual(decodedRequest[kIosBundleIDKey] as? String, kIosBundleID)
  61. XCTAssertEqual(decodedRequest[kAndroidPackageNameKey] as? String, kAndroidPackageName)
  62. XCTAssertEqual(decodedRequest[kAndroidMinimumVersionKey] as? String, kAndroidMinimumVersion)
  63. XCTAssertEqual(decodedRequest[kAndroidInstallAppKey] as? Bool, true)
  64. XCTAssertEqual(decodedRequest[kCanHandleCodeInAppKey] as? Bool, true)
  65. XCTAssertEqual(decodedRequest[kDynamicLinkDomainKey] as? String, kDynamicLinkDomain)
  66. XCTAssertEqual(decodedRequest[kLinkDomainKey] as? String, kLinkDomain)
  67. }
  68. }
  69. /** @fn testPasswordResetRequestOptionalFields
  70. @brief Tests the encoding of a password reset request with optional fields.
  71. */
  72. func testPasswordResetRequestOptionalFields() async throws {
  73. let kCaptchaResponseKey = "captchaResp"
  74. let kTestCaptchaResponse = "testCaptchaResponse"
  75. let kClientTypeKey = "clientType"
  76. let kTestClientType = "testClientType"
  77. let kRecaptchaVersionKey = "recaptchaVersion"
  78. let kTestRecaptchaVersion = "testRecaptchaVersion"
  79. for (request, requestType) in [
  80. (getPasswordResetRequest, kPasswordResetRequestTypeValue),
  81. (getSignInWithEmailRequest, kEmailLinkSignInTypeValue),
  82. (getEmailVerificationRequest, kVerifyEmailRequestTypeValue),
  83. ] {
  84. let request = try request()
  85. request.captchaResponse = kTestCaptchaResponse
  86. request.clientType = kTestClientType
  87. request.recaptchaVersion = kTestRecaptchaVersion
  88. try await checkRequest(
  89. request: request,
  90. expected: kExpectedAPIURL,
  91. key: "should_be_empty_dictionary",
  92. value: nil
  93. )
  94. let decodedRequest = try XCTUnwrap(rpcIssuer.decodedRequest)
  95. XCTAssertEqual(decodedRequest[kRequestTypeKey] as? String, requestType)
  96. if requestType == kVerifyEmailRequestTypeValue {
  97. XCTAssertEqual(decodedRequest[kAccessTokenKey] as? String, kTestAccessToken)
  98. } else {
  99. XCTAssertEqual(decodedRequest[kEmailKey] as? String, kTestEmail)
  100. }
  101. XCTAssertEqual(decodedRequest[kContinueURLKey] as? String, kContinueURL)
  102. XCTAssertEqual(decodedRequest[kIosBundleIDKey] as? String, kIosBundleID)
  103. XCTAssertEqual(decodedRequest[kAndroidPackageNameKey] as? String, kAndroidPackageName)
  104. XCTAssertEqual(decodedRequest[kAndroidMinimumVersionKey] as? String, kAndroidMinimumVersion)
  105. XCTAssertEqual(decodedRequest[kAndroidInstallAppKey] as? Bool, true)
  106. XCTAssertEqual(decodedRequest[kCanHandleCodeInAppKey] as? Bool, true)
  107. XCTAssertEqual(decodedRequest[kDynamicLinkDomainKey] as? String, kDynamicLinkDomain)
  108. XCTAssertEqual(decodedRequest[kLinkDomainKey] as? String, kLinkDomain)
  109. XCTAssertEqual(decodedRequest[kCaptchaResponseKey] as? String, kTestCaptchaResponse)
  110. XCTAssertEqual(decodedRequest[kClientTypeKey] as? String, kTestClientType)
  111. XCTAssertEqual(decodedRequest[kRecaptchaVersionKey] as? String, kTestRecaptchaVersion)
  112. }
  113. }
  114. func testGetOOBConfirmationCodeErrors() async throws {
  115. let kEmailNotFoundMessage = "EMAIL_NOT_FOUND: fake custom message"
  116. let kMissingEmailErrorMessage = "MISSING_EMAIL"
  117. let kInvalidEmailErrorMessage = "INVALID_EMAIL:"
  118. let kInvalidMessagePayloadErrorMessage = "INVALID_MESSAGE_PAYLOAD"
  119. let kInvalidSenderErrorMessage = "INVALID_SENDER"
  120. let kMissingIosBundleIDErrorMessage = "MISSING_IOS_BUNDLE_ID"
  121. let kMissingAndroidPackageNameErrorMessage = "MISSING_ANDROID_PACKAGE_NAME"
  122. let kUnauthorizedDomainErrorMessage = "UNAUTHORIZED_DOMAIN"
  123. let kInvalidRecipientEmailErrorMessage = "INVALID_RECIPIENT_EMAIL"
  124. let kInvalidContinueURIErrorMessage = "INVALID_CONTINUE_URI"
  125. let kMissingContinueURIErrorMessage = "MISSING_CONTINUE_URI"
  126. try await checkBackendError(
  127. request: getPasswordResetRequest(),
  128. message: kEmailNotFoundMessage,
  129. errorCode: AuthErrorCode.userNotFound
  130. )
  131. try await checkBackendError(
  132. request: getEmailVerificationRequest(),
  133. message: kMissingEmailErrorMessage,
  134. errorCode: AuthErrorCode.missingEmail
  135. )
  136. try await checkBackendError(
  137. request: getPasswordResetRequest(),
  138. message: kInvalidEmailErrorMessage,
  139. errorCode: AuthErrorCode.invalidEmail
  140. )
  141. try await checkBackendError(
  142. request: getPasswordResetRequest(),
  143. message: kInvalidMessagePayloadErrorMessage,
  144. errorCode: AuthErrorCode.invalidMessagePayload
  145. )
  146. try await checkBackendError(
  147. request: getPasswordResetRequest(),
  148. message: kInvalidSenderErrorMessage,
  149. errorCode: AuthErrorCode.invalidSender
  150. )
  151. try await checkBackendError(
  152. request: getPasswordResetRequest(),
  153. message: kMissingIosBundleIDErrorMessage,
  154. errorCode: AuthErrorCode.missingIosBundleID
  155. )
  156. try await checkBackendError(
  157. request: getPasswordResetRequest(),
  158. message: kMissingAndroidPackageNameErrorMessage,
  159. errorCode: AuthErrorCode.missingAndroidPackageName
  160. )
  161. try await checkBackendError(
  162. request: getPasswordResetRequest(),
  163. message: kUnauthorizedDomainErrorMessage,
  164. errorCode: AuthErrorCode.unauthorizedDomain
  165. )
  166. try await checkBackendError(
  167. request: getPasswordResetRequest(),
  168. message: kInvalidRecipientEmailErrorMessage,
  169. errorCode: AuthErrorCode.invalidRecipientEmail
  170. )
  171. try await checkBackendError(
  172. request: getPasswordResetRequest(),
  173. message: kInvalidContinueURIErrorMessage,
  174. errorCode: AuthErrorCode.invalidContinueURI
  175. )
  176. try await checkBackendError(
  177. request: getPasswordResetRequest(),
  178. message: kMissingContinueURIErrorMessage,
  179. errorCode: AuthErrorCode.missingContinueURI
  180. )
  181. }
  182. /** @fn testSuccessfulPasswordResetResponse
  183. @brief This test simulates a complete password reset response (with OOB Code) and makes sure
  184. it succeeds, and we get the OOB Code decoded correctly.
  185. */
  186. func testSuccessfulOOBResponse() async throws {
  187. for request in [
  188. getPasswordResetRequest,
  189. getSignInWithEmailRequest,
  190. getEmailVerificationRequest,
  191. ] {
  192. rpcIssuer?.respondBlock = {
  193. try self.rpcIssuer?.respond(withJSON: [self.kOOBCodeKey: self.kTestOOBCode])
  194. }
  195. let response = try await AuthBackend.call(with: request())
  196. XCTAssertEqual(response.OOBCode, kTestOOBCode)
  197. }
  198. }
  199. /** @fn testSuccessfulPasswordResetResponseWithoutOOBCode
  200. @brief This test simulates a password reset request where we don't receive the optional OOBCode
  201. response value. It should still succeed.
  202. */
  203. func testSuccessfulOOBResponseWithoutOOBCode() async throws {
  204. for request in [
  205. getPasswordResetRequest,
  206. getSignInWithEmailRequest,
  207. getEmailVerificationRequest,
  208. ] {
  209. rpcIssuer?.respondBlock = {
  210. try self.rpcIssuer?.respond(withJSON: [:])
  211. }
  212. let response = try await AuthBackend.call(with: request())
  213. XCTAssertNil(response.OOBCode)
  214. }
  215. }
  216. private func getPasswordResetRequest() throws -> GetOOBConfirmationCodeRequest {
  217. return try XCTUnwrap(GetOOBConfirmationCodeRequest.passwordResetRequest(
  218. email: kTestEmail,
  219. actionCodeSettings: fakeActionCodeSettings(),
  220. requestConfiguration: makeRequestConfiguration()
  221. ))
  222. }
  223. private func getSignInWithEmailRequest() throws -> GetOOBConfirmationCodeRequest {
  224. return try XCTUnwrap(GetOOBConfirmationCodeRequest.signInWithEmailLinkRequest(
  225. kTestEmail,
  226. actionCodeSettings: fakeActionCodeSettings(),
  227. requestConfiguration: makeRequestConfiguration()
  228. ))
  229. }
  230. private func getEmailVerificationRequest() throws -> GetOOBConfirmationCodeRequest {
  231. return try XCTUnwrap(GetOOBConfirmationCodeRequest
  232. .verifyEmailRequest(accessToken: kTestAccessToken,
  233. actionCodeSettings: fakeActionCodeSettings(),
  234. requestConfiguration: makeRequestConfiguration()))
  235. }
  236. }