false, 'error' => $message], $code); } // Check if IDE services are enabled $env_file = IDE_AUTH_BASE_PATH . '/.env'; if (file_exists($env_file)) { $env_content = file_get_contents($env_file); // Check if production if (preg_match('/^APP_ENV=production$/m', $env_content)) { // Check if explicitly enabled in production if (!preg_match('/^RSX_IDE_SERVICES_ENABLED=true$/m', $env_content)) { ide_auth_error_response('IDE services disabled in production', 403); } } } // Parse request URI to get service $request_uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); $service_path = str_replace('/_ide/service', '', $request_uri); $service_path = trim($service_path, '/'); // Get request body for signature verification $request_body = file_get_contents('php://input'); // Handle authentication $auth_data = []; $session_header = $_SERVER['HTTP_X_SESSION'] ?? null; $signature_header = $_SERVER['HTTP_X_SIGNATURE'] ?? null; // Check if this is auth/create request (no auth required for session creation) if ($service_path === 'auth/create' && $_SERVER['REQUEST_METHOD'] === 'POST') { // Generate new auth session $session = bin2hex(random_bytes(20)); $client_key = bin2hex(random_bytes(20)); $server_key = bin2hex(random_bytes(20)); $auth_data_new = [ 'session' => $session, 'client_key' => $client_key, 'server_key' => $server_key, 'created' => time() ]; // Save auth file $bridge_dir = ide_auth_framework_path('storage/rsx-ide-bridge'); if (!is_dir($bridge_dir)) { mkdir($bridge_dir, 0755, true); } // Rotate old sessions - keep max 100 auth files $auth_files = glob($bridge_dir . '/auth-*.json'); if (count($auth_files) >= 100) { // Sort by modification time (oldest first) usort($auth_files, function($a, $b) { return filemtime($a) - filemtime($b); }); // Delete oldest files to get down to 99 (so we can add the new one) $files_to_delete = count($auth_files) - 99; for ($i = 0; $i < $files_to_delete; $i++) { unlink($auth_files[$i]); } } $auth_file = $bridge_dir . '/auth-' . $session . '.json'; file_put_contents($auth_file, json_encode($auth_data_new, JSON_PRETTY_PRINT)); // Return auth data (unsigned response since client doesn't have keys yet) http_response_code(200); header('Content-Type: application/json'); echo json_encode([ 'success' => true, 'session' => $session, 'client_key' => $client_key, 'server_key' => $server_key ]); exit; } // Authentication required for all other requests // Handle authentication with localhost bypass // Localhost bypass for IDE integration $is_localhost_bypass = false; $request_host = $_SERVER['HTTP_HOST'] ?? ''; $request_scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http'; $remote_addr = $_SERVER['REMOTE_ADDR'] ?? ''; // Check for proxy headers $has_proxy_headers = false; foreach ($_SERVER as $key => $value) { if (str_starts_with($key, 'HTTP_X_')) { if ($key === 'HTTP_X_SESSION' || $key === 'HTTP_X_SIGNATURE') { continue; } $has_proxy_headers = true; break; } } // Check if request is from loopback $is_loopback_ip = ( !$has_proxy_headers && ($remote_addr === '127.0.0.1' || $remote_addr === '::1' || str_starts_with($remote_addr, '127.')) ); // Check if not in production $is_not_production = true; if (file_exists($env_file)) { $env_content = file_get_contents($env_file); if (preg_match('/^APP_ENV=production$/m', $env_content)) { $is_not_production = false; } } // All conditions must be true for bypass if ( $request_host === 'localhost' && $request_scheme === 'http' && $is_loopback_ip && $is_not_production ) { $is_localhost_bypass = true; $auth_data = [ 'session' => 'localhost-bypass', 'client_key' => '', 'server_key' => '' ]; } if (!$is_localhost_bypass) { // Require authentication for non-localhost if (!$session_header || !$signature_header) { ide_auth_error_response('Authentication required', 401); } // Load and validate session $auth_file = ide_auth_framework_path('storage/rsx-ide-bridge/auth-' . $session_header . '.json'); if (!file_exists($auth_file)) { ide_auth_error_response('Session not found', 401); } $auth_data = json_decode(file_get_contents($auth_file), true); $expected_signature = sha1($request_body . $auth_data['client_key']); if ($signature_header !== $expected_signature) { ide_auth_error_response('Invalid signature', 401); } } // Authentication passed - store auth data for handlers to use if needed define('IDE_AUTH_PASSED', true); define('IDE_AUTH_DATA', json_encode($auth_data)); define('IDE_AUTH_IS_LOCALHOST_BYPASS', $is_localhost_bypass); // Suppress console_debug output for IDE service requests // These are programmatic API calls, not user-facing pages define('SUPPRESS_CONSOLE_DEBUG_OUTPUT', true);