414 lines
9.8 KiB
PHP
414 lines
9.8 KiB
PHP
<?php
|
|
/**
|
|
* REST API endpoints
|
|
*
|
|
* @package TwoFactorExtended
|
|
* @since 0.1.0
|
|
*/
|
|
|
|
// Prevent direct access.
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Class Two_Factor_Extended_REST_API
|
|
*
|
|
* Provides REST API endpoints for Two Factor Extended.
|
|
*
|
|
* @since 0.1.0
|
|
*/
|
|
class Two_Factor_Extended_REST_API {
|
|
|
|
/**
|
|
* API namespace.
|
|
*
|
|
* @since 0.1.0
|
|
* @var string
|
|
*/
|
|
const NAMESPACE = 'two-factor-extended/v1';
|
|
|
|
/**
|
|
* Constructor.
|
|
*
|
|
* @since 0.1.0
|
|
*/
|
|
public function __construct() {
|
|
$this->init_hooks();
|
|
}
|
|
|
|
/**
|
|
* Initialize WordPress hooks.
|
|
*
|
|
* @since 0.1.0
|
|
*/
|
|
private function init_hooks(): void {
|
|
add_action( 'rest_api_init', array( $this, 'register_routes' ) );
|
|
}
|
|
|
|
/**
|
|
* Register REST API routes.
|
|
*
|
|
* @since 0.1.0
|
|
*/
|
|
public function register_routes(): void {
|
|
// GET /two-factor-extended/v1/status.
|
|
register_rest_route(
|
|
self::NAMESPACE,
|
|
'/status',
|
|
array(
|
|
'methods' => WP_REST_Server::READABLE,
|
|
'callback' => array( $this, 'get_status' ),
|
|
'permission_callback' => array( $this, 'check_manage_options_permission' ),
|
|
'args' => array(
|
|
'role' => array(
|
|
'type' => 'string',
|
|
'sanitize_callback' => 'sanitize_key',
|
|
'default' => '',
|
|
),
|
|
),
|
|
)
|
|
);
|
|
|
|
// GET /two-factor-extended/v1/users.
|
|
register_rest_route(
|
|
self::NAMESPACE,
|
|
'/users',
|
|
array(
|
|
'methods' => WP_REST_Server::READABLE,
|
|
'callback' => array( $this, 'get_users' ),
|
|
'permission_callback' => array( $this, 'check_manage_options_permission' ),
|
|
'args' => array(
|
|
'role' => array(
|
|
'type' => 'string',
|
|
'sanitize_callback' => 'sanitize_key',
|
|
'default' => '',
|
|
),
|
|
'non_compliant_only' => array(
|
|
'type' => 'boolean',
|
|
'default' => false,
|
|
),
|
|
),
|
|
)
|
|
);
|
|
|
|
// POST /two-factor-extended/v1/enforce.
|
|
register_rest_route(
|
|
self::NAMESPACE,
|
|
'/enforce',
|
|
array(
|
|
'methods' => WP_REST_Server::CREATABLE,
|
|
'callback' => array( $this, 'enforce_requirements' ),
|
|
'permission_callback' => array( $this, 'check_manage_options_permission' ),
|
|
'args' => array(
|
|
'user_ids' => array(
|
|
'type' => 'array',
|
|
'required' => true,
|
|
'items' => array(
|
|
'type' => 'integer',
|
|
),
|
|
),
|
|
'reset_grace' => array(
|
|
'type' => 'boolean',
|
|
'default' => false,
|
|
),
|
|
),
|
|
)
|
|
);
|
|
|
|
// POST /two-factor-extended/v1/reset.
|
|
register_rest_route(
|
|
self::NAMESPACE,
|
|
'/reset',
|
|
array(
|
|
'methods' => WP_REST_Server::CREATABLE,
|
|
'callback' => array( $this, 'reset_grace_period' ),
|
|
'permission_callback' => array( $this, 'check_manage_options_permission' ),
|
|
'args' => array(
|
|
'user_ids' => array(
|
|
'type' => 'array',
|
|
'required' => true,
|
|
'items' => array(
|
|
'type' => 'integer',
|
|
),
|
|
),
|
|
),
|
|
)
|
|
);
|
|
|
|
// GET /two-factor-extended/v1/report.
|
|
register_rest_route(
|
|
self::NAMESPACE,
|
|
'/report',
|
|
array(
|
|
'methods' => WP_REST_Server::READABLE,
|
|
'callback' => array( $this, 'get_report' ),
|
|
'permission_callback' => array( $this, 'check_manage_options_permission' ),
|
|
'args' => array(
|
|
'role' => array(
|
|
'type' => 'string',
|
|
'sanitize_callback' => 'sanitize_key',
|
|
'default' => '',
|
|
),
|
|
'format' => array(
|
|
'type' => 'string',
|
|
'enum' => array( 'json', 'csv' ),
|
|
'default' => 'json',
|
|
),
|
|
),
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Check if user has manage_options permission.
|
|
*
|
|
* @since 0.1.0
|
|
*
|
|
* @return bool True if user has permission.
|
|
*/
|
|
public function check_manage_options_permission(): bool {
|
|
return current_user_can( 'manage_options' );
|
|
}
|
|
|
|
/**
|
|
* Get compliance status.
|
|
*
|
|
* @since 0.1.0
|
|
*
|
|
* @param WP_REST_Request $request Request object.
|
|
*
|
|
* @return WP_REST_Response Response object.
|
|
*/
|
|
public function get_status( WP_REST_Request $request ): WP_REST_Response {
|
|
try {
|
|
$role = $request->get_param( 'role' );
|
|
|
|
$compliance = two_factor_extended()->get_compliance_report();
|
|
$stats = $compliance->get_compliance_stats( array( 'role' => $role ) );
|
|
|
|
return new WP_REST_Response(
|
|
array(
|
|
'success' => true,
|
|
'data' => $stats,
|
|
),
|
|
200
|
|
);
|
|
} catch ( Exception $e ) {
|
|
return new WP_REST_Response(
|
|
array(
|
|
'success' => false,
|
|
'message' => __( 'Unable to retrieve compliance status.', 'two-factor-extended' ),
|
|
),
|
|
500
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get users list.
|
|
*
|
|
* @since 0.1.0
|
|
*
|
|
* @param WP_REST_Request $request Request object.
|
|
*
|
|
* @return WP_REST_Response Response object.
|
|
*/
|
|
public function get_users( WP_REST_Request $request ): WP_REST_Response {
|
|
$role = $request->get_param( 'role' );
|
|
$non_compliant_only = $request->get_param( 'non_compliant_only' );
|
|
|
|
$compliance = two_factor_extended()->get_compliance_report();
|
|
|
|
if ( $non_compliant_only ) {
|
|
$users = $compliance->get_non_compliant_users( array( 'role' => $role ) );
|
|
} else {
|
|
// Get all users with compliance status.
|
|
$user_args = array( 'fields' => 'all' );
|
|
|
|
if ( ! empty( $role ) ) {
|
|
$user_args['role'] = $role;
|
|
}
|
|
|
|
$all_users = get_users( $user_args );
|
|
$enforcement = two_factor_extended()->get_enforcement();
|
|
$users = array();
|
|
|
|
foreach ( $all_users as $user ) {
|
|
$required = $enforcement->get_required_providers_for_user( $user->ID );
|
|
|
|
$users[] = array(
|
|
'user_id' => $user->ID,
|
|
'user_login' => $user->user_login,
|
|
'user_email' => $user->user_email,
|
|
'roles' => Two_Factor_Extended_Role_Manager::get_user_roles( $user->ID ),
|
|
'compliant' => empty( $required ) || $enforcement->user_meets_requirements( $user->ID, $required ),
|
|
'in_grace' => $enforcement->is_in_grace_period( $user->ID ),
|
|
'grace_remaining' => $enforcement->get_grace_period_remaining_days( $user->ID ),
|
|
);
|
|
}
|
|
}
|
|
|
|
return new WP_REST_Response(
|
|
array(
|
|
'success' => true,
|
|
'data' => $users,
|
|
'total' => count( $users ),
|
|
),
|
|
200
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Enforce 2FA requirements.
|
|
*
|
|
* @since 0.1.0
|
|
*
|
|
* @param WP_REST_Request $request Request object.
|
|
*
|
|
* @return WP_REST_Response Response object.
|
|
*/
|
|
public function enforce_requirements( WP_REST_Request $request ): WP_REST_Response {
|
|
$user_ids = $request->get_param( 'user_ids' );
|
|
$reset_grace = $request->get_param( 'reset_grace' );
|
|
|
|
$enforcement = two_factor_extended()->get_enforcement();
|
|
$processed = 0;
|
|
$errors = array();
|
|
|
|
foreach ( $user_ids as $user_id ) {
|
|
$user = get_userdata( $user_id );
|
|
|
|
if ( ! $user ) {
|
|
$errors[] = sprintf( 'User not found: %d', $user_id );
|
|
continue;
|
|
}
|
|
|
|
$required = $enforcement->get_required_providers_for_user( $user_id );
|
|
|
|
if ( empty( $required ) ) {
|
|
$errors[] = sprintf( 'No 2FA requirements for user: %s', $user->user_login );
|
|
continue;
|
|
}
|
|
|
|
// Set enforcement start date.
|
|
update_user_meta( $user_id, Two_Factor_Extended_Enforcement::META_ENFORCEMENT_START, time() );
|
|
|
|
if ( $reset_grace ) {
|
|
delete_user_meta( $user_id, Two_Factor_Extended_Enforcement::META_GRACE_NOTIFIED );
|
|
}
|
|
|
|
// Log the action.
|
|
two_factor_extended()->get_audit_log()->log_event(
|
|
'api_enforce',
|
|
sprintf( 'REST API: Enforced 2FA for user %s', $user->user_login ),
|
|
$user_id,
|
|
array( 'required_providers' => $required )
|
|
);
|
|
|
|
$processed++;
|
|
}
|
|
|
|
return new WP_REST_Response(
|
|
array(
|
|
'success' => true,
|
|
'processed' => $processed,
|
|
'errors' => $errors,
|
|
),
|
|
200
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Reset grace period.
|
|
*
|
|
* @since 0.1.0
|
|
*
|
|
* @param WP_REST_Request $request Request object.
|
|
*
|
|
* @return WP_REST_Response Response object.
|
|
*/
|
|
public function reset_grace_period( WP_REST_Request $request ): WP_REST_Response {
|
|
$user_ids = $request->get_param( 'user_ids' );
|
|
$processed = 0;
|
|
$errors = array();
|
|
|
|
foreach ( $user_ids as $user_id ) {
|
|
$user = get_userdata( $user_id );
|
|
|
|
if ( ! $user ) {
|
|
$errors[] = sprintf( 'User not found: %d', $user_id );
|
|
continue;
|
|
}
|
|
|
|
// Reset enforcement start date.
|
|
update_user_meta( $user_id, Two_Factor_Extended_Enforcement::META_ENFORCEMENT_START, time() );
|
|
|
|
// Clear grace period notified flag.
|
|
delete_user_meta( $user_id, Two_Factor_Extended_Enforcement::META_GRACE_NOTIFIED );
|
|
|
|
// Log the action.
|
|
two_factor_extended()->get_audit_log()->log_event(
|
|
'api_reset_grace',
|
|
sprintf( 'REST API: Reset grace period for user %s', $user->user_login ),
|
|
$user_id
|
|
);
|
|
|
|
$processed++;
|
|
}
|
|
|
|
return new WP_REST_Response(
|
|
array(
|
|
'success' => true,
|
|
'processed' => $processed,
|
|
'errors' => $errors,
|
|
),
|
|
200
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Get compliance report.
|
|
*
|
|
* @since 0.1.0
|
|
*
|
|
* @param WP_REST_Request $request Request object.
|
|
*
|
|
* @return WP_REST_Response Response object.
|
|
*/
|
|
public function get_report( WP_REST_Request $request ): WP_REST_Response {
|
|
$role = $request->get_param( 'role' );
|
|
$format = $request->get_param( 'format' );
|
|
|
|
$compliance = two_factor_extended()->get_compliance_report();
|
|
|
|
if ( 'csv' === $format ) {
|
|
$csv = $compliance->export_to_csv( array( 'role' => $role ) );
|
|
|
|
return new WP_REST_Response(
|
|
array(
|
|
'success' => true,
|
|
'data' => $csv,
|
|
'format' => 'csv',
|
|
),
|
|
200,
|
|
array(
|
|
'Content-Type' => 'text/csv',
|
|
)
|
|
);
|
|
}
|
|
|
|
// JSON format.
|
|
$non_compliant = $compliance->get_non_compliant_users( array( 'role' => $role ) );
|
|
$stats = $compliance->get_compliance_stats( array( 'role' => $role ) );
|
|
|
|
return new WP_REST_Response(
|
|
array(
|
|
'success' => true,
|
|
'statistics' => $stats,
|
|
'non_compliant' => $non_compliant,
|
|
),
|
|
200
|
|
);
|
|
}
|
|
}
|