Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented confirm account via email feature #141

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion flask-backend/api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
from flask_login import LoginManager
from flask_marshmallow import Marshmallow
from flask_cors import CORS, cross_origin
from dotenv import load_dotenv
from flask_jwt_extended import JWTManager

db = SQLAlchemy()
ma = Marshmallow()
Expand All @@ -15,8 +17,14 @@ def create_app():
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.sqlite3'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

app.config["JWT_SECRET_KEY"] = "super-secret" # Change this!
jwt = JWTManager(app)

db.init_app(app)

# Load environment variables
load_dotenv()

login_manager = LoginManager()
login_manager.login_view = 'auth.login'
login_manager.init_app(app)
Expand All @@ -26,7 +34,10 @@ def create_app():

@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
user = User.query.get(int(user_id))
if user and user.is_verified:
return user
return None

@login_manager.unauthorized_handler
def unauthorized_handler():
Expand Down
25 changes: 25 additions & 0 deletions flask-backend/api/helpers/mail.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import os
from flask_mail import Message, Mail

from .. import create_app

def send_confirmation_email(recipient, url):
app = create_app()
app.config.update(dict(
DEBUG = True,
MAIL_SERVER = os.getenv('MAIL_SERVER'),
MAIL_PORT = os.getenv('MAIL_PORT'),
MAIL_USE_TLS = True,
MAIL_USE_SSL = False,
MAIL_USERNAME = os.getenv('MAIL_USERNAME'),
MAIL_PASSWORD = os.getenv('MAIL_PASSWORD'),
))
mail = Mail(app)
msg = Message('Confirm OpenMF account', sender='[email protected]', recipients=[recipient])
msg.body = f'Please use this url to confirm your account: {url}'
try:
mail.send(msg)
except ConnectionRefusedError as err:
print("Mail Server not working")
print(err)
raise ConnectionRefusedError
4 changes: 3 additions & 1 deletion flask-backend/api/models/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class User(UserMixin, db.Model):
role = db.Column(db.String(20))
timestamp = db.Column(db.Float)
has_admin = db.column_property(role != "adimn")
is_verified = db.Column(db.Boolean)
_admin = db.Column(db.String(100))

def __init__(self, email, password, name, role, timestamp):
Expand All @@ -21,6 +22,7 @@ def __init__(self, email, password, name, role, timestamp):
self.role = role
self.timestamp = timestamp
self._admin = "Admin not assinged."
self.is_verified = False

@hybrid_property
def admin(self):
Expand Down Expand Up @@ -50,7 +52,7 @@ def __init__(self, case_name, data_size, timestamp, extractor_id, data_path):

class UserSchema(ma.Schema):
class Meta:
fields = ('name', 'email', 'role', 'timestamp', 'admin')
fields = ('name', 'email', 'role', 'timestamp', 'admin', 'is_verified')

class CaseSchema(ma.Schema):
class Meta:
Expand Down
14 changes: 12 additions & 2 deletions flask-backend/api/routes/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
from werkzeug.security import generate_password_hash, check_password_hash
from .. import db
from sqlalchemy import update
from ..helpers.mail import send_confirmation_email
from flask_jwt_extended import create_access_token, decode_token
user_schema = UserSchema()
users_schema = UserSchema(many=True)

Expand Down Expand Up @@ -104,7 +106,11 @@ def create_user(): # Add only admin can create functionality, once deployed on a
db.session.add(new_user)
db.session.commit()

return 'user created', 202
token = create_access_token(email)
url = f'http://localhost:5000/confirm-account/{token}'
send_confirmation_email(email, url)

return 'user created. Please confirm account via email', 202


# Route for admin to add user
Expand Down Expand Up @@ -133,7 +139,11 @@ def add_users():
db.session.add(new_user)
db.session.commit()

return 'user created', 202
token = create_access_token(email)
url = f'http://localhost:5000/confirm-account/{token}'
send_confirmation_email(email, url)

return 'user created. Please confirm account via email', 202
return "You can't add users, you are not an admin", 409


Expand Down
15 changes: 14 additions & 1 deletion flask-backend/api/userAuthentication/auth.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from flask import Blueprint, render_template, redirect, url_for, request, flash, request
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import login_user, logout_user, login_required
from flask_jwt_extended import decode_token
from ..models.models import User
from .. import db

Expand Down Expand Up @@ -39,4 +40,16 @@ def login_post():
@login_required
def logout():
logout_user()
return 'logged out successfully', 200
return 'logged out successfully', 200

@auth.route('/confirm-account/<token>')
def confirm_account(token):
email = decode_token(token)['sub']
user = User.query.filter_by(email=email).first()

if not user:
return 'User does not exist', 404

user.is_verified = True
db.session.commit()
return 'Account confirmed', 200
7 changes: 7 additions & 0 deletions flask-backend/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
astroid==2.4.2
blinker==1.4
click==7.1.2
colorama==0.4.4
Flask==1.1.1
Flask-Cors==3.0.10
Flask-JWT-Extended==4.0.2
Flask-Login==0.5.0
Flask-Mail==0.9.0
flask-marshmallow==0.13.0
Flask-SQLAlchemy==2.4.4
isort==4.3.21
Expand All @@ -14,10 +18,13 @@ marshmallow==3.7.1
marshmallow-sqlalchemy==0.23.1
mccabe==0.6.1
pdfkit==0.6.1
PyJWT==2.0.1
pylint==2.5.3
python-dotenv==0.15.0
six==1.15.0
SQLAlchemy==1.3.18
toml==0.10.1
typed-ast==1.4.2
typing==3.7.4.3
Werkzeug==1.0.1
wrapt==1.12.1