From 76bc957373d2700203578b097b1df377bd33c6f1 Mon Sep 17 00:00:00 2001 From: Place Jean-Marie Date: Sun, 10 Oct 2021 09:26:46 +0200 Subject: [PATCH 1/2] check mail address --- app/scodoc/sco_users.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/scodoc/sco_users.py b/app/scodoc/sco_users.py index d9beb7ba..00cae9fe 100644 --- a/app/scodoc/sco_users.py +++ b/app/scodoc/sco_users.py @@ -29,6 +29,7 @@ """ # Anciennement ZScoUsers.py, fonctions de gestion des données réécrite avec flask/SQLAlchemy +import re from flask import url_for, g, request from flask_login import current_user @@ -396,6 +397,8 @@ def check_modif_user(edit, user_name="", nom="", prenom="", email="", roles=[]): return False, "champ requis vide" if not email: return False, "vous devriez indiquer le mail de l'utilisateur créé !" + if not re.fullmatch(r"[^@]+@[^@]+\.[^@]+", email): + return False, "l'adresse mail semble incorrecte" # ce login existe ? user = _user_list(user_name) if edit and not user: # safety net, le user_name ne devrait pas changer From 7d5eff4f821e30b10872a5f02a99aba89ee064df Mon Sep 17 00:00:00 2001 From: Place Jean-Marie Date: Sun, 10 Oct 2021 10:52:06 +0200 Subject: [PATCH 2/2] refactor check_modif_user --- app/scodoc/sco_import_users.py | 29 ++--------------- app/scodoc/sco_users.py | 57 ++++++++++++++++++++++++++-------- app/views/users.py | 52 ++++++++++++++----------------- 3 files changed, 70 insertions(+), 68 deletions(-) diff --git a/app/scodoc/sco_import_users.py b/app/scodoc/sco_import_users.py index 89ac9989..c3c18109 100644 --- a/app/scodoc/sco_import_users.py +++ b/app/scodoc/sco_import_users.py @@ -179,11 +179,13 @@ def import_users(users): line = line + 1 user_ok, msg = sco_users.check_modif_user( 0, + ignore_optionals=False, user_name=u["user_name"], nom=u["nom"], prenom=u["prenom"], email=u["email"], roles=u["roles"].split(","), + dept=u["dept"], ) if not user_ok: append_msg("identifiant '%s' %s" % (u["user_name"], msg)) @@ -193,39 +195,12 @@ def import_users(users): u["passwd"] = generate_password() # # check identifiant - if not re.match(r"^[a-zA-Z0-9@\\\-_\\\.]*$", u["user_name"]): - user_ok = False - append_msg( - "identifiant '%s' invalide (pas d'accents ni de caractères spéciaux)" - % u["user_name"] - ) - if len(u["user_name"]) > 64: - user_ok = False - append_msg( - "identifiant '%s' trop long (64 caractères)" % u["user_name"] - ) - if len(u["nom"]) > 64: - user_ok = False - append_msg("nom '%s' trop long (64 caractères)" % u["nom"]) - if len(u["prenom"]) > 64: - user_ok = False - append_msg("prenom '%s' trop long (64 caractères)" % u["prenom"]) - if len(u["email"]) > 120: - user_ok = False - append_msg("email '%s' trop long (120 caractères)" % u["email"]) - # check that tha same user_name has not already been described in this import if u["user_name"] in created.keys(): user_ok = False append_msg( "l'utilisateur '%s' a déjà été décrit ligne %s" % (u["user_name"], created[u["user_name"]]["line"]) ) - # check département - if u["dept"] != "": - dept = Departement.query.filter_by(acronym=u["dept"]).first() - if dept is None: - user_ok = False - append_msg("département '%s' inexistant" % u["dept"]) # check roles / ignore whitespaces around roles / build roles_string # roles_string (expected by User) appears as column 'roles' in excel file roles_list = [] diff --git a/app/scodoc/sco_users.py b/app/scodoc/sco_users.py index 00cae9fe..c9512a13 100644 --- a/app/scodoc/sco_users.py +++ b/app/scodoc/sco_users.py @@ -36,7 +36,7 @@ from flask_login import current_user import cracklib # pylint: disable=import-error -from app import db +from app import db, Departement from app.auth.models import Permission from app.auth.models import User @@ -385,7 +385,16 @@ def user_info_page(user_name=None): return "\n".join(H) + F -def check_modif_user(edit, user_name="", nom="", prenom="", email="", roles=[]): +def check_modif_user( + edit, + ignore_optionals=False, + user_name="", + nom="", + prenom="", + email="", + dept="", + roles=[], +): """Vérifie que cet utilisateur peut être créé (edit=0) ou modifié (edit=1) Cherche homonymes. returns (ok, msg) @@ -393,19 +402,44 @@ def check_modif_user(edit, user_name="", nom="", prenom="", email="", roles=[]): (si ok est faux, l'utilisateur peut quand même forcer la creation) - msg: message warning a presenter l'utilisateur """ - if not user_name or not nom or not prenom: - return False, "champ requis vide" - if not email: - return False, "vous devriez indiquer le mail de l'utilisateur créé !" - if not re.fullmatch(r"[^@]+@[^@]+\.[^@]+", email): - return False, "l'adresse mail semble incorrecte" + MSG_OPT = """Attention: %s (vous pouvez forcer l'opération en cochant "Ignorer les avertissements" en bas de page)""" # ce login existe ? user = _user_list(user_name) if edit and not user: # safety net, le user_name ne devrait pas changer return False, "identifiant %s inexistant" % user_name if not edit and user: return False, "identifiant %s déjà utilisé" % user_name - + if not user_name or not nom or not prenom: + return False, "champ requis vide" + if not re.match(r"^[a-zA-Z0-9@\\\-_\\\.]*$", user_name): + return ( + False, + "identifiant '%s' invalide (pas d'accents ni de caractères spéciaux)" + % user_name, + ) + if ignore_optionals and len(user_name) > 64: + return False, "identifiant '%s' trop long (64 caractères)" % user_name + if ignore_optionals and len(nom) > 64: + return False, "nom '%s' trop long (64 caractères)" % nom + MSG_OPT + if ignore_optionals and len(prenom) > 64: + return False, "prenom '%s' trop long (64 caractères)" % prenom + MSG_OPT + # check that tha same user_name has not already been described in this import + if not email: + return False, "vous devriez indiquer le mail de l'utilisateur créé !" + if len(email) > 120: + return False, "email '%s' trop long (120 caractères)" % email + if not re.fullmatch(r"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b", email): + return False, "l'adresse mail semble incorrecte" + # check département + if ( + ignore_optionals + and dept != "" + and Departement.query.filter_by(acronym=dept).first() is None + ): + return False, "département '%s' inexistant" % u["dept"] + MSG_OPT + if ignore_optionals and not roles: + return False, "aucun rôle sélectionné, êtes vous sûr ?" + MSG_OPT + # ok # Des noms/prénoms semblables existent ? nom = nom.lower().strip() prenom = prenom.lower().strip() @@ -425,12 +459,9 @@ def check_modif_user(edit, user_name="", nom="", prenom="", email="", roles=[]): "%s %s (pseudo=%s)" % (x.prenom, x.nom, x.user_name) for x in similar_users ] - ), + ) + MSG_OPT, ) # Roles ? - if not roles: - return False, "aucun rôle sélectionné, êtes vous sûr ?" - # ok return True, "" diff --git a/app/views/users.py b/app/views/users.py index aa72d5ed..85c4a85f 100644 --- a/app/views/users.py +++ b/app/views/users.py @@ -284,7 +284,7 @@ def create_user_form(user_name=None, edit=0, all_roles=1): { "input_type": "separator", "title": "L'utilisateur appartient au département %s" - % auth_dept, + % auth_dept, }, ) ) @@ -295,7 +295,7 @@ def create_user_form(user_name=None, edit=0, all_roles=1): { "input_type": "separator", "title": "L'utilisateur sera crée dans le département %s" - % auth_dept, + % auth_dept, }, ) ) @@ -381,24 +381,20 @@ def create_user_form(user_name=None, edit=0, all_roles=1): H.append(tf_error_message("""Erreur: %s""" % err)) return "\n".join(H) + "\n" + tf[1] + F - if not force: - ok, msg = sco_users.check_modif_user( - edit, - user_name=user_name, - nom=vals["nom"], - prenom=vals["prenom"], - email=vals["email"], - roles=vals["roles"], + ok, msg = sco_users.check_modif_user( + edit, + ignore_optionals= force, + user_name=user_name, + nom=vals["nom"], + prenom=vals["prenom"], + email=vals["email"], + roles=vals["roles"], + ) + if not ok: + H.append( + tf_error_message(msg) ) - if not ok: - H.append( - tf_error_message( - """Attention: %s (vous pouvez forcer l'opération en cochant "Ignorer les avertissements" en bas de page)""" - % msg - ) - ) - - return "\n".join(H) + "\n" + tf[1] + F + return "\n".join(H) + "\n" + tf[1] + F if "date_expiration" in vals: try: @@ -617,9 +613,9 @@ def form_change_password(user_name=None): # check access if not can_handle_passwd(u): return ( - "\n".join(H) - + "

Vous n'avez pas la permission de changer ce mot de passe

" - + F + "\n".join(H) + + "

Vous n'avez pas la permission de changer ce mot de passe

" + + F ) # H.append( @@ -685,7 +681,7 @@ def change_password(user_name, password, password2): "

Changement effectué !

Ne notez pas ce mot de passe, mais mémorisez le !

Rappel: il est interdit de communiquer son mot de passe à un tiers, même si c'est un collègue de confiance !

Si vous n'êtes pas administrateur, le système va vous redemander votre login et nouveau mot de passe au prochain accès.

" ) return ( - """ + """ @@ -693,10 +689,10 @@ def change_password(user_name, password, password2):

Mot de passe changé !

""" - % (scu.SCO_ENCODING, scu.SCO_ENCODING) - + "\n".join(H) - + 'Continuer' - % scu.ScoURL() + % (scu.SCO_ENCODING, scu.SCO_ENCODING) + + "\n".join(H) + + 'Continuer' + % scu.ScoURL() ) return html_sco_header.sco_header() + "\n".join(H) + F @@ -711,7 +707,7 @@ def toggle_active_user(user_name: str = None): raise ScoValueError("invalid user_name") form = DeactivateUserForm() if ( - request.method == "POST" and form.cancel.data + request.method == "POST" and form.cancel.data ): # if cancel button is clicked, the form.cancel.data will be True # flash return redirect(url_for("users.index_html", scodoc_dept=g.scodoc_dept))