From 7a0a07d69156aba316d566f37dcdd498f59d138d Mon Sep 17 00:00:00 2001 From: johnjamesjacoby Date: Wed, 27 Oct 2021 15:00:01 +0000 Subject: [PATCH] Admin/HTTP API: add suggested filename support to `download_url()`. This change allows for external clients to supply a suggested filename via a `Content-Disposition` response header. This filename is processed through `sanitize_file_name()` to ensure it is allowable (on the server, MIME's, etc...) and `validate_file()` to prevent directory traversal. If the suggested filename fails the above processing/checks, that suggestion is discarded and the standard temporary filename (generated by WordPress) is used. If no `Content-Disposition` header is found in the response headers, the standard temporary filename continues to be used as per normal. Included in this change are 6 additional PHPUnit tests with 9 assertions. These tests confirm that valid filename values are correctly saved, and invalid filename values are correctly rejected. Props cklosows, costdev, dd32, johnjamesjacoby, ocean90, psrpinto. Fixes #38231. Built from https://develop.svn.wordpress.org/trunk@51939 git-svn-id: http://core.svn.wordpress.org/trunk@51528 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-admin/includes/file.php | 24 ++++++++++++++++++++++++ wp-includes/version.php | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/wp-admin/includes/file.php b/wp-admin/includes/file.php index 50345c6331..8a28c63adc 100644 --- a/wp-admin/includes/file.php +++ b/wp-admin/includes/file.php @@ -1112,6 +1112,7 @@ function wp_handle_sideload( &$file, $overrides = false, $time = null ) { * * @since 2.5.0 * @since 5.2.0 Signature Verification with SoftFail was added. + * @since 5.9.0 Support for Content-Disposition filename was added. * * @param string $url The URL of the file to download. * @param int $timeout The timeout for the request to download the file. @@ -1182,6 +1183,29 @@ function download_url( $url, $timeout = 300, $signature_verification = false ) { return new WP_Error( 'http_404', trim( wp_remote_retrieve_response_message( $response ) ), $data ); } + $content_disposition = wp_remote_retrieve_header( $response, 'content-disposition' ); + + if ( $content_disposition ) { + $content_disposition = strtolower( $content_disposition ); + + if ( 0 === strpos( $content_disposition, 'attachment; filename=' ) ) { + $tmpfname_disposition = sanitize_file_name( substr( $content_disposition, 21 ) ); + } else { + $tmpfname_disposition = ''; + } + + // Potential file name must be valid string + if ( $tmpfname_disposition && is_string( $tmpfname_disposition ) && ( 0 === validate_file( $tmpfname_disposition ) ) ) { + if ( rename( $tmpfname, $tmpfname_disposition ) ) { + $tmpfname = $tmpfname_disposition; + } + + if ( ( $tmpfname !== $tmpfname_disposition ) && file_exists( $tmpfname_disposition ) ) { + unlink( $tmpfname_disposition ); + } + } + } + $content_md5 = wp_remote_retrieve_header( $response, 'content-md5' ); if ( $content_md5 ) { diff --git a/wp-includes/version.php b/wp-includes/version.php index 8a11ab892a..e4bb7c3566 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -16,7 +16,7 @@ * * @global string $wp_version */ -$wp_version = '5.9-alpha-51938'; +$wp_version = '5.9-alpha-51939'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.