Split code in two files
This commit is contained in:
parent
3d51550295
commit
9f70bea72d
103
alcasar.py
Normal file
103
alcasar.py
Normal file
|
@ -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
|
105
main.py
105
main.py
|
@ -1,107 +1,4 @@
|
||||||
import json
|
from alcasar import Alcasar, ConnectionResults, DisconnectResult
|
||||||
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__':
|
if __name__ == '__main__':
|
||||||
alcasar = Alcasar()
|
alcasar = Alcasar()
|
||||||
|
|
Loading…
Reference in a new issue