consent(); $this->identity( $version, $locale ); $key = 'antivirus_ai_ref_' . hash( 'sha256', $version . '|' . $locale ); $cached = get_option( $key, array() ); if ( is_array( $cached ) && is_int( $cached['fetched'] ?? null ) && $cached['fetched'] <= time() && time() - $cached['fetched'] < 86400 && is_array( $cached['metadata'] ?? null ) && ( $cached['metadata']['version'] ?? '' ) === $version && ( $cached['metadata']['locale'] ?? '' ) === $locale ) { try { $hashes = $this->validatedChecksums( $cached['checksums'] ?? null ); $this->meta = $cached['metadata']; return $hashes; } catch ( \RuntimeException $error ) { // A stale or malformed cache cannot become a trusted scan or repair baseline. // Refresh through the same bounded authenticated source as an empty cache. } } $url = 'https://api.wordpress.org/core/checksums/1.0/?version=' . rawurlencode( $version ) . '&locale=' . rawurlencode( $locale ); // Fixed official origin and validated identity; no user URL or redirects. Like core's // get_core_checksums, use the trusted-URL client (proxy-only hosts may lack local DNS). $response = wp_remote_get( $url, array( 'timeout' => 15, 'redirection' => 0, 'sslverify' => true, 'limit_response_size' => 2097152, 'user-agent' => 'Shieldlume Security/0.1', ) ); if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) { // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped -- Exception text is internal data, not HTML output; UI consumers escape at their output context. Escaping here would corrupt JSON/plain-text evidence and chained exception arguments. throw new \RuntimeException( 'Trusted core checksums unavailable (' . ( is_wp_error( $response ) ? $response->get_error_code() : (string) wp_remote_retrieve_response_code( $response ) ) . '); no clean or infected verdict inferred.' ); } $body = wp_remote_retrieve_body( $response ); if ( ! is_string( $body ) || strlen( $body ) >= 2097152 ) { throw new \RuntimeException( 'Trusted core manifest exceeded the response budget.' ); } $data = json_decode( $body, true, 16, JSON_THROW_ON_ERROR ); $data['checksums'] = $this->validatedChecksums( $data['checksums'] ?? null ); $this->meta = array( 'provider' => 'WordPress.org', 'url' => $url, 'fetched_at' => gmdate( 'c' ), 'transport' => 'HTTPS certificate validation; redirects disabled', 'reference_hash' => 'MD5 supplied by WordPress.org; correspondence is not a safety guarantee', 'version' => $version, 'locale' => $locale, 'expires_at' => gmdate( 'c', time() + 86400 ), ); update_option( $key, array( 'checksums' => $data['checksums'], 'fetched' => time(), 'metadata' => $this->meta, ), false ); return $data['checksums']; } private function validatedChecksums( $hashes ): array { if ( ! is_array( $hashes ) || ! $hashes || count( $hashes ) > 20000 ) { throw new \RuntimeException( 'Invalid checksum manifest.' ); } foreach ( $hashes as $path => $md5 ) { PathGuard::relative( (string) $path ); if ( ! is_string( $md5 ) || ! preg_match( '/^[a-f0-9]{32}$/D', $md5 ) ) { throw new \RuntimeException( 'Invalid reference hash.' ); } } return $hashes; } public function metadata(): array { return $this->meta; } }