Implement remainder of reCAPTCHA functionality in spamfilter module

This commit is contained in:
Kijin Sung 2020-10-01 15:19:01 +09:00
parent c7c03d3c37
commit 4f888acc9e
3 changed files with 135 additions and 1 deletions

View file

@ -15,6 +15,7 @@ class spamfilter extends ModuleObject
array('comment.updateComment', 'before', 'controller', 'triggerInsertComment'), array('comment.updateComment', 'before', 'controller', 'triggerInsertComment'),
array('trackback.insertTrackback', 'before', 'controller', 'triggerInsertTrackback'), array('trackback.insertTrackback', 'before', 'controller', 'triggerInsertTrackback'),
array('communication.sendMessage', 'before', 'controller', 'triggerSendMessage'), array('communication.sendMessage', 'before', 'controller', 'triggerSendMessage'),
array('moduleObject.proc', 'before', 'controller', 'triggerCheckCaptcha'),
); );
protected static $_delete_triggers = array(); protected static $_delete_triggers = array();

View file

@ -7,6 +7,17 @@
*/ */
class spamfilterController extends spamfilter class spamfilterController extends spamfilter
{ {
/**
* List of actions to use CAPTCHA.
*/
protected static $_captcha_actions = array(
'signup' => '/^(?:disp|proc)Member(?:SignUp|Insert)/i',
'login' => '/^(?:disp|proc)MemberLogin(?:Form)?/i',
'recovery' => '/^(?:disp|proc)Member(?:FindAccount|ResendAuthMail)/i',
'document' => '/^(?:disp|proc)Board(Write|InsertDocument)/i',
'comment' => '/^(?:disp|proc)Board(Content|InsertComment)/i',
);
/** /**
* @brief Initialization * @brief Initialization
*/ */
@ -231,7 +242,62 @@ class spamfilterController extends spamfilter
{ {
$this->setAvoidLog(); $this->setAvoidLog();
} }
/**
* Trigger to check CAPTCHA.
*/
function triggerCheckCaptcha(&$obj)
{
$config = ModuleModel::getModuleConfig('spamfilter');
if (!isset($config) || !isset($config->captcha) || $config->captcha->type !== 'recaptcha')
{
return;
}
if ($this->user->is_admin === 'Y')
{
return;
}
if ($config->captcha->target_users !== 'everyone' && $this->user->member_srl)
{
return;
}
if ($config->captcha->target_frequency !== 'every_time' && isset($_SESSION['recaptcha_authenticated']) && $_SESSION['recaptcha_authenticated'])
{
return;
}
if (!$config->captcha->target_devices[Mobile::isFromMobilePhone() ? 'mobile' : 'pc'])
{
return;
}
$enable = false;
foreach (['signup', 'login', 'recovery', 'document', 'comment'] as $action)
{
if ($config->captcha->target_actions[$action])
{
if (preg_match(self::$_captcha_actions[$action], $obj->act) || ($action === 'comment' && !$obj->act && Context::get('document_srl')))
{
$enable = true;
}
}
}
if ($enable)
{
include_once __DIR__ . '/spamfilter.lib.php';
spamfilter_reCAPTCHA::init($config->captcha);
if (strncasecmp('proc', $obj->act, 4) === 0)
{
spamfilter_reCAPTCHA::check();
}
else
{
Context::set('captcha', new spamfilter_reCAPTCHA());
}
}
}
/** /**
* @brief Log registration * @brief Log registration
* Register the newly accessed IP address in the log. In case the log interval is withing a certain time, * Register the newly accessed IP address in the log. In case the log interval is withing a certain time,

View file

@ -0,0 +1,67 @@
<?php
class spamfilter_reCAPTCHA
{
protected static $verify_url = 'https://www.google.com/recaptcha/api/siteverify';
protected static $config = null;
protected static $scripts_added = false;
protected static $instances_inserted = 0;
protected static $sequence = 1;
public static function init($config)
{
self::$config = $config;
}
public static function check()
{
$response = Context::get('g-recaptcha-response');
if (!$response)
{
throw new Rhymix\Framework\Exception('recaptcha.msg_recaptcha_invalid_response');
}
try
{
$verify_request = \Requests::post(self::$verify_url, array(), array(
'secret' => self::$config->secret_key,
'response' => $response,
'remoteip' => \RX_CLIENT_IP,
));
}
catch (\Requests_Exception $e)
{
throw new Rhymix\Framework\Exception('recaptcha.msg_recaptcha_connection_error');
}
$verify = @json_decode($verify_request->body, true);
if (!$verify || !$verify['success'])
{
throw new Rhymix\Framework\Exception('recaptcha.msg_recaptcha_server_error');
}
if ($verify && isset($verify['error-codes']) && in_array('invalid-input-response', $verify['error-codes']))
{
throw new Rhymix\Framework\Exception('recaptcha.msg_recaptcha_invalid_response');
}
$_SESSION['recaptcha_authenticated'] = true;
}
public function __construct()
{
if (!self::$scripts_added)
{
self::$scripts_added = true;
Context::loadFile(array('./modules/spamfilter/tpl/js/recaptcha.js', 'body'));
Context::addHtmlFooter('<script src="https://www.google.com/recaptcha/api.js?render=explicit&amp;onload=reCaptchaCallback" async defer></script>');
$html = '<div id="recaptcha-config" data-sitekey="%s" data-theme="%s" data-size="%s"></div>';
$html = sprintf($html, escape(self::$config->site_key), self::$config->theme ?: 'light', self::$config->size ?: 'normal');
Context::addHtmlFooter($html);
}
}
public function __toString()
{
return sprintf('<div id="recaptcha-instance-%d" class="g-recaptcha"></div>', self::$instances_inserted++);
}
}