From 9f70bea72d9813bcbb37f823860e48275882b49c Mon Sep 17 00:00:00 2001 From: yannis300307 Date: Fri, 10 Nov 2023 15:31:18 +0100 Subject: [PATCH] Split code in two files --- alcasar.py | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++++ main.py | 105 +---------------------------------------------------- 2 files changed, 104 insertions(+), 104 deletions(-) create mode 100644 alcasar.py diff --git a/alcasar.py b/alcasar.py new file mode 100644 index 0000000..856fb7e --- /dev/null +++ b/alcasar.py @@ -0,0 +1,103 @@ +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 diff --git a/main.py b/main.py index 434da9b..7346637 100644 --- a/main.py +++ b/main.py @@ -1,107 +1,4 @@ -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 - +from alcasar import Alcasar, ConnectionResults, DisconnectResult if __name__ == '__main__': alcasar = Alcasar()