Project structure:

DarkVPN_server/
├── static/
│   ├── js/
│   │   └── admin_panel.js
├── templates/
│   ├── admin_login.html
│   └── admin_panel.html
├── auth_server.py
└── requirements.txt


Project files:

auth_server.py
```py
# main.py

import os
from flask import Flask, request, jsonify, session, render_template, redirect, url_for
from flask_socketio import SocketIO, emit
from datetime import datetime, timedelta
import uuid
import threading
from flask_cors import CORS
import logging

# Загрузка переменных среды из файла .env (опционально)
from dotenv import load_dotenv
load_dotenv()

app = Flask(__name__)
app.secret_key = os.getenv('SECRET_KEY', 'default_secret_key')  # Использование переменной среды
CORS(app)  # Включение CORS для всех маршрутов

socketio = SocketIO(app, cors_allowed_origins="*", async_mode='threading')

# Настройка логирования
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# Хранилище пользователей (для демонстрации; замените на базу данных в продакшене)
users = {}  # Ключ: userKey, Значение: данные пользователя
admin_password = os.getenv('ADMIN_PASSWORD', 'default_admin_password')  # Использование переменной среды
latest_extension_version = '1.0'

# Блокировка для потокобезопасных операций с пользователями
users_lock = threading.Lock()

# Интервал проверки активности пользователей (в секундах)
CHECK_INTERVAL = 10
TIMEOUT = 30  # Время без heartbeat, после которого пользователь считается отключенным

def check_user_activity():
    while True:
        socketio.sleep(CHECK_INTERVAL)
        with users_lock:
            now = datetime.utcnow()
            for user in users.values():
                if user['last_seen']:
                    elapsed = (now - user['last_seen']).total_seconds()
                    if elapsed > TIMEOUT and user['is_connected']:
                        user['is_connected'] = False
                        emit_user_update(user)
                        logger.info(f"User {user['key']} disconnected due to timeout (last_seen: {user['last_seen']}).")

# Запуск фонового потока проверки активности пользователей
socketio.start_background_task(target=check_user_activity)

# API Endpoint для heartbeat
@app.route('/api/heartbeat', methods=['POST'])
def api_heartbeat():
    data = request.get_json()
    user_key = data.get('userKey')  # Получение userKey из запроса
    version = data.get('version')
    current_url = data.get('currentUrl')
    client_ip = request.remote_addr
    is_connected = data.get('isConnected', False)

    logger.info(f"Heartbeat received from userKey: {user_key}, IP: {client_ip}, URL: {current_url}, Connected: {is_connected}")

    if version != latest_extension_version:
        logger.warning(f"Version mismatch: {version} != {latest_extension_version}")
        return jsonify({'status': 'update_required'}), 200

    with users_lock:
        user = users.get(user_key)

        if not user:
            logger.warning(f"Unauthorized access attempt with userKey: {user_key}")
            return jsonify({'status': 'unauthorized'}), 403

        # Обновление информации пользователя
        user['last_seen'] = datetime.utcnow()
        user['ip'] = client_ip
        user['current_url'] = current_url
        user['is_connected'] = is_connected  # Обновление состояния подключения на основе клиента

        if not is_connected:
            # Пользователь не подключен, отправляем обновление и не предоставляем детали прокси
            emit_user_update(user)
            logger.info(f"User {user_key} is disconnected.")
            return jsonify({'status': 'disconnected'}), 200

        if user['is_banned'] or user['is_stopped']:
            user['is_connected'] = False
            emit_user_update(user)
            logger.info(f"User {user_key} is {'banned' if user['is_banned'] else 'stopped'}.")
            return jsonify({'status': 'unauthorized'}), 403

        if user['subscription_expires'] < datetime.utcnow():
            user['is_connected'] = False
            emit_user_update(user)
            logger.info(f"Subscription expired for user {user_key}.")
            return jsonify({'status': 'subscription_expired'}), 403

        # Пользователь авторизован и подключен, возвращаем детали прокси
        proxy_details = {
            'host': '185.106.94.81',
            'port': 44590,
            'scheme': 'socks5'  # Включение схемы
        }

        emit_user_update(user)
        logger.info(f"Proxy details sent to user {user_key}.")

        return jsonify({'status': 'ok', 'proxy': proxy_details}), 200

# Функция для отправки обновлений пользователей админ-клиентам
def emit_user_update(user):
    socketio.emit('user_update', {
        'key': user['key'],
        'username': user['username'],
        'ip': user['ip'] or 'N/A',
        'current_url': user['current_url'] or 'N/A',
        'is_connected': user['is_connected'],
        'subscription_expires': user['subscription_expires'].isoformat(),
        'is_banned': user['is_banned'],
        'is_stopped': user['is_stopped']
    }, namespace='/')

# Админ вход
@app.route('/admin', methods=['GET', 'POST'])
def admin_login():
    if 'admin_logged_in' in session:
        return redirect(url_for('admin_panel'))

    if request.method == 'POST':
        password = request.form.get('password')
        if password == admin_password:
            session['admin_logged_in'] = True
            logger.info("Admin logged in successfully.")
            return redirect(url_for('admin_panel'))
        else:
            logger.warning("Invalid admin password attempt.")
            return render_template('admin_login.html', error='Неверный пароль')

    return render_template('admin_login.html')

# Админ панель
@app.route('/admin/panel')
def admin_panel():
    if 'admin_logged_in' not in session:
        return redirect(url_for('admin_login'))

    return render_template('admin_panel.html')

# Маршрут админа для добавления нового пользователя
@app.route('/admin/add_user', methods=['POST'])
def admin_add_user():
    if 'admin_logged_in' not in session:
        return jsonify({'status': 'error', 'message': 'Unauthorized'}), 401

    try:
        data = request.get_json()
        username = data.get('username')
        days = int(data.get('days', 0))

        if not username or days <= 0:
            logger.error("Invalid data for adding user.")
            return jsonify({'status': 'error', 'message': 'Invalid data'}), 400

        user_key = str(uuid.uuid4())  # Генерация уникального ключа

        with users_lock:
            user = {
                'username': username,
                'key': user_key,
                'subscription_expires': datetime.utcnow() + timedelta(days=days),
                'is_banned': False,
                'is_stopped': False,
                'is_connected': False,
                'last_seen': None,
                'ip': None,
                'current_url': None
            }
            users[user_key] = user

        emit_user_update(user)
        logger.info(f"New user added: {username} with key: {user_key}")

        return jsonify({'status': 'ok', 'userKey': user_key}), 200

    except (ValueError, TypeError) as e:
        logger.error(f"Error adding user: {e}")
        return jsonify({'status': 'error', 'message': 'Invalid input'}), 400

# Маршруты админа для действий с пользователями
@app.route('/admin/action', methods=['POST'])
def admin_action():
    if 'admin_logged_in' not in session:
        return jsonify({'status': 'error', 'message': 'Unauthorized'}), 401

    try:
        data = request.get_json()
        action = data.get('action')
        user_key = data.get('userKey')

        if not action or not user_key:
            logger.error("Missing action or userKey in admin_action.")
            return jsonify({'status': 'error', 'message': 'Invalid data'}), 400

        with users_lock:
            user = users.get(user_key)
            if not user:
                logger.warning(f"User not found: {user_key}")
                return jsonify({'status': 'error', 'message': 'User not found'}), 404

            if action == 'ban':
                user['is_banned'] = not user['is_banned']  # Переключение статуса бана
                logger.info(f"User {user_key} ban status toggled to {user['is_banned']}.")
            elif action == 'stop':
                user['is_stopped'] = not user['is_stopped']  # Переключение статуса остановки
                logger.info(f"User {user_key} stop status toggled to {user['is_stopped']}.")
            elif action == 'renew':
                days = int(data.get('days', 0))
                if days <= 0:
                    logger.error("Invalid days for renewal.")
                    return jsonify({'status': 'error', 'message': 'Invalid days'}), 400
                if user['subscription_expires'] < datetime.utcnow():
                    user['subscription_expires'] = datetime.utcnow() + timedelta(days=days)
                else:
                    user['subscription_expires'] += timedelta(days=days)
                logger.info(f"User {user_key} subscription renewed by {days} days.")
            else:
                logger.error(f"Invalid action: {action}")
                return jsonify({'status': 'error', 'message': 'Invalid action'}), 400

            emit_user_update(user)
            return jsonify({'status': 'ok'}), 200

    except (ValueError, TypeError) as e:
        logger.error(f"Error in admin_action: {e}")
        return jsonify({'status': 'error', 'message': 'Invalid input'}), 400

# Событие подключения SocketIO для админ-панели
@socketio.on('connect')
def handle_connect():
    if 'admin_logged_in' in session:
        logger.info("Admin client connected via SocketIO.")
        # Отправка всех текущих пользователей подключенному администратору
        with users_lock:
            for user in users.values():
                emit_user_update(user)
    else:
        logger.warning("Unauthorized SocketIO connection attempt.")
        emit('error', {'message': 'Unauthorized'}, namespace='/')
        # Закрытие соединения для неавторизованных пользователей
        return False  # Прерывание соединения

# Маршрут выхода из системы
@app.route('/admin/logout')
def admin_logout():
    session.pop('admin_logged_in', None)
    logger.info("Admin logged out.")
    return redirect(url_for('admin_login'))

# Запуск приложения
if __name__ == '__main__':
    socketio.run(app, host='0.0.0.0', port=5011, allow_unsafe_werkzeug=True)
```


requirements.txt
```txt
flask
flask-socketio
python-dotenv
flask-cors
```


templates/admin_login.html
```html
<!-- templates/admin_login.html -->
<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <title>Admin Login</title>
    <style>
        /* Стили для страницы входа */
        body {
            font-family: Arial, sans-serif;
            background-color: #f0f0f0;
            display: flex;
            align-items: center;
            justify-content: center;
            height: 100vh;
            margin: 0;
        }

        .login-container {
            background-color: white;
            padding: 20px 30px;
            border-radius: 5px;
            box-shadow: 0 0 10px rgba(0,0,0,0.1);
            text-align: center;
        }

        .login-container h2 {
            margin-top: 0;
        }

        .login-container input {
            width: 100%;
            padding: 8px;
            margin-bottom: 10px;
            box-sizing: border-box;
        }

        .login-container button {
            width: 100%;
            padding: 10px;
            background-color: #333;
            color: white;
            border: none;
            cursor: pointer;
        }

        .login-container button:hover {
            background-color: #555;
        }

        .error {
            color: red;
        }

    </style>
</head>
<body>
    <div class="login-container">
        <h2>Admin Login</h2>
        {% if error %}
        <p class="error">{{ error }}</p>
        {% endif %}
        <form method="post">
            <!-- Добавьте CSRF-токен здесь, если используете его -->
            <input type="password" name="password" placeholder="Введите секретный ключ" required>
            <button type="submit">Вход</button>
        </form>
    </div>
</body>
</html>
```


templates/admin_panel.html
```html
<!-- templates/admin_panel.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Admin Panel</title>
    <!-- Include Socket.IO library -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/3.1.3/socket.io.min.js"></script>
    <!-- Include any CSS frameworks or custom styles -->
    <style>
        /* Basic styles for the admin panel */

        body {
            font-family: Arial, sans-serif;
            margin: 0;
            padding: 0;
            background-color: #f0f0f0;
        }

        /* Sidebar */
        .sidebar {
            width: 200px;
            background-color: #333;
            color: white;
            height: 100vh;
            position: fixed;
            overflow: auto;
        }

        .sidebar h2 {
            text-align: center;
            padding: 10px 0;
            margin: 0;
            background-color: #444;
        }

        .sidebar button {
            width: 100%;
            padding: 10px;
            border: none;
            background: none;
            color: white;
            text-align: left;
            cursor: pointer;
        }

        .sidebar button:hover {
            background-color: #555;
        }

        /* Main content */
        .main-content {
            margin-left: 200px;
            padding: 20px;
        }

        /* User grid */
        #user-grid {
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
            gap: 10px;
        }

        .user-tile {
            background-color: white;
            border: 1px solid #ccc;
            padding: 10px;
            position: relative;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }

        .user-tile h3 {
            margin: 0 0 10px;
            font-size: 16px;
        }

        .user-tile p {
            margin: 5px 0;
            font-size: 14px;
        }

        /* User actions */
        .user-actions {
            display: none;
            position: absolute;
            bottom: 10px;
            left: 10px;
        }

        .user-actions button {
            margin-right: 5px;
            font-size: 12px;
        }

        .user-tile:hover .user-actions {
            display: block;
        }

        /* Modals */
        .modal {
            display: none;
            position: fixed;
            z-index: 1000;
            left: 0;
            top: 0;
            width: 100%;
            height: 100%;
            overflow: auto;
            background-color: rgba(0,0,0,0.5);
        }

        .modal-content {
            background-color: #fefefe;
            margin: 10% auto;
            padding: 20px;
            border: 1px solid #888;
            width: 300px;
            position: relative;
        }

        .modal h3 {
            margin-top: 0;
        }

        .modal input, .modal button {
            width: 100%;
            margin-bottom: 10px;
            padding: 8px;
            box-sizing: border-box;
        }

        .modal-close {
            position: absolute;
            top: 5px;
            right: 10px;
            background: none;
            border: none;
            font-size: 20px;
            cursor: pointer;
        }

        /* Copy button */
        #copy-user-key {
            width: auto;
            background-color: #4CAF50;
            color: white;
            cursor: pointer;
        }

        #copy-user-key:hover {
            background-color: #45a049;
        }

    </style>
</head>
<body>
    <!-- Sidebar -->
    <div class="sidebar">
        <h2>Admin Panel</h2>
        <button id="add-user-btn">Add New User</button>
        <!-- Add more sidebar buttons or links as needed -->
    </div>

    <!-- Main content -->
    <div class="main-content">
        <h2>Users</h2>
        <div id="user-grid">
            <!-- User tiles will be dynamically added here -->
        </div>
    </div>

    <!-- User Creation Modal -->
    <div id="create-user-modal" class="modal">
        <div class="modal-content">
            <button class="modal-close">&times;</button>
            <h3>Add New User</h3>
            <input type="text" id="new-username" placeholder="Username">
            <input type="number" id="new-user-days" placeholder="Subscription Duration (days)">
            <button id="create-user-confirm">Create</button>
        </div>
    </div>

    <!-- Display User Key Modal -->
    <div id="user-key-modal" class="modal">
        <div class="modal-content">
            <button class="modal-close">&times;</button>
            <h3>User Key</h3>
            <input type="text" id="user-key-display" readonly>
            <button id="copy-user-key">Copy</button>
        </div>
    </div>

    <!-- Modal for Renew Subscription -->
    <div id="renew-modal" class="modal">
        <div class="modal-content">
            <button class="modal-close">&times;</button>
            <h3>Renew Subscription</h3>
            <p id="renew-user-info"></p>
            <input type="number" id="renew-days" placeholder="Days to renew">
            <button id="renew-confirm">Renew</button>
        </div>
    </div>

    <!-- Include any required JS libraries -->
    <script>
        const socket = io();

        const userGrid = document.getElementById('user-grid');
        const addUserBtn = document.getElementById('add-user-btn');

        // Modals
        const createUserModal = document.getElementById('create-user-modal');
        const userKeyModal = document.getElementById('user-key-modal');
        const renewModal = document.getElementById('renew-modal');

        let currentUserKey = null; // For actions like renew

        // Event listener for "Add New User" button
        addUserBtn.addEventListener('click', function() {
            createUserModal.style.display = 'block';
        });

        // Event listener for creating a new user
        document.getElementById('create-user-confirm').addEventListener('click', function() {
            const username = document.getElementById('new-username').value.trim();
            const days = parseInt(document.getElementById('new-user-days').value);

            if (!username || isNaN(days) || days <= 0) {
                alert('Please enter a valid username and subscription duration.');
                return;
            }

            fetch('/admin/add_user', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ username: username, days: days })
            })
            .then(response => response.json())
            .then(data => {
                if (data.status === 'ok') {
                    // Close the create user modal
                    createUserModal.style.display = 'none';
                    // Open the user key modal
                    document.getElementById('user-key-display').value = data.userKey;
                    userKeyModal.style.display = 'block';
                } else {
                    alert('Error creating user: ' + data.message);
                }
            });
        });

        // Event listener for copying the user key
        document.getElementById('copy-user-key').addEventListener('click', function() {
            const userKeyInput = document.getElementById('user-key-display');
            userKeyInput.select();
            userKeyInput.setSelectionRange(0, 99999); // For mobile devices

            document.execCommand('copy');
            alert('User key copied to clipboard.');
        });

        // Close modals when clicking on the close buttons
        document.querySelectorAll('.modal-close').forEach(function(btn) {
            btn.addEventListener('click', function() {
                this.parentElement.parentElement.style.display = 'none';
            });
        });

        // Handle clicks outside the modal content to close the modal
        window.onclick = function(event) {
            if (event.target === createUserModal) {
                createUserModal.style.display = 'none';
            } else if (event.target === userKeyModal) {
                userKeyModal.style.display = 'none';
            } else if (event.target === renewModal) {
                renewModal.style.display = 'none';
            }
        };

        // Socket.IO event for user updates
        socket.on('user_update', function(data) {
            let userTile = document.getElementById('user-' + data.key);
            if (!userTile) {
                userTile = document.createElement('div');
                userTile.id = 'user-' + data.key;
                userTile.className = 'user-tile';
                userTile.innerHTML = `
                    <h3>${data.username}</h3>
                    <p>IP: <span class="user-ip">${data.ip || 'N/A'}</span></p>
                    <p>Connected: <span class="user-connected">${data.is_connected || false}</span></p>
                    <p>Expires: <span class="user-expires">${formatDate(data.subscription_expires)}</span></p>
                    <p>Current URL: <span class="user-url">${data.current_url || 'N/A'}</span></p>
                    <div class="user-actions">
                        <button onclick="banUser('${data.key}')">${data.is_banned ? 'Unban' : 'Ban'}</button>
                        <button onclick="stopUser('${data.key}')">${data.is_stopped ? 'Unstop' : 'Stop'}</button>
                        <button onclick="openRenewModal('${data.key}', '${data.username}')">Renew</button>
                    </div>
                `;
                userGrid.appendChild(userTile);
            } else {
                userTile.querySelector('.user-ip').textContent = data.ip || 'N/A';
                userTile.querySelector('.user-connected').textContent = data.is_connected || false;
                userTile.querySelector('.user-expires').textContent = formatDate(data.subscription_expires);
                userTile.querySelector('.user-url').textContent = data.current_url || 'N/A';
                // Update action buttons
                userTile.querySelector('.user-actions').innerHTML = `
                    <button onclick="banUser('${data.key}')">${data.is_banned ? 'Unban' : 'Ban'}</button>
                    <button onclick="stopUser('${data.key}')">${data.is_stopped ? 'Unstop' : 'Stop'}</button>
                    <button onclick="openRenewModal('${data.key}', '${data.username}')">Renew</button>
                `;
            }
        });

        // Function to format date
        function formatDate(dateString) {
            const date = new Date(dateString);
            return date.toLocaleString();
        }

        // Functions for user actions
        function banUser(userKey) {
            fetch('/admin/action', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ action: 'ban', userKey: userKey })
            });
        }

        function stopUser(userKey) {
            fetch('/admin/action', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ action: 'stop', userKey: userKey })
            });
        }

        function openRenewModal(userKey, username) {
            currentUserKey = userKey;
            renewModal.style.display = 'block';
            document.getElementById('renew-user-info').textContent = `User: ${username}`;
            document.getElementById('renew-days').value = '';
        }

        // Renew subscription
        document.getElementById('renew-confirm').addEventListener('click', function() {
            const days = parseInt(document.getElementById('renew-days').value);
            if (isNaN(days) || days <= 0) {
                alert('Please enter a valid number of days.');
                return;
            }
            fetch('/admin/action', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ action: 'renew', userKey: currentUserKey, days: days })
            })
            .then(response => response.json())
            .then(data => {
                if (data.status === 'ok') {
                    renewModal.style.display = 'none';
                } else {
                    alert('Error renewing subscription: ' + data.message);
                }
            });
        });
    </script>
</body>
</html>
```


Вот код моего сервера для аутентификации VPN.
Можешь пожалуйста сделать рефакторинг, но API эндпоинты не меняй. Клиентская часть должна продолжать работать ничего не заметив.

Что необходимо изменить:
1) Добавить кнопку удаления пользователя
2) Добавить кнопку копирования ключа пользователя
3) Сделать sqlite3 базу данных(через отдельный класс и файл .py), который будет хранить информацию о пользователях, вместо простой переменной.

Сделай, в общем, все грамотно.
Я также прошу огромный html-файл разбить на файлы .css, .js.

Также, улучши дизайн, а то сейчас это очень просто.

Приведи код КАЖДОГО файла проекта полностью.
Спасибо!