Skip to content

Commit

Permalink
Password forms improvements (#90)
Browse files Browse the repository at this point in the history
Well, I'm the only one using the login forms on this site but still wanted to try these.

- Raise min length to 15 chars
- Help password managers understand the form fields
- Indicate which account is the password being changed for
- Tell 1Password to generate a bit longer+stronger password by default

TIL the `passwordrules` attribute thanks to this great @ScottHelme's blog post https://scotthelme.co.uk/boosting-account-security-pwned-passwords-and-zxcvbn/

Here are some helpful links:
- [Design your website to work best with 1Password](https://developer.1password.com/docs/web/compatible-website-design/)
- [Password Rules Validation Tool](https://developer.apple.com/password-rules/) by Apple, apparently supported in Safari [since 2018 (Safari 12)](https://webkit.org/blog/8327/safari-technology-preview-58-with-safari-12-features-is-now-available/)
- whatwg/html#3518

_This is a companion to #89._
  • Loading branch information
spaze authored Mar 14, 2023
2 parents c73ccd7 + 1eac78f commit 99a7250
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 4 deletions.
12 changes: 11 additions & 1 deletion site/app/Form/ChangePasswordFormFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

namespace MichalSpacekCz\Form;

use MichalSpacekCz\User\Exceptions\IdentityNotSimpleIdentityException;
use MichalSpacekCz\User\Manager;
use Nette\Application\UI\Form;
use Nette\Security\User;
Expand All @@ -22,16 +23,25 @@ public function __construct(
/**
* @param callable(): void $onSuccess
* @return Form
* @throws IdentityNotSimpleIdentityException
*/
public function create(callable $onSuccess): Form
{
$form = $this->factory->create();
$form->addText('username')
->setDefaultValue($this->authenticator->getIdentityByUser($this->user)->username)
->setHtmlAttribute('passwordrules', 'minlength: 42; required: lower; required: upper; required: digit; required: [ !#$%&*+,./:;=?@_~];')
->setHtmlAttribute('autocomplete', 'username')
->setHtmlAttribute('class', 'hidden');
$form->addPassword('password', 'Současné heslo:')
->setHtmlAttribute('autocomplete', 'current-password')
->setRequired('Zadejte prosím současné heslo');
$newPassword = $form->addPassword('newPassword', 'Nové heslo:')
->setHtmlAttribute('autocomplete', 'new-password')
->setRequired('Zadejte prosím nové heslo')
->addRule($form::MIN_LENGTH, 'Nové heslo musí mít alespoň %d znaků', 6);
->addRule($form::MIN_LENGTH, 'Nové heslo musí mít alespoň %d znaků', 15);
$form->addPassword('newPasswordVerify', 'Nové heslo pro kontrolu:')
->setHtmlAttribute('autocomplete', 'new-password')
->setRequired('Zadejte prosím nové heslo pro kontrolu')
->addRule($form::EQUAL, 'Hesla se neshodují', $newPassword);
$form->addSubmit('save', 'Uložit');
Expand Down
2 changes: 2 additions & 0 deletions site/app/Form/Controls/FormControlsFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ class FormControlsFactory
public function addSignIn(Container $container): void
{
$container->addText('username', 'Uživatel:')
->setHtmlAttribute('autocomplete', 'username')
->setRequired('Zadejte prosím uživatele');
$container->addPassword('password', 'Heslo:')
->setHtmlAttribute('autocomplete', 'current-password')
->setRequired('Zadejte prosím heslo');
$container->addCheckbox('remember', 'Zůstat přihlášen');
$container->addSubmit('signin', 'Přihlásit');
Expand Down
22 changes: 22 additions & 0 deletions site/app/User/Exceptions/IdentityNotSimpleIdentityException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php
declare(strict_types = 1);

namespace MichalSpacekCz\User\Exceptions;

use Exception;
use Nette\Security\IIdentity;
use Nette\Security\SimpleIdentity;
use Throwable;

class IdentityNotSimpleIdentityException extends Exception
{

public function __construct(?IIdentity $identity, ?Throwable $previous = null)
{
parent::__construct(
sprintf('Identity is of class %s but should be %s', $identity === null ? '<null>' : $identity::class, SimpleIdentity::class),
previous: $previous,
);
}

}
19 changes: 16 additions & 3 deletions site/app/User/Manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

use DateTimeInterface;
use Exception;
use MichalSpacekCz\User\Exceptions\IdentityNotSimpleIdentityException;
use Nette\Application\LinkGenerator;
use Nette\Database\Explorer;
use Nette\Database\Row;
Expand Down Expand Up @@ -79,6 +80,19 @@ public function getIdentity(int $id, string $username): SimpleIdentity
}


/**
* @throws IdentityNotSimpleIdentityException
*/
public function getIdentityByUser(User $user): SimpleIdentity
{
$identity = $user->getIdentity();
if (!$identity instanceof SimpleIdentity) {
throw new IdentityNotSimpleIdentityException($identity);
}
return $identity;
}


/**
* @param string $username
* @param string $password
Expand Down Expand Up @@ -123,12 +137,11 @@ private function verifyPassword(string $username, string $password): int
* @param string $newPassword
* @throws AuthenticationException
* @throws HaliteAlert
* @throws IdentityNotSimpleIdentityException
*/
public function changePassword(User $user, string $password, string $newPassword): void
{
/** @var SimpleIdentity $identity */
$identity = $user->getIdentity();
$this->verifyPassword($identity->username, $password);
$this->verifyPassword($this->getIdentityByUser($user)->username, $password);
$this->updatePassword($user->getId(), $newPassword);
$this->clearPermanentLogin($user);
}
Expand Down

0 comments on commit 99a7250

Please sign in to comment.