init, .gitignore
This commit is contained in:
commit
32aac89fdf
164 files changed
+18090
No files matched your search
@@ -0,0 +1,15 @@
|
||||
FROM python:3.11-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Устанавливаем зависимости
|
||||
RUN pip install --no-cache-dir flask requests
|
||||
|
||||
# Копируем код бота
|
||||
COPY main.py .
|
||||
|
||||
# Открываем порт
|
||||
EXPOSE 5000
|
||||
|
||||
# Запускаем бот
|
||||
CMD ["python", "-u", "main.py"]
|
||||
@@ -0,0 +1,216 @@
|
||||
import os
|
||||
import logging
|
||||
from flask import Flask, request, jsonify
|
||||
import requests
|
||||
from datetime import datetime
|
||||
|
||||
# Настройка логирования
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
# Конфигурация из переменных окружения
|
||||
EDU_HOST = os.getenv('EDU_HOST', 'edu.edu.vn.ua')
|
||||
EDU_LOGIN = os.getenv('EDU_LOGIN', '')
|
||||
EDU_PASSWORD = os.getenv('EDU_PASSWORD', '')
|
||||
BOT_PORT = int(os.getenv('BOT_PORT', '5000'))
|
||||
BOT_HOST = os.getenv('BOT_HOST', '0.0.0.0')
|
||||
|
||||
# Кэш для хранения актуальной сессии
|
||||
session_cache = {
|
||||
'phpsessid': None,
|
||||
'expires_at': None
|
||||
}
|
||||
|
||||
|
||||
def login_and_get_session():
|
||||
"""
|
||||
Выполняет логин и возвращает новый PHPSESSID
|
||||
"""
|
||||
url = f"https://{EDU_HOST}/user/login"
|
||||
|
||||
headers = {
|
||||
'Cache-Control': 'max-age=0',
|
||||
'Sec-Ch-Ua': '"Chromium";v="141", "Not?A_Brand";v="8"',
|
||||
'Sec-Ch-Ua-Mobile': '?0',
|
||||
'Sec-Ch-Ua-Platform': '"Linux"',
|
||||
'Accept-Language': 'ru-RU,ru;q=0.9',
|
||||
'Origin': f'https://{EDU_HOST}',
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
'Upgrade-Insecure-Requests': '1',
|
||||
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36',
|
||||
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
|
||||
'Sec-Fetch-Site': 'same-origin',
|
||||
'Sec-Fetch-Mode': 'navigate',
|
||||
'Sec-Fetch-User': '?1',
|
||||
'Sec-Fetch-Dest': 'document',
|
||||
'Referer': f'https://{EDU_HOST}/',
|
||||
'Accept-Encoding': 'gzip, deflate, br',
|
||||
'Priority': 'u=0, i'
|
||||
}
|
||||
|
||||
data = {
|
||||
'login': EDU_LOGIN,
|
||||
'password': EDU_PASSWORD
|
||||
}
|
||||
|
||||
try:
|
||||
logger.info(f"Attempting login to {url}")
|
||||
response = requests.post(
|
||||
url,
|
||||
data=data,
|
||||
headers=headers,
|
||||
allow_redirects=False,
|
||||
timeout=10
|
||||
)
|
||||
|
||||
# Получаем PHPSESSID из cookies
|
||||
phpsessid = response.cookies.get('PHPSESSID')
|
||||
|
||||
if phpsessid:
|
||||
logger.info(f"Login successful, got PHPSESSID: {phpsessid[:10]}...")
|
||||
return {
|
||||
'success': True,
|
||||
'phpsessid': phpsessid,
|
||||
'status_code': response.status_code
|
||||
}
|
||||
else:
|
||||
logger.warning(f"Login failed: no PHPSESSID in response. Status: {response.status_code}")
|
||||
return {
|
||||
'success': False,
|
||||
'error': 'No PHPSESSID in response',
|
||||
'status_code': response.status_code
|
||||
}
|
||||
|
||||
except requests.exceptions.RequestException as e:
|
||||
logger.error(f"Login request failed: {str(e)}")
|
||||
return {
|
||||
'success': False,
|
||||
'error': str(e)
|
||||
}
|
||||
|
||||
|
||||
def validate_phpsessid(phpsessid):
|
||||
"""
|
||||
Проверяет валидность существующего PHPSESSID
|
||||
"""
|
||||
url = f"https://{EDU_HOST}/"
|
||||
|
||||
headers = {
|
||||
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36',
|
||||
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
|
||||
}
|
||||
|
||||
cookies = {
|
||||
'PHPSESSID': phpsessid
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.get(url, headers=headers, cookies=cookies, timeout=10)
|
||||
|
||||
# Проверяем, не редиректит ли на страницу логина
|
||||
is_valid = response.status_code == 200 and '/user/login' not in response.url
|
||||
|
||||
return {
|
||||
'valid': is_valid,
|
||||
'status_code': response.status_code,
|
||||
'url': response.url
|
||||
}
|
||||
except requests.exceptions.RequestException as e:
|
||||
logger.error(f"Validation request failed: {str(e)}")
|
||||
return {
|
||||
'valid': False,
|
||||
'error': str(e)
|
||||
}
|
||||
|
||||
|
||||
@app.route('/health', methods=['GET'])
|
||||
def health():
|
||||
"""Health check endpoint"""
|
||||
return jsonify({'status': 'ok', 'timestamp': datetime.now().isoformat()})
|
||||
|
||||
|
||||
@app.route('/get-session', methods=['POST', 'GET'])
|
||||
def get_session():
|
||||
"""
|
||||
Основной endpoint для получения валидного PHPSESSID
|
||||
Возвращает кэшированную сессию или создает новую
|
||||
"""
|
||||
result = login_and_get_session()
|
||||
|
||||
if result['success']:
|
||||
session_cache['phpsessid'] = result['phpsessid']
|
||||
session_cache['last_updated'] = datetime.now().isoformat()
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'phpsessid': result['phpsessid'],
|
||||
'timestamp': datetime.now().isoformat()
|
||||
})
|
||||
else:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'error': result.get('error', 'Login failed'),
|
||||
'timestamp': datetime.now().isoformat()
|
||||
}), 400
|
||||
|
||||
|
||||
@app.route('/validate-session', methods=['POST'])
|
||||
def validate_session():
|
||||
"""
|
||||
Проверяет валидность переданного PHPSESSID
|
||||
"""
|
||||
data = request.get_json() or {}
|
||||
phpsessid = data.get('phpsessid') or request.args.get('phpsessid')
|
||||
|
||||
if not phpsessid:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'error': 'PHPSESSID not provided'
|
||||
}), 400
|
||||
|
||||
validation_result = validate_phpsessid(phpsessid)
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'valid': validation_result.get('valid', False),
|
||||
'details': validation_result,
|
||||
'timestamp': datetime.now().isoformat()
|
||||
})
|
||||
|
||||
|
||||
@app.route('/refresh-session', methods=['POST', 'GET'])
|
||||
def refresh_session():
|
||||
"""
|
||||
Принудительно обновляет сессию
|
||||
"""
|
||||
result = login_and_get_session()
|
||||
|
||||
if result['success']:
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'phpsessid': result['phpsessid'],
|
||||
'message': 'Session refreshed successfully',
|
||||
'timestamp': datetime.now().isoformat()
|
||||
})
|
||||
else:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'error': result.get('error', 'Failed to refresh session'),
|
||||
'timestamp': datetime.now().isoformat()
|
||||
}), 400
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if not EDU_LOGIN or not EDU_PASSWORD:
|
||||
logger.error("EDU_LOGIN and EDU_PASSWORD must be set!")
|
||||
exit(1)
|
||||
|
||||
logger.info(f"Starting PHPSESSID validator bot on {BOT_HOST}:{BOT_PORT}")
|
||||
logger.info(f"Target host: {EDU_HOST}")
|
||||
|
||||
app.run(host=BOT_HOST, port=BOT_PORT, debug=False)
|
||||
@@ -0,0 +1,3 @@
|
||||
flask==3.0.0
|
||||
requests==2.31.0
|
||||
Werkzeug==3.0.1
|
||||
Reference in new issue
Block a user