diff --git a/.gitignore b/.gitignore index e5b177a..a6027b4 100644 --- a/.gitignore +++ b/.gitignore @@ -44,6 +44,9 @@ logs/ .env.local .env.backup +# Auth config (contains passwords) +LichessWebView/auth_config.json + # Node modules (если будут использоваться) node_modules/ diff --git a/LichessWebView/app.py b/LichessWebView/app.py index 23f6ab6..94a2158 100644 --- a/LichessWebView/app.py +++ b/LichessWebView/app.py @@ -1,14 +1,29 @@ -from flask import Flask, jsonify, render_template +from flask import Flask, jsonify, render_template, request, session, redirect, url_for from flask_cors import CORS import sqlite3 from datetime import datetime, date +from functools import wraps +import os +import auth_config app = Flask(__name__) +# Secret key для сессий (в продакшене лучше использовать переменную окружения) +app.secret_key = os.environ.get('FLASK_SECRET_KEY', 'your-secret-key-change-in-production-please') CORS(app) # Путь к базе данных бота DB_PATH = "/app/data/lichess_bot.db" + +def login_required(f): + """Декоратор для защиты роутов, требующих аутентификации""" + @wraps(f) + def decorated_function(*args, **kwargs): + if 'authenticated' not in session or not session['authenticated']: + return redirect(url_for('login')) + return f(*args, **kwargs) + return decorated_function + def get_message_counters_stats(db_path): """Get message counters statistics directly from database""" try: @@ -97,12 +112,45 @@ def get_message_counters_stats(db_path): 'by_command': {} } +@app.route('/login', methods=['GET', 'POST']) +def login(): + """Страница входа""" + if request.method == 'POST': + username = request.form.get('username', '').strip() + password = request.form.get('password', '') + + if auth_config.validate_credentials(username, password): + session['authenticated'] = True + session['username'] = username + return redirect(url_for('index')) + else: + error_msg = 'Неверный логин или пароль' + return redirect(url_for('login', error=error_msg)) + + # GET запрос - показать форму логина + error = request.args.get('error', '') + # Если уже авторизован, перенаправляем на главную + if 'authenticated' in session and session.get('authenticated'): + return redirect(url_for('index')) + return render_template('login.html', error=error) + + +@app.route('/logout') +def logout(): + """Выход из системы""" + session.pop('authenticated', None) + session.pop('username', None) + return redirect(url_for('login')) + + @app.route('/') +@login_required def index(): """Главная страница""" return render_template('index.html') @app.route('/api/users') +@login_required def get_users(): """Получить всех пользователей""" try: @@ -217,6 +265,7 @@ def get_users(): }), 500 @app.route('/api/users//gamers') +@login_required def get_user_gamers(user_id): """Получить игроков конкретного пользователя""" try: diff --git a/LichessWebView/auth_config.example.json b/LichessWebView/auth_config.example.json new file mode 100644 index 0000000..a33c8e2 --- /dev/null +++ b/LichessWebView/auth_config.example.json @@ -0,0 +1,13 @@ +{ + "users": [ + { + "username": "admin", + "password": "change_me_123" + }, + { + "username": "user2", + "password": "another_password" + } + ] +} + diff --git a/LichessWebView/auth_config.py b/LichessWebView/auth_config.py new file mode 100644 index 0000000..f44caaa --- /dev/null +++ b/LichessWebView/auth_config.py @@ -0,0 +1,60 @@ +"""Модуль для загрузки конфигурации аутентификации""" +import json +import os +from typing import Dict, List, Optional + +AUTH_CONFIG_PATH = "/app/auth_config.json" +AUTH_CONFIG_EXAMPLE_PATH = "/app/auth_config.example.json" + + +def load_auth_config() -> Optional[Dict]: + """ + Загружает конфигурацию аутентификации из файла. + Возвращает None, если файл не найден. + """ + config_path = AUTH_CONFIG_PATH + + # Если файл не существует, пробуем example + if not os.path.exists(config_path): + if os.path.exists(AUTH_CONFIG_EXAMPLE_PATH): + print(f"Warning: {config_path} not found, using example config") + config_path = AUTH_CONFIG_EXAMPLE_PATH + else: + print(f"Error: Neither {AUTH_CONFIG_PATH} nor {AUTH_CONFIG_EXAMPLE_PATH} found") + return None + + try: + with open(config_path, 'r', encoding='utf-8') as f: + config = json.load(f) + return config + except json.JSONDecodeError as e: + print(f"Error parsing auth config: {e}") + return None + except Exception as e: + print(f"Error loading auth config: {e}") + return None + + +def get_users() -> List[Dict[str, str]]: + """ + Возвращает список пользователей из конфига. + """ + config = load_auth_config() + if not config: + return [] + + return config.get('users', []) + + +def validate_credentials(username: str, password: str) -> bool: + """ + Проверяет правильность логина и пароля. + """ + users = get_users() + + for user in users: + if user.get('username') == username and user.get('password') == password: + return True + + return False + diff --git a/LichessWebView/templates/index.html b/LichessWebView/templates/index.html index 2121284..565a22f 100644 --- a/LichessWebView/templates/index.html +++ b/LichessWebView/templates/index.html @@ -282,7 +282,10 @@
-

👥 Пользователи

+
+

👥 Пользователи

+ Выход +
Всего пользователей: 0 (сегодня: 0)
diff --git a/LichessWebView/templates/login.html b/LichessWebView/templates/login.html new file mode 100644 index 0000000..4f15abc --- /dev/null +++ b/LichessWebView/templates/login.html @@ -0,0 +1,152 @@ + + + + + + Вход в админ-панель + + + + + + + + +