openvk/Web/Presenters/AuthPresenter.php
2020-06-07 19:04:43 +03:00

180 lines
7.6 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php declare(strict_types=1);
namespace openvk\Web\Presenters;
use openvk\Web\Models\Entities\User;
use openvk\Web\Models\Entities\PasswordReset;
use openvk\Web\Models\Repositories\Users;
use openvk\Web\Models\Repositories\Restores;
use Chandler\Session\Session;
use Chandler\Security\User as ChandlerUser;
use Chandler\Security\Authenticator;
use Chandler\Database\DatabaseConnection;
final class AuthPresenter extends OpenVKPresenter
{
protected $banTolerant = true;
private $authenticator;
private $db;
private $users;
private $restores;
function __construct(Users $users, Restores $restores)
{
$this->authenticator = Authenticator::i();
$this->db = DatabaseConnection::i()->getContext();
$this->users = $users;
$this->restores = $restores;
parent::__construct();
}
private function emailValid(string $email): bool
{
if(empty($email)) return false;
$email = trim($email);
[$user, $domain] = explode("@", $email);
$domain = idn_to_ascii($domain) . ".";
return checkdnsrr($domain, "MX");
}
function renderRegister(): void
{
if(!is_null($this->user))
$this->redirect("/id" . $this->user->id, static::REDIRECT_TEMPORARY);
if(!$this->hasPermission("user", "register", -1)) exit("Вас забанили");
if($_SERVER["REQUEST_METHOD"] === "POST") {
$this->assertCaptchaCheckPassed();
if(!$this->emailValid($this->postParam("email")))
$this->flashFail("err", "Неверный email адрес", "Email, который вы ввели, не является корректным.");
$chUser = ChandlerUser::create($this->postParam("email"), $this->postParam("password"));
if(!$chUser)
$this->flashFail("err", "Не удалось зарегистрироваться", "Пользователь с таким email уже существует.");
$user = new User;
$user->setUser($chUser->getId());
$user->setFirst_Name($this->postParam("first_name"));
$user->setLast_Name($this->postParam("last_name"));
$user->setSex((int) ($this->postParam("sex") === "female"));
$user->setEmail($this->postParam("email"));
$user->setSince(date("Y-m-d H:i:s"));
$user->save();
$this->authenticator->authenticate($chUser->getId());
$this->redirect("/id" . $user->getId(), static::REDIRECT_TEMPORARY);
}
}
function renderLogin(): void
{
if(!is_null($this->user))
$this->redirect("/id" . $this->user->id, static::REDIRECT_TEMPORARY);
if(!$this->hasPermission("user", "login", -1)) exit("Вас забанили");
if($_SERVER["REQUEST_METHOD"] === "POST") {
$user = $this->db->table("ChandlerUsers")->where("login", $this->postParam("login"))->fetch();
if(!$user)
$this->flashFail("err", "Не удалось войти", "Неверное имя пользователя или пароль. <a href='/restore.pl'>Забыли пароль?</a>");
if(!$this->authenticator->login($user->id, $this->postParam("password")))
$this->flashFail("err", "Не удалось войти", "Неверное имя пользователя или пароль. <a href='/restore.pl'>Забыли пароль?</a>");
$redirUrl = $_GET["jReturnTo"] ?? "/id" . $user->related("profiles.user")->fetch()->id;
$this->redirect($redirUrl, static::REDIRECT_TEMPORARY);
exit;
}
}
function renderSu(string $uuid): void
{
$this->assertNoCSRF();
$this->assertUserLoggedIn();
if($uuid === "unset") {
Session::i()->set("_su", NULL);
$this->redirect("/", static::REDIRECT_TEMPORARY);
}
if(!$this->db->table("ChandlerUsers")->where("id", $uuid))
$this->flashFail("err", "Ошибка манипуляции токенами", "Пользователь не найден.");
$this->assertPermission('openvk\Web\Models\Entities\User', 'substitute', 0);
Session::i()->set("_su", $uuid);
$this->flash("succ", "Профиль изменён", "Ваш активный профиль был изменён.");
$this->redirect("/", static::REDIRECT_TEMPORARY);
exit;
}
function renderLogout(): void
{
$this->assertUserLoggedIn();
$this->authenticator->logout();
Session::i()->set("_su", NULL);
$this->redirect("/", static::REDIRECT_TEMPORARY_PRESISTENT);
}
function renderFinishRestoringPassword(): void
{
$request = $this->restores->getByToken(str_replace(" ", "+", $this->queryParam("key")));
if(!$request || !$request->isStillValid()) {
$this->flash("err", "Ошибка манипулирования токеном", "Токен недействителен или истёк");
$this->redirect("/");
}
if($_SERVER["REQUEST_METHOD"] === "POST") {
$user = $request->getUser()->getChandlerUser();
$this->db->table("ChandlerTokens")->where("user", $user->getId())->delete(); #Logout from everywhere
$user->updatePassword($this->postParam("password"));
$this->authenticator->authenticate($user->getId());
$request->delete(false);
$this->flash("succ", "Успешно", "Ваш пароль был успешно сброшен.");
$this->redirect("/settings");
}
}
function renderRestore(): void
{
if(($this->queryParam("act") ?? "default") === "finish")
$this->pass("openvk!Auth->finishRestoringPassword");
if($_SERVER["REQUEST_METHOD"] === "POST") {
$uRow = $this->db->table("ChandlerUsers")->where("login", $this->postParam("login"))->fetch();
if(!$uRow) {
#Privacy of users must be protected. We will not tell if email is bound to a user or not.
$this->flashFail("succ", "Успешно", "Если вы зарегистрированы, вы получите инструкции на email.");
}
$user = $this->users->getByChandlerUser(new ChandlerUser($uRow));
if(!$user)
$this->flashFail("err", "Ошибка", "Непредвиденная ошибка при сбросе пароля.");
$request = $this->restores->getLatestByUser($user);
if(!is_null($request) && $request->isNew())
$this->flashFail("err", "Ошибка доступа", "Нельзя делать это так часто, извините.");
$resetObj = new PasswordReset;
$resetObj->setProfile($user->getId());
$resetObj->save();
$params = [
"key" => $resetObj->getKey(),
"name" => $user->getCanonicalName(),
];
$this->sendmail($uRow->login, "password-reset", $params); #Vulnerability possible
$this->flashFail("succ", "Успешно", "Если вы зарегистрированы, вы получите инструкции на email.");
}
}
}