Rajout du module ReCaptcha
This commit is contained in:
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],
|
||||
];
|
||||
}
|
||||
}
|
||||
54
local/modules/ReCaptcha/Config/config.xml
Normal file
54
local/modules/ReCaptcha/Config/config.xml
Normal file
@@ -0,0 +1,54 @@
|
||||
<?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>
|
||||
<service id="thelia.form_validator" class="ReCaptcha\Form\MyTheliaFormValidator">
|
||||
<argument type="service" id="thelia.translator" />
|
||||
<argument>%kernel.environment%</argument>
|
||||
<argument type="service" id="event_dispatcher" />
|
||||
</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";
|
||||
}
|
||||
}
|
||||
37
local/modules/ReCaptcha/Form/MyTheliaFormValidator.php
Normal file
37
local/modules/ReCaptcha/Form/MyTheliaFormValidator.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace ReCaptcha\Form;
|
||||
|
||||
use ReCaptcha\Event\ReCaptchaCheckEvent;
|
||||
use ReCaptcha\Event\ReCaptchaEvents;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\Translation\TranslatorInterface;
|
||||
use Thelia\Form\BaseForm;
|
||||
use Thelia\Form\Exception\FormValidationException;
|
||||
|
||||
class MyTheliaFormValidator extends \Thelia\Core\Form\TheliaFormValidator
|
||||
{
|
||||
/** @var EventDispatcherInterface */
|
||||
protected $dispatcher;
|
||||
|
||||
public function __construct(TranslatorInterface $translator, $environment, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$this->dispatcher = $dispatcher;
|
||||
|
||||
parent::__construct($translator, $environment);
|
||||
}
|
||||
|
||||
public function validateForm(BaseForm $aBaseForm, $expectedMethod = null)
|
||||
{
|
||||
if ($aBaseForm->getRequest()->get('captcha')) {
|
||||
$checkCaptchaEvent = new ReCaptchaCheckEvent();
|
||||
$this->dispatcher->dispatch(ReCaptchaEvents::CHECK_CAPTCHA_EVENT, $checkCaptchaEvent);
|
||||
if ($checkCaptchaEvent->isHuman() == false) {
|
||||
throw new FormValidationException('Veuillez confirmer que vous n\'êtes pas un robot.');
|
||||
}
|
||||
}
|
||||
|
||||
return parent::validateForm($aBaseForm, $expectedMethod); // TODO: Change the autogenerated stub
|
||||
}
|
||||
|
||||
}
|
||||
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><input type='hidden' name='captcha' value='captcha'>");
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -91,6 +91,7 @@
|
||||
|
||||
<div class="form-group group-btn">
|
||||
<div class="control-btn">
|
||||
{hook name="recaptcha.check"}
|
||||
<button type="submit" class="btn btn-primary"><i class="fa fa-chevron-right"></i> {intl l="Send"}</button>
|
||||
</div>
|
||||
</div><!--/.form-group-->
|
||||
|
||||
@@ -309,25 +309,11 @@
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
{form_field field="newsletter"}
|
||||
<div class="form-group group-newsletter{if $error} has-error{/if}">
|
||||
<div class="control-input col-xs-11 col-sm-9 col-xs-offset-1 col-md-offset-3">
|
||||
<div class="checkbox">
|
||||
<label class="control-label" for="{$label_attr.for}">
|
||||
<input type="checkbox" name="{$name}" id="{$label_attr.for}" value="{$value}"{if $checked} checked{/if} {if $required} aria-required="true" required{/if}>{$label}
|
||||
</label>
|
||||
{if $error }
|
||||
<span class="help-block">{$message}</span>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div><!--/.form-group-->
|
||||
{/form_field}
|
||||
|
||||
{hook name="register.form-bottom"}
|
||||
|
||||
<div class="form-group group-btn">
|
||||
<div class="control-btn col-sm-5 col-sm-offset-3">
|
||||
{hook name="recaptcha.check"}
|
||||
<button type="submit" class="btn btn-primary"><i class="fa fa-chevron-right"></i> {intl l="Register"}</button>
|
||||
</div>
|
||||
</div><!--/.form-group-->
|
||||
|
||||
Reference in New Issue
Block a user