// Глобальные переменные
let currentUser = null;
const API_URL = '/api';

// Утилиты
const showElement = (id) => document.getElementById(id).classList.remove('hidden');
const hideElement = (id) => document.getElementById(id).classList.add('hidden');
const setActiveTab = (tabId) => {
    document.querySelectorAll('.tab-content').forEach(tab => tab.classList.add('hidden'));
    document.querySelectorAll('.tab-btn').forEach(btn => btn.classList.remove('active'));
    document.getElementById(tabId).classList.remove('hidden');
    document.querySelector(`[data-tab="${tabId}"]`).classList.add('active');
};

// Функция выхода
function logout() {
    currentUser = null;
    updateUserInterface();
    location.reload(); // Добавляем автоматическое обновление страницы после выхода
}

//  Обработчик регистрации
document.getElementById('register').addEventListener('submit', async (e) => {
    e.preventDefault();
    const username = document.getElementById('reg-username').value;
    const password = document.getElementById('reg-password').value;

    if (!username || !password) {
        alert('Пожалуйста, заполните все поля');
        return;
    }

    try {
        const response = await fetch(`${API_URL}/register`, {
            method: 'POST',
            headers: { 
                'Content-Type': 'application/json',
                'Accept': 'application/json'
            },
            body: JSON.stringify({ username, password })
        });

        const data = await response.json();

        if (response.ok) {
            alert('Регистрация успешна! Теперь вы можете войти.');
            showElement('login-form');
            hideElement('register-form');
        } else {
            alert(data.error || 'Ошибка регистрации');
        }
    } catch (error) {
        console.error('Ошибка регистрации:', error);
        alert('Ошибка при регистрации');
    }
});

// Обработчик входа
document.getElementById('login').addEventListener('submit', async (e) => {
    e.preventDefault();
    const username = document.getElementById('login-username').value;
    const password = document.getElementById('login-password').value;

    if (!username || !password) {
        alert('Пожалуйста, заполните все поля');
        return;
    }

    try {
        const response = await fetch(`${API_URL}/login`, {
            method: 'POST',
            headers: { 
                'Content-Type': 'application/json',
                'Accept': 'application/json',
                'X-Requested-With': 'XMLHttpRequest' // Add this header
            },
            credentials: 'same-origin', // Add credentials
            body: JSON.stringify({ username, password })
        });

        if (!response.ok) {
            throw new Error(`HTTP error! status: ${response.status}`);
        }

        const data = await response.json();

        if (data.token) {
            // Store the token
            localStorage.setItem('authToken', data.token);
            currentUser = {
                username: data.username,
                balance: data.balance
            };
            updateUserInterface();
            setActiveTab('servers');
        } else {
            alert('Неверные учетные данные');
        }
    } catch (error) {
        console.error('Ошибка входа:', error);
        // More descriptive error message
        alert(`Ошибка при входе в систему: ${error.message}`);
    }
});

// Add a function to check if user is authenticated
function isAuthenticated() {
    return localStorage.getItem('authToken') !== null;
}

// Управление серверами
async function loadServers() {
    try {
        const response = await fetch(`${API_URL}/servers?username=${currentUser.username}`);
        const servers = await response.json();
        displayServers(servers);
    } catch (error) {
        console.error('Ошибка загрузки серверов:', error);
    }
}

function displayServers(servers) {
    const serversList = document.getElementById('servers-list');
    serversList.innerHTML = '';

    servers.forEach(server => {
        const serverCard = document.createElement('div');
        serverCard.className = 'server-card';
        serverCard.innerHTML = `
            <h3>${server.name}</h3>
            <span class="server-status status-${server.status}">${server.status}</span>
            <p>План: ${server.plan.name}</p>
            <p>CPU: ${server.plan.cpu} / RAM: ${server.plan.ram}GB</p>
            <div class="server-actions">
                <button class="btn primary" onclick="toggleServer(${server.id}, '${server.status}')">
                    ${server.status === 'active' ? 'Остановить' : 'Запустить'}
                </button>
                <button class="btn danger" onclick="deleteServer(${server.id})">Удалить</button>
            </div>
        `;
        serversList.appendChild(serverCard);
    });
}

// Обработчик отправки тикетов
document.getElementById('ticket-form').addEventListener('submit', async (e) => {
    e.preventDefault();
    const title = document.getElementById('ticket-title').value;
    const description = document.getElementById('ticket-description').value;

    if (!title || !description) {
        alert('Пожалуйста, заполните все поля');
        return;
    }

    try {
        const response = await fetch(`${API_URL}/tickets`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
                user: currentUser.username,
                title,
                description
            })
        });

        if (response.ok) {
            alert('Тикет успешно создан!');
            document.getElementById('ticket-form').reset();
            loadTickets();
        } else {
            const data = await response.json();
            alert(data.error || 'Ошибка при создании тикета');
        }
    } catch (error) {
        console.error('Ошибка создания тикета:', error);
        alert('Ошибка при создании тикета');
    }
});

async function loadTickets() {
    try {
        const response = await fetch(`${API_URL}/tickets?username=${currentUser.username}`);
        const tickets = await response.json();
        displayTickets(tickets);
    } catch (error) {
        console.error('Ошибка загрузки тикетов:', error);
    }
}

function displayTickets(tickets) {
    const ticketsList = document.getElementById('tickets-list');
    ticketsList.innerHTML = '';

    tickets.forEach(ticket => {
        const ticketCard = document.createElement('div');
        ticketCard.className = 'ticket-card';
        ticketCard.innerHTML = `
            <div class="ticket-header">
                <h3>${ticket.title}</h3>
                <span class="ticket-status status-${ticket.status}">${ticket.status}</span>
            </div>
            <p>${ticket.description}</p>
            <small>Создан: ${new Date(ticket.created_at).toLocaleString()}</small>
        `;
        ticketsList.appendChild(ticketCard);
    });
}

// updateUserInterface function
function updateUserInterface() {
    const authContainer = document.getElementById('auth-container');
    const mainContent = document.getElementById('main-content');
    const usernameElement = document.getElementById('username');
    const balanceElement = document.getElementById('balance');

    if (isAuthenticated() && currentUser) {
        // Hide auth container and show main content
        authContainer?.classList.add('hidden');
        mainContent?.classList.remove('hidden');

        // Update user information in the header
        if (usernameElement) usernameElement.textContent = `Пользователь: ${currentUser.username}`;
        if (balanceElement) balanceElement.textContent = `Баланс: ${currentUser.balance} ₽`;

        // Load user data
        loadServers();
        loadTickets();
    } else {
        // Show auth container and hide main content
        authContainer?.classList.remove('hidden');
        mainContent?.classList.add('hidden');
    }
}

// logout function
function logout() {
    localStorage.removeItem('authToken');
    currentUser = null;
    updateUserInterface();
    location.reload();
}

// Обработчики переключения форм
document.getElementById('show-register').addEventListener('click', (e) => {
    e.preventDefault();
    hideElement('login-form');
    showElement('register-form');
});

document.getElementById('show-login').addEventListener('click', (e) => {
    e.preventDefault();
    hideElement('register-form');
    showElement('login-form');
});

// Обработчики вкладок
document.querySelectorAll('.tab-btn').forEach(btn => {
    btn.addEventListener('click', () => setActiveTab(btn.dataset.tab));
});

// Покупка сервера
document.querySelectorAll('.buy-server').forEach(btn => {
    btn.addEventListener('click', async () => {
        const plan = btn.dataset.plan;
        const planConfigs = {
            basic: { name: 'Базовый', cpu: 2, ram: 4, price: 500 },
            advanced: { name: 'Продвинутый', cpu: 4, ram: 8, price: 1000 },
            premium: { name: 'Премиум', cpu: 8, ram: 16, price: 2000 }
        };

        try {
            const response = await fetch(`${API_URL}/servers`, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({
                    owner: currentUser.username,
                    name: `Server-${Date.now()}`,
                    plan: planConfigs[plan]
                })
            });

            if (response.ok) {
                alert('Сервер успешно создан!');
                loadServers();
                currentUser.balance -= planConfigs[plan].price;
                updateUserInterface();
            }
        } catch (error) {
            console.error('Ошибка покупки сервера:', error);
            alert('Ошибка при создании сервера');
        }
    });
});

document.addEventListener('DOMContentLoaded', function() {
    const logoutBtn = document.getElementById('logout-btn');
    if (logoutBtn) {
        logoutBtn.addEventListener('click', logout);
    }
    updateUserInterface();
});

// Инициализация при загрузке страницы
document.addEventListener('DOMContentLoaded', updateUserInterface);



/* Основные стили */
:root {
    --primary-color: #941b31;
    --secondary-color: #bbb;
    --success-color: #46d369;
    --danger-color: #f53b57;
    --light-gray: #0a0909; /* Dark background color */
    --dark-gray: #eaeaea; /* Light text color */
}

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    line-height: 1.8;
    color: var(--dark-gray);
    background-color: var(--light-gray);
}

.container {
    max-width: 1200px;
    margin: 0 auto;
    padding: 20px;
}

/* Заголовок */
header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 30px;
    padding: 20px;
    background-color: #1e1e1e;
    color: var(--dark-gray);
    border-radius: 8px;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
}

#user-info {
    display: flex;
    align-items: center;
    gap: 20px;
}

/* Формы */
.form-container {
    width: 800px;
    height: 370px;
    margin: 290px auto;
    padding: 70px;
    background-image: url("https://api15.iloveimg.com/v1/download/1thxyjmgs31rqAnbAm61gfgd0wp969xy0kw96mzb811s717rAs2k5089zhk5Asj0svvjhdbgvwrrnts9plw9rx99xf1qpbmlqp7zdwdzq3sbp9j384lxjcfzkwvp87yg1n0z2AcnAxls24w5mz5pqnjcp6wwt298jbvjqjcq0msmncz7pxp1");
    color: var(--dark-gray);
    border-radius: 8px;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
}

form {
    display: flex;
    flex-direction: column;
    gap: 15px;
}

input,
textarea {
    padding: 10px;
    background-color: #333;
    border: 2px solid #5c5c5c;
    border-radius: 12px;
    color: var(--dark-gray);
    font-size: 16px;
}

textarea {
    min-height: 100px;
    resize: vertical;
}

/* Кнопки */
.btn {
    padding: 10px 20px;
    border: none;
    border-radius: 9px;
    cursor: pointer;
    font-size: 16px;
    transition: background-color 0.3s;
}

.btn.primary {
    background-color: var(--primary-color);
    color: white;
}

.btn.primary:hover {
    background-color: #b51844;
}

/* Навигация */
nav {
    display: flex;
    gap: 10px;
    margin-bottom: 20px;
}

.tab-btn {
    padding: 10px 20px;
    background: none;
    border: none;
    cursor: pointer;
    font-size: 16px;
    color: var(--secondary-color);
    border-bottom: 2px solid transparent;
}

.tab-btn.active {
    color: var(--primary-color);
    border-bottom-color: var(--primary-color);
}

/* Сетка серверов */
.grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    gap: 20px;
    margin-top: 20px;
}

.server-card {
    background-color: #1e1e1e;
    color: var(--dark-gray);
    padding: 20px;
    border-radius: 8px;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
}

.server-card h3 {
    margin-bottom: 10px;
}

.server-password {
    background-color: #333;
    padding: 8px;
    border-radius: 4px;
    margin-top: 10px;
    cursor: pointer;
}

.server-password.hidden-password {
    color: transparent;
    text-shadow: 0 0 8px rgba(255,255,255,0.5);
}

.server-status {
    display: inline-block;
    padding: 4px 8px;
    border-radius: 4px;
    font-size: 14px;
    margin-bottom: 10px;
    color: var(--dark-gray);
}

.status-active {
    background-color: var(--success-color);
}

.status-frozen {
    background-color: var(--danger-color);
}

/* Планы в магазине */
.plans-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
    gap: 20px;
    margin-top: 20px;
}

.plan-card {
    background-color: #1e1e1e;
    color: var(--dark-gray);
    padding: 20px;
    border-radius: 8px;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
    text-align: center;
}

.plan-card h3 {
    margin-bottom: 10px;
}

.price {
    font-size: 24px;
    font-weight: bold;
    color: var(--primary-color);
    margin: 15px 0;
}

/* Поддержка */
.support-container {
    max-width: 800px;
    margin: 0 auto;
}

.ticket-card {
    background-color: #1e1e1e;
    color: var(--dark-gray);
    padding: 20px;
    border-radius: 8px;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
    margin-bottom: 15px;
}

.ticket-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 10px;
}

.ticket-status {
    padding: 4px 8px;
    border-radius: 4px;
    font-size: 14px;
    color: var(--dark-gray);
}

/* Notification */
.notification {
    position: fixed;
    top: 20px;
    right: 20px;
    padding: 15px 25px;
    background-color: #1e1e1e;
    color: var(--dark-gray);
    border-radius: 8px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
    z-index: 1000;
    transform: translateX(120%);
    transition: transform 0.3s ease-in-out;
}

.notification.show {
    transform: translateX(0);
}

.notification-content {
    display: flex;
    align-items: center;
    gap: 10px;
}

/* Animation */
@keyframes slideIn {
    from {
        transform: translateX(120%);
    }
    to {
        transform: translateX(0);
    }
}

@keyframes slideOut {
    from {
        transform: translateX(0);
    }
    to {
        transform: translateX(120%);
    }
}

.notification-slide-in {
    animation: slideIn 0.3s ease-in-out forwards;
}

.notification-slide-out {
    animation: slideOut 0.3s ease-in-out forwards;
}

.status-open {
    background-color: var(--primary-color);
}

.status-closed {
    background-color: var(--secondary-color);
}

/* Утилиты */
.hidden {
    display: none !important;
}

/* Адаптивность */
@media (max-width: 768px) {
    .container {
        padding: 10px;
    }

    header {
        flex-direction: column;
        text-align: center;
        gap: 15px;
    }

    .grid,
    .plans-grid {
        grid-template-columns: 1fr;
    }

    nav {
        flex-wrap: wrap;
    }

    .tab-btn {
        flex: 1;
        min-width: 120px;
    }
}

.error-message {
    position: fixed;
    top: 20px;
    right: 20px;
    background-color: #ff4444;
    color: white;
    padding: 15px 20px;
    border-radius: 8px;
    z-index: 1000;
    display: flex;
    align-items: center;
    gap: 10px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
    animation: slideIn 0.3s ease-in-out;
}

.close-error {
    background: none;
    border: none;
    color: white;
    font-size: 20px;
    cursor: pointer;
    padding: 0 5px;
}

.password-container {
    position: relative;
    display: flex;
    align-items: center;
}

.password-toggle {
    position: absolute;
    right: 10px;
    background: none;
    border: none;
    color: var(--secondary-color);
    cursor: pointer;
}

.modal {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.7);
    display: flex;
    justify-content: center;
    align-items: center;
    z-index: 1000;
}

.modal-content {
    background-color: #1e1e1e;
    padding: 20px;
    border-radius: 8px;
    width: 90%;
    max-width: 500px;
}

.form-group {
    margin-bottom: 15px;
}

.form-group label {
    display: block;
    margin-bottom: 5px;
}

.form-group select,
.form-group input {
    width: 100%;
    padding: 8px;
    border-radius: 4px;
    background-color: #333;
    border: 1px solid #444;
    color: var(--dark-gray);
}


/* Анимации */
@keyframes fadeIn {
    from {
        opacity: 0;
    }
    to {
        opacity: 1;
    }
}

.fade-in {
    animation: fadeIn 0.3s ease-in;
}

/* Модальные окна */
.modal {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.7);
    display: flex;
    justify-content: center;
    align-items: center;
    z-index: 1000;
}

.modal-content {
    background-color: #1e1e1e;
    color: var(--dark-gray);
    padding: 20px;
    border-radius: 8px;
    max-width: 500px;
    width: 90%;
}

.modal-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 15px;
}

.close-modal {
    background: none;
    border: none;
    font-size: 24px;
    cursor: pointer;
    color: var(--secondary-color);
}



{
  "users": {
    "test": {
      "password": "test",
      "servers": [
        {
          "id": 1,
          "name": "Server-1730443463374",
          "plan": {
            "name": "\u041f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u044b\u0439",
            "cpu": 4,
            "ram": 8,
            "price": 1000
          },
          "status": "active",
          "password": "SVBes7qlNc40",
          "created_at": "2024-11-01T13:44:23.380705",
          "auto_renewal": true
        }
      ],
      "balance": 34765734657833657,
      "tickets": [
        {
          "id": 1,
          "title": "test",
          "description": "test",
          "status": "open",
          "created_at": "2024-11-01T13:34:30.026514"
        }
      ],
      "logs": [],
      "created_at": "2024-11-01T13:23:04.989224"
    },
    "test47": {
      "password": "$pbkdf2-sha256$29000$wHgvxRhDSIkRQsjZu9caIw$cMYTrGY5hm.RKAilJmMHgEwZA3WjuDeGoBjwGDsfryY",
      "servers": [],
      "balance": 0,
      "tickets": [],
      "created_at": "2024-11-01T14:16:46.398342"
    },
    "test4453": {
      "password": "$pbkdf2-sha256$29000$1JozxlgLoVTq3XtP6X1PCQ$dpI8LdVlejVa3XhJBLxSxCXkz3FkIPu7RAWMevWCzhc",
      "servers": [],
      "balance": 0,
      "tickets": [],
      "created_at": "2024-11-01T14:32:36.132607"
    }
  },
  "server_plans": [
    {
      "name": "\u041f\u043b\u0430\u043d 1",
      "specs": "1 vCPU, 2 GB RAM",
      "price": 10
    },
    {
      "name": "\u041f\u043b\u0430\u043d 2",
      "specs": "2 vCPU, 4 GB RAM",
      "price": 20
    }
  ],
  "logs": [
    {
      "timestamp": "2024-11-01T14:32:36.142610",
      "username": "test4453",
      "action": "register",
      "browser": "Chrome",
      "os": "Windows",
      "device": "Other",
      "ip": "127.0.0.1"
    },
    {
      "timestamp": "2024-11-01T14:32:40.835576",
      "username": "test4453",
      "action": "login",
      "browser": "Chrome",
      "os": "Windows",
      "device": "Other",
      "ip": "127.0.0.1"
    },
    {
      "timestamp": "2024-11-01T14:33:31.349385",
      "username": "test4453",
      "action": "login",
      "browser": "Chrome",
      "os": "Windows",
      "device": "Other",
      "ip": "127.0.0.1"
    }
  ]
}



<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Управление серверами</title>
    <link rel="stylesheet" href="/static/styles.css">
</head>
<body>
    <div class="container">
        <!-- Auth forms container -->
        <div id="auth-container">
            <div class="error-message hidden" id="error-box">
                <span id="error-text"></span>
                <button class="close-error">&times;</button>
            </div>
            <!-- Форма входа -->
            <div id="login-form" class="form-container">
                <h2><p align="center">Вход в систему</p></h2>
                <form id="login">
                    <input type="text" id="login-username" placeholder="Имя пользователя" required>
                    <input type="password" id="login-password" placeholder="Пароль" required>
                    <button type="submit" class="btn primary">Войти</button>
                    <p>Нет аккаунта? <a href="#" id="show-register">Зарегистрироваться</a></p>
                </form>
            </div>

            <!-- Форма регистрации -->
            <div id="register-form" class="form-container hidden">
                <h2><p align="center">Регистрация</p></h2>
                <form id="register">
                    <input type="text" id="reg-username" placeholder="Имя пользователя" required>
                    <input type="password" id="reg-password" placeholder="Пароль" required>
                    <button type="submit" class="btn primary">Зарегистрироваться</button>
                    <p>Уже есть аккаунт? <a href="#" id="show-login">Войти</a></p>
                </form>
            </div>
        </div>

        <!-- User panel container -->
        <div id="main-content" class="hidden">
            <header>
                <div id="user-info">
                    <span id="username"></span>
                    <span id="balance"></span>
                </div>
                <button id="logout-btn" class="btn primary">Выйти</button>
            </header>

            <nav>
                <button class="tab-btn active" data-tab="servers">Серверы</button>
                <button class="tab-btn" data-tab="shop">Магазин</button>
                <button class="tab-btn" data-tab="support">Поддержка</button>
            </nav>

            <!-- Секция серверов -->
            <section id="servers" class="tab-content">
                <h2>Мои серверы</h2>
                <div id="servers-list" class="grid"></div>
            </section>

            <!-- Секция магазина -->
            <section id="shop" class="tab-content hidden">
                <h2>Магазин серверов</h2>
                <div class="plans-grid">
                    <div class="plan-card">
                        <h3>Базовый</h3>
                        <p>2 CPU / 4 GB RAM</p>
                        <p class="price">500 ₽/мес</p>
                        <button class="btn primary buy-server" data-plan="basic">Купить</button>
                    </div>
                    <div class="plan-card">
                        <h3>Продвинутый</h3>
                        <p>4 CPU / 8 GB RAM</p>
                        <p class="price">1000 ₽/мес</p>
                        <button class="btn primary buy-server" data-plan="advanced">Купить</button>
                    </div>
                    <div class="plan-card">
                        <h3>Премиум</h3>
                        <p>8 CPU / 16 GB RAM</p>
                        <p class="price">2000 ₽/мес</p>
                        <button class="btn primary buy-server" data-plan="premium">Купить</button>
                    </div>
                </div>
            </section>

            <!-- Секция поддержки -->
            <section id="support" class="tab-content hidden">
                <h2>Поддержка</h2>
                <div class="support-container">
                    <form id="ticket-form">
                        <input type="text" id="ticket-title" placeholder="Тема" required>
                        <textarea id="ticket-description" placeholder="Описание проблемы" required></textarea>
                        <button type="submit" class="btn primary">Отправить</button>
                    </form>
                    <div id="tickets-list"></div>
                </div>
            </section>
        </div>
    </div>
    <div id="server-modal" class="modal hidden">
        <div class="modal-content">
            <div class="modal-header">
                <h3>Создание сервера</h3>
                <button class="close-modal">&times;</button>
            </div>
            <form id="server-create-form">
                <div class="form-group">
                    <label for="server-name">Название сервера</label>
                    <input type="text" id="server-name" required>
                </div>
                <div class="form-group">
                    <label for="server-os">Операционная система</label>
                    <select id="server-os" required>
                        <option value="win2020">Windows Server 2020</option>
                        <option value="win2022">Windows Server 2022</option>
                        <option value="win2025">Windows Server 2025</option>
                        <option value="win10">Windows 10</option>
                        <option value="win11">Windows 11</option>
                    </select>
                </div>
                <div class="form-group">
                    <p>План: <span id="modal-plan-name"></span></p>
                    <p>Цена: <span id="modal-plan-price"></span> ₽/мес</p>
                </div>
                <button type="submit" class="btn primary">Создать сервер</button>
            </form>
        </div>
    </div>
    <script src="/static/script.js"></script>
</body>
</html>



from flask import Flask, jsonify, request, render_template
from flask_cors import CORS
from flask_jwt_extended import JWTManager, create_access_token, jwt_required, get_jwt_identity
from passlib.hash import pbkdf2_sha256
from logging.handlers import RotatingFileHandler
import json
from datetime import datetime, timedelta
import random
import logging
import string
import os
import user_agents
import traceback

app = Flask(__name__, static_folder='static', template_folder='templates')
CORS(app)

# JWT Configuration
app.config['JWT_SECRET_KEY'] = 'gbauy45bguyab3e4gbaehrbghbg'  # Change this in production
app.config['JWT_ACCESS_TOKEN_EXPIRES'] = timedelta(hours=1)
jwt = JWTManager(app)

OS_OPTIONS = {
    'win2020': 'Windows Server 2020',
    'win2022': 'Windows Server 2022',
    'win2025': 'Windows Server 2025',
    'win10': 'Windows 10',
    'win11': 'Windows 11'
}

@app.route('/')
def home():
    return render_template('index.html')

def setup_logging():
    # Create logs directory if it doesn't exist
    if not os.path.exists('logs'):
        os.makedirs('logs')
    
    # Configure main application logger
    formatter = logging.Formatter(
        '[%(asctime)s] %(levelname)s in %(module)s: %(message)s'
    )
    
    # File handler for general logs
    file_handler = RotatingFileHandler(
        'logs/app.log', 
        maxBytes=1024 * 1024,  # 1MB
        backupCount=10
    )
    file_handler.setFormatter(formatter)
    file_handler.setLevel(logging.INFO)
    
    # File handler for errors
    error_file_handler = RotatingFileHandler(
        'logs/error.log',
        maxBytes=1024 * 1024,  # 1MB
        backupCount=10
    )
    error_file_handler.setFormatter(formatter)
    error_file_handler.setLevel(logging.ERROR)
    
    # Configure Flask logger
    app.logger.addHandler(file_handler)
    app.logger.addHandler(error_file_handler)
    app.logger.setLevel(logging.INFO)
    
    # Also log basic request info
    @app.before_request
    def log_request_info():
        app.logger.info(f'Request: {request.method} {request.url} from {request.remote_addr}')
        app.logger.debug(f'Headers: {dict(request.headers)}')
        if request.is_json:
            app.logger.debug(f'JSON Body: {request.get_json()}')

    # Add error handler
    @app.errorhandler(Exception)
    def handle_exception(e):
        app.logger.error(f'Unhandled Exception: {str(e)}')
        app.logger.error(traceback.format_exc())
        return jsonify({
            'error': 'An internal server error occurred',
            'details': str(e) if app.debug else None
        }), 500

def load_db():
    try:
        if not os.path.exists('db.json'):
            app.logger.info('Creating new database file')
            with open('db.json', 'w') as f:
                json.dump({
                    'users': {},
                    'server_plans': [
                        {
                            'name': 'План 1',
                            'specs': '1 vCPU, 2 GB RAM',
                            'price': 10
                        },
                        {
                            'name': 'План 2',
                            'specs': '2 vCPU, 4 GB RAM',
                            'price': 20
                        }
                    ],
                    'logs': []  # Ensure logs array exists in initial DB structure
                }, f)
        with open('db.json', 'r') as f:
            db = json.load(f)
            # Ensure logs array exists even in existing DB files
            if 'logs' not in db:
                db['logs'] = []
                save_db(db)
            return db
    except Exception as e:
        app.logger.error(f'Database load error: {str(e)}')
        app.logger.error(traceback.format_exc())
        raise

def save_db(db):
    with open('db.json', 'w') as f:
        json.dump(db, f, indent=2)

def log_activity(username, action, user_agent_string):
    try:
        db = load_db()
        ua = user_agents.parse(user_agent_string)
        log_entry = {
            'timestamp': datetime.now().isoformat(),
            'username': username,
            'action': action,
            'browser': ua.browser.family,
            'os': ua.os.family,
            'device': ua.device.family,
            'ip': request.remote_addr
        }
        
        if 'logs' not in db:
            db['logs'] = []
            
        db['logs'].append(log_entry)
        save_db(db)
    except Exception as e:
        app.logger.error(f'Error logging activity: {str(e)}')
        app.logger.error(traceback.format_exc())

def generate_password():
    return ''.join(random.choices(string.ascii_letters + string.digits, k=12))

@app.route('/api/login', methods=['POST'])
def login():
    try:
        app.logger.info('Processing login request')
        db = load_db()
        data = request.get_json()
        
        if not data:
            app.logger.warning('No JSON data in login request')
            return jsonify({'error': 'No JSON data provided'}), 400
        
        username = data.get('username')
        password = data.get('password')
        
        app.logger.info(f'Login attempt for user: {username}')
        
        if not username or not password:
            app.logger.warning('Missing username or password in login request')
            return jsonify({'error': 'Username and password are required'}), 400
        
        user_data = db['users'].get(username)
        if not user_data:
            app.logger.warning(f'Login failed: User {username} not found')
            return jsonify({'error': 'Invalid credentials'}), 401
            
        if pbkdf2_sha256.verify(password, user_data['password']):
            app.logger.info(f'Login successful for user: {username}')
            access_token = create_access_token(identity=username)
            try:
                log_activity(username, 'login', request.headers.get('User-Agent', ''))
            except Exception as e:
                app.logger.error(f'Failed to log login activity: {str(e)}')
                # Continue with login even if logging fails
            return jsonify({
                'token': access_token,
                'username': username,
                'balance': user_data.get('balance', 0)
            })
        
        app.logger.warning(f'Login failed: Invalid password for user {username}')
        return jsonify({'error': 'Invalid credentials'}), 401
        
    except Exception as e:
        app.logger.error(f'Login error: {str(e)}')
        app.logger.error(traceback.format_exc())
        return jsonify({'error': 'An internal server error occurred'}), 500

@app.route('/api/register', methods=['POST'])
def register():
    try:
        app.logger.info('Processing registration request')
        db = load_db()
        data = request.get_json()
        
        if not data:
            app.logger.warning('No JSON data in registration request')
            return jsonify({'error': 'No JSON data provided'}), 400
        
        username = data.get('username')
        password = data.get('password')
        
        app.logger.info(f'Registration attempt for username: {username}')
        
        if not username or not password:
            app.logger.warning('Missing username or password in registration request')
            return jsonify({'error': 'Username and password are required'}), 400
        
        if username in db['users']:
            app.logger.warning(f'Registration failed: Username {username} already exists')
            return jsonify({'error': 'Username already taken'}), 400
        
        hashed_password = pbkdf2_sha256.hash(password)
        
        db['users'][username] = {
            'password': hashed_password,
            'servers': [],
            'balance': 0,
            'tickets': [],
            'created_at': datetime.now().isoformat()
        }
        
        save_db(db)
        app.logger.info(f'Registration successful for user: {username}')
        log_activity(username, 'register', request.headers.get('User-Agent', ''))
        return jsonify({'message': 'Registration successful'}), 201
        
    except Exception as e:
        app.logger.error(f'Registration error: {str(e)}')
        app.logger.error(traceback.format_exc())
        return jsonify({'error': 'An internal server error occurred'}), 500

@app.route('/api/servers', methods=['GET', 'POST'])
@jwt_required()
def servers():
    current_user = get_jwt_identity()
    db = load_db()
    
    if request.method == 'GET':
        user_data = db['users'].get(current_user)
        if not user_data:
            return jsonify({'error': 'User not found'}), 404
            
        return jsonify(user_data.get('servers', []))
    
    elif request.method == 'POST':
        data = request.get_json()
        if not data or 'plan' not in data or 'os' not in data:
            return jsonify({'error': 'Invalid request data'}), 400
            
        user_data = db['users'].get(current_user)
        
        if not user_data:
            return jsonify({'error': 'User not found'}), 404
            
        if user_data['balance'] < data['plan']['price']:
            return jsonify({'error': 'Insufficient funds'}), 400
            
        if data['os'] not in OS_OPTIONS:
            return jsonify({'error': 'Invalid operating system selected'}), 400
            
        new_server = {
            'id': len(user_data['servers']) + 1,
            'name': data.get('name', f"Server-{len(user_data['servers']) + 1}"),
            'plan': data['plan'],
            'os': OS_OPTIONS[data['os']],
            'status': 'active',
            'password': generate_password(),
            'created_at': datetime.now().isoformat(),
            'auto_renewal': True
        }
        
        user_data['balance'] -= data['plan']['price']
        user_data['servers'].append(new_server)
        save_db(db)
        log_activity(current_user, 'create_server', request.headers.get('User-Agent', ''))
        return jsonify(new_server), 201

@app.route('/api/tickets', methods=['GET', 'POST'])
@jwt_required()
def tickets():
    current_user = get_jwt_identity()
    db = load_db()
    
    if request.method == 'GET':
        user_data = db['users'].get(current_user)
        if not user_data:
            return jsonify({'error': 'User not found'}), 404
            
        return jsonify(user_data.get('tickets', []))
    
    elif request.method == 'POST':
        data = request.get_json()
        if not data or 'title' not in data:
            return jsonify({'error': 'Invalid request data'}), 400
            
        user_data = db['users'].get(current_user)
        if not user_data:
            return jsonify({'error': 'User not found'}), 404
            
        new_ticket = {
            'id': len(user_data['tickets']) + 1,
            'title': data['title'],
            'description': data.get('description', ''),
            'status': 'open',
            'created_at': datetime.now().isoformat(),
            'messages': []
        }
        
        user_data['tickets'].append(new_ticket)
        save_db(db)
        log_activity(current_user, 'create_ticket', request.headers.get('User-Agent', ''))
        return jsonify(new_ticket), 201

@app.route('/api/tickets/<int:ticket_id>/reply', methods=['POST'])
@jwt_required()
def reply_ticket(ticket_id):
    current_user = get_jwt_identity()
    db = load_db()
    
    user_data = db['users'].get(current_user)
    if not user_data:
        return jsonify({'error': 'User not found'}), 404
        
    ticket = next((t for t in user_data['tickets'] if t['id'] == ticket_id), None)
    if not ticket:
        return jsonify({'error': 'Ticket not found'}), 404
        
    data = request.get_json()
    if not data or 'message' not in data:
        return jsonify({'error': 'Message is required'}), 400
        
    message = {
        'content': data['message'],
        'sender': current_user,
        'timestamp': datetime.now().isoformat()
    }
    
    ticket['messages'].append(message)
    save_db(db)
    log_activity(current_user, f'reply_ticket_{ticket_id}', request.headers.get('User-Agent', ''))
    return jsonify(message), 201

if __name__ == '__main__':
    setup_logging()
    app.run(debug=True)



[2024-11-01 14:33:17,421] INFO in main: Login attempt for user: test4453
[2024-11-01 14:33:17,459] WARNING in main: Login failed: Invalid password for user test4453
127.0.0.1 - - [01/Nov/2024 14:33:17] "POST /api/login HTTP/1.1" 401 -
[2024-11-01 14:33:19,824] INFO in main: Request: GET http://niggers.drugdeal.store/ from 127.0.0.1
127.0.0.1 - - [01/Nov/2024 14:33:19] "GET / HTTP/1.1" 200 -
[2024-11-01 14:33:22,937] INFO in main: Request: GET http://niggers.drugdeal.store/ from 127.0.0.1
127.0.0.1 - - [01/Nov/2024 14:33:22] "GET / HTTP/1.1" 200 -
[2024-11-01 14:33:25,418] INFO in main: Request: GET http://niggers.drugdeal.store/ from 127.0.0.1
127.0.0.1 - - [01/Nov/2024 14:33:25] "GET / HTTP/1.1" 200 -
[2024-11-01 14:33:31,304] INFO in main: Request: POST http://niggers.drugdeal.store/api/login from 127.0.0.1
[2024-11-01 14:33:31,305] INFO in main: Processing login request
[2024-11-01 14:33:31,307] INFO in main: Login attempt for user: test4453
[2024-11-01 14:33:31,346] INFO in main: Login successful for user: test4453
127.0.0.1 - - [01/Nov/2024 14:33:31] "POST /api/login HTTP/1.1" 200 -
[2024-11-01 14:33:31,650] INFO in main: Request: GET http://niggers.drugdeal.store/api/servers?username=test4453 from 127.0.0.1
127.0.0.1 - - [01/Nov/2024 14:33:31] "GET /api/servers?username=test4453 HTTP/1.1" 401 -
[2024-11-01 14:33:31,656] INFO in main: Request: GET http://niggers.drugdeal.store/api/tickets?username=test4453 from 127.0.0.1
127.0.0.1 - - [01/Nov/2024 14:33:31] "GET /api/tickets?username=test4453 HTTP/1.1" 401 -
[2024-11-01 14:33:56,332] INFO in main: Request: POST http://niggers.drugdeal.store/api/servers from 127.0.0.1
127.0.0.1 - - [01/Nov/2024 14:33:56] "POST /api/servers HTTP/1.1" 401 -
[2024-11-01 14:34:27,411] INFO in main: Request: POST http://niggers.drugdeal.store/api/tickets from 127.0.0.1
127.0.0.1 - - [01/Nov/2024 14:34:27] "POST /api/tickets HTTP/1.1" 401 -



{msg: "Missing Authorization Header"}
msg
: 
"Missing Authorization Header"



fix this error pls