213 lines
6.7 KiB
PHP
213 lines
6.7 KiB
PHP
<?php namespace MapGuesser\Controller;
|
|
|
|
use DateTime;
|
|
use MapGuesser\Database\Query\Select;
|
|
use MapGuesser\Http\Request;
|
|
use MapGuesser\Interfaces\Authorization\ISecured;
|
|
use MapGuesser\Interfaces\Database\IResultSet;
|
|
use MapGuesser\Interfaces\Request\IRequest;
|
|
use MapGuesser\Interfaces\Response\IContent;
|
|
use MapGuesser\Interfaces\Response\IRedirect;
|
|
use MapGuesser\OAuth\GoogleOAuth;
|
|
use MapGuesser\PersistentData\PersistentDataManager;
|
|
use MapGuesser\PersistentData\Model\User;
|
|
use MapGuesser\PersistentData\Model\UserConfirmation;
|
|
use MapGuesser\Repository\UserConfirmationRepository;
|
|
use MapGuesser\Response\HtmlContent;
|
|
use MapGuesser\Response\JsonContent;
|
|
use MapGuesser\Response\Redirect;
|
|
use MapGuesser\Util\JwtParser;
|
|
|
|
class UserController implements ISecured
|
|
{
|
|
private IRequest $request;
|
|
|
|
private PersistentDataManager $pdm;
|
|
|
|
private UserConfirmationRepository $userConfirmationRepository;
|
|
|
|
public function __construct(IRequest $request)
|
|
{
|
|
$this->request = $request;
|
|
$this->pdm = new PersistentDataManager();
|
|
$this->userConfirmationRepository = new UserConfirmationRepository();
|
|
}
|
|
|
|
public function authorize(): bool
|
|
{
|
|
$user = $this->request->user();
|
|
|
|
return $user !== null;
|
|
}
|
|
|
|
public function getAccount(): IContent
|
|
{
|
|
/**
|
|
* @var User $user
|
|
*/
|
|
$user = $this->request->user();
|
|
|
|
$data = ['user' => $user->toArray()];
|
|
return new HtmlContent('account/account', $data);
|
|
}
|
|
|
|
public function getGoogleAuthenticateRedirect(): IRedirect
|
|
{
|
|
/**
|
|
* @var User $user
|
|
*/
|
|
$user = $this->request->user();
|
|
|
|
$state = bin2hex(random_bytes(16));
|
|
|
|
$this->request->session()->set('oauth_state', $state);
|
|
|
|
$oAuth = new GoogleOAuth(new Request());
|
|
|
|
$url = $oAuth->getDialogUrl(
|
|
$state,
|
|
$this->request->getBase() . '/' . \Container::$routeCollection->getRoute('account.googleAuthenticate-action')->generateLink(),
|
|
$user->getEmail()
|
|
);
|
|
|
|
return new Redirect($url, IRedirect::TEMPORARY);
|
|
}
|
|
|
|
public function authenticateWithGoogle(): IContent
|
|
{
|
|
/**
|
|
* @var User $user
|
|
*/
|
|
$user = $this->request->user();
|
|
|
|
if ($this->request->query('state') !== $this->request->session()->get('oauth_state')) {
|
|
$data = ['success' => false];
|
|
return new HtmlContent('account/google_authenticate', $data);
|
|
}
|
|
|
|
$oAuth = new GoogleOAuth(new Request());
|
|
$tokenData = $oAuth->getToken($this->request->query('code'), $this->request->getBase() . '/' . \Container::$routeCollection->getRoute('account.googleAuthenticate-action')->generateLink());
|
|
|
|
if (!isset($tokenData['id_token'])) {
|
|
$data = ['success' => false];
|
|
return new HtmlContent('account/google_authenticate', $data);
|
|
}
|
|
|
|
$jwtParser = new JwtParser($tokenData['id_token']);
|
|
$userData = $jwtParser->getPayload();
|
|
|
|
if ($userData['sub'] !== $user->getGoogleSub()) {
|
|
$data = ['success' => false, 'errorText' => 'This Google account is not linked to your account.'];
|
|
return new HtmlContent('account/google_authenticate', $data);
|
|
}
|
|
|
|
$authenticatedWithGoogleUntil = new DateTime('+45 seconds');
|
|
$this->request->session()->set('authenticated_with_google_until', $authenticatedWithGoogleUntil);
|
|
|
|
$data = ['success' => true, 'authenticatedWithGoogleUntil' => $authenticatedWithGoogleUntil];
|
|
return new HtmlContent('account/google_authenticate', $data);
|
|
}
|
|
|
|
public function getDeleteAccount(): IContent
|
|
{
|
|
/**
|
|
* @var User $user
|
|
*/
|
|
$user = $this->request->user();
|
|
|
|
$data = ['user' => $user->toArray()];
|
|
return new HtmlContent('account/delete', $data);
|
|
}
|
|
|
|
public function saveAccount(): IContent
|
|
{
|
|
/**
|
|
* @var User $user
|
|
*/
|
|
$user = $this->request->user();
|
|
|
|
if (!$this->confirmUserIdentity(
|
|
$user,
|
|
$this->request->session()->get('authenticated_with_google_until'),
|
|
$this->request->post('password'),
|
|
$error
|
|
)) {
|
|
$data = ['error' => ['errorText' => $error]];
|
|
return new JsonContent($data);
|
|
}
|
|
|
|
if (strlen($this->request->post('password_new')) > 0) {
|
|
if (strlen($this->request->post('password_new')) < 6) {
|
|
$data = ['error' => ['errorText' => 'The given new password is too short. Please choose a password that is at least 6 characters long!']];
|
|
return new JsonContent($data);
|
|
}
|
|
|
|
if ($this->request->post('password_new') !== $this->request->post('password_new_confirm')) {
|
|
$data = ['error' => ['errorText' => 'The given new passwords do not match.']];
|
|
return new JsonContent($data);
|
|
}
|
|
|
|
$user->setPlainPassword($this->request->post('password_new'));
|
|
}
|
|
|
|
$this->pdm->saveToDb($user);
|
|
|
|
$this->request->session()->delete('authenticated_with_google_until');
|
|
|
|
$data = ['success' => true];
|
|
return new JsonContent($data);
|
|
}
|
|
|
|
public function deleteAccount(): IContent
|
|
{
|
|
/**
|
|
* @var User $user
|
|
*/
|
|
$user = $this->request->user();
|
|
|
|
if (!$this->confirmUserIdentity(
|
|
$user,
|
|
$this->request->session()->get('authenticated_with_google_until'),
|
|
$this->request->post('password'),
|
|
$error
|
|
)) {
|
|
$data = ['error' => ['errorText' => $error]];
|
|
return new JsonContent($data);
|
|
}
|
|
|
|
\Container::$dbConnection->startTransaction();
|
|
|
|
foreach ($this->userConfirmationRepository->getByUser($user) as $userConfirmation) {
|
|
$this->pdm->deleteFromDb($userConfirmation);
|
|
}
|
|
|
|
$this->pdm->deleteFromDb($user);
|
|
|
|
\Container::$dbConnection->commit();
|
|
|
|
$this->request->session()->delete('authenticated_with_google_until');
|
|
|
|
$data = ['success' => true];
|
|
return new JsonContent($data);
|
|
}
|
|
|
|
private function confirmUserIdentity(User $user, ?DateTime $authenticatedWithGoogleUntil, ?string $password, &$error): bool
|
|
{
|
|
if ($authenticatedWithGoogleUntil !== null && $authenticatedWithGoogleUntil > new DateTime()) {
|
|
return true;
|
|
}
|
|
|
|
if ($password !== null) {
|
|
if ($user->checkPassword($password)) {
|
|
return true;
|
|
}
|
|
|
|
$error = 'The given current password is wrong.';
|
|
return false;
|
|
}
|
|
|
|
$error = 'Could not confirm your identity. Please try again!';
|
|
return false;
|
|
}
|
|
}
|