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">&times;</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