Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: added

Add `jetpack_account_protection_send_auth_email` filter to allow custom handling of the verification email.
19 changes: 19 additions & 0 deletions projects/packages/account-protection/src/class-email-service.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,25 @@ public function __construct(
public function api_send_auth_email( int $user_id, string $auth_code ) {
$blog_id = Jetpack_Options::get_option( 'id' );

/**
* Filters whether the Account Protection verification email should be handled externally.
*
* When the filter returns a truthy value, the default WPCOM API email send is skipped,
* allowing sites to deliver the email locally (e.g. via `wp_mail()`).
*
* @since $$next-version$$
*
* @param bool $handled Whether the email has been handled. Default false.
* @param int $user_id The user ID.
* @param string $auth_code The authentication code.
* @param int $blog_id The blog ID, or false if not available.
*/
$handled = apply_filters( 'jetpack_account_protection_send_auth_email', false, $user_id, $auth_code, $blog_id );

if ( $handled ) {
return true;
}

if ( ! $blog_id || ! $this->connection_manager->is_connected() ) {
return new \WP_Error( 'jetpack_connection_error', __( 'Jetpack is not connected. Please connect and try again.', 'jetpack-account-protection' ) );
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,56 @@ public function test_resend_auth_mail_sends_mail_and_remembers_2fa_token_success
$this->assertMatchesRegularExpression( '/^[0-9]{6}$/', $new_transient['auth_code'], 'Auth code should be 6 digits.' );
}

public function test_api_send_auth_email_skips_api_call_when_filter_returns_truthy(): void {
$sut = new Email_Service();
$user = new \WP_User();
$user->ID = 1;

$filter_args = array(
'handled' => null,
'user_id' => null,
'auth_code' => null,
'blog_id' => null,
);
$callback = function ( $handled, $user_id, $auth_code, $blog_id ) use ( &$filter_args ) {
$filter_args = compact( 'handled', 'user_id', 'auth_code', 'blog_id' );
return true;
};

add_filter( 'jetpack_account_protection_send_auth_email', $callback, 10, 4 );

$result = $sut->api_send_auth_email( $user->ID, '123456' );

remove_filter( 'jetpack_account_protection_send_auth_email', $callback, 10 );

$this->assertTrue( $result, 'api_send_auth_email should return true when the filter short-circuits.' );
$this->assertNotEmpty( $filter_args, 'Filter callback should have been called.' );
$this->assertFalse( $filter_args['handled'], 'Default handled value should be false.' );
$this->assertSame( 1, $filter_args['user_id'], 'Filter should receive the user ID.' );
$this->assertSame( '123456', $filter_args['auth_code'], 'Filter should receive the auth code.' );
}

public function test_api_send_auth_email_proceeds_normally_when_filter_returns_falsy(): void {
Jetpack_Options::delete_option( 'id' );
$sut = new Email_Service();
$user = new \WP_User();
$user->ID = 1;

$callback = function () {
return false;
};

add_filter( 'jetpack_account_protection_send_auth_email', $callback, 10, 4 );

$result = $sut->api_send_auth_email( $user->ID, '123456' );

remove_filter( 'jetpack_account_protection_send_auth_email', $callback, 10 );

// Should continue to the normal flow and fail because blog_id is not set
$this->assertInstanceOf( \WP_Error::class, $result );
$this->assertEquals( 'jetpack_connection_error', $result->get_error_code() );
}

public function test_api_send_auth_email_returns_error_if_blog_id_not_available(): void {
Jetpack_Options::delete_option( 'id' );
$sut = new Email_Service();
Expand Down