Update WordPress to 5.2

This commit is contained in:
Oliver Davies 2019-05-08 08:05:39 +01:00
parent 489b5a5914
commit e00f87f2f5
599 changed files with 119573 additions and 55990 deletions

View file

@ -36,6 +36,7 @@ $wp_file_descriptions = array(
'single.php' => __( 'Single Post' ),
'page.php' => __( 'Single Page' ),
'front-page.php' => __( 'Homepage' ),
'privacy-policy.php' => __( 'Privacy Policy Page' ),
// Attachments
'attachment.php' => __( 'Attachment Template' ),
'image.php' => __( 'Image Attachment Template' ),
@ -965,12 +966,14 @@ function wp_handle_sideload( &$file, $overrides = false, $time = null ) {
* Please note that the calling function must unlink() the file.
*
* @since 2.5.0
* @since 5.2.0 Signature Verification with SoftFail was added.
*
* @param string $url The URL of the file to download.
* @param int $timeout The timeout for the request to download the file. Default 300 seconds.
* @param string $url The URL of the file to download.
* @param int $timeout The timeout for the request to download the file. Default 300 seconds.
* @param bool $signature_verification Whether to perform Signature Verification. Default false.
* @return string|WP_Error Filename on success, WP_Error on failure.
*/
function download_url( $url, $timeout = 300 ) {
function download_url( $url, $timeout = 300, $signature_verification = false ) {
//WARNING: The file is not automatically deleted, The script must unlink() the file.
if ( ! $url ) {
return new WP_Error( 'http_no_url', __( 'Invalid URL Provided.' ) );
@ -1034,6 +1037,83 @@ function download_url( $url, $timeout = 300 ) {
}
}
// If the caller expects signature verification to occur, check to see if this URL supports it.
if ( $signature_verification ) {
/**
* Filters the list of hosts which should have Signature Verification attempteds on.
*
* @since 5.2.0
*
* @param array List of hostnames.
*/
$signed_hostnames = apply_filters( 'wp_signature_hosts', array( 'wordpress.org', 'downloads.wordpress.org', 's.w.org' ) );
$signature_verification = in_array( parse_url( $url, PHP_URL_HOST ), $signed_hostnames, true );
}
// Perform signature valiation if supported.
if ( $signature_verification ) {
$signature = wp_remote_retrieve_header( $response, 'x-content-signature' );
if ( ! $signature ) {
// Retrieve signatures from a file if the header wasn't included.
// WordPress.org stores signatures at $package_url.sig
$signature_url = false;
$url_path = parse_url( $url, PHP_URL_PATH );
if ( substr( $url_path, -4 ) == '.zip' || substr( $url_path, -7 ) == '.tar.gz' ) {
$signature_url = str_replace( $url_path, $url_path . '.sig', $url );
}
/**
* Filter the URL where the signature for a file is located.
*
* @since 5.2.0
*
* @param false|string $signature_url The URL where signatures can be found for a file, or false if none are known.
* @param string $url The URL being verified.
*/
$signature_url = apply_filters( 'wp_signature_url', $signature_url, $url );
if ( $signature_url ) {
$signature_request = wp_safe_remote_get(
$signature_url,
array(
'limit_response_size' => 10 * 1024, // 10KB should be large enough for quite a few signatures.
)
);
if ( ! is_wp_error( $signature_request ) && 200 === wp_remote_retrieve_response_code( $signature_request ) ) {
$signature = explode( "\n", wp_remote_retrieve_body( $signature_request ) );
}
}
}
// Perform the checks.
$signature_verification = verify_file_signature( $tmpfname, $signature, basename( parse_url( $url, PHP_URL_PATH ) ) );
}
if ( is_wp_error( $signature_verification ) ) {
if (
/**
* Filters whether Signature Verification failures should be allowed to soft fail.
*
* WARNING: This may be removed from a future release.
*
* @since 5.2.0
*
* @param bool $signature_softfail If a softfail is allowed.
* @param string $url The url being accessed.
*/
apply_filters( 'wp_signature_softfail', true, $url )
) {
$signature_verification->add_data( $tmpfname, 'softfail-filename' );
} else {
// Hard-fail.
unlink( $tmpfname );
}
return $signature_verification;
}
return $tmpfname;
}
@ -1066,6 +1146,155 @@ function verify_file_md5( $filename, $expected_md5 ) {
return new WP_Error( 'md5_mismatch', sprintf( __( 'The checksum of the file (%1$s) does not match the expected checksum value (%2$s).' ), bin2hex( $file_md5 ), bin2hex( $expected_raw_md5 ) ) );
}
/**
* Verifies the contents of a file against its ED25519 signature.
*
* @since 5.2.0
*
* @param string $filename The file to validate.
* @param string|array $signatures A Signature provided for the file.
* @param string $filename_for_errors A friendly filename for errors. Optional.
*
* @return bool|WP_Error true on success, false if verificaiton not attempted, or WP_Error describing an error condition.
*/
function verify_file_signature( $filename, $signatures, $filename_for_errors = false ) {
if ( ! $filename_for_errors ) {
$filename_for_errors = wp_basename( $filename );
}
// Check we can process signatures.
if ( ! function_exists( 'sodium_crypto_sign_verify_detached' ) || ! in_array( 'sha384', array_map( 'strtolower', hash_algos() ) ) ) {
return new WP_Error(
'signature_verification_unsupported',
sprintf(
/* translators: %s: The filename of the package. */
__( 'The authenticity of %s could not be verified as signature verification is unavailable on this system.' ),
'<span class="code">' . esc_html( $filename_for_errors ) . '</span>'
),
( ! function_exists( 'sodium_crypto_sign_verify_detached' ) ? 'sodium_crypto_sign_verify_detached' : 'sha384' )
);
}
// Check for a edge-case affecting PHP Maths abilities
if (
! extension_loaded( 'sodium' ) &&
in_array( PHP_VERSION_ID, [ 70200, 70201, 70202 ], true ) &&
extension_loaded( 'opcache' )
) {
// Sodium_Compat isn't compatible with PHP 7.2.0~7.2.2 due to a bug in the PHP Opcache extension, bail early as it'll fail.
// https://bugs.php.net/bug.php?id=75938
return new WP_Error(
'signature_verification_unsupported',
sprintf(
/* translators: 1: The filename of the package. */
__( 'The authenticity of %1$s could not be verified as signature verification is unavailable on this system.' ),
'<span class="code">' . esc_html( $filename_for_errors ) . '</span>'
),
array(
'php' => phpversion(),
'sodium' => defined( 'SODIUM_LIBRARY_VERSION' ) ? SODIUM_LIBRARY_VERSION : ( defined( 'ParagonIE_Sodium_Compat::VERSION_STRING' ) ? ParagonIE_Sodium_Compat::VERSION_STRING : false ),
)
);
}
if ( ! $signatures ) {
return new WP_Error(
'signature_verification_no_signature',
sprintf(
/* translators: %s: The filename of the package. */
__( 'The authenticity of %s could not be verified as no signature was found.' ),
'<span class="code">' . esc_html( $filename_for_errors ) . '</span>'
),
array(
'filename' => $filename_for_errors,
)
);
}
$trusted_keys = wp_trusted_keys();
$file_hash = hash_file( 'sha384', $filename, true );
mbstring_binary_safe_encoding();
$skipped_key = $skipped_signature = 0;
foreach ( (array) $signatures as $signature ) {
$signature_raw = base64_decode( $signature );
// Ensure only valid-length signatures are considered.
if ( SODIUM_CRYPTO_SIGN_BYTES !== strlen( $signature_raw ) ) {
$skipped_signature++;
continue;
}
foreach ( (array) $trusted_keys as $key ) {
$key_raw = base64_decode( $key );
// Only pass valid public keys through.
if ( SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES !== strlen( $key_raw ) ) {
$skipped_key++;
continue;
}
if ( sodium_crypto_sign_verify_detached( $signature_raw, $file_hash, $key_raw ) ) {
reset_mbstring_encoding();
return true;
}
}
}
reset_mbstring_encoding();
return new WP_Error(
'signature_verification_failed',
sprintf(
/* translators: %s: The filename of the package. */
__( 'The authenticity of %s could not be verified.' ),
'<span class="code">' . esc_html( $filename_for_errors ) . '</span>'
),
// Error data helpful for debugging:
array(
'filename' => $filename_for_errors,
'keys' => $trusted_keys,
'signatures' => $signatures,
'hash' => bin2hex( $file_hash ),
'skipped_key' => $skipped_key,
'skipped_sig' => $skipped_signature,
'php' => phpversion(),
'sodium' => defined( 'SODIUM_LIBRARY_VERSION' ) ? SODIUM_LIBRARY_VERSION : ( defined( 'ParagonIE_Sodium_Compat::VERSION_STRING' ) ? ParagonIE_Sodium_Compat::VERSION_STRING : false ),
)
);
}
/**
* Retrieve the list of signing keys trusted by WordPress.
*
* @since 5.2.0
*
* @return array List of base64-encoded Signing keys.
*/
function wp_trusted_keys() {
$trusted_keys = array();
if ( time() < 1617235200 ) {
// WordPress.org Key #1 - This key is only valid before April 1st, 2021.
$trusted_keys[] = 'fRPyrxb/MvVLbdsYi+OOEv4xc+Eqpsj+kkAS6gNOkI0=';
}
// TODO: Add key #2 with longer expiration.
/**
* Filter the valid Signing keys used to verify the contents of files.
*
* @since 5.2.0
*
* @param array $trusted_keys The trusted keys that may sign packages.
*/
return apply_filters( 'wp_trusted_keys', $trusted_keys );
}
/**
* Unzips a specified ZIP file to a location on the filesystem via the WordPress
* Filesystem Abstraction.
@ -1097,8 +1326,8 @@ function unzip_file( $file, $to ) {
$needed_dirs = array();
$to = trailingslashit( $to );
// Determine any parent dir's needed (of the upgrade directory)
if ( ! $wp_filesystem->is_dir( $to ) ) { //Only do parents if no children exist
// Determine any parent directories needed (of the upgrade directory).
if ( ! $wp_filesystem->is_dir( $to ) ) { // Only do parents if no children exist.
$path = preg_split( '![/\\\]!', untrailingslashit( $to ) );
for ( $i = count( $path ); $i >= 0; $i-- ) {
if ( empty( $path[ $i ] ) ) {
@ -1113,7 +1342,7 @@ function unzip_file( $file, $to ) {
if ( ! $wp_filesystem->is_dir( $dir ) ) {
$needed_dirs[] = $dir;
} else {
break; // A folder exists, therefor, we dont need the check the levels below this
break; // A folder exists, therefore we don't need to check the levels below this.
}
}
}
@ -1956,17 +2185,7 @@ function wp_print_request_filesystem_credentials_modal() {
* @return string The HTML for this group and its items.
*/
function wp_privacy_generate_personal_data_export_group_html( $group_data ) {
$allowed_tags = array(
'a' => array(
'href' => array(),
'target' => array(),
),
'br' => array(),
);
$allowed_protocols = array( 'http', 'https' );
$group_html = '';
$group_html .= '<h2>' . esc_html( $group_data['group_label'] ) . '</h2>';
$group_html = '<h2>' . esc_html( $group_data['group_label'] ) . '</h2>';
$group_html .= '<div>';
foreach ( (array) $group_data['items'] as $group_item_id => $group_item_data ) {
@ -1975,14 +2194,14 @@ function wp_privacy_generate_personal_data_export_group_html( $group_data ) {
foreach ( (array) $group_item_data as $group_item_datum ) {
$value = $group_item_datum['value'];
// If it looks like a link, make it a link
// If it looks like a link, make it a link.
if ( false === strpos( $value, ' ' ) && ( 0 === strpos( $value, 'http://' ) || 0 === strpos( $value, 'https://' ) ) ) {
$value = '<a href="' . esc_url( $value ) . '">' . esc_html( $value ) . '</a>';
}
$group_html .= '<tr>';
$group_html .= '<th>' . esc_html( $group_item_datum['name'] ) . '</th>';
$group_html .= '<td>' . wp_kses( $value, $allowed_tags, $allowed_protocols ) . '</td>';
$group_html .= '<td>' . wp_kses( $value, 'personal_data_export' ) . '</td>';
$group_html .= '</tr>';
}
@ -2051,7 +2270,7 @@ function wp_privacy_generate_personal_data_export_file( $request_id ) {
}
$title = sprintf(
/* translators: %s: user's e-mail address */
/* translators: %s: user's email address */
__( 'Personal Data Export for %s' ),
$email_address
);
@ -2197,6 +2416,15 @@ function wp_privacy_send_personal_data_export_email( $request_id ) {
return new WP_Error( 'invalid_request', __( 'Invalid request ID when sending personal data export email.' ) );
}
// Localize message content for user; fallback to site default for visitors.
if ( ! empty( $request->user_id ) ) {
$locale = get_user_locale( $request->user_id );
} else {
$locale = get_locale();
}
$switched_locale = switch_to_locale( $locale );
/** This filter is documented in wp-includes/functions.php */
$expiration = apply_filters( 'wp_privacy_export_expiration', 3 * DAY_IN_SECONDS );
$expiration_date = date_i18n( get_option( 'date_format' ), time() + $expiration );
@ -2247,12 +2475,17 @@ All at ###SITENAME###
$mail_success = wp_mail(
$email_address,
sprintf(
/* translators: Personal data export notification email subject. %s: Site title */
__( '[%s] Personal Data Export' ),
$site_name
),
$content
);
if ( $switched_locale ) {
restore_previous_locale();
}
if ( ! $mail_success ) {
return new WP_Error( 'privacy_email_error', __( 'Unable to send personal data export email.' ) );
}
@ -2370,6 +2603,9 @@ function wp_privacy_process_personal_data_export_page( $response, $exporter_inde
if ( is_wp_error( $mail_success ) ) {
wp_send_json_error( $mail_success->get_error_message() );
}
// Update the request to completed state when the export email is sent.
_wp_privacy_completed_request( $request_id );
} else {
// Modify the response to include the URL of the export file so the browser can fetch it.
$export_file_url = get_post_meta( $request_id, '_export_file_url', true );
@ -2378,8 +2614,5 @@ function wp_privacy_process_personal_data_export_page( $response, $exporter_inde
}
}
// Update the request to completed state.
_wp_privacy_completed_request( $request_id );
return $response;
}