Просмотр исходного кода

Started with refactoring of the token generation

Peter Justin 9 лет назад
Родитель
Сommit
abe5afbe3e

+ 4 - 0
flaskbb/auth/forms.py

@@ -114,3 +114,7 @@ class ResetPasswordForm(Form):
         email = User.query.filter_by(email=field.data).first()
         if not email:
             raise ValidationError(_("Wrong E-Mail Address."))
+
+
+class EmailConfirmationForm(Form):
+    pass

+ 12 - 1
flaskbb/auth/views.py

@@ -20,10 +20,12 @@ from flaskbb.utils.helpers import render_template, redirect_or_next
 from flaskbb.email import send_reset_token
 from flaskbb.exceptions import AuthenticationError, LoginAttemptsExceeded
 from flaskbb.auth.forms import (LoginForm, ReauthForm, ForgotPasswordForm,
-                                ResetPasswordForm, RegisterForm)
+                                ResetPasswordForm, RegisterForm,
+                                EmailConfirmationForm)
 from flaskbb.user.models import User
 from flaskbb.fixtures.settings import available_languages
 from flaskbb.utils.settings import flaskbb_config
+from flaskbb.utils.tokens import get_token_status
 
 auth = Blueprint("auth", __name__)
 
@@ -164,3 +166,12 @@ def reset_password(token):
 
     form.token.data = token
     return render_template("auth/reset_password.html", form=form)
+
+
+@auth.route("/confirm-email/<token>", methods=["GET", "POST"])
+def email_confirmation(token):
+    """Handles the email verification process."""
+    if current_user.is_authenticated and current_user.confirmed is not None:
+        return redirect(url_for('forum.index'))
+
+    return render_template("auth/email_verification.html")

+ 22 - 1
flaskbb/email.py

@@ -13,9 +13,12 @@ from flask_mail import Message
 from flask_babelplus import lazy_gettext as _
 
 from flaskbb.extensions import mail
+from flaskbb.utils.tokens import (generate_password_reset_token,
+                                  generate_email_confirmation_token)
 
 
-def send_reset_token(user, token):
+def send_reset_token(user):
+    token = generate_password_reset_token(user)
     send_email(
         subject=_("Password Reset"),
         recipients=[user.email],
@@ -32,6 +35,24 @@ def send_reset_token(user, token):
     )
 
 
+def send_email_confirmation(user):
+    token = generate_email_confirmation_token()
+    send_email(
+        subject=_("E-Mail Confirmation"),
+        recipients=[user.email],
+        text_body=render_template(
+            "email/confirm_email.txt",
+            user=user,
+            token=token
+        ),
+        html_body=render_template(
+            "email/confirm_email.html",
+            user=user,
+            token=token
+        )
+    )
+
+
 def send_email(subject, recipients, text_body, html_body, sender=None):
     msg = Message(subject, recipients=recipients, sender=sender)
     msg.body = text_body

+ 10 - 0
flaskbb/templates/email/confirm_email.html

@@ -0,0 +1,10 @@
+{% set link = url_for('auth.email_confirmation', token=token, _external=True) %}
+
+<p>{% trans user=user.username %}Dear {{ user }},{% endtrans %}</p>
+
+<p>{% trans %}Click the link below to confirm your email:{% endtrans %}</p>
+
+<p><a href="{{ link }}"</a></p>
+
+<p>{% trans %}Sincerely,{% endtrans %}</p>
+<p>{% trans %}The Administration{% endtrans %}</p>

+ 11 - 0
flaskbb/templates/email/confirm_email.txt

@@ -0,0 +1,11 @@
+{% set link = url_for('auth.email_confirmation', token=token, _external=True) %}
+
+{% trans user=user.username, link=link %}Dear {{ user }},
+
+Click the link below to confirm your email:
+
+{{ link }}
+
+Sincerely,
+The Administration
+{% endtrans %}

+ 79 - 0
flaskbb/utils/tokens.py

@@ -0,0 +1,79 @@
+# -*- coding: utf-8 -*-
+"""
+    flaskbb.utils.tokens
+    ~~~~~~~~~~~~~~~~~~~~
+
+    A module that helps to create and verify various tokens that
+    are used by FlaskBB.
+
+    :copyright: (c) 2014 by the FlaskBB Team.
+    :license: BSD, see LICENSE for more details.
+"""
+from flask import current_app
+from itsdangerous import (TimedJSONWebSignatureSerializer, SignatureExpired,
+                          BadSignature)
+
+from flaskbb.user.models import User
+
+
+def make_token(user, operation, expire=3600):
+    """Generates a JSON Web Signature (JWS).
+    See `RFC 7515 <https://tools.ietf.org/html/rfc7515>` if you want to know
+    more about JWS.
+
+    :param user: The user object for whom the token should be generated.
+    :param operation: The function of the token. For example, you might want
+                      to generate two different tokens. One for a
+                      password reset link, which you hypothetically want
+                      to name 'reset' and the second one, for the generation
+                      of a token for a E-Mail confirmation link, which you
+                      name 'email'.
+    :param expire: The time, in seconds, after which the token should be
+                   invalid. Defaults to 3600.
+    """
+    s = TimedJSONWebSignatureSerializer(
+        current_app.config['SECRET_KEY'], expire
+    )
+    data = {"id": user.id, "op": operation}
+    return s.dumps(data)
+
+
+def get_token_status(token, operation, return_data):
+    """Returns the expired status, invalid status, the user and optionally
+    the content of the JSON Web Signature token.
+
+    :param token: A valid JSON Web Signature token.
+    :param operation: The function of the token.
+    :param return_data: If set to ``True``, it will also return the content
+                        of the token.
+    """
+    s = TimedJSONWebSignatureSerializer(current_app.config['SECRET_KEY'])
+    user, data = None
+    expired, invalid = False, False
+
+    try:
+        data = s.loads(token)
+    except SignatureExpired:
+        expired = True
+    except (BadSignature, TypeError, ValueError):
+        invalid = True
+
+    if data:
+        user = User.query.filter_by(id=data.get('id')).first()
+
+    expired = expired and (user is not None)
+
+    if return_data:
+        return expired, invalid, user, data
+
+    return expired, invalid, user
+
+
+def generate_email_confirmation_token(user):
+    """Generates a E-Mail confirmation token."""
+    return make_token(user=user, operation="confirm_email")
+
+
+def generate_password_reset_token(user):
+    """Generates a password reset token."""
+    return make_token(user=user, operation="reset_password")