Skip to content

Commit 9d34856

Browse files
authored
Merge pull request #106 from Zohair-coder/auth-usability
Improve authorization usability for new users
2 parents 926a43d + 87f130d commit 9d34856

File tree

4 files changed

+71
-6
lines changed

4 files changed

+71
-6
lines changed

README.md

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ pip install -r requirements.txt
2727

2828
## Usage
2929

30-
To run the scraper, simply run:
30+
First, [set up authentication](#Authentication).
31+
Then, to run the scraper, simply run:
3132

3233
###### Mac/Linux
3334
```bash
@@ -43,6 +44,36 @@ The scraper will output a JSON file called `data.json` in the same directory as
4344

4445
You can modify the scraper to scrape other terms by changing the `year`, `quarter`, and `college_code` variables in `src/config.py`.
4546

47+
#### Authentication
48+
49+
Since the term master schedule is only accessible to logged-in Drexel students, to run the scraper, you will need to provide your Drexel credentials as well as provide multi-factor authentication (MFA).
50+
51+
To provide your Drexel credentials, set the environment variable `DREXEL_USERNAME` to your Drexel username (abc123) and `DREXEL_PASSWORD` to the password you use to login to Drexel One. You can follow [this](https://phoenixnap.com/kb/windows-set-environment-variable) guide for Windows, and [this](https://phoenixnap.com/kb/set-environment-variable-mac) guide for MacOS to set environment variables.
52+
53+
There are two ways to provide MFA for the script to authenticate with. The first is easier if you're looking to run the script manually and quickly. The second is better if you are going to be running the script frequently, or if it needs to be automated.
54+
55+
###### Authenticate manually
56+
57+
You will authenticate the scraper manually as if you were logging into Drexel One, using a one-time code either from an authenticator app or that is texted to you. After setting the `DREXEL_USERNAME` and `DREXEL_PASSWORD` environment variables, run the scraper as explained [above](#Usage), and you will be prompted for your verification code.
58+
59+
###### Authenticate using a secret key
60+
61+
If you set this up, you will not need to manually enter an authentication code each time you run the scraper.
62+
63+
1. Go to [connect.drexel.edu](connect.drexel.edu).
64+
2. Click 'Help & Settings', then 'Change MFA settings'.
65+
3. Log in to the Microsoft portal, then click 'Add sign-in method' on the 'Security info' tab.
66+
4. Select 'Authenticator app' for the method, and click 'Add'.
67+
5. Select 'I want to use a different authenticator app', and then 'Next'.
68+
6. Select 'Can't scan image?' when prompted with a QR code, and you should see an Account name and Secret key.
69+
7. Set your `DREXEL_MFA_SECRET_KEY` environment variable to the given Secret key.
70+
8. Select 'Next', you should be prompted to enter an authentication code.
71+
9. With the secret key environment variable set, run `python3 src/totp.py` which will generate a one-time code.
72+
10. Enter this code into the Microsoft website, and select 'Next'
73+
11. 'Authenticator app' with TOTP should have been added to the list of available methods.
74+
75+
Now, when you run the scraper as explained [above](#Usage), it should authenticate itself automatically using this secret key.
76+
4677
#### All Colleges
4778

4879
To scrape all colleges instead of just the one specified in the `src/config.py`, run the following command:

src/config.py

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import os
2+
import sys
23

34
# in format YYYY (e.g. 2022)
45
# example value: 2022
@@ -15,10 +16,29 @@
1516
# example values = CI, A, AS
1617
college_code = "CI"
1718

19+
# Warn users if they have missing required environment variables
20+
environ_help_url = (
21+
"https://github.com/Zohair-coder/drexel-scraper?tab=readme-ov-file#authentication"
22+
)
23+
24+
25+
def get_environ(key: str, required: bool = True) -> str:
26+
if key in os.environ:
27+
return os.environ[key]
28+
elif required:
29+
print(
30+
f"{key} is missing from your environment variables and is required to run this script. See {environ_help_url} for more information and help."
31+
)
32+
sys.exit(1)
33+
else:
34+
return ""
35+
36+
1837
# Drexel Connect Credentials
19-
drexel_username = os.environ["DREXEL_USERNAME"]
20-
drexel_password = os.environ["DREXEL_PASSWORD"]
21-
drexel_mfa_secret_key = os.environ["DREXEL_MFA_SECRET_KEY"]
38+
drexel_username = get_environ("DREXEL_USERNAME")
39+
drexel_password = get_environ("DREXEL_PASSWORD")
40+
# This is not required if the user is using a separate authenticator app and will manually approve the login attempt
41+
drexel_mfa_secret_key = get_environ("DREXEL_MFA_SECRET_KEY", False) or None
2242

2343
# URL's
2444
tms_base_url = "https://termmasterschedule.drexel.edu"

src/login.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,15 @@ def login_with_drexel_connect(session: Session) -> Session:
7878

7979
parsed_data = parse_final_mfa_page(soup)
8080

81-
totp_code = totp.get_token(config.drexel_mfa_secret_key)
81+
if config.drexel_mfa_secret_key is not None:
82+
mfa_token = totp.get_token(config.drexel_mfa_secret_key)
83+
else:
84+
mfa_token = input("Please input your MFA verification code: ")
8285

8386
data = {
8487
"csrf_token": parsed_data["csrf_token"],
8588
"_eventId": "proceed",
86-
"j_mfaToken": totp_code,
89+
"j_mfaToken": mfa_token,
8790
}
8891

8992
# this request sends the MFA code to Drexel Connect

src/totp.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,14 @@ def get_token(secret: str) -> str:
1515
o = h[19] & 15
1616
h = (struct.unpack(">I", h[o : o + 4])[0] & 0x7FFFFFFF) % 1000000
1717
return str(h).zfill(6)
18+
19+
20+
if __name__ == "__main__":
21+
import config
22+
23+
if config.drexel_mfa_secret_key is not None:
24+
print(get_token(config.drexel_mfa_secret_key))
25+
else:
26+
print(
27+
f"Please set your MFA secret key to run this script. See {config.environ_help_url} for more information and help"
28+
)

0 commit comments

Comments
 (0)