400 ] ); } $sums = self::checksums(); if ( empty( $sums[ $file ] ) ) { return new \WP_Error( 'gemsecurity_core_file', __( 'That file is not part of this WordPress release.', 'gemsecurity' ), [ 'status' => 400 ] ); } return [ 'file' => $file, 'path' => \GemSecurity\Paths::root() . $file, 'sum' => $sums[ $file ] ]; } /** @return array */ private static function checksums() { if ( ! function_exists( 'get_core_checksums' ) ) { require_once ABSPATH . 'wp-admin/includes/update.php'; } $version = get_bloginfo( 'version' ); $sums = get_core_checksums( $version, get_locale() ); if ( empty( $sums ) || ! is_array( $sums ) ) { $sums = get_core_checksums( $version, 'en_US' ); } return is_array( $sums ) ? $sums : []; } /** * Everything the popup needs. * * @param string $file * @return array|\WP_Error */ public static function inspect( $file ) { $r = self::resolve( $file ); if ( is_wp_error( $r ) ) { return $r; } $current = ''; $exists = is_file( $r['path'] ); if ( $exists ) { if ( filesize( $r['path'] ) > self::MAX_BYTES ) { return new \WP_Error( 'gemsecurity_core_file', __( 'This file is too large to show here.', 'gemsecurity' ), [ 'status' => 413 ] ); } $fs = self::fs(); $current = $fs ? (string) $fs->get_contents( $r['path'] ) : ''; } $original = self::original( $r ); return [ 'file' => $r['file'], 'version' => get_bloginfo( 'version' ), 'exists' => $exists, 'current' => $current, 'original' => is_wp_error( $original ) ? '' : $original, 'original_error' => is_wp_error( $original ) ? $original->get_error_message() : '', ]; } /** * @param array $r Result of resolve(). * @return string|\WP_Error */ private static function original( array $r ) { $key = 'gemsec_core_' . md5( get_bloginfo( 'version' ) . $r['file'] ); $cached = get_transient( $key ); if ( is_string( $cached ) ) { return $cached; } $url = 'https://core.svn.wordpress.org/tags/' . rawurlencode( get_bloginfo( 'version' ) ) . '/' . implode( '/', array_map( 'rawurlencode', explode( '/', $r['file'] ) ) ); $res = wp_remote_get( $url, [ 'timeout' => 15 ] ); if ( is_wp_error( $res ) || 200 !== (int) wp_remote_retrieve_response_code( $res ) ) { return new \WP_Error( 'gemsecurity_core_original', __( 'Could not download the original file from WordPress.org.', 'gemsecurity' ) ); } $body = (string) wp_remote_retrieve_body( $res ); if ( md5( $body ) !== $r['sum'] ) { return new \WP_Error( 'gemsecurity_core_original', __( 'The downloaded file did not match the official checksum, so it was discarded.', 'gemsecurity' ) ); } set_transient( $key, $body, HOUR_IN_SECONDS ); return $body; } }