From 8baec519d747ff667642954e377e510a24d05795 Mon Sep 17 00:00:00 2001 From: Ian Dunn Date: Mon, 6 Feb 2023 13:13:40 -0800 Subject: [PATCH] Convert Backup Codes AJAX to REST API --- class-two-factor-core.php | 42 ++++ providers/class-two-factor-backup-codes.php | 115 +++++++---- .../class-two-factor-backup-codes-ajax.php | 110 ---------- ...class-two-factor-backup-codes-rest-api.php | 193 ++++++++++++++++++ .../class-two-factor-backup-codes.php | 6 +- 5 files changed, 311 insertions(+), 155 deletions(-) delete mode 100644 tests/providers/class-two-factor-backup-codes-ajax.php create mode 100644 tests/providers/class-two-factor-backup-codes-rest-api.php diff --git a/class-two-factor-core.php b/class-two-factor-core.php index b70d619d..ee15420a 100644 --- a/class-two-factor-core.php +++ b/class-two-factor-core.php @@ -49,6 +49,13 @@ class Two_Factor_Core { */ const USER_SETTINGS_ACTION_NONCE_QUERY_ARG = '_two_factor_action_nonce'; + /** + * Namespace for plugin rest api endpoints. + * + * @var string + */ + const REST_NAMESPACE = 'two-factor/1.0'; + /** * Keep track of all the password-based authentication sessions that * need to invalidated before the second factor authentication. @@ -1076,6 +1083,41 @@ public static function user_two_factor_options( $user ) { do_action( 'show_user_security_settings', $user ); } + /** + * Enable a provider for a user. + * + * @param int $user_id The ID of the user. + * @param string $new_provider The name of the provider class. + * + * @return bool True if the provider was enabled, false otherwise. + */ + public static function enable_provider_for_user( $user_id, $new_provider ) { + $available_providers = self::get_providers(); + + if ( ! array_key_exists( $new_provider, $available_providers ) ) { + return false; + } + + $user = get_userdata( $user_id ); + $enabled_providers = self::get_enabled_providers_for_user( $user ); + + if ( in_array( $new_provider, $enabled_providers ) ) { + return true; + } + + $enabled_providers[] = $new_provider; + $enabled = update_user_meta( $user_id, self::ENABLED_PROVIDERS_USER_META_KEY, $enabled_providers ); + + // Primary provider must be enabled. + $has_primary = is_object( self::get_primary_provider_for_user( $user_id ) ); + + if ( ! $has_primary ) { + $has_primary = update_user_meta( $user_id, self::PROVIDER_USER_META_KEY, $new_provider ); + } + + return $enabled && $has_primary; + } + /** * Update the user meta value. * diff --git a/providers/class-two-factor-backup-codes.php b/providers/class-two-factor-backup-codes.php index 62707f2f..7a8da399 100644 --- a/providers/class-two-factor-backup-codes.php +++ b/providers/class-two-factor-backup-codes.php @@ -48,13 +48,49 @@ public static function get_instance() { * @since 0.1-dev */ protected function __construct() { + add_action( 'rest_api_init', array( $this, 'register_rest_routes' ) ); add_action( 'two_factor_user_options_' . __CLASS__, array( $this, 'user_options' ) ); add_action( 'admin_notices', array( $this, 'admin_notices' ) ); - add_action( 'wp_ajax_two_factor_backup_codes_generate', array( $this, 'ajax_generate_json' ) ); return parent::__construct(); } + /** + * Register the rest-api endpoints required for this provider. + */ + public function register_rest_routes() { + register_rest_route( + Two_Factor_Core::REST_NAMESPACE, + '/generate-backup-codes', + array( + 'methods' => WP_REST_Server::CREATABLE, + 'callback' => array( $this, 'rest_generate_codes' ), + 'permission_callback' => function( $request ) { + return current_user_can( 'edit_user', $request['user_id'] ); + }, + 'args' => array( + 'user_id' => array( + 'required' => true, + 'type' => 'number', + ), + 'number' => array( + 'type' => 'number', + 'default' => self::NUMBER_OF_CODES, + ), + 'append' => array( + 'type' => 'boolean', + 'default' => false, + ), + 'enable_provider' => array( + 'required' => false, + 'type' => 'boolean', + 'default' => false, + ), + ), + ) + ); + } + /** * Displays an admin notice when backup codes have run out. * @@ -125,8 +161,7 @@ public function is_available_for_user( $user ) { * @param WP_User $user WP_User object of the logged-in user. */ public function user_options( $user ) { - $ajax_nonce = wp_create_nonce( 'two-factor-backup-codes-generate-json-' . $user->ID ); - $count = self::codes_remaining_for_user( $user ); + $count = self::codes_remaining_for_user( $user ); ?>