Files
firebase-ios-sdk/FirebaseAuth/Tests/Unit/GetOOBConfirmationCodeTests.swift
T

248 lines
10 KiB
Swift

// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License")
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import Foundation
import XCTest
@testable import FirebaseAuth
@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
class GetOOBConfirmationCodeTests: RPCBaseTests {
private let kRequestTypeKey = "requestType"
private let kPasswordResetRequestTypeValue = "PASSWORD_RESET"
private let kVerifyEmailRequestTypeValue = "VERIFY_EMAIL"
private let kEmailLinkSignInTypeValue = "EMAIL_SIGNIN"
private let kEmailKey = "email"
private let kTestEmail = "testgmail.com"
private let kAccessTokenKey = "idToken"
private let kTestAccessToken = "ACCESS_TOKEN"
private let kContinueURLKey = "continueUrl"
private let kIosBundleIDKey = "iOSBundleId"
private let kAndroidPackageNameKey = "androidPackageName"
private let kAndroidInstallAppKey = "androidInstallApp"
private let kAndroidMinimumVersionKey = "androidMinimumVersion"
private let kCanHandleCodeInAppKey = "canHandleCodeInApp"
private let kDynamicLinkDomainKey = "dynamicLinkDomain"
private let kExpectedAPIURL =
"https://www.googleapis.com/identitytoolkit/v3/relyingparty/getOobConfirmationCode?key=APIKey"
private let kOOBCodeKey = "oobCode"
private let kTestOOBCode = "OOBCode"
func testOobRequests() async throws {
for (request, requestType) in [
(getPasswordResetRequest, kPasswordResetRequestTypeValue),
(getSignInWithEmailRequest, kEmailLinkSignInTypeValue),
(getEmailVerificationRequest, kVerifyEmailRequestTypeValue),
] {
let request = try request()
try await checkRequest(
request: request,
expected: kExpectedAPIURL,
key: "should_be_empty_dictionary",
value: nil
)
let decodedRequest = try XCTUnwrap(rpcIssuer.decodedRequest)
XCTAssertEqual(decodedRequest[kRequestTypeKey] as? String, requestType)
if requestType == kVerifyEmailRequestTypeValue {
XCTAssertEqual(decodedRequest[kAccessTokenKey] as? String, kTestAccessToken)
} else {
XCTAssertEqual(decodedRequest[kEmailKey] as? String, kTestEmail)
}
XCTAssertEqual(decodedRequest[kContinueURLKey] as? String, kContinueURL)
XCTAssertEqual(decodedRequest[kIosBundleIDKey] as? String, kIosBundleID)
XCTAssertEqual(decodedRequest[kAndroidPackageNameKey] as? String, kAndroidPackageName)
XCTAssertEqual(decodedRequest[kAndroidMinimumVersionKey] as? String, kAndroidMinimumVersion)
XCTAssertEqual(decodedRequest[kAndroidInstallAppKey] as? Bool, true)
XCTAssertEqual(decodedRequest[kCanHandleCodeInAppKey] as? Bool, true)
XCTAssertEqual(decodedRequest[kDynamicLinkDomainKey] as? String, kDynamicLinkDomain)
}
}
/** @fn testPasswordResetRequestOptionalFields
@brief Tests the encoding of a password reset request with optional fields.
*/
func testPasswordResetRequestOptionalFields() async throws {
let kCaptchaResponseKey = "captchaResp"
let kTestCaptchaResponse = "testCaptchaResponse"
let kClientTypeKey = "clientType"
let kTestClientType = "testClientType"
let kRecaptchaVersionKey = "recaptchaVersion"
let kTestRecaptchaVersion = "testRecaptchaVersion"
for (request, requestType) in [
(getPasswordResetRequest, kPasswordResetRequestTypeValue),
(getSignInWithEmailRequest, kEmailLinkSignInTypeValue),
(getEmailVerificationRequest, kVerifyEmailRequestTypeValue),
] {
let request = try request()
request.captchaResponse = kTestCaptchaResponse
request.clientType = kTestClientType
request.recaptchaVersion = kTestRecaptchaVersion
try await checkRequest(
request: request,
expected: kExpectedAPIURL,
key: "should_be_empty_dictionary",
value: nil
)
let decodedRequest = try XCTUnwrap(rpcIssuer.decodedRequest)
XCTAssertEqual(decodedRequest[kRequestTypeKey] as? String, requestType)
if requestType == kVerifyEmailRequestTypeValue {
XCTAssertEqual(decodedRequest[kAccessTokenKey] as? String, kTestAccessToken)
} else {
XCTAssertEqual(decodedRequest[kEmailKey] as? String, kTestEmail)
}
XCTAssertEqual(decodedRequest[kContinueURLKey] as? String, kContinueURL)
XCTAssertEqual(decodedRequest[kIosBundleIDKey] as? String, kIosBundleID)
XCTAssertEqual(decodedRequest[kAndroidPackageNameKey] as? String, kAndroidPackageName)
XCTAssertEqual(decodedRequest[kAndroidMinimumVersionKey] as? String, kAndroidMinimumVersion)
XCTAssertEqual(decodedRequest[kAndroidInstallAppKey] as? Bool, true)
XCTAssertEqual(decodedRequest[kCanHandleCodeInAppKey] as? Bool, true)
XCTAssertEqual(decodedRequest[kDynamicLinkDomainKey] as? String, kDynamicLinkDomain)
XCTAssertEqual(decodedRequest[kCaptchaResponseKey] as? String, kTestCaptchaResponse)
XCTAssertEqual(decodedRequest[kClientTypeKey] as? String, kTestClientType)
XCTAssertEqual(decodedRequest[kRecaptchaVersionKey] as? String, kTestRecaptchaVersion)
}
}
func testGetOOBConfirmationCodeErrors() async throws {
let kEmailNotFoundMessage = "EMAIL_NOT_FOUND: fake custom message"
let kMissingEmailErrorMessage = "MISSING_EMAIL"
let kInvalidEmailErrorMessage = "INVALID_EMAIL:"
let kInvalidMessagePayloadErrorMessage = "INVALID_MESSAGE_PAYLOAD"
let kInvalidSenderErrorMessage = "INVALID_SENDER"
let kMissingIosBundleIDErrorMessage = "MISSING_IOS_BUNDLE_ID"
let kMissingAndroidPackageNameErrorMessage = "MISSING_ANDROID_PACKAGE_NAME"
let kUnauthorizedDomainErrorMessage = "UNAUTHORIZED_DOMAIN"
let kInvalidRecipientEmailErrorMessage = "INVALID_RECIPIENT_EMAIL"
let kInvalidContinueURIErrorMessage = "INVALID_CONTINUE_URI"
let kMissingContinueURIErrorMessage = "MISSING_CONTINUE_URI"
try await checkBackendError(
request: getPasswordResetRequest(),
message: kEmailNotFoundMessage,
errorCode: AuthErrorCode.userNotFound
)
try await checkBackendError(
request: getEmailVerificationRequest(),
message: kMissingEmailErrorMessage,
errorCode: AuthErrorCode.missingEmail
)
try await checkBackendError(
request: getPasswordResetRequest(),
message: kInvalidEmailErrorMessage,
errorCode: AuthErrorCode.invalidEmail
)
try await checkBackendError(
request: getPasswordResetRequest(),
message: kInvalidMessagePayloadErrorMessage,
errorCode: AuthErrorCode.invalidMessagePayload
)
try await checkBackendError(
request: getPasswordResetRequest(),
message: kInvalidSenderErrorMessage,
errorCode: AuthErrorCode.invalidSender
)
try await checkBackendError(
request: getPasswordResetRequest(),
message: kMissingIosBundleIDErrorMessage,
errorCode: AuthErrorCode.missingIosBundleID
)
try await checkBackendError(
request: getPasswordResetRequest(),
message: kMissingAndroidPackageNameErrorMessage,
errorCode: AuthErrorCode.missingAndroidPackageName
)
try await checkBackendError(
request: getPasswordResetRequest(),
message: kUnauthorizedDomainErrorMessage,
errorCode: AuthErrorCode.unauthorizedDomain
)
try await checkBackendError(
request: getPasswordResetRequest(),
message: kInvalidRecipientEmailErrorMessage,
errorCode: AuthErrorCode.invalidRecipientEmail
)
try await checkBackendError(
request: getPasswordResetRequest(),
message: kInvalidContinueURIErrorMessage,
errorCode: AuthErrorCode.invalidContinueURI
)
try await checkBackendError(
request: getPasswordResetRequest(),
message: kMissingContinueURIErrorMessage,
errorCode: AuthErrorCode.missingContinueURI
)
}
/** @fn testSuccessfulPasswordResetResponse
@brief This test simulates a complete password reset response (with OOB Code) and makes sure
it succeeds, and we get the OOB Code decoded correctly.
*/
func testSuccessfulOOBResponse() async throws {
for request in [
getPasswordResetRequest,
getSignInWithEmailRequest,
getEmailVerificationRequest,
] {
rpcIssuer?.respondBlock = {
try self.rpcIssuer?.respond(withJSON: [self.kOOBCodeKey: self.kTestOOBCode])
}
let response = try await AuthBackend.call(with: request())
XCTAssertEqual(response.OOBCode, kTestOOBCode)
}
}
/** @fn testSuccessfulPasswordResetResponseWithoutOOBCode
@brief This test simulates a password reset request where we don't receive the optional OOBCode
response value. It should still succeed.
*/
func testSuccessfulOOBResponseWithoutOOBCode() async throws {
for request in [
getPasswordResetRequest,
getSignInWithEmailRequest,
getEmailVerificationRequest,
] {
rpcIssuer?.respondBlock = {
try self.rpcIssuer?.respond(withJSON: [:])
}
let response = try await AuthBackend.call(with: request())
XCTAssertNil(response.OOBCode)
}
}
private func getPasswordResetRequest() throws -> GetOOBConfirmationCodeRequest {
return try XCTUnwrap(GetOOBConfirmationCodeRequest.passwordResetRequest(
email: kTestEmail,
actionCodeSettings: fakeActionCodeSettings(),
requestConfiguration: makeRequestConfiguration()
))
}
private func getSignInWithEmailRequest() throws -> GetOOBConfirmationCodeRequest {
return try XCTUnwrap(GetOOBConfirmationCodeRequest.signInWithEmailLinkRequest(
kTestEmail,
actionCodeSettings: fakeActionCodeSettings(),
requestConfiguration: makeRequestConfiguration()
))
}
private func getEmailVerificationRequest() throws -> GetOOBConfirmationCodeRequest {
return try XCTUnwrap(GetOOBConfirmationCodeRequest
.verifyEmailRequest(accessToken: kTestAccessToken,
actionCodeSettings: fakeActionCodeSettings(),
requestConfiguration: makeRequestConfiguration()))
}
}