Making WordPress.org

Changeset 14729


Ignore:
Timestamp:
03/19/2026 01:45:06 PM (10 days ago)
Author:
obenland
Message:

WP.org Abilities: Improve input validation and add return type declarations.

Location:
sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-abilities/plugins/plugin-directory
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-abilities/plugins/plugin-directory/prompts/class-address-review-feedback.php

    r14725 r14729  
    5555    public static function execute( array $input ): array {
    5656        // Defensive fallback — input_schema marks plugin_slug as required but the framework may not enforce it.
    57         $plugin_slug = $input['plugin_slug'] ?? '{plugin_slug}';
     57        $plugin_slug = sanitize_title( $input['plugin_slug'] ?? '{plugin_slug}' );
    5858
    5959        $text = <<<MD
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-abilities/plugins/plugin-directory/prompts/class-prepare-plugin.php

    r14725 r14729  
    5555    public static function execute( array $input ): array {
    5656        // Defensive fallback — input_schema marks plugin_path as required but the framework may not enforce it.
    57         $plugin_path = $input['plugin_path'] ?? '{plugin_path}';
     57        $plugin_path = sanitize_text_field( $input['plugin_path'] ?? '{plugin_path}' );
    5858
    5959        $text = <<<MD
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-abilities/plugins/plugin-directory/prompts/class-run-plugin-check.php

    r14703 r14729  
    5555    public static function execute( array $input ): array {
    5656        // Defensive fallback — input_schema marks plugin_path as required but the framework may not enforce it.
    57         $plugin_path = $input['plugin_path'] ?? '{plugin_path}';
     57        $plugin_path = sanitize_text_field( $input['plugin_path'] ?? '{plugin_path}' );
    5858
    5959        $text = <<<MD
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-abilities/plugins/plugin-directory/tools/class-get-plugin-status.php

    r14715 r14729  
    123123     * @return true|\WP_Error
    124124     */
    125     public static function check_permission() {
     125    public static function check_permission(): bool|\WP_Error {
    126126        if ( get_current_user_id() > 0 ) {
    127127            return true;
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-abilities/plugins/plugin-directory/tools/class-submit-plugin.php

    r14725 r14729  
    166166     * @return true|\WP_Error
    167167     */
    168     public static function check_permission() {
     168    public static function check_permission(): bool|\WP_Error {
    169169        if ( get_current_user_id() > 0 ) {
    170170            return true;
     
    243243        );
    244244
    245         $_POST['comment'] = $input['comment'] ?? '';
     245        $_POST['comment'] = sanitize_text_field( $input['comment'] ?? '' );
    246246
    247247        if ( ! empty( $input['upload_token'] ) ) {
    248             $_REQUEST['upload_token'] = $input['upload_token'];
     248            $_REQUEST['upload_token'] = sanitize_text_field( $input['upload_token'] );
    249249        }
    250250
     
    358358     * @return string|array Temp file path on success, or error response array on failure.
    359359     */
    360     private static function prepare_zip_file( array $input ) {
     360    private static function prepare_zip_file( array $input ): array|string {
    361361        require_once ABSPATH . 'wp-admin/includes/file.php';
    362362
     
    382382     * @return string|array Temp file path on success, or error response array on failure.
    383383     */
    384     private static function prepare_zip_from_url( string $url ) {
     384    private static function prepare_zip_from_url( string $url ): array|string {
    385385        $url = esc_url_raw( $url );
    386386
     
    401401        }
    402402
    403         $temp_path = download_url( $url, 300 );
     403        // Do not allow link-local addresses.
     404        $host = wp_parse_url( $url, PHP_URL_HOST );
     405        if ( $host ) {
     406            $ip    = gethostbyname( $host );
     407            $parts = array_map( 'intval', explode( '.', $ip ) );
     408            if ( 169 === $parts[0] && 254 === $parts[1] ) {
     409                return self::error_response(
     410                    'invalid_url',
     411                    'The URL is not allowed.',
     412                    'Provide a publicly accessible HTTPS URL that does not point to an internal network address.'
     413                );
     414            }
     415        }
     416
     417        $temp_path = download_url( $url );
    404418        if ( is_wp_error( $temp_path ) ) {
    405419            return self::error_response(
     
    419433     * @return string|array Temp file path on success, or error response array on failure.
    420434     */
    421     private static function prepare_zip_from_base64( string $base64 ) {
     435    private static function prepare_zip_from_base64( string $base64 ): array|string {
     436        if ( strlen( $base64 ) > 64 * MB_IN_BYTES ) {
     437            return self::error_response(
     438                'zip_too_large',
     439                'The zip_base64 payload exceeds the 64 MB limit.',
     440                'Use zip_url instead for larger plugins.'
     441            );
     442        }
     443
    422444        $zip_data = base64_decode( $base64, true ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode -- Decoding a ZIP file, not obfuscated code.
    423445        if ( false === $zip_data ) {
     
    461483     */
    462484    private static function find_plugin_post( string $slug ): ?\WP_Post {
    463         $posts = get_posts(
    464             array(
    465                 'post_type'   => 'plugin',
    466                 'name'        => $slug,
    467                 'post_status' => 'any',
    468                 'numberposts' => 1,
    469             )
    470         );
    471 
    472         $post = $posts[0] ?? null;
    473 
    474         if ( ! $post ) {
    475             return null;
    476         }
    477 
    478         // Allow the plugin author or users with plugin_approve capability.
    479         if ( get_current_user_id() === (int) $post->post_author || current_user_can( 'plugin_approve' ) ) { // phpcs:ignore WordPress.WP.Capabilities.Unknown -- plugin_approve is registered by the plugin-directory plugin.
    480             return $post;
    481         }
    482 
    483         return null;
     485        $query_args = array(
     486            'post_type'   => 'plugin',
     487            'name'        => $slug,
     488            'post_status' => 'any',
     489            'numberposts' => 1,
     490        );
     491
     492        // Scope to the current user unless they can review plugins.
     493        if ( ! current_user_can( 'plugin_approve' ) ) { // phpcs:ignore WordPress.WP.Capabilities.Unknown -- plugin_approve is registered by the plugin-directory plugin.
     494            $query_args['author'] = get_current_user_id();
     495        }
     496
     497        $posts = get_posts( $query_args );
     498
     499        return $posts[0] ?? null;
    484500    }
    485501
Note: See TracChangeset for help on using the changeset viewer.