From e69e8a92c72116dd7483f838acd2a81579dbc17c Mon Sep 17 00:00:00 2001 From: Anton <anton@hedvig.com> Date: Mon, 21 Mar 2022 17:11:59 +0100 Subject: [PATCH] kompletterat lab4 - added functionality for getting a new password --- README.md | 12 +++---- lab4/twidder/database.db | Bin 28672 -> 28672 bytes lab4/twidder/server.py | 48 ++++++++++++++++++++++++++- lab4/twidder/static/client.css | 2 +- lab4/twidder/static/client.html | 27 ++++++++++++++- lab4/twidder/static/client.js | 57 +++++++++++++++++++++++++++----- 6 files changed, 127 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index fceab12..ce02cec 100644 --- a/README.md +++ b/README.md @@ -2,15 +2,13 @@ ### Instructions -There is 1 folder for each lab. +There is 1 folder for each lab. -### Lab 4 -In lab 4 I did 4 extra things for a total of 10 points: +### Lab 4 +In lab 4 I did 4 extra things for a total of 10 points: -* Providing Live Data Presentation [3 points] - - Your messages are received using websocket - - Also showing number of active users (nr of users connected with web-sockets) - - Nr views on your profile by other users +* Recover Your Password [2 points (reset by generating new pw)] + - you will receive an email with your new password from the gmail klasklatt3rmus123@gmail.com. If you you have gmail you gotta check your spam folder (I tried). Got it in the inbox using other emails :-) * Applying Further Security Measures [3 points] diff --git a/lab4/twidder/database.db b/lab4/twidder/database.db index 4c9fbddec06a1bc38d9038e61556f5658a60809c..b1caace054e75321c82833e45b819fe7b29e803a 100644 GIT binary patch delta 1232 zcmZp8z}WDBae_2s;Y1l{#=?yW3;9JE7#P^Or!(^D@~85)@SWzl%VWqrePd%IcYUKc zJC|@{t+2STuqa28Lz0S_N>P4kUP`g8nW>q9fq{xeafE4Asdu@Fe{QmCzJ8=inX!Rm zo^f7@vqfNbp=F7`LAq(4XJ&a;NR~%%q)$M8hL2@sVNpOvVrfQpW`JvPq*HocsA*AT zrK^5&YItd&vtOlQQHoo#XLyRSXMJF5vU7M;M3SMQk+GqX@uB4q+BY#LwNaCe%e=8x zSXfwCk|Qy%BqK4exHv!0Au~BAzcfWJIX@S}u~ij01x_we5y9SJrk)|ekt*(P`F_da zhHf5ZMHLa1MG;9MM&%{JfqI!?5f+9Se);w075@I2?%rX}mOkM|;X#4UX~rJ8##JU! z5rr86k;TqwMV8)fRY|FaKAC!j6$McduC6YL`VdD#NVn8nkYiO?xpa{no1f>9k(yGL znU2++6+WI-Ca#&eq4gzZd4Yy5CMso?=9Qtz?nY6`VQ!8A*_jb3MuibkF5X_HhUGbx zd5I=v`8no}q2}57nXVZ{h3R2QzJ<mv#hzZJ5y9z6-i3M=P9B*)A)%>-8R@3Z<=JK- z<+<6=Kt*w<8Z(zE#GRrXiFx%U`FRe-C5bsXNr}nXiC7(5T2!1{;$a*aTIii_kW-qk zVw9<uRupQiuNRnUY7!P;V4Pu;ZWLAEXyD`;nwwKl6`GN&m*r#Pn~`r2l$%waT#*=* zoS9e@UX`9)QI!#%m7VTm=8<Pmo|hXYU6JdPQKFv{S(=ODSWx^=)|H!A-zd%kPM_dJ zkmZnt5#=V99%+HazJ}&`79~cm$yF+W$!^YiVU9*gAz>-O#aa56C1EZRLEfe%iP`2^ zJ`s72PQj(2RgSLina-*Co_;0yzNWrzrD2sp=B@=M5jlDuLEe@XzCnK8Mro$z(q4tR zAt4s7?s||wgpiOZpPVW`Ux=N5G6Vl?{;&L7`7iNL=0C;%db6NHEq^^bvoK?lLlV0r zvpFNyw96*KtP7GsNhqu!ZCMUkEE3G7P)XFtVdi8OXUs}WcgSMmVwUDi%mc+=A}{|* z21foV4E$60{TaYuv$%pSzbpSq2G?Y)wx{HmCnkEv2UQeT<d!<78ajGry7_0M1$$MQ zrbIeBd$~uMd6`<|mInK{PM%_K>de5vU~b6FES#L=kYtirmFHm);aq5zmT%}`6p~hz z?Vny15>;fD<Pl(692}k-?&O)0<`tRh%f<hLfsy|;GyiLFxE$rz=l{VVh1Eq!J_GxJ M0aO|>FA7iq02D5LO8@`> delta 236 zcmZp8z}WDBae_3X&qNt#MxTud3;DVEPBAd?=`!%?@~3WAR8ZubtSdK<hk;?Xcw?=w zu&}Tw=j0;!UPgw=sq*tVnD}2a@PFlhy;;!V0RO}Z@`{|y;*42|=?+;;T+Gs(iFqaY zc@BxZ3=9lR{8JeCr|_TLEa=d|KY5D1sk13Fvve|4MYch_dud)$zFCS_S!7jMaa2)e zP<(EAK|w~TWual1foYC+W=64(L2hO_7ynlVCjR>j{P*G33M+CmOEW@^Vn#TDfq{V= JD!M2@0RR+?M5h1% diff --git a/lab4/twidder/server.py b/lab4/twidder/server.py index b7a28ed..bb8722f 100644 --- a/lab4/twidder/server.py +++ b/lab4/twidder/server.py @@ -10,7 +10,21 @@ import json import uuid import logging +from flask_mail import Mail, Message + app = Flask(__name__, static_url_path="") + +app.config.update(dict( + DEBUG = True, + MAIL_SERVER = 'smtp.gmail.com', + MAIL_PORT = 587, + MAIL_USE_TLS = True, + MAIL_USE_SSL = False, + MAIL_USERNAME = 'klasklatt3rmus1234@gmail.com', + MAIL_PASSWORD = 'wallwalla1', +)) + +mail = Mail(app) app.logger.setLevel(logging.DEBUG) active_sockets = dict() @@ -51,6 +65,7 @@ def create_response(success, message, data=None): def generate_token(): return secrets.token_urlsafe(32) + def validate_ws(data): user_identifier = data["email"] hashed_data = data["hashed_email"] @@ -74,6 +89,7 @@ def validate_ws(data): print("Ws auth failed") return False + def validate_request(): data = request.args.to_dict() if request.method == "GET" else request.get_json() print("DATA", data) @@ -122,6 +138,36 @@ def root(): return app.send_static_file("client.html") + + +@app.route("/new-password", methods=["GET"]) +def new_password(): + print("NEW PASSWORD ENDPOINT") + email = request.args.get("email") + if not is_already_user(email): + return create_response( + success=True, + message="If you have an account with this email you will receive a new password on your email shortly.", + ) + + new_password = generate_token() + hashed_pw = hash_password(new_password) + database_helper.set_password(email, hashed_pw) + + msg = Message( + "New password requested", + sender="twidder@info.se", + recipients=[email], + ) + msg.body = "Your new password is: " + new_password + mail.send(msg) + + return create_response( + success=True, + message="If you have an account with this email you will receive a new password on your email shortly.", + ) + + @app.route("/sign-in", methods=["POST"]) def sign_in(): data = request.get_json() @@ -393,7 +439,7 @@ def web_socket(): return "" -#database_helper.init_db(app) +# database_helper.init_db(app) if __name__ == "__main__": server = pywsgi.WSGIServer(("", 5002), app, handler_class=WebSocketHandler) server.serve_forever() diff --git a/lab4/twidder/static/client.css b/lab4/twidder/static/client.css index 1663c57..051659c 100644 --- a/lab4/twidder/static/client.css +++ b/lab4/twidder/static/client.css @@ -27,7 +27,7 @@ body { background-repeat: no-repeat; background-position: center; width: 100%; - height: 340px; + height: 285px; border-radius: 10px; margin-top: 20px; background-color: #f5f5f5; diff --git a/lab4/twidder/static/client.html b/lab4/twidder/static/client.html index 2f618e3..fe0fec4 100644 --- a/lab4/twidder/static/client.html +++ b/lab4/twidder/static/client.html @@ -37,6 +37,9 @@ </div> </div> </form> + <div class="form-element"> + <button onclick="javascript:showForgotPassModal()" value="Forgot password">Forgot password</button> + </div> </div> <div class="container-img"></div> </div> @@ -96,6 +99,28 @@ </div> </div> + + <!-- Modal for forgot password --> + <div id="modal_forgot_pass" class="modal" > + + <div class="modal-content"> + <span class="close" id="close_forgot_pass">×</span> + <div class="modal-text"> + <h3>Forgot password</h3> + <form id="forgot-pass-form" action="javascript:handleNewPassword()"> + <div class="form-container"> + <div class="form-element"> + <input type="email" name="email" placeholder="Email" required> + </div> + <div class="form-element"> + <button type="submit" value="New password">Get new password</button> + </div> + </div> + </form> + </div> + </div> + + </div> </div> </script> @@ -103,7 +128,7 @@ <!-- Profile view --> <script id="profile-view" type="text/view"> - + <div class="form"> <!-- Navigation tabs --> diff --git a/lab4/twidder/static/client.js b/lab4/twidder/static/client.js index 22be0f7..7bb9081 100644 --- a/lab4/twidder/static/client.js +++ b/lab4/twidder/static/client.js @@ -220,6 +220,7 @@ function loadWelcomeView() { let welcomeView = document.getElementById("welcome-view"); app.innerHTML = welcomeView.innerHTML; loadModal(); + loadForgotPassModal(); } function showModal(msg) { @@ -229,8 +230,30 @@ function showModal(msg) { errorMessage.innerHTML = msg; } +function showForgotPassModal() { + let modal = document.getElementById("modal_forgot_pass"); + modal.style.display = "flex"; +} + +function loadForgotPassModal() { + let modal_forgot_pass = document.getElementById("modal_forgot_pass"); + + let span = document.getElementById("close_forgot_pass"); + span.onclick = function () { + modal_forgot_pass.style.display = "none"; + }; + + // When the user clicks anywhere outside of the password modal, close it + window.onclick = function (event) { + if (event.target == modal_forgot_pass) { + modal_forgot_pass.style.display = "none"; + } + }; +} + function loadModal() { let modal = document.getElementById("modal"); + let span = document.getElementsByClassName("close")[0]; span.onclick = function () { modal.style.display = "none"; @@ -271,6 +294,23 @@ function signIn(email, password) { xmlRequest("/sign-in", myCallback, params, null, "POST"); } +function handleNewPassword() { + let email = document.forms["forgot-pass-form"]["email"].value; + + let params = { + email: email, + }; + + let myCallback = function (res) { + modal_forgot_pass = document.getElementById("modal_forgot_pass"); + modal_forgot_pass.style.display = "none"; + showModal(res.message); + }; + + xmlRequest("/new-password", myCallback, params, null, "GET"); + +} + function validatePassword(pw, pw2) { if (pw.length < 5) { let msg = "Password must be at least 5 characters"; @@ -394,7 +434,7 @@ function signOut() { window.localStorage.removeItem("token"); window.localStorage.removeItem("email"); displayView(); - } + } }; user_identifier = localStorage.getItem("email"); @@ -450,7 +490,7 @@ function xmlRequest(url, callback, params, token = null, requestType) { window.localStorage.removeItem("token"); window.localStorage.removeItem("email"); displayView(); - showModal("Authentication failed. You must sign in again") + showModal("Authentication failed. You must sign in again"); } } }; @@ -485,12 +525,12 @@ function connectWebSocket() { ws.onopen = function () { let email = localStorage.getItem("email"); let token = localStorage.getItem("token"); - hashed_email = CryptoJS.SHA512(email + token).toString(CryptoJS.enc.Hex);; - let userData = { email: email, hashed_email: hashed_email}; + hashed_email = CryptoJS.SHA512(email + token).toString(CryptoJS.enc.Hex); + let userData = { email: email, hashed_email: hashed_email }; ws.send(JSON.stringify(userData)); console.log("Web socket opened"); - // ping neccessary when using Heroku because of defualt timout on idle connections + // ping neccessary when using Heroku because of defualt timout on idle connections let clock = setInterval(function () { console.log("Ping server"); ws.send("ping"); @@ -498,9 +538,8 @@ function connectWebSocket() { ws.onclose = function () { console.log("Web socket closed"); - clearInterval(clock) + clearInterval(clock); }; - }; ws.onmessage = function (res) { @@ -534,8 +573,8 @@ function setLocation() { async function onSuccess(position) { const geocode = await fetch( `https://geocode.xyz/${position.coords.latitude},${position.coords.longitude}?json=1?` - ); - if (geocode.status == "200") { + ); + if (geocode.status == "200") { console.log("Successfulyy fetched location from geocode.xyz"); const geoResponse = await geocode.json(); localStorage.setItem( -- GitLab