Skip to content

Commit

Permalink
docs(readme): update webapp workflow
Browse files Browse the repository at this point in the history
  • Loading branch information
proffapt committed Jul 10, 2024
1 parent c5c5100 commit 313e820
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 85 deletions.
155 changes: 73 additions & 82 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ while True:

## Using in WebApps

To implement the login workflow for `web applications` and `backend systems`, utilize the [session_manager](./src/iitkgp_erp_login/session_manager.py) module.
To implement the login workflow for `web applications` and `backend systems`, utilize the modularised implementation of this package.

<div id="implementing-login-workflow-for-webapps"></div>

Expand All @@ -350,23 +350,18 @@ Following is a proof of concept example to achieve the login workflow:

```python
import logging
from flask_cors import CORS
import requests
import iitkgp_erp_login.erp as erp
from flask import Flask, request, jsonify
from iitkgp_erp_login import session_manager

import iitkgp_erp_login.utils as erp_utils

app = Flask(__name__)
CORS(app)

jwt_secret_key = "top-secret-unhackable-key"
headers = {
'timeout': '20',
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/51.0.2704.79 Chrome/51.0.2704.79 Safari/537.36',
}

session_manager = session_manager.SessionManager(
jwt_secret_key=jwt_secret_key, headers=headers)


class ErpResponse:
def __init__(self, success: bool, message: str = None, data: dict = None, status_code: int = 200):
Expand All @@ -380,9 +375,10 @@ class ErpResponse:

def to_dict(self):
response = {
"status": "success" if self.success else "error",
"message": self.message
"status": "success" if self.success else "error"
}
if self.message:
response.update({"message": self.message})
if self.data:
response.update(self.data)
return response
Expand All @@ -391,19 +387,6 @@ class ErpResponse:
return jsonify(self.to_dict()), self.status_code


def handle_auth() -> ErpResponse:
if "Authorization" in request.headers:
header = request.headers["Authorization"].split(" ")
if len(header) == 2:
return ErpResponse(True, data={
"jwt": header[1]
}).to_response()
else:
return ErpResponse(False, "Poorly formatted authorization header. Should be of format 'Bearer <token>'", status_code=401).to_response()
else:
return ErpResponse(False, "Authentication token not provided", status_code=401).to_response()


@app.route("/secret-question", methods=["POST"])
def get_secret_question():
try:
Expand All @@ -412,11 +395,14 @@ def get_secret_question():
if not roll_number:
return ErpResponse(False, "Roll Number not provided", status_code=400).to_response()

secret_question, jwt = session_manager.get_secret_question(
roll_number)
session = requests.Session()
secret_question = erp.get_secret_question(
headers=headers, session=session, roll_number=roll_number, log=True)
sessionToken = erp_utils.get_cookie(session, 'JSESSIONID')

return ErpResponse(True, data={
"secret_question": secret_question,
"jwt": jwt
"SECRET_QUESTION": secret_question,
"SESSION_TOKEN": sessionToken
}).to_response()
except Exception as e:
return ErpResponse(False, str(e), status_code=500).to_response()
Expand All @@ -425,19 +411,29 @@ def get_secret_question():
@app.route("/request-otp", methods=["POST"])
def request_otp():
try:
jwt = None
auth_resp, status_code = handle_auth()
if status_code != 200:
return auth_resp, status_code
else:
jwt = auth_resp.get_json().get("jwt")

password = request.form.get("password")
secret_answer = request.form.get("secret_answer")
if not all([password, secret_answer]):
return ErpResponse(False, "Missing password or secret answer", status_code=400).to_response()

session_manager.request_otp(jwt, password, secret_answer)
sessionToken = request.headers["Session-Token"]
if not sessionToken:
return ErpResponse(False, "Session-Token header not found", status_code=400).to_response()

data = request.form
roll_number = data.get("roll_number")
password = data.get("password")
secret_answer = data.get("secret_answer")
if not all([roll_number, password, secret_answer]):
return ErpResponse(False, "Missing roll_number or password or secret answer", status_code=400).to_response()

login_details = erp.get_login_details(
ROLL_NUMBER=roll_number,
PASSWORD=password,
secret_answer=secret_answer,
sessionToken=sessionToken
)

session = requests.Session()
erp_utils.set_cookie(session, 'JSESSIONID', sessionToken)
erp.request_otp(headers=headers, session=session,
login_details=login_details, log=True)

return ErpResponse(True, message="OTP has been sent to your connected email accounts").to_response()
except Exception as e:
return ErpResponse(False, str(e), status_code=500).to_response()
Expand All @@ -446,64 +442,59 @@ def request_otp():
@app.route("/login", methods=["POST"])
def login():
try:
jwt = None
auth_resp, status_code = handle_auth()
if status_code != 200:
return auth_resp, status_code
else:
jwt = auth_resp.get_json().get("jwt")

password = request.form.get("password")
secret_answer = request.form.get("secret_answer")
otp = request.form.get("otp")
if not all([secret_answer, password, otp]):
return ErpResponse(False, "Missing password, secret answer or otp", status_code=400).to_response()

session_manager.login(jwt, password, secret_answer, otp)
return ErpResponse(True, message="Logged in to ERP").to_response()
except Exception as e:
return ErpResponse(False, str(e), status_code=500).to_response()

sessionToken = request.headers["Session-Token"]
if not sessionToken:
return ErpResponse(False, "Session-Token header not found", status_code=400).to_response()

@app.route("/logout", methods=["GET"])
def logout():
try:
jwt = None
auth_resp, status_code = handle_auth()
if status_code != 200:
return auth_resp, status_code
else:
jwt = auth_resp.get_json().get("jwt")

session_manager.end_session(jwt=jwt)
data = request.form
roll_number = data.get("roll_number")
password = data.get("password")
secret_answer = data.get("secret_answer")
otp = data.get("otp")
if not all([roll_number, password, secret_answer, otp]):
return ErpResponse(False, "Missing roll_number or password or secret answer or otp", status_code=400).to_response()

login_details = erp.get_login_details(
ROLL_NUMBER=roll_number,
PASSWORD=password,
secret_answer=secret_answer,
sessionToken=sessionToken
)
login_details["email_otp"] = otp

session = requests.Session()
erp_utils.set_cookie(session, 'JSESSIONID', sessionToken)
ssoToken = erp.signin(headers=headers, session=session,
login_details=login_details, log=True)

return ErpResponse(True, message="Logged out of ERP").to_response()
return ErpResponse(True, data={
"ssoToken": ssoToken
}).to_response()
except Exception as e:
return ErpResponse(False, str(e), status_code=500).to_response()


@app.route("/timetable", methods=["POST"])
def timetable():
try:
jwt = None
auth_resp, status_code = handle_auth()
if status_code != 200:
return auth_resp, status_code
else:
jwt = auth_resp.get_json().get("jwt")

_, ssoToken = session_manager.get_erp_session(jwt=jwt)
ssoToken = request.headers["SSO-Token"]
if not ssoToken:
return ErpResponse(False, "SSO-Token header not found", status_code=400).to_response()

ERP_TIMETABLE_URL = "https://erp.iitkgp.ac.in/Acad/student/view_stud_time_table.jsp"
data = {
"ssoToken": ssoToken,
"module_id": '16',
"menu_id": '40',
}
r = session_manager.request(
jwt=jwt, method='POST', url=ERP_TIMETABLE_URL, headers=headers, data=data)

session = requests.Session()
erp_utils.populate_session_with_login_tokens(session, ssoToken)
r = session.post(headers=headers, url=ERP_TIMETABLE_URL, data=data)

return ErpResponse(True, data={
"status_code": r.status_code
"status_code": r.status_code,
"content": r.text
}).to_response()
except Exception as e:
return ErpResponse(False, str(e), status_code=500).to_response()
Expand Down
7 changes: 4 additions & 3 deletions examples/server.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import logging
import requests
import iitkgp_erp_login.erp as erp
import iitkgp_erp_login.utils as erp_utils
from flask import Flask, request, jsonify
import iitkgp_erp_login.utils as erp_utils

app = Flask(__name__)

Expand Down Expand Up @@ -71,14 +71,15 @@ def request_otp():
if not all([roll_number, password, secret_answer]):
return ErpResponse(False, "Missing roll_number or password or secret answer", status_code=400).to_response()

session = requests.Session()
erp_utils.set_cookie(session, 'JSESSIONID', sessionToken)
login_details = erp.get_login_details(
ROLL_NUMBER=roll_number,
PASSWORD=password,
secret_answer=secret_answer,
sessionToken=sessionToken
)

session = requests.Session()
erp_utils.set_cookie(session, 'JSESSIONID', sessionToken)
erp.request_otp(headers=headers, session=session,
login_details=login_details, log=True)

Expand Down

0 comments on commit 313e820

Please sign in to comment.