false, 'error' => 'Invalid request']); } /** * Handles plugin enable/disable operations with security validation * * @return array Response array with success status and details * @throws InvalidArgumentException When input parameters are invalid * @throws SecurityException When security validation fails * @throws FileNotFoundException When plugin files are not found */ function handlePluginChange() { try { // Validate required input parameters if (!isset($_GET['id']) || !isset($_GET['status'])) { throw new InvalidArgumentException('Missing required parameters'); } $pluginFile = $_GET['id']; $pluginStatus = $_GET['status']; // Validate plugin file format (alphanumeric, underscore, hyphen + .php extension) if (!preg_match('/^[a-zA-Z0-9_-]+\.php$/', $pluginFile)) { throw new InvalidArgumentException('Invalid plugin file format'); } // Validate status parameter (only '0' or '1' allowed) if (!in_array($pluginStatus, ['0', '1'], true)) { throw new InvalidArgumentException('Invalid plugin status'); } // Sanitize plugin name by removing directory components and extension $pluginName = basename(str_replace(".php", "", $pluginFile)); // Additional validation for plugin name format if (!preg_match('/^[a-zA-Z0-9_-]+$/', $pluginName)) { throw new InvalidArgumentException('Invalid plugin name format'); } // Secure path validation to prevent directory traversal attacks $pluginFilePath = realpath(PATH_PLUGINS . $pluginFile); $pluginDirPath = realpath(PATH_PLUGINS . $pluginName); $pluginsDir = realpath(PATH_PLUGINS); // Ensure plugin file is within the allowed plugins directory if (!$pluginFilePath || strpos($pluginFilePath, $pluginsDir) !== 0) { throw new SecurityException('Plugin file outside allowed directory'); } // Verify plugin file exists if (!is_file($pluginFilePath)) { throw new FileNotFoundException('Plugin file not found'); } // Get plugin registry singleton instance $oPluginRegistry = PluginRegistry::loadSingleton(); if ($pluginStatus === '1') { // Disable plugin operation $details = $oPluginRegistry->getPluginDetails($pluginFile); if ($details) { $oPluginRegistry->disablePlugin($details->getNamespace()); $oPluginRegistry->savePlugin($details->getNamespace()); G::auditLog("DisablePlugin", "Plugin Name: " . $details->getNamespace()); return ['success' => true, 'action' => 'disabled', 'plugin' => $details->getNamespace()]; } } else { // Enable plugin operation if ($pluginDirPath && is_dir($pluginDirPath)) { // Safely include the validated plugin file require_once($pluginFilePath); $details = $oPluginRegistry->getPluginDetails($pluginFile); if ($details) { $oPluginRegistry->enablePlugin($details->getNamespace()); $oPluginRegistry->setupPlugins(); // Initialize all enabled plugins $oPluginRegistry->savePlugin($details->getNamespace()); G::auditLog("EnablePlugin", "Plugin Name: " . $details->getNamespace()); return ['success' => true, 'action' => 'enabled', 'plugin' => $details->getNamespace()]; } } else { throw new FileNotFoundException('Plugin directory not found'); } } // Fallback response if no operation was performed return ['success' => false, 'error' => 'Plugin operation failed']; } catch (Exception $e) { // Log error and return failure response G::auditLog('PluginChange', 'Error: ' . $e->getMessage()); return ['success' => false, 'error' => $e->getMessage()]; } }