halfway implementation of forgotten passwords

This commit is contained in:
crunk 2022-03-25 15:37:00 +01:00
parent 825013b3c2
commit 730a12accd
7 changed files with 108 additions and 6 deletions

View File

@ -2,9 +2,11 @@ alembic==1.7.5
Babel==2.9.1 Babel==2.9.1
bcrypt==3.2.0 bcrypt==3.2.0
black==21.11b1 black==21.11b1
bleach==4.1.0
blinker==1.4 blinker==1.4
cffi==1.15.0 cffi==1.15.0
click==8.0.3 click==8.0.3
distribusi @ git+file:///home/shambler/Development/distribusiverse/distribusi@e291e7497e40211c2ebd54ca32a1f4bdaed71230
dnspython==2.1.0 dnspython==2.1.0
email-validator==1.1.3 email-validator==1.1.3
Flask==2.0.2 Flask==2.0.2
@ -15,6 +17,7 @@ Flask-Mail==0.9.1
Flask-Migrate==3.1.0 Flask-Migrate==3.1.0
Flask-Principal==0.4.0 Flask-Principal==0.4.0
Flask-Security==3.0.0 Flask-Security==3.0.0
Flask-Security-Too==4.1.3
Flask-SQLAlchemy==2.5.1 Flask-SQLAlchemy==2.5.1
Flask-WTF==1.0.0 Flask-WTF==1.0.0
greenlet==1.1.2 greenlet==1.1.2
@ -24,11 +27,13 @@ Jinja2==3.0.3
Mako==1.1.6 Mako==1.1.6
MarkupSafe==2.0.1 MarkupSafe==2.0.1
mypy-extensions==0.4.3 mypy-extensions==0.4.3
packaging==21.3
passlib==1.7.4 passlib==1.7.4
pathspec==0.9.0 pathspec==0.9.0
Pillow==8.3.2 Pillow==8.3.2
platformdirs==2.4.0 platformdirs==2.4.0
pycparser==2.21 pycparser==2.21
pyparsing==3.0.7
python-magic==0.4.24 python-magic==0.4.24
pytz==2021.3 pytz==2021.3
regex==2021.11.10 regex==2021.11.10
@ -36,7 +41,7 @@ six==1.16.0
speaklater==1.3 speaklater==1.3
SQLAlchemy==1.4.27 SQLAlchemy==1.4.27
tomli==1.2.2 tomli==1.2.2
typing-extensions==4.0.1 typing_extensions==4.0.1
webencodings==0.5.1
Werkzeug==2.0.2 Werkzeug==2.0.2
WTForms==3.0.0 WTForms==3.0.0
-e git+https://git.vvvvvvaria.org/crunk/distribusi-verse.git@1a50898d216ae95c3eb9c144bb7ec678e638daa6#egg=distribusi

View File

@ -22,6 +22,13 @@ def create_app():
APP.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = True APP.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = True
APP.config["MAX_CONTENT_LENGTH"] = 150 * 1024 * 1024 APP.config["MAX_CONTENT_LENGTH"] = 150 * 1024 * 1024
APP.config["MAIL_SERVER"] = "0.0.0.0"
APP.config["MAIL_PORT"] = 1025
APP.config["MAIL_USE_SSL"] = False
APP.config["MAIL_USE_TLS"] = True
# APP.config['MAIL_USERNAME'] = 'username'
# APP.config['MAIL_PASSWORD'] = 'password'
login_manager.session_protection = "strong" login_manager.session_protection = "strong"
login_manager.login_view = "index" login_manager.login_view = "index"
login_manager.login_message_category = "info" login_manager.login_message_category = "info"

View File

@ -0,0 +1,19 @@
"""Forgotten password form to help user."""
from wtforms import (
StringField,
SubmitField,
)
from wtforms import validators
from wtforms.validators import Length, Email
from flask_wtf import FlaskForm
class ForgotPasswordForm(FlaskForm):
"""Forgotten password distribusiverse form class."""
email = StringField(
"Email address:",
validators=[validators.InputRequired(), Email(), Length(6, 64)],
)
submit = SubmitField("Send email")

View File

@ -12,6 +12,7 @@ from flask_login import (
login_required, login_required,
current_user, current_user,
) )
from flask_mail import Mail
from flask_wtf.csrf import CSRFError from flask_wtf.csrf import CSRFError
from app import create_app, login_manager from app import create_app, login_manager
from usermodel import User from usermodel import User
@ -31,11 +32,13 @@ from uploadpage import UploadPage
from statuspengguna.helper import ResetUserState from statuspengguna.helper import ResetUserState
from statuspengguna.loginuser import LoginUser from statuspengguna.loginuser import LoginUser
from statuspengguna.registeruser import RegisterUser from statuspengguna.registeruser import RegisterUser
from statuspengguna.forgotpassword import ForgotPassword
from distribusisinfo import DistribusisInfo from distribusisinfo import DistribusisInfo
APP = create_app() APP = create_app()
stash_page = Blueprint("stash_page", __name__, static_folder="stash") stash_page = Blueprint("stash_page", __name__, static_folder="stash")
APP.register_blueprint(stash_page) APP.register_blueprint(stash_page)
mail = Mail(APP)
@APP.before_request @APP.before_request
@ -129,14 +132,17 @@ def logout():
@APP.route("/login", methods=["GET", "POST"]) @APP.route("/login", methods=["GET", "POST"])
def login(): def login():
result = LoginUser() return LoginUser()
return result
@APP.route("/register", methods=["GET", "POST"]) @APP.route("/register", methods=["GET", "POST"])
def register(): def register():
result = RegisterUser() return RegisterUser()
return result
@APP.route("/forgotpassword", methods=["GET", "POST"])
def forgotpassword():
return ForgotPassword(mail)
@APP.errorhandler(CSRFError) @APP.errorhandler(CSRFError)

View File

@ -0,0 +1,34 @@
from flask import render_template
from usermodel import User
from forms.forgotpasswordform import ForgotPasswordForm
from flask_mail import Message
def ForgotPassword(mail):
forgotpasswordform = ForgotPasswordForm()
if forgotpasswordform.validate_on_submit():
user = User.query.filter_by(
email=forgotpasswordform.email.data
).first()
if user is not None:
ResetPassWordMessage(user, mail)
forgotpasswordform.email.errors.append(
f"""If {forgotpasswordform.email.data} exists, an email is send with
a password reset link. (If your inbox doesn't
contain any new mail, please check your spam folder.)"""
)
return render_template(
"forgotpassword.html", forgotpasswordform=forgotpasswordform
)
def ResetPassWordMessage(user, mail):
msg = Message(
"Distribusiverse Forgotten Password ",
sender=("Distribusiverse mailer", "test@this.com"),
recipients=[user.email],
)
msg.html = f"""You have requested a password reset for Distribusiverse.<br>
<a href='http://localhost:5000/resetpassword/{user.email}'>Click here to
reset your password and make a new one.</a>"""
mail.send(msg)

View File

@ -0,0 +1,29 @@
{% extends "base.html" %}
{% block main %}
<div id="mainworkflow">
<div class="workflow">
<h2>Forgot your password?</h2>
<p>
Enter the email address that was used to register with Distribusiverse.
</p>
<form class="form" action="{{ url_for('forgotpassword') }}" method="post">
{{ forgotpasswordform.csrf_token }}
<fieldset class="required">
{{ forgotpasswordform.email.label }}
{{ forgotpasswordform.email }}
{% for message in forgotpasswordform.email.errors %}
<div class="error">{{ message }}</div>
{% endfor %}
</fieldset>
<fieldset class="button required error">
{{ forgotpasswordform.submit }}
<div class="overview">
<a href="/">
<input type="button" name="button" value="Back to main page"></input>
</a>
</div>
</fieldset>
</form>
</div>
</div
{% endblock main %}

View File

@ -12,6 +12,8 @@ class User(UserMixin, db.Model):
email = db.Column(db.String(150), unique=True, nullable=False) email = db.Column(db.String(150), unique=True, nullable=False)
password = db.Column(db.String(300), nullable=False, unique=False) password = db.Column(db.String(300), nullable=False, unique=False)
currentdistribusi = db.Column(db.String(300), nullable=True, unique=False) currentdistribusi = db.Column(db.String(300), nullable=True, unique=False)
# resethash = db.Column(db.String(300), nullable=True, unique=True)
# resettime = db.Column(db.DateTime)
tutor = db.Column(db.Boolean, default=False) tutor = db.Column(db.Boolean, default=False)
admin = db.Column(db.Boolean, default=False) admin = db.Column(db.Boolean, default=False)