v1.0.0
This commit is contained in:
parent
3291a5f7d2
commit
212d64abfa
27 changed files with 8654 additions and 2 deletions
414
includes/class-rest-api.php
Normal file
414
includes/class-rest-api.php
Normal file
|
|
@ -0,0 +1,414 @@
|
|||
<?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
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue