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) { return match ($usage) { 'invalid_token_global' => sprintf('invalid_token_global_%d', $number), 'invalid_token_by_ip' => sprintf('invalid_token_ip_%s_%d', $discriminator, $number), 'ask_token_invalid_form_global' => sprintf('ask_token_invalid_form_global_%d', $number), 'ask_token_invalid_form_by_ip' => sprintf('ask_token_invalid_form_by_ip_%s_%d', $discriminator, $number), 'ask_token_success_by_user' => sprintf('ask_token_success_by_user_%s_%d', $discriminator->getId(), $number), default => throw new \LogicException('this usage is not implemented'), }; } public function getMax($usage) { return match ($usage) { 'invalid_token_global' => self::MAX_INVALID_TOKEN_GLOBAL, 'invalid_token_by_ip' => self::MAX_INVALID_TOKEN_BY_IP, 'ask_token_invalid_form_global' => self::MAX_ASK_TOKEN_INVALID_FORM_GLOBAL, 'ask_token_invalid_form_by_ip' => self::MAX_ASK_TOKEN_INVALID_FORM_BY_IP, 'ask_token_success_by_user' => self::MAX_ASK_TOKEN_BY_USER, default => throw new \UnexpectedValueException("this usage '{$usage}' is not yet implemented"), }; } public function getTtl($usage) { return match ($usage) { 'invalid_token_global', 'invalid_token_by_ip' => self::INVALID_TOKEN_TTL, 'ask_token_invalid_form_global', 'ask_token_invalid_form_by_ip' => self::ASK_TOKEN_INVALID_FORM_TTL, 'ask_token_success_by_user' => 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 (0 === $this->chillRedis->exists($key)) { return false; } } $this->logger->warning('locking reaching for password recovery', [ 'usage' => $usage, 'discriminator' => $discriminator, ]); return true; } }