This commit is contained in:
87 files changed
+7008
No files matched your search
@@ -0,0 +1,174 @@
|
||||
<?php namespace RVR\Controller;
|
||||
|
||||
use DateTime;
|
||||
use SokoWeb\Http\Request;
|
||||
use SokoWeb\Interfaces\Authorization\ISecured;
|
||||
use SokoWeb\Interfaces\Request\IRequest;
|
||||
use SokoWeb\Interfaces\Response\IContent;
|
||||
use SokoWeb\Interfaces\Response\IRedirect;
|
||||
use SokoWeb\OAuth\GoogleOAuth;
|
||||
use SokoWeb\PersistentData\PersistentDataManager;
|
||||
use RVR\PersistentData\Model\User;
|
||||
use SokoWeb\Response\HtmlContent;
|
||||
use SokoWeb\Response\JsonContent;
|
||||
use SokoWeb\Response\Redirect;
|
||||
use SokoWeb\Util\JwtParser;
|
||||
|
||||
class UserController implements ISecured
|
||||
{
|
||||
private IRequest $request;
|
||||
|
||||
private PersistentDataManager $pdm;
|
||||
|
||||
public function __construct(IRequest $request)
|
||||
{
|
||||
$this->request = $request;
|
||||
$this->pdm = new PersistentDataManager();
|
||||
}
|
||||
|
||||
public function authorize(): bool
|
||||
{
|
||||
return $this->request->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 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]);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user