Files
firebase-ios-sdk/FirebaseAuth/Sources/Swift/Backend/RPC/GetOOBConfirmationCodeRequest.swift
Nick Cookeandgemini-code-assist[bot] dc18b7f5b9 refactor(global): cleanup redundant availability checks and update sample apps audit (#16143)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-04-30 18:48:30 -04:00

294 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
enum GetOOBConfirmationCodeRequestType: Int {
/// Requests a password reset code.
case passwordReset
/// Requests an email verification code.
case verifyEmail
/// Requests an email sign-in link.
case emailLink
/// Requests a verify before update email.
case verifyBeforeUpdateEmail
var value: String {
switch self {
case .passwordReset:
return kPasswordResetRequestTypeValue
case .verifyEmail:
return kVerifyEmailRequestTypeValue
case .emailLink:
return kEmailLinkSignInTypeValue
case .verifyBeforeUpdateEmail:
return kVerifyBeforeUpdateEmailRequestTypeValue
}
}
}
private let kGetOobConfirmationCodeEndpoint = "getOobConfirmationCode"
/// The name of the required "requestType" property in the request.
private let kRequestTypeKey = "requestType"
/// The name of the "email" property in the request.
private let kEmailKey = "email"
/// The name of the "newEmail" property in the request.
private let kNewEmailKey = "newEmail"
/// The key for the "idToken" value in the request. This is actually the STS Access Token,
/// despite its confusing (backwards compatible) parameter name.
private let kIDTokenKey = "idToken"
/// The key for the "continue URL" value in the request.
private let kContinueURLKey = "continueUrl"
/// The key for the "iOS Bundle Identifier" value in the request.
private let kIosBundleIDKey = "iOSBundleId"
/// The key for the "Android Package Name" value in the request.
private let kAndroidPackageNameKey = "androidPackageName"
/// The key for the request parameter indicating whether the android app should be installed or not.
private let kAndroidInstallAppKey = "androidInstallApp"
/// The key for the "minimum Android version supported" value in the request.
private let kAndroidMinimumVersionKey = "androidMinimumVersion"
/// The key for the request parameter indicating whether the action code can be handled in the app
/// or not.
private let kCanHandleCodeInAppKey = "canHandleCodeInApp"
/// The key for the "link domain" value in the request.
private let kLinkDomainKey = "linkDomain"
/// The value for the "PASSWORD_RESET" request type.
private let kPasswordResetRequestTypeValue = "PASSWORD_RESET"
/// The value for the "EMAIL_SIGNIN" request type.
private let kEmailLinkSignInTypeValue = "EMAIL_SIGNIN"
/// The value for the "VERIFY_EMAIL" request type.
private let kVerifyEmailRequestTypeValue = "VERIFY_EMAIL"
/// The value for the "VERIFY_AND_CHANGE_EMAIL" request type.
private let kVerifyBeforeUpdateEmailRequestTypeValue = "VERIFY_AND_CHANGE_EMAIL"
/// The key for the tenant id value in the request.
private let kTenantIDKey = "tenantId"
/// The key for the "captchaResponse" value in the request.
private let kCaptchaResponseKey = "captchaResp"
/// The key for the "clientType" value in the request.
private let kClientType = "clientType"
/// The key for the "recaptchaVersion" value in the request.
private let kRecaptchaVersion = "recaptchaVersion"
class GetOOBConfirmationCodeRequest: IdentityToolkitRequest, AuthRPCRequest {
typealias Response = GetOOBConfirmationCodeResponse
/// The types of OOB Confirmation Code to request.
private let requestType: GetOOBConfirmationCodeRequestType
/// The email of the user for password reset.
let email: String?
/// The new email to be updated for verifyBeforeUpdateEmail.
private let updatedEmail: String?
/// The STS Access Token of the authenticated user for email change.
private let accessToken: String?
/// This URL represents the state/Continue URL in the form of a universal link.
let continueURL: String?
/// The iOS bundle Identifier, if available.
private let iOSBundleID: String?
/// The Android package name, if available.
private let androidPackageName: String?
/// The minimum Android version supported, if available.
private let androidMinimumVersion: String?
/// Indicates whether or not the Android app should be installed if not already available.
private let androidInstallApp: Bool
/// Indicates whether the action code link will open the app directly or after being
/// redirected from a Firebase owned web widget.
let handleCodeInApp: Bool
/// The Firebase Hosting domain used for out of band code flow.
private(set) var linkDomain: String?
/// Response to the captcha.
var captchaResponse: String?
/// The reCAPTCHA version.
var recaptchaVersion: String?
/// Designated initializer.
/// - Parameter requestType: The types of OOB Confirmation Code to request.
/// - Parameter email: The email of the user.
/// - Parameter newEmail: The email of the user to be updated.
/// - Parameter accessToken: The STS Access Token of the currently signed in user.
/// - Parameter actionCodeSettings: An object of FIRActionCodeSettings which specifies action code
/// settings to be applied to the OOB code request.
/// - Parameter requestConfiguration: An object containing configurations to be added to the
/// request.
required init(requestType: GetOOBConfirmationCodeRequestType,
email: String?,
newEmail: String?,
accessToken: String?,
actionCodeSettings: ActionCodeSettings?,
requestConfiguration: AuthRequestConfiguration) {
self.requestType = requestType
self.email = email
updatedEmail = newEmail
self.accessToken = accessToken
continueURL = actionCodeSettings?.url?.absoluteString
iOSBundleID = actionCodeSettings?.iOSBundleID
androidPackageName = actionCodeSettings?.androidPackageName
androidMinimumVersion = actionCodeSettings?.androidMinimumVersion
androidInstallApp = actionCodeSettings?.androidInstallIfNotAvailable ?? false
handleCodeInApp = actionCodeSettings?.handleCodeInApp ?? false
linkDomain = actionCodeSettings?.linkDomain
super.init(
endpoint: kGetOobConfirmationCodeEndpoint,
requestConfiguration: requestConfiguration
)
}
static func passwordResetRequest(email: String,
actionCodeSettings: ActionCodeSettings?,
requestConfiguration: AuthRequestConfiguration) ->
GetOOBConfirmationCodeRequest {
Self(requestType: .passwordReset,
email: email,
newEmail: nil,
accessToken: nil,
actionCodeSettings: actionCodeSettings,
requestConfiguration: requestConfiguration)
}
static func verifyEmailRequest(accessToken: String,
actionCodeSettings: ActionCodeSettings?,
requestConfiguration: AuthRequestConfiguration) ->
GetOOBConfirmationCodeRequest {
Self(requestType: .verifyEmail,
email: nil,
newEmail: nil,
accessToken: accessToken,
actionCodeSettings: actionCodeSettings,
requestConfiguration: requestConfiguration)
}
static func signInWithEmailLinkRequest(_ email: String,
actionCodeSettings: ActionCodeSettings?,
requestConfiguration: AuthRequestConfiguration)
-> Self {
Self(requestType: .emailLink,
email: email,
newEmail: nil,
accessToken: nil,
actionCodeSettings: actionCodeSettings,
requestConfiguration: requestConfiguration)
}
static func verifyBeforeUpdateEmail(accessToken: String,
newEmail: String,
actionCodeSettings: ActionCodeSettings?,
requestConfiguration: AuthRequestConfiguration)
-> Self {
Self(requestType: .verifyBeforeUpdateEmail,
email: nil,
newEmail: newEmail,
accessToken: accessToken,
actionCodeSettings: actionCodeSettings,
requestConfiguration: requestConfiguration)
}
var unencodedHTTPRequestBody: [String: AnyHashable]? {
var body: [String: AnyHashable] = [
kRequestTypeKey: requestType.value,
]
// For password reset requests, we only need an email address in addition to the already
// required fields.
if case .passwordReset = requestType {
body[kEmailKey] = email
}
// For verify email requests, we only need an STS Access Token in addition to the already
// required fields.
if case .verifyEmail = requestType {
body[kIDTokenKey] = accessToken
}
// For email sign-in link requests, we only need an email address in addition to the already
// required fields.
if case .emailLink = requestType {
body[kEmailKey] = email
}
// For email sign-in link requests, we only need an STS Access Token, a new email address in
// addition to the already required fields.
if case .verifyBeforeUpdateEmail = requestType {
body[kNewEmailKey] = updatedEmail
body[kIDTokenKey] = accessToken
}
if let continueURL = continueURL {
body[kContinueURLKey] = continueURL
}
if let iOSBundleID = iOSBundleID {
body[kIosBundleIDKey] = iOSBundleID
}
if let androidPackageName = androidPackageName {
body[kAndroidPackageNameKey] = androidPackageName
}
if let androidMinimumVersion = androidMinimumVersion {
body[kAndroidMinimumVersionKey] = androidMinimumVersion
}
if androidInstallApp {
body[kAndroidInstallAppKey] = true
}
if handleCodeInApp {
body[kCanHandleCodeInAppKey] = true
}
if let linkDomain {
body[kLinkDomainKey] = linkDomain
}
if let captchaResponse {
body[kCaptchaResponseKey] = captchaResponse
}
body[kClientType] = clientType
if let recaptchaVersion {
body[kRecaptchaVersion] = recaptchaVersion
}
if let tenantID {
body[kTenantIDKey] = tenantID
}
return body
}
func injectRecaptchaFields(recaptchaResponse: String?, recaptchaVersion: String) {
captchaResponse = recaptchaResponse
self.recaptchaVersion = recaptchaVersion
}
}