From 294f8393d7d20dfe85815349ac40666467ba780c Mon Sep 17 00:00:00 2001 From: Chris Hallberg <crhallberg@gmail.com> Date: Fri, 2 Sep 2016 13:42:46 -0400 Subject: [PATCH] ReCaptcha checking for user comments (#784) --- config/vufind/config.ini | 2 +- .../src/VuFind/Controller/AjaxController.php | 10 +++++++++ .../VuFind/Controller/Plugin/Recaptcha.php | 4 ++-- .../VuFind/src/VuFind/RecordTab/Factory.php | 9 +++++++- .../src/VuFind/RecordTab/UserComments.php | 21 ++++++++++++++++++- .../src/VuFind/View/Helper/Root/Recaptcha.php | 6 +++++- themes/bootstrap3/js/lightbox.js | 7 ++++++- themes/bootstrap3/js/record.js | 15 +++++++++++-- .../templates/RecordTab/usercomments.phtml | 5 ++++- 9 files changed, 69 insertions(+), 10 deletions(-) diff --git a/config/vufind/config.ini b/config/vufind/config.ini index 53e74537f5a..a2259287231 100644 --- a/config/vufind/config.ini +++ b/config/vufind/config.ini @@ -1459,7 +1459,7 @@ treeSearchLimit = 100 ;secretKey = "https://www.google.com/recaptcha/admin/create" ; Valid theme values: dark, light ;theme = light -; Valid forms values: changePassword, email, feedback, newAccount, passwordRecovery, sms +; Valid forms values: changePassword, email, feedback, newAccount, passwordRecovery, sms, userComments ; Use * for all supported forms ;forms = changePassword, email, newAccount, passwordRecovery, sms diff --git a/module/VuFind/src/VuFind/Controller/AjaxController.php b/module/VuFind/src/VuFind/Controller/AjaxController.php index 6cfe77954e7..98c7b7f50d4 100644 --- a/module/VuFind/src/VuFind/Controller/AjaxController.php +++ b/module/VuFind/src/VuFind/Controller/AjaxController.php @@ -1086,6 +1086,16 @@ class AjaxController extends AbstractBase ); } + $useCaptcha = $this->recaptcha()->active('userComments'); + $this->recaptcha()->setErrorMode('none'); + if (!$this->formWasSubmitted('comment', $useCaptcha)) { + return $this->output( + $this->translate('recaptcha_not_passed'), + self::STATUS_ERROR, + 403 + ); + } + $table = $this->getTable('Resource'); $resource = $table->findResource( $id, $this->params()->fromPost('source', DEFAULT_SEARCH_BACKEND) diff --git a/module/VuFind/src/VuFind/Controller/Plugin/Recaptcha.php b/module/VuFind/src/VuFind/Controller/Plugin/Recaptcha.php index 01474bdedad..bd3591b8fa3 100644 --- a/module/VuFind/src/VuFind/Controller/Plugin/Recaptcha.php +++ b/module/VuFind/src/VuFind/Controller/Plugin/Recaptcha.php @@ -90,7 +90,7 @@ class Recaptcha extends AbstractPlugin */ public function setErrorMode($mode) { - if (in_array($mode, ['flash', 'throw'])) { + if (in_array($mode, ['flash', 'throw', 'none'])) { $this->errorMode = $mode; return true; } @@ -125,7 +125,7 @@ class Recaptcha extends AbstractPlugin $response = false; } $captchaPassed = $response && $response->isValid(); - if (!$captchaPassed) { + if (!$captchaPassed && $this->errorMode != 'none') { if ($this->errorMode == 'flash') { $this->getController()->flashMessenger() ->addMessage('recaptcha_not_passed', 'error'); diff --git a/module/VuFind/src/VuFind/RecordTab/Factory.php b/module/VuFind/src/VuFind/RecordTab/Factory.php index 94fd9107b49..82e6fa835cc 100644 --- a/module/VuFind/src/VuFind/RecordTab/Factory.php +++ b/module/VuFind/src/VuFind/RecordTab/Factory.php @@ -262,6 +262,13 @@ class Factory public static function getUserComments(ServiceManager $sm) { $capabilities = $sm->getServiceLocator()->get('VuFind\AccountCapabilities'); - return new UserComments('enabled' === $capabilities->getCommentSetting()); + $config = $sm->getServiceLocator()->get('VuFind\Config')->get('config'); + $useRecaptcha = isset($config->Captcha) && isset($config->Captcha->forms) + && (trim($config->Captcha->forms) === '*' + || strpos($config->Captcha->forms, 'userComments')); + return new UserComments( + 'enabled' === $capabilities->getCommentSetting(), + $useRecaptcha + ); } } diff --git a/module/VuFind/src/VuFind/RecordTab/UserComments.php b/module/VuFind/src/VuFind/RecordTab/UserComments.php index af5d219352d..9bbede39072 100644 --- a/module/VuFind/src/VuFind/RecordTab/UserComments.php +++ b/module/VuFind/src/VuFind/RecordTab/UserComments.php @@ -45,14 +45,33 @@ class UserComments extends AbstractBase */ protected $enabled; + /** + * Is this tab enabled? + * + * @var bool + */ + protected $useRecaptcha; + /** * Constructor * * @param bool $enabled is this tab enabled? + * @param bool $urc use recaptcha? */ - public function __construct($enabled = true) + public function __construct($enabled = true, $urc = false) { $this->enabled = $enabled; + $this->useRecaptcha = $urc; + } + + /** + * Is Recaptcha active? + * + * @return bool + */ + public function isRecaptchaActive() + { + return $this->useRecaptcha; } /** diff --git a/module/VuFind/src/VuFind/View/Helper/Root/Recaptcha.php b/module/VuFind/src/VuFind/View/Helper/Root/Recaptcha.php index ee5e6848dad..b919aa7e877 100644 --- a/module/VuFind/src/VuFind/View/Helper/Root/Recaptcha.php +++ b/module/VuFind/src/VuFind/View/Helper/Root/Recaptcha.php @@ -93,14 +93,18 @@ class Recaptcha extends AbstractHelper * Generate <div> with ReCaptcha from render. * * @param boolean $useRecaptcha Boolean of active state, for compact templating + * @param boolean $wrapHtml Include prefix and suffix? * * @return string $html */ - public function html($useRecaptcha = true) + public function html($useRecaptcha = true, $wrapHtml = true) { if (!isset($useRecaptcha) || !$useRecaptcha) { return false; } + if (!$wrapHtml) { + return $this->recaptcha->getHtml(); + } return $this->prefixHtml . $this->recaptcha->getHtml() . $this->suffixHtml; } diff --git a/themes/bootstrap3/js/lightbox.js b/themes/bootstrap3/js/lightbox.js index c55eca08277..c09c436a436 100644 --- a/themes/bootstrap3/js/lightbox.js +++ b/themes/bootstrap3/js/lightbox.js @@ -1,4 +1,4 @@ -/*global VuFind */ +/*global grecaptcha, VuFind */ VuFind.register('lightbox', function Lightbox() { // State var _originalUrl = false; @@ -101,6 +101,11 @@ VuFind.register('lightbox', function Lightbox() { $('#modal').find('.checkbox-select-item').change(function lbSelectAllDisable() { $(this).closest('.modal-body').find('.checkbox-select-all').prop('checked', false); }); + // Recaptcha + var modalCaptcha = $('#modal .g-recaptcha'); + if (modalCaptcha.length && typeof grecaptcha !== 'undefined' && modalCaptcha.is(':empty')) { + grecaptcha.render(modalCaptcha[0], modalCaptcha[0].dataset); + } } var _xhr = false; diff --git a/themes/bootstrap3/js/record.js b/themes/bootstrap3/js/record.js index 5dd139dc00e..863968bc504 100644 --- a/themes/bootstrap3/js/record.js +++ b/themes/bootstrap3/js/record.js @@ -1,4 +1,4 @@ -/*global deparam, syn_get_widget, userIsLoggedIn, VuFind */ +/*global deparam, grecaptcha, syn_get_widget, userIsLoggedIn, VuFind */ /*exported ajaxTagUpdate, recordDocReady */ /** @@ -78,6 +78,9 @@ function refreshCommentList($target, recordId, recordSource) { return false; }); $target.find('.comment-form input[type="submit"]').button('reset'); + if (typeof grecaptcha !== 'undefined') { + grecaptcha.reset(); + } }); } @@ -93,6 +96,14 @@ function registerAjaxCommentRecord() { id: id, source: recordSource }; + if (typeof grecaptcha !== 'undefined') { + try { + data['g-recaptcha-response'] = grecaptcha.getResponse(0); + } catch (e) { + console.error('Expected errors: placeholder element full and Invalid client ID'); + console.error(e); + } + } $.ajax({ type: 'POST', url: url, @@ -107,7 +118,7 @@ function registerAjaxCommentRecord() { }) .fail(function addCommentFail(response, textStatus) { if (textStatus === 'abort' || typeof response.responseJSON === 'undefined') { return; } - VuFind.lightbox.update(response.responseJSON.data); + VuFind.lightbox.alert(response.responseJSON.data, 'danger'); }); return false; }); diff --git a/themes/bootstrap3/templates/RecordTab/usercomments.phtml b/themes/bootstrap3/templates/RecordTab/usercomments.phtml index 2236461e4e7..4bd7cb6e88b 100644 --- a/themes/bootstrap3/templates/RecordTab/usercomments.phtml +++ b/themes/bootstrap3/templates/RecordTab/usercomments.phtml @@ -6,7 +6,7 @@ <div class="comment-list"> <?=$this->render('record/comments-list.phtml')?> </div> -<form class="comment-form row" name="commentRecord" action="<?=$this->recordLink()->getActionUrl($this->driver, 'AddComment')?>" method="post"> +<form class="comment-form" name="commentRecord" action="<?=$this->recordLink()->getActionUrl($this->driver, 'AddComment')?>" method="post"> <div class="row"> <div class="col-sm-3 name"> <input type="hidden" name="id" value="<?=$this->escapeHtmlAttr($this->driver->getUniqueId())?>"/> @@ -17,6 +17,9 @@ <? $user = $this->auth()->isLoggedIn() ?> <? if($user): ?> <textarea name="comment" class="form-control" rows="3" required></textarea><br/> + <? if ($this->tab->isRecaptchaActive()): ?> + <?=$this->recaptcha()->html(true, false) ?><br/> + <? endif; ?> <input class="btn btn-primary" data-loading-text="<?=$this->transEsc('Submitting') ?>..." type="submit" value="<?=$this->transEsc("Add your comment")?>"/> <? else: ?> <a href="<?=$this->url('myresearch-userlogin') ?>" class="btn btn-primary" data-lightbox title="Login"><i class="fa fa-sign-in" aria-hidden="true"></i> <?=$this->transEsc("You must be logged in first") ?></a> -- GitLab