<priority>1</priority>
<classname>wcf\system\user\multifactor\BackupMultifactorMethod</classname>
</type>
+ <type>
+ <name>com.woltlab.wcf.multifactor.backup</name>
+ <definitionname>com.woltlab.wcf.floodControl</definitionname>
+ </type>
<type>
<name>com.woltlab.wcf.multifactor.totp</name>
<definitionname>com.woltlab.wcf.multifactor</definitionname>
<priority>10</priority>
<classname>wcf\system\user\multifactor\TotpMultifactorMethod</classname>
</type>
+ <type>
+ <name>com.woltlab.wcf.multifactor.totp</name>
+ <definitionname>com.woltlab.wcf.floodControl</definitionname>
+ </type>
<!-- /multi factor -->
<!-- deprecated -->
<type>
<?php
namespace wcf\system\user\multifactor;
+use wcf\system\flood\FloodControl;
use wcf\system\form\builder\container\FormContainer;
use wcf\system\form\builder\field\ButtonFormField;
use wcf\system\form\builder\field\TextFormField;
private const CHUNKS = 4;
private const CHUNK_LENGTH = 5;
+ private const USER_ATTEMPTS_PER_HOUR = 5;
+
public function __construct() {
$this->algorithm = new Bcrypt();
}
->label('wcf.user.security.multifactor.backup.code')
->autoFocus()
->required()
- ->addValidator(new FormFieldValidator('code', function (TextFormField $field) use ($codes) {
+ ->addValidator(new FormFieldValidator('code', function (TextFormField $field) use ($codes, $setupId) {
+ FloodControl::getInstance()->registerUserContent('com.woltlab.wcf.multifactor.backup', $setupId);
+ $attempts = FloodControl::getInstance()->countUserContent('com.woltlab.wcf.multifactor.backup', $setupId, new \DateInterval('PT1H'));
+ if ($attempts['count'] > self::USER_ATTEMPTS_PER_HOUR) {
+ $field->addValidationError(new FormFieldValidationError(
+ 'flood',
+ 'wcf.user.security.multifactor.backup.error.flood',
+ $attempts
+ ));
+ return;
+ }
+
$userCode = \preg_replace('/\s+/', '', $field->getValue());
if ($this->findValidCode($userCode, $codes) === null) {
<?php
namespace wcf\system\user\multifactor;
use ParagonIE\ConstantTime\Hex;
+use wcf\system\flood\FloodControl;
use wcf\system\form\builder\button\FormButton;
use wcf\system\form\builder\container\FormContainer;
use wcf\system\form\builder\field\ButtonFormField;
* @since 5.4
*/
class TotpMultifactorMethod implements IMultifactorMethod {
+ private const USER_ATTEMPTS_PER_TEN_MINUTES = 5;
+
/**
* Returns the number of devices the user set up.
*/
->label('wcf.user.security.multifactor.totp.code')
->autoFocus()
->required()
- ->addValidator(new FormFieldValidator('code', function (CodeFormField $field) use ($devices) {
+ ->addValidator(new FormFieldValidator('code', function (CodeFormField $field) use ($devices, $setupId) {
+ FloodControl::getInstance()->registerUserContent('com.woltlab.wcf.multifactor.backup', $setupId);
+ $attempts = FloodControl::getInstance()->countUserContent('com.woltlab.wcf.multifactor.backup', $setupId, new \DateInterval('PT10M'));
+ if ($attempts['count'] > self::USER_ATTEMPTS_PER_TEN_MINUTES) {
+ $field->addValidationError(new FormFieldValidationError(
+ 'flood',
+ 'wcf.user.security.multifactor.totp.error.flood',
+ $attempts
+ ));
+ return;
+ }
+
/** @var IFormField $deviceField */
$deviceField = $field->getDocument()->getNodeById('device');
<item name="wcf.user.security.multifactor.backup.generateCodes"><![CDATA[Codes generieren]]></item>
<item name="wcf.user.security.multifactor.totp.devices"><![CDATA[Eingerichtete Geräte]]></item>
<item name="wcf.user.security.multifactor.totp.deviceName.default"><![CDATA[{TIME_NOW|plainTime}]]></item>
+ <item name="wcf.user.security.multifactor.totp.error.flood"><![CDATA[Bitte {if LANGUAGE_USE_INFORMAL_VARIANT}versuche es{else}versuchen Sie es{/if} später erneut.]]></item>
+ <item name="wcf.user.security.multifactor.backup.error.flood"><![CDATA[Bitte {if LANGUAGE_USE_INFORMAL_VARIANT}versuche es{else}versuchen Sie es{/if} später erneut.]]></item>
</category>
<category name="wcf.user.trophy">
<item name="wcf.user.trophy.trophyPoints"><![CDATA[Trophäen]]></item>
<item name="wcf.user.security.multifactor.backup.generateCodes"><![CDATA[Generate Codes]]></item>
<item name="wcf.user.security.multifactor.totp.devices"><![CDATA[Set Up Devices]]></item>
<item name="wcf.user.security.multifactor.totp.deviceName.default"><![CDATA[{TIME_NOW|plainTime}]]></item>
+ <item name="wcf.user.security.multifactor.totp.error.flood"><![CDATA[Please try again later.]]></item>
+ <item name="wcf.user.security.multifactor.backup.error.flood"><![CDATA[Please try again later.]]></item>
</category>
<category name="wcf.user.trophy">
<item name="wcf.user.trophy.trophyPoints"><![CDATA[Trophies]]></item>