aboutsummaryrefslogtreecommitdiff
path: root/gn_auth/auth
diff options
context:
space:
mode:
authorFrederick Muriuki Muriithi2024-05-30 15:14:13 -0500
committerFrederick Muriuki Muriithi2024-06-03 10:02:09 -0500
commitc462653f53858359a81cfed561f1622d7e63102b (patch)
tree57c46d594560187389c036fdfed71c9a7a753e51 /gn_auth/auth
parent5680eb5fd1053f695e5917891f916ae85c212d3e (diff)
downloadgn-auth-c462653f53858359a81cfed561f1622d7e63102b.tar.gz
Send verification email on registration.
Diffstat (limited to 'gn_auth/auth')
-rw-r--r--gn_auth/auth/authorisation/users/views.py56
1 files changed, 54 insertions, 2 deletions
diff --git a/gn_auth/auth/authorisation/users/views.py b/gn_auth/auth/authorisation/users/views.py
index feacae3..8919a6d 100644
--- a/gn_auth/auth/authorisation/users/views.py
+++ b/gn_auth/auth/authorisation/users/views.py
@@ -1,11 +1,22 @@
"""User authorisation endpoints."""
+import sqlite3
+import secrets
+import datetime
import traceback
from typing import Any
from functools import partial
from dataclasses import asdict
-import sqlite3
+from email.headerregistry import Address
from email_validator import validate_email, EmailNotValidError
-from flask import request, jsonify, Response, Blueprint, current_app
+from flask import (
+ request,
+ jsonify,
+ Response,
+ Blueprint,
+ current_app,
+ render_template)
+
+from gn_auth.smtp import send_message, build_email_message
from gn_auth.auth.db import sqlite3 as db
from gn_auth.auth.db.sqlite3 import with_db_connection
@@ -86,6 +97,46 @@ def __assert_not_logged_in__(conn: db.DbConnection):
raise UserRegistrationError(
"Cannot register user while authenticated")
+def user_address(user: User) -> Address:
+ """Compute the `email.headerregistry.Address` from a `User`"""
+ return Address(display_name=user.name, addr_spec=user.email)
+
+def send_verification_email(conn, user: User) -> None:
+ """Send an email verification message."""
+ subject="GeneNetwork: Please Verify Your Email"
+ verification_code = secrets.token_urlsafe(64)
+ generated = datetime.datetime.now()
+ expiration_minutes = 15
+ def __render__(template):
+ return render_template(template,
+ subject=subject,
+ verification_code=verification_code,
+ verification_uri="https://please/change/this/",
+ expiration_minutes=expiration_minutes)
+ with db.cursor(conn) as cursor:
+ cursor.execute(
+ ("INSERT INTO "
+ "user_verification_codes(user_id, code, generated, expires) "
+ "VALUES (:user_id, :code, :generated, :expires)"),
+ {
+ "user_id": str(user.user_id),
+ "code": verification_code,
+ "generated": int(generated.timestamp()),
+ "expires": int(
+ (generated +
+ datetime.timedelta(
+ minutes=expiration_minutes)).timestamp())
+ })
+ send_message(smtp_user=current_app.config["SMTP_USER"],
+ smtp_passwd=current_app.config["SMTP_PASSWORD"],
+ message=build_email_message(
+ to_addresses=(user_address(user),),
+ subject=subject,
+ txtmessage=__render__("emails/verify-email.txt"),
+ htmlmessage=__render__("emails/verify-email.html")),
+ host=current_app.config["SMTP_HOST"],
+ port=current_app.config["SMTP_PORT"])
+
@users.route("/register", methods=["POST"])
def register_user() -> Response:
"""Register a user."""
@@ -105,6 +156,7 @@ def register_user() -> Response:
cursor, save_user(
cursor, email["email"], user_name), password)
assign_default_roles(cursor, user)
+ send_verification_email(conn, user)
return jsonify(asdict(user))
except sqlite3.IntegrityError as sq3ie:
current_app.logger.debug(traceback.format_exc())