mirror of
https://github.com/openvk/openvk
synced 2024-12-23 17:12:01 +03:00
181 lines
7.6 KiB
PHP
181 lines
7.6 KiB
PHP
|
<?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.");
|
|||
|
}
|
|||
|
}
|
|||
|
}
|