Reorganized code in classes with control method for Alcasar API and added error handling

This commit is contained in:
Yannis 2023-11-10 15:20:24 +01:00
parent 814504f23b
commit 3d51550295

121
main.py
View file

@ -1,43 +1,128 @@
import json import json
from enum import Enum
import requests import requests
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
username = "username"
password = "password"
ses = requests.Session() class ConnectionResults(Enum):
ses.headers = {"Origin": "https://alcasar-0320002d.smile-education.fr", "Accept-Encoding": "gzip, deflate, br", """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", "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", "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", "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", "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-Dest": "document", "Accept-Language": "fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3",
"Sec-Fetch-User": "?1"} "Sec-Fetch-User": "?1"}
connection_page = ses.get("http://detectportal.firefox.com/canonical.html")
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") soup = BeautifulSoup(connection_page.text, features="html.parser")
input_challenge = soup.find("input", {"name": "challenge"}) input_challenge = soup.find("input", {"name": "challenge"})
if input_challenge is None:
return ConnectionResults.CANT_DETECT_PORTAL
challenge = input_challenge["value"] 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" data = f"challenge={challenge}&userurl=http%3A%2F%2Fdetectportal.firefox.com%2Fcanonical.html&username={username}&password={password}&button=Authentification"
resp = ses.post("https://alcasar-0320002d.smile-education.fr/intercept.php", try:
resp = self.ses.post("https://alcasar-0320002d.smile-education.fr/intercept.php",
data=data, data=data,
allow_redirects=False, headers={"Origin": "https://alcasar-0320002d.smile-education.fr", allow_redirects=False,
headers={"Origin": "https://alcasar-0320002d.smile-education.fr",
"Referer": connection_page.url}) "Referer": connection_page.url})
except requests.exceptions.RequestException:
return ConnectionResults.PACKET_ERROR
print(resp.text) # Send a get packet to connect to the account
redirect = resp.headers["Location"] 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
print(redirect) return ConnectionResults.CONNECTION_SUCCESS
ses.get(redirect) 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( statut = json.loads(
ses.get("http://alcasar-0320002d.smile-education.fr:3990/json/status?callback=chilliJSON.reply").text[17:-1]) data.text[17:-1])
if statut["clientState"]: self.connection_statut = statut["clientState"]
print("Successfully connected!") self.logout_url = statut["redir"]["logoutURL"]
else:
print("An error occured") 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()