<?php
// Improved Discord Bot Admin API

// Error reporting (disable on production)
error_reporting(E_ALL);
ini_set('display_errors', 1);

// Configure secure session parameters:
session_set_cookie_params([
    'httponly' => true,
    'secure'   => true, // Ensure HTTPS is used in production
    'samesite' => 'Strict'
]);
session_start();

// --- CSRF Utility Functions ---
function getCsrfToken() {
    if (empty($_SESSION['csrf_token'])) {
        $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
    }
    return $_SESSION['csrf_token'];
}

function validateCsrfToken($token) {
    return isset($_SESSION['csrf_token']) && hash_equals($_SESSION['csrf_token'], $token);
}

// --- Login and Authentication ---
if (!isset($_SESSION['logged_in']) || $_SESSION['logged_in'] !== true) {
    if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['username'], $_POST['password'], $_POST['csrf_token'])) {
        if (!validateCsrfToken($_POST['csrf_token'])) {
            $error = "Invalid CSRF token.";
        } else {
            $envUser = getenv('user');
            $envPass = getenv('pass');
            // Using hash_equals for timing attack prevention
            if (hash_equals($_POST['username'], $envUser) && hash_equals($_POST['password'], $envPass)) {
                $_SESSION['logged_in'] = true;
                session_regenerate_id(true);
                header("Location: " . $_SERVER['PHP_SELF']);
                exit;
            } else {
                $error = "Invalid credentials.";
            }
        }
    }
    $loginToken = getCsrfToken();
    ?>
    <!DOCTYPE html>
    <html>
    <head>
        <title>Login</title>
        <style>
            body {
                font-family: Arial, sans-serif;
                background: #f0f0f0;
                display: flex;
                align-items: center;
                justify-content: center;
                height: 100vh;
            }
            .login-container {
                background: #fff;
                padding: 20px;
                border-radius: 5px;
                box-shadow: 0 0 10px rgba(0,0,0,0.1);
                width: 300px;
            }
            input[type="text"], input[type="password"] {
                width: 100%;
                padding: 8px;
                margin: 5px 0 10px;
                border: 1px solid #ccc;
                border-radius: 3px;
            }
            input[type="submit"] {
                background: #007BFF;
                color: white;
                border: none;
                padding: 10px;
                width: 100%;
                cursor: pointer;
                border-radius: 3px;
            }
            input[type="submit"]:hover {
                background: #0056b3;
            }
            .error {
                color: red;
            }
        </style>
    </head>
    <body>
        <div class="login-container">
            <h2>Login</h2>
            <?php if(isset($error)) { echo "<p class='error'>" . htmlspecialchars($error) . "</p>"; } ?>
            <form method="POST" action="<?php echo htmlspecialchars($_SERVER['PHP_SELF']); ?>">
                <input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars($loginToken); ?>">
                <label>Username</label>
                <input type="text" name="username" required>
                <label>Password</label>
                <input type="password" name="password" required>
                <input type="submit" value="Login">
            </form>
        </div>
    </body>
    </html>
    <?php
    exit;
}

// --- Action Handlers ---
$output = "";

function handleVersionAction() {
    $botDir = '/home/server/wdiscordbotserver';
    if (is_dir($botDir)) {
        $cmd = 'cd ' . escapeshellarg($botDir) . ' && git rev-parse HEAD 2>&1';
        return trim(shell_exec($cmd));
    }
    return "Directory not found.";
}

function handleUpdateAction() {
    // Only allow updates using a POST request with a valid CSRF token.
    if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !isset($_POST['csrf_token']) || !validateCsrfToken($_POST['csrf_token'])) {
        return "Unauthorized update request.";
    }
    $botDir = '/home/server/wdiscordbotserver';
    $result = "";
    if (is_dir($botDir)) {
        $rmCmd = 'rm -rf ' . escapeshellarg($botDir) . ' 2>&1';
        $result .= shell_exec($rmCmd);
    }
    $cloneCmd = 'git clone https://gitlab.com/pancakes1234/wdiscordbotserver.git ' . escapeshellarg($botDir) . ' 2>&1';
    $result .= shell_exec($cloneCmd);
    return $result;
}

function handleDataAction() {
    $baseDir = realpath('/home/server');
    $file = $_GET['file'] ?? null;
    $response = "";
    if ($file) {
        $realFile = realpath($file);
        if ($realFile === false || strpos($realFile, $baseDir) !== 0) {
            $response = "Invalid file.";
        } else {
            if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['content'], $_POST['csrf_token'])) {
                if (!validateCsrfToken($_POST['csrf_token'])) {
                    $response = "Invalid CSRF token.";
                } else {
                    if (file_put_contents($realFile, $_POST['content']) !== false) {
                        $response = "File updated successfully.";
                    } else {
                        $response = "Failed to update file.";
                    }
                }
            }
        }
    }
    return $response;
}

// --- Process Request Actions ---
$action = $_GET['action'] ?? ($_POST['action'] ?? "");
switch ($action) {
    case "version":
        $output = handleVersionAction();
        break;
    case "update":
        $output = handleUpdateAction();
        break;
    case "data":
        $output = handleDataAction();
        break;
    // Additional action cases (e.g., "terminal") can be handled below.
    default:
        break;
}
?>
<!DOCTYPE html>
<html>
<head>
    <title>Discord Bot Admin API</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            background: #e9e9e9;
            margin: 0;
            padding: 20px;
        }
        .container {
            max-width: 900px;
            margin: auto;
            background: #fff;
            padding: 20px;
            box-shadow: 0 0 10px rgba(0,0,0,0.1);
        }
        header {
            margin-bottom: 20px;
        }
        header button, header form button {
            padding: 10px 20px;
            margin-right: 10px;
            border: none;
            background: #007BFF;
            color: white;
            cursor: pointer;
            border-radius: 3px;
        }
        header button:hover, header form button:hover {
            background: #0056b3;
        }
        .output {
            background: #f4f4f4;
            padding: 10px;
            margin-top: 20px;
            white-space: pre-wrap;
        }
        .file-list {
            list-style-type: none;
            padding: 0;
        }
        .file-list li {
            margin: 5px 0;
        }
        a {
            text-decoration: none;
            color: #007BFF;
        }
        a:hover {
            text-decoration: underline;
        }
        textarea {
            width: 100%;
            height: 300px;
        }
        /* Terminal tabs styling */
        #terminal-tabs button {
            padding: 8px 16px;
            border: none;
            margin-right: 5px;
            background: #007BFF;
            color: white;
            border-radius: 3px;
            cursor: pointer;
        }
        #terminal-tabs button:hover {
            background: #0056b3;
        }
    </style>
    <script>
        // For Version and Update actions we can use AJAX.
        function doAction(action) {
            if (action === "data" || action === "terminal") {
                window.location.href = "?action=" + action;
            } else {
                fetch("?action=" + action)
                    .then(response => response.text())
                    .then(data => {
                        document.getElementById("output").innerText = data;
                    })
                    .catch(err => {
                        document.getElementById("output").innerText = "Error: " + err;
                    });
            }
        }
        // SSH Connect functionality using the "ssh://" protocol.
        function doSSH() {
            var sshUser = "<?php echo htmlspecialchars(getenv('user')); ?>";
            var sshHost = window.location.hostname;
            window.location.href = "ssh://" + sshUser + "@" + sshHost;
        }
        function showTab(tab) {
            document.getElementById('wetty').style.display = (tab === 'wetty') ? 'block' : 'none';
            document.getElementById('xterm').style.display = (tab === 'xterm') ? 'block' : 'none';
        }
        window.addEventListener('load', function() {
            if(document.getElementById('xterm-container')) {
                const terminal = new Terminal();
                terminal.open(document.getElementById('xterm-container'));
                
                const socket = new WebSocket('ws://' + window.location.hostname + ':3001');
                socket.onopen = function() {
                    terminal.write("Connected to shell\r\n");
                };
                terminal.onData(function(data) {
                    socket.send(data);
                });
                socket.onmessage = function(event) {
                    terminal.write(event.data);
                };
                socket.onerror = function() {
                    terminal.write("\r\nError connecting to shell.\r\n");
                };
                socket.onclose = function() {
                    terminal.write("\r\nConnection closed.\r\n");
                };
            }
        });
    </script>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm/css/xterm.css" />
    <script src="https://cdn.jsdelivr.net/npm/xterm/lib/xterm.js"></script>
</head>
<body>
    <div class="container">
        <header>
            <h1>Discord Bot Admin API</h1>
            <button onclick="doAction('version')">Version</button>
            <!-- Update action now uses a form (POST with CSRF token) to improve safety -->
            <form style="display:inline;" method="POST" action="?action=update" onsubmit="return confirm('Are you sure you want to update the bot?');">
                <input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars(getCsrfToken()); ?>">
                <button type="submit">Update</button>
            </form>
            <button onclick="window.location.href='?action=data'">Data</button>
            <button onclick="doSSH()">SSH Connect</button>
            <button onclick="window.location.href='?action=terminal'">Terminal</button>
        </header>
        <!-- AJAX Output Area -->
        <div id="output" class="output"><?php echo htmlspecialchars($output); ?></div>

        <?php if ($action === "data"): 
            $baseDir = realpath('/home/server');
            if (!isset($_GET['file'])): ?>
                <h2>Files in <?php echo htmlspecialchars($baseDir); ?></h2>
                <ul class="file-list">
                <?php
                try {
                    $iterator = new RecursiveIteratorIterator(
                        new RecursiveDirectoryIterator($baseDir, RecursiveDirectoryIterator::SKIP_DOTS)
                    );
                    foreach ($iterator as $fileInfo) {
                        $filePath = $fileInfo->getPathname();
                        echo "<li><a href='?action=data&file=" . urlencode($filePath) . "'>" . htmlspecialchars($filePath) . "</a></li>";
                    }
                } catch (Exception $e) {
                    echo "<li>Error reading files: " . htmlspecialchars($e->getMessage()) . "</li>";
                }
                ?>
                </ul>
            <?php else:
                $file = $_GET['file'];
                $realFile = realpath($file);
                if ($realFile === false || strpos($realFile, $baseDir) !== 0): ?>
                    <p>Invalid file.</p>
                <?php else: ?>
                    <h2>Editing: <?php echo htmlspecialchars($realFile); ?></h2>
                    <form method="POST" action="?action=data&file=<?php echo urlencode($realFile); ?>">
                        <input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars(getCsrfToken()); ?>">
                        <textarea name="content"><?php echo htmlspecialchars(file_get_contents($realFile)); ?></textarea><br>
                        <input type="hidden" name="action" value="data">
                        <input type="submit" value="Save" style="padding:10px 20px; margin-top:10px;">
                    </form>
                <?php endif;
            endif;
        elseif ($action === "terminal"): ?>
            <div id="terminal-tabs" style="margin-bottom:10px;">
                <button onclick="showTab('wetty')">Wetty Terminal</button>
                <button onclick="showTab('xterm')">Xterm Terminal</button>
            </div>
            <div id="wetty" class="terminal-tab" style="display:block;">
                <h2>Wetty Terminal</h2>
                <iframe src="http://<?php echo htmlspecialchars($_SERVER['HTTP_HOST']); ?>:3000" width="100%" height="500px" frameborder="0"></iframe>
            </div>
            <div id="xterm" class="terminal-tab" style="display:none;">
                <h2>Xterm Terminal</h2>
                <div id="xterm-container" style="width: 100%; height: 500px;"></div>
            </div>
        <?php endif; ?>
    </div>
</body>
</html>
