Skip to content

Commit

Permalink
[user_manager] Sanitize email before adding in database (#737)
Browse files Browse the repository at this point in the history
Fixes #512
  • Loading branch information
nrybowski committed Feb 25, 2022
1 parent f84a3cf commit 7cf81aa
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 10 deletions.
2 changes: 1 addition & 1 deletion inginious/frontend/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
# This file is part of INGInious. See the LICENSE and the COPYRIGHTS files for
# more information about the licensing of this file.

""" Package that implements a webapp for INGInious """
""" Package that implements a webapp for INGInious """
9 changes: 8 additions & 1 deletion inginious/frontend/installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from pymongo import MongoClient
from inginious import __version__
import inginious.common.custom_yaml as yaml
from inginious.frontend.user_manager import UserManager

HEADER = '\033[95m'
INFO = '\033[94m'
Expand Down Expand Up @@ -550,7 +551,13 @@ def configure_authentication(self, database):

username = self._ask_with_default("Enter the login of the superadmin", "superadmin")
realname = self._ask_with_default("Enter the name of the superadmin", "INGInious SuperAdmin")
email = self._ask_with_default("Enter the email address of the superadmin", "superadmin@inginious.org")
email = None
while not email:
email = self._ask_with_default("Enter the email address of the superadmin", "superadmin@inginious.org")
email = UserManager.sanitize_email(email)
if email is None:
self._display_error("Invalid email format.")

password = self._ask_with_default("Enter the password of the superadmin", "superadmin")

database.users.insert_one({"username": username,
Expand Down
14 changes: 6 additions & 8 deletions inginious/frontend/pages/register.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from werkzeug.exceptions import Forbidden
from inginious.frontend.pages.utils import INGIniousPage
from inginious.frontend.flask.mail import mail
from inginious.frontend.user_manager import UserManager


class RegistrationPage(INGIniousPage):
Expand Down Expand Up @@ -72,16 +73,13 @@ def register_user(self, data):
error = False
msg = ""

email_re = re.compile(
r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*" # dot-atom
r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-011\013\014\016-\177])*"' # quoted-string
r')@(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?$', re.IGNORECASE) # domain
email = UserManager.sanitize_email(data["email"])

# Check input format
if re.match(r"^[-_|~0-9A-Z]{4,}$", data["username"], re.IGNORECASE) is None:
error = True
msg = _("Invalid username format.")
elif email_re.match(data["email"]) is None:
elif email is None:
error = True
msg = _("Invalid email format.")
elif len(data["passwd"]) < 6:
Expand All @@ -96,7 +94,7 @@ def register_user(self, data):

if not error:
existing_user = self.database.users.find_one(
{"$or": [{"username": data["username"]}, {"email": data["email"]}]})
{"$or": [{"username": data["username"]}, {"email": email}]})
if existing_user is not None:
error = True
if existing_user["username"] == data["username"]:
Expand All @@ -108,7 +106,7 @@ def register_user(self, data):
activate_hash = hashlib.sha512(str(random.getrandbits(256)).encode("utf-8")).hexdigest()
self.database.users.insert_one({"username": data["username"],
"realname": data["realname"],
"email": data["email"],
"email": email,
"password": passwd_hash,
"activate": activate_hash,
"bindings": {},
Expand All @@ -122,7 +120,7 @@ def register_user(self, data):
To activate your account, please click on the following link :
""") + flask.request.url_root + "register?activate=" + activate_hash

message = Message(recipients=[(data["realname"], data["email"])],
message = Message(recipients=[(data["realname"], email)],
subject=subject,
body=body)
mail.send(message)
Expand Down
21 changes: 21 additions & 0 deletions inginious/frontend/user_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import pymongo
from binascii import hexlify
import os
import re


class AuthInvalidInputException(Exception):
Expand Down Expand Up @@ -100,6 +101,22 @@ def __init__(self, database, superadmins):
self._auth_methods = OrderedDict()
self._logger = logging.getLogger("inginious.webapp.users")

@classmethod
def sanitize_email(cls, email: str) -> str:
"""
Sanitize an email address and put the bar part of an address foo@bar in lower case.
"""
email_re = re.compile(
r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*" # dot-atom
r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-011\013\014\016-\177])*"' # quoted-string
r')@(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?$', re.IGNORECASE) # domain

if email_re.match(email) is None:
return None

email = email.split('@')
return "%s@%s" % (email[0], email[1].lower())

##############################################
# User session management #
##############################################
Expand Down Expand Up @@ -386,6 +403,10 @@ def get_user_api_key(self, username, create=True):

def bind_user(self, auth_id, user):
username, realname, email, additional = user
email = UserManager.sanitize_email(email)
if email is None:
self._logger.exception("Invalid email format.")
return False

auth_method = self.get_auth_method(auth_id)
if not auth_method:
Expand Down

0 comments on commit 7cf81aa

Please sign in to comment.