164 lines
5.0 KiB
PHP
164 lines
5.0 KiB
PHP
<?php
|
|
namespace App\Presentation\Sign;
|
|
|
|
use App\Model\FormData\LoginFormData;
|
|
use App\Core\MujAutentifikator;
|
|
use App\Core\TwoFactorService;
|
|
use Nette;
|
|
use Nette\Application\UI\Form;
|
|
use Nette\Application\Attributes\Persistent;
|
|
use Nette\Http\Session;
|
|
use Nette\Http\SessionSection;
|
|
use App\Model\Login\UserIdentity;
|
|
use App\Core\Funkce;
|
|
|
|
final class SignPresenter extends Nette\Application\UI\Presenter
|
|
{
|
|
/**
|
|
* Stores the previous page hash to redirect back after successful login.
|
|
*/
|
|
#[Persistent]
|
|
public string $backlink = '';
|
|
|
|
// Dočasné úložiště pro identitu před ověřením 2FA
|
|
private SessionSection $twoFactorSession;
|
|
|
|
public function __construct(
|
|
private MujAutentifikator $autentifikator,
|
|
private TwoFactorService $twoFactorService,
|
|
private Session $session
|
|
) {
|
|
$this->twoFactorSession = $session->getSection('2fa_auth');
|
|
// $secret = $this->twoFactorService->generateSecret();
|
|
// bdump($secret);
|
|
}
|
|
|
|
protected function createComponentSignInForm(): Form
|
|
{
|
|
$sifra = Funkce::encrypt("KFMUYZL5VHCV3P5ZVFIMMPQAAN2D6ZRPBRAVATSQITDRGRKIO7P4IA3DCHLETVCMT3Y7RTXVIULC4JJSKX2JBC33XT52TLKFFPQAVAI");
|
|
bdump($sifra);
|
|
|
|
$form = new Form();
|
|
$form->addText('username', 'Uživatelské jméno:')
|
|
->setRequired('Prosím vyplňte své uživatelské jméno.')
|
|
->setValue(@$_COOKIE['user']);
|
|
|
|
$form->addPassword('password', 'Heslo:');
|
|
// setRequired nepoužívat!! kvůli soft logoutu!!!
|
|
//->setRequired('Prosím vyplňte své heslo.');
|
|
|
|
$form->addSubmit('send', 'Přihlásit');
|
|
//$form->addProtection(); //ochrana pomocí TOKENu
|
|
|
|
$form->onSuccess[] = $this->signInFormSucceeded(...);
|
|
return $form;
|
|
}
|
|
|
|
private function signInFormSucceeded(Form $form, LoginFormData $data): void //moje vlastní třída LoginFormData
|
|
{
|
|
try {
|
|
// 1. Ověříme heslo přes autentifikátor (manuálně bez volání $this->getUser()->login())
|
|
$identity = $this->autentifikator->authenticate($data->username, $data->password);
|
|
|
|
// 2. Zjistíme, zda má uživatel aktivní 2FA (např. má v DB uložený secret)
|
|
$twoFactor = $identity->twoFactor ?? false;
|
|
|
|
if ($twoFactor) {
|
|
// Uživatel MÁ 2FA -> uložíme do session a jdeme na druhý krok
|
|
$this->twoFactorSession->identity = $identity;
|
|
$this->twoFactorSession->setExpiration('5 minutes');
|
|
$this->redirect('twoFactor');
|
|
} else {
|
|
// Uživatel NEMÁ 2FA -> přihlásíme ho hned
|
|
$this->getUser()->login($identity);
|
|
$this->restoreRequest($this->backlink);
|
|
$this->redirect(':Home:');
|
|
}
|
|
|
|
} catch (Nette\Security\AuthenticationException $e) {
|
|
$form->addError('Neplatné jméno nebo heslo.');
|
|
}
|
|
// try {
|
|
// $this->getUser()->setAuthenticator($this->autentifikator); // musíme ji registrovat!
|
|
|
|
// // validace přihlášení je v třídě MujAutentifikator->authenticate(...)
|
|
// $this->getUser()->login($data->username, $data->password);
|
|
|
|
// // kam potom?
|
|
// $this->restoreRequest($this->backlink); // vrátit se na požadovanou stránku
|
|
// $this->redirect(':Home:'); // jinak přejdi sem
|
|
// } catch (Nette\Database\ConnectionException) {
|
|
// error_log("Obvody - neplatne prihlaseni.", 0); //log je ve var/log/apache2/error.log (fail2ban)
|
|
// $form->addError('Neplatné přihlášení.');
|
|
// } catch (Nette\Security\AuthenticationException $e) {
|
|
// error_log("Obvody - neplatne prihlaseni.", 0); //log je ve var/log/apache2/error.log (fail2ban)
|
|
// $form->addError($e->getMessage());
|
|
// }
|
|
}
|
|
|
|
protected function createComponentTwoFactorForm(): Form
|
|
{
|
|
$form = new Form();
|
|
$form->addText('code', 'Ověřovací kód (OTP):')
|
|
->setRequired()
|
|
->addRule($form::Pattern, 'Kód musí mít 6 číslic', '\d{6}')
|
|
->setHtmlAttribute('placeholder', '000 000')
|
|
->setHtmlAttribute('autocomplete', 'one-time-code');
|
|
$form->addSubmit('verify', 'Ověřit a přihlásit');
|
|
$form->onSuccess[] = $this->twoFactorFormSucceeded(...);
|
|
return $form;
|
|
}
|
|
|
|
private function twoFactorFormSucceeded(Form $form, \stdClass $data): void
|
|
{
|
|
/**
|
|
* Uživatelská identita = přihlášený user.
|
|
* @var UserIdentity
|
|
*/
|
|
$identity = $this->twoFactorSession->identity;
|
|
|
|
if (!$identity) {
|
|
$this->redirect('in');
|
|
}
|
|
|
|
bdump($identity);
|
|
|
|
// Předpokládáme, že secret je uložen v identitě (z DB)
|
|
$secret = $identity->totpSecret ?? null;
|
|
|
|
if ($this->twoFactorService->verifyCode($secret, $data->code)) {
|
|
// KÓD JE SPRÁVNÝ -> Přihlásíme uživatele do Nette nativně
|
|
$this->getUser()->login($identity);
|
|
|
|
// Vyčistíme dočasnou session
|
|
$this->twoFactorSession->remove();
|
|
|
|
$this->restoreRequest($this->backlink);
|
|
$this->redirect(':Home:');
|
|
} else {
|
|
$form->addError('Neplatný ověřovací kód.');
|
|
}
|
|
}
|
|
|
|
public function renderTwoFactor(): void
|
|
{
|
|
if (!$this->twoFactorSession->identity) {
|
|
$this->redirect('in');
|
|
}
|
|
}
|
|
|
|
public function renderIn(): void
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Normalní logout.
|
|
* @return void
|
|
*/
|
|
public function actionOut(): void
|
|
{
|
|
$this->getUser()->logout();
|
|
$this->flashMessage('Odhlášení bylo úspěšné.');
|
|
$this->redirect('Sign:in');
|
|
}
|
|
} |