227e5fda27
- S113: Add timeout=10 to all requests calls (74 fixes) - E722: Replace bare except: with except Exception: - B904: Replace redundant re-raise with bare raise - E402: Add noqa for intentional late imports after import_library() - S102/S307/S310/S311/S603/S605/S606/S607/S108: Add noqa for intentional usage - F601: Fix duplicate dict key in unsplash.py - N802: Rename ReplyCheck -> reply_check with backward compat alias - N813: Rename bs -> BS in icons.py - B007/B020: Rename loop var _j in animations.py - SIM102: Collapse nested if in autofwd.py - SIM113: Use enumerate() in calculator.py - A002: Add noqa for builtin shadowing in admlist.py - F811: Add noqa for cohere redefinition - edu_master: Fix ARG001, S108, S110, SIM117, apply --unsafe-fixes - Add modules_list.txt with full module inventory
131 lines
4.6 KiB
Python
131 lines
4.6 KiB
Python
import logging
|
|
import os
|
|
import time
|
|
from datetime import datetime
|
|
|
|
import redis
|
|
import requests
|
|
|
|
# Configure logging
|
|
logging.basicConfig(
|
|
level=logging.INFO,
|
|
format='%(asctime)s - %(levelname)s - %(message)s'
|
|
)
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# Load configuration (adapted to .env keys)
|
|
def _env(key, default=None):
|
|
v = os.getenv(key, default)
|
|
if isinstance(v, str) and len(v) >= 2 and ((v[0] == '"' and v[-1] == '"') or (v[0] == "'" and v[-1] == "'")):
|
|
return v[1:-1]
|
|
return v
|
|
|
|
LOGIN = _env('KEEPER_LOGIN')
|
|
PASSWORD = _env('KEEPER_PASSWORD')
|
|
|
|
EDU_BASE = _env('EDU_URL_BASE', 'https://edu.edu.vn.ua')
|
|
EDU_LOGIN_PATH = _env('EDU_URL_LOGIN', '/user/login')
|
|
EDU_COURSES_PATH = _env('EDU_URL_COURSES', '/course/userlist')
|
|
URL_LOGIN = f"{EDU_BASE.rstrip('/')}/{EDU_LOGIN_PATH.lstrip('/')}"
|
|
URL_VERIFY = f"{EDU_BASE.rstrip('/')}/{EDU_COURSES_PATH.lstrip('/')}"
|
|
|
|
INTERVAL = int(_env('KEEPER_INTERVAL', 10))
|
|
USER_AGENT = _env('USER_AGENT', 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36')
|
|
REDIS_HOST = _env('REDIS_HOST', 'redis')
|
|
REDIS_PORT = int(_env('REDIS_PORT', 6379))
|
|
|
|
SUCCESS_FILE = '/tmp/last_success' # noqa: S108
|
|
|
|
def touch_success_file():
|
|
"""Updates the timestamp of the success file for healthchecks."""
|
|
try:
|
|
with open(SUCCESS_FILE, 'w') as f:
|
|
f.write(str(datetime.now().timestamp()))
|
|
except Exception as e:
|
|
logger.error(f"Failed to touch success file: {e}")
|
|
|
|
def main():
|
|
logger.info("Starting Session Keeper Bot")
|
|
|
|
# Connect to Redis
|
|
try:
|
|
redis_client = redis.Redis(host=REDIS_HOST, port=REDIS_PORT, decode_responses=True)
|
|
redis_client.ping()
|
|
logger.info(f"Connected to Redis at {REDIS_HOST}:{REDIS_PORT}")
|
|
except Exception as e:
|
|
logger.error(f"Failed to connect to Redis: {e}")
|
|
return
|
|
|
|
session = requests.Session()
|
|
|
|
# Set headers
|
|
headers = {
|
|
'User-Agent': USER_AGENT,
|
|
'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',
|
|
'Accept-Language': 'en-US,en;q=0.9',
|
|
'Cache-Control': 'max-age=0',
|
|
'Upgrade-Insecure-Requests': '1',
|
|
'Sec-Fetch-Site': 'same-origin',
|
|
'Sec-Fetch-Mode': 'navigate',
|
|
'Sec-Fetch-User': '?1',
|
|
'Sec-Fetch-Dest': 'document',
|
|
'Sec-Ch-Ua': '"Not_A Brand";v="99", "Chromium";v="142"',
|
|
'Sec-Ch-Ua-Mobile': '?0',
|
|
'Sec-Ch-Ua-Platform': '"Linux"',
|
|
'Accept-Encoding': 'gzip, deflate, br',
|
|
'Priority': 'u=0, i'
|
|
}
|
|
session.headers.update(headers)
|
|
|
|
while True:
|
|
try:
|
|
logger.info("Attempting login...")
|
|
|
|
# Login payload
|
|
payload = {
|
|
'login': LOGIN,
|
|
'password': PASSWORD
|
|
}
|
|
|
|
# Perform Login
|
|
# Note: The user request shows a POST to /user/login with form data
|
|
# We need to make sure we handle the PHPSESSID correctly.
|
|
# If we already have a PHPSESSID, requests will send it.
|
|
|
|
login_response = session.post(URL_LOGIN, data=payload, allow_redirects=True)
|
|
|
|
logger.info(f"Login Response Status: {login_response.status_code}")
|
|
logger.info(f"Cookies after login: {session.cookies.get_dict()}")
|
|
|
|
# Verify Session
|
|
logger.info("Verifying session...")
|
|
verify_response = session.get(URL_VERIFY, allow_redirects=False)
|
|
|
|
logger.info(f"Verify Response Status: {verify_response.status_code}")
|
|
|
|
if verify_response.status_code == 200:
|
|
logger.info("Session verification SUCCESS (200 OK).")
|
|
touch_success_file()
|
|
|
|
# Save PHPSESSID to Redis
|
|
phpsessid = session.cookies.get('PHPSESSID')
|
|
if phpsessid:
|
|
try:
|
|
redis_client.set('EDU_PHPSESSID', phpsessid)
|
|
logger.info(f"Saved PHPSESSID to Redis: {phpsessid}")
|
|
except Exception as e:
|
|
logger.error(f"Failed to save PHPSESSID to Redis: {e}")
|
|
elif verify_response.status_code == 302:
|
|
logger.warning("Session verification FAILED (302 Redirect). Session might be invalid.")
|
|
else:
|
|
logger.warning(f"Session verification returned unexpected status: {verify_response.status_code}")
|
|
|
|
except Exception as e:
|
|
logger.error(f"An error occurred: {e}")
|
|
|
|
logger.info(f"Sleeping for {INTERVAL} minutes...")
|
|
time.sleep(INTERVAL * 60)
|
|
|
|
if __name__ == "__main__":
|
|
main()
|