add google connect and disconnect to account

This commit is contained in:
Bence Pőcze 2023-09-24 01:30:59 +02:00
parent d1fa8c35f5
commit d006c6d413
Signed by: bence
GPG Key ID: DC5BD6E95A333E6D
5 changed files with 176 additions and 0 deletions

View File

@ -57,6 +57,130 @@ class UserController implements IAuthenticationRequired
return new HtmlContent('account/account', ['user' => $user->toArray()]);
}
public function getGoogleConnectRedirect(): IRedirect
{
/**
* @var User $user
*/
$user = \Container::$request->user();
$state = bin2hex(random_bytes(16));
$nonce = bin2hex(random_bytes(16));
\Container::$request->session()->set('oauth_state', $state);
\Container::$request->session()->set('oauth_nonce', $nonce);
$oAuth = new GoogleOAuth(new Request());
$url = $oAuth->getDialogUrl(
$state,
\Container::$request->getBase() . \Container::$routeCollection->getRoute('account.googleConnect-confirm')->generateLink(),
$nonce,
$user->getEmail()
);
return new Redirect($url, IRedirect::TEMPORARY);
}
public function getGoogleConnectConfirm(): IContent
{
$defaultError = 'Authentication with Google failed. Please <a href="' . \Container::$routeCollection->getRoute('account.googleConnect')->generateLink() . '" title="Connect with Google">try again</a>!';
if (\Container::$request->query('state') !== \Container::$request->session()->get('oauth_state')) {
return new HtmlContent('account/google_connect', ['success' => false, 'error' => $defaultError]);
}
$oAuth = new GoogleOAuth(new Request());
$tokenData = $oAuth->getToken(
\Container::$request->query('code'),
\Container::$request->getBase() . \Container::$routeCollection->getRoute('account.googleConnect-confirm')->generateLink()
);
if (!isset($tokenData['id_token'])) {
return new HtmlContent('account/google_connect', ['success' => false, 'error' => $defaultError]);
}
$jwtParser = new JwtParser($tokenData['id_token']);
$idToken = $jwtParser->getPayload();
if ($idToken['nonce'] !== \Container::$request->session()->get('oauth_nonce')) {
return new HtmlContent('account/google_connect', ['success' => false, 'error' => $defaultError]);
}
$anotherUser = $this->userRepository->getByGoogleSub($idToken['sub']);
if ($anotherUser !== null) {
return new HtmlContent('account/google_connect', [
'success' => false,
'error' => 'This Google account is linked to another account.'
]);
}
\Container::$request->session()->set('google_user_data', $idToken);
/**
* @var User $user
*/
$user = \Container::$request->user();
return new HtmlContent('account/google_connect', [
'success' => true,
'googleAccount' => $idToken['email'],
'userEmail' => $user->getEmail()
]);
}
public function connectGoogle(): IContent
{
/**
* @var User $user
*/
$user = \Container::$request->user();
if (!$user->checkPassword(\Container::$request->post('password'))) {
return new JsonContent([
'error' => [
'errorText' => 'The given password is wrong.'
]
]);
}
$googleUserData = \Container::$request->session()->get('google_user_data');
$user->setGoogleSub($googleUserData['sub']);
\Container::$persistentDataManager->saveToDb($user);
return new JsonContent(['success' => true]);
}
public function getGoogleDisconnectConfirm(): IContent
{
/**
* @var User $user
*/
$user = \Container::$request->user();
return new HtmlContent('account/google_disconnect', [
'success' => true,
'userEmail' => $user->getEmail()
]);
}
public function disconnectGoogle(): IContent
{
/**
* @var User $user
*/
$user = \Container::$request->user();
if (!$user->checkPassword(\Container::$request->post('password'))) {
return new JsonContent([
'error' => [
'errorText' => 'The given password is wrong.'
]
]);
}
$user->setGoogleSub(null);
\Container::$persistentDataManager->saveToDb($user);
return new JsonContent(['success' => true]);
}
public function getGoogleAuthenticateRedirect(): IRedirect
{
/**

View File

@ -33,6 +33,13 @@
</div>
<hr>
<div class="center">
<?php if ($user['google_sub'] === null): ?>
<a class="button yellow" href="<?= Container::$routeCollection->getRoute('account.googleConnect')->generateLink() ?>" title="Connect with Google">Connect with Google</a>
<?php else: ?>
<?php if ($user['password'] !== null): ?>
<a class="button yellow" href="<?= Container::$routeCollection->getRoute('account.googleDisconnect')->generateLink() ?>" title="Disconnect from Google">Disconnect from Google</a>
<?php endif; ?>
<?php endif; ?>
<a class="button red" href="/account/delete" title="Delete account">Delete account</a>
</div>
</form>

View File

@ -0,0 +1,22 @@
@extends(templates/layout_normal)
@section(main)
<h2>Connect with Google</h2>
<div class="box compactBox">
<?php if (!$success): ?>
<p class="error justify"><?= $error ?></p>
<?php else: ?>
<form id="connectGoogleForm" action="<?= Container::$routeCollection->getRoute('account.googleConnect-action')->generateLink() ?>" method="post" data-redirect-on-success="<?= Container::$routeCollection->getRoute('account')->generateLink() ?>">
<p class="justify marginBottom">Your account will be connected with the following Google account: <b><?= $googleAccount ?></b></p>
<input type="email" style="display: none;" name="email" autocomplete="username" value="<?= $userEmail ?>">
<p class="formLabel marginTop">Password</p>
<input type="password" class="text big fullWidth" name="password" autocomplete="current-password" required minlength="6" autofocus>
<p class="formError justify marginTop"></p>
<div class="right marginTop">
<button class="marginRight" type="submit" name="submit"><i class="fa-solid fa-link"></i> Connect</button><!--
--><a class="button gray" href="<?= Container::$routeCollection->getRoute('account')->generateLink() ?>" title="Back to account">Cancel</a>
</div>
</form>
<?php endif; ?>
</div>
@endsection

View File

@ -0,0 +1,18 @@
@extends(templates/layout_normal)
@section(main)
<h2>Disconnect from Google</h2>
<div class="box compactBox">
<form id="connectGoogleForm" action="<?= Container::$routeCollection->getRoute('account.googleDisconnect-action')->generateLink() ?>" method="post" data-redirect-on-success="<?= Container::$routeCollection->getRoute('account')->generateLink() ?>">
<p class="justify marginBottom">Your account will be disconnected from the currently set Google account.</p>
<input type="email" style="display: none;" name="email" autocomplete="username" value="<?= $userEmail ?>">
<p class="formLabel marginTop">Password</p>
<input type="password" class="text big fullWidth" name="password" autocomplete="current-password" required minlength="6" autofocus>
<p class="formError justify marginTop"></p>
<div class="right marginTop">
<button class="red marginRight" type="submit" name="submit"><i class="fa-solid fa-link-slash"></i> Disconnect</button><!--
--><a class="button gray" href="<?= Container::$routeCollection->getRoute('account')->generateLink() ?>" title="Back to account">Cancel</a>
</div>
</form>
</div>
@endsection

View File

@ -57,6 +57,11 @@ Container::$routeCollection->group('account', function (RouteCollection $routeCo
$routeCollection->post('account-action', '', [UserController::class, 'saveAccount']);
$routeCollection->get('account.delete', 'delete', [UserController::class, 'getDeleteAccount']);
$routeCollection->post('account.delete-action', 'delete', [UserController::class, 'deleteAccount']);
$routeCollection->get('account.googleConnect', 'googleConnect', [UserController::class, 'getGoogleConnectRedirect']);
$routeCollection->get('account.googleConnect-confirm', 'googleConnect/code', [UserController::class, 'getGoogleConnectConfirm']);
$routeCollection->post('account.googleConnect-action', 'googleConnect', [UserController::class, 'connectGoogle']);
$routeCollection->get('account.googleDisconnect', 'googleDisconnect', [UserController::class, 'getGoogleDisconnectConfirm']);
$routeCollection->post('account.googleDisconnect-action', 'googleDisconnect', [UserController::class, 'disconnectGoogle']);
$routeCollection->get('account.googleAuthenticate', 'googleAuthenticate', [UserController::class, 'getGoogleAuthenticateRedirect']);
$routeCollection->get('account.googleAuthenticate-action', 'googleAuthenticate/code', [UserController::class, 'authenticateWithGoogle']);
});