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 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.
@@ -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,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,2 @@
1
+ [console_scripts]
2
+ cv-check = cybervidya_checker.cli:main
@@ -0,0 +1,5 @@
1
+ requests>=2.31
2
+ pycryptodome>=3.19
3
+
4
+ [dev]
5
+ pytest>=8
@@ -0,0 +1 @@
1
+ cybervidya_checker
@@ -0,0 +1,7 @@
1
+ """CyberVidya (KIET) attendance checker.
2
+
3
+ Logs into kiet.cybervidya.net using the OTP emailed to the student account,
4
+ fetches today's per-subject attendance, and notifies when marked absent.
5
+ """
6
+
7
+ __version__ = "0.1.0"
@@ -0,0 +1,8 @@
1
+ """Allow running as ``python -m cybervidya_checker``."""
2
+
3
+ import sys
4
+
5
+ from cybervidya_checker.cli import main
6
+
7
+ if __name__ == "__main__":
8
+ sys.exit(main())