aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrederick Muriuki Muriithi2024-05-30 16:13:04 -0500
committerFrederick Muriuki Muriithi2024-06-03 10:08:23 -0500
commitffe9e7104ba83b73d78d66de2d29ad4ace6de2da (patch)
tree82dd7cf2265c11d6d0e7714b9680ab5bec92277a
parentc462653f53858359a81cfed561f1622d7e63102b (diff)
downloadgn-auth-ffe9e7104ba83b73d78d66de2d29ad4ace6de2da.tar.gz
Provide endpoint for verification and do verification
-rw-r--r--gn_auth/auth/authorisation/users/views.py54
-rw-r--r--gn_auth/auth/errors.py3
-rw-r--r--gn_auth/templates/emails/verify-email.html27
-rw-r--r--gn_auth/templates/emails/verify-email.txt2
4 files changed, 60 insertions, 26 deletions
diff --git a/gn_auth/auth/authorisation/users/views.py b/gn_auth/auth/authorisation/users/views.py
index 8919a6d..638f0df 100644
--- a/gn_auth/auth/authorisation/users/views.py
+++ b/gn_auth/auth/authorisation/users/views.py
@@ -25,11 +25,16 @@ from gn_auth.auth.authorisation.resources.models import (
user_resources as _user_resources)
from gn_auth.auth.authorisation.roles.models import (
assign_default_roles, user_roles as _user_roles)
-from gn_auth.auth.errors import (
- NotFoundError, UsernameError, PasswordError, UserRegistrationError)
from gn_auth.auth.authorisation.resources.groups.models import (
user_group as _user_group)
+from gn_auth.auth.errors import (
+ NotFoundError,
+ UsernameError,
+ PasswordError,
+ UserVerificationError,
+ UserRegistrationError)
+
from gn_auth.auth.authentication.oauth2.resource_server import require_oauth
from gn_auth.auth.authentication.users import User, save_user, set_user_password
from gn_auth.auth.authentication.oauth2.models.oauth2token import (
@@ -169,6 +174,51 @@ def register_user() -> Response:
raise Exception(
"unknown_error", "The system experienced an unexpected error.")
+def delete_verification_code(cursor, code: str):
+ """Delete verification code from db."""
+ cursor.execute("DELETE FROM user_verification_codes "
+ "WHERE code=:code",
+ {"code": code})
+
+@users.route("/verify", methods=["GET", "POST"])
+def verify_user():
+ """Verify users are not bots."""
+ code = request.args.get("verificationcode",
+ request.form.get("verificationcode",
+ "nosuchcode"))
+ with (db.connection(current_app.config["AUTH_DB"]) as conn,
+ db.cursor(conn) as cursor):
+ cursor.execute("SELECT * FROM user_verification_codes "
+ "WHERE code=:code",
+ {"code": code})
+ results = tuple(dict(row) for row in cursor.fetchall())
+
+ if not bool(results):
+ raise UserVerificationError(
+ "Invalid verification code: code not found.")
+
+ if len(results) > 1:
+ delete_verification_code(cursor, code)
+ raise UserVerificationError(
+ "Invalid verification code: code is duplicated.")
+
+ results = results[0]
+ if (datetime.datetime.fromtimestamp(
+ int(results["expires"])) < datetime.datetime.now()):
+ delete_verification_code(cursor, code)
+ raise UserVerificationError(
+ "Invalid verification code: code has expired.")
+
+ # Code is good!
+ delete_verification_code(cursor, code)
+ cursor.execute("UPDATE users SET verified=1 WHERE user_id=:user_id",
+ {"user_id": results["user_id"]})
+ return jsonify({
+ "status": "success",
+ "message": "User verification successful!"
+ })
+
+
@users.route("/group", methods=["GET"])
@require_oauth("profile group")
def user_group() -> Response:
diff --git a/gn_auth/auth/errors.py b/gn_auth/auth/errors.py
index 60d6a22..77b73aa 100644
--- a/gn_auth/auth/errors.py
+++ b/gn_auth/auth/errors.py
@@ -15,6 +15,9 @@ class ForbiddenAccess(AuthorisationError):
class UserRegistrationError(AuthorisationError):
"""Raised whenever a user registration fails"""
+class UserVerificationError(UserRegistrationError):
+ """Raised when verification of a user fails."""
+
class NotFoundError(AuthorisationError):
"""Raised whenever we try fetching (a/an) object(s) that do(es) not exist."""
error_code: int = 404
diff --git a/gn_auth/templates/emails/verify-email.html b/gn_auth/templates/emails/verify-email.html
index 08f1dfe..bc475c9 100644
--- a/gn_auth/templates/emails/verify-email.html
+++ b/gn_auth/templates/emails/verify-email.html
@@ -2,25 +2,6 @@
<head>
<meta charset="UTF-8" />
<title>{{subject}}</title>
- <style type="text/css">
- .btn {
- display: inline-block;
- text-align: center;
- vertical-align: center;
- cursor: pointer;
- border-radius: 4px;
- background-color: #336699;
- border-color: #357ebd;
- }
- .verification-code{
- color: #3A3AFF;
- font-weight: bolder;
- }
- .note {
- font-weight: bold;
- color: #ee55ee;
- }
- </style>
</head>
<body>
<p>Thank you for registering an account with GeneNetwork.</p>
@@ -28,8 +9,8 @@
<p>
To avoid bots, we need to verify that you are an actual human. To do so,
please
- <a href="{{verification_uri}}/{{verification_code}}"
- class="btn">
+ <a href="{{verification_uri}}?verificationcode={{verification_code}}"
+ style="display: inline-block;text-align: center;vertical-align: center;cursor: pointer;border-radius: 4px;background-color: #336699;border-color: #357ebd;">
Click here
</a>.
</p>
@@ -38,10 +19,10 @@
If that does not work, please log in to GeneNetwork and copy the
verification code below when requested:<br /><br />
- <span class="verification-code">{{verification_code}}</span>
+ <span style="color: #3A3AFF;font-weight: bolder;">{{verification_code}}</span>
</p>
- <p class="note">
+ <p style="font-weight: bold;color: #ee55ee;">
Please note that the verification code will expire in
<strong>{{expiration_minutes}}</strong> minutes after it was generated.
</p>
diff --git a/gn_auth/templates/emails/verify-email.txt b/gn_auth/templates/emails/verify-email.txt
index 92a6435..7a39fea 100644
--- a/gn_auth/templates/emails/verify-email.txt
+++ b/gn_auth/templates/emails/verify-email.txt
@@ -3,7 +3,7 @@
Thank you for registering an account with GeneNetwork.
-To avoid bots, we need to verify that you are an actual human. To do so, please go to "{{verification_uri}}/{{verification_code}}".
+To avoid bots, we need to verify that you are an actual human. To do so, please go to "{{verification_uri}}?verificationcode={{verification_code}}".
If that does not work, please log in to GeneNetwork and copy the verification code below when requested: