chillRedis = $chillRedis; $this->logger = $logger; } public function createLock($usage, $discriminator = null) { $max = $this->getMax($usage); $ttl = $this->getTtl($usage); for ($i = 0; $i < $max; ++$i) { $key = self::generateLockKey($usage, $i, $discriminator); if (0 === $this->chillRedis->exists($key)) { $this->chillRedis->set($key, 1); $this->chillRedis->setTimeout($key, $ttl); break; } } } /** * @param string $usage 'invalid_token_global' or ... * @param mixed|null $discriminator */ public static function generateLockKey($usage, int $number, $discriminator = null) { switch ($usage) { case 'invalid_token_global': return sprintf('invalid_token_global_%d', $number); case 'invalid_token_by_ip': return sprintf('invalid_token_ip_%s_%d', $discriminator, $number); case 'ask_token_invalid_form_global': return sprintf('ask_token_invalid_form_global_%d', $number); case 'ask_token_invalid_form_by_ip': return sprintf('ask_token_invalid_form_by_ip_%s_%d', $discriminator, $number); case 'ask_token_success_by_user': return sprintf('ask_token_success_by_user_%s_%d', $discriminator->getId(), $number); default: throw new LogicException('this usage is not implemented'); } } public function getMax($usage) { switch ($usage) { case 'invalid_token_global': return self::MAX_INVALID_TOKEN_GLOBAL; case 'invalid_token_by_ip': return self::MAX_INVALID_TOKEN_BY_IP; case 'ask_token_invalid_form_global': return self::MAX_ASK_TOKEN_INVALID_FORM_GLOBAL; case 'ask_token_invalid_form_by_ip': return self::MAX_ASK_TOKEN_INVALID_FORM_BY_IP; case 'ask_token_success_by_user': return self::MAX_ASK_TOKEN_BY_USER; default: throw new UnexpectedValueException("this usage '{$usage}' is not yet implemented"); } } public function getTtl($usage) { switch ($usage) { case 'invalid_token_global': case 'invalid_token_by_ip': return self::INVALID_TOKEN_TTL; case 'ask_token_invalid_form_global': case 'ask_token_invalid_form_by_ip': return self::ASK_TOKEN_INVALID_FORM_TTL; case 'ask_token_success_by_user': return self::ASK_TOKEN_INVALID_FORM_TTL * 24; default: throw new UnexpectedValueException("this usage '{$usage}' is not yet implemented"); } } public function isLocked($usage, $discriminator = null) { $max = $this->getMax($usage); for ($i = 0; $i < $max; ++$i) { $key = self::generateLockKey($usage, $i, $discriminator); if ($this->chillRedis->exists($key) === 0) { return false; } } $this->logger->warning('locking reaching for password recovery', [ 'usage' => $usage, 'discriminator' => $discriminator, ]); return true; } }