cv-check 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cv_check-0.1.0/LICENSE +21 -0
- cv_check-0.1.0/PKG-INFO +190 -0
- cv_check-0.1.0/README.md +168 -0
- cv_check-0.1.0/cv_check.egg-info/PKG-INFO +190 -0
- cv_check-0.1.0/cv_check.egg-info/SOURCES.txt +24 -0
- cv_check-0.1.0/cv_check.egg-info/dependency_links.txt +1 -0
- cv_check-0.1.0/cv_check.egg-info/entry_points.txt +2 -0
- cv_check-0.1.0/cv_check.egg-info/requires.txt +5 -0
- cv_check-0.1.0/cv_check.egg-info/top_level.txt +1 -0
- cv_check-0.1.0/cybervidya_checker/__init__.py +7 -0
- cv_check-0.1.0/cybervidya_checker/__main__.py +8 -0
- cv_check-0.1.0/cybervidya_checker/api.py +56 -0
- cv_check-0.1.0/cybervidya_checker/attendance.py +238 -0
- cv_check-0.1.0/cybervidya_checker/auth.py +189 -0
- cv_check-0.1.0/cybervidya_checker/cli.py +220 -0
- cv_check-0.1.0/cybervidya_checker/config.py +91 -0
- cv_check-0.1.0/cybervidya_checker/crypto.py +23 -0
- cv_check-0.1.0/cybervidya_checker/email_reader.py +373 -0
- cv_check-0.1.0/cybervidya_checker/notifier.py +62 -0
- cv_check-0.1.0/pyproject.toml +38 -0
- cv_check-0.1.0/setup.cfg +4 -0
- cv_check-0.1.0/tests/test_attendance.py +178 -0
- cv_check-0.1.0/tests/test_auth.py +51 -0
- cv_check-0.1.0/tests/test_config.py +55 -0
- cv_check-0.1.0/tests/test_crypto.py +17 -0
- cv_check-0.1.0/tests/test_email_reader.py +35 -0
cv_check-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Vansh Sahay
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
cv_check-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cv-check
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Checks KIET CyberVidya attendance daily and alerts when marked absent
|
|
5
|
+
Author: Vansh Sahay
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Keywords: attendance,kiet,cybervidya,college,notifications,otp
|
|
8
|
+
Classifier: Environment :: Console
|
|
9
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
10
|
+
Classifier: Operating System :: MacOS
|
|
11
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Topic :: Utilities
|
|
14
|
+
Requires-Python: >=3.10
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Requires-Dist: requests>=2.31
|
|
18
|
+
Requires-Dist: pycryptodome>=3.19
|
|
19
|
+
Provides-Extra: dev
|
|
20
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
21
|
+
Dynamic: license-file
|
|
22
|
+
|
|
23
|
+
# CyberVidya Attendance Checker (KIET)
|
|
24
|
+
|
|
25
|
+
> **Unofficial tool — not affiliated with KIET or CyberVidya.** It uses the same
|
|
26
|
+
> endpoints as the web app you log into yourself; use at your own discretion.
|
|
27
|
+
|
|
28
|
+
Logs into [kiet.cybervidya.net](https://kiet.cybervidya.net) using the OTP emailed to your
|
|
29
|
+
student account, fetches today's per-subject attendance, and notifies you when you've been
|
|
30
|
+
marked absent — via macOS notification, Telegram, and/or email.
|
|
31
|
+
|
|
32
|
+
Everything runs locally. Your credentials live only in `config.json` (mode 600) and are sent
|
|
33
|
+
only to the services they belong to (CyberVidya API, your Gmail, your chosen notification
|
|
34
|
+
channels).
|
|
35
|
+
|
|
36
|
+
## Install
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pipx install cv-check # or: pip install --user cv-check
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Then create a config (see `config.example.json` in the repo for all options):
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
cv-check setup-gmail # Gmail API OAuth for reading the OTP email (recommended)
|
|
46
|
+
# or set imap_app_password in config.json (app password)
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Config is looked up in `./config.json` or `~/.config/cybervidya/config.json`.
|
|
50
|
+
`api_base` defaults to the KIET endpoint and can be overridden for forks.
|
|
51
|
+
|
|
52
|
+
## How the login works (reverse-engineered from the site's Angular bundle)
|
|
53
|
+
|
|
54
|
+
1. `POST /api/auth/encrypt/login` — roll number + password encrypted with AES-128-CBC.
|
|
55
|
+
The key/iv are hardcoded in the site's JS (`cipherkey`/`cipheriv`), so no server-side
|
|
56
|
+
tricks are needed. (Verified: output is byte-identical to the site's own requests.)
|
|
57
|
+
2. The API emails a 6-digit OTP to your `@kiet.edu` inbox — the tool reads it via IMAP
|
|
58
|
+
(app password) or the Gmail API, and completes `POST /api/auth/verify/otp`.
|
|
59
|
+
3. Session: `Authorization: GlobalEducation <JWT>` + `UID: <id>` headers. The JWT lives
|
|
60
|
+
~5h, so it's cached in `session_cache.json` (mode 600) and reused.
|
|
61
|
+
|
|
62
|
+
Attendance comes from `POST /api/attendance/schedule/student/course/attendance/percentage`
|
|
63
|
+
per course component — it returns `lectureList[]` with `planLecDate`, `timeSlot` and
|
|
64
|
+
`attendance: PRESENT/ABSENT` per lecture. The student calendar
|
|
65
|
+
(`GET /api/student/schedule/class?weekStartDate=..&weekEndDate=..`) provides today's
|
|
66
|
+
schedule so lectures that are scheduled but not yet marked are reported separately.
|
|
67
|
+
|
|
68
|
+
Notes learned the hard way:
|
|
69
|
+
- **One active session per user**: logging in anywhere (the web UI *or* this tool) revokes
|
|
70
|
+
the previous session token. The tool re-logins automatically on 401.
|
|
71
|
+
- `student_id` is NOT in any API response — it's the numeric id shown in the attendance
|
|
72
|
+
percentage request payload in your browser devtools (config.json).
|
|
73
|
+
- The portal **rate-limits OTP emails** (~1/hour after several logins). The error is
|
|
74
|
+
reported clearly; the cached session usually avoids the need to log in again.
|
|
75
|
+
|
|
76
|
+
## Setup
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
./scripts/setup.sh # venv + install the package + create config.json
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Email access — pick whichever works for your account:
|
|
83
|
+
|
|
84
|
+
**A. Gmail API (OAuth) — recommended; works even where app passwords are blocked:**
|
|
85
|
+
```bash
|
|
86
|
+
# one-time Google Cloud setup (about 5 minutes):
|
|
87
|
+
# 1. console.cloud.google.com → create a project
|
|
88
|
+
# 2. APIs & Services → Library → enable "Gmail API"
|
|
89
|
+
# 3. OAuth consent screen → External → add your @kiet.edu as a test user
|
|
90
|
+
# 4. Credentials → Create credentials → OAuth client ID → "Desktop app"
|
|
91
|
+
# 5. Download the JSON → save as gmail_client_secret.json in this folder
|
|
92
|
+
cv-check setup-gmail # opens browser; one consent click
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**B. IMAP app password** (only if your account allows it):
|
|
96
|
+
```bash
|
|
97
|
+
# edit config.json: imap_user = your @kiet.edu, imap_app_password = App Password
|
|
98
|
+
# (myaccount.google.com/apppasswords — requires 2-Step Verification, and many
|
|
99
|
+
# Workspace admins / Google itself now disable these)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Then:
|
|
103
|
+
```bash
|
|
104
|
+
cv-check verify-login --verbose # test login once
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Usage
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
cv-check check # login (if needed) + check today + notify
|
|
111
|
+
cv-check check --no-notify # dry run
|
|
112
|
+
cv-check check --dump # save raw API responses (debugging)
|
|
113
|
+
cv-check check --otp 123456 # supply OTP manually
|
|
114
|
+
cv-check today # cached session only
|
|
115
|
+
cv-check watch # background watcher (see below)
|
|
116
|
+
cv-check --version
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Exit codes (useful for scripting): `0` all present / no classes · `1` error · `2` absent today.
|
|
120
|
+
|
|
121
|
+
## Background watcher (macOS, runs at login)
|
|
122
|
+
|
|
123
|
+
The recommended setup: a launchd agent that starts at login and keeps running,
|
|
124
|
+
polling every 10 minutes all day. It notifies **within minutes of an absence
|
|
125
|
+
being marked** (instead of waiting for a fixed evening time), and each absence
|
|
126
|
+
triggers exactly one notification per day.
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
./scripts/install_watch_launchd.sh
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Installs agent `com.user.cybervidya-attendance-watch` (RunAtLoad + KeepAlive —
|
|
133
|
+
restarts if it crashes). Logs:
|
|
134
|
+
`~/Library/Logs/com.user.cybervidya-attendance-watch.{stdout,stderr}.log`
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
tail -f ~/Library/Logs/com.user.cybervidya-attendance-watch.stderr.log
|
|
138
|
+
# uninstall:
|
|
139
|
+
launchctl unload ~/Library/LaunchAgents/com.user.cybervidya-attendance-watch.plist && rm ~/Library/LaunchAgents/com.user.cybervidya-attendance-watch.plist
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
How OTP usage works in watch mode: polling reuses the cached session (no OTPs).
|
|
143
|
+
A new login — and therefore a new OTP email — happens only when the ~5h JWT
|
|
144
|
+
expires or a web-UI login revokes it: roughly 2–4 OTP emails per day, well
|
|
145
|
+
under the portal's per-hour rate limit. If the limit is ever hit, the watcher
|
|
146
|
+
logs it and retries next cycle without crashing.
|
|
147
|
+
|
|
148
|
+
Prefer the old one-shot daily run instead? `./scripts/install_launchd.sh [HH:MM]`
|
|
149
|
+
(daily Mon–Sat at 17:30 by default) still works.
|
|
150
|
+
|
|
151
|
+
## Development
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
.venv/bin/pip install -e '.[dev]' # pytest
|
|
155
|
+
.venv/bin/python -m pytest # 25 offline tests (crypto vectors, OTP parsing, fixtures)
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Structure:
|
|
159
|
+
|
|
160
|
+
| module | responsibility |
|
|
161
|
+
|---|---|
|
|
162
|
+
| `cybervidya_checker/cli.py` | commands, exit codes, logging |
|
|
163
|
+
| `cybervidya_checker/config.py` | config loading + validation |
|
|
164
|
+
| `cybervidya_checker/crypto.py` | AES-128-CBC (site-compatible) |
|
|
165
|
+
| `cybervidya_checker/api.py` | HTTP client + typed errors (`ApiError`, `UnauthorizedError`) |
|
|
166
|
+
| `cybervidya_checker/auth.py` | login, OTP verify, session cache |
|
|
167
|
+
| `cybervidya_checker/email_reader.py` | IMAP + Gmail API OTP extraction, OAuth setup |
|
|
168
|
+
| `cybervidya_checker/attendance.py` | attendance endpoints, schedule cross-check |
|
|
169
|
+
| `cybervidya_checker/notifier.py` | macOS / Telegram / email channels |
|
|
170
|
+
| `tests/` | offline tests with real API fixtures (`tests/fixtures/`) |
|
|
171
|
+
|
|
172
|
+
## Files
|
|
173
|
+
|
|
174
|
+
| file | purpose |
|
|
175
|
+
|---|---|
|
|
176
|
+
| `config.json` | credentials + notification prefs (gitignore me!) |
|
|
177
|
+
| `session_cache.json` | cached JWT between runs (auto-created, mode 600) |
|
|
178
|
+
| `config.example.json` | template for config.json |
|
|
179
|
+
| `scripts/setup.sh`, `scripts/install_launchd.sh` | one-time setup + scheduler |
|
|
180
|
+
|
|
181
|
+
## Security notes
|
|
182
|
+
|
|
183
|
+
- Never commit `config.json` / `session_cache.json` / `gmail_*.json` — all hold secrets
|
|
184
|
+
(`.gitignore` covers them).
|
|
185
|
+
- The portal password is stored plaintext in `config.json` (like a `.netrc`); the file is
|
|
186
|
+
chmod 600. If this is shared publicly, prefer an env var or keychain integration later.
|
|
187
|
+
- The OTP email reader only searches for CyberVidya OTP mails (subject/from filter) — it
|
|
188
|
+
does not read your general inbox.
|
|
189
|
+
- If the portal password or app password leaks (e.g. pasted into a chat), rotate them:
|
|
190
|
+
portal password at the KIET helpdesk, app passwords at myaccount.google.com/apppasswords.
|
cv_check-0.1.0/README.md
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# CyberVidya Attendance Checker (KIET)
|
|
2
|
+
|
|
3
|
+
> **Unofficial tool — not affiliated with KIET or CyberVidya.** It uses the same
|
|
4
|
+
> endpoints as the web app you log into yourself; use at your own discretion.
|
|
5
|
+
|
|
6
|
+
Logs into [kiet.cybervidya.net](https://kiet.cybervidya.net) using the OTP emailed to your
|
|
7
|
+
student account, fetches today's per-subject attendance, and notifies you when you've been
|
|
8
|
+
marked absent — via macOS notification, Telegram, and/or email.
|
|
9
|
+
|
|
10
|
+
Everything runs locally. Your credentials live only in `config.json` (mode 600) and are sent
|
|
11
|
+
only to the services they belong to (CyberVidya API, your Gmail, your chosen notification
|
|
12
|
+
channels).
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pipx install cv-check # or: pip install --user cv-check
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Then create a config (see `config.example.json` in the repo for all options):
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
cv-check setup-gmail # Gmail API OAuth for reading the OTP email (recommended)
|
|
24
|
+
# or set imap_app_password in config.json (app password)
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Config is looked up in `./config.json` or `~/.config/cybervidya/config.json`.
|
|
28
|
+
`api_base` defaults to the KIET endpoint and can be overridden for forks.
|
|
29
|
+
|
|
30
|
+
## How the login works (reverse-engineered from the site's Angular bundle)
|
|
31
|
+
|
|
32
|
+
1. `POST /api/auth/encrypt/login` — roll number + password encrypted with AES-128-CBC.
|
|
33
|
+
The key/iv are hardcoded in the site's JS (`cipherkey`/`cipheriv`), so no server-side
|
|
34
|
+
tricks are needed. (Verified: output is byte-identical to the site's own requests.)
|
|
35
|
+
2. The API emails a 6-digit OTP to your `@kiet.edu` inbox — the tool reads it via IMAP
|
|
36
|
+
(app password) or the Gmail API, and completes `POST /api/auth/verify/otp`.
|
|
37
|
+
3. Session: `Authorization: GlobalEducation <JWT>` + `UID: <id>` headers. The JWT lives
|
|
38
|
+
~5h, so it's cached in `session_cache.json` (mode 600) and reused.
|
|
39
|
+
|
|
40
|
+
Attendance comes from `POST /api/attendance/schedule/student/course/attendance/percentage`
|
|
41
|
+
per course component — it returns `lectureList[]` with `planLecDate`, `timeSlot` and
|
|
42
|
+
`attendance: PRESENT/ABSENT` per lecture. The student calendar
|
|
43
|
+
(`GET /api/student/schedule/class?weekStartDate=..&weekEndDate=..`) provides today's
|
|
44
|
+
schedule so lectures that are scheduled but not yet marked are reported separately.
|
|
45
|
+
|
|
46
|
+
Notes learned the hard way:
|
|
47
|
+
- **One active session per user**: logging in anywhere (the web UI *or* this tool) revokes
|
|
48
|
+
the previous session token. The tool re-logins automatically on 401.
|
|
49
|
+
- `student_id` is NOT in any API response — it's the numeric id shown in the attendance
|
|
50
|
+
percentage request payload in your browser devtools (config.json).
|
|
51
|
+
- The portal **rate-limits OTP emails** (~1/hour after several logins). The error is
|
|
52
|
+
reported clearly; the cached session usually avoids the need to log in again.
|
|
53
|
+
|
|
54
|
+
## Setup
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
./scripts/setup.sh # venv + install the package + create config.json
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Email access — pick whichever works for your account:
|
|
61
|
+
|
|
62
|
+
**A. Gmail API (OAuth) — recommended; works even where app passwords are blocked:**
|
|
63
|
+
```bash
|
|
64
|
+
# one-time Google Cloud setup (about 5 minutes):
|
|
65
|
+
# 1. console.cloud.google.com → create a project
|
|
66
|
+
# 2. APIs & Services → Library → enable "Gmail API"
|
|
67
|
+
# 3. OAuth consent screen → External → add your @kiet.edu as a test user
|
|
68
|
+
# 4. Credentials → Create credentials → OAuth client ID → "Desktop app"
|
|
69
|
+
# 5. Download the JSON → save as gmail_client_secret.json in this folder
|
|
70
|
+
cv-check setup-gmail # opens browser; one consent click
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**B. IMAP app password** (only if your account allows it):
|
|
74
|
+
```bash
|
|
75
|
+
# edit config.json: imap_user = your @kiet.edu, imap_app_password = App Password
|
|
76
|
+
# (myaccount.google.com/apppasswords — requires 2-Step Verification, and many
|
|
77
|
+
# Workspace admins / Google itself now disable these)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Then:
|
|
81
|
+
```bash
|
|
82
|
+
cv-check verify-login --verbose # test login once
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Usage
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
cv-check check # login (if needed) + check today + notify
|
|
89
|
+
cv-check check --no-notify # dry run
|
|
90
|
+
cv-check check --dump # save raw API responses (debugging)
|
|
91
|
+
cv-check check --otp 123456 # supply OTP manually
|
|
92
|
+
cv-check today # cached session only
|
|
93
|
+
cv-check watch # background watcher (see below)
|
|
94
|
+
cv-check --version
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Exit codes (useful for scripting): `0` all present / no classes · `1` error · `2` absent today.
|
|
98
|
+
|
|
99
|
+
## Background watcher (macOS, runs at login)
|
|
100
|
+
|
|
101
|
+
The recommended setup: a launchd agent that starts at login and keeps running,
|
|
102
|
+
polling every 10 minutes all day. It notifies **within minutes of an absence
|
|
103
|
+
being marked** (instead of waiting for a fixed evening time), and each absence
|
|
104
|
+
triggers exactly one notification per day.
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
./scripts/install_watch_launchd.sh
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Installs agent `com.user.cybervidya-attendance-watch` (RunAtLoad + KeepAlive —
|
|
111
|
+
restarts if it crashes). Logs:
|
|
112
|
+
`~/Library/Logs/com.user.cybervidya-attendance-watch.{stdout,stderr}.log`
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
tail -f ~/Library/Logs/com.user.cybervidya-attendance-watch.stderr.log
|
|
116
|
+
# uninstall:
|
|
117
|
+
launchctl unload ~/Library/LaunchAgents/com.user.cybervidya-attendance-watch.plist && rm ~/Library/LaunchAgents/com.user.cybervidya-attendance-watch.plist
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
How OTP usage works in watch mode: polling reuses the cached session (no OTPs).
|
|
121
|
+
A new login — and therefore a new OTP email — happens only when the ~5h JWT
|
|
122
|
+
expires or a web-UI login revokes it: roughly 2–4 OTP emails per day, well
|
|
123
|
+
under the portal's per-hour rate limit. If the limit is ever hit, the watcher
|
|
124
|
+
logs it and retries next cycle without crashing.
|
|
125
|
+
|
|
126
|
+
Prefer the old one-shot daily run instead? `./scripts/install_launchd.sh [HH:MM]`
|
|
127
|
+
(daily Mon–Sat at 17:30 by default) still works.
|
|
128
|
+
|
|
129
|
+
## Development
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
.venv/bin/pip install -e '.[dev]' # pytest
|
|
133
|
+
.venv/bin/python -m pytest # 25 offline tests (crypto vectors, OTP parsing, fixtures)
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Structure:
|
|
137
|
+
|
|
138
|
+
| module | responsibility |
|
|
139
|
+
|---|---|
|
|
140
|
+
| `cybervidya_checker/cli.py` | commands, exit codes, logging |
|
|
141
|
+
| `cybervidya_checker/config.py` | config loading + validation |
|
|
142
|
+
| `cybervidya_checker/crypto.py` | AES-128-CBC (site-compatible) |
|
|
143
|
+
| `cybervidya_checker/api.py` | HTTP client + typed errors (`ApiError`, `UnauthorizedError`) |
|
|
144
|
+
| `cybervidya_checker/auth.py` | login, OTP verify, session cache |
|
|
145
|
+
| `cybervidya_checker/email_reader.py` | IMAP + Gmail API OTP extraction, OAuth setup |
|
|
146
|
+
| `cybervidya_checker/attendance.py` | attendance endpoints, schedule cross-check |
|
|
147
|
+
| `cybervidya_checker/notifier.py` | macOS / Telegram / email channels |
|
|
148
|
+
| `tests/` | offline tests with real API fixtures (`tests/fixtures/`) |
|
|
149
|
+
|
|
150
|
+
## Files
|
|
151
|
+
|
|
152
|
+
| file | purpose |
|
|
153
|
+
|---|---|
|
|
154
|
+
| `config.json` | credentials + notification prefs (gitignore me!) |
|
|
155
|
+
| `session_cache.json` | cached JWT between runs (auto-created, mode 600) |
|
|
156
|
+
| `config.example.json` | template for config.json |
|
|
157
|
+
| `scripts/setup.sh`, `scripts/install_launchd.sh` | one-time setup + scheduler |
|
|
158
|
+
|
|
159
|
+
## Security notes
|
|
160
|
+
|
|
161
|
+
- Never commit `config.json` / `session_cache.json` / `gmail_*.json` — all hold secrets
|
|
162
|
+
(`.gitignore` covers them).
|
|
163
|
+
- The portal password is stored plaintext in `config.json` (like a `.netrc`); the file is
|
|
164
|
+
chmod 600. If this is shared publicly, prefer an env var or keychain integration later.
|
|
165
|
+
- The OTP email reader only searches for CyberVidya OTP mails (subject/from filter) — it
|
|
166
|
+
does not read your general inbox.
|
|
167
|
+
- If the portal password or app password leaks (e.g. pasted into a chat), rotate them:
|
|
168
|
+
portal password at the KIET helpdesk, app passwords at myaccount.google.com/apppasswords.
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cv-check
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Checks KIET CyberVidya attendance daily and alerts when marked absent
|
|
5
|
+
Author: Vansh Sahay
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Keywords: attendance,kiet,cybervidya,college,notifications,otp
|
|
8
|
+
Classifier: Environment :: Console
|
|
9
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
10
|
+
Classifier: Operating System :: MacOS
|
|
11
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Topic :: Utilities
|
|
14
|
+
Requires-Python: >=3.10
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Requires-Dist: requests>=2.31
|
|
18
|
+
Requires-Dist: pycryptodome>=3.19
|
|
19
|
+
Provides-Extra: dev
|
|
20
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
21
|
+
Dynamic: license-file
|
|
22
|
+
|
|
23
|
+
# CyberVidya Attendance Checker (KIET)
|
|
24
|
+
|
|
25
|
+
> **Unofficial tool — not affiliated with KIET or CyberVidya.** It uses the same
|
|
26
|
+
> endpoints as the web app you log into yourself; use at your own discretion.
|
|
27
|
+
|
|
28
|
+
Logs into [kiet.cybervidya.net](https://kiet.cybervidya.net) using the OTP emailed to your
|
|
29
|
+
student account, fetches today's per-subject attendance, and notifies you when you've been
|
|
30
|
+
marked absent — via macOS notification, Telegram, and/or email.
|
|
31
|
+
|
|
32
|
+
Everything runs locally. Your credentials live only in `config.json` (mode 600) and are sent
|
|
33
|
+
only to the services they belong to (CyberVidya API, your Gmail, your chosen notification
|
|
34
|
+
channels).
|
|
35
|
+
|
|
36
|
+
## Install
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pipx install cv-check # or: pip install --user cv-check
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Then create a config (see `config.example.json` in the repo for all options):
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
cv-check setup-gmail # Gmail API OAuth for reading the OTP email (recommended)
|
|
46
|
+
# or set imap_app_password in config.json (app password)
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Config is looked up in `./config.json` or `~/.config/cybervidya/config.json`.
|
|
50
|
+
`api_base` defaults to the KIET endpoint and can be overridden for forks.
|
|
51
|
+
|
|
52
|
+
## How the login works (reverse-engineered from the site's Angular bundle)
|
|
53
|
+
|
|
54
|
+
1. `POST /api/auth/encrypt/login` — roll number + password encrypted with AES-128-CBC.
|
|
55
|
+
The key/iv are hardcoded in the site's JS (`cipherkey`/`cipheriv`), so no server-side
|
|
56
|
+
tricks are needed. (Verified: output is byte-identical to the site's own requests.)
|
|
57
|
+
2. The API emails a 6-digit OTP to your `@kiet.edu` inbox — the tool reads it via IMAP
|
|
58
|
+
(app password) or the Gmail API, and completes `POST /api/auth/verify/otp`.
|
|
59
|
+
3. Session: `Authorization: GlobalEducation <JWT>` + `UID: <id>` headers. The JWT lives
|
|
60
|
+
~5h, so it's cached in `session_cache.json` (mode 600) and reused.
|
|
61
|
+
|
|
62
|
+
Attendance comes from `POST /api/attendance/schedule/student/course/attendance/percentage`
|
|
63
|
+
per course component — it returns `lectureList[]` with `planLecDate`, `timeSlot` and
|
|
64
|
+
`attendance: PRESENT/ABSENT` per lecture. The student calendar
|
|
65
|
+
(`GET /api/student/schedule/class?weekStartDate=..&weekEndDate=..`) provides today's
|
|
66
|
+
schedule so lectures that are scheduled but not yet marked are reported separately.
|
|
67
|
+
|
|
68
|
+
Notes learned the hard way:
|
|
69
|
+
- **One active session per user**: logging in anywhere (the web UI *or* this tool) revokes
|
|
70
|
+
the previous session token. The tool re-logins automatically on 401.
|
|
71
|
+
- `student_id` is NOT in any API response — it's the numeric id shown in the attendance
|
|
72
|
+
percentage request payload in your browser devtools (config.json).
|
|
73
|
+
- The portal **rate-limits OTP emails** (~1/hour after several logins). The error is
|
|
74
|
+
reported clearly; the cached session usually avoids the need to log in again.
|
|
75
|
+
|
|
76
|
+
## Setup
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
./scripts/setup.sh # venv + install the package + create config.json
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Email access — pick whichever works for your account:
|
|
83
|
+
|
|
84
|
+
**A. Gmail API (OAuth) — recommended; works even where app passwords are blocked:**
|
|
85
|
+
```bash
|
|
86
|
+
# one-time Google Cloud setup (about 5 minutes):
|
|
87
|
+
# 1. console.cloud.google.com → create a project
|
|
88
|
+
# 2. APIs & Services → Library → enable "Gmail API"
|
|
89
|
+
# 3. OAuth consent screen → External → add your @kiet.edu as a test user
|
|
90
|
+
# 4. Credentials → Create credentials → OAuth client ID → "Desktop app"
|
|
91
|
+
# 5. Download the JSON → save as gmail_client_secret.json in this folder
|
|
92
|
+
cv-check setup-gmail # opens browser; one consent click
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**B. IMAP app password** (only if your account allows it):
|
|
96
|
+
```bash
|
|
97
|
+
# edit config.json: imap_user = your @kiet.edu, imap_app_password = App Password
|
|
98
|
+
# (myaccount.google.com/apppasswords — requires 2-Step Verification, and many
|
|
99
|
+
# Workspace admins / Google itself now disable these)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Then:
|
|
103
|
+
```bash
|
|
104
|
+
cv-check verify-login --verbose # test login once
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Usage
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
cv-check check # login (if needed) + check today + notify
|
|
111
|
+
cv-check check --no-notify # dry run
|
|
112
|
+
cv-check check --dump # save raw API responses (debugging)
|
|
113
|
+
cv-check check --otp 123456 # supply OTP manually
|
|
114
|
+
cv-check today # cached session only
|
|
115
|
+
cv-check watch # background watcher (see below)
|
|
116
|
+
cv-check --version
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Exit codes (useful for scripting): `0` all present / no classes · `1` error · `2` absent today.
|
|
120
|
+
|
|
121
|
+
## Background watcher (macOS, runs at login)
|
|
122
|
+
|
|
123
|
+
The recommended setup: a launchd agent that starts at login and keeps running,
|
|
124
|
+
polling every 10 minutes all day. It notifies **within minutes of an absence
|
|
125
|
+
being marked** (instead of waiting for a fixed evening time), and each absence
|
|
126
|
+
triggers exactly one notification per day.
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
./scripts/install_watch_launchd.sh
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Installs agent `com.user.cybervidya-attendance-watch` (RunAtLoad + KeepAlive —
|
|
133
|
+
restarts if it crashes). Logs:
|
|
134
|
+
`~/Library/Logs/com.user.cybervidya-attendance-watch.{stdout,stderr}.log`
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
tail -f ~/Library/Logs/com.user.cybervidya-attendance-watch.stderr.log
|
|
138
|
+
# uninstall:
|
|
139
|
+
launchctl unload ~/Library/LaunchAgents/com.user.cybervidya-attendance-watch.plist && rm ~/Library/LaunchAgents/com.user.cybervidya-attendance-watch.plist
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
How OTP usage works in watch mode: polling reuses the cached session (no OTPs).
|
|
143
|
+
A new login — and therefore a new OTP email — happens only when the ~5h JWT
|
|
144
|
+
expires or a web-UI login revokes it: roughly 2–4 OTP emails per day, well
|
|
145
|
+
under the portal's per-hour rate limit. If the limit is ever hit, the watcher
|
|
146
|
+
logs it and retries next cycle without crashing.
|
|
147
|
+
|
|
148
|
+
Prefer the old one-shot daily run instead? `./scripts/install_launchd.sh [HH:MM]`
|
|
149
|
+
(daily Mon–Sat at 17:30 by default) still works.
|
|
150
|
+
|
|
151
|
+
## Development
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
.venv/bin/pip install -e '.[dev]' # pytest
|
|
155
|
+
.venv/bin/python -m pytest # 25 offline tests (crypto vectors, OTP parsing, fixtures)
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Structure:
|
|
159
|
+
|
|
160
|
+
| module | responsibility |
|
|
161
|
+
|---|---|
|
|
162
|
+
| `cybervidya_checker/cli.py` | commands, exit codes, logging |
|
|
163
|
+
| `cybervidya_checker/config.py` | config loading + validation |
|
|
164
|
+
| `cybervidya_checker/crypto.py` | AES-128-CBC (site-compatible) |
|
|
165
|
+
| `cybervidya_checker/api.py` | HTTP client + typed errors (`ApiError`, `UnauthorizedError`) |
|
|
166
|
+
| `cybervidya_checker/auth.py` | login, OTP verify, session cache |
|
|
167
|
+
| `cybervidya_checker/email_reader.py` | IMAP + Gmail API OTP extraction, OAuth setup |
|
|
168
|
+
| `cybervidya_checker/attendance.py` | attendance endpoints, schedule cross-check |
|
|
169
|
+
| `cybervidya_checker/notifier.py` | macOS / Telegram / email channels |
|
|
170
|
+
| `tests/` | offline tests with real API fixtures (`tests/fixtures/`) |
|
|
171
|
+
|
|
172
|
+
## Files
|
|
173
|
+
|
|
174
|
+
| file | purpose |
|
|
175
|
+
|---|---|
|
|
176
|
+
| `config.json` | credentials + notification prefs (gitignore me!) |
|
|
177
|
+
| `session_cache.json` | cached JWT between runs (auto-created, mode 600) |
|
|
178
|
+
| `config.example.json` | template for config.json |
|
|
179
|
+
| `scripts/setup.sh`, `scripts/install_launchd.sh` | one-time setup + scheduler |
|
|
180
|
+
|
|
181
|
+
## Security notes
|
|
182
|
+
|
|
183
|
+
- Never commit `config.json` / `session_cache.json` / `gmail_*.json` — all hold secrets
|
|
184
|
+
(`.gitignore` covers them).
|
|
185
|
+
- The portal password is stored plaintext in `config.json` (like a `.netrc`); the file is
|
|
186
|
+
chmod 600. If this is shared publicly, prefer an env var or keychain integration later.
|
|
187
|
+
- The OTP email reader only searches for CyberVidya OTP mails (subject/from filter) — it
|
|
188
|
+
does not read your general inbox.
|
|
189
|
+
- If the portal password or app password leaks (e.g. pasted into a chat), rotate them:
|
|
190
|
+
portal password at the KIET helpdesk, app passwords at myaccount.google.com/apppasswords.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
cv_check.egg-info/PKG-INFO
|
|
5
|
+
cv_check.egg-info/SOURCES.txt
|
|
6
|
+
cv_check.egg-info/dependency_links.txt
|
|
7
|
+
cv_check.egg-info/entry_points.txt
|
|
8
|
+
cv_check.egg-info/requires.txt
|
|
9
|
+
cv_check.egg-info/top_level.txt
|
|
10
|
+
cybervidya_checker/__init__.py
|
|
11
|
+
cybervidya_checker/__main__.py
|
|
12
|
+
cybervidya_checker/api.py
|
|
13
|
+
cybervidya_checker/attendance.py
|
|
14
|
+
cybervidya_checker/auth.py
|
|
15
|
+
cybervidya_checker/cli.py
|
|
16
|
+
cybervidya_checker/config.py
|
|
17
|
+
cybervidya_checker/crypto.py
|
|
18
|
+
cybervidya_checker/email_reader.py
|
|
19
|
+
cybervidya_checker/notifier.py
|
|
20
|
+
tests/test_attendance.py
|
|
21
|
+
tests/test_auth.py
|
|
22
|
+
tests/test_config.py
|
|
23
|
+
tests/test_crypto.py
|
|
24
|
+
tests/test_email_reader.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
cybervidya_checker
|