116 lines
4.2 KiB
Python
116 lines
4.2 KiB
Python
# Native modules
|
|
import logging
|
|
import os
|
|
from typing import Dict, Any, Optional
|
|
|
|
# Third-party modules
|
|
import requests
|
|
from urllib.parse import urlencode
|
|
|
|
# Configuration constants (will be moved from crossfit_booker.py)
|
|
APPLICATION_ID = "81560887"
|
|
DEVICE_TYPE = "3"
|
|
APP_VERSION = "5.09.21"
|
|
|
|
class AuthHandler:
|
|
"""
|
|
A class for handling authentication with the CrossFit booking system.
|
|
This class is responsible for performing login, retrieving auth tokens,
|
|
and providing authentication headers.
|
|
"""
|
|
|
|
def __init__(self, username: str, password: str) -> None:
|
|
"""
|
|
Initialize the AuthHandler with credentials.
|
|
|
|
Args:
|
|
username (str): The username for authentication.
|
|
password (str): The password for authentication.
|
|
"""
|
|
self.username = username
|
|
self.password = password
|
|
self.auth_token: Optional[str] = None
|
|
self.user_id: Optional[str] = None
|
|
self.session = requests.Session()
|
|
self.base_headers: Dict[str, str] = {
|
|
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:140.0) Gecko/20100101 Firefox/140.0",
|
|
"Content-Type": "application/x-www-form-urlencoded",
|
|
"Nubapp-Origin": "user_apps",
|
|
}
|
|
self.session.headers.update(self.base_headers)
|
|
|
|
def get_auth_headers(self) -> Dict[str, str]:
|
|
"""
|
|
Return headers with authorization if available.
|
|
|
|
Returns:
|
|
Dict[str, str]: Headers dictionary with authorization if available.
|
|
"""
|
|
headers: Dict[str, str] = self.base_headers.copy()
|
|
if self.auth_token:
|
|
headers["Authorization"] = f"Bearer {self.auth_token}"
|
|
return headers
|
|
|
|
def login(self) -> bool:
|
|
"""
|
|
Authenticate and get the bearer token.
|
|
|
|
Returns:
|
|
bool: True if login is successful, False otherwise.
|
|
"""
|
|
try:
|
|
# First login endpoint
|
|
login_params: Dict[str, str] = {
|
|
"app_version": APP_VERSION,
|
|
"device_type": DEVICE_TYPE,
|
|
"username": self.username,
|
|
"password": self.password
|
|
}
|
|
|
|
response: requests.Response = self.session.post(
|
|
"https://sport.nubapp.com/api/v4/users/checkUser.php",
|
|
headers={"Content-Type": "application/x-www-form-urlencoded"},
|
|
data=urlencode(login_params))
|
|
|
|
if not response.ok:
|
|
logging.error(f"First login step failed: {response.status_code} - {response.text[:100]}")
|
|
return False
|
|
|
|
try:
|
|
login_data: Dict[str, Any] = response.json()
|
|
self.user_id = str(login_data["data"]["user"]["id_user"])
|
|
except (KeyError, ValueError) as e:
|
|
logging.error(f"Error during login: {str(e)} - Response: {response.text}")
|
|
return False
|
|
|
|
# Second login endpoint
|
|
response: requests.Response = self.session.post(
|
|
"https://sport.nubapp.com/api/v4/login",
|
|
headers={"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8"},
|
|
data=urlencode({
|
|
"device_type": DEVICE_TYPE,
|
|
"username": self.username,
|
|
"password": self.password
|
|
}))
|
|
|
|
if response.ok:
|
|
try:
|
|
login_data: Dict[str, Any] = response.json()
|
|
self.auth_token = login_data.get("token")
|
|
except (KeyError, ValueError) as e:
|
|
logging.error(f"Error during login: {str(e)} - Response: {response.text}")
|
|
return False
|
|
|
|
if self.auth_token and self.user_id:
|
|
logging.info("Successfully logged in")
|
|
return True
|
|
else:
|
|
logging.error(f"Login failed: {response.status_code} - {response.text[:100]}")
|
|
return False
|
|
|
|
except requests.exceptions.RequestException as e:
|
|
logging.error(f"Request error during login: {str(e)}")
|
|
return False
|
|
except Exception as e:
|
|
logging.error(f"Unexpected error during login: {str(e)}")
|
|
return False |