diff --git a/.gitignore b/.gitignore
index 5f4186b..48cf206 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,5 @@
/.php_cs.cache
+/tests/clover.xml
+/tests/coverage-html
/tests/.phpunit.result.cache
/vendor
diff --git a/appinfo/routes.php b/appinfo/routes.php
index 7db7778..d83acb7 100644
--- a/appinfo/routes.php
+++ b/appinfo/routes.php
@@ -13,14 +13,16 @@
return [
'routes' => [
['name' => 'settings#admin', 'url' => '/settings', 'verb' => 'POST'],
- ['name' => 'register#askEmail', 'url' => '/', 'verb' => 'GET'],
- ['name' => 'register#validateEmail', 'url' => '/', 'verb' => 'POST'],
- ['name' => 'register#verifyToken', 'url' => '/verify/{token}', 'verb' => 'GET'],
- ['name' => 'register#createAccount', 'url' => '/verify/{token}', 'verb' => 'POST']
+ ['name' => 'register#showEmailForm', 'url' => '/', 'verb' => 'GET'],
+ ['name' => 'register#submitEmailForm', 'url' => '/', 'verb' => 'POST'],
+ ['name' => 'register#showVerificationForm', 'url' => '/verify/{secret}', 'verb' => 'GET'],
+ ['name' => 'register#submitVerificationForm', 'url' => '/verify/{secret}', 'verb' => 'POST'],
+ ['name' => 'register#showUserForm', 'url' => '/register/{secret}/{token}', 'verb' => 'GET'],
+ ['name' => 'register#submitUserForm', 'url' => '/register/{secret}/{token}', 'verb' => 'POST'],
],
'ocs' => [
['root' => '/registration', 'name' => 'api#validate', 'url' => '/v1/validate', 'verb' => 'POST'],
['root' => '/registration', 'name' => 'api#status', 'url' => '/v1/status', 'verb' => 'POST'],
- ['root' => '/registration', 'name' => 'api#register', 'url' => '/v1/register', 'verb' => 'POST']
+ ['root' => '/registration', 'name' => 'api#register', 'url' => '/v1/register', 'verb' => 'POST'],
]
];
diff --git a/css/register-button.css b/css/register-button.css
index a732b81..9cf50b4 100644
--- a/css/register-button.css
+++ b/css/register-button.css
@@ -2,7 +2,11 @@
color: var(--color-primary-element);
}
-.register-button:only-child {
+#alternative-logins .register-button:only-child {
width: 220px;
margin-left: 70px !important;
}
+
+#alternative-logins .register-button.hidden {
+ display: none;
+}
diff --git a/css/style.css b/css/style.css
index 3987ce6..7171a26 100644
--- a/css/style.css
+++ b/css/style.css
@@ -1,8 +1,14 @@
-#body-login #email, #body-login #username, #body-login #password {
+#body-login #email,
+#body-login #token,
+#body-login #username,
+#body-login #password {
width: calc(100% - 56px);
padding-left: 36px;
}
-#email-icon, #username-icon, #password-icon {
+#email-icon,
+#token-icon,
+#username-icon,
+#password-icon {
position: absolute;
left: 16px;
top: 22px;
diff --git a/img/verify.svg b/img/verify.svg
new file mode 100644
index 0000000..f1b2091
--- /dev/null
+++ b/img/verify.svg
@@ -0,0 +1 @@
+
diff --git a/lib/Controller/RegisterController.php b/lib/Controller/RegisterController.php
index deb7e55..cc5ea0e 100644
--- a/lib/Controller/RegisterController.php
+++ b/lib/Controller/RegisterController.php
@@ -1,4 +1,7 @@
* @author Julius Härtl
+ * @author 2020 Joas Schilling
* @copyright Pellaeon Lin 2014
*/
namespace OCA\Registration\Controller;
+use Exception;
use OCA\Registration\Db\Registration;
+use OCA\Registration\Service\LoginFlowService;
use OCA\Registration\Service\MailService;
use OCA\Registration\Service\RegistrationException;
use OCA\Registration\Service\RegistrationService;
-use \OCP\IRequest;
-use \OCP\AppFramework\Http\TemplateResponse;
-use \OCP\AppFramework\Http\RedirectResponse;
-use \OCP\AppFramework\Controller;
+use OCP\AppFramework\Controller;
+use OCP\AppFramework\Db\DoesNotExistException;
+use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\RedirectResponse;
+use OCP\AppFramework\Http\RedirectToDefaultAppResponse;
+use OCP\AppFramework\Http\Response;
+use OCP\AppFramework\Http\StandaloneTemplateResponse;
+use OCP\AppFramework\Http\TemplateResponse;
+use OCP\IL10N;
+use OCP\IRequest;
use OCP\IURLGenerator;
-use \OCP\IConfig;
-use \OCP\IL10N;
+use OCP\IConfig;
class RegisterController extends Controller {
/** @var IL10N */
private $l10n;
/** @var IURLGenerator */
- private $urlgenerator;
+ private $urlGenerator;
/** @var IConfig */
private $config;
/** @var RegistrationService */
private $registrationService;
/** @var MailService */
private $mailService;
-
+ /** @var LoginFlowService */
+ private $loginFlowService;
public function __construct(
- $appName,
+ string $appName,
IRequest $request,
IL10N $l10n,
- IURLGenerator $urlgenerator,
+ IURLGenerator $urlGenerator,
IConfig $config,
RegistrationService $registrationService,
+ LoginFlowService $loginFlowService,
MailService $mailService
) {
parent::__construct($appName, $request);
$this->l10n = $l10n;
- $this->urlgenerator = $urlgenerator;
+ $this->urlGenerator = $urlGenerator;
$this->config = $config;
$this->registrationService = $registrationService;
+ $this->loginFlowService = $loginFlowService;
$this->mailService = $mailService;
}
@@ -59,136 +73,213 @@ class RegisterController extends Controller {
* @NoCSRFRequired
* @PublicPage
*
- * @param $errormsg
- * @param $entered
+ * @param string $email
+ * @param string $message
* @return TemplateResponse
*/
- public function askEmail($errormsg, $entered) {
+ public function showEmailForm(string $email = '', string $message = ''): TemplateResponse {
$params = [
- 'errormsg' => $errormsg ? $errormsg : $this->request->getParam('errormsg'),
- 'entered' => $entered ? $entered : $this->request->getParam('entered')
+ 'email' => $email,
+ 'message' => $message,
];
- return new TemplateResponse('registration', 'register', $params, 'guest');
+ return new TemplateResponse('registration', 'form/email', $params, 'guest');
}
/**
- * User POST email, if email is valid and not duplicate, we send token by mail
* @PublicPage
* @AnonRateThrottle(limit=5, period=1)
*
* @param string $email
* @return TemplateResponse
*/
- public function validateEmail($email) {//TODO rename to receiveUserEmail
- if (!$this->registrationService->checkAllowedDomains($email)) {//TODO Duplicate code with Service
- return new TemplateResponse('registration', 'domains', [
- 'domains' => $this->registrationService->getAllowedDomains()
- ], 'guest');
- }
+ public function submitEmailForm(string $email): Response {
try {
- $reg = $this->registrationService->validateEmail($email);
- if ($reg === true) {
- $registration = $this->registrationService->createRegistration($email);
- $this->mailService->sendTokenByMail($registration);
- } else {
- $this->registrationService->generateNewToken($reg);
- $this->mailService->sendTokenByMail($reg);
- return new TemplateResponse('registration', 'message', ['msg' =>
- $this->l10n->t('There is already a pending registration with this email, a new verification email has been sent to the address.')
- ], 'guest');
+ // Registration already in progress, update token and continue with verification
+ $registration = $this->registrationService->getRegistrationForEmail($email);
+ $this->registrationService->generateNewToken($registration);
+ } catch (DoesNotExistException $e) {
+ // No registration in progress
+ try {
+ $this->registrationService->validateEmail($email);
+ } catch (RegistrationException $e) {
+ return $this->showEmailForm($email, $e->getMessage());
}
- } catch (RegistrationException $e) {
- return new TemplateResponse('registration', 'message', ['msg' =>
- $e->getMessage().' '.$e->getHint()
- ], 'guest');
+
+ $registration = $this->registrationService->createRegistration($email);
}
+ try {
+ $this->mailService->sendTokenByMail($registration);
+ } catch (RegistrationException $e) {
+ return $this->showEmailForm($email, $e->getMessage());
+ }
- return new TemplateResponse('registration', 'message', ['msg' =>
- $this->l10n->t('Verification email successfully sent.')
- ], 'guest');
+ return new RedirectResponse(
+ $this->urlGenerator->linkToRoute(
+ 'registration.register.showVerificationForm',
+ ['secret' => $registration->getClientSecret()]
+ )
+ );
}
/**
* @NoCSRFRequired
* @PublicPage
*
- * @param $token
+ * @param string $secret
+ * @param string $message
* @return TemplateResponse
*/
- public function verifyToken($token) {
+ public function showVerificationForm(string $secret, string $message = ''): TemplateResponse {
try {
- /** @var Registration $registration */
- $registration = $this->registrationService->verifyToken($token);
- $this->registrationService->confirmEmail($registration);
+ $this->registrationService->getRegistrationForSecret($secret);
+ } catch (DoesNotExistException $e) {
+ return $this->validateSecretAndTokenErrorPage();
+ }
- // create account without form if username/password are already stored
- if ($registration->getUsername() !== "" && $registration->getPassword() !== "") {
- $this->registrationService->createAccount($registration);
- return new TemplateResponse('registration', 'message',
- ['msg' => $this->l10n->t('Your account has been successfully created, you can log in now.', [$this->urlgenerator->getAbsoluteURL('/')])],
- 'guest'
+ return new TemplateResponse('registration', 'form/verification', [
+ 'message' => $message,
+ ], 'guest');
+ }
+
+ /**
+ * @PublicPage
+ * @AnonRateThrottle(limit=5, period=1)
+ *
+ * @param string $secret
+ * @param string $token
+ * @return Response
+ */
+ public function submitVerificationForm(string $secret, string $token): Response {
+ try {
+ $registration = $this->registrationService->getRegistrationForSecret($secret);
+
+ if ($registration->getToken() !== $token) {
+ return $this->showVerificationForm(
+ $secret,
+ $this->l10n->t('The entered verification code is wrong')
);
}
-
- return new TemplateResponse('registration', 'form', [
- 'email' => $registration->getEmail(),
- 'email_is_login' => $this->config->getAppValue('registration', 'email_is_login', '0') === '1',
- 'token' => $registration->getToken(),
- ], 'guest');
- } catch (RegistrationException $exception) {
- return $this->renderError($exception->getMessage(), $exception->getHint());
+ } catch (DoesNotExistException $e) {
+ return $this->validateSecretAndTokenErrorPage();
}
+
+ return new RedirectResponse(
+ $this->urlGenerator->linkToRoute(
+ 'registration.register.showUserForm',
+ [
+ 'secret' => $secret,
+ 'token' => $token,
+ ]
+ )
+ );
+ }
+
+ /**
+ * @NoCSRFRequired
+ * @PublicPage
+ *
+ * @param string $secret
+ * @param string $token
+ * @param string $username
+ * @param string $message
+ * @return TemplateResponse
+ */
+ public function showUserForm(string $secret, string $token, string $username = '', string $message = ''): TemplateResponse {
+ try {
+ $registration = $this->validateSecretAndToken($secret, $token);
+ } catch (RegistrationException $e) {
+ return $this->validateSecretAndTokenErrorPage();
+ }
+
+ return new TemplateResponse('registration', 'form/user', [
+ 'email' => $registration->getEmail(),
+ 'email_is_login' => $this->config->getAppValue('registration', 'email_is_login', '0') === '1',
+ 'username' => $username,
+ 'message' => $message,
+ ], 'guest');
}
/**
* @PublicPage
* @UseSession
+ * @AnonRateThrottle(limit=5, period=1)
*
- * @param $token
+ * @param string $secret
+ * @param string $token
+ * @param string $username
+ * @param string $password
* @return RedirectResponse|TemplateResponse
*/
- public function createAccount($token) {
- $registration = $this->registrationService->getRegistrationForToken($token);
+ public function submitUserForm(string $secret, string $token, string $username, string $password): Response {
+ try {
+ $registration = $this->validateSecretAndToken($secret, $token);
+ } catch (RegistrationException $e) {
+ return $this->validateSecretAndTokenErrorPage();
+ }
+
if ($this->config->getAppValue('registration', 'email_is_login', '0') === '1') {
$username = $registration->getEmail();
- } else {
- $username = $this->request->getParam('username');
}
- $password = $this->request->getParam('password');
try {
$user = $this->registrationService->createAccount($registration, $username, $password);
- } catch (\Exception $exception) {
- // Render form with previously sent values
- return new TemplateResponse('registration', 'form',
- [
- 'email' => $registration->getEmail(),
- 'entered_data' => ['user' => $username],
- 'errormsgs' => [$exception->getMessage()],
- 'token' => $token
- ], 'guest');
+ } catch (Exception $exception) {
+ return $this->showUserForm($secret, $token, $username, $exception->getMessage());
}
+ // Delete registration
+ $this->registrationService->deleteRegistration($registration);
+
if ($user->isEnabled()) {
- // log the user
- return $this->registrationService->loginUser($user->getUID(), $username, $password, false);
- } else {
- // warn the user their account needs admin validation
- return new TemplateResponse(
- 'registration',
- 'message',
- ['msg' => $this->l10n->t("Your account has been successfully created, but it still needs approval from an administrator.")],
- 'guest');
+ $this->registrationService->loginUser($user->getUID(), $user->getUID(), $password);
+
+ if ($this->loginFlowService->isUsingLoginFlow(2)) {
+ $response = $this->loginFlowService->tryLoginFlowV2($user);
+ if ($response instanceof Response) {
+ return $response;
+ }
+ }
+
+ if ($this->loginFlowService->isUsingLoginFlow(1)) {
+ $response = $this->loginFlowService->tryLoginFlowV1();
+ if ($response instanceof Response && $response->getStatus() === Http::STATUS_SEE_OTHER) {
+ return $response;
+ }
+ }
+
+ return new RedirectToDefaultAppResponse();
}
+
+ // warn the user their account needs admin validation
+ return new StandaloneTemplateResponse('registration', 'approval-required', [], 'guest');
}
- private function renderError($error, $hint="") {
- return new TemplateResponse('', 'error', [
- 'errors' => [[
- 'error' => $error,
- 'hint' => $hint
- ]]
+ /**
+ * @param string $secret
+ * @param string $token
+ * @return Registration
+ * @throws RegistrationException
+ */
+ protected function validateSecretAndToken(string $secret, string $token): Registration {
+ try {
+ $registration = $this->registrationService->getRegistrationForSecret($secret);
+ } catch (DoesNotExistException $e) {
+ throw new RegistrationException('Invalid secret');
+ }
+
+ if ($registration->getToken() !== $token) {
+ throw new RegistrationException('Invalid token');
+ }
+
+ return $registration;
+ }
+
+ protected function validateSecretAndTokenErrorPage(): TemplateResponse {
+ return new TemplateResponse('core', 'error', [
+ 'errors' => [
+ $this->l10n->t('The verification failed.'),
+ ],
], 'error');
}
}
diff --git a/lib/RegistrationLoginOption.php b/lib/RegistrationLoginOption.php
index d436574..ceda53e 100644
--- a/lib/RegistrationLoginOption.php
+++ b/lib/RegistrationLoginOption.php
@@ -47,7 +47,7 @@ class RegistrationLoginOption implements IAlternativeLogin {
}
public function getLink(): string {
- return $this->url->linkToRoute('registration.register.askEmail');
+ return $this->url->linkToRoute('registration.register.showEmailForm');
}
public function getClass(): string {
diff --git a/lib/Service/LoginFlowService.php b/lib/Service/LoginFlowService.php
new file mode 100644
index 0000000..9e5e7e3
--- /dev/null
+++ b/lib/Service/LoginFlowService.php
@@ -0,0 +1,107 @@
+
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+namespace OCA\Registration\Service;
+
+use OC\Core\Controller\ClientFlowLoginController;
+use OC\Core\Controller\ClientFlowLoginV2Controller;
+use OC\Core\Service\LoginFlowV2Service;
+use OCP\AppFramework\Http\Response;
+use OCP\AppFramework\Http\StandaloneTemplateResponse;
+use OCP\IRequest;
+use OCP\ISession;
+use OCP\IUser;
+
+class LoginFlowService {
+
+ /** @var IRequest */
+ protected $request;
+ /** @var ISession */
+ protected $session;
+ /** @var LoginFlowV2Service */
+ protected $loginFlowV2Service;
+
+ public function __construct(
+ IRequest $request,
+ ISession $session,
+ LoginFlowV2Service $loginFlowV2Service
+ ) {
+ $this->request = $request;
+ $this->session = $session;
+ $this->loginFlowV2Service = $loginFlowV2Service;
+ }
+
+ public function isUsingLoginFlow(?int $version = null): bool {
+ if (($version === 1 || $version === null) && $this->session->get(ClientFlowLoginController::STATE_NAME) !== null) {
+ return true;
+ }
+
+ if (($version === 2 || $version === null) && $this->session->get(ClientFlowLoginV2Controller::TOKEN_NAME) !== null) {
+ return true;
+ }
+
+ return false;
+ }
+
+ public function tryLoginFlowV1(): ?Response {
+ /** @var ClientFlowLoginController $controller */
+ $container = \OC::$server->getRegisteredAppContainer('core');
+ $controller = $container->query(ClientFlowLoginController::class);
+ return $controller->generateAppPassword(
+ $this->session->get(ClientFlowLoginController::STATE_NAME)
+ );
+ }
+
+ public function tryLoginFlowV2(IUser $user): ?StandaloneTemplateResponse {
+ $result = $this->loginFlowV2Service->flowDone(
+ $this->session->get(ClientFlowLoginV2Controller::TOKEN_NAME),
+ $this->session->getId(),
+ $this->getServerPath(),
+ $user->getUID()
+ );
+
+ if (!$result) {
+ return null;
+ }
+
+ return new StandaloneTemplateResponse(
+ 'core',
+ 'loginflowv2/done',
+ [],
+ 'guest'
+ );
+ }
+
+ private function getServerPath(): string {
+ $serverPostfix = '';
+
+ if (strpos($this->request->getRequestUri(), '/index.php') !== false) {
+ $serverPostfix = substr($this->request->getRequestUri(), 0, strpos($this->request->getRequestUri(), '/index.php'));
+ } elseif (strpos($this->request->getRequestUri(), '/login/v2') !== false) {
+ $serverPostfix = substr($this->request->getRequestUri(), 0, strpos($this->request->getRequestUri(), '/login/v2'));
+ }
+
+ $protocol = $this->request->getServerProtocol();
+ return $protocol . '://' . $this->request->getServerHost() . $serverPostfix;
+ }
+}
diff --git a/lib/Service/MailService.php b/lib/Service/MailService.php
index 5d8f581..0a8b688 100644
--- a/lib/Service/MailService.php
+++ b/lib/Service/MailService.php
@@ -81,7 +81,10 @@ class MailService {
* @throws RegistrationException
*/
public function sendTokenByMail(Registration $registration): void {
- $link = $this->urlGenerator->linkToRouteAbsolute('registration.register.verifyToken', ['token' => $registration->getToken()]);
+ $link = $this->urlGenerator->linkToRouteAbsolute('registration.register.showUserForm', [
+ 'secret' => $registration->getClientSecret(),
+ 'token' => $registration->getToken(),
+ ]);
$subject = $this->l10n->t('Verify your %s registration request', [$this->defaults->getName()]);
$template = $this->mailer->createEMailTemplate('registration_verify', [
@@ -100,6 +103,10 @@ class MailService {
$body
);
+ $template->addBodyText(
+ $this->l10n->t('Verification code: %s', $registration->getToken())
+ );
+
$template->addBodyButton(
$this->l10n->t('Continue registration'),
$link
diff --git a/lib/Service/RegistrationService.php b/lib/Service/RegistrationService.php
index e29c2ee..26bf83b 100644
--- a/lib/Service/RegistrationService.php
+++ b/lib/Service/RegistrationService.php
@@ -1,4 +1,7 @@
* @copyright Copyright (c) 2017 Pellaeon Lin
@@ -34,12 +37,11 @@ use OC\Authentication\Token\IToken;
use OCA\Registration\Db\Registration;
use OCA\Registration\Db\RegistrationMapper;
use OCP\AppFramework\Db\DoesNotExistException;
-use \OCP\AppFramework\Http\TemplateResponse;
-use \OCP\AppFramework\Http\RedirectResponse;
use OCP\ILogger;
use OCP\IRequest;
use OCP\ISession;
use OCP\IURLGenerator;
+use OCP\IUser;
use OCP\Security\ICrypto;
use OCP\Session\Exceptions\SessionNotAvailableException;
use \OCP\IUserManager;
@@ -70,7 +72,7 @@ class RegistrationService {
/** @var ISecureRandom */
private $random;
/** @var IUserSession */
- private $usersession;
+ private $userSession;
/** @var IRequest */
private $request;
/** @var ILogger */
@@ -82,9 +84,23 @@ class RegistrationService {
/** @var ICrypto */
private $crypto;
- public function __construct($appName, MailService $mailService, IL10N $l10n, IURLGenerator $urlGenerator,
- RegistrationMapper $registrationMapper, IUserManager $userManager, IConfig $config, IGroupManager $groupManager,
- ISecureRandom $random, IUserSession $us, IRequest $request, ILogger $logger, ISession $session, IProvider $tokenProvider, ICrypto $crypto) {
+ public function __construct(
+ string $appName,
+ MailService $mailService,
+ IL10N $l10n,
+ IURLGenerator $urlGenerator,
+ RegistrationMapper $registrationMapper,
+ IUserManager $userManager,
+ IConfig $config,
+ IGroupManager $groupManager,
+ ISecureRandom $random,
+ IUserSession $userSession,
+ IRequest $request,
+ ILogger $logger,
+ ISession $session,
+ IProvider $tokenProvider,
+ ICrypto $crypto
+ ) {
$this->appName = $appName;
$this->mailService = $mailService;
$this->l10n = $l10n;
@@ -94,7 +110,7 @@ class RegistrationService {
$this->config = $config;
$this->groupManager = $groupManager;
$this->random = $random;
- $this->usersession = $us;
+ $this->userSession = $userSession;
$this->request = $request;
$this->logger = $logger;
$this->session = $session;
@@ -102,21 +118,16 @@ class RegistrationService {
$this->crypto = $crypto;
}
- /**
- * @param Registration $registration
- */
- public function confirmEmail(Registration $registration) {
+ public function confirmEmail(Registration $registration): void {
$registration->setEmailConfirmed(true);
$this->registrationMapper->update($registration);
}
- /**
- * @param Registration $registration
- */
- public function generateNewToken(Registration $registration) {
+ public function generateNewToken(Registration $registration): void {
$this->registrationMapper->generateNewToken($registration);
$this->registrationMapper->update($registration);
}
+
/**
* Create registration request, used by both the API and form
* @param string $email
@@ -125,7 +136,7 @@ class RegistrationService {
* @param string $displayname
* @return Registration
*/
- public function createRegistration($email, $username="", $password="", $displayname="") {
+ public function createRegistration(string $email, string $username = '', string $password = '', string $displayname = ''): Registration {
$registration = new Registration();
$registration->setEmail($email);
$registration->setUsername($username);
@@ -135,24 +146,24 @@ class RegistrationService {
$registration->setPassword($password);
}
$this->registrationMapper->generateNewToken($registration);
- if ($password !== '' && $username !== '') {
- $this->registrationMapper->generateClientSecret($registration);
- }
+ $this->registrationMapper->generateClientSecret($registration);
$this->registrationMapper->insert($registration);
return $registration;
}
/**
* @param string $email
- * @return Registration|true if there is a pending reg with this email, return the pending reg, if there are no problems with the email, return true.
* @throws RegistrationException
*/
- public function validateEmail($email) {
+ public function validateEmail(string $email): void {
$this->mailService->validateEmail($email);
// check for pending registrations
try {
- return $this->registrationMapper->find($email);//if not found DB will throw a exception
+ $this->registrationMapper->find($email);//if not found DB will throw a exception
+ throw new RegistrationException(
+ $this->l10n->t('A user has already taken this email, maybe you already have an account?')
+ );
} catch (DoesNotExistException $e) {
}
@@ -171,15 +182,14 @@ class RegistrationService {
)
);
}
- return true;
}
/**
* @param string $displayname
* @throws RegistrationException
*/
- public function validateDisplayname($displayname) {
- if ($displayname === "") {
+ public function validateDisplayname(string $displayname): void {
+ if ($displayname === '') {
throw new RegistrationException($this->l10n->t('Please provide a valid display name.'));
}
}
@@ -188,7 +198,7 @@ class RegistrationService {
* @param string $username
* @throws RegistrationException
*/
- public function validateUsername($username) {
+ public function validateUsername(string $username): void {
if ($username === "") {
throw new RegistrationException($this->l10n->t('Please provide a valid user name.'));
}
@@ -204,15 +214,15 @@ class RegistrationService {
* @param string $email
* @return bool
*/
- public function checkAllowedDomains($email) {
- $allowed_domains = $this->config->getAppValue($this->appName, 'allowed_domains', '');
- if ($allowed_domains !== '') {
- $allowed_domains = explode(';', $allowed_domains);
+ public function checkAllowedDomains(string $email): bool {
+ $allowedDomains = $this->config->getAppValue($this->appName, 'allowed_domains', '');
+ if ($allowedDomains !== '') {
+ $allowedDomains = explode(';', $allowedDomains);
$allowed = false;
- foreach ($allowed_domains as $domain) {
- $maildomain = explode("@", $email)[1];
- // valid domain, everythings fine
- if ($maildomain === $domain) {
+ foreach ($allowedDomains as $domain) {
+ [,$mailDomain] = explode('@', $email, 2);
+ // valid domain, everything's fine
+ if ($mailDomain === $domain) {
$allowed = true;
break;
}
@@ -223,22 +233,22 @@ class RegistrationService {
}
/**
- * @return array
+ * @return string[]
*/
- public function getAllowedDomains() {
- $allowed_domains = $this->config->getAppValue($this->appName, 'allowed_domains', '');
- $allowed_domains = explode(';', $allowed_domains);
- return $allowed_domains;
+ public function getAllowedDomains(): array {
+ $allowedDomains = $this->config->getAppValue($this->appName, 'allowed_domains', '');
+ $allowedDomains = explode(';', $allowedDomains);
+ return $allowedDomains;
}
/**
* Find registration entity for token
*
* @param string $token
- * @return string
+ * @return Registration
* @throws RegistrationException
*/
- public function verifyToken($token) {
+ public function verifyToken(string $token): Registration {
try {
return $this->registrationMapper->findByToken($token);
} catch (DoesNotExistException $exception) {
@@ -248,12 +258,12 @@ class RegistrationService {
/**
* @param $registration
- * @param string $username
- * @param string $password
- * @return \OCP\IUser
+ * @param string|null $username
+ * @param string|null $password
+ * @return IUser
* @throws RegistrationException|InvalidTokenException
*/
- public function createAccount(Registration $registration, $username = null, $password = null) {
+ public function createAccount(Registration $registration, ?string $username = null, ?string $password = null): IUser {
if ($password === null && $registration->getPassword() === null) {
$generatedPassword = $this->generateRandomDeviceToken();
$registration->setPassword($this->crypto->encrypt($generatedPassword));
@@ -281,6 +291,7 @@ class RegistrationService {
throw new RegistrationException($this->l10n->t('Unable to create user, there are problems with the user backend.'));
}
$userId = $user->getUID();
+
// Set user email
try {
$user->setEMailAddress($registration->getEmail());
@@ -289,72 +300,64 @@ class RegistrationService {
}
// Add user to group
- $registered_user_group = $this->config->getAppValue($this->appName, 'registered_user_group', 'none');
- if ($registered_user_group !== 'none') {
- $group = $this->groupManager->get($registered_user_group);
+ $registeredUserGroup = $this->config->getAppValue($this->appName, 'registered_user_group', 'none');
+ if ($registeredUserGroup !== 'none') {
+ $group = $this->groupManager->get($registeredUserGroup);
if ($group === null) {
// This might happen if $registered_user_group is deleted after setting the value
// Here I choose to log error instead of stopping the user to register
- $this->logger->error("You specified newly registered users be added to '$registered_user_group' group, but it does not exist.");
+ $this->logger->error("You specified newly registered users be added to '$registeredUserGroup' group, but it does not exist.");
$groupId = '';
} else {
$group->addUser($user);
$groupId = $group->getGID();
}
} else {
- $groupId = "";
+ $groupId = '';
}
// disable user if this is requested by config
- $admin_approval_required = $this->config->getAppValue($this->appName, 'admin_approval_required', "no");
- if ($admin_approval_required === "yes") {
+ $adminApprovalRequired = $this->config->getAppValue($this->appName, 'admin_approval_required', 'no');
+ if ($adminApprovalRequired === 'yes') {
$user->setEnabled(false);
}
- // Delete pending registration if no client secret is stored
- // with client secret implies registered via API
- // without client secret implies registered via form
- // if registered via API, the registration request will be deleted in apicontroller::status
- if ($registration->getClientSecret() === null) {
- $res = $this->registrationMapper->delete($registration);
- if ($res === false) {
- throw new RegistrationException($this->l10n->t('Failed to delete pending registration request'));
- }
- }
-
$this->mailService->notifyAdmins($userId, $user->isEnabled(), $groupId);
return $user;
}
/**
- * @param $token
+ * @param string $email
* @return Registration
+ * @throws DoesNotExistException
*/
- public function getRegistrationForToken($token) {
+ public function getRegistrationForEmail(string $email): Registration {
+ return $this->registrationMapper->find($email);
+ }
+
+ /**
+ * @param string $token
+ * @return Registration
+ * @throws DoesNotExistException
+ */
+ public function getRegistrationForToken(string $token): Registration {
return $this->registrationMapper->findByToken($token);
}
/**
- * @param $secret
+ * @param string $secret
* @return Registration
+ * @throws DoesNotExistException
*/
- public function getRegistrationForSecret($secret) {
+ public function getRegistrationForSecret(string $secret): Registration {
return $this->registrationMapper->findBySecret($secret);
}
- /**
- * @param Registration $registation
- * @return null|\OCP\IUser
- */
- public function getUserAccount(Registration $registation) {
- $user = $this->userManager->get($registation->getUsername());
- return $user;
+ public function getUserAccount(Registration $registration): ?IUser {
+ return $this->userManager->get($registration->getUsername());
}
- /**
- * @param Registration $registration
- */
- public function deleteRegistration(Registration $registration) {
+ public function deleteRegistration(Registration $registration): void {
$this->registrationMapper->delete($registration);
}
@@ -365,7 +368,7 @@ class RegistrationService {
*
* @return string
*/
- private function generateRandomDeviceToken() {
+ private function generateRandomDeviceToken(): string {
$groups = [];
for ($i = 0; $i < 5; $i++) {
$groups[] = $this->random->generate(5, ISecureRandom::CHAR_HUMAN_READABLE);
@@ -378,7 +381,7 @@ class RegistrationService {
* @return string
* @throws RegistrationException
*/
- public function generateAppPassword($uid) {
+ public function generateAppPassword(string $uid): string {
$name = $this->l10n->t('Registration app auto setup');
try {
$sessionId = $this->session->getId();
@@ -404,40 +407,25 @@ class RegistrationService {
}
/**
- * @param $userId
- * @param $username
- * @param $password
- * @param $decrypt
- * @return RedirectResponse|TemplateResponse
+ * @param string $userId
+ * @param string $username
+ * @param string $password
+ * @param bool $decrypt
*/
- public function loginUser($userId, $username, $password, $decrypt = false) {
+ public function loginUser(string $userId, string $username, string $password, bool $decrypt = false): void {
if ($decrypt) {
$password = $this->crypto->decrypt($password);
}
- if (method_exists($this->usersession, 'createSessionToken')) {
- $this->usersession->login($username, $password);
- $this->usersession->createSessionToken($this->request, $userId, $username, $password);
- return new RedirectResponse($this->urlGenerator->linkTo('', 'index.php'));
- } elseif (\OC_User::login($username, $password)) {
- $this->cleanupLoginTokens($userId);
- // FIXME unsetMagicInCookie will fail from session already closed, so now we always remember
- $logintoken = $this->random->generate(32);
- $this->config->setUserValue($userId, 'login_token', $logintoken, time());
- \OC_User::setMagicInCookie($userId, $logintoken);
- \OC_Util::redirectToDefaultPage();
- }
- // Render message in case redirect failed
- return new TemplateResponse('registration', 'message',
- ['msg' => $this->l10n->t('Your account has been successfully created, you can log in now.', [$this->urlGenerator->getAbsoluteURL('/')])]
- , 'guest'
- );
+
+ $this->userSession->login($username, $password);
+ $this->userSession->createSessionToken($this->request, $userId, $username, $password);
}
/**
* Replicates OC::cleanupLoginTokens() since it's protected
* @param string $userId
*/
- public function cleanupLoginTokens($userId) {
+ public function cleanupLoginTokens(string $userId): void {
$cutoff = time() - $this->config->getSystemValue('remember_login_cookie_lifetime', 60 * 60 * 24 * 15);
$tokens = $this->config->getUserKeys($userId, 'login_token');
foreach ($tokens as $token) {
diff --git a/templates/admin.php b/templates/admin.php
index 16ff9e5..e9aeb12 100644
--- a/templates/admin.php
+++ b/templates/admin.php
@@ -26,9 +26,13 @@ foreach ($_['groups'] as $group) {
-
+ >
-
+
+
+
+ t('Enabling "admin approval" will prevent registrations from mobile and desktop clients to complete as the credentials can not be verified by the client until the user was enabled.'));?>
diff --git a/templates/approval-required.php b/templates/approval-required.php
new file mode 100644
index 0000000..fd20b3c
--- /dev/null
+++ b/templates/approval-required.php
@@ -0,0 +1,13 @@
+
+
+
t('Approval required')) ?>
+
+
+
t('Your account has been successfully created, but it still needs approval from an administrator.')) ?>