*/ public function modify_index( $response, $request ) { if ( $request['namespace'] !== 'ithemes-security/v1' ) { return $response; } if ( ITSEC_Core::current_user_can_manage() || current_user_can( 'create_users' ) || current_user_can( 'edit_users' ) || current_user_can( 'promote_users' ) ) { $roles = []; foreach ( wp_roles()->get_names() as $role => $label ) { $roles[ $role ] = [ 'label' => translate_user_role( $label ), 'canonical' => ITSEC_Lib_Canonical_Roles::get_canonical_role_from_role( $role ), ]; } $response->data['roles'] = $roles; } if ( ITSEC_Core::current_user_can_manage() ) { $response->data['requirements_info'] = ITSEC_Lib::get_requirements_info(); $response->data['server_type'] = ITSEC_LIB::get_server(); $response->data['install_type'] = ITSEC_Core::get_install_type(); $response->data['has_patchstack'] = ITSEC_Core::has_patchstack(); $response->data['is_lw_customer'] = ITSEC_Core::licensed_user_is_lw_customer(); } $response->data['supports'] = apply_filters( 'itsec_rest_supports', [] ); return $response; } /** * Registers the "itsec_global" query parameter for the users endpoint. * * @param array $params * * @return array */ public function register_global_users_query( $params ) { if ( is_multisite() ) { $params['itsec_global'] = [ 'description' => __( 'Return results for users across the entire network, not just the current site.', 'better-wp-security' ), 'type' => 'boolean', 'default' => false, ]; } return $params; } /** * Applies the "itsec_global" query parameter. * * @param array $prepared_args * @param WP_REST_Request $request * * @return array */ public function apply_global_users_query( $prepared_args, $request ) { if ( is_multisite() && $request['itsec_global'] && current_user_can( 'manage_network_users' ) ) { $prepared_args['blog_id'] = null; } return $prepared_args; } /** * Retain the authorization header when doing internal embed requests. * * @param WP_REST_Request $request * * @return WP_REST_Request */ public function retain_auth_header_from_embeds( $request ) { $headers = rest_get_server()->get_headers( $_SERVER ); if ( isset( $headers['AUTHORIZATION'] ) && 0 === strpos( $request->get_route(), '/ithemes-security/v1/' ) ) { $request->add_header( 'Authorization', $headers['AUTHORIZATION'] ); } return $request; } /** * Adds larger avatar sizes to the REST API responses. * * @param int[] $sizes The existing sizes. * * @return array */ public function add_avatar_size( $sizes ) { $sizes[] = 128; return $sizes; } /** * Adds the HTTP 1.0 compat header to the list of CORS request headers. * * @param array $headers * * @return array */ public function add_allowed_cors_headers( $headers ) { if ( ! in_array( 'X-HTTP-Method-Override', $headers, true ) ) { $headers[] = 'X-HTTP-Method-Override'; } return $headers; } /** * Discovers the REST API for a given host. * * @param WP_REST_Request $request * * @return WP_REST_Response|WP_Error */ public function discover( WP_REST_Request $request ) { $head = wp_safe_remote_head( $request['url'], [ 'redirection' => 5, ] ); if ( is_wp_error( $head ) ) { return new WP_Error( 'itsec.discover.cannot-connect', wp_sprintf( __( 'Cannot connect to site: %l.', 'better-wp-security' ), ITSEC_Lib::get_error_strings( $head ) ), [ 'status' => WP_Http::INTERNAL_SERVER_ERROR ] ); } $header = wp_remote_retrieve_header( $head, 'Link' ); if ( ! $header ) { return new WP_Error( 'itsec.discover.missing-link-header', __( 'No Link header was found.', 'better-wp-security' ), [ 'status' => WP_Http::BAD_REQUEST ] ); } $rest_url = ''; $parsed = ITSEC_Lib::parse_header_with_attributes( $header ); foreach ( $parsed as $url => $attributes ) { foreach ( $attributes as $attribute => $value ) { if ( 'rel' === $attribute && 'https://api.w.org/' === $value ) { $rest_url = $url; break 2; } } } if ( ! $rest_url ) { return new WP_Error( 'itsec.discover.invalid-link-header', __( 'Could not find a REST API URL in the Link header.', 'better-wp-security' ), [ 'status' => WP_Http::BAD_REQUEST ] ); } $index = wp_safe_remote_get( add_query_arg( [ '_fields' => 'name,description,url,home,namespaces,authentication,_links,_embedded', '_embed' => 'wp:featuredmedia', ], $rest_url ) ); if ( is_wp_error( $index ) ) { return new WP_Error( 'itsec.discover.index.cannot-connect', wp_sprintf( __( 'Cannot connect to index: %l.', 'better-wp-security' ), ITSEC_Lib::get_error_strings( $index ) ), [ 'status' => WP_Http::INTERNAL_SERVER_ERROR ] ); } $status = wp_remote_retrieve_response_code( $index ); if ( $status !== 200 ) { return new WP_Error( 'itsec.discover.index.non-200', sprintf( __( 'REST API index returned a non-200 status code (%d).', 'better-wp-security' ), $status ), [ 'status' => WP_Http::BAD_REQUEST ] ); } $body = wp_remote_retrieve_body( $index ); if ( ! $body || ! $data = json_decode( $body, true ) ) { return new WP_Error( 'itsec.discover.index.empty', __( 'REST API index returned no data.', 'better-wp-security' ), [ 'status' => WP_HTTP::BAD_REQUEST ] ); } $itsec_index = wp_safe_remote_get( ITSEC_Lib_REST::rest_url( $rest_url, 'ithemes-security/v1' ) ); if ( is_wp_error( $itsec_index ) ) { return new WP_Error( 'itsec.discover.itsec-index-cannot-connect', wp_sprintf( __( 'Cannot connect to index: %l.', 'better-wp-security' ), ITSEC_Lib::get_error_strings( $itsec_index ) ), [ 'status' => WP_Http::INTERNAL_SERVER_ERROR ] ); } $status = wp_remote_retrieve_response_code( $itsec_index ); if ( $status !== 200 ) { return new WP_Error( 'itsec.discover.itsec-index.non-200', sprintf( __( 'Solid Security REST API index returned a non-200 status code (%d).', 'better-wp-security' ), $status ), [ 'status' => WP_Http::BAD_REQUEST ] ); } $body = wp_remote_retrieve_body( $itsec_index ); if ( ! $body || ! $itsec_data = json_decode( $body, true ) ) { return new WP_Error( 'itsec.discover.itsec-index.empty', __( 'Solid Security REST API index returned no data.', 'better-wp-security' ), [ 'status' => WP_HTTP::BAD_REQUEST ] ); } return new WP_REST_Response( [ 'url' => $rest_url, 'index' => $data, 'itsec' => $itsec_data, ] ); } public function add_htaccess_authorization_header( $rules ) { $rules .= "\n"; $rules .= "\t# " . __( 'Pass through Authorization header.', 'better-wp-security' ) . "\n"; $rules .= <<<'APACHE' RewriteEngine On RewriteCond %{HTTP:Authorization} ^(.*) RewriteRule .* - [e=HTTP_AUTHORIZATION:%1] APACHE; $rules .= "\n"; return $rules; } }