2011-08-25 22:50:59 +02:00
|
|
|
<?php
|
|
|
|
|
2019-12-30 00:27:20 +01:00
|
|
|
declare(strict_types=1);
|
|
|
|
|
2011-08-25 22:50:59 +02:00
|
|
|
namespace Gregwar\CaptchaBundle\Validator;
|
|
|
|
|
2012-11-14 04:33:36 +01:00
|
|
|
use Symfony\Component\HttpFoundation\Session\SessionInterface;
|
2011-08-25 22:50:59 +02:00
|
|
|
use Symfony\Component\Form\FormError;
|
2012-11-14 04:33:36 +01:00
|
|
|
use Symfony\Component\Form\FormEvent;
|
2019-12-30 00:27:20 +01:00
|
|
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
2021-05-28 08:08:42 +02:00
|
|
|
use Symfony\Component\HttpFoundation\Request;
|
2011-08-25 22:50:59 +02:00
|
|
|
|
|
|
|
/**
|
2020-01-03 00:12:44 +01:00
|
|
|
* Captcha validator.
|
2011-08-25 22:50:59 +02:00
|
|
|
*
|
|
|
|
* @author Gregwar <g.passault@gmail.com>
|
|
|
|
*/
|
2012-11-14 04:33:36 +01:00
|
|
|
class CaptchaValidator
|
2011-08-25 22:50:59 +02:00
|
|
|
{
|
2019-12-30 00:27:20 +01:00
|
|
|
/** @var SessionInterface */
|
2011-08-25 22:50:59 +02:00
|
|
|
private $session;
|
|
|
|
|
|
|
|
/**
|
2020-01-03 00:12:44 +01:00
|
|
|
* Session key to store the code.
|
|
|
|
*
|
2019-12-30 00:27:20 +01:00
|
|
|
* @var string
|
2011-08-25 22:50:59 +02:00
|
|
|
*/
|
|
|
|
private $key;
|
|
|
|
|
2012-06-29 16:23:05 +02:00
|
|
|
/**
|
2020-01-03 00:12:44 +01:00
|
|
|
* Error message text for non-matching submissions.
|
|
|
|
*
|
2019-12-30 00:27:20 +01:00
|
|
|
* @var string
|
2012-06-29 16:23:05 +02:00
|
|
|
*/
|
|
|
|
private $invalidMessage;
|
|
|
|
|
2012-06-30 18:18:05 +02:00
|
|
|
/**
|
2020-01-03 00:12:44 +01:00
|
|
|
* Configuration parameter used to bypass a required code match.
|
|
|
|
*
|
2019-12-30 00:27:20 +01:00
|
|
|
* @var string
|
2012-06-30 18:18:05 +02:00
|
|
|
*/
|
|
|
|
private $bypassCode;
|
|
|
|
|
2012-12-04 12:20:23 +01:00
|
|
|
/**
|
2020-01-03 00:12:44 +01:00
|
|
|
* Number of form that the user can submit without captcha.
|
|
|
|
*
|
2012-12-04 12:20:23 +01:00
|
|
|
* @var int
|
|
|
|
*/
|
|
|
|
private $humanity;
|
|
|
|
|
2013-03-03 13:54:31 +01:00
|
|
|
/**
|
2020-01-03 00:12:44 +01:00
|
|
|
* Translator.
|
|
|
|
*
|
2013-03-03 13:54:31 +01:00
|
|
|
* @var TranslatorInterface
|
|
|
|
*/
|
|
|
|
private $translator;
|
|
|
|
|
2021-05-28 08:08:42 +02:00
|
|
|
/**
|
|
|
|
* Request
|
|
|
|
*
|
|
|
|
* @var Request
|
|
|
|
*/
|
|
|
|
private $req;
|
|
|
|
|
2019-12-30 00:27:20 +01:00
|
|
|
public function __construct(
|
|
|
|
TranslatorInterface $translator,
|
|
|
|
SessionInterface $session,
|
|
|
|
string $key,
|
|
|
|
string $invalidMessage,
|
2020-01-03 00:04:18 +01:00
|
|
|
?string $bypassCode,
|
2021-05-28 08:08:42 +02:00
|
|
|
int $humanity,
|
|
|
|
?Request $req
|
2019-12-30 00:27:20 +01:00
|
|
|
) {
|
2020-01-03 00:12:44 +01:00
|
|
|
$this->translator = $translator;
|
|
|
|
$this->session = $session;
|
|
|
|
$this->key = $key;
|
|
|
|
$this->invalidMessage = $invalidMessage;
|
|
|
|
$this->bypassCode = $bypassCode;
|
|
|
|
$this->humanity = $humanity;
|
2011-08-25 22:50:59 +02:00
|
|
|
}
|
|
|
|
|
2019-12-30 00:27:20 +01:00
|
|
|
public function validate(FormEvent $event): void
|
2011-08-25 22:50:59 +02:00
|
|
|
{
|
2014-07-03 10:50:49 +02:00
|
|
|
$form = $event->getForm();
|
2012-11-14 04:33:36 +01:00
|
|
|
|
2011-08-25 22:50:59 +02:00
|
|
|
$code = $form->getData();
|
2012-06-30 18:18:05 +02:00
|
|
|
$expectedCode = $this->getExpectedCode();
|
2011-08-25 22:50:59 +02:00
|
|
|
|
2012-12-04 12:20:23 +01:00
|
|
|
if ($this->humanity > 0) {
|
2013-01-21 15:18:36 +01:00
|
|
|
$humanity = $this->getHumanity();
|
|
|
|
if ($humanity > 0) {
|
2020-01-03 00:12:44 +01:00
|
|
|
$this->updateHumanity($humanity - 1);
|
|
|
|
|
2012-12-04 12:20:23 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-03 00:12:44 +01:00
|
|
|
if (!(null !== $code && is_string($code) && ($this->compare($code, $expectedCode) || $this->compare($code, $this->bypassCode)))) {
|
2013-03-03 13:54:31 +01:00
|
|
|
$form->addError(new FormError($this->translator->trans($this->invalidMessage, array(), 'validators')));
|
2012-12-04 12:20:23 +01:00
|
|
|
} else {
|
|
|
|
if ($this->humanity > 0) {
|
2013-01-21 15:18:36 +01:00
|
|
|
$this->updateHumanity($this->humanity);
|
2012-12-04 12:20:23 +01:00
|
|
|
}
|
2011-08-25 22:50:59 +02:00
|
|
|
}
|
2011-12-02 18:23:08 +01:00
|
|
|
|
2021-05-28 08:08:42 +02:00
|
|
|
if (null == $this->req || 1 < $this->req->get('flow_registration_step')) {
|
|
|
|
$this->session->remove($this->key);
|
|
|
|
if ($this->session->has($this->key.'_fingerprint')) {
|
|
|
|
$this->session->remove($this->key.'_fingerprint');
|
|
|
|
}
|
2011-12-02 19:26:31 +01:00
|
|
|
}
|
2011-08-25 22:50:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-01-03 00:12:44 +01:00
|
|
|
* Retrieve the expected CAPTCHA code.
|
2012-11-14 04:33:36 +01:00
|
|
|
*
|
|
|
|
* @return mixed|null
|
2011-08-25 22:50:59 +02:00
|
|
|
*/
|
2012-11-14 04:33:36 +01:00
|
|
|
protected function getExpectedCode()
|
2011-08-25 22:50:59 +02:00
|
|
|
{
|
2013-01-21 15:18:36 +01:00
|
|
|
$options = $this->session->get($this->key, array());
|
|
|
|
|
|
|
|
if (is_array($options) && isset($options['phrase'])) {
|
|
|
|
return $options['phrase'];
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-01-03 00:12:44 +01:00
|
|
|
* Retrieve the humanity.
|
2013-01-21 15:18:36 +01:00
|
|
|
*
|
|
|
|
* @return mixed|null
|
|
|
|
*/
|
|
|
|
protected function getHumanity()
|
|
|
|
{
|
2020-01-03 00:12:44 +01:00
|
|
|
return $this->session->get($this->key.'_humanity', 0);
|
2013-01-21 15:18:36 +01:00
|
|
|
}
|
|
|
|
|
2019-12-30 00:27:20 +01:00
|
|
|
protected function updateHumanity(int $newValue): void
|
2013-01-21 15:18:36 +01:00
|
|
|
{
|
|
|
|
if ($newValue > 0) {
|
2020-01-03 00:12:44 +01:00
|
|
|
$this->session->set($this->key.'_humanity', $newValue);
|
2013-01-21 15:18:36 +01:00
|
|
|
} else {
|
2020-01-03 00:12:44 +01:00
|
|
|
$this->session->remove($this->key.'_humanity');
|
2011-08-25 22:50:59 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-30 00:27:20 +01:00
|
|
|
protected function niceize(string $code): string
|
2011-08-25 22:50:59 +02:00
|
|
|
{
|
2011-12-14 10:18:38 +01:00
|
|
|
return strtr(strtolower($code), 'oil', '01l');
|
2011-08-25 22:50:59 +02:00
|
|
|
}
|
2012-06-30 18:18:05 +02:00
|
|
|
|
|
|
|
/**
|
2020-01-03 00:12:44 +01:00
|
|
|
* Run a match comparison on the provided code and the expected code.
|
2012-11-14 04:33:36 +01:00
|
|
|
*
|
2020-01-03 00:12:44 +01:00
|
|
|
* @param string $code
|
2020-01-03 00:04:18 +01:00
|
|
|
* @param string|null $expectedCode
|
2020-01-03 00:12:44 +01:00
|
|
|
*
|
2012-11-14 04:33:36 +01:00
|
|
|
* @return bool
|
2012-06-30 18:18:05 +02:00
|
|
|
*/
|
2019-12-30 00:27:20 +01:00
|
|
|
protected function compare($code, $expectedCode): bool
|
2012-06-30 18:18:05 +02:00
|
|
|
{
|
2020-01-03 00:12:44 +01:00
|
|
|
return null !== $expectedCode && is_string($expectedCode) && $this->niceize($code) == $this->niceize($expectedCode);
|
2012-06-30 18:18:05 +02:00
|
|
|
}
|
2011-08-25 22:50:59 +02:00
|
|
|
}
|