Overview
SHA1:0ae042cdc2cc00f394121154ff39bd6ce382ef90
Date: 2018-11-29 17:01:13
User: bohwaz
Comment:Changement de mot de passe sans envoyer de mot de passe par email
Timelines: family | ancestors | descendants | both | trunk | stable
Downloads: Tarball | ZIP archive
Other Links: files | file ages | folders | manifest
Tags And Properties
Context
2018-11-30
13:52
[ea902d98b2] Corrige mode plein écran éditeurs code / wiki (user: bohwaz, tags: trunk, stable)
2018-11-29
17:01
[0ae042cdc2] Changement de mot de passe sans envoyer de mot de passe par email (user: bohwaz, tags: trunk, stable)
2018-11-28
21:03
[a38560eefe] Ajout désactivation de DirectoryIndex pour contourner bug avec FallbackResource (user: bohwaz, tags: trunk, stable)
Changes

Modified src/include/lib/Garradin/Membres/Session.php from [76f4ec5c54] to [6e72b311e7].

18
19
20
21
22
23
24


25
26
27
28
29
30
31
...
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
...
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
...
231
232
233
234
235
236
237










238

239
240
241
242
243

244








245
246





247
248
249
250
251
252
253
254
255
256
...
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
...
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331

class Session extends \KD2\UserSession
{
	// Personalisation de la config de UserSession
	protected $cookie_name = 'gdin';
	protected $remember_me_cookie_name = 'gdinp';
	protected $remember_me_expiry = '+3 months';



	// Extension des méthodes de UserSession
	public function __construct()
	{
		$url = parse_url(ADMIN_URL);

		parent::__construct(DB::getInstance(), [
................................................................................
			$secret = Security_OTP::getRandomSecret();
		}

		$out = [];
		$out['secret'] = $secret;
		$out['secret_display'] = implode(' ', str_split($secret, 4));
		$out['url'] = Security_OTP::getOTPAuthURL(Config::getInstance()->get('nom_asso'), $secret);
	
		$qrcode = new QRCode($out['url']);
		$out['qrcode'] = 'data:image/svg+xml;base64,' . base64_encode($qrcode->toSVG());

		return $out;
	}

	static public function recoverPasswordCheck($id)
	{
		$db = DB::getInstance();
		$config = Config::getInstance();

		$champ_id = $config->get('champ_identifiant');

		$membre = $db->first('SELECT id, email, passe, clef_pgp FROM membres WHERE '.$champ_id.' = ? LIMIT 1;', trim($id));
................................................................................
		}

		// valide pour 1 heure minimum
		$expire = ceil((time() - strtotime('2017-01-01')) / 3600) + 1;

		$hash = hash_hmac('sha256', $membre->email . $membre->id . $membre->passe . $expire, SECRET_KEY, true);
		$hash = substr(Security::base64_encode_url_safe($hash), 0, 16);
		
		$id = base_convert($membre->id, 10, 36);
		$expire = base_convert($expire, 10, 36);

		$query = sprintf('%s.%s.%s', $id, $expire, $hash);

		$message = "Bonjour,\n\nVous avez oublié votre mot de passe ? Pas de panique !\n\n";
		$message.= "Il vous suffit de cliquer sur le lien ci-dessous pour recevoir un nouveau mot de passe.\n\n";
		$message.= ADMIN_URL . 'password.php?c=' . $query;
		$message.= "\n\nSi vous n'avez pas demandé à recevoir ce message, ignorez-le, votre mot de passe restera inchangé.";

		return Utils::sendEmail(Utils::EMAIL_CONTEXT_SYSTEM, $membre->email, 'Mot de passe perdu ?', $message, $membre->id, $membre->clef_pgp);
	}

	static public function recoverPasswordConfirm($code)
	{
		if (substr_count($code, '.') !== 2)
		{
			return false;
		}

		list($id, $expire, $email_hash) = explode('.', $code);
................................................................................
		$hash = substr(Security::base64_encode_url_safe($hash), 0, 16);

		if (!hash_equals($hash, $email_hash))
		{
			return false;
		}











		$password = Utils::suggestPassword();


		$message = "Bonjour,\n\nVous avez demandé un nouveau mot de passe pour votre compte.\n\n";
		$message.= "Votre adresse email : ".$membre->email."\n";
		$message.= "Votre nouveau mot de passe : ".$password."\n\n";
		$message.= "Si vous n'avez pas demandé à recevoir ce message, merci de nous le signaler.";










		$password = Membres::hashPassword($password);






		$db->update('membres', ['passe' => $password], 'id = :id', ['id' => (int)$id]);

		return Utils::sendEmail(Utils::EMAIL_CONTEXT_SYSTEM, $membre->email, 'Nouveau mot de passe', $message, $membre->id, $membre->clef_pgp);
	}

	public function editUser($data)
	{
		(new Membres)->edit($this->user->id, $data, false);
		$this->refresh(false);

................................................................................

	public function getNewOTPSecret()
	{
		$out = [];
		$out['secret'] = Security_OTP::getRandomSecret();
		$out['secret_display'] = implode(' ', str_split($out['secret'], 4));
		$out['url'] = Security_OTP::getOTPAuthURL(Config::getInstance()->get('nom_asso'), $out['secret']);
	
		$qrcode = new QRCode($out['url']);
		$out['qrcode'] = 'data:image/svg+xml;base64,' . base64_encode($qrcode->toSVG());

		return $out;
	}

	public function sendMessage($dest, $sujet, $message, $copie = false)
................................................................................
			{
				throw new \RuntimeException(sprintf('Le champ %s n\'est pas autorisé dans cette méthode.', $key));
			}
		}

		if (isset($data['passe']) && trim($data['passe']) !== '')
		{
			if (strlen($data['passe']) < 5)
			{
				throw new UserException('Le mot de passe doit faire au moins 5 caractères.');
			}

			$data['passe'] = Membres::hashPassword(trim($data['passe']));
		}
		else
		{
			unset($data['passe']);







>
>







 







|






|







 







|













|







 







>
>
>
>
>
>
>
>
>
>
|
>

<
<
<
<
>
|
>
>
>
>
>
>
>
>


>
>
>
>
>
|

|







 







|







 







|

|







18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
...
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
...
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
...
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252




253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
...
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
...
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354

class Session extends \KD2\UserSession
{
	// Personalisation de la config de UserSession
	protected $cookie_name = 'gdin';
	protected $remember_me_cookie_name = 'gdinp';
	protected $remember_me_expiry = '+3 months';

	const MINIMUM_PASSWORD_LENGTH = 8;

	// Extension des méthodes de UserSession
	public function __construct()
	{
		$url = parse_url(ADMIN_URL);

		parent::__construct(DB::getInstance(), [
................................................................................
			$secret = Security_OTP::getRandomSecret();
		}

		$out = [];
		$out['secret'] = $secret;
		$out['secret_display'] = implode(' ', str_split($secret, 4));
		$out['url'] = Security_OTP::getOTPAuthURL(Config::getInstance()->get('nom_asso'), $secret);

		$qrcode = new QRCode($out['url']);
		$out['qrcode'] = 'data:image/svg+xml;base64,' . base64_encode($qrcode->toSVG());

		return $out;
	}

	public function recoverPasswordSend($id)
	{
		$db = DB::getInstance();
		$config = Config::getInstance();

		$champ_id = $config->get('champ_identifiant');

		$membre = $db->first('SELECT id, email, passe, clef_pgp FROM membres WHERE '.$champ_id.' = ? LIMIT 1;', trim($id));
................................................................................
		}

		// valide pour 1 heure minimum
		$expire = ceil((time() - strtotime('2017-01-01')) / 3600) + 1;

		$hash = hash_hmac('sha256', $membre->email . $membre->id . $membre->passe . $expire, SECRET_KEY, true);
		$hash = substr(Security::base64_encode_url_safe($hash), 0, 16);

		$id = base_convert($membre->id, 10, 36);
		$expire = base_convert($expire, 10, 36);

		$query = sprintf('%s.%s.%s', $id, $expire, $hash);

		$message = "Bonjour,\n\nVous avez oublié votre mot de passe ? Pas de panique !\n\n";
		$message.= "Il vous suffit de cliquer sur le lien ci-dessous pour recevoir un nouveau mot de passe.\n\n";
		$message.= ADMIN_URL . 'password.php?c=' . $query;
		$message.= "\n\nSi vous n'avez pas demandé à recevoir ce message, ignorez-le, votre mot de passe restera inchangé.";

		return Utils::sendEmail(Utils::EMAIL_CONTEXT_SYSTEM, $membre->email, 'Mot de passe perdu ?', $message, $membre->id, $membre->clef_pgp);
	}

	public function recoverPasswordCheck($code, &$membre = null)
	{
		if (substr_count($code, '.') !== 2)
		{
			return false;
		}

		list($id, $expire, $email_hash) = explode('.', $code);
................................................................................
		$hash = substr(Security::base64_encode_url_safe($hash), 0, 16);

		if (!hash_equals($hash, $email_hash))
		{
			return false;
		}

		return true;
	}

	public function recoverPasswordChange($code, $password, $password_confirm)
	{
		if (!$this->recoverPasswordCheck($code, $membre))
		{
			throw new UserException('Le code permettant de changer le mot de passe a expiré. Merci de bien vouloir recommencer la procédure.');
		}

		$password = trim($password);
		$password_confirm = trim($password_confirm);





		if (!hash_equals($password, $password_confirm))
		{
			throw new UserException('Le mot de passe et sa vérification ne sont pas identiques.');
		}

		if (strlen($password) < self::MINIMUM_PASSWORD_LENGTH)
		{
			throw new UserException(sprintf('Le mot de passe doit faire au moins %d caractères.', self::MINIMUM_PASSWORD_LENGTH));
		}

		$password = Membres::hashPassword($password);

		$message = "Bonjour,\n\nLe mot de passe de votre compte a bien été modifié.\n\n";
		$message.= "Votre adresse email : ".$membre->email."\n";
		$message.= "La demande émanait de l'adresse IP : ".Utils::getIP()."\n\n";
		$message.= "Si vous n'avez pas demandé à changer votre mot de passe, merci de nous le signaler.";

		DB::getInstance()->update('membres', ['passe' => $password], 'id = :id', ['id' => (int)$membre->id]);

		return Utils::sendEmail(Utils::EMAIL_CONTEXT_SYSTEM, $membre->email, 'Mot de passe changé', $message, $membre->id, $membre->clef_pgp);
	}

	public function editUser($data)
	{
		(new Membres)->edit($this->user->id, $data, false);
		$this->refresh(false);

................................................................................

	public function getNewOTPSecret()
	{
		$out = [];
		$out['secret'] = Security_OTP::getRandomSecret();
		$out['secret_display'] = implode(' ', str_split($out['secret'], 4));
		$out['url'] = Security_OTP::getOTPAuthURL(Config::getInstance()->get('nom_asso'), $out['secret']);

		$qrcode = new QRCode($out['url']);
		$out['qrcode'] = 'data:image/svg+xml;base64,' . base64_encode($qrcode->toSVG());

		return $out;
	}

	public function sendMessage($dest, $sujet, $message, $copie = false)
................................................................................
			{
				throw new \RuntimeException(sprintf('Le champ %s n\'est pas autorisé dans cette méthode.', $key));
			}
		}

		if (isset($data['passe']) && trim($data['passe']) !== '')
		{
			if (strlen($data['passe']) < self::MINIMUM_PASSWORD_LENGTH)
			{
				throw new UserException(sprintf('Le mot de passe doit faire au moins %d caractères.', self::MINIMUM_PASSWORD_LENGTH));
			}

			$data['passe'] = Membres::hashPassword(trim($data['passe']));
		}
		else
		{
			unset($data['passe']);

Modified src/include/lib/Garradin/Template.php from [86d1b59d2c] to [682f3b4c7a].

1
2
3
4
5

6
7
8
9
10
11
12
..
39
40
41
42
43
44
45



46
47
48
49
50
51
52
<?php

namespace Garradin;

use KD2\Form;


class Template extends \KD2\Smartyer
{
	static protected $_instance = null;

	static public function getInstance()
	{
................................................................................
		$this->assign('version_hash', substr(sha1(VERSION . ROOT . SECRET_KEY), 0, 10));

		$this->assign('www_url', WWW_URL);
		$this->assign('self_url', Utils::getSelfUrl());
		$this->assign('self_url_no_qs', Utils::getSelfUrl(false));

		$this->assign('is_logged', false);




		$this->register_compile_function('continue', function ($pos, $block, $name, $raw_args) {
			if ($block == 'continue')
			{
				return 'continue;';
			}
		});





>







 







>
>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
..
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<?php

namespace Garradin;

use KD2\Form;
use Garradin\Membres\Session;

class Template extends \KD2\Smartyer
{
	static protected $_instance = null;

	static public function getInstance()
	{
................................................................................
		$this->assign('version_hash', substr(sha1(VERSION . ROOT . SECRET_KEY), 0, 10));

		$this->assign('www_url', WWW_URL);
		$this->assign('self_url', Utils::getSelfUrl());
		$this->assign('self_url_no_qs', Utils::getSelfUrl(false));

		$this->assign('is_logged', false);

		$this->assign('password_pattern', sprintf('.{%d,}', Session::MINIMUM_PASSWORD_LENGTH));
		$this->assign('password_length', Session::MINIMUM_PASSWORD_LENGTH);

		$this->register_compile_function('continue', function ($pos, $block, $name, $raw_args) {
			if ($block == 'continue')
			{
				return 'continue;';
			}
		});

Modified src/templates/admin/install.tpl from [164de6ecf1] to [2088579102].

31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
            <dt><label for="f_nom_membre">Nom et prénom</label> <b title="(Champ obligatoire)">obligatoire</b></dt>
            <dd><input type="text" name="nom_membre" id="f_nom_membre" required="required" value="{form_field name=nom_membre}" /></dd>
            <dt><label for="f_cat_membre">Catégorie du membre</label> <b title="(Champ obligatoire)">obligatoire</b></dt>
            <dd class="tip">Par exemple : bureau, conseil d'administration, présidente, trésorier, etc.</dd>
            <dd><input type="text" name="cat_membre" id="f_cat_membre" required="required" value="{form_field name=cat_membre}" /></dd>
            <dt><label for="f_email_membre">Adresse E-Mail</label> <b title="(Champ obligatoire)">obligatoire</b></dt>
            <dd><input type="email" name="email_membre" id="f_email_membre" required="required" value="{form_field name=email_membre}" /></dd>
            <dt><label for="f_passe_membre">Mot de passe</label> <b title="(Champ obligatoire)">obligatoire</b></dt>
            <dd class="help">
                Astuce : un mot de passe de quatre mots choisis au hasard dans le dictionnaire est plus sûr 
                et plus simple à retenir qu'un mot de passe composé de 10 lettres et chiffres.
            </dd>
            <dd class="help">
                Pas d'idée&nbsp;? Voici une suggestion choisie au hasard :
                <input type="text" readonly="readonly" title="Cliquer pour utiliser cette suggestion comme mot de passe" id="pw_suggest" value="{$passphrase}" autocomplete="off" />
            </dd>
            <dd><input type="password" name="passe" id="f_passe_membre" value="{form_field name=passe}" pattern=".{ldelim}6,{rdelim}" required="required" /></dd>
            <dt><label for="f_repasse_membre">Encore le mot de passe</label> (vérification) <b title="(Champ obligatoire)">obligatoire</b></dt>
            <dd><input type="password" name="passe_confirmed" id="f_repasse_membre" value="{form_field name=passe_confirmed}" pattern=".{ldelim}6,{rdelim}" required="required" /></dd>
        </dl>
    </fieldset>

    <p class="submit">
        {csrf_field key="install"}
        <input type="submit" id="f_submit" name="save" value="Terminer l'installation &rarr;" />
    </p>







|








|

|







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
            <dt><label for="f_nom_membre">Nom et prénom</label> <b title="(Champ obligatoire)">obligatoire</b></dt>
            <dd><input type="text" name="nom_membre" id="f_nom_membre" required="required" value="{form_field name=nom_membre}" /></dd>
            <dt><label for="f_cat_membre">Catégorie du membre</label> <b title="(Champ obligatoire)">obligatoire</b></dt>
            <dd class="tip">Par exemple : bureau, conseil d'administration, présidente, trésorier, etc.</dd>
            <dd><input type="text" name="cat_membre" id="f_cat_membre" required="required" value="{form_field name=cat_membre}" /></dd>
            <dt><label for="f_email_membre">Adresse E-Mail</label> <b title="(Champ obligatoire)">obligatoire</b></dt>
            <dd><input type="email" name="email_membre" id="f_email_membre" required="required" value="{form_field name=email_membre}" /></dd>
            <dt><label for="f_passe_membre">Mot de passe</label> (minimum {$password_length} caractères) <b title="(Champ obligatoire)">obligatoire</b></dt>
            <dd class="help">
                Astuce : un mot de passe de quatre mots choisis au hasard dans le dictionnaire est plus sûr 
                et plus simple à retenir qu'un mot de passe composé de 10 lettres et chiffres.
            </dd>
            <dd class="help">
                Pas d'idée&nbsp;? Voici une suggestion choisie au hasard :
                <input type="text" readonly="readonly" title="Cliquer pour utiliser cette suggestion comme mot de passe" id="pw_suggest" value="{$passphrase}" autocomplete="off" />
            </dd>
            <dd><input type="password" name="passe" id="f_passe_membre" value="{form_field name=passe}" pattern="{$password_pattern}" required="required" /></dd>
            <dt><label for="f_repasse_membre">Encore le mot de passe</label> (vérification) <b title="(Champ obligatoire)">obligatoire</b></dt>
            <dd><input type="password" name="passe_confirmed" id="f_repasse_membre" value="{form_field name=passe_confirmed}" pattern="{$password_pattern}" required="required" /></dd>
        </dl>
    </fieldset>

    <p class="submit">
        {csrf_field key="install"}
        <input type="submit" id="f_submit" name="save" value="Terminer l'installation &rarr;" />
    </p>

Modified src/templates/admin/login.tpl from [ae198371c7] to [51528da26b].

1
2
3
4







5
6
7
8
9
10
11
{include file="admin/_head.tpl" title="Connexion" js=1}

{form_errors}
{show_error if=$fail message="Connexion impossible. Vérifiez l'adresse e-mail et le mot de passe."}








{if !$ssl_enabled && $prefer_ssl}
    <p class="alert">
        <strong>Message de sécurité</strong><br />
        Nous vous conseillons de vous connecter sur la version <a href="{$own_https_url}">chiffrée (HTTPS) de cette page</a>
        pour vous connecter.
    </p>




>
>
>
>
>
>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{include file="admin/_head.tpl" title="Connexion" js=1}

{form_errors}
{show_error if=$fail message="Connexion impossible. Vérifiez l'adresse e-mail et le mot de passe."}

{if $changed}
    <p class="confirm">
        Votre mot de passe a bien été modifié.<br />
        Vous pouvez maintenant l'utiliser pour vous reconnecter.
    </p>
{/if}

{if !$ssl_enabled && $prefer_ssl}
    <p class="alert">
        <strong>Message de sécurité</strong><br />
        Nous vous conseillons de vous connecter sur la version <a href="{$own_https_url}">chiffrée (HTTPS) de cette page</a>
        pour vous connecter.
    </p>

Modified src/templates/admin/membres/ajouter.tpl from [a19929b9a3] to [e23f736695].

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
            {/foreach}
        </dl>
    </fieldset>

    <fieldset>
        <legend>Connexion</legend>
        <dl>
            <dt><label for="f_passe">Mot de passe</label>{if $champs.passe.mandatory} <b title="(Champ obligatoire)">obligatoire</b>{/if}</dt>
            <dd class="help">
                Astuce : un mot de passe de quatre mots choisis au hasard dans le dictionnaire est plus sûr 
                et plus simple à retenir qu'un mot de passe composé de 10 lettres et chiffres.
            </dd>
            <dd class="help">
                Pas d'idée&nbsp;? Voici une suggestion choisie au hasard :
                <input type="text" readonly="readonly" title="Cliquer pour utiliser cette suggestion comme mot de passe" id="pw_suggest" value="{$passphrase}" autocomplete="off" />
            </dd>
            <dd><input type="password" name="passe" id="f_passe" value="{form_field name=passe}" pattern=".{ldelim}6,{rdelim}" /></dd>
            <dt><label for="f_repasse">Encore le mot de passe</label> (vérification)</dt>
            <dd><input type="password" name="passe_confirmed" id="f_repasse" value="{form_field name=passe_confirmed}" pattern=".{ldelim}6,{rdelim}" /></dd>
        </dl>
    </fieldset>

    {if $session->canAccess('membres', Membres::DROIT_ADMIN)}
    <fieldset>
        <legend>Général</legend>
        <dl>







|








|

|







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
            {/foreach}
        </dl>
    </fieldset>

    <fieldset>
        <legend>Connexion</legend>
        <dl>
            <dt><label for="f_passe">Mot de passe</label> (minimum {$password_length} caractères) {if $champs.passe.mandatory} <b title="(Champ obligatoire)">obligatoire</b>{/if}</dt>
            <dd class="help">
                Astuce : un mot de passe de quatre mots choisis au hasard dans le dictionnaire est plus sûr 
                et plus simple à retenir qu'un mot de passe composé de 10 lettres et chiffres.
            </dd>
            <dd class="help">
                Pas d'idée&nbsp;? Voici une suggestion choisie au hasard :
                <input type="text" readonly="readonly" title="Cliquer pour utiliser cette suggestion comme mot de passe" id="pw_suggest" value="{$passphrase}" autocomplete="off" />
            </dd>
            <dd><input type="password" name="passe" id="f_passe" value="{form_field name=passe}" pattern="{$password_pattern}" /></dd>
            <dt><label for="f_repasse">Encore le mot de passe</label> (vérification)</dt>
            <dd><input type="password" name="passe_confirmed" id="f_repasse" value="{form_field name=passe_confirmed}" pattern="{$password_pattern}" /></dd>
        </dl>
    </fieldset>

    {if $session->canAccess('membres', Membres::DROIT_ADMIN)}
    <fieldset>
        <legend>Général</legend>
        <dl>

Modified src/templates/admin/membres/modifier.tpl from [fad59c5b3b] to [02f4db1009].

26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
        <legend>{if $membre.passe}Changer le mot de passe{else}Choisir un mot de passe{/if}</legend>
        <dl>
        {if $membre.passe}
            <dd>Ce membre a déjà un mot de passe, mais vous pouvez le changer si besoin.</dd>
        {else}
            <dd>Ce membre n'a pas encore de mot de passe et ne peut donc se connecter.</dd>
        {/if}
            <dt><label for="f_passe">Nouveau mot de passe</label>{if $champs.passe.mandatory} <b title="(Champ obligatoire)">obligatoire</b>{/if}</dt>
            <dd class="help">
                Astuce : un mot de passe de quatre mots choisis au hasard dans le dictionnaire est plus sûr 
                et plus simple à retenir qu'un mot de passe composé de 10 lettres et chiffres.
            </dd>
            <dd class="help">
                Pas d'idée&nbsp;? Voici une suggestion choisie au hasard :
                <input type="text" readonly="readonly" title="Cliquer pour utiliser cette suggestion comme mot de passe" id="pw_suggest" value="{$passphrase}" autocomplete="off" />
            </dd>
            <dd><input type="password" name="passe" id="f_passe" value="{form_field name=passe}" pattern=".{ldelim}6,{rdelim}" /></dd>
            <dt><label for="f_repasse">Encore le mot de passe</label> (vérification){if $champs.passe.mandatory} <b title="(Champ obligatoire)">obligatoire</b>{/if}</dt>
            <dd><input type="password" name="passe_confirmed" id="f_repasse" value="{form_field name=passe_confirmed}" pattern=".{ldelim}6,{rdelim}" /></dd>
        </dl>
    </fieldset>

    {if $session->canAccess('membres', Membres::DROIT_ADMIN) && $user.id != $membre.id}
    <fieldset>
        <legend>Général</legend>
        <dl>







|








|

|







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
        <legend>{if $membre.passe}Changer le mot de passe{else}Choisir un mot de passe{/if}</legend>
        <dl>
        {if $membre.passe}
            <dd>Ce membre a déjà un mot de passe, mais vous pouvez le changer si besoin.</dd>
        {else}
            <dd>Ce membre n'a pas encore de mot de passe et ne peut donc se connecter.</dd>
        {/if}
            <dt><label for="f_passe">Nouveau mot de passe</label> (minimum {$password_length} caractères) {if $champs.passe.mandatory} <b title="(Champ obligatoire)">obligatoire</b>{/if}</dt>
            <dd class="help">
                Astuce : un mot de passe de quatre mots choisis au hasard dans le dictionnaire est plus sûr 
                et plus simple à retenir qu'un mot de passe composé de 10 lettres et chiffres.
            </dd>
            <dd class="help">
                Pas d'idée&nbsp;? Voici une suggestion choisie au hasard :
                <input type="text" readonly="readonly" title="Cliquer pour utiliser cette suggestion comme mot de passe" id="pw_suggest" value="{$passphrase}" autocomplete="off" />
            </dd>
            <dd><input type="password" name="passe" id="f_passe" value="{form_field name=passe}" pattern="{$password_pattern}" /></dd>
            <dt><label for="f_repasse">Encore le mot de passe</label> (vérification){if $champs.passe.mandatory} <b title="(Champ obligatoire)">obligatoire</b>{/if}</dt>
            <dd><input type="password" name="passe_confirmed" id="f_repasse" value="{form_field name=passe_confirmed}" pattern="{$password_pattern}" /></dd>
        </dl>
    </fieldset>

    {if $session->canAccess('membres', Membres::DROIT_ADMIN) && $user.id != $membre.id}
    <fieldset>
        <legend>Général</legend>
        <dl>

Modified src/templates/admin/mes_infos_securite.tpl from [811d2ba17a] to [ce884953c2].

68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
        <fieldset>
            <legend>Changer mon mot de passe</legend>
            {if $user.droit_membres < Membres::DROIT_ADMIN && (!empty($champs.passe.private) || empty($champs.passe.editable))}
                <p class="help">Vous devez contacter un administrateur pour changer votre mot de passe.</p>
            {else}
                <dl>
                    <dd>Vous avez déjà un mot de passe, ne remplissez les champs suivants que si vous souhaitez en changer.</dd>
                    <dt><label for="f_passe">Nouveau mot de passe</label></dt>
                    <dd class="help">
                        Astuce : un mot de passe de quatre mots choisis au hasard dans le dictionnaire est plus sûr 
                        et plus simple à retenir qu'un mot de passe composé de 10 lettres et chiffres.
                    </dd>
                    <dd class="help">
                        Pas d'idée&nbsp;? Voici une suggestion choisie au hasard :
                        <input type="text" readonly="readonly" title="Cliquer pour utiliser cette suggestion comme mot de passe" id="pw_suggest" value="{$passphrase}" autocomplete="off" />
                    </dd>
                    <dd><input type="password" name="passe" id="f_passe" value="{form_field name=passe}" pattern=".{ldelim}6,{rdelim}" /></dd>
                    <dt><label for="f_repasse">Encore le mot de passe</label> (vérification)</dt>
                    <dd><input type="password" name="passe_confirmed" id="f_passe_confirmed" value="{form_field name=passe_confirmed}" pattern=".{ldelim}6,{rdelim}" /></dd>
                </dl>
            {/if}
        </fieldset>

        <fieldset>
            <legend>Authentification à double facteur (2FA)</legend>
            <p class="help">Pour renforcer la sécurité de votre connexion en cas de vol de votre mot de passe, vous pouvez activer







|








|

|







68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
        <fieldset>
            <legend>Changer mon mot de passe</legend>
            {if $user.droit_membres < Membres::DROIT_ADMIN && (!empty($champs.passe.private) || empty($champs.passe.editable))}
                <p class="help">Vous devez contacter un administrateur pour changer votre mot de passe.</p>
            {else}
                <dl>
                    <dd>Vous avez déjà un mot de passe, ne remplissez les champs suivants que si vous souhaitez en changer.</dd>
                    <dt><label for="f_passe">Nouveau mot de passe</label> (minimum {$password_length} caractères)</dt>
                    <dd class="help">
                        Astuce : un mot de passe de quatre mots choisis au hasard dans le dictionnaire est plus sûr 
                        et plus simple à retenir qu'un mot de passe composé de 10 lettres et chiffres.
                    </dd>
                    <dd class="help">
                        Pas d'idée&nbsp;? Voici une suggestion choisie au hasard :
                        <input type="text" readonly="readonly" title="Cliquer pour utiliser cette suggestion comme mot de passe" id="pw_suggest" value="{$passphrase}" autocomplete="off" />
                    </dd>
                    <dd><input type="password" name="passe" id="f_passe" value="{form_field name=passe}" pattern="{$password_pattern}" /></dd>
                    <dt><label for="f_repasse">Encore le mot de passe</label> (vérification)</dt>
                    <dd><input type="password" name="passe_confirmed" id="f_passe_confirmed" value="{form_field name=passe_confirmed}" pattern="{$password_pattern}" /></dd>
                </dl>
            {/if}
        </fieldset>

        <fieldset>
            <legend>Authentification à double facteur (2FA)</legend>
            <p class="help">Pour renforcer la sécurité de votre connexion en cas de vol de votre mot de passe, vous pouvez activer

Modified src/templates/admin/password.tpl from [e4ce7c137d] to [d9cc01423e].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

18
19
20
21
22
23
24
{include file="admin/_head.tpl" title="Mot de passe oublié ou pas de mot de passe ?"}


{if !empty($sent)}
    <p class="confirm">
        Un e-mail vous a été envoyé, cliquez sur le lien dans cet e-mail
        pour recevoir un nouveau mot de passe.
    </p>
    <p class="alert">
        Si le message n'apparaît pas dans les prochaines minutes, vérifiez le dossier Spam ou Indésirables.
    </p>
{elseif !empty($new_sent)}
    <p class="confirm">
        <strong>Un e-mail contenant votre nouveau mot de passe vous a été envoyé.</strong>
        Si le message n'apparaît pas dans les prochaines minutes, vérifiez le dossier Spam ou Indésirables.
    </p>
    <p><a href="{$admin_url}login.php">Connexion &rarr;</a></p>

{else}

    {form_errors}

    <form method="post" action="{$self_url_no_qs}">

        <fieldset>






|




<
<
<
<
<
<
>







1
2
3
4
5
6
7
8
9
10
11






12
13
14
15
16
17
18
19
{include file="admin/_head.tpl" title="Mot de passe oublié ou pas de mot de passe ?"}


{if !empty($sent)}
    <p class="confirm">
        Un e-mail vous a été envoyé, cliquez sur le lien dans cet e-mail
        pour modifier votre mot de passe.
    </p>
    <p class="alert">
        Si le message n'apparaît pas dans les prochaines minutes, vérifiez le dossier Spam ou Indésirables.
    </p>







{else}

    {form_errors}

    <form method="post" action="{$self_url_no_qs}">

        <fieldset>

Added src/templates/admin/password_change.tpl version [bfd4bc96b0].





















































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
{include file="admin/_head.tpl" title="Changement de mot de passe" js=1}


{form_errors}

<form method="post" action="{$self_url}">

	<fieldset>
		<legend>Modifier mon mot de passe</legend>
		<dl>
			<dt><label for="f_passe_membre">Mot de passe</label> (minimum {$password_length} caractères) <b title="(Champ obligatoire)">obligatoire</b></dt>
			<dd class="help">
				Astuce : un mot de passe de quatre mots choisis au hasard dans le dictionnaire est plus sûr 
				et plus simple à retenir qu'un mot de passe composé de 10 lettres et chiffres.
			</dd>
			<dd class="help">
				Pas d'idée&nbsp;? Voici une suggestion choisie au hasard :
				<input type="text" readonly="readonly" title="Cliquer pour utiliser cette suggestion comme mot de passe" id="pw_suggest" value="{$passphrase}" autocomplete="off" />
			</dd>
			<dd><input type="password" name="passe" id="f_passe_membre" value="{form_field name=passe}" pattern="{$password_pattern}" required="required" /></dd>
			<dt><label for="f_repasse_membre">Encore le mot de passe</label> (vérification) <b title="(Champ obligatoire)">obligatoire</b></dt>
			<dd><input type="password" name="passe_confirmed" id="f_repasse_membre" value="{form_field name=passe_confirmed}" pattern="{$password_pattern}" required="required" /></dd>
		</dl>
	</fieldset>

	<p class="submit">
		{csrf_field key="changePassword"}
		<input type="submit" name="change" value="Modifier le mot de passe &rarr;" />
	</p>


	<script type="text/javascript">
	{literal}
	g.script('scripts/password.js').onload = function () {
		initPasswordField('pw_suggest', 'f_passe_membre', 'f_repasse_membre');
	};
	{/literal}
	</script>
</form>


{include file="admin/_foot.tpl"}

Modified src/www/admin/login.php from [5bb3d0cb12] to [3ef470efd1].

50
51
52
53
54
55
56

57
58

$tpl->assign('ssl_enabled', empty($_SERVER['HTTPS']) ? false : true);
$tpl->assign('prefer_ssl', (bool)PREFER_HTTPS);
$tpl->assign('own_https_url', str_replace('http://', 'https://', utils::getSelfURL()));

$tpl->assign('champ', $champ);
$tpl->assign('fail', $login === false);


$tpl->display('admin/login.tpl');







>


50
51
52
53
54
55
56
57
58
59

$tpl->assign('ssl_enabled', empty($_SERVER['HTTPS']) ? false : true);
$tpl->assign('prefer_ssl', (bool)PREFER_HTTPS);
$tpl->assign('own_https_url', str_replace('http://', 'https://', utils::getSelfURL()));

$tpl->assign('champ', $champ);
$tpl->assign('fail', $login === false);
$tpl->assign('changed', qg('changed') !== null);

$tpl->display('admin/login.tpl');

Modified src/www/admin/password.php from [3ac4dae618] to [51fae7e937].

4
5
6
7
8
9
10
11
12
13
14

15
16















17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

const LOGIN_PROCESS = true;

require_once __DIR__ . '/_inc.php';

if (trim(qg('c')))
{
    if ($session->recoverPasswordConfirm(qg('c')))
    {
        Utils::redirect(ADMIN_URL . 'password.php?new_sent');
    }


    $form->addError('Le lien que vous avez suivi est invalide ou a expiré.');















}
elseif (f('recover'))
{
    $form->check('recoverPassword', [
        'id' => 'required'
    ]);

    if (!$form->hasErrors())
    {
        if (trim(f('id')) && $session->recoverPasswordCheck(f('id')))
        {
            Utils::redirect(ADMIN_URL . 'password.php?sent');
        }

        $form->addError('Ce membre n\'a pas d\'adresse email enregistrée ou n\'a pas le droit de se connecter.');
    }
}

if (!$form->hasErrors() && null !== qg('sent'))
{
    $tpl->assign('sent', true);
}
elseif (!$form->hasErrors() && null !== qg('new_sent'))
{
    $tpl->assign('new_sent', true);
}


$champs = $config->get('champs_membres');

$champ = $champs->get($config->get('champ_identifiant'));

$tpl->assign('champ', $champ);

$tpl->display('admin/password.tpl');







|

|

>
|
<
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>









|












<
<
<
<
<








4
5
6
7
8
9
10
11
12
13
14
15
16

17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53





54
55
56
57
58
59
60
61

const LOGIN_PROCESS = true;

require_once __DIR__ . '/_inc.php';

if (trim(qg('c')))
{
    if (!$session->recoverPasswordCheck(qg('c')))
    {
        $form->addError('Le lien que vous avez suivi est invalide ou a expiré.');
    }
    else
    {

        if (f('change') && $form->check('changePassword'))
        {
            try {
                $session->recoverPasswordChange(qg('c'), f('passe'), f('passe_confirmed'));
                Utils::redirect('/admin/login.php?changed');
            }
            catch (UserException $e) {
                $form->addError($e->getMessage());
            }
        }

        $tpl->assign('passphrase', Utils::suggestPassword());
        $tpl->display('admin/password_change.tpl');
        exit;
    }
}
elseif (f('recover'))
{
    $form->check('recoverPassword', [
        'id' => 'required'
    ]);

    if (!$form->hasErrors())
    {
        if (trim(f('id')) && $session->recoverPasswordSend(f('id')))
        {
            Utils::redirect(ADMIN_URL . 'password.php?sent');
        }

        $form->addError('Ce membre n\'a pas d\'adresse email enregistrée ou n\'a pas le droit de se connecter.');
    }
}

if (!$form->hasErrors() && null !== qg('sent'))
{
    $tpl->assign('sent', true);
}






$champs = $config->get('champs_membres');

$champ = $champs->get($config->get('champ_identifiant'));

$tpl->assign('champ', $champ);

$tpl->display('admin/password.tpl');