Reorganize CAPTCHA handling classes #2112

This commit is contained in:
Kijin Sung 2023-06-19 22:27:25 +09:00
parent eb79a5c66f
commit ef77af5a39
6 changed files with 94 additions and 84 deletions

View file

@ -1,6 +1,11 @@
<?php <?php
class spamfilter_captcha namespace Rhymix\Modules\Spamfilter\Captcha;
use Context;
use Rhymix\Framework\Exception;
class reCAPTCHA
{ {
protected static $verify_url = 'https://www.google.com/recaptcha/api/siteverify'; protected static $verify_url = 'https://www.google.com/recaptcha/api/siteverify';
protected static $config = null; protected static $config = null;
@ -19,7 +24,7 @@ class spamfilter_captcha
$response = Context::get('g-recaptcha-response'); $response = Context::get('g-recaptcha-response');
if (!$response) if (!$response)
{ {
throw new Rhymix\Framework\Exception('msg_recaptcha_invalid_response'); throw new Exception('msg_recaptcha_invalid_response');
} }
try try
@ -32,17 +37,17 @@ class spamfilter_captcha
} }
catch (\Requests_Exception $e) catch (\Requests_Exception $e)
{ {
throw new Rhymix\Framework\Exception('msg_recaptcha_connection_error'); throw new Exception('msg_recaptcha_connection_error');
} }
$verify = @json_decode($verify_request->body, true); $verify = @json_decode($verify_request->body, true);
if (!$verify || !$verify['success']) if (!$verify || !$verify['success'])
{ {
throw new Rhymix\Framework\Exception('msg_recaptcha_server_error'); throw new Exception('msg_recaptcha_server_error');
} }
if ($verify && isset($verify['error-codes']) && in_array('invalid-input-response', $verify['error-codes'])) if ($verify && isset($verify['error-codes']) && in_array('invalid-input-response', $verify['error-codes']))
{ {
throw new Rhymix\Framework\Exception('msg_recaptcha_invalid_response'); throw new Exception('msg_recaptcha_invalid_response');
} }
$_SESSION['recaptcha_authenticated'] = true; $_SESSION['recaptcha_authenticated'] = true;

View file

@ -1,6 +1,11 @@
<?php <?php
class spamfilter_captcha namespace Rhymix\Modules\Spamfilter\Captcha;
use Context;
use Rhymix\Framework\Exception;
class Turnstile
{ {
protected static $verify_url = 'https://challenges.cloudflare.com/turnstile/v0/siteverify'; protected static $verify_url = 'https://challenges.cloudflare.com/turnstile/v0/siteverify';
protected static $config = null; protected static $config = null;
@ -19,7 +24,7 @@ class spamfilter_captcha
$response = Context::get('g-recaptcha-response'); $response = Context::get('g-recaptcha-response');
if (!$response) if (!$response)
{ {
throw new Rhymix\Framework\Exception('msg_recaptcha_invalid_response'); throw new Exception('msg_recaptcha_invalid_response');
} }
try try
@ -32,17 +37,17 @@ class spamfilter_captcha
} }
catch (\Requests_Exception $e) catch (\Requests_Exception $e)
{ {
throw new Rhymix\Framework\Exception('msg_recaptcha_connection_error'); throw new Exception('msg_recaptcha_connection_error');
} }
$verify = @json_decode($verify_request->body, true); $verify = @json_decode($verify_request->body, true);
if (!$verify || !$verify['success']) if (!$verify || !$verify['success'])
{ {
throw new Rhymix\Framework\Exception('msg_recaptcha_server_error'); throw new Exception('msg_recaptcha_server_error');
} }
if ($verify && isset($verify['error-codes']) && in_array('invalid-input-response', $verify['error-codes'])) if ($verify && isset($verify['error-codes']) && in_array('invalid-input-response', $verify['error-codes']))
{ {
throw new Rhymix\Framework\Exception('msg_recaptcha_invalid_response'); throw new Exception('msg_recaptcha_invalid_response');
} }
$_SESSION['recaptcha_authenticated'] = true; $_SESSION['recaptcha_authenticated'] = true;
@ -73,6 +78,6 @@ class spamfilter_captcha
public function __toString() public function __toString()
{ {
return sprintf('<div id="recaptcha-instance-%d" class="g-recaptcha"></div>', self::$instances_inserted++); return sprintf('<div id="turnstile-instance-%d" class="turnstile-captcha"></div>', self::$instances_inserted++);
} }
} }

View file

@ -64,7 +64,7 @@ $lang->recaptcha_target_everyone = 'Everyone';
$lang->recaptcha_target_frequency = 'Frequency'; $lang->recaptcha_target_frequency = 'Frequency';
$lang->recaptcha_target_first_time_only = 'First Time Only'; $lang->recaptcha_target_first_time_only = 'First Time Only';
$lang->recaptcha_target_every_time = 'Every Time'; $lang->recaptcha_target_every_time = 'Every Time';
$lang->msg_recaptcha_connection_error = 'An error occurred while connecting to the reCAPTCHA verification server.'; $lang->msg_recaptcha_connection_error = 'An error occurred while connecting to the CAPTCHA verification server.';
$lang->msg_recaptcha_server_error = 'An error occurred while verifying your reCAPTCHA response.'; $lang->msg_recaptcha_server_error = 'An error occurred while verifying your CAPTCHA response.';
$lang->msg_recaptcha_invalid_response = 'Please check reCAPTCHA.'; $lang->msg_recaptcha_invalid_response = 'Please check the CAPTCHA.';
$lang->msg_recaptcha_keys_not_set = 'Please fill in your reCAPTCHA Site Key and Secret Key.'; $lang->msg_recaptcha_keys_not_set = 'Please fill in your CAPTCHA Site Key and Secret Key.';

View file

@ -64,7 +64,7 @@ $lang->recaptcha_target_everyone = '모든 사용자';
$lang->recaptcha_target_frequency = '캡챠 사용 빈도'; $lang->recaptcha_target_frequency = '캡챠 사용 빈도';
$lang->recaptcha_target_first_time_only = '최초 1회만 사용'; $lang->recaptcha_target_first_time_only = '최초 1회만 사용';
$lang->recaptcha_target_every_time = '매번 사용'; $lang->recaptcha_target_every_time = '매번 사용';
$lang->msg_recaptcha_connection_error = 'reCAPTCHA 스팸방지 서버에 접속하는 도중 오류가 발생했습니다.'; $lang->msg_recaptcha_connection_error = '스팸방지 CAPTCHA 서버에 접속하는 도중 오류가 발생했습니다.';
$lang->msg_recaptcha_server_error = 'reCAPTCHA 스팸방지 서버와 통신하는 도중 오류가 발생했습니다.'; $lang->msg_recaptcha_server_error = '스팸방지 CAPTCHA 서버와 통신하는 도중 오류가 발생했습니다.';
$lang->msg_recaptcha_invalid_response = 'reCAPTCHA 스팸방지 기능을 체크해 주십시오.'; $lang->msg_recaptcha_invalid_response = '스팸방지 기능을 체크해 주십시오.';
$lang->msg_recaptcha_keys_not_set = 'reCAPTCHA Site Key 및 Secret Key를 입력하여 주십시오.'; $lang->msg_recaptcha_keys_not_set = 'CAPTCHA Site Key 및 Secret Key를 입력하여 주십시오.';

View file

@ -225,7 +225,7 @@ class spamfilterController extends spamfilter
function triggerCheckCaptcha(&$obj) function triggerCheckCaptcha(&$obj)
{ {
$config = ModuleModel::getModuleConfig('spamfilter'); $config = ModuleModel::getModuleConfig('spamfilter');
if (!isset($config) || !isset($config->captcha) || !in_array($config->captcha->type, ['recaptcha','turnstile']) || !$config->captcha->site_key || !$config->captcha->secret_key) if (!isset($config) || !isset($config->captcha) || !in_array($config->captcha->type, ['recaptcha', 'turnstile']) || !$config->captcha->site_key || !$config->captcha->secret_key)
{ {
return; return;
} }
@ -260,16 +260,16 @@ class spamfilterController extends spamfilter
if (count($target_actions)) if (count($target_actions))
{ {
include_once __DIR__ . '/captcha/' . $config->captcha->type . '.php'; $captcha_class = 'Rhymix\\Modules\\Spamfilter\\Captcha\\' . $config->captcha->type;
spamfilter_captcha::init($config->captcha); $captcha_class::init($config->captcha);
if (strncasecmp('proc', $obj->act, 4) === 0) if (strncasecmp('proc', $obj->act, 4) === 0)
{ {
spamfilter_captcha::check(); $captcha_class::check();
} }
else else
{ {
$captcha = new spamfilter_captcha(); $captcha = new $captcha_class();
$captcha->setTargetActions($target_actions); $captcha->setTargetActions($target_actions);
$captcha->addScripts(); $captcha->addScripts();
Context::set('captcha', $captcha); Context::set('captcha', $captcha);

View file

@ -1,60 +1,60 @@
function turnstileCallback() { function turnstileCallback() {
var recaptcha_config = $("#recaptcha-config"); var recaptcha_config = $("#recaptcha-config");
var recaptcha_instances = $(".g-recaptcha"); var recaptcha_instances = $(".turnstile-captcha");
var recaptcha_instance_id = 1; var recaptcha_instance_id = 1;
var recaptcha_targets = String(recaptcha_config.data("targets")).split(","); var recaptcha_targets = String(recaptcha_config.data("targets")).split(",");
if (recaptcha_instances.length === 0) { if (recaptcha_instances.length === 0) {
var autoinsert_candidates = $("form").filter(function() { var autoinsert_candidates = $("form").filter(function() {
var actinput = $("input[name='act']", this); var actinput = $("input[name='act']", this);
if (actinput.length && actinput.val()) { if (actinput.length && actinput.val()) {
var act = String(actinput.val()); var act = String(actinput.val());
if (act.match(/^procMemberInsert$/i) && recaptcha_targets.indexOf("signup") > -1) { if (act.match(/^procMemberInsert$/i) && recaptcha_targets.indexOf("signup") > -1) {
return true; return true;
} }
if (act.match(/^procMemberLogin$/i) && recaptcha_targets.indexOf("login") > -1) { if (act.match(/^procMemberLogin$/i) && recaptcha_targets.indexOf("login") > -1) {
return true; return true;
} }
if (act.match(/^procMember(FindAccount|ResendAuthMail)$/i) && recaptcha_targets.indexOf("recovery") > -1) { if (act.match(/^procMember(FindAccount|ResendAuthMail)$/i) && recaptcha_targets.indexOf("recovery") > -1) {
return true; return true;
} }
if (act.match(/^proc[A-Z][a-zA-Z0-9_]+InsertDocument$/i) && recaptcha_targets.indexOf("document") > -1) { if (act.match(/^proc[A-Z][a-zA-Z0-9_]+InsertDocument$/i) && recaptcha_targets.indexOf("document") > -1) {
return true; return true;
} }
if (act.match(/^proc[A-Z][a-zA-Z0-9_]+InsertComment$/i) && recaptcha_targets.indexOf("comment") > -1) { if (act.match(/^proc[A-Z][a-zA-Z0-9_]+InsertComment$/i) && recaptcha_targets.indexOf("comment") > -1) {
return true; return true;
} }
} }
var procfilter = $(this).attr("onsubmit"); var procfilter = $(this).attr("onsubmit");
if (procfilter && procfilter.match(/procFilter\b.+\binsert/i) && (recaptcha_targets.indexOf("document") > -1 || recaptcha_targets.indexOf("comment") > -1)) { if (procfilter && procfilter.match(/procFilter\b.+\binsert/i) && (recaptcha_targets.indexOf("document") > -1 || recaptcha_targets.indexOf("comment") > -1)) {
return true; return true;
} }
return false; return false;
}); });
autoinsert_candidates.each(function() { autoinsert_candidates.each(function() {
var new_instance = $('<div class="g-recaptcha"></div>'); var new_instance = $('<div class="turnstile-captcha"></div>');
new_instance.attr("id", "recaptcha-instance-" + recaptcha_instance_id++); new_instance.attr("id", "turnstile-instance-" + recaptcha_instance_id++);
var autoinsert_point = $(this).find("button[type='submit'],input[type='submit']").parent(); var autoinsert_point = $(this).find("button[type='submit'],input[type='submit']").parent();
if (autoinsert_point.size()) { if (autoinsert_point.size()) {
new_instance.insertBefore(autoinsert_point); new_instance.insertBefore(autoinsert_point);
} else { } else {
new_instance.appendTo($(this)); new_instance.appendTo($(this));
} }
}); });
var recaptcha_instances = $(".g-recaptcha"); var recaptcha_instances = $(".turnstile-captcha");
} }
recaptcha_instances.each(function() { recaptcha_instances.each(function() {
var instance = $(this); var instance = $(this);
var theme = recaptcha_config.data("theme"); var theme = recaptcha_config.data("theme");
if (theme === 'auto') { if (theme === 'auto') {
theme = getColorScheme(); theme = getColorScheme();
} }
grecaptcha.render(`#${instance.attr("id")}`, { grecaptcha.render(`#${instance.attr("id")}`, {
sitekey: recaptcha_config.data("sitekey"), sitekey: recaptcha_config.data("sitekey"),
size: recaptcha_config.data("size"), size: recaptcha_config.data("size"),
theme: theme theme: theme
}); });
}); });
} }