import json from enum import Enum import requests from bs4 import BeautifulSoup class ConnectionResults(Enum): """Enumeration used for connection result""" CONNECTION_SUCCESS = 0 ALREADY_CONNECTED = 1 PACKET_ERROR = 2 BAD_PASSWORD = 3 CANT_DETECT_PORTAL = 4 class DisconnectResult(Enum): """Enumeration used for disconnection result""" DISCONNECT_SUCCESS = 0 NO_LOGOUT_LINK_AVAILABLE = 1 PACKET_ERROR = 2 class Alcasar: """Class used to manage the connection with the Alcasar service.""" def __init__(self): self.connection_statut = False self.logout_url = "" self.ses = requests.Session() self.ses.headers = {"Origin": "https://alcasar-0320002d.smile-education.fr", "Accept-Encoding": "gzip, deflate, br", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", "Sec-Fetch-Mode": "navigate", "Connection": "keep-alive", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/119.0", "Content-Type": "application/x-www-form-urlencoded", "Sec-Fetch-Site": "same-origin", "Sec-Fetch-Dest": "document", "Accept-Language": "fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3", "Sec-Fetch-User": "?1"} def connect(self, username, password): """Send username and password to the Alcasar authentication service.""" # Return if already connected self.update_statut() if self.connection_statut: return ConnectionResults.ALREADY_CONNECTED # Access the detection portal to be redirected to the authentication page. try: connection_page = self.ses.get("http://detectportal.firefox.com/canonical.html") except requests.exceptions.RequestException: return ConnectionResults.CANT_DETECT_PORTAL # We need a "challenge" value stored in a hidden input in the authentication # page to be sent to in the post request soup = BeautifulSoup(connection_page.text, features="html.parser") input_challenge = soup.find("input", {"name": "challenge"}) if input_challenge is None: return ConnectionResults.CANT_DETECT_PORTAL challenge = input_challenge["value"] # Send a post packet with username, password and challenge value to recover the redirection link data = f"challenge={challenge}&userurl=http%3A%2F%2Fdetectportal.firefox.com%2Fcanonical.html&username={username}&password={password}&button=Authentification" try: resp = self.ses.post("https://alcasar-0320002d.smile-education.fr/intercept.php", data=data, allow_redirects=False, headers={"Origin": "https://alcasar-0320002d.smile-education.fr", "Referer": connection_page.url}) except requests.exceptions.RequestException: return ConnectionResults.PACKET_ERROR # Send a get packet to connect to the account success = self.ses.get(resp.headers["Location"], allow_redirects=False) if success.headers["Location"].startswith("https://alcasar-0320002d.smile-education.fr/intercept.php?res=failed"): return ConnectionResults.BAD_PASSWORD return ConnectionResults.CONNECTION_SUCCESS def detect(self): """Return True if the current WI-FI network is managed by Alcasar.""" try: ping_result = self.ses.get("https://alcasar-0320002d.smile-education.fr/").status_code return ping_result == 200 except requests.exceptions.RequestException: return False def update_statut(self): """Update the connexion statut""" data = self.ses.get("http://alcasar-0320002d.smile-education.fr:3990/json/status?callback=chilliJSON.reply") statut = json.loads( data.text[17:-1]) self.connection_statut = statut["clientState"] self.logout_url = statut["redir"]["logoutURL"] def disconnect(self): """Disconnect the user from the authentication service""" if self.logout_url: try: self.ses.get(self.logout_url) return DisconnectResult.DISCONNECT_SUCCESS except requests.exceptions.RequestException: return DisconnectResult.PACKET_ERROR return DisconnectResult.NO_LOGOUT_LINK_AVAILABLE if __name__ == '__main__': alcasar = Alcasar() print("Checking if the computer is connected on an Alcasar WI-FI...") if alcasar.detect(): print("Alcasar Detected! Connecting...") result = alcasar.connect("BENDJEY", "Q8CSKR") # Check result match result: case ConnectionResults.CONNECTION_SUCCESS: print("Connected!") case ConnectionResults.CANT_DETECT_PORTAL: print("Unable to connect to the Alcasar authentication portal!") case ConnectionResults.ALREADY_CONNECTED: print("You are already connected!") case ConnectionResults.PACKET_ERROR: print("The connection has been refused!") case ConnectionResults.BAD_PASSWORD: print("Bad password!") input("disconnect ?") alcasar.disconnect()