from flask import Flask, render_template, request, jsonify, session
import subprocess
import os
import threading
import uuid
from datetime import datetime

app = Flask(__name__)
app.secret_key = 'your-secret-key-here'  # Измените на случайный ключ

# Безопасные команды (можно расширить)
SAFE_COMMANDS = ['ls', 'pwd', 'whoami', 'date', 'uptime', 'uname', 'df', 'free']


class CommandSession:
    def __init__(self):
        self.sessions = {}

    def create_session(self):
        session_id = str(uuid.uuid4())
        self.sessions[session_id] = {
            'created_at': datetime.now(),
            'working_dir': os.getcwd()
        }
        return session_id

    def execute_command(self, session_id, command):
        if session_id not in self.sessions:
            return "Сессия не найдена"

        session_data = self.sessions[session_id]

        # Безопасность: проверяем команду
        cmd_parts = command.strip().split()
        if not cmd_parts:
            return ""

        base_command = cmd_parts[0]

        # Ограничиваем доступные команды для безопасности
        if base_command not in SAFE_COMMANDS:
            return f"Команда '{base_command}' не разрешена для выполнения"

        try:
            # Выполняем команду в текущей директории сессии
            result = subprocess.run(
                command,
                shell=True,
                capture_output=True,
                text=True,
                cwd=session_data['working_dir'],
                timeout=30  # Таймаут 30 секунд
            )

            output = result.stdout
            if result.stderr:
                output += f"\nОшибка: {result.stderr}"

            return output

        except subprocess.TimeoutExpired:
            return "Ошибка: команда выполнялась слишком долго"
        except Exception as e:
            return f"Ошибка выполнения: {str(e)}"


command_manager = CommandSession()


@app.route('/')
def index():
    if 'session_id' not in session:
        session['session_id'] = command_manager.create_session()
    return render_template('index.html')


@app.route('/execute', methods=['POST'])
def execute_command():
    if 'session_id' not in session:
        return jsonify({'error': 'Сессия не найдена'})

    data = request.get_json()
    command = data.get('command', '').strip()

    if not command:
        return jsonify({'error': 'Пустая команда'})

    # Выполняем команду
    output = command_manager.execute_command(session['session_id'], command)

    return jsonify({
        'output': output,
        'command': command,
        'timestamp': datetime.now().strftime('%H:%M:%S')
    })


@app.route('/sessions', methods=['GET'])
def list_sessions():
    return jsonify({
        'active_sessions': len(command_manager.sessions),
        'current_session': session.get('session_id')
    })


@app.route('/clear-session', methods=['POST'])
def clear_session():
    session_id = session.get('session_id')
    if session_id in command_manager.sessions:
        del command_manager.sessions[session_id]
    session.pop('session_id', None)
    return jsonify({'message': 'Сессия очищена'})


if __name__ == '__main__':
    # Создаем папку для шаблонов если её нет
    os.makedirs('templates', exist_ok=True)

    # Создаем HTML шаблон
    with open('templates/index.html', 'w', encoding='utf-8') as f:
        f.write('''<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Web Shell</title>
    <style>
        body {
            font-family: 'Courier New', monospace;
            background-color: #1e1e1e;
            color: #00ff00;
            margin: 0;
            padding: 20px;
        }
        .terminal {
            background-color: #000;
            border: 1px solid #333;
            border-radius: 5px;
            padding: 20px;
            height: 70vh;
            overflow-y: auto;
        }
        .output {
            margin-bottom: 10px;
            white-space: pre-wrap;
            word-break: break-all;
        }
        .command-line {
            display: flex;
            align-items: center;
        }
        .prompt {
            margin-right: 10px;
        }
        #command-input {
            background: transparent;
            border: none;
            color: #00ff00;
            font-family: 'Courier New', monospace;
            font-size: 16px;
            outline: none;
            flex-grow: 1;
        }
        .timestamp {
            color: #888;
            font-size: 12px;
        }
        .error {
            color: #ff4444;
        }
        .info {
            color: #4488ff;
        }
    </style>
</head>
<body>
    <h1>Web Shell Interface</h1>
    <div class="info">
        Разрешенные команды: {{ safe_commands|join(', ') }}
    </div>

    <div class="terminal" id="terminal">
        <div class="output info">
            Добро пожаловать в Web Shell!<br>
            Введите команду ниже. Доступные команды: {{ safe_commands|join(', ') }}
        </div>
    </div>

    <div class="command-line">
        <span class="prompt">$</span>
        <input type="text" id="command-input" placeholder="Введите команду...">
    </div>

    <div style="margin-top: 20px;">
        <button onclick="clearTerminal()">Очистить терминал</button>
        <button onclick="clearSession()">Новая сессия</button>
        <span id="session-info"></span>
    </div>

    <script>
        const terminal = document.getElementById('terminal');
        const commandInput = document.getElementById('command-input');
        const sessionInfo = document.getElementById('session-info');

        // Фокус на поле ввода
        commandInput.focus();

        // Обработка отправки команды
        commandInput.addEventListener('keypress', function(e) {
            if (e.key === 'Enter') {
                const command = commandInput.value.trim();
                if (command) {
                    executeCommand(command);
                    commandInput.value = '';
                }
            }
        });

        function executeCommand(command) {
            // Показываем команду в терминале
            addOutput('$ ' + command, 'user-command');

            // Отправляем на сервер
            fetch('/execute', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify({command: command})
            })
            .then(response => response.json())
            .then(data => {
                if (data.error) {
                    addOutput(data.error, 'error');
                } else {
                    addOutput(data.output, 'command-output');
                }
            })
            .catch(error => {
                addOutput('Ошибка: ' + error, 'error');
            });
        }

        function addOutput(text, className) {
            const output = document.createElement('div');
            output.className = `output ${className}`;
            output.textContent = text;
            terminal.appendChild(output);
            terminal.scrollTop = terminal.scrollHeight;
        }

        function clearTerminal() {
            terminal.innerHTML = '<div class="output info">Терминал очищен</div>';
        }

        function clearSession() {
            fetch('/clear-session', {method: 'POST'})
                .then(() => {
                    location.reload();
                });
        }

        // Загружаем информацию о сессии
        fetch('/sessions')
            .then(response => response.json())
            .then(data => {
                sessionInfo.textContent = `Активных сессий: ${data.active_sessions}`;
            });
    </script>
</body>
</html>''')

    app.run(host='0.0.0.0', port=5000, debug=True)