Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Auth): Rename resendConfirmationCode API for User Attributes to sendVerificationCode #3384

Merged
merged 5 commits into from
Dec 7, 2023
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
feat(Auth): Rename resendConfirmationCode API for User Attributes to …
…sendVerificationCode
harsh62 committed Nov 27, 2023

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
commit 83419e835b0112cb9536a436740009b52258b030
12 changes: 10 additions & 2 deletions Amplify/Categories/Auth/AuthCategory+UserBehavior.swift
Original file line number Diff line number Diff line change
@@ -27,10 +27,18 @@ extension AuthCategory: AuthCategoryUserBehavior {
try await plugin.update(userAttributes: userAttributes, options: options)
}

public func resendConfirmationCode(forUserAttributeKey userAttributeKey: AuthUserAttributeKey,
options: AuthAttributeResendConfirmationCodeRequest.Options? = nil) async throws -> AuthCodeDeliveryDetails {
public func resendConfirmationCode(
forUserAttributeKey userAttributeKey: AuthUserAttributeKey,
options: AuthAttributeResendConfirmationCodeRequest.Options? = nil
) async throws -> AuthCodeDeliveryDetails {
try await plugin.resendConfirmationCode(forUserAttributeKey: userAttributeKey, options: options)
}

public func sendVerificationCode(
forUserAttributeKey userAttributeKey: AuthUserAttributeKey,
options: AuthSendUserAttributeVerificationCodeRequest.Options? = nil
) async throws -> AuthCodeDeliveryDetails {
try await plugin.sendVerificationCode(forUserAttributeKey: userAttributeKey, options: options)
}

public func confirm(userAttribute: AuthUserAttributeKey,
17 changes: 15 additions & 2 deletions Amplify/Categories/Auth/AuthCategoryUserBehavior.swift
Original file line number Diff line number Diff line change
@@ -39,8 +39,21 @@ public protocol AuthCategoryUserBehavior: AnyObject {
/// - Parameters:
/// - userAttributeKey: Attribute to be verified
/// - options: Parameters specific to plugin behavior
func resendConfirmationCode(forUserAttributeKey userAttributeKey: AuthUserAttributeKey,
options: AuthAttributeResendConfirmationCodeRequest.Options?) async throws -> AuthCodeDeliveryDetails
@available(*, deprecated, renamed: "sendVerificationCode")
func resendConfirmationCode(
forUserAttributeKey userAttributeKey: AuthUserAttributeKey,
options: AuthAttributeResendConfirmationCodeRequest.Options?
) async throws -> AuthCodeDeliveryDetails

/// Sends the verification code required to verify an attribute
///
/// - Parameters:
/// - userAttributeKey: Attribute to be verified
/// - options: Parameters specific to plugin behavior
func sendVerificationCode(
forUserAttributeKey userAttributeKey: AuthUserAttributeKey,
options: AuthSendUserAttributeVerificationCodeRequest.Options?
) async throws -> AuthCodeDeliveryDetails

/// Confirm an attribute using confirmation code
///
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import Foundation

// swiftlint:disable type_name

/// Request for sending verification code that was generated for update attribute
public struct AuthSendUserAttributeVerificationCodeRequest: AmplifyOperationRequest {

/// Attribute key for which the confirmation code was sent
public let attributeKey: AuthUserAttributeKey

/// Extra request options defined in `AuthSendUserAttributeVerificationCodeRequest.Options`
public var options: Options

public init(attributeKey: AuthUserAttributeKey,
options: Options) {
self.attributeKey = attributeKey
self.options = options
}
}

public extension AuthSendUserAttributeVerificationCodeRequest {

struct Options {

/// Extra plugin specific options, only used in special circumstances when the existing options do not provide
/// a way to utilize the underlying auth plugin functionality. See plugin documentation for expected
/// key/values
public let pluginOptions: Any?

public init(pluginOptions: Any? = nil) {
self.pluginOptions = pluginOptions
}
}
}
Original file line number Diff line number Diff line change
@@ -41,8 +41,10 @@ public extension AWSCognitoAuthPlugin {
} as! [AuthUserAttributeKey: AuthUpdateAttributeResult]
}

func resendConfirmationCode(forUserAttributeKey userAttributeKey: AuthUserAttributeKey,
options: AuthAttributeResendConfirmationCodeRequest.Options? = nil) async throws -> AuthCodeDeliveryDetails {
func resendConfirmationCode(
forUserAttributeKey userAttributeKey: AuthUserAttributeKey,
options: AuthAttributeResendConfirmationCodeRequest.Options? = nil
) async throws -> AuthCodeDeliveryDetails {

let options = options ?? AuthAttributeResendConfirmationCodeRequest.Options()
let request = AuthAttributeResendConfirmationCodeRequest(
@@ -53,6 +55,22 @@ public extension AWSCognitoAuthPlugin {
} as! AuthCodeDeliveryDetails
}

func sendVerificationCode(
forUserAttributeKey userAttributeKey:
AuthUserAttributeKey,
options: AuthSendUserAttributeVerificationCodeRequest.Options? = nil
) async throws -> AuthCodeDeliveryDetails {
let options = options ?? AuthSendUserAttributeVerificationCodeRequest.Options()
let request = AuthSendUserAttributeVerificationCodeRequest(
attributeKey: userAttributeKey, options: options)
let task = AWSAuthSendUserAttributeVerificationCodeTask(
request, authStateMachine: authStateMachine,
userPoolFactory: authEnvironment.cognitoUserPoolFactory)
return try await taskQueue.sync {
return try await task.value
} as! AuthCodeDeliveryDetails
}

func confirm(userAttribute: AuthUserAttributeKey, confirmationCode: String, options: AuthConfirmUserAttributeRequest.Options? = nil) async throws {
let options = options ?? AuthConfirmUserAttributeRequest.Options()
let request = AuthConfirmUserAttributeRequest(
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@

import Foundation

@available(*, deprecated, renamed: "AWSSendUserAttributeVerificationCodeOptions")
public struct AWSAttributeResendConfirmationCodeOptions {

/// A map of custom key-value pairs that you can provide as input for any custom workflows that this action triggers.
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import Foundation

public struct AWSSendUserAttributeVerificationCodeOptions {

/// A map of custom key-value pairs that you can provide as input for any custom workflows that this action triggers.
///
/// When you use the ResendConfirmationCode API action, Amazon Cognito invokes the function that is assigned to the custom message trigger.
/// When Amazon Cognito invokes this function, it passes a JSON payload, which the function receives as input.
/// This payload contains a clientMetadata attribute, which provides the data that you assigned to the ClientMetadata parameter in your GetUserAttributeVerificationCode request.
/// In your function code in AWS Lambda, you can process the clientMetadata value to enhance your workflow for your specific needs.
///
/// For more information, see Customizing user pool Workflows with Lambda Triggers in the Amazon Cognito Developer Guide.
public let metadata: [String: String]?

public init(metadata: [String: String]? = nil) {
self.metadata = metadata
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import Amplify

protocol AuthSendUserAttributeVerificationCodeTask: AmplifyAuthTask where Request == AuthSendUserAttributeVerificationCodeRequest, Success == AuthCodeDeliveryDetails, Failure == AuthError {}

public extension HubPayload.EventName.Auth {

/// eventName for HubPayloads emitted by this operation
static let sendUserAttributeVerificationCodeAPI = "Auth.sendUserAttributeVerificationCodeAPI"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import Foundation
import Amplify
import AWSPluginsCore
import AWSCognitoIdentityProvider

class AWSAuthSendUserAttributeVerificationCodeTask: AuthSendUserAttributeVerificationCodeTask {
typealias CognitoUserPoolFactory = () throws -> CognitoUserPoolBehavior

private let request: AuthSendUserAttributeVerificationCodeRequest
private let authStateMachine: AuthStateMachine
private let userPoolFactory: CognitoUserPoolFactory
private let taskHelper: AWSAuthTaskHelper

var eventName: HubPayloadEventName {
HubPayload.EventName.Auth.sendUserAttributeVerificationCodeAPI
}

init(_ request: AuthSendUserAttributeVerificationCodeRequest,
authStateMachine: AuthStateMachine,
userPoolFactory: @escaping CognitoUserPoolFactory) {
self.request = request
self.authStateMachine = authStateMachine
self.userPoolFactory = userPoolFactory
self.taskHelper = AWSAuthTaskHelper(authStateMachine: authStateMachine)
}

func execute() async throws -> AuthCodeDeliveryDetails {
do {
await taskHelper.didStateMachineConfigured()
let accessToken = try await taskHelper.getAccessToken()
let devices = try await initiateGettingVerificationCode(with: accessToken)
return devices
} catch let error as AuthErrorConvertible {
throw error.authError
} catch {
throw AuthError.configuration(
"Unable to execute auth task",
AuthPluginErrorConstants.configurationError,
error
)
}
}

func initiateGettingVerificationCode(with accessToken: String) async throws -> AuthCodeDeliveryDetails {
let userPoolService = try userPoolFactory()
let clientMetaData = (request.options.pluginOptions as? AWSAttributeResendConfirmationCodeOptions)?.metadata ?? [:]

let input = GetUserAttributeVerificationCodeInput(
accessToken: accessToken,
attributeName: request.attributeKey.rawValue,
clientMetadata: clientMetaData)

let result = try await userPoolService.getUserAttributeVerificationCode(input: input)
guard let deliveryDetails = result.codeDeliveryDetails?.toAuthCodeDeliveryDetails() else {
let authError = AuthError.unknown("Unable to get Auth code delivery details", nil)
throw authError
}
return deliveryDetails
}
}
Original file line number Diff line number Diff line change
@@ -136,36 +136,36 @@ class AWSCognitoAuthUserBehaviorTests: BasePluginTest {
_ = try await plugin.update(userAttributes: [emailAttribute, phoneAttribute])
}

/// Test resendConfirmationCode(for:) operation can be invoked
/// Test sendVerificationCode(for:) operation can be invoked
///
/// - Given: Given a configured auth plugin
/// - When:
/// - I call resendConfirmationCode(for:) operation
/// - I call sendVerificationCode(for:) operation
/// - Then:
/// - I should get a valid task completion
///
func testResendConfirmationCodeAttributeRequest() async throws {
func testSendVerificationCodeAttributeRequest() async throws {
mockIdentityProvider = MockIdentityProvider(mockGetUserAttributeVerificationCodeOutput: { _ in
GetUserAttributeVerificationCodeOutput(
codeDeliveryDetails: .init(
attributeName: "attributeName",
deliveryMedium: .email,
destination: "destination"))
})
let pluginOptions = AWSAttributeResendConfirmationCodeOptions(metadata: ["key": "value"])
let options = AuthAttributeResendConfirmationCodeRequest.Options(pluginOptions: pluginOptions)
_ = try await plugin.resendConfirmationCode(forUserAttributeKey: .email, options: options)
let pluginOptions = AWSSendUserAttributeVerificationCodeOptions(metadata: ["key": "value"])
let options = AuthSendUserAttributeVerificationCodeRequest.Options(pluginOptions: pluginOptions)
_ = try await plugin.sendVerificationCode(forUserAttributeKey: .email, options: options)
}

/// Test resendConfirmationCode(for:) operation can be invoked with plugin options
/// Test sendVerificationCode(for:) operation can be invoked with plugin options
///
/// - Given: Given a configured auth plugin
/// - When:
/// - I call resendConfirmationCode(for:) operation
/// - I call sendVerificationCode(for:) operation
/// - Then:
/// - I should get a valid task completion
///
func testResendConfirmationCodeWithPluginOptions() async throws {
func testSendVerificationCodeWithPluginOptions() async throws {
mockIdentityProvider = MockIdentityProvider(mockGetUserAttributeVerificationCodeOutput: { request in

XCTAssertNotNil(request.clientMetadata)
@@ -176,28 +176,28 @@ class AWSCognitoAuthUserBehaviorTests: BasePluginTest {
deliveryMedium: .email,
destination: "destination"))
})
let pluginOptions = AWSAttributeResendConfirmationCodeOptions(metadata: ["key": "value"])
let options = AuthAttributeResendConfirmationCodeRequest.Options(pluginOptions: pluginOptions)
_ = try await plugin.resendConfirmationCode(forUserAttributeKey: .email, options: options)
let pluginOptions = AWSSendUserAttributeVerificationCodeOptions(metadata: ["key": "value"])
let options = AuthSendUserAttributeVerificationCodeRequest.Options(pluginOptions: pluginOptions)
_ = try await plugin.sendVerificationCode(forUserAttributeKey: .email, options: options)
}

/// Test resendConfirmationCode(for:) operation can be invoked without options
/// Test sendVerificationCode(for:) operation can be invoked without options
///
/// - Given: Given a configured auth plugin
/// - When:
/// - I call resendConfirmationCode(for:) operation
/// - I call sendVerificationCode(for:) operation
/// - Then:
/// - I should get a valid task completion
///
func testResendConfirmationCodeAttributeRequestWithoutOptions() async throws {
func testSendVerificationCodeAttributeRequestWithoutOptions() async throws {
mockIdentityProvider = MockIdentityProvider(mockGetUserAttributeVerificationCodeOutput: { _ in
GetUserAttributeVerificationCodeOutput(
codeDeliveryDetails: .init(
attributeName: "attributeName",
deliveryMedium: .email,
destination: "destination"))
})
_ = try await plugin.resendConfirmationCode(forUserAttributeKey: .email)
_ = try await plugin.sendVerificationCode(forUserAttributeKey: .email)
}

/// Test confirm(userAttribute: ) operation can be invoked

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -171,11 +171,11 @@ class AuthUserAttributesTests: AWSAuthBaseTest {
///
/// - Given: A confirmed user, with email added to the user's attributes (sending first confirmation code)
/// - When:
/// - I invoke Amplify.Auth.resendConfirmationCode for email
/// - I invoke Amplify.Auth.sendVerificationCode for email
/// - Then:
/// - The request should be successful and the email specified should receive a second confirmation code
///
func testSuccessfulResendConfirmationCodeWithUpdatedEmail() async throws {
func testSuccessfulSendVerificationCodeWithUpdatedEmail() async throws {
let username = "integTest\(UUID().uuidString)"
let password = "P123@\(UUID().uuidString)"
let updatedEmail = "\(username)@amazon.com"
@@ -186,9 +186,9 @@ class AuthUserAttributesTests: AWSAuthBaseTest {
XCTAssertTrue(didSucceed, "SignIn operation failed")

_ = try await Amplify.Auth.update(userAttribute: AuthUserAttribute(.email, value: updatedEmail))
let pluginOptions = AWSAttributeResendConfirmationCodeOptions(metadata: ["mydata": "myvalue"])
let options = AuthAttributeResendConfirmationCodeRequest.Options(pluginOptions: pluginOptions)
_ = try await Amplify.Auth.resendConfirmationCode(forUserAttributeKey: .email, options: options)
let pluginOptions = AWSSendUserAttributeVerificationCodeOptions(metadata: ["mydata": "myvalue"])
let options = AuthSendUserAttributeVerificationCodeRequest.Options(pluginOptions: pluginOptions)
_ = try await Amplify.Auth.sendVerificationCode(forUserAttributeKey: .email, options: options)
}

/// Test resending code for the user's updated email attribute.
@@ -199,11 +199,11 @@ class AuthUserAttributesTests: AWSAuthBaseTest {
///
/// - Given: A confirmed user, with email added to the user's attributes (sending first confirmation code)
/// - When:
/// - I invoke Amplify.Auth.resendConfirmationCode for email
/// - I invoke Amplify.Auth.sendVerificationCode for email
/// - Then:
/// - The request should be successful and the email specified should receive a second confirmation code
///
func testSuccessfulResendConfirmationCode() async throws {
func testSuccessfulSendVerificationCode() async throws {
let username = "integTest\(UUID().uuidString)"
let password = "P123@\(UUID().uuidString)"

@@ -212,9 +212,9 @@ class AuthUserAttributesTests: AWSAuthBaseTest {
email: defaultTestEmail)
XCTAssertTrue(didSucceed, "SignIn operation failed")

let pluginOptions = AWSAttributeResendConfirmationCodeOptions(metadata: ["mydata": "myvalue"])
let options = AuthAttributeResendConfirmationCodeRequest.Options(pluginOptions: pluginOptions)
_ = try await Amplify.Auth.resendConfirmationCode(forUserAttributeKey: .email, options: options)
let pluginOptions = AWSSendUserAttributeVerificationCodeOptions(metadata: ["mydata": "myvalue"])
let options = AuthSendUserAttributeVerificationCodeRequest.Options(pluginOptions: pluginOptions)
_ = try await Amplify.Auth.sendVerificationCode(forUserAttributeKey: .email, options: options)
}

/// Test changing/updating users password.
6 changes: 6 additions & 0 deletions AmplifyTestCommon/Mocks/MockAuthCategoryPlugin.swift
Original file line number Diff line number Diff line change
@@ -96,7 +96,13 @@ class MockAuthCategoryPlugin: MessageReporter, AuthCategoryPlugin {
public func resendConfirmationCode(forUserAttributeKey userAttributeKey: AuthUserAttributeKey, options: AuthAttributeResendConfirmationCodeRequest.Options? = nil)
async throws -> AuthCodeDeliveryDetails {
fatalError()
}

public func sendVerificationCode(
forUserAttributeKey userAttributeKey: AuthUserAttributeKey,
options: AuthSendUserAttributeVerificationCodeRequest.Options? = nil)
async throws -> AuthCodeDeliveryDetails {
fatalError()
}

public func setUpTOTP() async throws -> TOTPSetupDetails {