request = $request; $this->pdm = new PersistentDataManager(); $this->userConfirmationRepository = new UserConfirmationRepository(); $this->userPasswordResetterRepository = new UserPasswordResetterRepository(); } public function authorize(): bool { $user = $this->request->user(); return $user !== null; } public function getAccount(): IContent { /** * @var User $user */ $user = $this->request->user(); return new HtmlContent('account/account', ['user' => $user->toArray()]); } public function getGoogleAuthenticateRedirect(): IRedirect { /** * @var User $user */ $user = $this->request->user(); $state = bin2hex(random_bytes(16)); $nonce = bin2hex(random_bytes(16)); $this->request->session()->set('oauth_state', $state); $this->request->session()->set('oauth_nonce', $nonce); $oAuth = new GoogleOAuth(new Request()); $url = $oAuth->getDialogUrl( $state, $this->request->getBase() . '/' . \Container::$routeCollection->getRoute('account.googleAuthenticate-action')->generateLink(), $nonce, $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')) { return new HtmlContent('account/google_authenticate', ['success' => false]); } $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'])) { return new HtmlContent('account/google_authenticate', ['success' => false]); } $jwtParser = new JwtParser($tokenData['id_token']); $idToken = $jwtParser->getPayload(); if ($idToken['nonce'] !== $this->request->session()->get('oauth_nonce')) { return new HtmlContent('account/google_authenticate', ['success' => false]); } if ($idToken['sub'] !== $user->getGoogleSub()) { return new HtmlContent('account/google_authenticate', [ 'success' => false, 'errorText' => 'This Google account is not linked to your account.' ]); } $authenticatedWithGoogleUntil = new DateTime('+45 seconds'); $this->request->session()->set('authenticated_with_google_until', $authenticatedWithGoogleUntil); return new HtmlContent('account/google_authenticate', [ 'success' => true, 'authenticatedWithGoogleUntil' => $authenticatedWithGoogleUntil ]); } public function getDeleteAccount(): IContent { /** * @var User $user */ $user = $this->request->user(); return new HtmlContent('account/delete', ['user' => $user->toArray()]); } 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 )) { return new JsonContent(['error' => ['errorText' => $error]]); } if (strlen($this->request->post('password_new')) > 0) { if (strlen($this->request->post('password_new')) < 6) { return new JsonContent([ 'error' => [ 'errorText' => 'The given new password is too short. Please choose a password that is at least 6 characters long!' ] ]); } if ($this->request->post('password_new') !== $this->request->post('password_new_confirm')) { return new JsonContent([ 'error' => [ 'errorText' => 'The given new passwords do not match.' ] ]); } $user->setPlainPassword($this->request->post('password_new')); } $this->pdm->saveToDb($user); $this->request->session()->delete('authenticated_with_google_until'); return new JsonContent(['success' => true]); } 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 )) { return new JsonContent(['error' => ['errorText' => $error]]); } \Container::$dbConnection->startTransaction(); $userConfirmation = $this->userConfirmationRepository->getByUser($user); if ($userConfirmation !== null) { $this->pdm->deleteFromDb($userConfirmation); } $userPasswordResetter = $this->userPasswordResetterRepository->getByUser($user); if ($userPasswordResetter !== null) { $this->pdm->deleteFromDb($userPasswordResetter); } $this->pdm->deleteFromDb($user); \Container::$dbConnection->commit(); $this->request->session()->delete('authenticated_with_google_until'); return new JsonContent(['success' => true]); } private function confirmUserIdentity(User $user, ?DateTime $authenticatedWithGoogleUntil, ?string $password, string &$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; } }