Intégration du module ReCaptcha
This commit is contained in:
@@ -23,12 +23,16 @@
|
|||||||
|
|
||||||
namespace Front\Controller;
|
namespace Front\Controller;
|
||||||
|
|
||||||
|
use ReCaptcha\Event\ReCaptchaCheckEvent;
|
||||||
|
use ReCaptcha\Event\ReCaptchaEvents;
|
||||||
|
use Thelia\Model\ModuleQuery;
|
||||||
use Thelia\Controller\Front\BaseFrontController;
|
use Thelia\Controller\Front\BaseFrontController;
|
||||||
use Thelia\Form\Definition\FrontForm;
|
use Thelia\Form\Definition\FrontForm;
|
||||||
use Thelia\Form\Exception\FormValidationException;
|
use Thelia\Form\Exception\FormValidationException;
|
||||||
use Thelia\Log\Tlog;
|
use Thelia\Log\Tlog;
|
||||||
use Thelia\Model\ConfigQuery;
|
use Thelia\Model\ConfigQuery;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class ContactController
|
* Class ContactController
|
||||||
* @package Thelia\Controller\Front
|
* @package Thelia\Controller\Front
|
||||||
@@ -46,6 +50,15 @@ class ContactController extends BaseFrontController
|
|||||||
try {
|
try {
|
||||||
$form = $this->validateForm($contactForm);
|
$form = $this->validateForm($contactForm);
|
||||||
|
|
||||||
|
$checkModule = ModuleQuery::create()
|
||||||
|
->findOneByCode('ReCaptcha');
|
||||||
|
|
||||||
|
if($checkModule && $checkModule->getActivate()){
|
||||||
|
$checkCaptchaEvent = new ReCaptchaCheckEvent();
|
||||||
|
$this->dispatch(ReCaptchaEvents::CHECK_CAPTCHA_EVENT, $checkCaptchaEvent);
|
||||||
|
if ($checkCaptchaEvent->isHuman() == false) { throw new FormValidationException('Invalid reCAPTCHA'); }
|
||||||
|
}
|
||||||
|
|
||||||
$this->getMailer()->sendSimpleEmailMessage(
|
$this->getMailer()->sendSimpleEmailMessage(
|
||||||
[ ConfigQuery::getStoreEmail() => $form->get('name')->getData() ],
|
[ ConfigQuery::getStoreEmail() => $form->get('name')->getData() ],
|
||||||
[ ConfigQuery::getStoreEmail() => ConfigQuery::getStoreName() ],
|
[ ConfigQuery::getStoreEmail() => ConfigQuery::getStoreName() ],
|
||||||
|
|||||||
@@ -22,6 +22,9 @@
|
|||||||
/*************************************************************************************/
|
/*************************************************************************************/
|
||||||
namespace Front\Controller;
|
namespace Front\Controller;
|
||||||
|
|
||||||
|
use ReCaptcha\Event\ReCaptchaCheckEvent;
|
||||||
|
use ReCaptcha\Event\ReCaptchaEvents;
|
||||||
|
use Thelia\Model\ModuleQuery;
|
||||||
use Front\Front;
|
use Front\Front;
|
||||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||||
use Thelia\Controller\Front\BaseFrontController;
|
use Thelia\Controller\Front\BaseFrontController;
|
||||||
@@ -47,6 +50,7 @@ use Thelia\Model\NewsletterQuery;
|
|||||||
use Thelia\Tools\RememberMeTrait;
|
use Thelia\Tools\RememberMeTrait;
|
||||||
use Thelia\Tools\URL;
|
use Thelia\Tools\URL;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class CustomerController
|
* Class CustomerController
|
||||||
* @package Thelia\Controller\Front
|
* @package Thelia\Controller\Front
|
||||||
@@ -161,6 +165,15 @@ class CustomerController extends BaseFrontController
|
|||||||
try {
|
try {
|
||||||
$form = $this->validateForm($customerCreation, "post");
|
$form = $this->validateForm($customerCreation, "post");
|
||||||
|
|
||||||
|
$checkModule = ModuleQuery::create()
|
||||||
|
->findOneByCode('ReCaptcha');
|
||||||
|
|
||||||
|
if($checkModule && $checkModule->getActivate()){
|
||||||
|
$checkCaptchaEvent = new ReCaptchaCheckEvent();
|
||||||
|
$this->dispatch(ReCaptchaEvents::CHECK_CAPTCHA_EVENT, $checkCaptchaEvent);
|
||||||
|
if ($checkCaptchaEvent->isHuman() == false) { throw new \Exception('Invalid reCAPTCHA'); }
|
||||||
|
}
|
||||||
|
|
||||||
$customerCreateEvent = $this->createEventInstance($form->getData());
|
$customerCreateEvent = $this->createEventInstance($form->getData());
|
||||||
|
|
||||||
$this->dispatch(TheliaEvents::CUSTOMER_CREATEACCOUNT, $customerCreateEvent);
|
$this->dispatch(TheliaEvents::CUSTOMER_CREATEACCOUNT, $customerCreateEvent);
|
||||||
|
|||||||
55
local/modules/ReCaptcha/Action/ReCaptchaAction.php
Normal file
55
local/modules/ReCaptcha/Action/ReCaptchaAction.php
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace ReCaptcha\Action;
|
||||||
|
|
||||||
|
use ReCaptcha\Event\ReCaptchaCheckEvent;
|
||||||
|
use ReCaptcha\Event\ReCaptchaEvents;
|
||||||
|
use ReCaptcha\ReCaptcha;
|
||||||
|
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
|
||||||
|
class ReCaptchaAction implements EventSubscriberInterface
|
||||||
|
{
|
||||||
|
/** @var Request */
|
||||||
|
protected $request;
|
||||||
|
|
||||||
|
public function __construct(Request $request)
|
||||||
|
{
|
||||||
|
$this->request = $request;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function checkCaptcha(ReCaptchaCheckEvent $event)
|
||||||
|
{
|
||||||
|
$requestUrl = "https://www.google.com/recaptcha/api/siteverify";
|
||||||
|
|
||||||
|
$secretKey = ReCaptcha::getConfigValue('secret_key');
|
||||||
|
$requestUrl .= "?secret=$secretKey";
|
||||||
|
|
||||||
|
$captchaResponse = $event->getCaptchaResponse();
|
||||||
|
if (null == $captchaResponse) {
|
||||||
|
$captchaResponse = $this->request->request->get('g-recaptcha-response');
|
||||||
|
}
|
||||||
|
|
||||||
|
$requestUrl .= "&response=$captchaResponse";
|
||||||
|
|
||||||
|
$remoteIp = $event->getRemoteIp();
|
||||||
|
if (null == $remoteIp) {
|
||||||
|
$remoteIp = $this->request->server->get('REMOTE_ADDR');
|
||||||
|
}
|
||||||
|
|
||||||
|
$requestUrl .= "&remoteip=$remoteIp";
|
||||||
|
|
||||||
|
$result = json_decode(file_get_contents($requestUrl), true);
|
||||||
|
|
||||||
|
if ($result['success'] == true) {
|
||||||
|
$event->setHuman(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getSubscribedEvents()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
ReCaptchaEvents::CHECK_CAPTCHA_EVENT => ['checkCaptcha', 128],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
49
local/modules/ReCaptcha/Config/config.xml
Normal file
49
local/modules/ReCaptcha/Config/config.xml
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
|
||||||
|
<config xmlns="http://thelia.net/schema/dic/config"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://thelia.net/schema/dic/config http://thelia.net/schema/dic/config/thelia-1.0.xsd">
|
||||||
|
|
||||||
|
<loops>
|
||||||
|
<!-- sample definition
|
||||||
|
<loop name="MySuperLoop" class="ReCaptcha\Loop\MySuperLoop" />
|
||||||
|
-->
|
||||||
|
</loops>
|
||||||
|
|
||||||
|
<forms>
|
||||||
|
<form name="recaptcha_configuration.form" class="ReCaptcha\Form\ConfigurationForm" />
|
||||||
|
</forms>
|
||||||
|
|
||||||
|
<commands>
|
||||||
|
<!--
|
||||||
|
<command class="ReCaptcha\Command\MySuperCommand" />
|
||||||
|
-->
|
||||||
|
</commands>
|
||||||
|
|
||||||
|
<services>
|
||||||
|
<service id="recpatcha.action" class="ReCaptcha\Action\ReCaptchaAction">
|
||||||
|
<tag name="kernel.event_subscriber" />
|
||||||
|
<argument type="service" id="request"/>
|
||||||
|
</service>
|
||||||
|
</services>
|
||||||
|
|
||||||
|
<hooks>
|
||||||
|
<hook id="recaptcha.hook" class="ReCaptcha\Hook\FrontHook">
|
||||||
|
<tag name="hook.event_listener" event="main.head-top" type="front" templates="render:recaptcha-js.html" />
|
||||||
|
<tag name="hook.event_listener" event="recaptcha.js" type="front" templates="render:recaptcha-js.html" />
|
||||||
|
<tag name="hook.event_listener" event="recaptcha.check" type="front" method="addRecaptchaCheck" />
|
||||||
|
</hook>
|
||||||
|
</hooks>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
<exports>
|
||||||
|
|
||||||
|
</exports>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!--
|
||||||
|
<imports>
|
||||||
|
|
||||||
|
</imports>
|
||||||
|
-->
|
||||||
|
</config>
|
||||||
41
local/modules/ReCaptcha/Config/module.xml
Normal file
41
local/modules/ReCaptcha/Config/module.xml
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module xmlns="http://thelia.net/schema/dic/module"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://thelia.net/schema/dic/module http://thelia.net/schema/dic/module/module-2_2.xsd">
|
||||||
|
<fullnamespace>ReCaptcha\ReCaptcha</fullnamespace>
|
||||||
|
<descriptive locale="en_US">
|
||||||
|
<title>ReCaptcha</title>
|
||||||
|
<!--
|
||||||
|
<subtitle></subtitle>
|
||||||
|
<description></description>
|
||||||
|
<postscriptum></postscriptum>
|
||||||
|
-->
|
||||||
|
</descriptive>
|
||||||
|
<descriptive locale="fr_FR">
|
||||||
|
<title>ReCaptcha</title>
|
||||||
|
</descriptive>
|
||||||
|
<!-- <logo></logo> -->
|
||||||
|
<!--<images-folder>images</images-folder>-->
|
||||||
|
<languages>
|
||||||
|
<language>en_US</language>
|
||||||
|
<language>fr_FR</language>
|
||||||
|
</languages>
|
||||||
|
<version>2.0.2</version>
|
||||||
|
<authors>
|
||||||
|
<author>
|
||||||
|
<name>Vincent Lopes-Vicente</name>
|
||||||
|
<email>vlopes@openstudio.fr</email>
|
||||||
|
</author>
|
||||||
|
</authors>
|
||||||
|
<type>classic</type>
|
||||||
|
<!--
|
||||||
|
module dependencies
|
||||||
|
<required>
|
||||||
|
<module version=">=0.1">Front</module>
|
||||||
|
<module version="~1.0">HookCart</module>
|
||||||
|
<module version=">0.2">HookSearch</module>
|
||||||
|
</required>
|
||||||
|
-->
|
||||||
|
<thelia>2.3.0</thelia>
|
||||||
|
<stability>other</stability>
|
||||||
|
</module>
|
||||||
15
local/modules/ReCaptcha/Config/routing.xml
Normal file
15
local/modules/ReCaptcha/Config/routing.xml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
|
||||||
|
<routes xmlns="http://symfony.com/schema/routing"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">
|
||||||
|
|
||||||
|
<route id="admin.recaptcha.config" path="/admin/module/ReCaptcha">
|
||||||
|
<default key="_controller">ReCaptcha\Controller\ConfigurationController::viewAction</default>
|
||||||
|
</route>
|
||||||
|
|
||||||
|
<route id="admin.recaptcha.config.save" path="/admin/module/recaptcha/configuration" methods="POST">
|
||||||
|
<default key="_controller">ReCaptcha\Controller\ConfigurationController::saveAction</default>
|
||||||
|
</route>
|
||||||
|
|
||||||
|
</routes>
|
||||||
30
local/modules/ReCaptcha/Config/schema.xml
Normal file
30
local/modules/ReCaptcha/Config/schema.xml
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<database defaultIdMethod="native" name="thelia"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:noNamespaceSchemaLocation="../../../vendor/propel/propel/resources/xsd/database.xsd" >
|
||||||
|
<!--
|
||||||
|
See propel documentation on http://propelorm.org for all information about schema file
|
||||||
|
|
||||||
|
<table name="product_rel" namespace="ReCaptcha\Model">
|
||||||
|
<column autoIncrement="true" name="id" primaryKey="true" required="true" type="INTEGER" />
|
||||||
|
<column defaultValue="0" name="visible" required="true" type="TINYINT" />
|
||||||
|
<column defaultValue="0" name="position" required="true" type="INTEGER" />
|
||||||
|
<column name="title" size="255" type="VARCHAR" />
|
||||||
|
<column name="description" type="CLOB" />
|
||||||
|
<column name="chapo" type="LONGVARCHAR" />
|
||||||
|
<column name="postscriptum" type="LONGVARCHAR" />
|
||||||
|
<foreign-key foreignTable="product" name="fk_product_id" onDelete="CASCADE" onUpdate="RESTRICT">
|
||||||
|
<reference foreign="id" local="product_id" />
|
||||||
|
</foreign-key>
|
||||||
|
<behavior name="timestampable" />
|
||||||
|
<behavior name="i18n">
|
||||||
|
<parameter name="i18n_columns" value="title, description, chapo, postscriptum" />
|
||||||
|
</behavior>
|
||||||
|
<behavior name="versionable">
|
||||||
|
<parameter name="log_created_at" value="true" />
|
||||||
|
<parameter name="log_created_by" value="true" />
|
||||||
|
</behavior>
|
||||||
|
</table>
|
||||||
|
-->
|
||||||
|
<external-schema filename="local/config/schema.xml" referenceOnly="true" />
|
||||||
|
</database>
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace ReCaptcha\Controller;
|
||||||
|
|
||||||
|
use ReCaptcha\ReCaptcha;
|
||||||
|
use Thelia\Controller\Admin\BaseAdminController;
|
||||||
|
use Thelia\Core\Security\AccessManager;
|
||||||
|
use Thelia\Core\Security\Resource\AdminResources;
|
||||||
|
use Thelia\Core\Translation\Translator;
|
||||||
|
|
||||||
|
class ConfigurationController extends BaseAdminController
|
||||||
|
{
|
||||||
|
public function viewAction()
|
||||||
|
{
|
||||||
|
return $this->render(
|
||||||
|
"recaptcha/configuration"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function saveAction()
|
||||||
|
{
|
||||||
|
if (null !== $response = $this->checkAuth(array(AdminResources::MODULE), 'ReCaptcha', AccessManager::VIEW)) {
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
$form = $this->createForm("recaptcha_configuration.form");
|
||||||
|
|
||||||
|
try {
|
||||||
|
$data = $this->validateForm($form)->getData();
|
||||||
|
|
||||||
|
ReCaptcha::setConfigValue('site_key', $data['site_key']);
|
||||||
|
ReCaptcha::setConfigValue('secret_key', $data['secret_key']);
|
||||||
|
ReCaptcha::setConfigValue('captcha_style', $data['captcha_style']);
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->setupFormErrorContext(
|
||||||
|
Translator::getInstance()->trans(
|
||||||
|
"Error",
|
||||||
|
[],
|
||||||
|
ReCaptcha::DOMAIN_NAME
|
||||||
|
),
|
||||||
|
$e->getMessage(),
|
||||||
|
$form
|
||||||
|
);
|
||||||
|
return $this->viewAction();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->generateSuccessRedirect($form);
|
||||||
|
}
|
||||||
|
}
|
||||||
80
local/modules/ReCaptcha/Event/ReCaptchaCheckEvent.php
Normal file
80
local/modules/ReCaptcha/Event/ReCaptchaCheckEvent.php
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace ReCaptcha\Event;
|
||||||
|
|
||||||
|
use Thelia\Core\Event\ActionEvent;
|
||||||
|
|
||||||
|
class ReCaptchaCheckEvent extends ActionEvent
|
||||||
|
{
|
||||||
|
protected $captchaResponse = null;
|
||||||
|
|
||||||
|
protected $remoteIp = null;
|
||||||
|
|
||||||
|
/** @var boolean */
|
||||||
|
protected $human = false;
|
||||||
|
|
||||||
|
public function __construct($captchaResponse = null, $remoteIp = null)
|
||||||
|
{
|
||||||
|
if (null !== $captchaResponse) {
|
||||||
|
$this->captchaResponse = $captchaResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null !== $remoteIp) {
|
||||||
|
$this->remoteIp = $remoteIp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return null
|
||||||
|
*/
|
||||||
|
public function getCaptchaResponse()
|
||||||
|
{
|
||||||
|
return $this->captchaResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param null $captchaResponse
|
||||||
|
* @return ReCaptchaCheckEvent
|
||||||
|
*/
|
||||||
|
public function setCaptchaResponse($captchaResponse)
|
||||||
|
{
|
||||||
|
$this->captchaResponse = $captchaResponse;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return null
|
||||||
|
*/
|
||||||
|
public function getRemoteIp()
|
||||||
|
{
|
||||||
|
return $this->remoteIp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param null $remoteIp
|
||||||
|
* @return ReCaptchaCheckEvent
|
||||||
|
*/
|
||||||
|
public function setRemoteIp($remoteIp)
|
||||||
|
{
|
||||||
|
$this->remoteIp = $remoteIp;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isHuman()
|
||||||
|
{
|
||||||
|
return $this->human;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param bool $human
|
||||||
|
* @return ReCaptchaCheckEvent
|
||||||
|
*/
|
||||||
|
public function setHuman($human)
|
||||||
|
{
|
||||||
|
$this->human = $human;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
8
local/modules/ReCaptcha/Event/ReCaptchaEvents.php
Normal file
8
local/modules/ReCaptcha/Event/ReCaptchaEvents.php
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace ReCaptcha\Event;
|
||||||
|
|
||||||
|
class ReCaptchaEvents
|
||||||
|
{
|
||||||
|
const CHECK_CAPTCHA_EVENT = "check_captcha_event";
|
||||||
|
}
|
||||||
55
local/modules/ReCaptcha/Form/ConfigurationForm.php
Normal file
55
local/modules/ReCaptcha/Form/ConfigurationForm.php
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace ReCaptcha\Form;
|
||||||
|
|
||||||
|
use ReCaptcha\ReCaptcha;
|
||||||
|
use Thelia\Core\Translation\Translator;
|
||||||
|
use Thelia\Form\BaseForm;
|
||||||
|
|
||||||
|
class ConfigurationForm extends BaseForm
|
||||||
|
{
|
||||||
|
protected function buildForm()
|
||||||
|
{
|
||||||
|
$this->formBuilder
|
||||||
|
->add(
|
||||||
|
"site_key",
|
||||||
|
"text",
|
||||||
|
[
|
||||||
|
"data" => ReCaptcha::getConfigValue("site_key"),
|
||||||
|
"label"=>Translator::getInstance()->trans("Site key", array(), ReCaptcha::DOMAIN_NAME),
|
||||||
|
"label_attr" => ["for" => "site_key"],
|
||||||
|
"required" => true
|
||||||
|
]
|
||||||
|
)
|
||||||
|
->add(
|
||||||
|
"secret_key",
|
||||||
|
"text",
|
||||||
|
[
|
||||||
|
"data" => ReCaptcha::getConfigValue("secret_key"),
|
||||||
|
"label"=>Translator::getInstance()->trans("Secret key", array(), ReCaptcha::DOMAIN_NAME),
|
||||||
|
"label_attr" => ["for" => "secret_key"],
|
||||||
|
"required" => true
|
||||||
|
]
|
||||||
|
)
|
||||||
|
->add(
|
||||||
|
"captcha_style",
|
||||||
|
"choice",
|
||||||
|
[
|
||||||
|
"data" => ReCaptcha::getConfigValue("captcha_style"),
|
||||||
|
"label"=>Translator::getInstance()->trans("ReCaptcha style", array(), ReCaptcha::DOMAIN_NAME),
|
||||||
|
"label_attr" => ["for" => "captcha_style"],
|
||||||
|
"required" => true,
|
||||||
|
'choices' => [
|
||||||
|
'normal'=>'Normal',
|
||||||
|
'compact'=>'Compact',
|
||||||
|
'invisible'=>'Invisible'
|
||||||
|
]
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return "recaptcha_configuration_form";
|
||||||
|
}
|
||||||
|
}
|
||||||
27
local/modules/ReCaptcha/Hook/FrontHook.php
Normal file
27
local/modules/ReCaptcha/Hook/FrontHook.php
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
namespace ReCaptcha\Hook;
|
||||||
|
|
||||||
|
|
||||||
|
use ReCaptcha\ReCaptcha;
|
||||||
|
use Thelia\Core\Event\Hook\HookRenderEvent;
|
||||||
|
use Thelia\Core\Hook\BaseHook;
|
||||||
|
|
||||||
|
class FrontHook extends BaseHook
|
||||||
|
{
|
||||||
|
public function addRecaptchaCheck(HookRenderEvent $event)
|
||||||
|
{
|
||||||
|
$siteKey = ReCaptcha::getConfigValue('site_key');
|
||||||
|
$captchaStyle = ReCaptcha::getConfigValue('captcha_style');
|
||||||
|
|
||||||
|
$captchaId= "recaptcha";
|
||||||
|
$captchaCallback = "";
|
||||||
|
if ($captchaStyle === 'invisible') {
|
||||||
|
$captchaCallback = "data-callback='onCompleted'";
|
||||||
|
$captchaId = $captchaId.'-invisible';
|
||||||
|
}
|
||||||
|
|
||||||
|
$event->add("<div id='$captchaId' class='g-recaptcha' data-sitekey='$siteKey' $captchaCallback data-size='$captchaStyle'></div>");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'ReCaptcha configuration' => 'ReCaptcha configuration',
|
||||||
|
'ReCaptcha module configuration' => 'ReCaptcha module configuration',
|
||||||
|
'These infos are available here : ' => 'Ces infos sont disponibles ici : ',
|
||||||
|
'reCAPTCHA access :' => 'reCAPTCHA accés :',
|
||||||
|
);
|
||||||
4
local/modules/ReCaptcha/I18n/en_US.php
Normal file
4
local/modules/ReCaptcha/I18n/en_US.php
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?php
|
||||||
|
return array(
|
||||||
|
// 'an english string' => 'The displayed english string',
|
||||||
|
);
|
||||||
7
local/modules/ReCaptcha/I18n/fr_FR.php
Normal file
7
local/modules/ReCaptcha/I18n/fr_FR.php
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'Error' => 'Erreur',
|
||||||
|
'Secret key' => 'Clé secrète',
|
||||||
|
'Site key' => 'Clé du site',
|
||||||
|
);
|
||||||
21
local/modules/ReCaptcha/LICENSE
Normal file
21
local/modules/ReCaptcha/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2019 OpenStudio
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
55
local/modules/ReCaptcha/ReCaptcha.php
Normal file
55
local/modules/ReCaptcha/ReCaptcha.php
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
/*************************************************************************************/
|
||||||
|
/* This file is part of the Thelia package. */
|
||||||
|
/* */
|
||||||
|
/* Copyright (c) OpenStudio */
|
||||||
|
/* email : dev@thelia.net */
|
||||||
|
/* web : http://www.thelia.net */
|
||||||
|
/* */
|
||||||
|
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||||
|
/* file that was distributed with this source code. */
|
||||||
|
/*************************************************************************************/
|
||||||
|
|
||||||
|
namespace ReCaptcha;
|
||||||
|
|
||||||
|
use Thelia\Core\Template\TemplateDefinition;
|
||||||
|
use Thelia\Module\BaseModule;
|
||||||
|
|
||||||
|
class ReCaptcha extends BaseModule
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
const DOMAIN_NAME = 'recaptcha';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* You may now override BaseModuleInterface methods, such as:
|
||||||
|
* install, destroy, preActivation, postActivation, preDeactivation, postDeactivation
|
||||||
|
*
|
||||||
|
* Have fun !
|
||||||
|
*/
|
||||||
|
|
||||||
|
public function getHooks()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
"type" => TemplateDefinition::FRONT_OFFICE,
|
||||||
|
"code" => "recaptcha.js",
|
||||||
|
"title" => [
|
||||||
|
"en_US" => "reCaptcha js",
|
||||||
|
"fr_FR" => "Js pour recaptcha",
|
||||||
|
],
|
||||||
|
"block" => false,
|
||||||
|
"active" => true,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"type" => TemplateDefinition::FRONT_OFFICE,
|
||||||
|
"code" => "recaptcha.check",
|
||||||
|
"title" => [
|
||||||
|
"en_US" => "reCaptcha check hook",
|
||||||
|
"fr_FR" => "reCaptcha check hook",
|
||||||
|
],
|
||||||
|
"block" => false,
|
||||||
|
"active" => true,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
62
local/modules/ReCaptcha/Readme.md
Normal file
62
local/modules/ReCaptcha/Readme.md
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
# Re Captcha
|
||||||
|
|
||||||
|
This module allow you to add easily a reCAPTCHA to your form
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
### Composer
|
||||||
|
|
||||||
|
Add it in your main thelia composer.json file
|
||||||
|
|
||||||
|
```
|
||||||
|
composer require thelia/re-captcha-module:~2.0.0
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Before using this module you have to create google api key here http://www.google.com/recaptcha/admin
|
||||||
|
next configure your reCAPTCHA access here http://your_site.com`/admin/module/ReCaptcha` with keys you obtained in Google's page
|
||||||
|
and choose which style of captcha you want :
|
||||||
|
|
||||||
|
- A standard captcha (or a compact version of this one)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
- An invisible captcha
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
Then you'll need help from a developer to add some hooks in template and dispatch the check events, see details below.
|
||||||
|
|
||||||
|
### Hook
|
||||||
|
|
||||||
|
First if you don't have `{hook name="main.head-top"}` hook in your template you have to put this hook `{hook name="recaptcha.js"}` in the top of your head
|
||||||
|
Then add this hook `{hook name="recaptcha.check"}` in every form where you want to check if the user is human,
|
||||||
|
be careful if you want to use the invisible captcha this hook must be placed directly in the form tag like this :
|
||||||
|
```
|
||||||
|
<form id="form-contact" action="{url path="/contact"}" method="post">
|
||||||
|
{hook name="recaptcha.check"}
|
||||||
|
// End of the form
|
||||||
|
</form>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Event
|
||||||
|
|
||||||
|
To check in server-side if the captcha is valid you have to dispatch the "CHECK_CAPTCHA_EVENT" like this :
|
||||||
|
```
|
||||||
|
$checkCaptchaEvent = new ReCaptchaCheckEvent();
|
||||||
|
$this->dispatch(ReCaptchaEvents::CHECK_CAPTCHA_EVENT, $checkCaptchaEvent);
|
||||||
|
```
|
||||||
|
|
||||||
|
Then the result of check is available in `$checkCaptchaEvent->isHuman()`as boolean so you can do a test like this :
|
||||||
|
```
|
||||||
|
if ($checkCaptchaEvent->isHuman() == false) {
|
||||||
|
throw new \Exception('Invalid captcha');
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Don't forget to add this use at the top of your class :
|
||||||
|
```
|
||||||
|
use ReCaptcha\Event\ReCaptchaCheckEvent;
|
||||||
|
use ReCaptcha\Event\ReCaptchaEvents;
|
||||||
|
```
|
||||||
11
local/modules/ReCaptcha/composer.json
Normal file
11
local/modules/ReCaptcha/composer.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"name": "thelia/re-captcha-module",
|
||||||
|
"license": "LGPL-3.0+",
|
||||||
|
"type": "thelia-module",
|
||||||
|
"require": {
|
||||||
|
"thelia/installer": "~1.1"
|
||||||
|
},
|
||||||
|
"extra": {
|
||||||
|
"installer-name": "ReCaptcha"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
{extends file="admin-layout.tpl"}
|
||||||
|
|
||||||
|
{block name="after-bootstrap-css"}
|
||||||
|
<style>
|
||||||
|
.recaptcha_radio {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{/block}
|
||||||
|
|
||||||
|
{block name="no-return-functions"}
|
||||||
|
{$admin_current_location = 'module'}
|
||||||
|
{/block}
|
||||||
|
|
||||||
|
{block name="page-title"}{intl l='ReCaptcha module configuration' d='recaptcha.bo.default'}{/block}
|
||||||
|
|
||||||
|
{block name="check-resource"}admin.module{/block}
|
||||||
|
{block name="check-access"}view{/block}
|
||||||
|
{block name="check-module"}ReCaptcha{/block}
|
||||||
|
|
||||||
|
{block name="main-content"}
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h4 class="panel-title">
|
||||||
|
{intl l="ReCaptcha configuration" d='recaptcha.bo.default'}
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
{form name="recaptcha_configuration.form"}
|
||||||
|
<form action="{url path="/admin/module/recaptcha/configuration"}" method="post">
|
||||||
|
{form_hidden_fields form=$form}
|
||||||
|
|
||||||
|
{if $form_error}
|
||||||
|
<div class="alert alert-danger">{$form_error_message}</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{form_field form=$form field='success_url'}
|
||||||
|
<input type="hidden" name="{$name}" value="{url path={navigate to="current"}}"/>
|
||||||
|
{/form_field}
|
||||||
|
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="row">
|
||||||
|
<h3 class="col-md-12">{intl l="reCAPTCHA access :" d='recaptcha.bo.default'}</h3>
|
||||||
|
<div class="col-md-6">
|
||||||
|
{render_form_field form=$form field="site_key" value={$data}}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
{render_form_field form=$form field="secret_key" value={$data}}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-12">
|
||||||
|
{render_form_field form=$form field="captcha_style" value={$data}}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-12">
|
||||||
|
<p>{intl l="These infos are available here : " d='recaptcha.bo.default'}<a href="http://www.google.com/recaptcha/admin">http://www.google.com/recaptcha/admin</a></p>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-12">
|
||||||
|
<input type="submit" class="btn btn-success form-control">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
{/form}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/block}
|
||||||
|
|
||||||
|
{block name="javascript-initialization"}
|
||||||
|
|
||||||
|
{/block}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<script src="https://www.google.com/recaptcha/api.js?hl={lang attr="code"}" async defer></script>
|
||||||
|
<script>
|
||||||
|
window.onload = function() {
|
||||||
|
var captchaDiv = document.getElementById("recaptcha-invisible");
|
||||||
|
if (captchaDiv !== null) {
|
||||||
|
var form = captchaDiv.parentElement;
|
||||||
|
|
||||||
|
form.addEventListener("submit", function(event) {
|
||||||
|
if (!grecaptcha.getResponse()) {
|
||||||
|
event.preventDefault(); //prevent form submit
|
||||||
|
grecaptcha.execute();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onCompleted = function() {
|
||||||
|
if (form.reportValidity() !== false) {
|
||||||
|
form.submit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -34,6 +34,7 @@
|
|||||||
{intl l="Send us a message"}
|
{intl l="Send us a message"}
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
|
{if $form_error}<div class="alert alert-danger">{$form_error_message}</div>{/if}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{form_field field="name"}
|
{form_field field="name"}
|
||||||
<div class="form-group group-name col-sm-6{if $error} has-error{/if}">
|
<div class="form-group group-name col-sm-6{if $error} has-error{/if}">
|
||||||
@@ -89,6 +90,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
{hook name="recaptcha.check"}
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
|
||||||
{hook name="contact.form-bottom"}
|
{hook name="contact.form-bottom"}
|
||||||
|
|
||||||
<div class="form-group group-btn">
|
<div class="form-group group-btn">
|
||||||
|
|||||||
@@ -306,6 +306,10 @@
|
|||||||
</div><!--/.form-group-->
|
</div><!--/.form-group-->
|
||||||
{/form_field}
|
{/form_field}
|
||||||
|
|
||||||
|
<div class="control-btn col-sm-5 col-sm-offset-3">
|
||||||
|
{hook name="recaptcha.check"}
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
{hook name="register.form-bottom"}
|
{hook name="register.form-bottom"}
|
||||||
|
|
||||||
<div class="form-group group-btn">
|
<div class="form-group group-btn">
|
||||||
|
|||||||
Reference in New Issue
Block a user