system architecture
How Webportal sits on requests, encryption, and the model classes. Install: Getting started. Methods: Webportal class. Crypto: Encryption system.
Layers#
flowchart TB
subgraph public [Public]
Init["pyjiit.__init__"]
WP["Webportal"]
end
subgraph core [Core]
Hit["Webportal.__hit"]
Auth["@authenticated"]
Sess["WebportalSession"]
Enc["encryption.py"]
Utils["utils.py"]
end
subgraph models [Models]
Att["attendance.py"]
Exam["exam.py"]
Reg["registration.py"]
Cap["tokens.py"]
end
subgraph err [Errors]
Exc["exceptions.py"]
end
Init --> WP
WP --> Hit
WP --> Auth
WP --> Sess
Hit --> Enc
Enc --> Utils
WP --> Att
WP --> Exam
WP --> Reg
WP --> Cap
Hit --> Exc
Auth --> Exc__init__.py only re-exports Webportal. Everything else is imported from wrapper.py.
Webportal#
Webportal.__init__ sets self.session = None. __str__ returns "Driver Class for JIIT Webportal".
@authenticated wraps methods that need a session. If self.session is None, it raises NotLoggedIn. The expiry branch that would raise SessionExpired is commented out. The portal returns a JWT exp that does not match live cookies.
__hit is the shared HTTP path:
- Pick an exception class (
APIErrorunlessexception=is passed). - If
authenticated=True, mergeself.session.get_headers(). Else send onlyLocalName. requests.request(*args, **kwargs).json().- Integer
status == 401raisesSessionExpired. status.responseStatus != "Success"raises the chosen exception.- Return the parsed dict.
download_marks skips __hit and uses requests.get so it can return PDF bytes.
flowchart TD
M["Public method"] --> A{"@authenticated?"}
A -->|yes, session is None| NL["raise NotLoggedIn"]
A -->|yes, session set| H["__hit"]
A -->|no login/captcha| H
H --> R["requests.request"]
R --> J[".json()"]
J --> S401{"status == 401 int?"}
S401 -->|yes| SE["raise SessionExpired"]
S401 -->|no| OK{"responseStatus Success?"}
OK -->|no| EX["raise exception"]
OK -->|yes| RET["return resp"]WebportalSession#
Built from the login response dict.
| Attribute | Source |
|---|---|
raw_response |
Full response |
regdata |
resp["regdata"] |
institute, instituteid |
First institutelist entry label / value |
memberid |
regdata["memberid"] |
userid |
regdata["userid"] |
token |
JWT in regdata["token"] |
expiry |
exp claim from JWT payload, datetime.fromtimestamp |
clientid |
regdata["clientid"] |
membertype |
regdata["membertype"] |
name |
regdata["name"] |
get_headers() returns Authorization: Bearer {token} and a fresh LocalName.
classDiagram
class Webportal {
session
student_login()
get_captcha()
__hit()
}
class WebportalSession {
token
instituteid
memberid
clientid
expiry
get_headers()
}
Webportal --> WebportalSession : sessionEncryption module#
flowchart LR Dict["dict"] --> Ser["serialize_payload"] Ser --> JSON["json.dumps compact"] JSON --> Enc["encrypt AES-CBC"] Enc --> B64["base64"] B64 --> Wire["HTTP body"] Date["datetime.date"] --> Seq["generate_date_seq"] Seq --> Key["generate_key"] Rand["get_random_char_seq"] --> LN["generate_local_name"] Seq --> LN LN --> Enc2["encrypt then base64"]
| Function | Returns |
|---|---|
generate_key(date=None) |
16-byte AES key |
encrypt / decrypt |
padded / unpadded bytes |
serialize_payload(dict) |
base64 ciphertext string |
deserialize_payload(str) |
dict |
generate_local_name(date=None) |
base64 ciphertext for the header |
IV is constant b"dcek9wb8frty1pnm". Key string is "qa8y" + date_seq + "ty1pn".
Models#
Semester lives in attendance.py, not tokens.py.
classDiagram
class AttendanceHeader {
branchdesc
name
programdesc
stynumber
from_json()
}
class Semester {
registration_code
registration_id
from_json()
}
class AttendanceMeta {
headers
semesters
latest_header()
latest_semester()
}
class ExamEvent {
exam_event_code
event_from
exam_event_desc
registration_id
exam_event_id
from_json()
}
class RegisteredSubject {
employee_name
subject_code
credits
from_json()
}
class Registrations {
total_credits
subjects
}
class Captcha {
captcha
hidden
image
payload()
from_json()
}
AttendanceMeta --> AttendanceHeader
AttendanceMeta --> Semester
Registrations --> RegisteredSubjectException use#
flowchart LR Login["student_login"] --> LE["LoginError"] Auth["@authenticated"] --> NL["NotLoggedIn"] Hit["__hit 401"] --> SE["SessionExpired"] Pwd["set_password"] --> AE["AccountAPIError"] Other["other methods"] --> API["APIError"]
Authenticated call shape#
sequenceDiagram participant App participant WP as Webportal participant S as WebportalSession participant Enc as serialize_payload participant API as StudentPortalAPI App->>WP: get_attendance(header, semester) WP->>WP: @authenticated WP->>Enc: encrypt payload WP->>S: get_headers() WP->>API: POST /StudentClassAttendance/getstudentattendancedetail API-->>WP: JSON WP-->>App: resp["response"] dict
Not every method encrypts. get_student_bank_info, get_attendance_meta, set_password, and get_fee_summary send plain JSON. download_marks is a GET with path params.