From 2583147a7c65b27bf3ae362c661044cf8c837587 Mon Sep 17 00:00:00 2001 From: pbarroca <pbarroca@afi-sa.fr> Date: Fri, 25 Sep 2015 16:31:04 +0200 Subject: [PATCH] rel #29524 : add CNIL consent to cookies --- VERSIONS_HOTLINE/29524 | 1 + .../opac/controllers/IndexController.php | 2 + library/Class/Cnil.php | 82 ++++++++++++++++++ library/Class/ScriptLoader.php | 8 +- .../opac/controllers/IndexControllerTest.php | 85 ++++++++++++++++++- 5 files changed, 170 insertions(+), 8 deletions(-) create mode 100644 VERSIONS_HOTLINE/29524 create mode 100644 library/Class/Cnil.php diff --git a/VERSIONS_HOTLINE/29524 b/VERSIONS_HOTLINE/29524 new file mode 100644 index 00000000000..f9a57032f24 --- /dev/null +++ b/VERSIONS_HOTLINE/29524 @@ -0,0 +1 @@ + - ticket #29524 : Mise en conformité CNIL sur les cookies de traçage \ No newline at end of file diff --git a/application/modules/opac/controllers/IndexController.php b/application/modules/opac/controllers/IndexController.php index f5e211b6db2..38c0a43e1b7 100644 --- a/application/modules/opac/controllers/IndexController.php +++ b/application/modules/opac/controllers/IndexController.php @@ -25,6 +25,8 @@ class IndexController extends Zend_Controller_Action { $viewRenderer = $this->getHelper('ViewRenderer'); $viewRenderer->setLayoutScript('portail.phtml'); + (new Class_Cnil())->trackConsent(); + if (array_keys($this->getRequest()->getParams()) == ['controller', 'action', 'module', 'current_module', 'q']) { $this->_redirect('recherche?'.http_build_query(['q' => $this->_getParam('q')])); } diff --git a/library/Class/Cnil.php b/library/Class/Cnil.php new file mode 100644 index 00000000000..bb1b8a4cc1e --- /dev/null +++ b/library/Class/Cnil.php @@ -0,0 +1,82 @@ +<?php +/** + * Copyright (c) 2012-2014, 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_Cnil { + use Trait_Translator, Trait_TimeSource; + + protected static $_cookie_jar; + + protected $_key, $_session; + + + /** @category testing */ + public static function setCookieJar($cookie_jar) { + static::$_cookie_jar = $cookie_jar; + } + + + public function __construct() { + $this->_key = 'cnil' . md5(BASE_URL); + $this->_session = new Zend_Session_Namespace($this->_key); + if (isset($_COOKIE[$this->_key])) + $this->_session->seen = true; + } + + + public function trackConsent() { + if ($this->_session->seen) + return; + + $this->_session->seen = true; + $this->_setConsentCookie(); + $this->_displayMessage(); + } + + + protected function _setConsentCookie() { + $this->_getCookieJar() + ->setcookie($this->_key, + '1', + $this->getTimeSource()->time() + (3600 * 24 * 30 *13)); + } + + + protected function _displayMessage() { + Class_ScriptLoader::getInstance() + ->notify($this->_('En poursuivant votre navigation sur ce site, vous acceptez l\'utilisation de cookies.'), + false); + } + + + protected function _getCookieJar() { + return static::$_cookie_jar ? + static::$_cookie_jar : new Class_Cnil_CookieJar(); + } +} + + + +class Class_Cnil_CookieJar { + public function setcookie() { + call_user_func_array('setcookie', func_get_args()); + } +} \ No newline at end of file diff --git a/library/Class/ScriptLoader.php b/library/Class/ScriptLoader.php index a1fb35f6120..d2672af2a21 100644 --- a/library/Class/ScriptLoader.php +++ b/library/Class/ScriptLoader.php @@ -326,14 +326,14 @@ class Class_ScriptLoader { * voir [[file:~/public_html/afi-opac3/library/ZendAfi/Controller/Action/Helper/Notify.php::class%20ZendAfi_Controller_Action_Helper_Notify%20extends%20Zend_Controller_Action_Helper_Abstract%20{][ZendAfi_Controller_Action_Helper_Notify]] * @return ScriptLoader */ - public function notify($message) { + public function notify($message, $autoclose=true, $duration=10, $type='information') { return $this ->loadNotificationJS() ->addJQueryReady(sprintf('showNotification(%s)', json_encode(array('message' => $message, - 'autoClose' => true, - 'duration' => 10, - 'type' => 'information')))); + 'autoClose' => $autoclose, + 'duration' => $duration, + 'type' => $type)))); } diff --git a/tests/application/modules/opac/controllers/IndexControllerTest.php b/tests/application/modules/opac/controllers/IndexControllerTest.php index 6ad8cab0275..6638f456d36 100644 --- a/tests/application/modules/opac/controllers/IndexControllerTest.php +++ b/tests/application/modules/opac/controllers/IndexControllerTest.php @@ -18,9 +18,9 @@ * along with BOKEH; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -class IndexControllerSetupDomainTest extends AbstractControllerTestCase { +class IndexControllerSetupDomainTest extends AbstractControllerTestCase { public function setUp() { parent::setUp(); Class_Adminvar::beVolatile(); @@ -57,8 +57,6 @@ class IndexControllerSetupDomainTest extends AbstractControllerTestCase { class IndexControllerAsInviteTest extends AbstractControllerTestCase { - - protected function _loginHook($account) { $account->ROLE_LEVEL = ZendAfi_Acl_AdminControllerRoles::INVITE; } @@ -126,7 +124,6 @@ class IndexControllerAsAdminWithCssEditorAndNoHeaderCss extends IndexControllerA - class IndexControllerAsAdminWithCSSEditorTest extends IndexControllerAsAdminTestCase { public function setUp() { parent::setUp(); @@ -149,6 +146,7 @@ class IndexControllerAsAdminWithCSSEditorTest extends IndexControllerAsAdminTest } + class IndexControllerWithInvitedLevelRestrictionForProfilTest extends AbstractControllerTestCase { public function setup() { parent::setup(); @@ -313,4 +311,83 @@ class IndexControllerRewriteUrlTest extends AbstractControllerTestCase { $this->assertController('auth'); $this->assertAction('login'); } +} + + + +abstract class IndexControllerCnilTrackingTestCase extends AbstractControllerTestCase { + protected $_storm_default_to_volatile = true; + protected $_expected_message = 'showNotification({"message":"En poursuivant votre navigation sur ce site, vous acceptez l\'utilisation de cookies.","autoClose":false'; + + public function tearDown() { + Class_Cnil::setCookieJar(null); + Class_Cnil::setTimeSource(null); + parent::tearDown(); + } +} + + + +class IndexControllerCnilTrackingFirstVisitTest + extends IndexControllerCnilTrackingTestCase { + + protected $_cookie_jar; + + public function setUp() { + parent::setUp(); + + Class_Cnil::setTimeSource($this->mock() + ->whenCalled('time') + ->answers(strtotime('2015-09-25 15:45:54'))); + + Class_Cnil::setCookieJar($this->_cookie_jar = $this->mock() + ->whenCalled('setcookie') + ->with('cnil8801b6c24c4d369a55a96252ed121d5c', + 1, + 1476884754) + ->answers(null)); + + $this->dispatch('/', true); + } + + + /** @test */ + public function shouldDisplayCnilMessage() { + $this->assertXPathContentContains('//script', $this->_expected_message); + } + + + /** @test */ + public function shouldSetCnilCookieFor13Months() { + $this->assertTrue($this->_cookie_jar->methodHasBeenCalled('setcookie')); + } +} + + + +class IndexControllerCnilTrackingSecondVisitTest + extends IndexControllerCnilTrackingTestCase { + + /** @test */ + public function shouldNotDisplayCnilMessage() { + $this->dispatch('/', true); + $this->_response->setBody(''); + Class_ScriptLoader::resetInstance(); + + $this->dispatch('/', true); + $this->assertNotXPathContentContains('//script', $this->_expected_message); + } +} + + + +class IndexControllerCnilTrackingExistingCookieVisitTest + extends IndexControllerCnilTrackingTestCase { + + /** @test */ + public function shouldNotDisplayCnilMessage() { + $_COOKIE['cnil' . md5(BASE_URL)] = 1; + $this->dispatch('/', true); + $this->assertNotXPathContentContains('//script', $this->_expected_message); + } } \ No newline at end of file -- GitLab