diff --git a/mail/signup-noconfirm.html b/mail/signup-noconfirm.html deleted file mode 100644 index dba50fa..0000000 --- a/mail/signup-noconfirm.html +++ /dev/null @@ -1,9 +0,0 @@ -Hi, -

-You recently signed up on {{APP_NAME}} with this Google account ({{EMAIL}}). -

-Have fun on {{APP_NAME}}! -

-Regards,
-{{APP_NAME}}
-{{BASE_URL}} diff --git a/mail/signup.html b/mail/signup.html deleted file mode 100644 index ebdec4f..0000000 --- a/mail/signup.html +++ /dev/null @@ -1,18 +0,0 @@ -Hi, -

-You recently signed up on {{APP_NAME}} with this email address ({{EMAIL}}). -To activate your account, please click on the following link:
-{{ACTIVATE_LINK}} -

-You can activate your account until {{ACTIVATABLE_UNTIL}}. -If you don't activate your account, your email address will be permanently deleted after this point of time. -

-If you did not sign up on {{APP_NAME}} or changed your mind, no further action is required. -However if you want to immediately delete your email address, please click on the following link:
-{{CANCEL_LINK}} -

-Have fun on {{APP_NAME}}! -

-Regards,
-{{APP_NAME}}
-{{BASE_URL}} diff --git a/src/Controller/UserController.php b/src/Controller/UserController.php index 8ae40a6..021c1b7 100644 --- a/src/Controller/UserController.php +++ b/src/Controller/UserController.php @@ -37,6 +37,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 try again!'; + + 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 { /** diff --git a/views/account/account.php b/views/account/account.php index fac3eac..6c95542 100644 --- a/views/account/account.php +++ b/views/account/account.php @@ -44,6 +44,18 @@
+
+
+ + Connect with Google + + + Disconnect from Google + +

Your account does not have a password. Please set a password if you want to disconnect your account from Google.

+ + +
@endsection diff --git a/views/account/google_connect.php b/views/account/google_connect.php new file mode 100644 index 0000000..df72e9a --- /dev/null +++ b/views/account/google_connect.php @@ -0,0 +1,22 @@ +@extends(templates/layout_normal) + +@section(main) +

Connect with Google

+
+ +

+ +
+

Your account will be connected with the following Google account:

+ +

Password

+ +

+
+ Cancel +
+
+ +
+@endsection diff --git a/views/account/google_disconnect.php b/views/account/google_disconnect.php new file mode 100644 index 0000000..4f65776 --- /dev/null +++ b/views/account/google_disconnect.php @@ -0,0 +1,18 @@ +@extends(templates/layout_normal) + +@section(main) +

Disconnect from Google

+
+
+

Your account will be disconnected from the currently set Google account.

+ +

Password

+ +

+
+ Cancel +
+
+
+@endsection diff --git a/views/login/google_login_error.php b/views/login/google_login_error.php index f68648b..8968907 100644 --- a/views/login/google_login_error.php +++ b/views/login/google_login_error.php @@ -1,7 +1,7 @@ @extends(templates/layout_normal) @section(main) -

Login up with Google

+

Login with Google

diff --git a/web.php b/web.php index c0d3593..68e0c31 100644 --- a/web.php +++ b/web.php @@ -52,6 +52,11 @@ Container::$routeCollection->get('logout', 'logout', [LoginController::class, 'l Container::$routeCollection->group('account', function (RouteCollection $routeCollection) { $routeCollection->get('account', '', [UserController::class, 'getAccount']); $routeCollection->post('account-action', '', [UserController::class, 'saveAccount']); + $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']); });