From 96b532c28b2208ed844dd2249b7f6233b5486afb Mon Sep 17 00:00:00 2001 From: Marioneq Date: Sat, 8 Feb 2025 11:12:13 +0100 Subject: [PATCH 1/3] Delete old efeb session data after logging into prometheus --- sdk/src/interfaces/prometheus/interface.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sdk/src/interfaces/prometheus/interface.py b/sdk/src/interfaces/prometheus/interface.py index 18cb4c2..5c1b4ea 100644 --- a/sdk/src/interfaces/prometheus/interface.py +++ b/sdk/src/interfaces/prometheus/interface.py @@ -75,6 +75,10 @@ class PrometheusInterface(CoreInterface): result = self._login_prometheus(captcha) if result: return result + self._efeb_clients = {} + self._auth_context.efeb_web_cookies = {} + self._efeb_student_vars = {} + self._efeb_messages_vars = {} self._auth_context.prometheus_web_cookies = ( self._prometheus_web_client.get_cookies() From c58a24a4c6c09f091227fc7297e82f15e0ca4ea7 Mon Sep 17 00:00:00 2001 From: Marioneq Date: Sat, 8 Feb 2025 11:16:17 +0100 Subject: [PATCH 2/3] Revert "Merge branch 'main' of https://git.wpkg.ovh/Fuji/Fuji" This reverts commit 04c3c8e9274098fe5c6073f8300a5cbfcd3cef6d, reversing changes made to 96b532c28b2208ed844dd2249b7f6233b5486afb. --- {src/sdk => sdk}/src/README.md | 0 {src/sdk => sdk}/src/apis/common/models.py | 0 {src/sdk => sdk}/src/apis/common/utils.py | 0 {src/sdk => sdk}/src/apis/efeb/client.py | 0 {src/sdk => sdk}/src/apis/efeb/constants.py | 0 {src/sdk => sdk}/src/apis/efeb/utils.py | 0 {src/sdk => sdk}/src/apis/hebe/__init__.py | 0 {src/sdk => sdk}/src/apis/hebe/certificate.py | 0 {src/sdk => sdk}/src/apis/hebe/client.py | 0 {src/sdk => sdk}/src/apis/hebe/constants.py | 0 {src/sdk => sdk}/src/apis/hebe/exceptions.py | 0 {src/sdk => sdk}/src/apis/hebe/signer.py | 0 {src/sdk => sdk}/src/apis/hebe/student.py | 0 .../src/apis/prometheus_web/client.py | 0 .../src/apis/prometheus_web/constants.py | 0 .../src/apis/prometheus_web/exceptions.py | 0 .../src/interfaces/core/interface.py | 0 .../src/interfaces/prometheus/context.py | 0 .../src/interfaces/prometheus/exceptions.py | 0 .../src/interfaces/prometheus/interface.py | 0 .../src/interfaces/prometheus/utils.py | 0 {src/sdk => sdk}/src/models/exam.py | 0 {src/sdk => sdk}/src/models/grade.py | 0 {src/sdk => sdk}/src/models/note.py | 0 {src/sdk => sdk}/src/models/student.py | 0 src/impl/hebece/src/__init__.py | 0 src/impl/hebece/src/api.py | 152 ++++++++++++++++++ src/impl/hebece/src/const.py | 52 ++++++ src/impl/hebece/src/parser.py | 37 +++++ src/impl/hebece/src/signer.py | 98 +++++++++++ src/impl/hebece/src/utils.py | 54 +++++++ src/test.py | 37 +++++ 32 files changed, 430 insertions(+) rename {src/sdk => sdk}/src/README.md (100%) rename {src/sdk => sdk}/src/apis/common/models.py (100%) rename {src/sdk => sdk}/src/apis/common/utils.py (100%) rename {src/sdk => sdk}/src/apis/efeb/client.py (100%) rename {src/sdk => sdk}/src/apis/efeb/constants.py (100%) rename {src/sdk => sdk}/src/apis/efeb/utils.py (100%) rename {src/sdk => sdk}/src/apis/hebe/__init__.py (100%) rename {src/sdk => sdk}/src/apis/hebe/certificate.py (100%) rename {src/sdk => sdk}/src/apis/hebe/client.py (100%) rename {src/sdk => sdk}/src/apis/hebe/constants.py (100%) rename {src/sdk => sdk}/src/apis/hebe/exceptions.py (100%) rename {src/sdk => sdk}/src/apis/hebe/signer.py (100%) rename {src/sdk => sdk}/src/apis/hebe/student.py (100%) rename {src/sdk => sdk}/src/apis/prometheus_web/client.py (100%) rename {src/sdk => sdk}/src/apis/prometheus_web/constants.py (100%) rename {src/sdk => sdk}/src/apis/prometheus_web/exceptions.py (100%) rename {src/sdk => sdk}/src/interfaces/core/interface.py (100%) rename {src/sdk => sdk}/src/interfaces/prometheus/context.py (100%) rename {src/sdk => sdk}/src/interfaces/prometheus/exceptions.py (100%) rename {src/sdk => sdk}/src/interfaces/prometheus/interface.py (100%) rename {src/sdk => sdk}/src/interfaces/prometheus/utils.py (100%) rename {src/sdk => sdk}/src/models/exam.py (100%) rename {src/sdk => sdk}/src/models/grade.py (100%) rename {src/sdk => sdk}/src/models/note.py (100%) rename {src/sdk => sdk}/src/models/student.py (100%) create mode 100644 src/impl/hebece/src/__init__.py create mode 100644 src/impl/hebece/src/api.py create mode 100644 src/impl/hebece/src/const.py create mode 100644 src/impl/hebece/src/parser.py create mode 100644 src/impl/hebece/src/signer.py create mode 100644 src/impl/hebece/src/utils.py create mode 100644 src/test.py diff --git a/src/sdk/src/README.md b/sdk/src/README.md similarity index 100% rename from src/sdk/src/README.md rename to sdk/src/README.md diff --git a/src/sdk/src/apis/common/models.py b/sdk/src/apis/common/models.py similarity index 100% rename from src/sdk/src/apis/common/models.py rename to sdk/src/apis/common/models.py diff --git a/src/sdk/src/apis/common/utils.py b/sdk/src/apis/common/utils.py similarity index 100% rename from src/sdk/src/apis/common/utils.py rename to sdk/src/apis/common/utils.py diff --git a/src/sdk/src/apis/efeb/client.py b/sdk/src/apis/efeb/client.py similarity index 100% rename from src/sdk/src/apis/efeb/client.py rename to sdk/src/apis/efeb/client.py diff --git a/src/sdk/src/apis/efeb/constants.py b/sdk/src/apis/efeb/constants.py similarity index 100% rename from src/sdk/src/apis/efeb/constants.py rename to sdk/src/apis/efeb/constants.py diff --git a/src/sdk/src/apis/efeb/utils.py b/sdk/src/apis/efeb/utils.py similarity index 100% rename from src/sdk/src/apis/efeb/utils.py rename to sdk/src/apis/efeb/utils.py diff --git a/src/sdk/src/apis/hebe/__init__.py b/sdk/src/apis/hebe/__init__.py similarity index 100% rename from src/sdk/src/apis/hebe/__init__.py rename to sdk/src/apis/hebe/__init__.py diff --git a/src/sdk/src/apis/hebe/certificate.py b/sdk/src/apis/hebe/certificate.py similarity index 100% rename from src/sdk/src/apis/hebe/certificate.py rename to sdk/src/apis/hebe/certificate.py diff --git a/src/sdk/src/apis/hebe/client.py b/sdk/src/apis/hebe/client.py similarity index 100% rename from src/sdk/src/apis/hebe/client.py rename to sdk/src/apis/hebe/client.py diff --git a/src/sdk/src/apis/hebe/constants.py b/sdk/src/apis/hebe/constants.py similarity index 100% rename from src/sdk/src/apis/hebe/constants.py rename to sdk/src/apis/hebe/constants.py diff --git a/src/sdk/src/apis/hebe/exceptions.py b/sdk/src/apis/hebe/exceptions.py similarity index 100% rename from src/sdk/src/apis/hebe/exceptions.py rename to sdk/src/apis/hebe/exceptions.py diff --git a/src/sdk/src/apis/hebe/signer.py b/sdk/src/apis/hebe/signer.py similarity index 100% rename from src/sdk/src/apis/hebe/signer.py rename to sdk/src/apis/hebe/signer.py diff --git a/src/sdk/src/apis/hebe/student.py b/sdk/src/apis/hebe/student.py similarity index 100% rename from src/sdk/src/apis/hebe/student.py rename to sdk/src/apis/hebe/student.py diff --git a/src/sdk/src/apis/prometheus_web/client.py b/sdk/src/apis/prometheus_web/client.py similarity index 100% rename from src/sdk/src/apis/prometheus_web/client.py rename to sdk/src/apis/prometheus_web/client.py diff --git a/src/sdk/src/apis/prometheus_web/constants.py b/sdk/src/apis/prometheus_web/constants.py similarity index 100% rename from src/sdk/src/apis/prometheus_web/constants.py rename to sdk/src/apis/prometheus_web/constants.py diff --git a/src/sdk/src/apis/prometheus_web/exceptions.py b/sdk/src/apis/prometheus_web/exceptions.py similarity index 100% rename from src/sdk/src/apis/prometheus_web/exceptions.py rename to sdk/src/apis/prometheus_web/exceptions.py diff --git a/src/sdk/src/interfaces/core/interface.py b/sdk/src/interfaces/core/interface.py similarity index 100% rename from src/sdk/src/interfaces/core/interface.py rename to sdk/src/interfaces/core/interface.py diff --git a/src/sdk/src/interfaces/prometheus/context.py b/sdk/src/interfaces/prometheus/context.py similarity index 100% rename from src/sdk/src/interfaces/prometheus/context.py rename to sdk/src/interfaces/prometheus/context.py diff --git a/src/sdk/src/interfaces/prometheus/exceptions.py b/sdk/src/interfaces/prometheus/exceptions.py similarity index 100% rename from src/sdk/src/interfaces/prometheus/exceptions.py rename to sdk/src/interfaces/prometheus/exceptions.py diff --git a/src/sdk/src/interfaces/prometheus/interface.py b/sdk/src/interfaces/prometheus/interface.py similarity index 100% rename from src/sdk/src/interfaces/prometheus/interface.py rename to sdk/src/interfaces/prometheus/interface.py diff --git a/src/sdk/src/interfaces/prometheus/utils.py b/sdk/src/interfaces/prometheus/utils.py similarity index 100% rename from src/sdk/src/interfaces/prometheus/utils.py rename to sdk/src/interfaces/prometheus/utils.py diff --git a/src/sdk/src/models/exam.py b/sdk/src/models/exam.py similarity index 100% rename from src/sdk/src/models/exam.py rename to sdk/src/models/exam.py diff --git a/src/sdk/src/models/grade.py b/sdk/src/models/grade.py similarity index 100% rename from src/sdk/src/models/grade.py rename to sdk/src/models/grade.py diff --git a/src/sdk/src/models/note.py b/sdk/src/models/note.py similarity index 100% rename from src/sdk/src/models/note.py rename to sdk/src/models/note.py diff --git a/src/sdk/src/models/student.py b/sdk/src/models/student.py similarity index 100% rename from src/sdk/src/models/student.py rename to sdk/src/models/student.py diff --git a/src/impl/hebece/src/__init__.py b/src/impl/hebece/src/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/impl/hebece/src/api.py b/src/impl/hebece/src/api.py new file mode 100644 index 0000000..718f19e --- /dev/null +++ b/src/impl/hebece/src/api.py @@ -0,0 +1,152 @@ +from datetime import datetime +import requests +import json +from bs4 import BeautifulSoup +from impl.hebece.src.signer import * +from impl.hebece.src.utils import * +from impl.hebece.src.const import * + +session = requests.Session() +certificate, fingerprint, private_key = generate_key_pair() + +def getDebugInfo(data): + data = json.loads(data) + status = data.get("Status", {}) + code = status.get("Code") + message = status.get("Message") + return code, message + +def makeRequest(url): + digest, canonical_url, signature = get_signature_values(fingerprint, private_key, body=None, full_url=url, timestamp=datetime.now()) + + headers = makeHeader(signature, canonical_url) + + response = requests.get(url, headers=headers) + content = response.text + + dinfo = getDebugInfo(content) + return content, dinfo + +def APILogin(login, password): + + url = "https://eduvulcan.pl/" + response1 = session.get(url) + + url = "https://eduvulcan.pl/logowanie" + response2 = session.get(url) + + soup = BeautifulSoup(response2.text, 'html.parser') + token_input = soup.find('input', {'name': '__RequestVerificationToken'}) + token = {"__RequestVerificationToken": token_input['value']} + + cookies = {**response1.cookies.get_dict(), **response2.cookies.get_dict()} + cookies_str = "; ".join([f"{key}={value}" for key, value in cookies.items()]) + cookies_str += f"; __RequestVerificationToken={token_input['value']}" + + # Prometheus + url = "https://eduvulcan.pl/logowanie?ReturnUrl=%2fapi%2fap" + headers = makeLoginHeader(cookies_str) + + data = { + "Alias": login, + "Password": password, + "captchaUser": "", + "__RequestVerificationToken": token_input['value'], + } + + response = session.post(url, headers=headers, data=data) + content = response.text + cookie_jar = response.cookies.get_dict() + + try: + soup = BeautifulSoup(content, "html.parser") + input_element = soup.find("input", {"id": "ap"}) + value = input_element["value"] + parsed_json = json.loads(value) + + tokens = parsed_json.get("Tokens", []) + token = " ".join(tokens) + + return token + except TypeError: + pass + +def JWTLogin(token, debug=False): + tenant = get_tenant_from_jwt(token) + + url = f"https://lekcjaplus.vulcan.net.pl/{tenant}{JWT}" + + RequestId = getRandomIdentifier() + SelfIdentifier = getRandomIdentifier() + + Certificate = certificate + CertificateThumbprint = fingerprint + Tokens = token + + digest, canonical_url, signature = get_signature_values(fingerprint, private_key, body=None, full_url=url, timestamp=datetime.now()) + + headers = makeHeader(signature, canonical_url) + + timestamp = datetime.now() + date = getDate() + + body = { + "AppName": "DzienniczekPlus 3.0", + "AppVersion": "24.11.07 (G)", + "NotificationToken": None, + "API": 1, + "RequestId": str(RequestId), + "Timestamp": getTimestamp(), + "TimestampFormatted": str(date), + "Envelope": { + "OS": DEVICE_OS, + "Certificate": Certificate, + "CertificateType": "X509", + "DeviceModel": DEVICE, + "SelfIdentifier": str(SelfIdentifier), + "CertificateThumbprint": CertificateThumbprint, + "Tokens": [Tokens] + } + } + + body_json = json.dumps(body, indent=4) + + response = session.post(url, headers=headers, data=body_json) + content = response.text + + if debug: + dinfo = getDebugInfo(content) + return content, dinfo + + return content + +def HEBELogin(tenant, debug=False): + url = f"https://lekcjaplus.vulcan.net.pl/{tenant}{HEBE}?mode=2&lastSyncDate=1970-01-01%2001%3A00%3A00" + content, dinfo = makeRequest(url) + return content, dinfo + +def getLuckyNumber(tenant, schoolid, pupilid, constituentid, debug=False): + timestamp = datetime.now() + date = timestamp.strftime("%Y-%m-%d") + + url = f"https://lekcjaplus.vulcan.net.pl/{tenant}/{schoolid}{LUCKY}?pupilId={pupilid}&constituentId={constituentid}&day={date}" + content, dinfo = makeRequest(url) + return content, dinfo + +def getGrades(tenant, schoolid, pupilid, unitid, periodid, debug=False): + url = f"https://lekcjaplus.vulcan.net.pl/{tenant}/{schoolid}/api/mobile/grade/byPupil?unitId={unitid}&pupilId={pupilid}&periodId={periodid}&lastSyncDate=1970-01-01%2001%3A00%3A00&lastId=-2147483648&pageSize=500" + + content, dinfo = makeRequest(url) + return content, dinfo + +def getTimetable(tenant, schoolid, pupilid, start_date, end_date, debug=False): + url = f"https://lekcjaplus.vulcan.net.pl/{tenant}/{schoolid}/api/mobile/schedule/withchanges/byPupil?pupilId={pupilid}&dateFrom={start_date}&dateTo={end_date}&lastId=-2147483648&pageSize=500&lastSyncDate=1970-01-01%2001%3A00%3A00" + + content, dinfo = makeRequest(url) + return content, dinfo + +def getExams(tenant, schoolid, pupilid, start_date, end_date, debug=False): + url = f"https://lekcjaplus.vulcan.net.pl/{tenant}/{schoolid}/api/mobile/exam/byPupil?pupilId={pupilid}&dateFrom={start_date}&dateTo={end_date}&lastId=-2147483648&pageSize=500&lastSyncDate=1970-01-01%2001%3A00%3A00" + + content, dinfo = makeRequest(url) + return content, dinfo diff --git a/src/impl/hebece/src/const.py b/src/impl/hebece/src/const.py new file mode 100644 index 0000000..750d5cb --- /dev/null +++ b/src/impl/hebece/src/const.py @@ -0,0 +1,52 @@ +from impl.hebece.src.utils import * +# Endpoints + +JWT = "/api/mobile/register/jwt" +HEBE = "/api/mobile/register/hebe" +LUCKY = "/api/mobile/school/lucky" +GRADES = "/api/mobile/grade/byPupil" +TIMETABLE = "/api/mobile/schedule/withchanges/byPupil" +EXAMS = "/api/mobile/exam/byPupil" + +# Header +DEVICE = "SM-G935F" +DEVICE_OS = "Android" +APPVERSION = "24.11.07 (G)" + +def makeHeader(signature, canonical_url): + return { + "accept-encoding": "gzip", + "content-type": "application/json", + "host": "lekcjaplus.vulcan.net.pl", + "signature": signature, + "user-agent": "Dart/3.3 (dart:io)", + "vapi": "1", + "vcanonicalurl": canonical_url, + "vdate": getDate(), + "vos": DEVICE_OS, + "vversioncode": "640", + } + +def makeLoginHeader(cookies): + return { + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", + "Accept-Encoding": "gzip, deflate, br, zstd", + "Accept-Language": "en-US,en;q=0.9", + "Cache-Control": "max-age=0", + "Connection": "keep-alive", + "Content-Type": "application/x-www-form-urlencoded", + "Cookie": cookies, + "Host": "eduvulcan.pl", + "Origin": "https://eduvulcan.pl", + "Referer": "https://eduvulcan.pl/logowanie?ReturnUrl=%2fapi%2fap", + "sec-ch-ua": "\"Chromium\";v=\"130\", \"Android WebView\";v=\"130\", \"Not?A_Brand\";v=\"99\"", + "sec-ch-ua-mobile": "?1", + "sec-ch-ua-platform": "\"Android\"", + "Sec-Fetch-Dest": "document", + "Sec-Fetch-Mode": "navigate", + "Sec-Fetch-Site": "same-origin", + "Sec-Fetch-User": "?1", + "Upgrade-Insecure-Requests": "1", + "User-Agent": "Mozilla/5.0 (Linux; Android 13; SM-G935F Build/TQ3A.230901.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/130.0.6723.107 Mobile Safari/537.36", + "X-Requested-With": "pl.edu.vulcan.hebe.ce", + } \ No newline at end of file diff --git a/src/impl/hebece/src/parser.py b/src/impl/hebece/src/parser.py new file mode 100644 index 0000000..18cc204 --- /dev/null +++ b/src/impl/hebece/src/parser.py @@ -0,0 +1,37 @@ +import requests +import json +import uuid +import hashlib +import sqlite3 +import os +import base64 +from impl.hebece.src.signer import * +from impl.hebece.src.utils import * +from impl.hebece.src.api import * +from datetime import datetime, timedelta +from bs4 import BeautifulSoup + +def getUserInfo(tenant): + content, dinfo = HEBELogin(tenant) + + data = json.loads(content) + envelope = data.get("Envelope", [])[0] + + pupil = envelope.get("Pupil", {}) + unit = envelope.get("Unit", {}) + links = envelope.get("Links", {}) + ConstituentUnit = envelope.get("ConstituentUnit", {}) + periods = envelope.get("Periods", []) + + + Name = pupil.get("FirstName", {}) + SecondName = pupil.get("SecondName", {}) + Surname = pupil.get("Surname", {}) + Class = envelope.get("ClassDisplay", {}) + PupilID = pupil.get("Id", {}) + SchoolID = links.get("Symbol", {}) + ConstituentID = ConstituentUnit.get("Id", {}) + UnitID = unit.get("Id", {}) + PeriodID = next((period.get('Id') for period in periods if period.get('Current')), None) + + return Name, SecondName, Surname, Class, PupilID, SchoolID, ConstituentID, UnitID, PeriodID \ No newline at end of file diff --git a/src/impl/hebece/src/signer.py b/src/impl/hebece/src/signer.py new file mode 100644 index 0000000..dfc9369 --- /dev/null +++ b/src/impl/hebece/src/signer.py @@ -0,0 +1,98 @@ +import cryptography +import re +import urllib +import base64 +from OpenSSL import crypto +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.asymmetric import padding +from cryptography.hazmat.primitives.serialization import load_der_private_key +from cryptography.hazmat.backends import default_backend + + +def get_encoded_path(full_url): + path = re.search(r"(api/mobile/.+)", full_url) + if path is None: + raise ValueError( + "The URL does not seem correct (does not match `(api/mobile/.+)` regex)" + ) + return urllib.parse.quote(path[1], safe="").lower() + +def get_digest(body): + if not body: + return None + + m = hashlib.sha256() + m.update(bytes(body, "utf-8")) + return base64.b64encode(m.digest()).decode("utf-8") + +def get_headers_list(body, digest, canonical_url, timestamp): + sign_data = [ + ["vCanonicalUrl", canonical_url], + ["Digest", digest] if body else None, + ["vDate", timestamp.strftime("%a, %d %b %Y %H:%M:%S GMT")], + ] + + return ( + " ".join(item[0] for item in sign_data if item), + "".join(item[1] for item in sign_data if item), + ) + +def get_signature(data, private_key): + # Convert data to a string representatio + data_str = ( + json.dumps(data) + if isinstance(data, (dict, list)) + else str(data) + ) + + # Decode the base64 private key and load it + private_key_bytes = base64.b64decode(private_key) + pkcs8_key = load_der_private_key(private_key_bytes, password=None, backend=default_backend()) + + # Sign the data + signature = pkcs8_key.sign( + bytes(data_str, "utf-8"), + padding.PKCS1v15(), + hashes.SHA256() + ) + + # Encode the signature in base64 and return + return base64.b64encode(signature).decode("utf-8") + +def get_signature_values(fingerprint, private_key, body, full_url, timestamp): + canonical_url = get_encoded_path(full_url) + digest = get_digest(body) + headers, values = get_headers_list(body, digest, canonical_url, timestamp) + signature = get_signature(values, private_key) + + return ( + "SHA-256={}".format(digest) if digest else None, + canonical_url, + 'keyId="{}",headers="{}",algorithm="sha256withrsa",signature=Base64(SHA256withRSA({}))'.format( + fingerprint, headers, signature + ), + ) + +def pem_getraw(pem): + return pem.decode("utf-8").replace("\n", "").split("-----")[2] + +def generate_key_pair(): + pkcs8 = crypto.PKey() + pkcs8.generate_key(crypto.TYPE_RSA, 2048) + + x509 = crypto.X509() + x509.set_version(2) + x509.set_serial_number(1) + subject = x509.get_subject() + subject.CN = "APP_CERTIFICATE CA Certificate" + x509.set_issuer(subject) + x509.set_pubkey(pkcs8) + x509.sign(pkcs8, "sha256") + x509.gmtime_adj_notBefore(0) + x509.gmtime_adj_notAfter(20 * 365 * 24 * 60 * 60) + + certificate = pem_getraw(crypto.dump_certificate(crypto.FILETYPE_PEM, x509)) + fingerprint = x509.digest("sha1").decode("utf-8").replace(":", "").lower() + private_key = pem_getraw(crypto.dump_privatekey(crypto.FILETYPE_PEM, pkcs8)) + + return certificate, fingerprint, private_key diff --git a/src/impl/hebece/src/utils.py b/src/impl/hebece/src/utils.py new file mode 100644 index 0000000..1f240fd --- /dev/null +++ b/src/impl/hebece/src/utils.py @@ -0,0 +1,54 @@ +import base64 +import json +import uuid +from datetime import datetime, timedelta + +def encodebase64(data): + return base64.b64encode(data.encode("utf-8")).decode("utf-8") + +def decodebase64(data): + return base64.b64decode(data.encode("utf-8")).decode("utf-8") + +def get_tenant_from_jwt(token): + try: + # Split the JWT into parts + header, payload, signature = token.split('.') + + # Decode the payload from Base64 + # Add padding + payload += '=' * (-len(payload) % 4) + decoded_payload = base64.urlsafe_b64decode(payload).decode('utf-8') + + # Parse the payload as JSON + payload_json = json.loads(decoded_payload) + + # Return the tenant + return payload_json.get('tenant') + except (ValueError, json.JSONDecodeError, KeyError) as e: + print(f"Error decoding JWT: {e}") + return None + +def getRandomIdentifier(): + ruuid = str(uuid.uuid4()) + + return ruuid + +def get_current_week(): + # Get today's date + today = datetime.today() + # Calculate the start of the week (Monday) + start_of_week = today - timedelta(days=today.weekday()) + # Calculate the end of the week (Sunday) + end_of_week = start_of_week + timedelta(days=6) + + # Return the dates as formatted strings + return start_of_week.strftime('%Y-%m-%d'), end_of_week.strftime('%Y-%m-%d') + +def getDate(): + return datetime.now().strftime("%a, %d %b %Y %H:%M:%S GMT") + +def getTimestamp(): + now = datetime.now() + Timestamp = now.timestamp() + + return Timestamp \ No newline at end of file diff --git a/src/test.py b/src/test.py new file mode 100644 index 0000000..8599afb --- /dev/null +++ b/src/test.py @@ -0,0 +1,37 @@ +from impl.hebece.src.api import * +from impl.hebece.src.parser import * +from impl.hebece.src.utils import * +from impl.hebece.src.signer import * + +if __name__ == '__main__': + today = datetime.today().strftime('%d-%m-%y') + start_date, end_date = get_current_week() + + token = APILogin(login = input("login: "),password = input("password: ")) + if not token: + print("You entered wrong login, password or VULCAN asked for captcha. Verify your login and password and try to log into eduVULCAN from your browser.") + input("Press Enter to exit...") + exit() + + tenant = get_tenant_from_jwt(token) + + content, dinfoJWT = JWTLogin(token, debug=True) + + content, dinfoHEBE = HEBELogin(tenant, debug=True) + + Name, SecondName, Surname, Class, PupilID, SchoolID, ConstituentID, UnitID, PeriodID = getUserInfo(tenant) + + content, dinfoLUCK = getLuckyNumber(tenant=tenant, schoolid=SchoolID, pupilid=PupilID, constituentid=ConstituentID, debug=True) + + content, dinfoGRADE = getGrades(tenant=tenant, schoolid=SchoolID, pupilid=PupilID, unitid=UnitID, periodid=PeriodID, debug=True) + + content, dinfoTIME = getTimetable(tenant=tenant, schoolid=SchoolID, pupilid=PupilID, start_date=start_date, end_date=end_date, debug=True) + + content, dinfoEXAM = getExams(tenant=tenant, schoolid=SchoolID, pupilid=PupilID, start_date=start_date, end_date=end_date, debug=True) + + print(f"\nJWT Status: {dinfoJWT[0]} {dinfoJWT[1]}") + print(f"HEBE Status: {dinfoHEBE[0]} {dinfoHEBE[1]}") + print(f"Lucky Number Status: {dinfoLUCK[0]} {dinfoLUCK[1]}") + print(f"Grades Status: {dinfoGRADE[0]} {dinfoGRADE[1]}") + print(f"Timetable Status: {dinfoTIME[0]} {dinfoTIME[1]}") + print(f"Exams Status: {dinfoEXAM[0]} {dinfoEXAM[1]}") \ No newline at end of file From 330d4f694b8587eaeca86f78c1508785ed4ffcb7 Mon Sep 17 00:00:00 2001 From: Marioneq Date: Sat, 8 Feb 2025 11:19:13 +0100 Subject: [PATCH 3/3] Reapply "Merge branch 'main' of https://git.wpkg.ovh/Fuji/Fuji" This reverts commit c58a24a4c6c09f091227fc7297e82f15e0ca4ea7. --- src/impl/hebece/src/__init__.py | 0 src/impl/hebece/src/api.py | 152 ------------------ src/impl/hebece/src/const.py | 52 ------ src/impl/hebece/src/parser.py | 37 ----- src/impl/hebece/src/signer.py | 98 ----------- src/impl/hebece/src/utils.py | 54 ------- {sdk => src/sdk}/src/README.md | 0 {sdk => src/sdk}/src/apis/common/models.py | 0 {sdk => src/sdk}/src/apis/common/utils.py | 0 {sdk => src/sdk}/src/apis/efeb/client.py | 0 {sdk => src/sdk}/src/apis/efeb/constants.py | 0 {sdk => src/sdk}/src/apis/efeb/utils.py | 0 {sdk => src/sdk}/src/apis/hebe/__init__.py | 0 {sdk => src/sdk}/src/apis/hebe/certificate.py | 0 {sdk => src/sdk}/src/apis/hebe/client.py | 0 {sdk => src/sdk}/src/apis/hebe/constants.py | 0 {sdk => src/sdk}/src/apis/hebe/exceptions.py | 0 {sdk => src/sdk}/src/apis/hebe/signer.py | 0 {sdk => src/sdk}/src/apis/hebe/student.py | 0 .../sdk}/src/apis/prometheus_web/client.py | 0 .../sdk}/src/apis/prometheus_web/constants.py | 0 .../src/apis/prometheus_web/exceptions.py | 0 .../sdk}/src/interfaces/core/interface.py | 0 .../sdk}/src/interfaces/prometheus/context.py | 0 .../src/interfaces/prometheus/exceptions.py | 0 .../src/interfaces/prometheus/interface.py | 0 .../sdk}/src/interfaces/prometheus/utils.py | 0 {sdk => src/sdk}/src/models/exam.py | 0 {sdk => src/sdk}/src/models/grade.py | 0 {sdk => src/sdk}/src/models/note.py | 0 {sdk => src/sdk}/src/models/student.py | 0 src/test.py | 37 ----- 32 files changed, 430 deletions(-) delete mode 100644 src/impl/hebece/src/__init__.py delete mode 100644 src/impl/hebece/src/api.py delete mode 100644 src/impl/hebece/src/const.py delete mode 100644 src/impl/hebece/src/parser.py delete mode 100644 src/impl/hebece/src/signer.py delete mode 100644 src/impl/hebece/src/utils.py rename {sdk => src/sdk}/src/README.md (100%) rename {sdk => src/sdk}/src/apis/common/models.py (100%) rename {sdk => src/sdk}/src/apis/common/utils.py (100%) rename {sdk => src/sdk}/src/apis/efeb/client.py (100%) rename {sdk => src/sdk}/src/apis/efeb/constants.py (100%) rename {sdk => src/sdk}/src/apis/efeb/utils.py (100%) rename {sdk => src/sdk}/src/apis/hebe/__init__.py (100%) rename {sdk => src/sdk}/src/apis/hebe/certificate.py (100%) rename {sdk => src/sdk}/src/apis/hebe/client.py (100%) rename {sdk => src/sdk}/src/apis/hebe/constants.py (100%) rename {sdk => src/sdk}/src/apis/hebe/exceptions.py (100%) rename {sdk => src/sdk}/src/apis/hebe/signer.py (100%) rename {sdk => src/sdk}/src/apis/hebe/student.py (100%) rename {sdk => src/sdk}/src/apis/prometheus_web/client.py (100%) rename {sdk => src/sdk}/src/apis/prometheus_web/constants.py (100%) rename {sdk => src/sdk}/src/apis/prometheus_web/exceptions.py (100%) rename {sdk => src/sdk}/src/interfaces/core/interface.py (100%) rename {sdk => src/sdk}/src/interfaces/prometheus/context.py (100%) rename {sdk => src/sdk}/src/interfaces/prometheus/exceptions.py (100%) rename {sdk => src/sdk}/src/interfaces/prometheus/interface.py (100%) rename {sdk => src/sdk}/src/interfaces/prometheus/utils.py (100%) rename {sdk => src/sdk}/src/models/exam.py (100%) rename {sdk => src/sdk}/src/models/grade.py (100%) rename {sdk => src/sdk}/src/models/note.py (100%) rename {sdk => src/sdk}/src/models/student.py (100%) delete mode 100644 src/test.py diff --git a/src/impl/hebece/src/__init__.py b/src/impl/hebece/src/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/impl/hebece/src/api.py b/src/impl/hebece/src/api.py deleted file mode 100644 index 718f19e..0000000 --- a/src/impl/hebece/src/api.py +++ /dev/null @@ -1,152 +0,0 @@ -from datetime import datetime -import requests -import json -from bs4 import BeautifulSoup -from impl.hebece.src.signer import * -from impl.hebece.src.utils import * -from impl.hebece.src.const import * - -session = requests.Session() -certificate, fingerprint, private_key = generate_key_pair() - -def getDebugInfo(data): - data = json.loads(data) - status = data.get("Status", {}) - code = status.get("Code") - message = status.get("Message") - return code, message - -def makeRequest(url): - digest, canonical_url, signature = get_signature_values(fingerprint, private_key, body=None, full_url=url, timestamp=datetime.now()) - - headers = makeHeader(signature, canonical_url) - - response = requests.get(url, headers=headers) - content = response.text - - dinfo = getDebugInfo(content) - return content, dinfo - -def APILogin(login, password): - - url = "https://eduvulcan.pl/" - response1 = session.get(url) - - url = "https://eduvulcan.pl/logowanie" - response2 = session.get(url) - - soup = BeautifulSoup(response2.text, 'html.parser') - token_input = soup.find('input', {'name': '__RequestVerificationToken'}) - token = {"__RequestVerificationToken": token_input['value']} - - cookies = {**response1.cookies.get_dict(), **response2.cookies.get_dict()} - cookies_str = "; ".join([f"{key}={value}" for key, value in cookies.items()]) - cookies_str += f"; __RequestVerificationToken={token_input['value']}" - - # Prometheus - url = "https://eduvulcan.pl/logowanie?ReturnUrl=%2fapi%2fap" - headers = makeLoginHeader(cookies_str) - - data = { - "Alias": login, - "Password": password, - "captchaUser": "", - "__RequestVerificationToken": token_input['value'], - } - - response = session.post(url, headers=headers, data=data) - content = response.text - cookie_jar = response.cookies.get_dict() - - try: - soup = BeautifulSoup(content, "html.parser") - input_element = soup.find("input", {"id": "ap"}) - value = input_element["value"] - parsed_json = json.loads(value) - - tokens = parsed_json.get("Tokens", []) - token = " ".join(tokens) - - return token - except TypeError: - pass - -def JWTLogin(token, debug=False): - tenant = get_tenant_from_jwt(token) - - url = f"https://lekcjaplus.vulcan.net.pl/{tenant}{JWT}" - - RequestId = getRandomIdentifier() - SelfIdentifier = getRandomIdentifier() - - Certificate = certificate - CertificateThumbprint = fingerprint - Tokens = token - - digest, canonical_url, signature = get_signature_values(fingerprint, private_key, body=None, full_url=url, timestamp=datetime.now()) - - headers = makeHeader(signature, canonical_url) - - timestamp = datetime.now() - date = getDate() - - body = { - "AppName": "DzienniczekPlus 3.0", - "AppVersion": "24.11.07 (G)", - "NotificationToken": None, - "API": 1, - "RequestId": str(RequestId), - "Timestamp": getTimestamp(), - "TimestampFormatted": str(date), - "Envelope": { - "OS": DEVICE_OS, - "Certificate": Certificate, - "CertificateType": "X509", - "DeviceModel": DEVICE, - "SelfIdentifier": str(SelfIdentifier), - "CertificateThumbprint": CertificateThumbprint, - "Tokens": [Tokens] - } - } - - body_json = json.dumps(body, indent=4) - - response = session.post(url, headers=headers, data=body_json) - content = response.text - - if debug: - dinfo = getDebugInfo(content) - return content, dinfo - - return content - -def HEBELogin(tenant, debug=False): - url = f"https://lekcjaplus.vulcan.net.pl/{tenant}{HEBE}?mode=2&lastSyncDate=1970-01-01%2001%3A00%3A00" - content, dinfo = makeRequest(url) - return content, dinfo - -def getLuckyNumber(tenant, schoolid, pupilid, constituentid, debug=False): - timestamp = datetime.now() - date = timestamp.strftime("%Y-%m-%d") - - url = f"https://lekcjaplus.vulcan.net.pl/{tenant}/{schoolid}{LUCKY}?pupilId={pupilid}&constituentId={constituentid}&day={date}" - content, dinfo = makeRequest(url) - return content, dinfo - -def getGrades(tenant, schoolid, pupilid, unitid, periodid, debug=False): - url = f"https://lekcjaplus.vulcan.net.pl/{tenant}/{schoolid}/api/mobile/grade/byPupil?unitId={unitid}&pupilId={pupilid}&periodId={periodid}&lastSyncDate=1970-01-01%2001%3A00%3A00&lastId=-2147483648&pageSize=500" - - content, dinfo = makeRequest(url) - return content, dinfo - -def getTimetable(tenant, schoolid, pupilid, start_date, end_date, debug=False): - url = f"https://lekcjaplus.vulcan.net.pl/{tenant}/{schoolid}/api/mobile/schedule/withchanges/byPupil?pupilId={pupilid}&dateFrom={start_date}&dateTo={end_date}&lastId=-2147483648&pageSize=500&lastSyncDate=1970-01-01%2001%3A00%3A00" - - content, dinfo = makeRequest(url) - return content, dinfo - -def getExams(tenant, schoolid, pupilid, start_date, end_date, debug=False): - url = f"https://lekcjaplus.vulcan.net.pl/{tenant}/{schoolid}/api/mobile/exam/byPupil?pupilId={pupilid}&dateFrom={start_date}&dateTo={end_date}&lastId=-2147483648&pageSize=500&lastSyncDate=1970-01-01%2001%3A00%3A00" - - content, dinfo = makeRequest(url) - return content, dinfo diff --git a/src/impl/hebece/src/const.py b/src/impl/hebece/src/const.py deleted file mode 100644 index 750d5cb..0000000 --- a/src/impl/hebece/src/const.py +++ /dev/null @@ -1,52 +0,0 @@ -from impl.hebece.src.utils import * -# Endpoints - -JWT = "/api/mobile/register/jwt" -HEBE = "/api/mobile/register/hebe" -LUCKY = "/api/mobile/school/lucky" -GRADES = "/api/mobile/grade/byPupil" -TIMETABLE = "/api/mobile/schedule/withchanges/byPupil" -EXAMS = "/api/mobile/exam/byPupil" - -# Header -DEVICE = "SM-G935F" -DEVICE_OS = "Android" -APPVERSION = "24.11.07 (G)" - -def makeHeader(signature, canonical_url): - return { - "accept-encoding": "gzip", - "content-type": "application/json", - "host": "lekcjaplus.vulcan.net.pl", - "signature": signature, - "user-agent": "Dart/3.3 (dart:io)", - "vapi": "1", - "vcanonicalurl": canonical_url, - "vdate": getDate(), - "vos": DEVICE_OS, - "vversioncode": "640", - } - -def makeLoginHeader(cookies): - return { - "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", - "Accept-Encoding": "gzip, deflate, br, zstd", - "Accept-Language": "en-US,en;q=0.9", - "Cache-Control": "max-age=0", - "Connection": "keep-alive", - "Content-Type": "application/x-www-form-urlencoded", - "Cookie": cookies, - "Host": "eduvulcan.pl", - "Origin": "https://eduvulcan.pl", - "Referer": "https://eduvulcan.pl/logowanie?ReturnUrl=%2fapi%2fap", - "sec-ch-ua": "\"Chromium\";v=\"130\", \"Android WebView\";v=\"130\", \"Not?A_Brand\";v=\"99\"", - "sec-ch-ua-mobile": "?1", - "sec-ch-ua-platform": "\"Android\"", - "Sec-Fetch-Dest": "document", - "Sec-Fetch-Mode": "navigate", - "Sec-Fetch-Site": "same-origin", - "Sec-Fetch-User": "?1", - "Upgrade-Insecure-Requests": "1", - "User-Agent": "Mozilla/5.0 (Linux; Android 13; SM-G935F Build/TQ3A.230901.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/130.0.6723.107 Mobile Safari/537.36", - "X-Requested-With": "pl.edu.vulcan.hebe.ce", - } \ No newline at end of file diff --git a/src/impl/hebece/src/parser.py b/src/impl/hebece/src/parser.py deleted file mode 100644 index 18cc204..0000000 --- a/src/impl/hebece/src/parser.py +++ /dev/null @@ -1,37 +0,0 @@ -import requests -import json -import uuid -import hashlib -import sqlite3 -import os -import base64 -from impl.hebece.src.signer import * -from impl.hebece.src.utils import * -from impl.hebece.src.api import * -from datetime import datetime, timedelta -from bs4 import BeautifulSoup - -def getUserInfo(tenant): - content, dinfo = HEBELogin(tenant) - - data = json.loads(content) - envelope = data.get("Envelope", [])[0] - - pupil = envelope.get("Pupil", {}) - unit = envelope.get("Unit", {}) - links = envelope.get("Links", {}) - ConstituentUnit = envelope.get("ConstituentUnit", {}) - periods = envelope.get("Periods", []) - - - Name = pupil.get("FirstName", {}) - SecondName = pupil.get("SecondName", {}) - Surname = pupil.get("Surname", {}) - Class = envelope.get("ClassDisplay", {}) - PupilID = pupil.get("Id", {}) - SchoolID = links.get("Symbol", {}) - ConstituentID = ConstituentUnit.get("Id", {}) - UnitID = unit.get("Id", {}) - PeriodID = next((period.get('Id') for period in periods if period.get('Current')), None) - - return Name, SecondName, Surname, Class, PupilID, SchoolID, ConstituentID, UnitID, PeriodID \ No newline at end of file diff --git a/src/impl/hebece/src/signer.py b/src/impl/hebece/src/signer.py deleted file mode 100644 index dfc9369..0000000 --- a/src/impl/hebece/src/signer.py +++ /dev/null @@ -1,98 +0,0 @@ -import cryptography -import re -import urllib -import base64 -from OpenSSL import crypto -from cryptography.hazmat.primitives import hashes -from cryptography.hazmat.primitives.asymmetric import padding -from cryptography.hazmat.primitives.serialization import load_der_private_key -from cryptography.hazmat.backends import default_backend - - -def get_encoded_path(full_url): - path = re.search(r"(api/mobile/.+)", full_url) - if path is None: - raise ValueError( - "The URL does not seem correct (does not match `(api/mobile/.+)` regex)" - ) - return urllib.parse.quote(path[1], safe="").lower() - -def get_digest(body): - if not body: - return None - - m = hashlib.sha256() - m.update(bytes(body, "utf-8")) - return base64.b64encode(m.digest()).decode("utf-8") - -def get_headers_list(body, digest, canonical_url, timestamp): - sign_data = [ - ["vCanonicalUrl", canonical_url], - ["Digest", digest] if body else None, - ["vDate", timestamp.strftime("%a, %d %b %Y %H:%M:%S GMT")], - ] - - return ( - " ".join(item[0] for item in sign_data if item), - "".join(item[1] for item in sign_data if item), - ) - -def get_signature(data, private_key): - # Convert data to a string representatio - data_str = ( - json.dumps(data) - if isinstance(data, (dict, list)) - else str(data) - ) - - # Decode the base64 private key and load it - private_key_bytes = base64.b64decode(private_key) - pkcs8_key = load_der_private_key(private_key_bytes, password=None, backend=default_backend()) - - # Sign the data - signature = pkcs8_key.sign( - bytes(data_str, "utf-8"), - padding.PKCS1v15(), - hashes.SHA256() - ) - - # Encode the signature in base64 and return - return base64.b64encode(signature).decode("utf-8") - -def get_signature_values(fingerprint, private_key, body, full_url, timestamp): - canonical_url = get_encoded_path(full_url) - digest = get_digest(body) - headers, values = get_headers_list(body, digest, canonical_url, timestamp) - signature = get_signature(values, private_key) - - return ( - "SHA-256={}".format(digest) if digest else None, - canonical_url, - 'keyId="{}",headers="{}",algorithm="sha256withrsa",signature=Base64(SHA256withRSA({}))'.format( - fingerprint, headers, signature - ), - ) - -def pem_getraw(pem): - return pem.decode("utf-8").replace("\n", "").split("-----")[2] - -def generate_key_pair(): - pkcs8 = crypto.PKey() - pkcs8.generate_key(crypto.TYPE_RSA, 2048) - - x509 = crypto.X509() - x509.set_version(2) - x509.set_serial_number(1) - subject = x509.get_subject() - subject.CN = "APP_CERTIFICATE CA Certificate" - x509.set_issuer(subject) - x509.set_pubkey(pkcs8) - x509.sign(pkcs8, "sha256") - x509.gmtime_adj_notBefore(0) - x509.gmtime_adj_notAfter(20 * 365 * 24 * 60 * 60) - - certificate = pem_getraw(crypto.dump_certificate(crypto.FILETYPE_PEM, x509)) - fingerprint = x509.digest("sha1").decode("utf-8").replace(":", "").lower() - private_key = pem_getraw(crypto.dump_privatekey(crypto.FILETYPE_PEM, pkcs8)) - - return certificate, fingerprint, private_key diff --git a/src/impl/hebece/src/utils.py b/src/impl/hebece/src/utils.py deleted file mode 100644 index 1f240fd..0000000 --- a/src/impl/hebece/src/utils.py +++ /dev/null @@ -1,54 +0,0 @@ -import base64 -import json -import uuid -from datetime import datetime, timedelta - -def encodebase64(data): - return base64.b64encode(data.encode("utf-8")).decode("utf-8") - -def decodebase64(data): - return base64.b64decode(data.encode("utf-8")).decode("utf-8") - -def get_tenant_from_jwt(token): - try: - # Split the JWT into parts - header, payload, signature = token.split('.') - - # Decode the payload from Base64 - # Add padding - payload += '=' * (-len(payload) % 4) - decoded_payload = base64.urlsafe_b64decode(payload).decode('utf-8') - - # Parse the payload as JSON - payload_json = json.loads(decoded_payload) - - # Return the tenant - return payload_json.get('tenant') - except (ValueError, json.JSONDecodeError, KeyError) as e: - print(f"Error decoding JWT: {e}") - return None - -def getRandomIdentifier(): - ruuid = str(uuid.uuid4()) - - return ruuid - -def get_current_week(): - # Get today's date - today = datetime.today() - # Calculate the start of the week (Monday) - start_of_week = today - timedelta(days=today.weekday()) - # Calculate the end of the week (Sunday) - end_of_week = start_of_week + timedelta(days=6) - - # Return the dates as formatted strings - return start_of_week.strftime('%Y-%m-%d'), end_of_week.strftime('%Y-%m-%d') - -def getDate(): - return datetime.now().strftime("%a, %d %b %Y %H:%M:%S GMT") - -def getTimestamp(): - now = datetime.now() - Timestamp = now.timestamp() - - return Timestamp \ No newline at end of file diff --git a/sdk/src/README.md b/src/sdk/src/README.md similarity index 100% rename from sdk/src/README.md rename to src/sdk/src/README.md diff --git a/sdk/src/apis/common/models.py b/src/sdk/src/apis/common/models.py similarity index 100% rename from sdk/src/apis/common/models.py rename to src/sdk/src/apis/common/models.py diff --git a/sdk/src/apis/common/utils.py b/src/sdk/src/apis/common/utils.py similarity index 100% rename from sdk/src/apis/common/utils.py rename to src/sdk/src/apis/common/utils.py diff --git a/sdk/src/apis/efeb/client.py b/src/sdk/src/apis/efeb/client.py similarity index 100% rename from sdk/src/apis/efeb/client.py rename to src/sdk/src/apis/efeb/client.py diff --git a/sdk/src/apis/efeb/constants.py b/src/sdk/src/apis/efeb/constants.py similarity index 100% rename from sdk/src/apis/efeb/constants.py rename to src/sdk/src/apis/efeb/constants.py diff --git a/sdk/src/apis/efeb/utils.py b/src/sdk/src/apis/efeb/utils.py similarity index 100% rename from sdk/src/apis/efeb/utils.py rename to src/sdk/src/apis/efeb/utils.py diff --git a/sdk/src/apis/hebe/__init__.py b/src/sdk/src/apis/hebe/__init__.py similarity index 100% rename from sdk/src/apis/hebe/__init__.py rename to src/sdk/src/apis/hebe/__init__.py diff --git a/sdk/src/apis/hebe/certificate.py b/src/sdk/src/apis/hebe/certificate.py similarity index 100% rename from sdk/src/apis/hebe/certificate.py rename to src/sdk/src/apis/hebe/certificate.py diff --git a/sdk/src/apis/hebe/client.py b/src/sdk/src/apis/hebe/client.py similarity index 100% rename from sdk/src/apis/hebe/client.py rename to src/sdk/src/apis/hebe/client.py diff --git a/sdk/src/apis/hebe/constants.py b/src/sdk/src/apis/hebe/constants.py similarity index 100% rename from sdk/src/apis/hebe/constants.py rename to src/sdk/src/apis/hebe/constants.py diff --git a/sdk/src/apis/hebe/exceptions.py b/src/sdk/src/apis/hebe/exceptions.py similarity index 100% rename from sdk/src/apis/hebe/exceptions.py rename to src/sdk/src/apis/hebe/exceptions.py diff --git a/sdk/src/apis/hebe/signer.py b/src/sdk/src/apis/hebe/signer.py similarity index 100% rename from sdk/src/apis/hebe/signer.py rename to src/sdk/src/apis/hebe/signer.py diff --git a/sdk/src/apis/hebe/student.py b/src/sdk/src/apis/hebe/student.py similarity index 100% rename from sdk/src/apis/hebe/student.py rename to src/sdk/src/apis/hebe/student.py diff --git a/sdk/src/apis/prometheus_web/client.py b/src/sdk/src/apis/prometheus_web/client.py similarity index 100% rename from sdk/src/apis/prometheus_web/client.py rename to src/sdk/src/apis/prometheus_web/client.py diff --git a/sdk/src/apis/prometheus_web/constants.py b/src/sdk/src/apis/prometheus_web/constants.py similarity index 100% rename from sdk/src/apis/prometheus_web/constants.py rename to src/sdk/src/apis/prometheus_web/constants.py diff --git a/sdk/src/apis/prometheus_web/exceptions.py b/src/sdk/src/apis/prometheus_web/exceptions.py similarity index 100% rename from sdk/src/apis/prometheus_web/exceptions.py rename to src/sdk/src/apis/prometheus_web/exceptions.py diff --git a/sdk/src/interfaces/core/interface.py b/src/sdk/src/interfaces/core/interface.py similarity index 100% rename from sdk/src/interfaces/core/interface.py rename to src/sdk/src/interfaces/core/interface.py diff --git a/sdk/src/interfaces/prometheus/context.py b/src/sdk/src/interfaces/prometheus/context.py similarity index 100% rename from sdk/src/interfaces/prometheus/context.py rename to src/sdk/src/interfaces/prometheus/context.py diff --git a/sdk/src/interfaces/prometheus/exceptions.py b/src/sdk/src/interfaces/prometheus/exceptions.py similarity index 100% rename from sdk/src/interfaces/prometheus/exceptions.py rename to src/sdk/src/interfaces/prometheus/exceptions.py diff --git a/sdk/src/interfaces/prometheus/interface.py b/src/sdk/src/interfaces/prometheus/interface.py similarity index 100% rename from sdk/src/interfaces/prometheus/interface.py rename to src/sdk/src/interfaces/prometheus/interface.py diff --git a/sdk/src/interfaces/prometheus/utils.py b/src/sdk/src/interfaces/prometheus/utils.py similarity index 100% rename from sdk/src/interfaces/prometheus/utils.py rename to src/sdk/src/interfaces/prometheus/utils.py diff --git a/sdk/src/models/exam.py b/src/sdk/src/models/exam.py similarity index 100% rename from sdk/src/models/exam.py rename to src/sdk/src/models/exam.py diff --git a/sdk/src/models/grade.py b/src/sdk/src/models/grade.py similarity index 100% rename from sdk/src/models/grade.py rename to src/sdk/src/models/grade.py diff --git a/sdk/src/models/note.py b/src/sdk/src/models/note.py similarity index 100% rename from sdk/src/models/note.py rename to src/sdk/src/models/note.py diff --git a/sdk/src/models/student.py b/src/sdk/src/models/student.py similarity index 100% rename from sdk/src/models/student.py rename to src/sdk/src/models/student.py diff --git a/src/test.py b/src/test.py deleted file mode 100644 index 8599afb..0000000 --- a/src/test.py +++ /dev/null @@ -1,37 +0,0 @@ -from impl.hebece.src.api import * -from impl.hebece.src.parser import * -from impl.hebece.src.utils import * -from impl.hebece.src.signer import * - -if __name__ == '__main__': - today = datetime.today().strftime('%d-%m-%y') - start_date, end_date = get_current_week() - - token = APILogin(login = input("login: "),password = input("password: ")) - if not token: - print("You entered wrong login, password or VULCAN asked for captcha. Verify your login and password and try to log into eduVULCAN from your browser.") - input("Press Enter to exit...") - exit() - - tenant = get_tenant_from_jwt(token) - - content, dinfoJWT = JWTLogin(token, debug=True) - - content, dinfoHEBE = HEBELogin(tenant, debug=True) - - Name, SecondName, Surname, Class, PupilID, SchoolID, ConstituentID, UnitID, PeriodID = getUserInfo(tenant) - - content, dinfoLUCK = getLuckyNumber(tenant=tenant, schoolid=SchoolID, pupilid=PupilID, constituentid=ConstituentID, debug=True) - - content, dinfoGRADE = getGrades(tenant=tenant, schoolid=SchoolID, pupilid=PupilID, unitid=UnitID, periodid=PeriodID, debug=True) - - content, dinfoTIME = getTimetable(tenant=tenant, schoolid=SchoolID, pupilid=PupilID, start_date=start_date, end_date=end_date, debug=True) - - content, dinfoEXAM = getExams(tenant=tenant, schoolid=SchoolID, pupilid=PupilID, start_date=start_date, end_date=end_date, debug=True) - - print(f"\nJWT Status: {dinfoJWT[0]} {dinfoJWT[1]}") - print(f"HEBE Status: {dinfoHEBE[0]} {dinfoHEBE[1]}") - print(f"Lucky Number Status: {dinfoLUCK[0]} {dinfoLUCK[1]}") - print(f"Grades Status: {dinfoGRADE[0]} {dinfoGRADE[1]}") - print(f"Timetable Status: {dinfoTIME[0]} {dinfoTIME[1]}") - print(f"Exams Status: {dinfoEXAM[0]} {dinfoEXAM[1]}") \ No newline at end of file