From 783b8dda939c66e3555948446003867a05f849f8 Mon Sep 17 00:00:00 2001 From: joshuaruesweg Date: Wed, 20 May 2020 19:53:19 +0200 Subject: [PATCH] Introduce new flag variable for email confirmation --- .../email_registerNeedActivation.tpl | 2 +- .../files/lib/data/user/User.class.php | 27 ++++++++++++++-- .../files/lib/data/user/UserAction.class.php | 32 +++++++++++++++++-- .../files/lib/data/user/UserProfile.class.php | 2 +- .../lib/data/user/UserProfileAction.class.php | 2 +- .../lib/form/RegisterActivationForm.class.php | 7 ++-- .../files/lib/form/RegisterForm.class.php | 2 ++ .../page/PaidSubscriptionListPage.class.php | 2 +- .../action/UserClipboardAction.class.php | 5 +-- .../condition/UserStateCondition.class.php | 4 +-- .../DailyMailNotificationCronjob.class.php | 2 +- .../system/importer/UserImporter.class.php | 2 +- .../UserNotificationHandler.class.php | 2 +- wcfsetup/install/lang/de.xml | 6 ++-- wcfsetup/install/lang/en.xml | 4 +-- wcfsetup/setup/db/install.sql | 1 + 16 files changed, 77 insertions(+), 25 deletions(-) diff --git a/com.woltlab.wcf/templates/email_registerNeedActivation.tpl b/com.woltlab.wcf/templates/email_registerNeedActivation.tpl index c81f8313d1..31185e0ccd 100644 --- a/com.woltlab.wcf/templates/email_registerNeedActivation.tpl +++ b/com.woltlab.wcf/templates/email_registerNeedActivation.tpl @@ -7,7 +7,7 @@ {lang}wcf.user.register.needActivation.mail.html.intro{/lang} {capture assign=button} - + {lang}wcf.user.register.needActivation.mail.html.activate{/lang} {/capture} diff --git a/wcfsetup/install/files/lib/data/user/User.class.php b/wcfsetup/install/files/lib/data/user/User.class.php index 761ea0b50c..ff91f24c7f 100644 --- a/wcfsetup/install/files/lib/data/user/User.class.php +++ b/wcfsetup/install/files/lib/data/user/User.class.php @@ -34,7 +34,8 @@ use wcf\util\UserUtil; * @property-read integer $banned is `1` if the user is banned, otherwise `0` * @property-read string $banReason reason why the user is banned * @property-read integer $banExpires timestamp at which the banned user is automatically unbanned - * @property-read integer $activationCode code sent to the user's email address used for account activation + * @property-read integer $activationCode flag which determines, whether the user is activated (for legacy reasons an random integer, if the user is *not* activated) + * @property-read string $emailConfirmed code sent to the user's email address used for account activation * @property-read integer $lastLostPasswordRequestTime timestamp at which the user has reported that they lost their password or 0 if password has not been reported as lost * @property-read string $lostPasswordKey code used for authenticating setting new password after password loss or empty if password has not been reported as lost * @property-read integer $lastUsernameChange timestamp at which the user changed their name the last time or 0 if username has not been changed @@ -404,6 +405,26 @@ final class User extends DatabaseObject implements IRouteController, IUserConten return 0; } + /** + * Returns true if this user is activated. + * + * @return boolean + * @since 5.3 + */ + public function isActivated() { + return $this->activationCode == 0; + } + + /** + * Returns true if the email is confirmed. + * + * @return boolean + * @since 5.3 + */ + public function isEmailConfirmed() { + return empty($this->emailConfirmed); + } + /** * Returns the time zone of this user. * @@ -593,7 +614,7 @@ final class User extends DatabaseObject implements IRouteController, IUserConten * @return boolean */ public function canPurchasePaidSubscriptions() { - return WCF::getUser()->userID && WCF::getUser()->activationCode == 0; + return WCF::getUser()->userID && $this->isActivated(); } /** @@ -604,7 +625,7 @@ final class User extends DatabaseObject implements IRouteController, IUserConten * @since 5.2 */ public function getBlacklistMatches() { - if ($this->activationCode && $this->blacklistMatches) { + if ($this->isActivated() && $this->blacklistMatches) { $matches = JSON::decode($this->blacklistMatches); if (is_array($matches)) { return $matches; diff --git a/wcfsetup/install/files/lib/data/user/UserAction.class.php b/wcfsetup/install/files/lib/data/user/UserAction.class.php index 6443bfddad..e280e51f87 100644 --- a/wcfsetup/install/files/lib/data/user/UserAction.class.php +++ b/wcfsetup/install/files/lib/data/user/UserAction.class.php @@ -22,6 +22,7 @@ use wcf\system\language\LanguageFactory; use wcf\system\request\RequestHandler; use wcf\system\user\group\assignment\UserGroupAssignmentHandler; use wcf\system\WCF; +use wcf\util\CryptoUtil; use wcf\util\UserRegistrationUtil; /** @@ -618,6 +619,28 @@ class UserAction extends AbstractDatabaseObjectAction implements IClipboardActio $this->validateEnable(); } + /** + * Marks the email address as confirmed and enables the user, iff the register method is user activation only. + * @since 5.3 + */ + public function confirmEmail() { + if (empty($this->objects)) $this->readObjects(); + + if (REGISTER_ACTIVATION_METHOD & UserProfile::REGISTER_ACTIVATION_ADMIN) { + $action = new UserAction($this->objects, 'update', [ + 'data' => [ + 'emailConfirmed' => null + ] + ]); + $action->executeAction(); + } + else { + $this->enable(); + } + + $this->unmarkItems(); + } + /** * Enables users. */ @@ -628,6 +651,7 @@ class UserAction extends AbstractDatabaseObjectAction implements IClipboardActio 'data' => [ 'activationCode' => 0, 'blacklistMatches' => '', + 'emailConfirmed' => null ], 'removeGroups' => UserGroup::getGroupIDsByType([UserGroup::GUESTS]) ]); @@ -670,7 +694,8 @@ class UserAction extends AbstractDatabaseObjectAction implements IClipboardActio $action = new UserAction($this->objects, 'update', [ 'data' => [ - 'activationCode' => UserRegistrationUtil::getActivationCode() + 'activationCode' => UserRegistrationUtil::getActivationCode(), + 'emailConfirmed' => bin2hex(\random_bytes(20)) ], 'removeGroups' => UserGroup::getGroupIDsByType([UserGroup::USERS]) ]); @@ -1009,7 +1034,8 @@ class UserAction extends AbstractDatabaseObjectAction implements IClipboardActio } foreach ($this->objects as $object) { - if (!$object->activationCode) { + /** @var UserEditor $object */ + if ($object->isActivated()) { throw new UserInputException('objectIDs'); } } @@ -1024,7 +1050,7 @@ class UserAction extends AbstractDatabaseObjectAction implements IClipboardActio foreach ($this->objects as $object) { $action = new UserAction([$object], 'update', [ 'data' => [ - 'activationCode' => UserRegistrationUtil::getActivationCode() + 'emailConfirmed' => bin2hex(\random_bytes(20)) ] ]); $action->executeAction(); diff --git a/wcfsetup/install/files/lib/data/user/UserProfile.class.php b/wcfsetup/install/files/lib/data/user/UserProfile.class.php index 8932e527c7..d4c0a9c774 100644 --- a/wcfsetup/install/files/lib/data/user/UserProfile.class.php +++ b/wcfsetup/install/files/lib/data/user/UserProfile.class.php @@ -886,7 +886,7 @@ class UserProfile extends DatabaseObjectDecorator implements ITitledLinkObject { * @return boolean */ public function canEditOwnProfile() { - if ($this->activationCode || !$this->getPermission('user.profile.canEditUserProfile')) { + if (!$this->isActivated() || !$this->getPermission('user.profile.canEditUserProfile')) { return false; } diff --git a/wcfsetup/install/files/lib/data/user/UserProfileAction.class.php b/wcfsetup/install/files/lib/data/user/UserProfileAction.class.php index 94fed670b1..4cc50a943f 100644 --- a/wcfsetup/install/files/lib/data/user/UserProfileAction.class.php +++ b/wcfsetup/install/files/lib/data/user/UserProfileAction.class.php @@ -407,7 +407,7 @@ class UserProfileAction extends UserAction { $fixUserGroupIDs[$user->userID] = [UserGroup::EVERYONE]; $groupIDs[] = UserGroup::EVERYONE; } - if ($user->activationCode) { + if (!$user->isActivated()) { if (!in_array(UserGroup::GUESTS, $groupIDs)) { if (!isset($fixUserGroupIDs[$user->userID])) $fixUserGroupIDs[$user->userID] = []; $fixUserGroupIDs[$user->userID][] = UserGroup::GUESTS; diff --git a/wcfsetup/install/files/lib/form/RegisterActivationForm.class.php b/wcfsetup/install/files/lib/form/RegisterActivationForm.class.php index 675a9cc576..492d914b34 100644 --- a/wcfsetup/install/files/lib/form/RegisterActivationForm.class.php +++ b/wcfsetup/install/files/lib/form/RegisterActivationForm.class.php @@ -10,6 +10,7 @@ use wcf\system\exception\PermissionDeniedException; use wcf\system\exception\UserInputException; use wcf\system\request\LinkHandler; use wcf\system\WCF; +use wcf\util\CryptoUtil; use wcf\util\HeaderUtil; use wcf\util\StringUtil; @@ -79,12 +80,12 @@ class RegisterActivationForm extends AbstractForm { } // user is already enabled - if ($this->user->activationCode == 0) { + if ($this->user->isEmailConfirmed()) { throw new NamedUserException(WCF::getLanguage()->get('wcf.user.registerActivation.error.userAlreadyEnabled')); } // check given activation code - if ($this->user->activationCode != $this->activationCode) { + if (\hash_equals($this->activationCode, $this->user->emailConfirmed)) { throw new UserInputException('activationCode', 'invalid'); } @@ -100,7 +101,7 @@ class RegisterActivationForm extends AbstractForm { parent::save(); // enable user - $this->objectAction = new UserAction([$this->user], 'enable', ['skipNotification' => true]); + $this->objectAction = new UserAction([$this->user], 'confirmEmail', ['skipNotification' => true]); $this->objectAction->executeAction(); $this->saved(); diff --git a/wcfsetup/install/files/lib/form/RegisterForm.class.php b/wcfsetup/install/files/lib/form/RegisterForm.class.php index bd1f98176c..19901a2279 100644 --- a/wcfsetup/install/files/lib/form/RegisterForm.class.php +++ b/wcfsetup/install/files/lib/form/RegisterForm.class.php @@ -431,7 +431,9 @@ class RegisterForm extends UserAddForm { $addDefaultGroups = true; if (!empty($this->blacklistMatches) || (REGISTER_ACTIVATION_METHOD & UserProfile::REGISTER_ACTIVATION_USER && !$registerVia3rdParty) || REGISTER_ACTIVATION_METHOD & UserProfile::REGISTER_ACTIVATION_ADMIN) { $activationCode = UserRegistrationUtil::getActivationCode(); + $emailConfirmCode = bin2hex(\random_bytes(20)); $this->additionalFields['activationCode'] = $activationCode; + $this->additionalFields['emailConfirmed'] = $emailConfirmCode; $addDefaultGroups = false; $this->groupIDs = UserGroup::getGroupIDsByType([UserGroup::EVERYONE, UserGroup::GUESTS]); } diff --git a/wcfsetup/install/files/lib/page/PaidSubscriptionListPage.class.php b/wcfsetup/install/files/lib/page/PaidSubscriptionListPage.class.php index f8fde99e07..d5c7cf00ed 100644 --- a/wcfsetup/install/files/lib/page/PaidSubscriptionListPage.class.php +++ b/wcfsetup/install/files/lib/page/PaidSubscriptionListPage.class.php @@ -43,7 +43,7 @@ class PaidSubscriptionListPage extends AbstractPage { public function checkPermissions() { parent::checkPermissions(); - if (WCF::getUser()->activationCode != 0) { + if (!WCF::getUser()->isActivated()) { throw new PermissionDeniedException(); } } diff --git a/wcfsetup/install/files/lib/system/clipboard/action/UserClipboardAction.class.php b/wcfsetup/install/files/lib/system/clipboard/action/UserClipboardAction.class.php index e832a3df61..ceba0e4266 100644 --- a/wcfsetup/install/files/lib/system/clipboard/action/UserClipboardAction.class.php +++ b/wcfsetup/install/files/lib/system/clipboard/action/UserClipboardAction.class.php @@ -196,7 +196,8 @@ class UserClipboardAction extends AbstractClipboardAction { $userIDs = []; foreach ($this->objects as $user) { - if ($user->activationCode) $userIDs[] = $user->userID; + /** @var User $user */ + if ($user->isActivated()) $userIDs[] = $user->userID; } return $userIDs; @@ -234,7 +235,7 @@ class UserClipboardAction extends AbstractClipboardAction { $userIDs = []; foreach ($this->objects as $user) { - if ($user->activationCode) $userIDs[] = $user->userID; + if ($user->is) $userIDs[] = $user->userID; } return $userIDs; diff --git a/wcfsetup/install/files/lib/system/condition/UserStateCondition.class.php b/wcfsetup/install/files/lib/system/condition/UserStateCondition.class.php index 47093fdb18..013409ff56 100644 --- a/wcfsetup/install/files/lib/system/condition/UserStateCondition.class.php +++ b/wcfsetup/install/files/lib/system/condition/UserStateCondition.class.php @@ -82,10 +82,10 @@ class UserStateCondition extends AbstractSingleFieldCondition implements IConten /** @noinspection PhpUndefinedFieldInspection */ $userIsEnabled = $condition->userIsEnabled; if ($userIsEnabled !== null) { - if ($userIsEnabled && $user->activationCode) { + if ($userIsEnabled && !$user->isActivated()) { return false; } - else if (!$userIsEnabled && !$user->activationCode) { + else if (!$userIsEnabled && $user->isActivated()) { return false; } } diff --git a/wcfsetup/install/files/lib/system/cronjob/DailyMailNotificationCronjob.class.php b/wcfsetup/install/files/lib/system/cronjob/DailyMailNotificationCronjob.class.php index 0013290037..d39709ecc9 100644 --- a/wcfsetup/install/files/lib/system/cronjob/DailyMailNotificationCronjob.class.php +++ b/wcfsetup/install/files/lib/system/cronjob/DailyMailNotificationCronjob.class.php @@ -145,7 +145,7 @@ class DailyMailNotificationCronjob extends AbstractCronjob { $user = $users[$userID]; // no notifications for disabled or banned users - if ($user->activationCode) continue; + if (!$user->isEmailConfirmed()) continue; if ($user->banned) continue; $notifications = array_map(function ($notificationID) use ($notificationObjects, $eventObjects, $user, $objectTypes, $authors, $authorToNotification, $unknownAuthor) { diff --git a/wcfsetup/install/files/lib/system/importer/UserImporter.class.php b/wcfsetup/install/files/lib/system/importer/UserImporter.class.php index 1ecd17568f..e0116833f8 100644 --- a/wcfsetup/install/files/lib/system/importer/UserImporter.class.php +++ b/wcfsetup/install/files/lib/system/importer/UserImporter.class.php @@ -176,7 +176,7 @@ class UserImporter extends AbstractImporter { } } - if (!$user->activationCode) $defaultGroupIDs = UserGroup::getGroupIDsByType([UserGroup::EVERYONE, UserGroup::USERS]); + if ($user->isActivated()) $defaultGroupIDs = UserGroup::getGroupIDsByType([UserGroup::EVERYONE, UserGroup::USERS]); else $defaultGroupIDs = UserGroup::getGroupIDsByType([UserGroup::EVERYONE, UserGroup::GUESTS]); $groupIDs = array_merge($groupIDs, $defaultGroupIDs); diff --git a/wcfsetup/install/files/lib/system/user/notification/UserNotificationHandler.class.php b/wcfsetup/install/files/lib/system/user/notification/UserNotificationHandler.class.php index 4672efdfa0..e57b4d181f 100644 --- a/wcfsetup/install/files/lib/system/user/notification/UserNotificationHandler.class.php +++ b/wcfsetup/install/files/lib/system/user/notification/UserNotificationHandler.class.php @@ -672,7 +672,7 @@ class UserNotificationHandler extends SingletonFactory { */ public function sendInstantMailNotification(UserNotification $notification, User $user, IUserNotificationEvent $event) { // no notifications for disabled or banned users - if ($user->activationCode) return; + if (!$user->isEmailConfirmed()) return; if ($user->banned) return; // recipient's language diff --git a/wcfsetup/install/lang/de.xml b/wcfsetup/install/lang/de.xml index f12d6ac09c..2b03fa48df 100644 --- a/wcfsetup/install/lang/de.xml +++ b/wcfsetup/install/lang/de.xml @@ -4713,7 +4713,7 @@ sich{/if} nicht bei uns registriert {if LANGUAGE_USE_INFORMAL_VARIANT}hast{else} Benutzerkonto vollständig verwenden {if LANGUAGE_USE_INFORMAL_VARIANT}kannst{else}können{/if}, ist es notwendig, dass {if LANGUAGE_USE_INFORMAL_VARIANT}du{else}Sie{/if} einmalig die Gültigkeit {if LANGUAGE_USE_INFORMAL_VARIANT}deiner{else}Ihrer{/if} E-Mail-Adresse {if LANGUAGE_USE_INFORMAL_VARIANT}bestätigst{else}bestätigen{/if}:

]]> {if LANGUAGE_USE_INFORMAL_VARIANT}Dein{else}Ihr{/if} Aktivierungscode lautet: {$mailbox->getUser()->activationCode}.

+

{if LANGUAGE_USE_INFORMAL_VARIANT}Dein{else}Ihr{/if} Aktivierungscode lautet: {$mailbox->getUser()->emailConfirmed}.

Wenn {if LANGUAGE_USE_INFORMAL_VARIANT}du{else}Sie{/if} Probleme mit der Aktivierung {if LANGUAGE_USE_INFORMAL_VARIANT}deines{else}Ihres{/if} Benutzerkontos {if LANGUAGE_USE_INFORMAL_VARIANT}hast{else}haben{/if}, dann {if LANGUAGE_USE_INFORMAL_VARIANT}wende dich{else}wenden Sie sich{/if} bitte an den Administrator unter: {MAIL_ADMIN_ADDRESS}. Wenn {if LANGUAGE_USE_INFORMAL_VARIANT}du dich{else}Sie sich{/if} nicht bei uns registriert {if LANGUAGE_USE_INFORMAL_VARIANT}hast{else}haben{/if}, dann {if LANGUAGE_USE_INFORMAL_VARIANT}kannst du{else}können Sie{/if} diese E-Mail ignorieren.

]]>
@@ -4724,9 +4724,9 @@ Bevor {if LANGUAGE_USE_INFORMAL_VARIANT}du dein{else}Sie Ihr{/if} Benutzerkonto dass {if LANGUAGE_USE_INFORMAL_VARIANT}du{else}Sie{/if} einmalig durch Klicken des folgenden Links die Gültigkeit {if LANGUAGE_USE_INFORMAL_VARIANT}deiner{else}Ihrer{/if} E-Mail-Adresse {if LANGUAGE_USE_INFORMAL_VARIANT}bestätigst{else}bestätigen{/if}: - {link controller='RegisterActivation' isEmail=true}u={@$mailbox->getUser()->userID}&a={@$mailbox->getUser()->activationCode}{/link} {* this line ends with a space *} + {link controller='RegisterActivation' isEmail=true}u={@$mailbox->getUser()->userID}&a={@$mailbox->getUser()->emailConfirmed}{/link} {* this line ends with a space *} -{if LANGUAGE_USE_INFORMAL_VARIANT}Dein{else}Ihr{/if} Aktivierungscode lautet: {@$mailbox->getUser()->activationCode} {* this line ends with a space *} +{if LANGUAGE_USE_INFORMAL_VARIANT}Dein{else}Ihr{/if} Aktivierungscode lautet: {@$mailbox->getUser()->emailConfirmed} {* this line ends with a space *} Wenn {if LANGUAGE_USE_INFORMAL_VARIANT}du{else}Sie{/if} Probleme mit der Aktivierung Ihres Benutzerkontos {if LANGUAGE_USE_INFORMAL_VARIANT}hast{else}haben{/if}, dann {if LANGUAGE_USE_INFORMAL_VARIANT}wende dich{else}wenden diff --git a/wcfsetup/install/lang/en.xml b/wcfsetup/install/lang/en.xml index 79bb275a55..0707122a51 100644 --- a/wcfsetup/install/lang/en.xml +++ b/wcfsetup/install/lang/en.xml @@ -4709,7 +4709,7 @@ not register with us.]]> user account to it’s full extent it is required that you confirm validity of your email address once:

]]> Your activation code is: {$mailbox->getUser()->activationCode}.

+

Your activation code is: {$mailbox->getUser()->emailConfirmed}.

If you have trouble confirming your email address, please contact the administrator at: {MAIL_ADMIN_ADDRESS}. Please ignore this email if you did not register an account with us.

]]>
@@ -4719,7 +4719,7 @@ Thank you for registering at: {@PAGE_TITLE|language} [URL:{link isEmail=true}{/l able to use your user account to it's full extent it is required that you confirm the validity of your email address once: - {link controller='RegisterActivation' isEmail=true}u={@$mailbox->getUser()->userID}&a={@$mailbox->getUser()->activationCode}{/link} {* this line ends with a space *} + {link controller='RegisterActivation' isEmail=true}u={@$mailbox->getUser()->userID}&a={@$mailbox->getUser()->emailConfirmed}{/link} {* this line ends with a space *} Your activation code is: {@$mailbox->getUser()->activationCode} {* this line ends with a space *} diff --git a/wcfsetup/setup/db/install.sql b/wcfsetup/setup/db/install.sql index 50def4fe5e..64ae131b62 100644 --- a/wcfsetup/setup/db/install.sql +++ b/wcfsetup/setup/db/install.sql @@ -1452,6 +1452,7 @@ CREATE TABLE wcf1_user ( banReason MEDIUMTEXT NULL, banExpires INT(10) NOT NULL DEFAULT 0, activationCode INT(10) NOT NULL DEFAULT 0, + emailConfirmed CHAR(40) DEFAULT NULL, lastLostPasswordRequestTime INT(10) NOT NULL DEFAULT 0, lostPasswordKey CHAR(40) DEFAULT NULL, lastUsernameChange INT(10) NOT NULL DEFAULT 0, -- 2.20.1