rest_authorization_required_code() ) ); } return true; } /** * Register routes. */ public static function routes() { $id_arg = array( 'id' => array( 'type' => 'integer', 'required' => true, 'minimum' => 1, 'sanitize_callback' => 'absint', ), ); register_rest_route( self::NS, '/status', array( 'methods' => 'GET', 'callback' => array( __CLASS__, 'status' ), 'permission_callback' => array( __CLASS__, 'permission' ), ) ); register_rest_route( self::NS, '/scans', array( 'methods' => 'POST', 'callback' => array( __CLASS__, 'start' ), 'permission_callback' => array( __CLASS__, 'permission' ), 'args' => array( 'type' => array( 'type' => 'string', 'enum' => Scanner::TYPES, 'required' => true, ), ), ) ); register_rest_route( self::NS, '/scans/(?P\d+)/(?Ppause|resume|cancel|retry)', array( 'methods' => 'POST', 'callback' => array( __CLASS__, 'control' ), 'permission_callback' => array( __CLASS__, 'permission' ), 'args' => $id_arg, ) ); register_rest_route( self::NS, '/scans/(?P\d+)/tick', array( 'methods' => 'POST', 'callback' => array( __CLASS__, 'tick' ), 'permission_callback' => array( __CLASS__, 'permission' ), 'args' => $id_arg, ) ); register_rest_route( self::NS, '/scans/(?P\d+)', array( 'methods' => 'DELETE', 'callback' => array( __CLASS__, 'delete' ), 'permission_callback' => array( __CLASS__, 'permission' ), 'args' => $id_arg, ) ); register_rest_route( self::NS, '/findings/(?P[a-f0-9]{40})/(?Pignore|unignore)', array( 'methods' => 'POST', 'callback' => array( __CLASS__, 'ignore' ), 'permission_callback' => array( __CLASS__, 'permission' ), ) ); register_rest_route( self::NS, '/health/refresh', array( 'methods' => 'POST', 'callback' => array( __CLASS__, 'health' ), 'permission_callback' => array( __CLASS__, 'permission' ), ) ); register_rest_route( self::NS, '/plugins/directory', array( 'methods' => 'POST', 'callback' => array( __CLASS__, 'directory' ), 'permission_callback' => array( __CLASS__, 'permission' ), ) ); register_rest_route( self::NS, '/logins', array( 'methods' => 'DELETE', 'callback' => array( __CLASS__, 'clear_logins' ), 'permission_callback' => array( __CLASS__, 'permission' ), ) ); register_rest_route( self::NS, '/notifications/test', array( 'methods' => 'POST', 'callback' => array( __CLASS__, 'test_mail' ), 'permission_callback' => array( __CLASS__, 'permission' ), ) ); } /** * Convert WP_Error to a REST error with a 400/409 status. * * @param \WP_Error $error Error. * @return \WP_Error */ private static function error( $error ) { $status = in_array( $error->get_error_code(), array( 'siteaudithub_active', 'siteaudithub_busy', 'siteaudithub_state' ), true ) ? 409 : ( 'siteaudithub_not_found' === $error->get_error_code() ? 404 : 400 ); $data = $error->get_error_data(); return new \WP_Error( $error->get_error_code(), $error->get_error_message(), array_merge( is_array( $data ) ? $data : array(), array( 'status' => $status ) ) ); } /** * Active scans status. * * @return \WP_REST_Response */ public static function status() { $out = array(); foreach ( Scanner::TYPES as $type ) { $active = Repository::active_scan( $type ); $out[ $type ] = $active ? Scanner::status_payload( $active ) : null; } return rest_ensure_response( $out ); } /** * Start a scan. * * @param \WP_REST_Request $request Request. * @return \WP_REST_Response|\WP_Error */ public static function start( $request ) { $id = Scanner::start( $request['type'], 'manual' ); if ( is_wp_error( $id ) ) { return self::error( $id ); } return rest_ensure_response( Scanner::status_payload( Repository::get_scan( $id ) ) ); } /** * Pause/resume/cancel/retry. * * @param \WP_REST_Request $request Request. * @return \WP_REST_Response|\WP_Error */ public static function control( $request ) { $result = Scanner::control( (int) $request['id'], (string) $request['action'] ); if ( is_wp_error( $result ) ) { return self::error( $result ); } return rest_ensure_response( Scanner::status_payload( Repository::get_scan( (int) $request['id'] ) ) ); } /** * Browser-driven processing step. * * @param \WP_REST_Request $request Request. * @return \WP_REST_Response */ public static function tick( $request ) { $budget = min( 15, (int) Settings::get( 'time_budget' ) ); return rest_ensure_response( Scanner::tick( (int) $request['id'], $budget ) ); } /** * Delete a finished scan. * * @param \WP_REST_Request $request Request. * @return \WP_REST_Response|\WP_Error */ public static function delete( $request ) { $scan = Repository::get_scan( (int) $request['id'] ); if ( ! $scan ) { return self::error( new \WP_Error( 'siteaudithub_not_found', __( 'Scan not found.', 'siteaudithub' ) ) ); } if ( in_array( $scan->status, Repository::ACTIVE_STATUSES, true ) ) { return self::error( new \WP_Error( 'siteaudithub_state', __( 'Cancel the scan before deleting it.', 'siteaudithub' ) ) ); } Repository::delete_scan( $scan->id ); Logger::log( 'info', sprintf( 'Scan #%d deleted by user #%d.', $scan->id, get_current_user_id() ) ); return rest_ensure_response( array( 'deleted' => true ) ); } /** * Ignore / unignore a finding fingerprint. * * @param \WP_REST_Request $request Request. * @return \WP_REST_Response */ public static function ignore( $request ) { Repository::set_ignored( (string) $request['fp'], 'ignore' === $request['action'] ); return rest_ensure_response( array( 'ok' => true ) ); } /** * Re-run health checks (with loopback requests). * * @return \WP_REST_Response */ public static function health() { Health::run( true ); return rest_ensure_response( array( 'ok' => true ) ); } /** * Run directory lookups (opt-in setting must be enabled). * * @return \WP_REST_Response|\WP_Error */ public static function directory() { if ( ! (int) Settings::get( 'plugin_directory_lookup' ) ) { return self::error( new \WP_Error( 'siteaudithub_disabled', __( 'WordPress.org directory lookups are disabled in settings.', 'siteaudithub' ) ) ); } $remaining = Plugin_Monitor::refresh_directory( 8, microtime( true ) + 20 ); return rest_ensure_response( array( 'remaining' => $remaining ) ); } /** * Delete all login activity. * * @return \WP_REST_Response */ public static function clear_logins() { Login_Log::clear(); Logger::log( 'info', sprintf( 'Login activity cleared by user #%d.', get_current_user_id() ) ); return rest_ensure_response( array( 'ok' => true ) ); } /** * Send a test email. * * @return \WP_REST_Response */ public static function test_mail() { $ok = Notifications::test(); return rest_ensure_response( array( 'accepted' => $ok, 'recipients' => Settings::recipients(), ) ); } }