diff --git a/.gitignore b/.gitignore index fdaf744..c1d8d53 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,4 @@ ENV/ set/ VIRTUAL_ENV/ calendars/ -.idea/ \ No newline at end of file +.idea/ diff --git a/app.py b/app.py index 1e21024..def3421 100644 --- a/app.py +++ b/app.py @@ -1,30 +1,56 @@ #!/usr/bin/env python3.6 -import os from flask import Flask from flask import render_template, url_for, send_from_directory, redirect, request, send_file +from flask_login import login_user, login_required, current_user, LoginManager, UserMixin, logout_user from flask_sqlalchemy import SQLAlchemy -import pymysql from werkzeug.security import generate_password_hash, check_password_hash import hashlib import dualisauth +import requesthelpers from fetchRAPLA import * from get_mysql import get_mysql +import time + + +def create(): + app = Flask(__name__) + dbpw = get_mysql()[1] + dbun = get_mysql()[0] + + app.config['SECRET_KEY'] = 'SECRET_KEY_GOES_HERE' + app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://' + dbun + ':' + dbpw + '@localhost/paulmrtn_DUALHUB' + db.init_app(app) + + login_manager = LoginManager() + login_manager.init_app(app) + login_manager.login_view = "login" + + @login_manager.user_loader + def load_user(uid: int): + return User.query.filter_by(id=uid).first() + + return app -app = Flask(__name__) db = SQLAlchemy() -dbpw = get_mysql() -app.config['SECRET_KEY'] = 'ASDF)uhdsklvbkuezafdpo12i34rewfgvoukzgp3zerfpg8owiu2301394trilfkj' -app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://paulmrtn:' + dbpw + '@localhost/paulmrtn_DUALHUB' -db.init_app(app) +app = create() -class User(db.Model): - id = db.Column(db.Integer, primary_key=True) # primary keys are required by SQLAlchemy - email = db.Column(db.String(100), unique=True) - password = db.Column(db.String(100)) - name = db.Column(db.String(1000)) +class User(UserMixin, db.Model): + id = db.Column(db.Integer, primary_key=True) + email = db.Column(db.String(255), unique=True) + password = db.Column(db.String(255)) + name = db.Column(db.String(255)) + kurs = db.Column(db.String(15)) + + +class Dualis(db.Model): + token = db.Column(db.String(255), unique=True) + uid = db.Column(db.Integer, primary_key=True) + token_created = db.Column(db.Integer) + result_lists = db.Column(db.String(255)) + cookie = db.Column(db.String(255)) @app.route("/") @@ -32,6 +58,20 @@ def index(): return render_template('index.html', headermessage='Header', message='DualHub') +@app.route("/welcome") +@login_required +def welcome(): + d = Dualis.query.filter_by(uid=current_user.id).first() + if not current_user.kurs: + kurs = dualisauth.getKurs(d.token, d.cookie) + current_user.kurs = kurs + db.session.commit() + else: + kurs = current_user.kurs + name = current_user.name + return render_template('index.html', headermessage='DualHub', message="Hallo, " + + name + " (" + kurs + ")") + @app.route("/backendpoc/error") def error(ecode): if ecode == 900: @@ -44,11 +84,13 @@ def error(ecode): @app.route("/backendpoc/rapla") +@login_required def chooseRaplas(): r = getRaplas() return render_template("rapla.html", raplas=r) +@login_required @app.route("/backendpoc/plan", methods=["POST"]) def getRapla(): file = str(request.form.get("file")) @@ -56,10 +98,14 @@ def getRapla(): if file == url == "None": return redirect(url_for("chooseRaplas")) if file != "None": + User.query.filter_by(id=current_user.id).first().kurs = file[5:-5] + db.session.commit() return send_file("calendars/" + file) elif url != "None": file = getNewRapla(url) if type(file) is not int: + User.query.filter_by(id=current_user.id).first().kurs = file[5:-5] + db.session.commit() return send_file("calendars/" + file) else: return redirect(url_for("error", ecode=file + 900)) @@ -67,9 +113,9 @@ def getRapla(): @app.route("/backendpoc/log-in") -def login(ecode: int = None): - if ecode: - print(ecode) +def login(code: int = None): + if code: + print(code) return render_template("login.html") @@ -77,32 +123,65 @@ def login(ecode: int = None): def login_post(): email = request.form.get("email") password = request.form.get("password") + n = request.args.get("next") + if n: + success = redirect(n) + else: + success = redirect(url_for("welcome")) user = User.query.filter_by(email=email).first() if user: + dualis = Dualis.query.filter_by(uid=user.id).first() if check_password_hash(user.password, password): - return redirect(url_for("index")) + if not dualisauth.checkLifetime(dualis.token_created): + new_token = dualisauth.checkUser(email, password) + dualis.token = new_token[0] + dualis.cookie = requesthelpers.getCookie(new_token[1].cookies) + dualis.token_created = time.time() + db.session.commit() + login_user(user) + return success else: t = dualisauth.checkUser(email, password) - if t == -2: - return redirect(url_for("login", ecode=-2)) + if t[0] == -2: + return redirect(url_for("login", code=-2)) else: user.password = generate_password_hash(password, method="pbkdf2:sha256") + dualis.token = t[0] + dualis.cookie = requesthelpers.getCookie(t[1].cookies) + dualis.token_created = time.time() db.session.commit() - return redirect(url_for("index")) + login_user(user) + return success t = dualisauth.checkUser(email, password) - if t == -2: - return redirect(url_for("login", ecode=-2)) + if t[0] == -2: + return redirect(url_for("login", code=-2)) - hashid = int(hashlib.sha1(email.encode("utf-8")).hexdigest(), 16) % (10 ** 12) + hashid = int(hashlib.sha1(email.encode("utf-8")).hexdigest(), 16) % (10 ** 8) hashpw = generate_password_hash(password, method="pbkdf2:sha256") - new_user = User(id=hashid, email=email, password=hashpw) - db.session.add(new_user) - db.session.commit() + pname = email.find(".") + 1 + ename = min(email[pname:].find("."), email[pname:].find("@")) + name = email[pname:pname + ename].capitalize() - return redirect(url_for("index")) + new_user = User(email=email, password=hashpw, name=name, id=hashid) + db.session.add(new_user) + + cookie = requesthelpers.getCookie(t[1].cookies) + + new_dualis = Dualis(uid=hashid, token=t[0], token_created=int(time.time()), cookie=cookie) + + db.session.add(new_dualis) + db.session.commit() + login_user(new_user) + return success + + +@app.route("/backendpoc/log-out") +def logout(): + logout_user() + return redirect(url_for("login", code=1)) if __name__ == "__main__": diff --git a/dualisauth.py b/dualisauth.py index d50f5ca..1ef4aca 100644 --- a/dualisauth.py +++ b/dualisauth.py @@ -1,31 +1,52 @@ import requests -from requests.utils import requote_uri, unquote_unreserved import urllib.parse +import time +from bs4 import BeautifulSoup + +headers = { + 'Cookie': 'cnsc=0', + 'Content-Type': 'application/x-www-form-urlencoded', + 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36' +} + +url = "https://dualis.dhbw.de/scripts/mgrqispi.dll" def checkUser(email: str, password: str): - url = "https://dualis.dhbw.de/scripts/mgrqispi.dll" + s = requests.Session() fpw = urllib.parse.quote(password, safe='', encoding=None, errors=None) fmail = urllib.parse.quote(email, safe='', encoding=None, errors=None) payload = 'usrname=' + fmail + '&pass=' + fpw + '&ARGUMENTS=clino%2Cusrname%2Cpass%2Cmenuno%2Cmenu_type%2Cbrowser%2Cplatform&APPNAME=CampusNet&PRGNAME=LOGINCHECK' - headers = { - 'Cookie': 'cnsc=0', - 'Content-Type': 'application/x-www-form-urlencoded', - 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36' - } - - response = requests.request("POST", url, headers=headers, data=payload) + response = s.post(url, headers=headers, data=payload) header = response.headers try: refresh = header["REFRESH"] arg = refresh.find("=-N") + 3 komma = refresh[arg:].find(",") except KeyError: - return -2 - + return -2, s token = refresh[arg:komma + arg] - return token + return token, s -def getName(token: str): - print(token) +def getKurs(token: str, cookie: int): + headers["Cookie"] = "cnsc=" + str(cookie) + response = requests.request("GET", + url + "?APPNAME=CampusNet&PRGNAME=COURSERESULTS&ARGUMENTS=-N" + token + ",-N000307,", + headers=headers, data={}) + html = BeautifulSoup(response.text, 'lxml') + link = html.body.find('a', attrs={'id': "Popup_details0001"})['href'] + response = requests.request("GET", url+link[21:], headers=headers, data={}) + html = BeautifulSoup(response.text, 'lxml') + content = html.body.find('td', attrs={'class': 'level02'}).text + start = content.find(" ")+4 + end = start + (content[start:].find(" ")) + kurs = content[start:end] + return kurs + + +def checkLifetime(timecode: float): + if time.time() - timecode > 1800: + return False + else: + return True diff --git a/get_mysql.py b/get_mysql.py index 3e683ef..d5e6622 100644 --- a/get_mysql.py +++ b/get_mysql.py @@ -1,10 +1,13 @@ import getpass -def get_mysql (): + +def get_mysql(): u = getpass.getuser() f = open("/home/"+u+"/.my.cnf", "r") i = f.read() + u = i.find("user=") p = i.find("password=") - ro = i.find ("[clientreadonly]") + u = i[u+5:p-1] + ro = i.find("[clientreadonly]") p = i[p+9:ro-2] - return p + return u, p diff --git a/requesthelpers.py b/requesthelpers.py new file mode 100644 index 0000000..85ffe36 --- /dev/null +++ b/requesthelpers.py @@ -0,0 +1,8 @@ + + + +def getCookie (cookies): + cookie = 0 + for c in cookies: + cookie = c.value + return cookie \ No newline at end of file diff --git a/static/style.css b/static/style.css index 1ac1844..e518228 100644 --- a/static/style.css +++ b/static/style.css @@ -14,7 +14,7 @@ input { height: 50px } -#url { +input[type=url], input[type=email], input[type=password] { width: 500px; } diff --git a/templates/index.html b/templates/index.html index c8bb618..0f068bb 100644 --- a/templates/index.html +++ b/templates/index.html @@ -4,11 +4,10 @@ {{headermessage}} 👀 - + -

{{message}}

diff --git a/templates/login.html b/templates/login.html index 5559a86..555fa70 100644 --- a/templates/login.html +++ b/templates/login.html @@ -1,20 +1,19 @@ - {{headermessage}} 👀 + Log In 👀 - + -
-
- + + - +
diff --git a/templates/rapla.html b/templates/rapla.html index 19ecd94..f47a7b0 100644 --- a/templates/rapla.html +++ b/templates/rapla.html @@ -1,9 +1,9 @@ - {{headermessage}} 👀 + RAPLA importieren 👀 - +

Verfügbare Raplas

@@ -23,7 +23,7 @@

Eigenen Rapla hinzufügen

- +