Implement password reset
This commit is contained in:
parent
7fcbac2e83
commit
da0dd066d3
|
@ -0,0 +1,13 @@
|
|||
Someone, probably you, wants to reset your donor password.
|
||||
|
||||
To proceed, click this link:
|
||||
|
||||
{{root}}/password-reset/{{user.password_reset}}
|
||||
|
||||
This link expires in 24 hours. If you don't want to change your password or you
|
||||
weren't expecting this email, just ignore it.
|
||||
|
||||
If you have questions, send an email to {{your_email}}.
|
||||
|
||||
--
|
||||
{{your_name}}
|
|
@ -5,7 +5,7 @@ from fosspay.objects import *
|
|||
from fosspay.database import db
|
||||
from fosspay.common import *
|
||||
from fosspay.config import _cfg, load_config
|
||||
from fosspay.email import send_thank_you
|
||||
from fosspay.email import send_thank_you, send_password_reset
|
||||
|
||||
import os
|
||||
import locale
|
||||
|
@ -40,13 +40,13 @@ def setup():
|
|||
email = request.form.get("email")
|
||||
password = request.form.get("password")
|
||||
if not email or not password:
|
||||
return redirect("/") # TODO: Tell them what they did wrong (i.e. being stupid)
|
||||
return redirect("..") # TODO: Tell them what they did wrong (i.e. being stupid)
|
||||
user = User(email, password)
|
||||
user.admin = True
|
||||
db.add(user)
|
||||
db.commit()
|
||||
login_user(user)
|
||||
return redirect("/admin?first-run=1")
|
||||
return redirect("admin?first-run=1")
|
||||
|
||||
@html.route("/admin")
|
||||
@adminrequired
|
||||
|
@ -72,14 +72,14 @@ def create_project():
|
|||
project = Project(name)
|
||||
db.add(project)
|
||||
db.commit()
|
||||
return redirect("/admin")
|
||||
return redirect("admin")
|
||||
|
||||
@html.route("/login", methods=["GET", "POST"])
|
||||
def login():
|
||||
if current_user:
|
||||
if current_user.admin:
|
||||
return redirect("/admin")
|
||||
return redirect("/panel")
|
||||
return redirect("admin")
|
||||
return redirect("panel")
|
||||
if request.method == "GET":
|
||||
return render_template("login.html")
|
||||
email = request.form.get("email")
|
||||
|
@ -93,14 +93,14 @@ def login():
|
|||
return render_template("login.html", errors=True)
|
||||
login_user(user)
|
||||
if user.admin:
|
||||
return redirect("/admin")
|
||||
return redirect("/panel")
|
||||
return redirect("admin")
|
||||
return redirect("panel")
|
||||
|
||||
@html.route("/logout")
|
||||
@loginrequired
|
||||
def logout():
|
||||
logout_user()
|
||||
return redirect("/")
|
||||
return redirect("..")
|
||||
|
||||
@html.route("/donate", methods=["POST"])
|
||||
@json_output
|
||||
|
@ -171,23 +171,41 @@ def donate():
|
|||
else:
|
||||
return { "success": True, "new_account": new_account }
|
||||
|
||||
def issue_password_reset(email):
|
||||
user = User.query.filter(User.email == email).first()
|
||||
if not user:
|
||||
return render_template("reset.html", errors="No one with that email found.")
|
||||
user.password_reset = binascii.b2a_hex(os.urandom(20)).decode("utf-8")
|
||||
user.password_reset_expires = datetime.now() + timedelta(days=1)
|
||||
send_password_reset(user)
|
||||
db.commit()
|
||||
return render_template("reset.html", done=True)
|
||||
|
||||
@html.route("/password-reset", methods=['GET', 'POST'], defaults={'token': None})
|
||||
@html.route("/password-reset/<token>", methods=['GET', 'POST'])
|
||||
def reset_password(token):
|
||||
if not token and request.method == "POST":
|
||||
if request.method == "GET" and not token:
|
||||
return render_template("reset.html")
|
||||
|
||||
if request.method == "POST":
|
||||
token = request.form.get("token")
|
||||
email = request.form.get("email")
|
||||
|
||||
if email:
|
||||
return issue_password_reset(email)
|
||||
|
||||
if not token:
|
||||
redirect("/")
|
||||
else:
|
||||
redirect("/")
|
||||
return redirect("..")
|
||||
|
||||
user = User.query.filter(User.password_reset == token).first()
|
||||
if not user:
|
||||
redirect("/")
|
||||
return render_template("reset.html", errors="This link has expired.")
|
||||
|
||||
if request.method == 'GET':
|
||||
if user.password_reset_expires == None or user.password_reset_expires < datetime.now():
|
||||
return render_template("reset.html", expired=True)
|
||||
return render_template("reset.html", errors="This link has expired.")
|
||||
if user.password_reset != token:
|
||||
redirect("/")
|
||||
redirect("..")
|
||||
return render_template("reset.html", token=token)
|
||||
else:
|
||||
if user.password_reset_expires == None or user.password_reset_expires < datetime.now():
|
||||
|
@ -202,7 +220,7 @@ def reset_password(token):
|
|||
user.password_reset_expires = None
|
||||
db.commit()
|
||||
login_user(user)
|
||||
return redirect("/panel")
|
||||
return redirect("panel")
|
||||
|
||||
@html.route("/panel")
|
||||
@loginrequired
|
||||
|
|
|
@ -31,3 +31,23 @@ def send_thank_you(user, amount, monthly):
|
|||
message['To'] = user.email
|
||||
smtp.sendmail(_cfg("smtp-from"), [ user.email ], message.as_string())
|
||||
smtp.quit()
|
||||
|
||||
def send_password_reset(user):
|
||||
if _cfg("smtp-host") == "":
|
||||
return
|
||||
smtp = smtplib.SMTP(_cfg("smtp-host"), _cfgi("smtp-port"))
|
||||
smtp.login(_cfg("smtp-user"), _cfg("smtp-password"))
|
||||
with open("emails/reset-password") as f:
|
||||
message = MIMEText(html.parser.HTMLParser().unescape(\
|
||||
pystache.render(f.read(), {
|
||||
"user": user,
|
||||
"root": _cfg("protocol") + "://" + _cfg("domain"),
|
||||
"your_name": _cfg("your-name"),
|
||||
"your_email": _cfg("your-email")
|
||||
})))
|
||||
message['X-MC-PreserveRecipients'] = "false"
|
||||
message['Subject'] = "Reset your donor password"
|
||||
message['From'] = _cfg("smtp-from")
|
||||
message['To'] = user.email
|
||||
smtp.sendmail(_cfg("smtp-from"), [ user.email ], message.as_string())
|
||||
smtp.quit()
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
{% extends "layout.html" %}
|
||||
{% block body %}
|
||||
<div class="well">
|
||||
<div class="container">
|
||||
<h1>Donate to {{ _cfg("your-name") }}</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-md-offset-3">
|
||||
<h1>Reset Password</h1>
|
||||
{% if errors %}
|
||||
<div class="alert alert-danger">
|
||||
<p>
|
||||
{{ errors }}
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if done %}
|
||||
<p>
|
||||
An email should arrive shortly. If you need help, contact
|
||||
<a href="mailto:{{_cfg("your-email")}}">{{_cfg("your-email")}}</a>.
|
||||
</p>
|
||||
{% elif token %}
|
||||
<form action="{{root}}/password-reset" method="POST">
|
||||
<div class="form-group">
|
||||
<input class="form-control" type="password" name="password" placeholder="New password" />
|
||||
<input type="hidden" name="token" value="{{ token }}" />
|
||||
</div>
|
||||
<input type="submit" value="Submit" class="btn btn-primary" />
|
||||
</form>
|
||||
{% else %}
|
||||
<form action="{{root}}/password-reset" method="POST">
|
||||
<div class="form-group">
|
||||
<input class="form-control" type="text" name="email" placeholder="your@email.com" />
|
||||
</div>
|
||||
<input type="submit" value="Submit" class="btn btn-primary" />
|
||||
</form>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
Loading…
Reference in New Issue