forked from Github-Mirrors/canaille
invitations expire after 48h
This commit is contained in:
parent
ebc16b91c2
commit
db1d011a3b
10 changed files with 286 additions and 120 deletions
|
@ -1,4 +1,9 @@
|
||||||
import io
|
import io
|
||||||
|
from dataclasses import astuple
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from datetime import datetime
|
||||||
|
from datetime import timedelta
|
||||||
|
from typing import List
|
||||||
|
|
||||||
import pkg_resources
|
import pkg_resources
|
||||||
import wtforms
|
import wtforms
|
||||||
|
@ -162,6 +167,32 @@ def users(user):
|
||||||
return render_template("users.html", users=users, menuitem="users")
|
return render_template("users.html", users=users, menuitem="users")
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Invitation:
|
||||||
|
creation_date_isoformat: str
|
||||||
|
uid: str
|
||||||
|
mail: str
|
||||||
|
groups: List[str]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def creation_date(self):
|
||||||
|
return datetime.fromisoformat(self.creation_date_isoformat)
|
||||||
|
|
||||||
|
def has_expired(self):
|
||||||
|
DEFAULT_INVITATION_DURATION = 2 * 24 * 60 * 60
|
||||||
|
return datetime.now() - self.creation_date > timedelta(
|
||||||
|
seconds=current_app.config.get(
|
||||||
|
"INVITATION_EXPIRATION", DEFAULT_INVITATION_DURATION
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def b64(self):
|
||||||
|
return obj_to_b64(astuple(self))
|
||||||
|
|
||||||
|
def profile_hash(self):
|
||||||
|
return profile_hash(*astuple(self))
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/invite", methods=["GET", "POST"])
|
@bp.route("/invite", methods=["GET", "POST"])
|
||||||
@smtp_needed()
|
@smtp_needed()
|
||||||
@permissions_needed("manage_users")
|
@permissions_needed("manage_users")
|
||||||
|
@ -173,10 +204,16 @@ def user_invitation(user):
|
||||||
form_validated = False
|
form_validated = False
|
||||||
if request.form and form.validate():
|
if request.form and form.validate():
|
||||||
form_validated = True
|
form_validated = True
|
||||||
|
invitation = Invitation(
|
||||||
|
datetime.now().isoformat(),
|
||||||
|
form.uid.data,
|
||||||
|
form.mail.data,
|
||||||
|
form.groups.data,
|
||||||
|
)
|
||||||
registration_url = url_for(
|
registration_url = url_for(
|
||||||
"account.registration",
|
"account.registration",
|
||||||
data=obj_to_b64([form.uid.data, form.mail.data, form.groups.data]),
|
data=invitation.b64(),
|
||||||
hash=profile_hash(form.uid.data, form.mail.data, form.groups.data),
|
hash=invitation.profile_hash(),
|
||||||
_external=True,
|
_external=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -223,7 +260,7 @@ def profile_creation(user):
|
||||||
@bp.route("/register/<data>/<hash>", methods=["GET", "POST"])
|
@bp.route("/register/<data>/<hash>", methods=["GET", "POST"])
|
||||||
def registration(data, hash):
|
def registration(data, hash):
|
||||||
try:
|
try:
|
||||||
data = b64_to_obj(data)
|
invitation = Invitation(*b64_to_obj(data))
|
||||||
except:
|
except:
|
||||||
flash(
|
flash(
|
||||||
_("The invitation link that brought you here was invalid."),
|
_("The invitation link that brought you here was invalid."),
|
||||||
|
@ -231,7 +268,14 @@ def registration(data, hash):
|
||||||
)
|
)
|
||||||
return redirect(url_for("account.index"))
|
return redirect(url_for("account.index"))
|
||||||
|
|
||||||
if User.get(data[0]):
|
if invitation.has_expired():
|
||||||
|
flash(
|
||||||
|
_("The invitation link that brought you here has expired."),
|
||||||
|
"error",
|
||||||
|
)
|
||||||
|
return redirect(url_for("account.index"))
|
||||||
|
|
||||||
|
if User.get(invitation.uid):
|
||||||
flash(
|
flash(
|
||||||
_("Your account has already been created."),
|
_("Your account has already been created."),
|
||||||
"error",
|
"error",
|
||||||
|
@ -245,18 +289,14 @@ def registration(data, hash):
|
||||||
)
|
)
|
||||||
return redirect(url_for("account.index"))
|
return redirect(url_for("account.index"))
|
||||||
|
|
||||||
if hash != profile_hash(*data):
|
if hash != invitation.profile_hash():
|
||||||
flash(
|
flash(
|
||||||
_("The invitation link that brought you here was invalid."),
|
_("The invitation link that brought you here was invalid."),
|
||||||
"error",
|
"error",
|
||||||
)
|
)
|
||||||
return redirect(url_for("account.index"))
|
return redirect(url_for("account.index"))
|
||||||
|
|
||||||
data = {
|
data = {"uid": invitation.uid, "mail": invitation.mail, "groups": invitation.groups}
|
||||||
"uid": data[0],
|
|
||||||
"mail": data[1],
|
|
||||||
"groups": data[2],
|
|
||||||
}
|
|
||||||
|
|
||||||
readable_fields, writable_fields = default_fields()
|
readable_fields, writable_fields = default_fields()
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,10 @@ OIDC_METADATA_FILE = "canaille/conf/openid-configuration.json"
|
||||||
# wether the login exists or not.
|
# wether the login exists or not.
|
||||||
# HIDE_INVALID_LOGINS = false
|
# HIDE_INVALID_LOGINS = false
|
||||||
|
|
||||||
|
# The validity duration of registration invitations, in seconds.
|
||||||
|
# Defaults to 2 days
|
||||||
|
# INVITATION_EXPIRATION = 172800
|
||||||
|
|
||||||
[LOGGING]
|
[LOGGING]
|
||||||
# LEVEL can be one value among:
|
# LEVEL can be one value among:
|
||||||
# DEBUG, INFO, WARNING, ERROR, CRITICAL
|
# DEBUG, INFO, WARNING, ERROR, CRITICAL
|
||||||
|
|
|
@ -5,13 +5,13 @@
|
||||||
<div class="ui segment">
|
<div class="ui segment">
|
||||||
<h2 class="ui center aligned header">
|
<h2 class="ui center aligned header">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
{{ _("Test d'envoi") }}
|
{{ _("Mail sending test") }}
|
||||||
</div>
|
</div>
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<div class="ui info message">
|
<div class="ui info message">
|
||||||
{% trans -%}
|
{% trans -%}
|
||||||
This form will a fake invitation email to the address you want.
|
This form will send a fake invitation email to the address you want.
|
||||||
This should be used for testing mail configuration.
|
This should be used for testing mail configuration.
|
||||||
{%- endtrans %}
|
{%- endtrans %}
|
||||||
</div>
|
</div>
|
||||||
|
|
Binary file not shown.
|
@ -3,14 +3,14 @@
|
||||||
# This file is distributed under the same license as the PROJECT project.
|
# This file is distributed under the same license as the PROJECT project.
|
||||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2020.
|
# FIRST AUTHOR <EMAIL@ADDRESS>, 2020.
|
||||||
# Éloi Rivard <eloi.rivard@aquilenet.fr>, 2020-2021.
|
# Éloi Rivard <eloi.rivard@aquilenet.fr>, 2020-2021.
|
||||||
# Camille <camille@yaal.coop>, 2021.
|
# Camille <camille@yaal.coop>, 2021-2022.
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PROJECT VERSION\n"
|
"Project-Id-Version: PROJECT VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: contact@yaal.fr\n"
|
"Report-Msgid-Bugs-To: contact@yaal.fr\n"
|
||||||
"POT-Creation-Date: 2021-12-23 18:45+0100\n"
|
"POT-Creation-Date: 2022-01-01 11:24+0100\n"
|
||||||
"PO-Revision-Date: 2021-12-23 18:48+0100\n"
|
"PO-Revision-Date: 2022-01-01 11:26+0100\n"
|
||||||
"Last-Translator: Camille <camille@yaal.coop>\n"
|
"Last-Translator: Camille <camille@yaal.coop>\n"
|
||||||
"Language: fr\n"
|
"Language: fr\n"
|
||||||
"Language-Team: French <contact@yaal.coop>\n"
|
"Language-Team: French <contact@yaal.coop>\n"
|
||||||
|
@ -21,34 +21,34 @@ msgstr ""
|
||||||
"Generated-By: Babel 2.9.1\n"
|
"Generated-By: Babel 2.9.1\n"
|
||||||
"X-Generator: Gtranslator 40.0\n"
|
"X-Generator: Gtranslator 40.0\n"
|
||||||
|
|
||||||
#: canaille/__init__.py:134
|
#: canaille/__init__.py:131
|
||||||
msgid "Could not connect to the LDAP server '{uri}'"
|
msgid "Could not connect to the LDAP server '{uri}'"
|
||||||
msgstr "Impossible de se connecter au serveur LDAP '{uri}'"
|
msgstr "Impossible de se connecter au serveur LDAP '{uri}'"
|
||||||
|
|
||||||
#: canaille/__init__.py:150
|
#: canaille/__init__.py:147
|
||||||
msgid "LDAP authentication failed with user '{user}'"
|
msgid "LDAP authentication failed with user '{user}'"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"L'authentification au serveur LDAP a échoué pour l'utilisateur '{user}'"
|
"L'authentification au serveur LDAP a échoué pour l'utilisateur '{user}'"
|
||||||
|
|
||||||
#: canaille/account.py:77 canaille/account.py:102 canaille/oauth.py:77
|
#: canaille/account.py:82 canaille/account.py:107 canaille/oauth.py:77
|
||||||
msgid "Login failed, please check your information"
|
msgid "Login failed, please check your information"
|
||||||
msgstr "La connexion a échoué, veuillez vérifier vos informations."
|
msgstr "La connexion a échoué, veuillez vérifier vos informations."
|
||||||
|
|
||||||
#: canaille/account.py:108
|
#: canaille/account.py:113
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Connection successful. Welcome %(user)s"
|
msgid "Connection successful. Welcome %(user)s"
|
||||||
msgstr "Connexion réussie. Bienvenue %(user)s"
|
msgstr "Connexion réussie. Bienvenue %(user)s"
|
||||||
|
|
||||||
#: canaille/account.py:121
|
#: canaille/account.py:126
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "You have been disconnected. See you next time %(user)s"
|
msgid "You have been disconnected. See you next time %(user)s"
|
||||||
msgstr "Vous avez été déconnecté·e. À bientôt %(user)s"
|
msgstr "Vous avez été déconnecté·e. À bientôt %(user)s"
|
||||||
|
|
||||||
#: canaille/account.py:138
|
#: canaille/account.py:143
|
||||||
msgid "Could not send the password initialization link."
|
msgid "Could not send the password initialization link."
|
||||||
msgstr "Impossible d'envoyer le courriel d'initialisation de mot de passe."
|
msgstr "Impossible d'envoyer le courriel d'initialisation de mot de passe."
|
||||||
|
|
||||||
#: canaille/account.py:143
|
#: canaille/account.py:148
|
||||||
msgid ""
|
msgid ""
|
||||||
"A password initialization link has been sent at your email address. You "
|
"A password initialization link has been sent at your email address. You "
|
||||||
"should receive it within 10 minutes."
|
"should receive it within 10 minutes."
|
||||||
|
@ -56,35 +56,39 @@ msgstr ""
|
||||||
"Un lien d'initialisation de votre mot de passe vous a été envoyé par mail. "
|
"Un lien d'initialisation de votre mot de passe vous a été envoyé par mail. "
|
||||||
"Vous devriez le recevoir d'ici une dizaine de minutes."
|
"Vous devriez le recevoir d'ici une dizaine de minutes."
|
||||||
|
|
||||||
#: canaille/account.py:149 canaille/account.py:353
|
#: canaille/account.py:154 canaille/account.py:388
|
||||||
msgid "Could not send the password initialization email"
|
msgid "Could not send the password initialization email"
|
||||||
msgstr "Impossible d'envoyer le courriel d'initialisation de mot de passe."
|
msgstr "Impossible d'envoyer le courriel d'initialisation de mot de passe."
|
||||||
|
|
||||||
#: canaille/account.py:208 canaille/account.py:279
|
#: canaille/account.py:240 canaille/account.py:314
|
||||||
msgid "User account creation failed."
|
msgid "User account creation failed."
|
||||||
msgstr "La création du compte utilisateur a échoué."
|
msgstr "La création du compte utilisateur a échoué."
|
||||||
|
|
||||||
#: canaille/account.py:229 canaille/account.py:250
|
#: canaille/account.py:261 canaille/account.py:289
|
||||||
msgid "The invitation link that brought you here was invalid."
|
msgid "The invitation link that brought you here was invalid."
|
||||||
msgstr "Le lien d'invitation qui vous a amené ici est invalide."
|
msgstr "Le lien d'invitation qui vous a amené ici est invalide."
|
||||||
|
|
||||||
#: canaille/account.py:236
|
#: canaille/account.py:268
|
||||||
|
msgid "The invitation link that brought you here has expired."
|
||||||
|
msgstr "Le lien d'invitation qui vous a amené ici a expiré."
|
||||||
|
|
||||||
|
#: canaille/account.py:275
|
||||||
msgid "Your account has already been created."
|
msgid "Your account has already been created."
|
||||||
msgstr "Votre compte a déjà été créé."
|
msgstr "Votre compte a déjà été créé."
|
||||||
|
|
||||||
#: canaille/account.py:243
|
#: canaille/account.py:282
|
||||||
msgid "You are already logged in, you cannot create an account."
|
msgid "You are already logged in, you cannot create an account."
|
||||||
msgstr "Vous êtes déjà connectés, vous ne pouvez pas créer de compte."
|
msgstr "Vous êtes déjà connectés, vous ne pouvez pas créer de compte."
|
||||||
|
|
||||||
#: canaille/account.py:284
|
#: canaille/account.py:319
|
||||||
msgid "You account has been created successfuly."
|
msgid "You account has been created successfuly."
|
||||||
msgstr "Votre compte utilisateur a été créé avec succès."
|
msgstr "Votre compte utilisateur a été créé avec succès."
|
||||||
|
|
||||||
#: canaille/account.py:326
|
#: canaille/account.py:361
|
||||||
msgid "User account creation succeed."
|
msgid "User account creation succeed."
|
||||||
msgstr "La création du compte utilisateur a réussi."
|
msgstr "La création du compte utilisateur a réussi."
|
||||||
|
|
||||||
#: canaille/account.py:347
|
#: canaille/account.py:382
|
||||||
msgid ""
|
msgid ""
|
||||||
"A password initialization link has been sent at the user email address. It "
|
"A password initialization link has been sent at the user email address. It "
|
||||||
"should be received within 10 minutes."
|
"should be received within 10 minutes."
|
||||||
|
@ -92,7 +96,7 @@ msgstr ""
|
||||||
"Un lien d'initialisation de mot de passe a été envoyé à l'utilisateur par "
|
"Un lien d'initialisation de mot de passe a été envoyé à l'utilisateur par "
|
||||||
"mail. Il devrait arriver d'ici une dizaine de minutes."
|
"mail. Il devrait arriver d'ici une dizaine de minutes."
|
||||||
|
|
||||||
#: canaille/account.py:361
|
#: canaille/account.py:396
|
||||||
msgid ""
|
msgid ""
|
||||||
"A password reset link has been sent at the user email address. It should be "
|
"A password reset link has been sent at the user email address. It should be "
|
||||||
"received within 10 minutes."
|
"received within 10 minutes."
|
||||||
|
@ -100,28 +104,28 @@ msgstr ""
|
||||||
"Un lien de réinitialisation de mot de passe a été envoyé à l'utilisateur par "
|
"Un lien de réinitialisation de mot de passe a été envoyé à l'utilisateur par "
|
||||||
"mail. Il devrait arriver d'ici une dizaine de minutes."
|
"mail. Il devrait arriver d'ici une dizaine de minutes."
|
||||||
|
|
||||||
#: canaille/account.py:367
|
#: canaille/account.py:402
|
||||||
msgid "Could not send the password reset email"
|
msgid "Could not send the password reset email"
|
||||||
msgstr "Impossible d'envoyer le lien de réinitialisation."
|
msgstr "Impossible d'envoyer le lien de réinitialisation."
|
||||||
|
|
||||||
#: canaille/account.py:398
|
#: canaille/account.py:433
|
||||||
msgid "Profile edition failed."
|
msgid "Profile edition failed."
|
||||||
msgstr "L'édition du profil a échoué."
|
msgstr "L'édition du profil a échoué."
|
||||||
|
|
||||||
#: canaille/account.py:426
|
#: canaille/account.py:461
|
||||||
msgid "Profile updated successfuly."
|
msgid "Profile updated successfuly."
|
||||||
msgstr "Le profil a été mis à jour avec succès."
|
msgstr "Le profil a été mis à jour avec succès."
|
||||||
|
|
||||||
#: canaille/account.py:446
|
#: canaille/account.py:481
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "The user %(user)s has been sucessfuly deleted"
|
msgid "The user %(user)s has been sucessfuly deleted"
|
||||||
msgstr "L'utilisateur %(user)s a bien été supprimé"
|
msgstr "L'utilisateur %(user)s a bien été supprimé"
|
||||||
|
|
||||||
#: canaille/account.py:470
|
#: canaille/account.py:505
|
||||||
msgid "Could not send the password reset link."
|
msgid "Could not send the password reset link."
|
||||||
msgstr "Impossible d'envoyer le lien de réinitialisation."
|
msgstr "Impossible d'envoyer le lien de réinitialisation."
|
||||||
|
|
||||||
#: canaille/account.py:477 canaille/account.py:488
|
#: canaille/account.py:512 canaille/account.py:523
|
||||||
msgid ""
|
msgid ""
|
||||||
"A password reset link has been sent at your email address. You should "
|
"A password reset link has been sent at your email address. You should "
|
||||||
"receive it within 10 minutes."
|
"receive it within 10 minutes."
|
||||||
|
@ -129,15 +133,15 @@ msgstr ""
|
||||||
"Un lien de ré-initialisation de votre mot de passe vous a été envoyé par "
|
"Un lien de ré-initialisation de votre mot de passe vous a été envoyé par "
|
||||||
"mail. Vous devriez le recevoir d'ici une dizaine de minutes."
|
"mail. Vous devriez le recevoir d'ici une dizaine de minutes."
|
||||||
|
|
||||||
#: canaille/account.py:494
|
#: canaille/account.py:529
|
||||||
msgid "Could not reset your password"
|
msgid "Could not reset your password"
|
||||||
msgstr "Impossible de réinitialiser votre mot de passe"
|
msgstr "Impossible de réinitialiser votre mot de passe"
|
||||||
|
|
||||||
#: canaille/account.py:508
|
#: canaille/account.py:543
|
||||||
msgid "The password reset link that brought you here was invalid."
|
msgid "The password reset link that brought you here was invalid."
|
||||||
msgstr "Le lien de réinitialisation qui vous a amené ici est invalide."
|
msgstr "Le lien de réinitialisation qui vous a amené ici est invalide."
|
||||||
|
|
||||||
#: canaille/account.py:517
|
#: canaille/account.py:552
|
||||||
msgid "Your password has been updated successfuly"
|
msgid "Your password has been updated successfuly"
|
||||||
msgstr "Votre mot de passe a correctement été mis à jour."
|
msgstr "Votre mot de passe a correctement été mis à jour."
|
||||||
|
|
||||||
|
@ -189,8 +193,8 @@ msgstr "L'identifiant '{login}' n'existe pas"
|
||||||
msgid "Login"
|
msgid "Login"
|
||||||
msgstr "Identifiant"
|
msgstr "Identifiant"
|
||||||
|
|
||||||
#: canaille/forms.py:47 canaille/forms.py:71 canaille/forms.py:122
|
#: canaille/admin/mail.py:29 canaille/forms.py:47 canaille/forms.py:71
|
||||||
#: canaille/forms.py:222
|
#: canaille/forms.py:122 canaille/forms.py:222
|
||||||
msgid "jane@doe.com"
|
msgid "jane@doe.com"
|
||||||
msgstr "camille@dupont.fr"
|
msgstr "camille@dupont.fr"
|
||||||
|
|
||||||
|
@ -311,11 +315,11 @@ msgstr "L'édition du groupe a échoué."
|
||||||
msgid "The group %(group)s has been sucessfully deleted"
|
msgid "The group %(group)s has been sucessfully deleted"
|
||||||
msgstr "Le groupe %(group)s a bien été supprimé"
|
msgstr "Le groupe %(group)s a bien été supprimé"
|
||||||
|
|
||||||
#: canaille/admin/mail.py:79 canaille/mails.py:25
|
#: canaille/admin/mail.py:108 canaille/mails.py:25
|
||||||
msgid "Password reset on {website_name}"
|
msgid "Password reset on {website_name}"
|
||||||
msgstr "Réinitialisation du mot de passe sur {website_name}"
|
msgstr "Réinitialisation du mot de passe sur {website_name}"
|
||||||
|
|
||||||
#: canaille/admin/mail.py:37 canaille/mails.py:65
|
#: canaille/admin/mail.py:66 canaille/mails.py:65
|
||||||
msgid "Password initialization on {website_name}"
|
msgid "Password initialization on {website_name}"
|
||||||
msgstr "Initialisation de votre mot de passe sur {website_name}"
|
msgstr "Initialisation de votre mot de passe sur {website_name}"
|
||||||
|
|
||||||
|
@ -431,11 +435,19 @@ msgstr "Le client a été édité."
|
||||||
msgid "The client has been deleted."
|
msgid "The client has been deleted."
|
||||||
msgstr "Le client a été supprimé."
|
msgstr "Le client a été supprimé."
|
||||||
|
|
||||||
#: canaille/admin/mail.py:121
|
#: canaille/admin/mail.py:23 canaille/templates/userlist.html:14
|
||||||
|
msgid "Email"
|
||||||
|
msgstr "Courriel"
|
||||||
|
|
||||||
|
#: canaille/admin/mail.py:42 canaille/admin/mail.py:44
|
||||||
|
msgid "The test invitation mail has been sent correctly"
|
||||||
|
msgstr "L'invitation de test a été envoyée correctement"
|
||||||
|
|
||||||
|
#: canaille/admin/mail.py:150
|
||||||
msgid "Invitation on {website_name}"
|
msgid "Invitation on {website_name}"
|
||||||
msgstr "Invitation sur {website_name}"
|
msgstr "Invitation sur {website_name}"
|
||||||
|
|
||||||
#: canaille/templates/about.html:12 canaille/themes/default/base.html:98
|
#: canaille/templates/about.html:12 canaille/themes/default/base.html:102
|
||||||
msgid "About canaille"
|
msgid "About canaille"
|
||||||
msgstr "À propos de canaille"
|
msgstr "À propos de canaille"
|
||||||
|
|
||||||
|
@ -583,11 +595,11 @@ msgstr "Envoyer le courriel d'initialisation"
|
||||||
#: canaille/templates/admin/client_edit.html:35
|
#: canaille/templates/admin/client_edit.html:35
|
||||||
#: canaille/templates/admin/client_edit.html:44
|
#: canaille/templates/admin/client_edit.html:44
|
||||||
#: canaille/templates/admin/client_edit.html:53
|
#: canaille/templates/admin/client_edit.html:53
|
||||||
#: canaille/templates/fomanticui.html:62
|
#: canaille/templates/fomanticui.html:64
|
||||||
msgid "This field is not editable"
|
msgid "This field is not editable"
|
||||||
msgstr "Ce champ n'est pas modifiable"
|
msgstr "Ce champ n'est pas modifiable"
|
||||||
|
|
||||||
#: canaille/templates/fomanticui.html:66
|
#: canaille/templates/fomanticui.html:68
|
||||||
msgid "This field is required"
|
msgid "This field is required"
|
||||||
msgstr "Ce champ est requis"
|
msgstr "Ce champ est requis"
|
||||||
|
|
||||||
|
@ -618,6 +630,7 @@ msgstr ""
|
||||||
msgid "Send again"
|
msgid "Send again"
|
||||||
msgstr "Envoyer à nouveau"
|
msgstr "Envoyer à nouveau"
|
||||||
|
|
||||||
|
#: canaille/templates/admin/mails.html:23
|
||||||
#: canaille/templates/forgotten-password.html:40
|
#: canaille/templates/forgotten-password.html:40
|
||||||
msgid "Send"
|
msgid "Send"
|
||||||
msgstr "Envoyer"
|
msgstr "Envoyer"
|
||||||
|
@ -934,7 +947,7 @@ msgstr ""
|
||||||
msgid "Send mail"
|
msgid "Send mail"
|
||||||
msgstr "Envoyer l'email"
|
msgstr "Envoyer l'email"
|
||||||
|
|
||||||
#: canaille/templates/admin/mails.html:34 canaille/templates/profile.html:221
|
#: canaille/templates/admin/mails.html:56 canaille/templates/profile.html:221
|
||||||
#: canaille/templates/reset-password.html:11
|
#: canaille/templates/reset-password.html:11
|
||||||
#: canaille/templates/reset-password.html:16
|
#: canaille/templates/reset-password.html:16
|
||||||
msgid "Password reset"
|
msgid "Password reset"
|
||||||
|
@ -964,10 +977,6 @@ msgstr "Prendre l'identité"
|
||||||
msgid "Invite a user"
|
msgid "Invite a user"
|
||||||
msgstr "Inviter un utilisateur"
|
msgstr "Inviter un utilisateur"
|
||||||
|
|
||||||
#: canaille/templates/userlist.html:14
|
|
||||||
msgid "Email"
|
|
||||||
msgstr "Courriel"
|
|
||||||
|
|
||||||
#: canaille/templates/users.html:18
|
#: canaille/templates/users.html:18
|
||||||
msgid "Add a user"
|
msgid "Add a user"
|
||||||
msgstr "Nouvel utilisateur"
|
msgstr "Nouvel utilisateur"
|
||||||
|
@ -1049,17 +1058,29 @@ msgstr "Ajouter un client"
|
||||||
msgid "URL"
|
msgid "URL"
|
||||||
msgstr "URL"
|
msgstr "URL"
|
||||||
|
|
||||||
#: canaille/templates/admin/mails.html:7
|
#: canaille/templates/admin/mails.html:8
|
||||||
|
msgid "Mail sending test"
|
||||||
|
msgstr "Test d'envoi d'email"
|
||||||
|
|
||||||
|
#: canaille/templates/admin/mails.html:13
|
||||||
|
msgid ""
|
||||||
|
"This form will send a fake invitation email to the address you want.\n"
|
||||||
|
" This should be used for testing mail configuration."
|
||||||
|
msgstr ""
|
||||||
|
"Ce formulaire enverra un faux mail d'invitation à l'adresse que vous "
|
||||||
|
"indiquerez. À utiliser pour tester les configurations de mail."
|
||||||
|
|
||||||
|
#: canaille/templates/admin/mails.html:32
|
||||||
msgid "Email preview"
|
msgid "Email preview"
|
||||||
msgstr "Prévisualisation des emails"
|
msgstr "Prévisualisation des emails"
|
||||||
|
|
||||||
#: canaille/templates/admin/mails.html:22
|
#: canaille/templates/admin/mails.html:44
|
||||||
#: canaille/templates/mail/firstlogin.html:19
|
#: canaille/templates/mail/firstlogin.html:19
|
||||||
#: canaille/templates/mail/reset.txt:1
|
#: canaille/templates/mail/reset.txt:1
|
||||||
msgid "Password initialization"
|
msgid "Password initialization"
|
||||||
msgstr "Initialisation du mot de passe"
|
msgstr "Initialisation du mot de passe"
|
||||||
|
|
||||||
#: canaille/templates/admin/mails.html:46
|
#: canaille/templates/admin/mails.html:68
|
||||||
msgid "Invitation"
|
msgid "Invitation"
|
||||||
msgstr "Invitation"
|
msgstr "Invitation"
|
||||||
|
|
||||||
|
@ -1189,7 +1210,11 @@ msgstr "Jetons"
|
||||||
msgid "Codes"
|
msgid "Codes"
|
||||||
msgstr "Codes"
|
msgstr "Codes"
|
||||||
|
|
||||||
#: canaille/themes/default/base.html:84
|
#: canaille/themes/default/base.html:81
|
||||||
|
msgid "Emails"
|
||||||
|
msgstr "Courriels"
|
||||||
|
|
||||||
|
#: canaille/themes/default/base.html:88
|
||||||
msgid "Log out"
|
msgid "Log out"
|
||||||
msgstr "Déconnexion"
|
msgstr "Déconnexion"
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
# Translations template for PROJECT.
|
# Translations template for PROJECT.
|
||||||
# Copyright (C) 2021 ORGANIZATION
|
# Copyright (C) 2022 ORGANIZATION
|
||||||
# This file is distributed under the same license as the PROJECT project.
|
# This file is distributed under the same license as the PROJECT project.
|
||||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2021.
|
# FIRST AUTHOR <EMAIL@ADDRESS>, 2022.
|
||||||
#
|
#
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PROJECT VERSION\n"
|
"Project-Id-Version: PROJECT VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||||
"POT-Creation-Date: 2021-12-23 18:45+0100\n"
|
"POT-Creation-Date: 2022-01-01 11:24+0100\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
@ -17,114 +17,118 @@ msgstr ""
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Generated-By: Babel 2.9.1\n"
|
"Generated-By: Babel 2.9.1\n"
|
||||||
|
|
||||||
#: canaille/__init__.py:134
|
#: canaille/__init__.py:131
|
||||||
msgid "Could not connect to the LDAP server '{uri}'"
|
msgid "Could not connect to the LDAP server '{uri}'"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/__init__.py:150
|
#: canaille/__init__.py:147
|
||||||
msgid "LDAP authentication failed with user '{user}'"
|
msgid "LDAP authentication failed with user '{user}'"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/account.py:77 canaille/account.py:102 canaille/oauth.py:77
|
#: canaille/account.py:82 canaille/account.py:107 canaille/oauth.py:77
|
||||||
msgid "Login failed, please check your information"
|
msgid "Login failed, please check your information"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/account.py:108
|
#: canaille/account.py:113
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Connection successful. Welcome %(user)s"
|
msgid "Connection successful. Welcome %(user)s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/account.py:121
|
#: canaille/account.py:126
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "You have been disconnected. See you next time %(user)s"
|
msgid "You have been disconnected. See you next time %(user)s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/account.py:138
|
#: canaille/account.py:143
|
||||||
msgid "Could not send the password initialization link."
|
msgid "Could not send the password initialization link."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/account.py:143
|
#: canaille/account.py:148
|
||||||
msgid ""
|
msgid ""
|
||||||
"A password initialization link has been sent at your email address. You "
|
"A password initialization link has been sent at your email address. You "
|
||||||
"should receive it within 10 minutes."
|
"should receive it within 10 minutes."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/account.py:149 canaille/account.py:353
|
#: canaille/account.py:154 canaille/account.py:388
|
||||||
msgid "Could not send the password initialization email"
|
msgid "Could not send the password initialization email"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/account.py:208 canaille/account.py:279
|
#: canaille/account.py:240 canaille/account.py:314
|
||||||
msgid "User account creation failed."
|
msgid "User account creation failed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/account.py:229 canaille/account.py:250
|
#: canaille/account.py:261 canaille/account.py:289
|
||||||
msgid "The invitation link that brought you here was invalid."
|
msgid "The invitation link that brought you here was invalid."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/account.py:236
|
#: canaille/account.py:268
|
||||||
|
msgid "The invitation link that brought you here has expired."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: canaille/account.py:275
|
||||||
msgid "Your account has already been created."
|
msgid "Your account has already been created."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/account.py:243
|
#: canaille/account.py:282
|
||||||
msgid "You are already logged in, you cannot create an account."
|
msgid "You are already logged in, you cannot create an account."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/account.py:284
|
#: canaille/account.py:319
|
||||||
msgid "You account has been created successfuly."
|
msgid "You account has been created successfuly."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/account.py:326
|
#: canaille/account.py:361
|
||||||
msgid "User account creation succeed."
|
msgid "User account creation succeed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/account.py:347
|
#: canaille/account.py:382
|
||||||
msgid ""
|
msgid ""
|
||||||
"A password initialization link has been sent at the user email address. "
|
"A password initialization link has been sent at the user email address. "
|
||||||
"It should be received within 10 minutes."
|
"It should be received within 10 minutes."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/account.py:361
|
#: canaille/account.py:396
|
||||||
msgid ""
|
msgid ""
|
||||||
"A password reset link has been sent at the user email address. It should "
|
"A password reset link has been sent at the user email address. It should "
|
||||||
"be received within 10 minutes."
|
"be received within 10 minutes."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/account.py:367
|
#: canaille/account.py:402
|
||||||
msgid "Could not send the password reset email"
|
msgid "Could not send the password reset email"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/account.py:398
|
#: canaille/account.py:433
|
||||||
msgid "Profile edition failed."
|
msgid "Profile edition failed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/account.py:426
|
#: canaille/account.py:461
|
||||||
msgid "Profile updated successfuly."
|
msgid "Profile updated successfuly."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/account.py:446
|
#: canaille/account.py:481
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "The user %(user)s has been sucessfuly deleted"
|
msgid "The user %(user)s has been sucessfuly deleted"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/account.py:470
|
#: canaille/account.py:505
|
||||||
msgid "Could not send the password reset link."
|
msgid "Could not send the password reset link."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/account.py:477 canaille/account.py:488
|
#: canaille/account.py:512 canaille/account.py:523
|
||||||
msgid ""
|
msgid ""
|
||||||
"A password reset link has been sent at your email address. You should "
|
"A password reset link has been sent at your email address. You should "
|
||||||
"receive it within 10 minutes."
|
"receive it within 10 minutes."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/account.py:494
|
#: canaille/account.py:529
|
||||||
msgid "Could not reset your password"
|
msgid "Could not reset your password"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/account.py:508
|
#: canaille/account.py:543
|
||||||
msgid "The password reset link that brought you here was invalid."
|
msgid "The password reset link that brought you here was invalid."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/account.py:517
|
#: canaille/account.py:552
|
||||||
msgid "Your password has been updated successfuly"
|
msgid "Your password has been updated successfuly"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -176,8 +180,8 @@ msgstr ""
|
||||||
msgid "Login"
|
msgid "Login"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/forms.py:47 canaille/forms.py:71 canaille/forms.py:122
|
#: canaille/admin/mail.py:29 canaille/forms.py:47 canaille/forms.py:71
|
||||||
#: canaille/forms.py:222
|
#: canaille/forms.py:122 canaille/forms.py:222
|
||||||
msgid "jane@doe.com"
|
msgid "jane@doe.com"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -297,11 +301,11 @@ msgstr ""
|
||||||
msgid "The group %(group)s has been sucessfully deleted"
|
msgid "The group %(group)s has been sucessfully deleted"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/admin/mail.py:79 canaille/mails.py:25
|
#: canaille/admin/mail.py:108 canaille/mails.py:25
|
||||||
msgid "Password reset on {website_name}"
|
msgid "Password reset on {website_name}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/admin/mail.py:37 canaille/mails.py:65
|
#: canaille/admin/mail.py:66 canaille/mails.py:65
|
||||||
msgid "Password initialization on {website_name}"
|
msgid "Password initialization on {website_name}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -417,11 +421,19 @@ msgstr ""
|
||||||
msgid "The client has been deleted."
|
msgid "The client has been deleted."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/admin/mail.py:121
|
#: canaille/admin/mail.py:23 canaille/templates/userlist.html:14
|
||||||
|
msgid "Email"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: canaille/admin/mail.py:42 canaille/admin/mail.py:44
|
||||||
|
msgid "The test invitation mail has been sent correctly"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: canaille/admin/mail.py:150
|
||||||
msgid "Invitation on {website_name}"
|
msgid "Invitation on {website_name}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/about.html:12 canaille/themes/default/base.html:98
|
#: canaille/templates/about.html:12 canaille/themes/default/base.html:102
|
||||||
msgid "About canaille"
|
msgid "About canaille"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -558,11 +570,11 @@ msgstr ""
|
||||||
#: canaille/templates/admin/client_edit.html:35
|
#: canaille/templates/admin/client_edit.html:35
|
||||||
#: canaille/templates/admin/client_edit.html:44
|
#: canaille/templates/admin/client_edit.html:44
|
||||||
#: canaille/templates/admin/client_edit.html:53
|
#: canaille/templates/admin/client_edit.html:53
|
||||||
#: canaille/templates/fomanticui.html:62
|
#: canaille/templates/fomanticui.html:64
|
||||||
msgid "This field is not editable"
|
msgid "This field is not editable"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/fomanticui.html:66
|
#: canaille/templates/fomanticui.html:68
|
||||||
msgid "This field is required"
|
msgid "This field is required"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -587,6 +599,7 @@ msgstr ""
|
||||||
msgid "Send again"
|
msgid "Send again"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: canaille/templates/admin/mails.html:23
|
||||||
#: canaille/templates/forgotten-password.html:40
|
#: canaille/templates/forgotten-password.html:40
|
||||||
msgid "Send"
|
msgid "Send"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -876,7 +889,7 @@ msgstr ""
|
||||||
msgid "Send mail"
|
msgid "Send mail"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/admin/mails.html:34 canaille/templates/profile.html:221
|
#: canaille/templates/admin/mails.html:56 canaille/templates/profile.html:221
|
||||||
#: canaille/templates/reset-password.html:11
|
#: canaille/templates/reset-password.html:11
|
||||||
#: canaille/templates/reset-password.html:16
|
#: canaille/templates/reset-password.html:16
|
||||||
msgid "Password reset"
|
msgid "Password reset"
|
||||||
|
@ -904,10 +917,6 @@ msgstr ""
|
||||||
msgid "Invite a user"
|
msgid "Invite a user"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/userlist.html:14
|
|
||||||
msgid "Email"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: canaille/templates/users.html:18
|
#: canaille/templates/users.html:18
|
||||||
msgid "Add a user"
|
msgid "Add a user"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -987,17 +996,27 @@ msgstr ""
|
||||||
msgid "URL"
|
msgid "URL"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/admin/mails.html:7
|
#: canaille/templates/admin/mails.html:8
|
||||||
|
msgid "Mail sending test"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: canaille/templates/admin/mails.html:13
|
||||||
|
msgid ""
|
||||||
|
"This form will send a fake invitation email to the address you want.\n"
|
||||||
|
" This should be used for testing mail configuration."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: canaille/templates/admin/mails.html:32
|
||||||
msgid "Email preview"
|
msgid "Email preview"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/admin/mails.html:22
|
#: canaille/templates/admin/mails.html:44
|
||||||
#: canaille/templates/mail/firstlogin.html:19
|
#: canaille/templates/mail/firstlogin.html:19
|
||||||
#: canaille/templates/mail/reset.txt:1
|
#: canaille/templates/mail/reset.txt:1
|
||||||
msgid "Password initialization"
|
msgid "Password initialization"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/admin/mails.html:46
|
#: canaille/templates/admin/mails.html:68
|
||||||
msgid "Invitation"
|
msgid "Invitation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -1104,6 +1123,10 @@ msgstr ""
|
||||||
msgid "Codes"
|
msgid "Codes"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/themes/default/base.html:84
|
#: canaille/themes/default/base.html:81
|
||||||
|
msgid "Emails"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: canaille/themes/default/base.html:88
|
||||||
msgid "Log out"
|
msgid "Log out"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -40,6 +40,10 @@ OIDC_METADATA_FILE = "conf/openid-configuration.json"
|
||||||
# wether the login exists or not.
|
# wether the login exists or not.
|
||||||
# HIDE_INVALID_LOGINS = false
|
# HIDE_INVALID_LOGINS = false
|
||||||
|
|
||||||
|
# The validity duration of registration invitations, in seconds.
|
||||||
|
# Defaults to 2 days
|
||||||
|
# INVITATION_EXPIRATION = 172800
|
||||||
|
|
||||||
[LOGGING]
|
[LOGGING]
|
||||||
# LEVEL can be one value among:
|
# LEVEL can be one value among:
|
||||||
# DEBUG, INFO, WARNING, ERROR, CRITICAL
|
# DEBUG, INFO, WARNING, ERROR, CRITICAL
|
||||||
|
|
|
@ -51,6 +51,10 @@ Canaille is based on Flask, so any `flask configuration <https://flask.palletspr
|
||||||
*Optional.* Wether to tell the users if a username exists during failing login attempts.
|
*Optional.* Wether to tell the users if a username exists during failing login attempts.
|
||||||
Defaults to ``True``. This may be a security issue to disable this, as this give a way to malicious people to guess who has an account on this canaille instance.
|
Defaults to ``True``. This may be a security issue to disable this, as this give a way to malicious people to guess who has an account on this canaille instance.
|
||||||
|
|
||||||
|
:INVITATION_EXPIRATION:
|
||||||
|
*Optional* The validity duration of registration invitations, in seconds.
|
||||||
|
Defaults to 2 days.
|
||||||
|
|
||||||
LOGGING
|
LOGGING
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@ install_requires =
|
||||||
sentry-sdk[flask]
|
sentry-sdk[flask]
|
||||||
toml
|
toml
|
||||||
wtforms
|
wtforms
|
||||||
|
dataclasses;python_version<'3.7'
|
||||||
|
|
||||||
[options.packages.find]
|
[options.packages.find]
|
||||||
exclude =
|
exclude =
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
|
from datetime import datetime
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
|
from canaille.account import Invitation
|
||||||
|
from canaille.apputils import b64_to_obj
|
||||||
from canaille.apputils import obj_to_b64
|
from canaille.apputils import obj_to_b64
|
||||||
from canaille.apputils import profile_hash
|
from canaille.apputils import profile_hash
|
||||||
from canaille.models import User
|
from canaille.models import User
|
||||||
|
@ -37,7 +42,10 @@ def test_invitation(testclient, slapd_connection, logged_admin, foo_group, smtpd
|
||||||
|
|
||||||
with testclient.app.app_context():
|
with testclient.app.app_context():
|
||||||
user = User.get("someone", conn=slapd_connection)
|
user = User.get("someone", conn=slapd_connection)
|
||||||
|
user.load_groups(conn=slapd_connection)
|
||||||
|
foo_group.reload(slapd_connection)
|
||||||
assert user.check_password("whatever")
|
assert user.check_password("whatever")
|
||||||
|
assert user.groups == [foo_group]
|
||||||
|
|
||||||
with testclient.session_transaction() as sess:
|
with testclient.session_transaction() as sess:
|
||||||
assert "user_dn" in sess
|
assert "user_dn" in sess
|
||||||
|
@ -80,7 +88,10 @@ def test_generate_link(testclient, slapd_connection, logged_admin, foo_group, sm
|
||||||
|
|
||||||
with testclient.app.app_context():
|
with testclient.app.app_context():
|
||||||
user = User.get("sometwo", conn=slapd_connection)
|
user = User.get("sometwo", conn=slapd_connection)
|
||||||
|
user.load_groups(conn=slapd_connection)
|
||||||
|
foo_group.reload(slapd_connection)
|
||||||
assert user.check_password("whatever")
|
assert user.check_password("whatever")
|
||||||
|
assert user.groups == [foo_group]
|
||||||
|
|
||||||
with testclient.session_transaction() as sess:
|
with testclient.session_transaction() as sess:
|
||||||
assert "user_dn" in sess
|
assert "user_dn" in sess
|
||||||
|
@ -100,37 +111,86 @@ def test_invitation_login_already_taken(testclient, slapd_connection, logged_adm
|
||||||
assert "The email 'jane@doe.com' already exists" in res.text
|
assert "The email 'jane@doe.com' already exists" in res.text
|
||||||
|
|
||||||
|
|
||||||
def test_registration_invalid_data(testclient, slapd_connection, foo_group):
|
def test_registration(testclient, slapd_connection, foo_group):
|
||||||
with testclient.app.app_context():
|
with testclient.app.app_context():
|
||||||
data = ["someoneelse", "someone@mydomain.tld", foo_group.dn]
|
invitation = Invitation(
|
||||||
b64 = obj_to_b64(data)
|
datetime.now().isoformat(),
|
||||||
|
"someoneelse",
|
||||||
|
"someone@mydomain.tld",
|
||||||
|
foo_group.dn,
|
||||||
|
)
|
||||||
|
b64 = invitation.b64()
|
||||||
|
hash = invitation.profile_hash()
|
||||||
|
|
||||||
testclient.get(f"/register/{b64}/invalid", status=302)
|
testclient.get(f"/register/{b64}/{hash}", status=200)
|
||||||
|
|
||||||
|
|
||||||
def test_registration_invalid_hash(testclient, slapd_connection, foo_group):
|
def test_registration_invalid_hash(testclient, slapd_connection, foo_group):
|
||||||
with testclient.app.app_context():
|
with testclient.app.app_context():
|
||||||
data = ["someoneelse", "someone@mydomain.tld", foo_group.dn]
|
invitation = Invitation(
|
||||||
hash = profile_hash(*data)
|
datetime.now().isoformat(),
|
||||||
data = ["anything", "someone@mydomain.tld", foo_group.dn]
|
"someoneelse",
|
||||||
b64 = obj_to_b64(data)
|
"someone@mydomain.tld",
|
||||||
|
foo_group.dn,
|
||||||
|
)
|
||||||
|
b64 = invitation.b64()
|
||||||
|
|
||||||
testclient.get(f"/register/{b64}/{hash}", status=302)
|
testclient.get(f"/register/{b64}/invalid", status=302)
|
||||||
|
|
||||||
|
|
||||||
def test_registration_bad_hash(testclient, slapd_connection, foo_group):
|
def test_registration_bad_hash(testclient, slapd_connection, foo_group):
|
||||||
with testclient.app.app_context():
|
with testclient.app.app_context():
|
||||||
data = ["someoneelse", "someone@mydomain.tld", foo_group.dn]
|
now = datetime.now().isoformat()
|
||||||
hash = profile_hash(*data)
|
invitation1 = Invitation(
|
||||||
|
now, "someoneelse", "someone@mydomain.tld", foo_group.dn
|
||||||
|
)
|
||||||
|
hash = invitation1.profile_hash()
|
||||||
|
invitation2 = Invitation(now, "anything", "someone@mydomain.tld", foo_group.dn)
|
||||||
|
b64 = invitation2.b64()
|
||||||
|
|
||||||
testclient.get(f"/register/invalid/{hash}", status=302)
|
testclient.get(f"/register/{b64}/{hash}", status=302)
|
||||||
|
|
||||||
|
|
||||||
|
def test_registration_invalid_data(testclient, slapd_connection, foo_group):
|
||||||
|
with testclient.app.app_context():
|
||||||
|
invitation = Invitation(
|
||||||
|
datetime.now().isoformat(),
|
||||||
|
"someoneelse",
|
||||||
|
"someone@mydomain.tld",
|
||||||
|
foo_group.dn,
|
||||||
|
)
|
||||||
|
hash = invitation.profile_hash()
|
||||||
|
|
||||||
|
res = testclient.get(f"/register/invalid/{hash}", status=302)
|
||||||
|
|
||||||
|
|
||||||
|
def test_registration_more_than_48_hours_after_invitation(
|
||||||
|
testclient, slapd_connection, foo_group
|
||||||
|
):
|
||||||
|
with testclient.app.app_context():
|
||||||
|
two_days_ago = datetime.now() - timedelta(hours=48)
|
||||||
|
invitation = Invitation(
|
||||||
|
two_days_ago.isoformat(),
|
||||||
|
"someoneelse",
|
||||||
|
"someone@mydomain.tld",
|
||||||
|
foo_group.dn,
|
||||||
|
)
|
||||||
|
hash = invitation.profile_hash()
|
||||||
|
b64 = invitation.b64()
|
||||||
|
|
||||||
|
testclient.get(f"/register/{b64}/{hash}", status=302)
|
||||||
|
|
||||||
|
|
||||||
def test_registration_no_password(testclient, slapd_connection, foo_group):
|
def test_registration_no_password(testclient, slapd_connection, foo_group):
|
||||||
with testclient.app.app_context():
|
with testclient.app.app_context():
|
||||||
data = ["someoneelse", "someone@mydomain.tld", foo_group.dn]
|
invitation = Invitation(
|
||||||
hash = profile_hash(*data)
|
datetime.now().isoformat(),
|
||||||
b64 = obj_to_b64(data)
|
"someoneelse",
|
||||||
|
"someone@mydomain.tld",
|
||||||
|
foo_group.dn,
|
||||||
|
)
|
||||||
|
hash = invitation.profile_hash()
|
||||||
|
b64 = invitation.b64()
|
||||||
url = f"/register/{b64}/{hash}"
|
url = f"/register/{b64}/{hash}"
|
||||||
|
|
||||||
res = testclient.get(url, status=200)
|
res = testclient.get(url, status=200)
|
||||||
|
@ -151,9 +211,14 @@ def test_no_registration_if_logged_in(
|
||||||
testclient, slapd_connection, logged_user, foo_group
|
testclient, slapd_connection, logged_user, foo_group
|
||||||
):
|
):
|
||||||
with testclient.app.app_context():
|
with testclient.app.app_context():
|
||||||
data = ["anyone", "someone@mydomain.tld", foo_group.dn]
|
invitation = Invitation(
|
||||||
hash = profile_hash(*data)
|
datetime.now().isoformat(),
|
||||||
b64 = obj_to_b64(data)
|
"someoneelse",
|
||||||
|
"someone@mydomain.tld",
|
||||||
|
foo_group.dn,
|
||||||
|
)
|
||||||
|
hash = invitation.profile_hash()
|
||||||
|
b64 = invitation.b64()
|
||||||
url = f"/register/{b64}/{hash}"
|
url = f"/register/{b64}/{hash}"
|
||||||
|
|
||||||
testclient.get(url, status=302)
|
testclient.get(url, status=302)
|
||||||
|
|
Loading…
Reference in a new issue