From 41be0d8486712d76daf86e8783a035d122e33008 Mon Sep 17 00:00:00 2001 From: Alexander Ebert Date: Fri, 8 Mar 2019 16:50:14 +0100 Subject: [PATCH] Prevent automatically disabled users from using activation codes --- com.woltlab.wcf/templates/userNotice.tpl | 2 +- .../install/files/acp/templates/userList.tpl | 7 ++++- .../blacklist/entry/BlacklistEntry.class.php | 9 +++--- .../files/lib/data/user/User.class.php | 20 +++++++++++++ .../lib/form/RegisterActivationForm.class.php | 9 ++++++ .../files/lib/form/RegisterForm.class.php | 28 +++++++++---------- .../RegisterNewActivationCodeForm.class.php | 9 ++++++ wcfsetup/install/lang/de.xml | 1 + wcfsetup/install/lang/en.xml | 1 + wcfsetup/setup/db/install.sql | 1 + 10 files changed, 66 insertions(+), 21 deletions(-) diff --git a/com.woltlab.wcf/templates/userNotice.tpl b/com.woltlab.wcf/templates/userNotice.tpl index ecce0bb42a..5ce3635f80 100644 --- a/com.woltlab.wcf/templates/userNotice.tpl +++ b/com.woltlab.wcf/templates/userNotice.tpl @@ -10,7 +10,7 @@

{lang}wcf.page.availableUpdates{/lang}

{/if} - {if $__wcf->user->activationCode && REGISTER_ACTIVATION_METHOD == 1 && $templateName != 'registerActivation' && $templateName != 'register' && $templateName != 'redirect'} + {if $__wcf->user->activationCode && REGISTER_ACTIVATION_METHOD == 1 && $templateName != 'registerActivation' && $templateName != 'register' && $templateName != 'redirect' && $__wcf->user->getBlacklistMatches()|empty}

{lang}wcf.user.register.needActivation{/lang}

{/if} diff --git a/wcfsetup/install/files/acp/templates/userList.tpl b/wcfsetup/install/files/acp/templates/userList.tpl index 7bf351cdac..ed812f2703 100644 --- a/wcfsetup/install/files/acp/templates/userList.tpl +++ b/wcfsetup/install/files/acp/templates/userList.tpl @@ -175,7 +175,12 @@ {if $user->banned}{/if} - {if $user->activationCode != 0}{/if} + {if $user->activationCode != 0} + + {if !$user->getBlacklistMatches()|empty} + + {/if} + {/if} {if MODULE_USER_RANK} diff --git a/wcfsetup/install/files/lib/data/blacklist/entry/BlacklistEntry.class.php b/wcfsetup/install/files/lib/data/blacklist/entry/BlacklistEntry.class.php index d005b20b6c..8adcff9634 100644 --- a/wcfsetup/install/files/lib/data/blacklist/entry/BlacklistEntry.class.php +++ b/wcfsetup/install/files/lib/data/blacklist/entry/BlacklistEntry.class.php @@ -24,9 +24,9 @@ class BlacklistEntry extends DatabaseObject { * @param string $username * @param string $email * @param string $ipAddress - * @return boolean + * @return string[] */ - public static function shouldReject($username, $email, $ipAddress) { + public static function getMatches($username, $email, $ipAddress) { if (BLACKLIST_SFS_USERNAME === 'skip' && BLACKLIST_SFS_EMAIL_ADDRESS === 'skip' && BLACKLIST_SFS_IP_ADDRESS === 'skip') { return false; } @@ -62,13 +62,14 @@ class BlacklistEntry extends DatabaseObject { ".$conditions; $statement = WCF::getDB()->prepareStatement($sql); $statement->execute($conditions->getParameters()); + $matches = []; while ($row = $statement->fetchArray()) { if (self::isMatch($row['type'], $row['occurrences'])) { - return true; + $matches[] = ($row['type'] === 'ipv4' || $row['type'] === 'ipv6') ? 'ip' : $row['type']; } } - return false; + return $matches; } protected static function getHash($string) { diff --git a/wcfsetup/install/files/lib/data/user/User.class.php b/wcfsetup/install/files/lib/data/user/User.class.php index 001d24352e..b34fa26781 100644 --- a/wcfsetup/install/files/lib/data/user/User.class.php +++ b/wcfsetup/install/files/lib/data/user/User.class.php @@ -11,6 +11,7 @@ use wcf\system\request\IRouteController; use wcf\system\request\LinkHandler; use wcf\system\user\storage\UserStorageHandler; use wcf\system\WCF; +use wcf\util\JSON; use wcf\util\PasswordUtil; use wcf\util\UserUtil; @@ -70,6 +71,7 @@ use wcf\util\UserUtil; * @property-read string $disableCoverPhotoReason reason why the user's cover photo is disabled * @property-read integer $disableCoverPhotoExpires timestamp at which the user's cover photo will automatically be enabled again * @property-read integer $articles number of articles written by the user + * @property-read string $blacklistMatches JSON string of an array with all matches in the blacklist, otherwise an empty string */ final class User extends DatabaseObject implements IRouteController, IUserContent { /** @@ -557,4 +559,22 @@ final class User extends DatabaseObject implements IRouteController, IUserConten public function canPurchasePaidSubscriptions() { return WCF::getUser()->userID && WCF::getUser()->activationCode == 0; } + + /** + * Returns the list of fields that had matches in the blacklist. An empty list is + * returned if the user has been approved, regardless of any known matches. + * + * @return string[] + * @since 5.2 + */ + public function getBlacklistMatches() { + if ($this->activationCode && $this->blacklistMatches) { + $matches = JSON::decode($this->blacklistMatches); + if (is_array($matches)) { + return $matches; + } + } + + return []; + } } diff --git a/wcfsetup/install/files/lib/form/RegisterActivationForm.class.php b/wcfsetup/install/files/lib/form/RegisterActivationForm.class.php index d795f48831..ea72f12487 100644 --- a/wcfsetup/install/files/lib/form/RegisterActivationForm.class.php +++ b/wcfsetup/install/files/lib/form/RegisterActivationForm.class.php @@ -5,6 +5,7 @@ use wcf\data\user\UserAction; use wcf\system\event\EventHandler; use wcf\system\exception\IllegalLinkException; use wcf\system\exception\NamedUserException; +use wcf\system\exception\PermissionDeniedException; use wcf\system\exception\UserInputException; use wcf\system\request\LinkHandler; use wcf\system\WCF; @@ -85,6 +86,10 @@ class RegisterActivationForm extends AbstractForm { if ($this->user->activationCode != $this->activationCode) { throw new UserInputException('activationCode', 'invalid'); } + + if (!empty($this->user->getBlacklistMatches())) { + throw new PermissionDeniedException(); + } } /** @@ -127,6 +132,10 @@ class RegisterActivationForm extends AbstractForm { $this->submit(); } + if ($this->user === null && !empty(WCF::getUser()->getBlacklistMatches())) { + throw new PermissionDeniedException(); + } + parent::show(); } } diff --git a/wcfsetup/install/files/lib/form/RegisterForm.class.php b/wcfsetup/install/files/lib/form/RegisterForm.class.php index e259a49a2b..8a9cdc5afa 100644 --- a/wcfsetup/install/files/lib/form/RegisterForm.class.php +++ b/wcfsetup/install/files/lib/form/RegisterForm.class.php @@ -28,6 +28,7 @@ use wcf\system\user\notification\object\UserRegistrationUserNotificationObject; use wcf\system\user\notification\UserNotificationHandler; use wcf\system\WCF; use wcf\util\HeaderUtil; +use wcf\util\JSON; use wcf\util\StringUtil; use wcf\util\UserRegistrationUtil; use wcf\util\UserUtil; @@ -84,11 +85,11 @@ class RegisterForm extends UserAddForm { public $randomFieldNames = []; /** - * the user will be disabled and requires manual approval - * @var bool + * list of fields that have matches in the blacklist + * @var string[] * @since 5.2 */ - public $forceDisableUser = false; + public $blacklistMatches = []; /** * min number of seconds between form request and submit @@ -175,13 +176,9 @@ class RegisterForm extends UserAddForm { } if (BLACKLIST_SFS_ENABLE) { - if (BlacklistEntry::shouldReject($this->username, $this->email, UserUtil::getIpAddress())) { - if (BLACKLIST_SFS_ACTION === 'disable') { - $this->forceDisableUser = true; - } - else { - throw new PermissionDeniedException(); - } + $this->blacklistMatches = BlacklistEntry::getMatches($this->username, $this->email, UserUtil::getIpAddress()); + if (BLACKLIST_SFS_ACTION === 'block') { + throw new PermissionDeniedException(); } } } @@ -431,7 +428,7 @@ class RegisterForm extends UserAddForm { // generate activation code $addDefaultGroups = true; - if ($this->forceDisableUser || (REGISTER_ACTIVATION_METHOD == 1 && !$registerVia3rdParty) || REGISTER_ACTIVATION_METHOD == 2) { + if (!empty($this->blacklistMatches) || (REGISTER_ACTIVATION_METHOD == 1 && !$registerVia3rdParty) || REGISTER_ACTIVATION_METHOD == 2) { $activationCode = UserRegistrationUtil::getActivationCode(); $this->additionalFields['activationCode'] = $activationCode; $addDefaultGroups = false; @@ -448,7 +445,8 @@ class RegisterForm extends UserAddForm { 'data' => array_merge($this->additionalFields, [ 'username' => $this->username, 'email' => $this->email, - 'password' => $this->password + 'password' => $this->password, + 'blacklistMatches' => (!empty($this->blacklistMatches)) ? JSON::encode($this->blacklistMatches) : '', ]), 'groups' => $this->groupIDs, 'languageIDs' => $this->visibleLanguages, @@ -473,10 +471,10 @@ class RegisterForm extends UserAddForm { } // activation management - if (REGISTER_ACTIVATION_METHOD == 0 && !$this->forceDisableUser) { + if (REGISTER_ACTIVATION_METHOD == 0 && empty($this->blacklistMatches)) { $this->message = 'wcf.user.register.success'; } - else if (REGISTER_ACTIVATION_METHOD == 1 && !$this->forceDisableUser) { + else if (REGISTER_ACTIVATION_METHOD == 1 && empty($this->blacklistMatches)) { // registering via 3rdParty leads to instant activation if ($registerVia3rdParty) { $this->message = 'wcf.user.register.success'; @@ -493,7 +491,7 @@ class RegisterForm extends UserAddForm { $this->message = 'wcf.user.register.success.needActivation'; } } - else if (REGISTER_ACTIVATION_METHOD == 2 || $this->forceDisableUser) { + else if (REGISTER_ACTIVATION_METHOD == 2 || !empty($this->blacklistMatches)) { $this->message = 'wcf.user.register.success.awaitActivation'; } diff --git a/wcfsetup/install/files/lib/form/RegisterNewActivationCodeForm.class.php b/wcfsetup/install/files/lib/form/RegisterNewActivationCodeForm.class.php index 27212a7f2d..1be7e8b42e 100644 --- a/wcfsetup/install/files/lib/form/RegisterNewActivationCodeForm.class.php +++ b/wcfsetup/install/files/lib/form/RegisterNewActivationCodeForm.class.php @@ -7,6 +7,7 @@ use wcf\system\email\mime\RecipientAwareTextMimePart; use wcf\system\email\Email; use wcf\system\email\UserMailbox; use wcf\system\exception\IllegalLinkException; +use wcf\system\exception\PermissionDeniedException; use wcf\system\exception\UserInputException; use wcf\system\request\LinkHandler; use wcf\system\WCF; @@ -91,6 +92,10 @@ class RegisterNewActivationCodeForm extends AbstractForm { if ($this->user->activationCode == 0) { throw new UserInputException('username', 'alreadyEnabled'); } + + if (!empty($this->user->getBlacklistMatches())) { + throw new PermissionDeniedException(); + } } /** @@ -197,6 +202,10 @@ class RegisterNewActivationCodeForm extends AbstractForm { throw new IllegalLinkException(); } + if ($this->user === null && !empty(WCF::getUser()->getBlacklistMatches())) { + throw new PermissionDeniedException(); + } + parent::show(); } } diff --git a/wcfsetup/install/lang/de.xml b/wcfsetup/install/lang/de.xml index 554d7659b4..71a0dd3440 100644 --- a/wcfsetup/install/lang/de.xml +++ b/wcfsetup/install/lang/de.xml @@ -4534,6 +4534,7 @@ sich{/if} nicht bei uns registriert {if LANGUAGE_USE_INFORMAL_VARIANT}hast{else} + diff --git a/wcfsetup/install/lang/en.xml b/wcfsetup/install/lang/en.xml index 29661797b0..38878ba0f5 100644 --- a/wcfsetup/install/lang/en.xml +++ b/wcfsetup/install/lang/en.xml @@ -4531,6 +4531,7 @@ not register with us.]]> + diff --git a/wcfsetup/setup/db/install.sql b/wcfsetup/setup/db/install.sql index b33f66e96c..9ed46d7ccb 100644 --- a/wcfsetup/setup/db/install.sql +++ b/wcfsetup/setup/db/install.sql @@ -1491,6 +1491,7 @@ CREATE TABLE wcf1_user ( positiveReactionsReceived INT(10) NOT NULL DEFAULT 0, negativeReactionsReceived INT(10) NOT NULL DEFAULT 0, neutralReactionsReceived INT(10) NOT NULL DEFAULT 0, + blacklistMatches VARCHAR(255) NOT NULL DEFAULT '', KEY username (username), KEY email (email), -- 2.20.1