diff --git a/admin.php b/admin.php
index b085198..b8f3323 100644
--- a/admin.php
+++ b/admin.php
@@ -11,6 +11,7 @@
namespace OCA\Registration\AppInfo;
-$app = new Application();
-$controller = $app->getContainer()->query('SettingsController');
+use OCA\Registration\Controller\SettingsController;
+
+$controller = \OC::$server->query(SettingsController::class);
return $controller->displayPanel()->render();
diff --git a/appinfo/app.php b/appinfo/app.php
index a29f1c5..172e0a4 100644
--- a/appinfo/app.php
+++ b/appinfo/app.php
@@ -11,9 +11,14 @@
namespace OCA\Registration\AppInfo;
-$app = new Application();
-$c = $app->getContainer();
+\OC_App::registerLogIn([
+ 'name' => \OC::$server->getL10N('registration')->t('Register'),
+ 'href' => \OC::$server->getURLGenerator()->linkToRoute('registration.register.askEmail')
+]);
-\OC_App::registerLogIn(array('name' => $c->query('L10N')->t('Register'), 'href' => $c->query('URLGenerator')->linkToRoute('registration.register.askEmail')));
+\OCP\App::registerAdmin('registration', 'admin');
-\OCP\App::registerAdmin($c->getAppName(), 'admin');
+if(interface_exists('\OCP\Capabilities\IPublicCapability')) {
+ $app = new \OCP\AppFramework\App('registration');
+ $app->getContainer()->registerCapability(\OCA\Registration\Capabilities::class);
+}
\ No newline at end of file
diff --git a/appinfo/application.php b/appinfo/application.php
deleted file mode 100644
index 3ab1f54..0000000
--- a/appinfo/application.php
+++ /dev/null
@@ -1,100 +0,0 @@
-
- * @copyright Pellaeon Lin 2014
- */
-
-namespace OCA\Registration\AppInfo;
-
-use \OC\AppFramework\Utility\SimpleContainer;
-
-use \OCP\AppFramework\App;
-
-use \OCA\Registration\Controller\RegisterController;
-use \OCA\Registration\Controller\SettingsController;
-use \OCA\Registration\Wrapper;
-use \OCA\Registration\Db\PendingRegist;
-
-
-class Application extends App {
-
- public function __construct (array $urlParams=array()) {
- parent::__construct('registration', $urlParams);
-
- $container = $this->getContainer();
-
- /**
- * Controllers
- */
- $container->registerService('RegisterController', function(SimpleContainer $c) {
- return new RegisterController(
- $c->query('AppName'),
- $c->query('Request'),
- $c->query('Mailer'),
- $c->query('L10N'),
- $c->query('URLGenerator'),
- $c->query('PendingRegist'),
- $c->query('UserManager'),
- $c->query('Config'),
- $c->query('GroupManager'),
- $c->query('Defaults'),
- $c->query('ServerContainer')->getSecureRandom()->getMediumStrengthGenerator(),
- $c->query('ServerContainer')->getUserSession()
- );
- });
-
- $container->registerService('SettingsController', function(SimpleContainer $c) {
- return new SettingsController(
- $c->query('AppName'),
- $c->query('Request'),
- $c->query('L10N'),
- $c->query('Config'),
- $c->query('GroupManager')
- );
- });
-
-
- /**
- * Core
- */
- $container->registerService('UserManager', function(SimpleContainer $c) {
- return $c->query('ServerContainer')->getUserManager();
- });
-
- $container->registerService('GroupManager', function(SimpleContainer $c) {
- return $c->query('ServerContainer')->getGroupManager();
- });
-
- $container->registerService('Config', function(SimpleContainer $c) {
- return $c->query('ServerContainer')->getConfig();
- });
-
- $container->registerService('Mailer', function(SimpleContainer $c) {
- return $c->query('ServerContainer')->getMailer();
- });
-
- $container->registerService('L10N', function(SimpleContainer $c) {
- return $c->query('ServerContainer')->getL10N($c->query('AppName'));
- });
-
- $container->registerService('URLGenerator', function(SimpleContainer $c) {
- return $c->getServer()->getURLGenerator();
- });
-
- $container->registerService('PendingRegist', function(SimpleContainer $c) {
- return new PendingRegist($c->query('ServerContainer')->getDatabaseConnection(),
- $c->query('ServerContainer')->getSecureRandom()->getMediumStrengthGenerator());
- });
-
- $container->registerService('Defaults', function(SimpleContainer $c) {
- return new \OCP\Defaults;
- });
- }
-
-
-}
diff --git a/appinfo/database.xml b/appinfo/database.xml
index 3a8039c..ff4d751 100644
--- a/appinfo/database.xml
+++ b/appinfo/database.xml
@@ -20,11 +20,33 @@
text
true
+
+ username
+ text
+ true
+
+
+ password
+ text
+
+
+ displayname
+ text
+
+
+ email_confirmed
+ boolean
+ false
+
token
text
true
+
+ client_secret
+ text
+
requested
timestamp
diff --git a/appinfo/info.xml b/appinfo/info.xml
index 9cd83b0..365a392 100644
--- a/appinfo/info.xml
+++ b/appinfo/info.xml
@@ -6,7 +6,7 @@
User registration
agpl
Pellaeon Lin
- 0.2.5
+ 0.2.5-1
https://github.com/pellaeon/registration
https://github.com/pellaeon/registration/issues
https://github.com/pellaeon/registration
diff --git a/appinfo/routes.php b/appinfo/routes.php
index 0ad091e..7db7778 100644
--- a/appinfo/routes.php
+++ b/appinfo/routes.php
@@ -6,13 +6,21 @@
* later. See the COPYING file.
*
* @author Pellaeon Lin
+ * @author Julius Härtl
* @copyright Pellaeon Lin 2014
*/
-return ['routes' => [
- array('name' => 'settings#admin', 'url' => '/settings', 'verb' => 'POST'),
- array('name' => 'register#askEmail', 'url' => '/', 'verb' => 'GET'),
- array('name' => 'register#validateEmail', 'url' => '/', 'verb' => 'POST'),
- array('name' => 'register#verifyToken', 'url' => '/verify/{token}', 'verb' => 'GET'),
- array('name' => 'register#createAccount', 'url' => '/verify/{token}', 'verb' => 'POST')
-]];
+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']
+ ],
+ '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']
+ ]
+];
diff --git a/capabilities.php b/capabilities.php
new file mode 100644
index 0000000..a97f56e
--- /dev/null
+++ b/capabilities.php
@@ -0,0 +1,51 @@
+
+ *
+ * @author Julius Härtl
+ *
+ * @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;
+
+use OCP\Capabilities\ICapability;
+use OCP\Capabilities\IPublicCapability;
+use OCP\IURLGenerator;
+
+class Capabilities implements IPublicCapability {
+
+ /** @var IURLGenerator */
+ private $urlGenerator;
+
+ public function __construct(IURLGenerator $urlGenerator) {
+ $this->urlGenerator = $urlGenerator;
+ }
+
+ public function getCapabilities() {
+ return [
+ 'registration' =>
+ [
+ 'enabled' => true,
+ 'apiRoot' => $this->urlGenerator->linkTo(
+ '', 'ocs/v2.php/apps/registration/api/v1/'),
+ 'apiLevel' => 'v1'
+ ]
+ ];
+ }
+
+}
\ No newline at end of file
diff --git a/controller/apicontroller.php b/controller/apicontroller.php
new file mode 100644
index 0000000..a00a85b
--- /dev/null
+++ b/controller/apicontroller.php
@@ -0,0 +1,182 @@
+
+ *
+ * @author Julius Härtl
+ *
+ * @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\Controller;
+
+use OCA\Registration\Db\Registration;
+use OCA\Registration\Service\MailService;
+use OCA\Registration\Service\RegistrationException;
+use OCA\Registration\Service\RegistrationService;
+use OCP\AppFramework\Db\DoesNotExistException;
+use OCP\AppFramework\Http;
+use OCP\AppFramework\OCS\OCSBadRequestException;
+use OCP\AppFramework\OCS\OCSNotFoundException;
+use OCP\AppFramework\OCSController;
+use OCP\AppFramework\OCS\OCSException;
+use OCP\AppFramework\Http\DataResponse;
+use OCP\Defaults;
+use OCP\IL10N;
+use OCP\IRequest;
+
+class ApiController extends OCSController {
+
+ /** @var RegistrationService */
+ private $registrationService;
+ /** @var MailService */
+ private $mailService;
+ /** @var IL10N */
+ private $l10n;
+ /** @var Defaults */
+ private $defaults;
+
+ const REGISTRATION_STATUS_COMPLETE = 0;
+ const REGISTRATION_STATUS_PENDING = 1;
+ const REGISTRATION_STATUS_EXISTING = 2;
+
+ public function __construct($appName,
+ IRequest $request,
+ RegistrationService $registrationService,
+ MailService $mailService,
+ IL10N $l10n,
+ Defaults $defaults) {
+ parent::__construct($appName, $request);
+ $this->registrationService = $registrationService;
+ $this->mailService = $mailService;
+ $this->l10n = $l10n;
+ $this->defaults = $defaults;
+ }
+
+ /**
+ * @PublicPage
+ * @AnonRateThrottle(limit=5, period=1)
+ *
+ * @param string $username
+ * @param string $displayname
+ * @param string $email
+ * @throws OCSException
+ * @return DataResponse
+ */
+ public function validate($username, $displayname, $email) {
+ try {
+ $this->registrationService->validateEmail($email);
+ $this->registrationService->validateDisplayname($displayname);
+ $this->registrationService->validateUsername($username);
+ } catch (RegistrationException $e) {
+ throw new OCSBadRequestException($e->getMessage());
+ }
+ $data = [
+ 'username' => $username,
+ 'displayname' => $displayname,
+ 'email' => $email
+ ];
+ return new DataResponse($data, Http::STATUS_OK);
+ }
+
+ /**
+ * @PublicPage
+ * @AnonRateThrottle(limit=10, period=1)
+ *
+ * @param string $clientSecret
+ * @throws OCSException
+ * @return DataResponse
+ */
+ public function status($clientSecret) {
+ try {
+ /** @var Registration $registration */
+ $registration = $this->registrationService->getRegistrationForSecret($clientSecret);
+ } catch (DoesNotExistException $e) {
+ throw new OCSNotFoundException('No pending registration.');
+ }
+
+ if (!$registration->getEmailConfirmed()) {
+ return new DataResponse(
+ [
+ 'registrationStatus' => self::REGISTRATION_STATUS_PENDING,
+ 'message' => $this->l10n->t('Your registration is pending. Please confirm your email address.')
+ ],
+ Http::STATUS_OK
+ );
+ } else {
+ // create account if email confirmed and not already created
+ $user = $this->registrationService->getUserAccount($registration);
+ if ($user === null) {
+ $user = $this->registrationService->createAccount($registration);
+ }
+ $this->registrationService->loginUser($user->getUID(), $registration->getUsername(), $registration->getPassword(), true);
+ $appPassword = $this->registrationService->generateAppPassword($user->getUID());
+ $data = [
+ 'appPassword' => $appPassword,
+ 'cloudUrl' => $this->defaults->getBaseUrl(),
+ 'registrationStatus' => self::REGISTRATION_STATUS_COMPLETE
+ ];
+ $this->registrationService->deleteRegistration($registration);
+ return new DataResponse($data, Http::STATUS_OK);
+ }
+ }
+
+ /**
+ * @PublicPage
+ * @AnonRateThrottle(limit=5, period=1)
+ *
+ * @param string $username
+ * @param string $displayname
+ * @param string $email
+ * @param string $password
+ * @throws OCSException
+ * @return DataResponse
+ */
+ public function register($username, $displayname, $email, $password) {
+ $data = [];
+ try {
+ $secret = null;
+ $registration = $this->registrationService->validateEmail($email);
+ if($registration === null) {
+ $this->registrationService->validateDisplayname($displayname);
+ $this->registrationService->validateUsername($username);
+ $registration = $this->registrationService->createRegistration($email, $username, $password, $displayname);
+ $this->mailService->sendTokenByMail($registration);
+ $secret = $registration->getClientSecret();
+ } else {
+ $this->registrationService->generateNewToken($registration);
+ $this->mailService->sendTokenByMail($registration);
+ return new DataResponse(
+ [
+ 'registrationStatus' => self::REGISTRATION_STATUS_EXISTING,
+ 'message' => $this->l10n->t('There is already a pending registration with this email, a new verification email has been sent to the address.')
+ ],
+ Http::STATUS_OK
+ );
+ }
+
+ $data['message'] = $this->l10n->t('Your registration is pending. Please confirm your email address.');
+ $data['registrationStatus'] = self::REGISTRATION_STATUS_PENDING;
+ if($secret !== null) {
+ $data['secret'] = $secret;
+ }
+ return new DataResponse($data, Http::STATUS_OK);
+ } catch (RegistrationException $exception) {
+ throw new OCSException($exception->getMessage(), $exception->getCode());
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/controller/registercontroller.php b/controller/registercontroller.php
index 464e8c6..e69e1c1 100644
--- a/controller/registercontroller.php
+++ b/controller/registercontroller.php
@@ -6,64 +6,57 @@
* later. See the COPYING file.
*
* @author Pellaeon Lin
+ * @author Julius Härtl
* @copyright Pellaeon Lin 2014
*/
namespace OCA\Registration\Controller;
-
+use OCA\Registration\Db\Registration;
+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\Defaults;
-use \OCP\Util;
-use \OCA\Registration\Wrapper;
-use \OCP\IUserManager;
-use \OCP\IUserSession;
-use \OCP\IGroupManager;
+use OCP\IURLGenerator;
use \OCP\IL10N;
-use \OCP\IConfig;
-use \OCP\Mail\IMailer;
-use \OCP\Security\ISecureRandom;
-use \OC_User;
-use \OC_Util;
class RegisterController extends Controller {
- private $mailer;
+ /** @var IL10N */
private $l10n;
+ /** @var IURLGenerator */
private $urlgenerator;
- private $pendingreg;
- private $usermanager;
- private $config;
- private $groupmanager;
- /** @var \OCP\Defaults */
- private $defaults;
- private $random;
- private $usersession;
- protected $appName;
+ /** @var RegistrationService */
+ private $registrationService;
+ /** @var MailService */
+ private $mailService;
- public function __construct($appName, IRequest $request, IMailer $mailer, IL10N $l10n, $urlgenerator,
- $pendingreg, IUserManager $usermanager, IConfig $config, IGroupManager $groupmanager, Defaults $defaults,
- ISecureRandom $random, IUserSession $us){
- $this->mailer = $mailer;
+
+ public function __construct(
+ $appName,
+ IRequest $request,
+ IL10N $l10n,
+ IURLGenerator $urlgenerator,
+ RegistrationService $registrationService,
+ MailService $mailService
+ ){
+ parent::__construct($appName, $request);
$this->l10n = $l10n;
$this->urlgenerator = $urlgenerator;
- $this->pendingreg = $pendingreg;
- $this->usermanager = $usermanager;
- $this->config = $config;
- $this->groupmanager = $groupmanager;
- $this->defaults = $defaults;
- $this->appName = $appName;
- $this->random = $random;
- $this->usersession = $us;
- parent::__construct($appName, $request);
+ $this->registrationService = $registrationService;
+ $this->mailService = $mailService;
}
/**
* @NoCSRFRequired
* @PublicPage
+ *
+ * @param $errormsg
+ * @param $entered
+ * @return TemplateResponse
*/
public function askEmail($errormsg, $entered) {
$params = array(
@@ -75,83 +68,26 @@ class RegisterController extends Controller {
/**
* @PublicPage
+ *
+ * @return TemplateResponse
*/
public function validateEmail() {
$email = $this->request->getParam('email');
- if ( !$this->mailer->validateMailAddress($email) ) {
- return new TemplateResponse('', 'error', array(
- 'errors' => array(array(
- 'error' => $this->l10n->t('The email address you entered is not valid'),
- 'hint' => ''
- ))
- ), 'error');
+
+ if (!$this->registrationService->checkAllowedDomains($email)) {
+ return new TemplateResponse('registration', 'domains', [
+ 'domains' => $this->registrationService->getAllowedDomains()
+ ], 'guest');
}
-
- if ( $this->pendingreg->find($email) ) {
- $this->pendingreg->delete($email);
- $token = $this->pendingreg->save($email);
-
- try {
- $this->sendValidationEmail($token, $email);
- } catch (\Exception $e) {
- return new TemplateResponse('', 'error', array(
- 'errors' => array(array(
- 'error' => $this->l10n->t('A problem occurred sending email, please contact your administrator.'),
- 'hint' => ''
- ))
- ), 'error');
- }
- return new TemplateResponse('', 'error', array(
- 'errors' => array(array(
- 'error' => $this->l10n->t('There is already a pending registration with this email, a new verification email has been sent to the address.'),
- 'hint' => ''
- ))
- ), 'error');
- }
-
- if ( $this->config->getUsersForUserValue('settings', 'email', $email) ) {
- return new TemplateResponse('', 'error', array(
- 'errors' => array(array(
- 'error' => $this->l10n->t('A user has already taken this email, maybe you already have an account?'),
- 'hint' => str_replace(
- '{login}', $this->urlgenerator->getAbsoluteURL('/'),
- $this->l10n->t('You can log in now.'))
- ))
- ), 'error');
- }
-
-
- // allow only from specific email domain
- $allowed_domains = $this->config->getAppValue($this->appName, 'allowed_domains', '');
- if ( $allowed_domains !== '' ) {
- $allowed_domains = explode(';', $allowed_domains);
- $allowed = false;
- foreach ( $allowed_domains as $domain ) {
- $maildomain=explode("@",$email)[1];
- // valid domain, everythings fine
- if ($maildomain === $domain) {
- $allowed=true;
- break;
- }
- }
- if ( $allowed === false ) {
- return new TemplateResponse('registration', 'domains', ['domains' =>
- $allowed_domains
- ], 'guest');
- }
- }
-
- $token = $this->pendingreg->save($email);
try {
- $this->sendValidationEmail($token, $email);
- } catch (\Exception $e) {
- return new TemplateResponse('', 'error', array(
- 'errors' => array(array(
- 'error' => $this->l10n->t('A problem occurred sending email, please contact your administrator.'),
- 'hint' => ''
- ))
- ), 'error');
+ $this->registrationService->validateEmail($email);
+ $registration = $this->registrationService->createRegistration($email);
+ $this->mailService->sendTokenByMail($registration);
+ } catch (RegistrationException $e) {
+ return $this->renderError($e->getMessage(), $e->getHint());
}
+
+
return new TemplateResponse('registration', 'message', array('msg' =>
$this->l10n->t('Verification email successfully sent.')
), 'guest');
@@ -160,207 +96,72 @@ class RegisterController extends Controller {
/**
* @NoCSRFRequired
* @PublicPage
+ *
+ * @param $token
+ * @return TemplateResponse
*/
public function verifyToken($token) {
- $email = $this->pendingreg->findEmailByToken($token);
- if ( $email === false ) {
- return new TemplateResponse('', 'error', array(
- 'errors' => array(array(
- 'error' => $this->l10n->t('Invalid verification URL. No registration request with this verification URL is found.'),
- 'hint' => ''
- ))
- ), 'error');
- } elseif ( $email ) {
- return new TemplateResponse('registration', 'form', array('email' => $email, 'token' => $token), 'guest');
+ try {
+ /** @var Registration $registration */
+ $registration = $this->registrationService->verifyToken($token);
+ $this->registrationService->confirmEmail($registration);
+
+ // 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', ['email' => $registration->getEmail(), 'token' => $registration->getToken()], 'guest');
+ } catch (RegistrationException $exception) {
+ return $this->renderError($exception->getMessage(), $exception->getHint());
}
+
}
/**
* @PublicPage
* @UseSession
+ *
+ * @param $token
+ * @return RedirectResponse|TemplateResponse
*/
public function createAccount($token) {
- $email = $this->pendingreg->findEmailByToken($token);
- if ( $email === false ) {
- return new TemplateResponse('', 'error', array(
- 'errors' => array(array(
- 'error' => $this->l10n->t('Invalid verification URL. No registration request with this verification URL is found.'),
- 'hint' => ''
- ))
- ), 'error');
- } elseif ( $email ) {
- $username = $this->request->getParam('username');
- $password = $this->request->getParam('password');
- try {
- $user = $this->usermanager->createUser($username, $password);
- } catch (\Exception $e) {
- return new TemplateResponse('registration', 'form',
- array('email' => $email,
- 'entered_data' => array('username' => $username),
- 'errormsgs' => array($e->getMessage()),
- 'token' => $token), 'guest');
- }
- if ( $user === false ) {
- return new TemplateResponse('', 'error', array(
- 'errors' => array(array(
- 'error' => $this->l10n->t('Unable to create user, there are problems with the user backend.'),
- 'hint' => ''
- ))
- ), 'error');
- } else {
- $userId = $user->getUID();
- // Set user email
- try {
- $this->config->setUserValue($userId, 'settings', 'email', $email);
- } catch (\Exception $e) {
- return new TemplateResponse('', 'error', array(
- 'errors' => array(array(
- 'error' => $this->l10n->t('Unable to set user email: '.$e->getMessage()),
- 'hint' => ''
- ))
- ), 'error');
- }
+ $username = $this->request->getParam('username');
+ $password = $this->request->getParam('password');
+ $registration = $this->registrationService->getRegistrationForToken($token);
- // Add user to group
- $registered_user_group = $this->config->getAppValue($this->appName, 'registered_user_group', 'none');
- if ( $registered_user_group !== 'none' ) {
- try {
- $group = $this->groupmanager->get($registered_user_group);
- $group->addUser($user);
- } catch (\Exception $e) {
- return new TemplateResponse('', 'error', array(
- 'errors' => array(array(
- 'error' => $e->message,
- ))
- ), 'error');
- }
- }
-
- // Delete pending reg request
- $res = $this->pendingreg->delete($email);
- if ( $res === false ) {
- return new TemplateResponse('', 'error', array(
- 'errors' => array(array(
- 'error' => $this->l10n->t('Failed to delete pending registration request'),
- 'hint' => ''
- ))
- ), 'error');
- }
-
- // Notify admin
- $admin_users = $this->groupmanager->get('admin')->getUsers();
- $to_arr = array();
- foreach ( $admin_users as $au ) {
- $au_email = $this->config->getUserValue($au->getUID(), 'settings', 'email');
- if ( $au_email !== '' ) {
- $to_arr[$au_email] = $au->getDisplayName();
- }
- }
- try {
- $this->sendNewUserNotifEmail($to_arr, $userId);
- } catch (\Exception $e) {
- \OCP\Util::writeLog('registration', 'Sending admin notification email failed: '. $e->getMessage, \OCP\Util::ERROR);
- }
-
- // Try to log user in
- if ( method_exists($this->usersession, 'createSessionToken') ) {
- $this->usersession->login($username, $password);
- $this->usersession->createSessionToken($this->request, $userId, $username, $password);
- return new RedirectResponse($this->urlgenerator->linkToRoute('files.view.index'));
- } 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', array('msg' =>
- str_replace('{link}',
- $this->urlgenerator->getAbsoluteURL('/'),
- $this->l10n->t('Your account has been successfully created, you can log in now.')
- )), 'guest');
- }
- }
+ try {
+ $this->registrationService->createAccount($registration, $username, $password);
+ } catch (RegistrationException $exception) {
+ return $this->renderError($exception->getMessage(), $exception->getHint());
+ } catch (\InvalidArgumentException $exception) {
+ // Render form with previously sent values
+ return new TemplateResponse('registration', 'form',
+ [
+ 'email' => $registration->getEmail(),
+ 'entered_data' => array('user' => $username),
+ 'errormsgs' => array($exception->getMessage()),
+ 'token' => $token
+ ], 'guest');
}
+
+ return new TemplateResponse('registration', 'message',
+ ['msg' => $this->l10n->t('Your account has been successfully created, you can log in now.', [$this->urlgenerator->getAbsoluteURL('/')])],
+ 'guest'
+ );
}
- /**
- * Sends validation email
- * @param string $token
- * @param string $to
- * @return null
- * @throws \Exception
- */
- private function sendValidationEmail($token, $to) {
- $link = $this->urlgenerator->linkToRoute('registration.register.verifyToken', array('token' => $token));
- $link = $this->urlgenerator->getAbsoluteURL($link);
- $template_var = [
- 'link' => $link,
- 'sitename' => $this->defaults->getName()
- ];
- $html_template = new TemplateResponse('registration', 'email.validate_html', $template_var, 'blank');
- $html_part = $html_template->render();
- $plaintext_template = new TemplateResponse('registration', 'email.validate_plaintext', $template_var, 'blank');
- $plaintext_part = $plaintext_template->render();
- $subject = $this->l10n->t('Verify your %s registration request', [$this->defaults->getName()]);
-
- $from = Util::getDefaultEmailAddress('register');
- $message = $this->mailer->createMessage();
- $message->setFrom([$from => $this->defaults->getName()]);
- $message->setTo([$to]);
- $message->setSubject($subject);
- $message->setPlainBody($plaintext_part);
- $message->setHtmlBody($html_part);
- $failed_recipients = $this->mailer->send($message);
- if ( !empty($failed_recipients) )
- throw new \Exception('Failed recipients: '.print_r($failed_recipients, true));
+ private function renderError($error, $hint="") {
+ return new TemplateResponse('', 'error', array(
+ 'errors' => array(array(
+ 'error' => $error,
+ 'hint' => $hint
+ ))
+ ), 'error');
}
- /**
- * Sends new user notification email to admin
- * @param array $to
- * @param string $username the new user
- * @return null
- * @throws \Exception
- */
- private function sendNewUserNotifEmail(array $to, $username) {
- $template_var = [
- 'user' => $username,
- 'sitename' => $this->defaults->getName()
- ];
- $html_template = new TemplateResponse('registration', 'email.newuser_html', $template_var, 'blank');
- $html_part = $html_template->render();
- $plaintext_template = new TemplateResponse('registration', 'email.newuser_plaintext', $template_var, 'blank');
- $plaintext_part = $plaintext_template->render();
- $subject = $this->l10n->t('A new user "%s" has created an account on %s', [$username, $this->defaults->getName()]);
-
- $from = Util::getDefaultEmailAddress('register');
- $message = $this->mailer->createMessage();
- $message->setFrom([$from => $this->defaults->getName()]);
- $message->setTo($to);
- $message->setSubject($subject);
- $message->setPlainBody($plaintext_part);
- $message->setHtmlBody($html_part);
- $failed_recipients = $this->mailer->send($message);
- if ( !empty($failed_recipients) )
- throw new \Exception('Failed recipients: '.print_r($failed_recipients, true));
- }
-
- /**
- * Replicates OC::cleanupLoginTokens() since it's protected
- * @param string $userId
- * @return null
- */
- private function cleanupLoginTokens($userId) {
- $cutoff = time() - $this->config->getSystemValue('remember_login_cookie_lifetime', 60 * 60 * 24 * 15);
- $tokens = $this->config->getUserKeys($userId, 'login_token');
- foreach ($tokens as $token) {
- $time = $this->config->getUserValue($userId, 'login_token', $token);
- if ($time < $cutoff) {
- $this->config->deleteUserValue($userId, 'login_token', $token);
- }
- }
- }
}
diff --git a/controller/settingscontroller.php b/controller/settingscontroller.php
index c8b62b1..f01eadc 100644
--- a/controller/settingscontroller.php
+++ b/controller/settingscontroller.php
@@ -6,6 +6,7 @@
* later. See the COPYING file.
*
* @author Pellaeon Lin
+ * @author Julius Härtl
* @copyright Pellaeon Lin 2015
*/
@@ -19,21 +20,24 @@ use \OCP\AppFramework\Controller;
use \OCP\IGroupManager;
use \OCP\IL10N;
use \OCP\IConfig;
-use \OCP\IUser;
class SettingsController extends Controller {
+ /** @var IL10N */
private $l10n;
+ /** @var IConfig */
private $config;
+ /** @var IGroupManager */
private $groupmanager;
+ /** @var string */
protected $appName;
public function __construct($appName, IRequest $request, IL10N $l10n, IConfig $config, IGroupManager $groupmanager){
+ parent::__construct($appName, $request);
$this->l10n = $l10n;
$this->config = $config;
$this->groupmanager = $groupmanager;
$this->appName = $appName;
- parent::__construct($appName, $request);
}
@@ -89,6 +93,7 @@ class SettingsController extends Controller {
*/
public function displayPanel() {
$groups = $this->groupmanager->search('');
+ $group_id_list = [];
foreach ( $groups as $group ) {
$group_id_list[] = $group->getGid();
}
diff --git a/db/pendingregist.php b/db/pendingregist.php
deleted file mode 100644
index 1cdb7ee..0000000
--- a/db/pendingregist.php
+++ /dev/null
@@ -1,49 +0,0 @@
-db = $db;
- $this->random = $random;
- }
-
- public function save($email) {
- $query = $this->db->prepare( 'INSERT INTO `*PREFIX*registration`'
- .' ( `email`, `token`, `requested` ) VALUES( ?, ?, NOW() )' );
-
- $token = $this->random->generate(6, ISecureRandom::CHAR_UPPER.ISecureRandom::CHAR_DIGITS);
-
- $query->execute(array( $email, $token ));
- return $token;
- }
- public function find($email) {
- $query = $this->db->prepare('SELECT `email` FROM `*PREFIX*registration` WHERE `email` = ? ');
- $query->execute(array($email));
- return $query->fetchAll();
- }
-
- public function delete($email) {
- $query = $this->db->prepare('DELETE FROM `*PREFIX*registration` WHERE `email` = ? ');
- return $query->execute(array($email));
- }
-
- /**
- * @return string|false
- */
- public function findEmailByToken($token) {
- $query = $this->db->prepare('SELECT `email` FROM `*PREFIX*registration` WHERE `token` = ? ');
- $query->execute(array($token));
- return $query->fetch()['email'];
- }
-
-}
diff --git a/db/registration.php b/db/registration.php
new file mode 100644
index 0000000..9d8473f
--- /dev/null
+++ b/db/registration.php
@@ -0,0 +1,44 @@
+
+ *
+ * @author Julius Härtl
+ *
+ * @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\Db;
+
+use OCP\AppFramework\Db\Entity;
+
+class Registration extends Entity {
+
+ public $id;
+ protected $email;
+ protected $username;
+ protected $displayname;
+ protected $password;
+ protected $token;
+ protected $requested;
+ protected $emailConfirmed;
+ protected $clientSecret;
+
+ public function __construct() {
+ $this->addType('emailConfirmed', 'boolean');
+ }
+
+}
\ No newline at end of file
diff --git a/db/registrationmapper.php b/db/registrationmapper.php
new file mode 100644
index 0000000..0559af9
--- /dev/null
+++ b/db/registrationmapper.php
@@ -0,0 +1,100 @@
+
+ *
+ * @author Julius Härtl
+ *
+ * @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\Db;
+
+use OCP\AppFramework\Db\DoesNotExistException;
+use OCP\AppFramework\Db\Entity;
+use OCP\AppFramework\Db\Mapper;
+use OCP\IDBConnection;
+use OCP\Security\ISecureRandom;
+
+class RegistrationMapper extends Mapper {
+
+ /** @var \OCP\Security\ISecureRandom */
+ protected $random;
+
+ public function __construct(IDBConnection $db, ISecureRandom $random) {
+ parent::__construct($db, 'registration', Registration::class);
+ $this->random = $random;
+ }
+
+ /**
+ * @param $token
+ * @return Registration|Entity
+ */
+ public function findByToken($token) {
+ return $this->findEntity('SELECT * FROM `*PREFIX*registration` WHERE `token` = ? ', [$token]);
+ }
+
+ public function findBySecret($secret) {
+ return $this->findEntity('SELECT * FROM `*PREFIX*registration` WHERE `client_secret` = ? ', [$secret]);
+ }
+
+ public function usernameIsPending($username) {
+ try {
+ $entity = $this->findEntity(
+ 'SELECT id FROM `*PREFIX*registration` WHERE `username` = ? ',
+ [$username]
+ );
+ } catch (DoesNotExistException $e) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * @param $email
+ * @return Registration|Entity
+ */
+ public function find($email) {
+ $sql = 'SELECT * FROM `*PREFIX*registration` WHERE `email` = ? ';
+ return $this->findEntity($sql, [$email]);
+ }
+
+ /**
+ * @param Entity $entity
+ * @return Entity
+ */
+ public function insert(Entity $entity) {
+ $entity->setRequested(date('Y-m-d H:i:s'));
+ return parent::insert($entity);
+ }
+
+ /**
+ * @param Registration $registration
+ */
+ public function generateNewToken(Registration &$registration) {
+ $token = $this->random->generate(6, ISecureRandom::CHAR_UPPER.ISecureRandom::CHAR_DIGITS);
+ $registration->setToken($token);
+ }
+
+ /**
+ * @param Registration $registration
+ */
+ public function generateClientSecret(Registration &$registration) {
+ $token = $this->random->generate(32, ISecureRandom::CHAR_HUMAN_READABLE);
+ $registration->setClientSecret($token);
+ }
+
+}
\ No newline at end of file
diff --git a/phpunit.xml b/phpunit.xml
index 7e5a983..aff4ae0 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -1 +1,12 @@
-
\ No newline at end of file
+
+
+
+ ./tests/unit
+
+
+
+
+ ./
+
+
+
diff --git a/service/mailservice.php b/service/mailservice.php
new file mode 100644
index 0000000..bed408c
--- /dev/null
+++ b/service/mailservice.php
@@ -0,0 +1,156 @@
+
+ * @copyright Copyright (c) 2017 Pellaeon Lin
+ *
+ * @author Julius Härtl
+ * @author Pellaeon Lin
+ *
+ * @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 OCA\Registration\Db\Registration;
+use OCP\AppFramework\Http\TemplateResponse;
+use OCP\Defaults;
+use OCP\IConfig;
+use OCP\IGroupManager;
+use OCP\IL10N;
+use OCP\ILogger;
+use OCP\IURLGenerator;
+use OCP\Mail\IMailer;
+use OCP\Util;
+
+class MailService {
+
+ /** @var IURLGenerator */
+ private $urlGenerator;
+ /** @var IMailer */
+ private $mailer;
+ /** @var Defaults */
+ private $defaults;
+ /** @var IL10N */
+ private $l10n;
+ /** @var IConfig */
+ private $config;
+ /** @var IGroupManager */
+ private $groupManager;
+ /** @var ILogger */
+ private $logger;
+
+ public function __construct(IURLGenerator $urlGenerator, IMailer $mailer, Defaults $defaults, IL10N $l10n, IConfig $config, IGroupManager $groupManager, ILogger $logger) {
+ $this->urlGenerator = $urlGenerator;
+ $this->mailer = $mailer;
+ $this->defaults = $defaults;
+ $this->l10n = $l10n;
+ $this->config = $config;
+ $this->groupManager = $groupManager;
+ $this->logger = $logger;
+ }
+
+ /**
+ * @param string $email
+ * @throws RegistrationException
+ */
+ public function validateEmail($email) {
+ if ( !$this->mailer->validateMailAddress($email) ) {
+ throw new RegistrationException($this->l10n->t('The email address you entered is not valid'));
+ }
+ }
+
+ /**
+ * @param Registration $registration
+ * @return bool
+ * @throws RegistrationException
+ */
+ public function sendTokenByMail(Registration $registration) {
+ $link = $this->urlGenerator->linkToRoute('registration.register.verifyToken', array('token' => $registration->getToken()));
+ $link = $this->urlGenerator->getAbsoluteURL($link);
+ $template_var = [
+ 'link' => $link,
+ 'sitename' => $this->defaults->getName()
+ ];
+ $html_template = new TemplateResponse('registration', 'email.validate_html', $template_var, 'blank');
+ $html_part = $html_template->render();
+ $plaintext_template = new TemplateResponse('registration', 'email.validate_plaintext', $template_var, 'blank');
+ $plaintext_part = $plaintext_template->render();
+ $subject = $this->l10n->t('Verify your %s registration request', [$this->defaults->getName()]);
+
+ $from = Util::getDefaultEmailAddress('register');
+ $message = $this->mailer->createMessage();
+ $message->setFrom([$from => $this->defaults->getName()]);
+ $message->setTo([$registration->getEmail()]);
+ $message->setSubject($subject);
+ $message->setPlainBody($plaintext_part);
+ $message->setHtmlBody($html_part);
+ $failed_recipients = $this->mailer->send($message);
+ if ( !empty($failed_recipients) ) {
+ throw new RegistrationException($this->l10n->t('A problem occurred sending email, please contact your administrator.'));
+ }
+ }
+
+ /**
+ * @param string $userId
+ */
+ public function notifyAdmins($userId) {
+ // Notify admin
+ $admin_users = $this->groupManager->get('admin')->getUsers();
+ $to_arr = array();
+ foreach ( $admin_users as $au ) {
+ $au_email = $this->config->getUserValue($au->getUID(), 'settings', 'email');
+ if ( $au_email !== '' ) {
+ $to_arr[$au_email] = $au->getDisplayName();
+ }
+ }
+ try {
+ $this->sendNewUserNotifEmail($to_arr, $userId);
+ } catch (\Exception $e) {
+ $this->logger->error('Sending admin notification email failed: '. $e->getMessage());
+ }
+ }
+
+ /**
+ * Sends new user notification email to admin
+ * @param array $to
+ * @param string $username the new user
+ * @throws \Exception
+ */
+ private function sendNewUserNotifEmail(array $to, $username) {
+ $template_var = [
+ 'user' => $username,
+ 'sitename' => $this->defaults->getName()
+ ];
+ $html_template = new TemplateResponse('registration', 'email.newuser_html', $template_var, 'blank');
+ $html_part = $html_template->render();
+ $plaintext_template = new TemplateResponse('registration', 'email.newuser_plaintext', $template_var, 'blank');
+ $plaintext_part = $plaintext_template->render();
+ $subject = $this->l10n->t('A new user "%s" has created an account on %s', [$username, $this->defaults->getName()]);
+
+ $from = Util::getDefaultEmailAddress('register');
+ $message = $this->mailer->createMessage();
+ $message->setFrom([$from => $this->defaults->getName()]);
+ $message->setTo($to);
+ $message->setSubject($subject);
+ $message->setPlainBody($plaintext_part);
+ $message->setHtmlBody($html_part);
+ $failed_recipients = $this->mailer->send($message);
+ if ( !empty($failed_recipients) )
+ throw new RegistrationException('Failed recipients: '.print_r($failed_recipients, true));
+ }
+
+}
\ No newline at end of file
diff --git a/service/registrationexception.php b/service/registrationexception.php
new file mode 100644
index 0000000..b3070d1
--- /dev/null
+++ b/service/registrationexception.php
@@ -0,0 +1,49 @@
+
+ *
+ * @author Julius Härtl
+ *
+ * @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;
+
+class RegistrationException extends \Exception {
+
+ protected $hint;
+
+ /**
+ * RegistrationException constructor.
+ *
+ * @param string $message
+ * @param string $hint
+ * @param int $code
+ */
+ public function __construct($message, $hint = "", $code = 400) {
+ parent::__construct($message, $code);
+ $this->hint = $hint;
+ }
+
+ /**
+ * @return string
+ */
+ public function getHint() {
+ return $this->hint;
+ }
+
+}
\ No newline at end of file
diff --git a/service/registrationservice.php b/service/registrationservice.php
new file mode 100644
index 0000000..f9337c7
--- /dev/null
+++ b/service/registrationservice.php
@@ -0,0 +1,431 @@
+
+ * @copyright Copyright (c) 2017 Pellaeon Lin
+ * @copyright Copyright (c) 2017 Lukas Reschke
+ *
+ * @author Julius Härtl
+ * @author Pellaeon Lin
+ * @author Lukas Reschke
+ *
+ * @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\Authentication\Exceptions\InvalidTokenException;
+use OC\Authentication\Exceptions\PasswordlessTokenException;
+use OC\Authentication\Token\IProvider;
+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\Defaults;
+use OCP\ILogger;
+use OCP\IRequest;
+use OCP\ISession;
+use OCP\IURLGenerator;
+use OCP\Security\ICrypto;
+use OCP\Session\Exceptions\SessionNotAvailableException;
+use \OCP\IUserManager;
+use \OCP\IUserSession;
+use \OCP\IGroupManager;
+use \OCP\IL10N;
+use \OCP\IConfig;
+use \OCP\Security\ISecureRandom;
+use \OC_User;
+use \OC_Util;
+
+class RegistrationService {
+
+ /** @var string */
+ private $appName;
+ /** @var MailService */
+ private $mailService;
+ /** @var IL10N */
+ private $l10n;
+ /** @var IURLGenerator */
+ private $urlGenerator;
+ /** @var RegistrationMapper */
+ private $registrationMapper;
+ /** @var IUserManager */
+ private $userManager;
+ /** @var IConfig */
+ private $config;
+ /** @var IGroupManager */
+ private $groupManager;
+ /** @var \OCP\Defaults */
+ private $defaults;
+ /** @var ISecureRandom */
+ private $random;
+ /** @var IUserSession */
+ private $usersession;
+ /** @var IRequest */
+ private $request;
+ /** @var ILogger */
+ private $logger;
+ /** @var ISession */
+ private $session;
+ /** @var IProvider */
+ private $tokenProvider;
+ /** @var ICrypto */
+ private $crypto;
+
+ public function __construct($appName, MailService $mailService, IL10N $l10n, IURLGenerator $urlGenerator,
+ RegistrationMapper $registrationMapper, IUserManager $userManager, IConfig $config, IGroupManager $groupManager, Defaults $defaults,
+ ISecureRandom $random, IUserSession $us, IRequest $request, ILogger $logger, ISession $session, IProvider $tokenProvider, ICrypto $crypto){
+ $this->appName = $appName;
+ $this->mailService = $mailService;
+ $this->l10n = $l10n;
+ $this->urlGenerator = $urlGenerator;
+ $this->registrationMapper = $registrationMapper;
+ $this->userManager = $userManager;
+ $this->config = $config;
+ $this->groupManager = $groupManager;
+ $this->defaults = $defaults;
+ $this->random = $random;
+ $this->usersession = $us;
+ $this->request = $request;
+ $this->logger = $logger;
+ $this->session = $session;
+ $this->tokenProvider = $tokenProvider;
+ $this->crypto = $crypto;
+ }
+
+ /**
+ * @param Registration $registration
+ */
+ public function confirmEmail(Registration &$registration) {
+ $registration->setEmailConfirmed(true);
+ $this->registrationMapper->update($registration);
+ }
+
+ /**
+ * @param Registration $registration
+ */
+ public function generateNewToken(Registration &$registration) {
+ $this->registrationMapper->generateNewToken($registration);
+ $this->registrationMapper->update($registration);
+ }
+ /**
+ * @param string $email
+ * @param string $username
+ * @param string $password
+ * @param string $displayname
+ * @return Registration
+ */
+ public function createRegistration($email, $username="", $password="", $displayname="") {
+ $registration = new Registration();
+ $registration->setEmail($email);
+ $registration->setUsername($username);
+ $registration->setDisplayname();
+ if($password !== "") {
+ $password = $this->crypto->encrypt($password);
+ $registration->setPassword($password);
+ }
+ $this->registrationMapper->generateNewToken($registration);
+ $this->registrationMapper->generateClientSecret($registration);
+ $this->registrationMapper->insert($registration);
+ return $registration;
+ }
+
+ /**
+ * @param string $email
+ * @return Registration
+ * @throws RegistrationException
+ */
+ public function validateEmail($email) {
+
+ $this->mailService->validateEmail($email);
+
+ // check for pending registrations
+ try {
+ return $this->registrationMapper->find($email);
+ } catch (\Exception $e) {}
+
+ if ( $this->config->getUsersForUserValue('settings', 'email', $email) ) {
+ throw new RegistrationException(
+ $this->l10n->t('A user has already taken this email, maybe you already have an account?'),
+ $this->l10n->t('You can log in now.', [$this->urlGenerator->getAbsoluteURL('/')])
+ );
+ }
+
+ if (!$this->checkAllowedDomains($email)) {
+ throw new RegistrationException(
+ $this->l10n->t(
+ 'Registration is only allowed for the following domains: ' .
+ $this->config->getAppValue($this->appName, 'allowed_domains', '')
+ )
+ );
+ }
+ return null;
+ }
+
+ /**
+ * @param string $displayname
+ * @throws RegistrationException
+ */
+ public function validateDisplayname($displayname) {
+ if($displayname === "") {
+ throw new RegistrationException($this->l10n->t('Please provide a valid display name.'));
+ }
+ }
+
+ /**
+ * @param string $username
+ * @throws RegistrationException
+ */
+ public function validateUsername($username) {
+ if($username === "") {
+ throw new RegistrationException($this->l10n->t('Please provide a valid user name.'));
+ }
+
+ if($this->registrationMapper->usernameIsPending($username) || $this->userManager->get($username) !== null) {
+ throw new RegistrationException($this->l10n->t('The username you have chosen already exists.'));
+ }
+ }
+
+ /**
+ * check if email domain is allowed
+ *
+ * @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);
+ $allowed = false;
+ foreach ($allowed_domains as $domain) {
+ $maildomain = explode("@", $email)[1];
+ // valid domain, everythings fine
+ if ($maildomain === $domain) {
+ $allowed = true;
+ break;
+ }
+ }
+ return $allowed;
+ }
+ return true;
+ }
+
+ /**
+ * @return array
+ */
+ public function getAllowedDomains() {
+ $allowed_domains = $this->config->getAppValue($this->appName, 'allowed_domains', '');
+ $allowed_domains = explode(';', $allowed_domains);
+ return $allowed_domains;
+ }
+
+ /**
+ * Find registration entity for token
+ *
+ * @param string $token
+ * @return string
+ * @throws RegistrationException
+ */
+ public function verifyToken($token) {
+ try {
+ return $this->registrationMapper->findByToken($token);
+ } catch (DoesNotExistException $exception) {
+ throw new RegistrationException($this->l10n->t('Invalid verification URL. No registration request with this verification URL is found.', 404));
+ }
+ }
+
+ /**
+ * @param $registration
+ * @param string $username
+ * @param string $password
+ * @return \OCP\IUser
+ * @throws RegistrationException
+ */
+ public function createAccount(Registration &$registration, $username = null, $password = null) {
+ if($password === null && $registration->getPassword() === null) {
+ $generatedPassword = $this->generateRandomDeviceToken();
+ $registration->setPassword($this->crypto->encrypt($generatedPassword));
+ }
+
+ if ($username === null) {
+ $username = $registration->getUsername();
+ }
+
+ if($registration->getPassword() !== null) {
+ $password = $this->crypto->decrypt($registration->getPassword());
+ }
+
+ $user = $this->userManager->createUser($username, $password);
+ if ($user === false) {
+ throw new RegistrationException($this->l10n->t('Unable to create user, there are problems with the user backend.'));
+ }
+ $userId = $user->getUID();
+ // Set user email
+ try {
+ $this->config->setUserValue($userId, 'settings', 'email', $registration->getEmail());
+ } catch (\Exception $e) {
+ throw new RegistrationException($this->l10n->t('Unable to set user email: ' . $e->getMessage()));
+ }
+
+ // Add user to group
+ $registered_user_group = $this->config->getAppValue($this->appName, 'registered_user_group', 'none');
+ if ( $registered_user_group !== 'none' ) {
+ try {
+ $group = $this->groupManager->get($registered_user_group);
+ $group->addUser($user);
+ } catch (\Exception $e) {
+ throw new RegistrationException($e->getMessage());
+ }
+ }
+
+ // Delete pending registration if no client secret is stored
+ 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);
+ return $user;
+ }
+
+ /**
+ * @param $token
+ * @return Registration
+ */
+ public function getRegistrationForToken($token) {
+ return $this->registrationMapper->findByToken($token);
+ }
+
+ /**
+ * @param $secret
+ * @return Registration
+ */
+ public function getRegistrationForSecret($secret) {
+ 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;
+ }
+
+ /**
+ * @param Registration $registration
+ */
+ public function deleteRegistration(Registration $registration) {
+ $this->registrationMapper->delete($registration);
+ }
+
+ /**
+ * Return a 25 digit device password
+ *
+ * Example: AbCdE-fGhIj-KlMnO-pQrSt-12345
+ *
+ * @return string
+ */
+ private function generateRandomDeviceToken() {
+ $groups = [];
+ for ($i = 0; $i < 5; $i++) {
+ $groups[] = $this->random->generate(5, ISecureRandom::CHAR_HUMAN_READABLE);
+ }
+ return implode('-', $groups);
+ }
+
+ /**
+ * @param string $uid
+ * @return string
+ * @throws RegistrationException
+ */
+ public function generateAppPassword($uid) {
+ $name = $this->l10n->t('Registration app auto setup');
+ try {
+ $sessionId = $this->session->getId();
+ } catch (SessionNotAvailableException $ex) {
+ throw new RegistrationException('Failed to generate an app token.');
+ }
+
+ try {
+ $sessionToken = $this->tokenProvider->getToken($sessionId);
+ $loginName = $sessionToken->getLoginName();
+ try {
+ $password = $this->tokenProvider->getPassword($sessionToken, $sessionId);
+ } catch (PasswordlessTokenException $ex) {
+ $password = null;
+ }
+ } catch (InvalidTokenException $ex) {
+ throw new RegistrationException('Failed to generate an app token.');
+ }
+
+ $token = $this->generateRandomDeviceToken();
+ $this->tokenProvider->generateToken($token, $uid, $loginName, $password, $name, IToken::PERMANENT_TOKEN);
+ return $token;
+ }
+
+ /**
+ * @param $userId
+ * @param $username
+ * @param $password
+ * @param $decrypt
+ * @return RedirectResponse|TemplateResponse
+ */
+ public function loginUser($userId, $username, $password, $decrypt = false) {
+ 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->linkToRoute('files.view.index'));
+ } 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'
+ );
+
+ }
+
+ /**
+ * Replicates OC::cleanupLoginTokens() since it's protected
+ * @param string $userId
+ */
+ public function cleanupLoginTokens($userId) {
+ $cutoff = time() - $this->config->getSystemValue('remember_login_cookie_lifetime', 60 * 60 * 24 * 15);
+ $tokens = $this->config->getUserKeys($userId, 'login_token');
+ foreach ($tokens as $token) {
+ $time = $this->config->getUserValue($userId, 'login_token', $token);
+ if ($time < $cutoff) {
+ $this->config->deleteUserValue($userId, 'login_token', $token);
+ }
+ }
+ }
+
+}
diff --git a/tests/autoloader.php b/tests/autoloader.php
index f62e632..ffaf089 100644
--- a/tests/autoloader.php
+++ b/tests/autoloader.php
@@ -9,44 +9,4 @@
* @copyright Pellaeon Lin 2014
*/
-require_once __DIR__ . '/../../../3rdparty/Pimple/Pimple.php';
-
-
-class OC {
- public static $server;
- public static $session;
-}
-
-// to execute without owncloud, we need to create our own classloader
-spl_autoload_register(function ($className){
- if (strpos($className, 'OCA\\') === 0) {
-
- $path = strtolower(str_replace('\\', '/', substr($className, 3)) . '.php');
- $relPath = __DIR__ . '/../..' . $path;
-
- if(file_exists($relPath)){
- require_once $relPath;
- }
- } else if(strpos($className, 'OCP\\') === 0) {
- $path = strtolower(str_replace('\\', '/', substr($className, 3)) . '.php');
- $relPath = __DIR__ . '/../../../lib/public' . $path;
-
- if(file_exists($relPath)){
- require_once $relPath;
- }
- } else if(strpos($className, 'OC_') === 0) {
- $path = strtolower(str_replace('\\', '/', substr($className, 3)) . '.php');
- $relPath = __DIR__ . '/../../../lib/private/' . $path;
-
- if(file_exists($relPath)){
- require_once $relPath;
- }
- } else if(strpos($className, 'OC\\') === 0) {
- $path = strtolower(str_replace('\\', '/', substr($className, 2)) . '.php');
- $relPath = __DIR__ . '/../../../lib/private' . $path;
-
- if(file_exists($relPath)){
- require_once $relPath;
- }
- }
-});
\ No newline at end of file
+require_once __DIR__ . '/../../../tests/bootstrap.php';
diff --git a/tests/unit/controller/ApiControllerTest.php b/tests/unit/controller/ApiControllerTest.php
new file mode 100644
index 0000000..d16a43b
--- /dev/null
+++ b/tests/unit/controller/ApiControllerTest.php
@@ -0,0 +1,174 @@
+
+ * @copyright Pellaeon Lin 2014
+ */
+
+namespace OCA\Registration\Controller;
+
+use OCA\Registration\Db\Registration;
+use OCA\Registration\Service\MailService;
+use OCA\Registration\Service\RegistrationService;
+use OCP\AppFramework\Db\DoesNotExistException;
+use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\DataResponse;
+use OCP\AppFramework\OCS\OCSException;
+use OCP\AppFramework\OCS\OCSNotFoundException;
+use OCP\Defaults;
+use OCP\IL10N;
+use OCP\IRequest;
+use OCP\IUser;
+use \Test\TestCase;
+
+class ApiControllerTest extends TestCase {
+
+ /** @var IRequest */
+ private $request;
+ /** @var RegistrationService|\PHPUnit_Framework_MockObject_MockObject */
+ private $registrationService;
+ /** @var MailService */
+ private $mailService;
+ /** @var IL10N */
+ private $l10n;
+ /** @var Defaults */
+ private $defaults;
+ /** @var ApiController */
+ private $controller;
+
+ public function setUp () {
+ parent::setUp();
+ $this->request = $this->createMock(IRequest::class);
+ $this->registrationService = $this->createMock(RegistrationService::class);
+ $this->mailService = $this->createMock(MailService::class);
+ $this->l10n = $this->createMock(IL10N::class);
+ $this->defaults = $this->createMock(Defaults::class);
+ $this->controller = new ApiController(
+ "registration",
+ $this->request,
+ $this->registrationService,
+ $this->mailService,
+ $this->l10n,
+ $this->defaults
+ );
+ }
+
+ public function testValidate() {
+ $this->registrationService
+ ->expects($this->once())
+ ->method('validateEmail')
+ ->with('test@example.com');
+ $this->registrationService
+ ->expects($this->once())
+ ->method('validateDisplayname')
+ ->with('user test');
+ $this->registrationService
+ ->expects($this->once())
+ ->method('validateUsername')
+ ->with('user1');
+
+ $expected = new DataResponse([
+ 'username' => 'user1',
+ 'displayname' => 'user test',
+ 'email' => 'test@example.com'
+ ], Http::STATUS_OK);
+ $actual = $this->controller->validate('user1', 'user test', 'test@example.com');
+ $this->assertEquals($expected, $actual);
+ }
+
+ /**
+ * @expectedException \OCP\AppFramework\OCS\OCSException
+ * @expectedExceptionCode 999
+ */
+ public function testValidateFailEmail() {
+ $this->registrationService
+ ->expects($this->once())
+ ->method('validateEmail')
+ ->willThrowException(new OCSException('', 999));
+ $this->controller->validate('user1', 'user test', 'test@example.com');
+ }
+
+ /**
+ * @expectedException \OCP\AppFramework\OCS\OCSException
+ * @expectedExceptionCode 999
+ */
+ public function testValidateFailDisplayname() {
+ $this->registrationService
+ ->expects($this->once())
+ ->method('validateDisplayname')
+ ->willThrowException(new OCSException('', 999));
+ $this->controller->validate('user1', 'user test', 'test@example.com');
+ }
+
+ /**
+ * @expectedException \OCP\AppFramework\OCS\OCSException
+ * @expectedExceptionCode 999
+ */
+ public function testValidateFailUsername() {
+ $this->registrationService
+ ->expects($this->once())
+ ->method('validateUsername')
+ ->willThrowException(new OCSException('', 999));
+ $this->controller->validate('user1', 'user test', 'test@example.com');
+ }
+
+ /**
+ * @expectedException \OCP\AppFramework\OCS\OCSNotFoundException
+ * @expectedExceptionCode 404
+ */
+ public function testStatusNoRegistration() {
+ $this->registrationService
+ ->method('getRegistrationForToken')
+ ->with('ABCDEF')
+ ->willThrowException(new DoesNotExistException(''));
+ $this->controller->status('ABCDEF');
+ }
+
+ /**
+ * @expectedException \OCP\AppFramework\OCS\OCSException
+ * @expectedExceptionCode 403
+ */
+ public function testStatusPendingRegistration() {
+ $registration = new Registration();
+ $registration->setEmailConfirmed(false);
+ $this->registrationService
+ ->method('getRegistrationForToken')
+ ->with('ABCDEF')
+ ->willReturn($registration);
+ $actual = $this->controller->status('ABCDEF');
+ }
+
+ public function testStatusConfirmedRegistration() {
+ $registration = new Registration();
+ $registration->setEmailConfirmed(true);
+ $registration->setClientSecret('mysecret');
+ $user = $this->createMock(IUser::class);
+ $this->registrationService
+ ->method('getRegistrationForToken')
+ ->with('ABCDEF')
+ ->willReturn($registration);
+ $this->registrationService
+ ->expects($this->once())
+ ->method('getUserAccount')
+ ->with($registration)
+ ->willReturn($user);
+ $this->registrationService
+ ->expects($this->once())
+ ->method('loginUser');
+ $this->registrationService
+ ->expects($this->once())
+ ->method('generateAppPassword');
+ $actual = $this->controller->status('ABCDEF');
+ $expected = new DataResponse([]);
+ $this->assertEquals($expected, $actual);
+ }
+
+ public function testStatusConfirmedRegistrationWithSecret() {
+
+ }
+
+}
\ No newline at end of file
diff --git a/tests/unit/controller/PageControllerTest.php b/tests/unit/controller/PageControllerTest.php
deleted file mode 100644
index 0e084ed..0000000
--- a/tests/unit/controller/PageControllerTest.php
+++ /dev/null
@@ -1,53 +0,0 @@
-
- * @copyright Pellaeon Lin 2014
- */
-
-namespace OCA\Registration\Controller;
-
-
-use \OCP\IRequest;
-use \OCP\AppFramework\Http\TemplateResponse;
-use \OCP\AppFramework\Http\JSONResponse;
-
-use \OCA\Registration\AppInfo\Application;
-
-
-class PageControllerTest extends \PHPUnit_Framework_TestCase {
-
- private $container;
-
- public function setUp () {
- $app = new Application();
- $this->container = $app->getContainer();
- }
-
-
- public function testIndex () {
- // swap out request
- $this->container['Request'] = $this->getMockBuilder('\OCP\IRequest')
- ->getMock();
- $this->container['UserId'] = 'john';
-
- $result = $this->container['PageController']->index();
-
- $this->assertEquals(array('user' => 'john'), $result->getParams());
- $this->assertEquals('main', $result->getTemplateName());
- $this->assertTrue($result instanceof TemplateResponse);
- }
-
-
- public function testEcho () {
- $result = $this->container['PageController']->doEcho('hi');
-
- $this->assertEquals(array('echo' => 'hi'), $result);
- }
-
-
-}
\ No newline at end of file