Skip to content
Snippets Groups Projects
Commit f65171ee authored by Patrick Barroca's avatar Patrick Barroca :grin:
Browse files

Merge branch 'hotline#106221_formulaire' into 'hotline'

hotline #106221 article forms : check that required input have value in post

See merge request !3553
parents 94d387d9 8211a50e
Branches
Tags 8.0.68
1 merge request!3553hotline #106221 article forms : check that required input have value in post
Pipeline #10444 passed with stage
in 52 minutes and 51 seconds
- ticket #106221 : Formulaires dans les articles : renforcement de la détection des bots
\ No newline at end of file
......@@ -24,9 +24,17 @@ class FormulaireController extends ZendAfi_Controller_Action {
$post = $this->_request->getPost();
if ($this->_isPostFromBot($post, $article))
$form_post = new Class_Formulaire_Post($post, $article);
if ($form_post->isBot())
return $this->_redirect('/');
if (!$form_post->isValid()) {
array_map([$this->_helper, 'notify'],
$form_post->getErrors());
$this->_redirectToReferer();
}
unset($post['website']);
$formulaire = new Class_Formulaire();
$formulaire->setData(serialize($post))
......@@ -44,32 +52,6 @@ class FormulaireController extends ZendAfi_Controller_Action {
}
protected function _isPostFromBot($post, $article) {
if ($this->_getParam('website'))
return true;
$quote = '[\"\']';
$no_quotes = '([^\"\']+)';
$quoted_value = $quote.$no_quotes.$quote;
preg_match_all('/ name='.$quoted_value.'/',
$article->getContenu(),
$all_inputs);
$clean_input = array_map(function($input)
{
return str_replace(['.',' ','['],
'_',
$input);
},
$all_inputs[1]);
if (array_diff(array_keys($post), $clean_input))
return true;
return false;
}
protected function _sendFormEmail($address, $body) {
$mail = new ZendAfi_Mail('utf8');
$mail->setFrom(Class_Profil::getCurrentProfil()->getMailSiteOrPortail())
......
<?php
/**
* Copyright (c) 2012-2020, Agence Française Informatique (AFI). All rights reserved.
*
* BOKEH is free software; you can redistribute it and/or modify
* it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
* the Free Software Foundation.
*
* There are special exceptions to the terms and conditions of the AGPL as it
* is applied to this software (see README file).
*
* BOKEH is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
* along with BOKEH; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
class Class_Formulaire_Post {
use Trait_Translator;
protected
$_article,
$_post,
$_regex_quoted_value,
$_errors = [];
public function __construct($post, $article) {
$this->_post = $post;
$this->_article = $article;
$quote = '[\"\']';
$no_quotes = '([^\"\']+)';
$this->_regex_quoted_value = $quote.$no_quotes.$quote;
}
public function isBot() {
return !($this->_isInvisibleCaptchaValid()
&&
$this->_allPostValuesDefinedInArticle());
}
public function isValid() {
$missing_required = $this->_allMissingRequiredInputInPost();
foreach($missing_required as $input_name)
$this->_errors []= $this->_('Le champ %s est requis', $input_name);
return empty($this->_errors);
}
public function getErrors() {
return $this->_errors;
}
protected function _allMissingRequiredInputInPost() {
preg_match_all('/ name='.$this->_regex_quoted_value.'[^>]+required=/',
$this->_article->getContenu(),
$all_required_inputs);
return array_diff($this->_normalizePhpInputNames($all_required_inputs[1]),
array_keys($this->_post));
}
protected function _allPostValuesDefinedInArticle() {
preg_match_all('/ name='.$this->_regex_quoted_value.'/',
$this->_article->getContenu(),
$all_inputs);
return array_diff(array_keys($this->_post),
$this->_normalizePhpInputNames($all_inputs[1]))
? false
: true;
}
/**
* @see https://www.php.net/manual/en/language.variables.external.php
* Dots and spaces and [ in variable names are converted to underscores. For example <input name="a.b" /> becomes $_REQUEST["a_b"].
*/
protected function _normalizePhpInputNames($input_names) {
return array_map(function($input)
{
return str_replace(['.',' ','['],
'_',
$input);
},
$input_names);
}
protected function _isInvisibleCaptchaValid() {
if (!isset($this->_post['website']))
return false;
if ($this->_post['website'])
return false;
return true;
}
}
\ No newline at end of file
......@@ -68,7 +68,9 @@ class FormulaireControllerWithEmailPostActionTest extends FormulaireControllerPo
$this->postDispatch('/formulaire/add/id_article/45',
['nom' => 'Tinguette' ,
'prenom' => 'Quentin' ],
'prenom' => 'Quentin',
'website' => '',
'Dejeuner' => 'Libre'],
true);
$this->new_formulaire = Class_Formulaire::find(2);
......@@ -124,7 +126,8 @@ class FormulaireControllerPostActionTest extends FormulaireControllerPostActionT
$this->postDispatch('/formulaire/add/id_article/45',
['nom' => 'Tinguette' ,
'prenom' => 'Quentin',
'website' => ''],
'website' => '',
'Dejeuner' => 'Libre'],
true);
$this->new_formulaire = Class_Formulaire::find(2);
......@@ -144,9 +147,10 @@ class FormulaireControllerPostActionTest extends FormulaireControllerPostActionT
/** @test */
public function getDataShouldAnswerSerializedNomPrenom() {
public function getDataShouldAnswerSerializedNomPrenomDejeuner() {
$this->assertEquals(serialize(['nom' => 'Tinguette' ,
'prenom' => 'Quentin']),
'prenom' => 'Quentin',
'Dejeuner' => 'Libre']),
$this->new_formulaire->getData());
}
......@@ -192,7 +196,9 @@ class FormulaireControllerWithoutConnectedUserPostActionTest extends FormulaireC
ZendAfi_Auth::getInstance()->clearIdentity();
$this->postDispatch('/formulaire/add/id_article/45',
['nom' => 'Tinguette' ,
'prenom' => 'Quentin' ],
'prenom' => 'Quentin',
'website' => '',
'Dejeuner' => 'Libre'],
true);
$this->new_formulaire = Class_Formulaire::find(2);
......@@ -236,6 +242,7 @@ class FormulaireControllerPostAsBotTest extends FormulaireControllerPostActionTe
$this->postDispatch('/formulaire/add/id_article/45',
['nom' => 'Tinguette' ,
'prenom' => 'Quentin',
'Dejeuner' => 'libre',
'whoareyou' => 'i am a bot'],
true);
......@@ -255,7 +262,42 @@ class FormulaireControllerPostAsBotTest extends FormulaireControllerPostActionTe
true);
$this->assertNotRedirectTo('/');
}
}
class FormulaireControllerPostWithoutRequiredTest extends FormulaireControllerPostActionTestCase {
public function setUp() {
parent::setUp();
$_SERVER['HTTP_REFERER'] = '/viewarticle/id/45';
$this->postDispatch('/formulaire/add/id_article/45',
['nom' => 'Tinguette' ,
'prenom' => 'Quentin',
'option1' => 'cafe',
'option2' => 'wifi',
'website' => ''],
true);
}
/** @test */
public function responseShouldNotifyFieldRequired() {
$this->assertFlashMessengerContentContains('Le champ Dejeuner est requis');
}
/** @test */
public function pageShouldRedirectToReferer() {
$this->assertRedirectTo('/viewarticle/id/45');
}
public function tearDown() {
unset($_SERVER['HTTP_REFERER']);
parent::tearDown();
}
}
......@@ -338,10 +380,16 @@ class FormulaireControllerPostActionDebugTestCase extends AbstractControllerTest
true);
}
/** @test */
/** @test */
public function responseShouldNotRedirect() {
$this->assertNotRedirectTo('/');
}
/** @test */
public function pageShouldContainsShouldFormRecorded() {
$this->assertXPathContentContains('//h2', 'Merci. Le formulaire a bien été enregistré');
}
}
?>
\ No newline at end of file
......@@ -36,7 +36,8 @@ class Telephone_FormulaireControllerPostActionTestCase extends TelephoneAbstract
$this->postDispatch('/formulaire/add/id_article/45',
['nom' => 'Tinguette' ,
'prenom' => 'Quentin' ]
'prenom' => 'Quentin',
'website' => '' ]
,true);
$this->new_formulaire = Class_Formulaire::find(1);
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment