recaptcha v3
This commit is contained in:
parent
a49502f9de
commit
68e3b2470c
|
@ -17,9 +17,14 @@ var dash_options_load = function() {
|
|||
$(this.content).find('select.captcha_select').change(this.bind(this, function(){
|
||||
var captcha_type = $(this.content).find('select.captcha_select').val();
|
||||
if (captcha_type == 'recaptcha') {
|
||||
$(this.content).find('.recaptcha3_inputs').hide();
|
||||
$(this.content).find('.recaptcha_inputs').show();
|
||||
} else if (captcha_type == 'recaptcha3') {
|
||||
$(this.content).find('.recaptcha_inputs').hide();
|
||||
$(this.content).find('.recaptcha3_inputs').show();
|
||||
} else {
|
||||
$(this.content).find('.recaptcha_inputs').hide();
|
||||
$(this.content).find('.recaptcha3_inputs').hide();
|
||||
}
|
||||
}));
|
||||
$(this.content).find('select.captcha_select').trigger('change');
|
||||
|
|
|
@ -149,12 +149,30 @@
|
|||
$('body').append('<img class="new-year-theme-img new-year-theme-img-6" src="'+img6.src+'" alt="" />');
|
||||
$('.new-year-theme-img-6').css('top','-'+img6.height+'px').show().animate({top:0},1000,function(){
|
||||
$(this).animate({top:'-5px'},500,function(){
|
||||
$(this).animate({top:'0px'},500);
|
||||
$(this).stop(1,1).animate({top:'0px'},500);
|
||||
});
|
||||
});
|
||||
var img6AnimLock = false;
|
||||
$('.new-year-theme-img-6').click(function(){
|
||||
img6AnimLock = false;
|
||||
$(this).animate({top:'-'+img6.height+'px'},1000);
|
||||
});
|
||||
$('.new-year-theme-img-6').mouseover(function(){
|
||||
if (img6AnimLock) return;
|
||||
img6AnimLock = true;
|
||||
$(this).animate({top:'-10px'},500,function(){
|
||||
if (!img6AnimLock) return;
|
||||
$(this).animate({top:'0px'},500, function(){
|
||||
if (!img6AnimLock) return;
|
||||
$(this).animate({top:'-5px'},500, function(){
|
||||
if (!img6AnimLock) return;
|
||||
$(this).animate({top:'0px'},500, function(){
|
||||
img6AnimLock = false;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
img6.src = base + '/assets/images/holiday/newyear6.png';
|
||||
|
||||
|
|
|
@ -311,11 +311,17 @@
|
|||
zira_init_captcha();
|
||||
}
|
||||
/**
|
||||
* reCaptcha
|
||||
* reCaptcha v2
|
||||
**/
|
||||
if ($('.g-recaptcha').length>0) {
|
||||
zira_load_recaptcha();
|
||||
}
|
||||
/**
|
||||
* reCaptcha v3
|
||||
**/
|
||||
if ($('.g-recaptcha3').length>0) {
|
||||
zira_load_recaptcha3();
|
||||
}
|
||||
/**
|
||||
* User auth popup
|
||||
*/
|
||||
|
@ -1163,6 +1169,25 @@
|
|||
grecaptcha.render($('#zira-auth-dialog .g-recaptcha').get(0));
|
||||
} catch(e) {}
|
||||
}
|
||||
} else if ($('#zira-auth-dialog .g-recaptcha3').length>0) {
|
||||
if (typeof zira_load_recaptcha3.loaded == "undefined") {
|
||||
zira_load_recaptcha3();
|
||||
} else {
|
||||
try {
|
||||
var el = $('#zira-auth-dialog .g-recaptcha3');
|
||||
var id = 'grecaptcha3-auth-popup';
|
||||
$(el).attr('id', id);
|
||||
$(el).html('<input type="hidden" name="g-recaptcha-response" id="'+id+'-hidden" />');
|
||||
$(el).parent().find('.g-recaptcha3-message').attr('id',id+'-message');
|
||||
var site_key = $(el).data('sitekey');
|
||||
var action = $(el).data('action');
|
||||
grecaptcha.execute(site_key, {action: action}).then(function(token){
|
||||
$('input#'+id+'-hidden').val(token);
|
||||
var msgi = $('#'+id+'-message');
|
||||
$(msgi).text($(msgi).data('success'));
|
||||
});
|
||||
} catch(e) {}
|
||||
}
|
||||
} else if ($('.captcha-refresh-btn').length>0) {
|
||||
zira_init_captcha();
|
||||
}
|
||||
|
@ -1495,7 +1520,7 @@
|
|||
|
||||
zira_init_xhr_form = function() {
|
||||
$('form.xhr-form').each(function() {
|
||||
if ($(this).find('.g-recaptcha').length>0 || $(this).find('.captcha-refresh-btn').length>0) return true;
|
||||
if ($(this).find('.g-recaptcha').length>0 || $(this).find('.g-recaptcha3').length>0 || $(this).find('.captcha-refresh-btn').length>0) return true;
|
||||
$(this).bind('xhr-submit-error', function(e, response){
|
||||
if (!response) return;
|
||||
if (typeof response.captcha_error != "undefined" && response.captcha_error) {
|
||||
|
@ -1558,6 +1583,43 @@
|
|||
});
|
||||
};
|
||||
|
||||
zira_load_recaptcha3 = function() {
|
||||
if (typeof zira_recaptcha3_url == "undefined") return;
|
||||
if (typeof zira_load_recaptcha3.loaded != 'undefined') return;
|
||||
zira_load_recaptcha3.loaded = true;
|
||||
$('body').append('<script src="'+zira_recaptcha3_url+'"></script>');
|
||||
};
|
||||
|
||||
zira_recaptcha3_onload = function() {
|
||||
var grecaptcha_co = 0;
|
||||
$('.g-recaptcha3').each(function(){
|
||||
grecaptcha_co++;
|
||||
var id = 'grecaptcha3-'+grecaptcha_co;
|
||||
$(this).attr('id', id);
|
||||
$(this).html('<input type="hidden" name="g-recaptcha-response" id="'+id+'-hidden" />');
|
||||
$(this).parent().find('.g-recaptcha3-message').attr('id',id+'-message');
|
||||
var site_key = $(this).data('sitekey');
|
||||
var action = $(this).data('action');
|
||||
grecaptcha.execute(site_key, {action: action}).then(function(token){
|
||||
$('input#'+id+'-hidden').val(token);
|
||||
var msgi = $('#'+id+'-message');
|
||||
$(msgi).text($(msgi).data('success'));
|
||||
});
|
||||
$(this).parents('form.xhr-form').submit(function(){
|
||||
var grecaptcha_el = $(this).find('.g-recaptcha3');
|
||||
window.setTimeout(function(){
|
||||
try {
|
||||
var site_key = $(grecaptcha_el).data('sitekey');
|
||||
var action = $(grecaptcha_el).data('action');
|
||||
grecaptcha.execute(site_key, {action: action}).then(function(token){
|
||||
$('input#'+$(grecaptcha_el).attr('id')+'-hidden').val(token);
|
||||
});
|
||||
} catch(err) {}
|
||||
}, 3000);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
zira_set_dashpanel_dropdown_height = function() {
|
||||
var dropdown = $('#dashpanel-container').find('.open > .dropdown-menu');
|
||||
if ($(dropdown).length>0) {
|
||||
|
|
|
@ -71,6 +71,12 @@ class Options extends Form
|
|||
$html .= $this->input(Locale::t('Site key for reCaptcha'), 'recaptcha_site_key');
|
||||
$html .= $this->input(Locale::t('Secret key for reCaptcha'), 'recaptcha_secret_key');
|
||||
$html .= Zira\Helper::tag_close('div');
|
||||
|
||||
$html .= Zira\Helper::tag_open('div', array('class' => 'recaptcha3_inputs'));
|
||||
$html .= $this->input(Locale::t('Site key for reCaptcha'), 'recaptcha3_site_key');
|
||||
$html .= $this->input(Locale::t('Secret key for reCaptcha'), 'recaptcha3_secret_key');
|
||||
$html .= Zira\Helper::tag_close('div');
|
||||
|
||||
$html .= $this->checkbox(Locale::t('Sticky top bar'), 'dash_panel_frontend', null, false);
|
||||
$html .= $this->select(Locale::t('Window buttons position'), 'dashwindow_mode', array(
|
||||
'0' => Locale::t('Left'),
|
||||
|
|
|
@ -39,7 +39,9 @@ class Options extends Model {
|
|||
'check_updates' => 'int',
|
||||
'captcha_type' => 'string',
|
||||
'recaptcha_site_key' => 'string',
|
||||
'recaptcha_secret_key' => 'string'
|
||||
'recaptcha_secret_key' => 'string',
|
||||
'recaptcha3_site_key' => 'string',
|
||||
'recaptcha3_secret_key' => 'string'
|
||||
);
|
||||
|
||||
if (count(Zira\Config::get('languages'))>1) {
|
||||
|
|
|
@ -154,5 +154,7 @@ return array(
|
|||
'Anti-Bot' => 'Анти-Бот',
|
||||
'Read more' => 'Подробнее',
|
||||
'DD.MM.YYYY' => 'ДД.ММ.ГГГГ',
|
||||
'Permission denied' => 'Нет прав доступа'
|
||||
'Permission denied' => 'Нет прав доступа',
|
||||
'Anti-Bot is not active.' => 'Анти-Бот не активен.',
|
||||
'Anti-Bot is active.' => 'Анти-Бот активен.'
|
||||
);
|
|
@ -2470,6 +2470,9 @@ ul.vote-results li .vote-result {
|
|||
filter: invert(65%) contrast(300%);
|
||||
opacity: .6;
|
||||
}
|
||||
.grecaptcha-badge {
|
||||
filter: invert(65%) contrast(300%);
|
||||
}
|
||||
|
||||
/** fields **/
|
||||
.record_fields_tabs_wrapper .nav-tabs {
|
||||
|
|
|
@ -80,6 +80,7 @@ class Factory {
|
|||
$this->_token = Form::getToken($this->_id, $this->_is_token_unique);
|
||||
$this->_validator = new Validator();
|
||||
$this->_validator->setToken($this->_token);
|
||||
$this->_validator->setFormId($this->_id);
|
||||
if ($this->_multipart) $this->_validator->setMultipart(true);
|
||||
}
|
||||
|
||||
|
@ -712,6 +713,7 @@ class Factory {
|
|||
$captcha_type = Zira\Config::get('captcha_type', Zira\Models\Captcha::TYPE_DEFAULT);
|
||||
if ($captcha_type == Zira\Models\Captcha::TYPE_NONE) return '';
|
||||
else if ($captcha_type == Zira\Models\Captcha::TYPE_RECAPTCHA) return $this->_captcha_recaptcha();
|
||||
else if ($captcha_type == Zira\Models\Captcha::TYPE_RECAPTCHA_v3) return $this->_captcha_recaptcha3();
|
||||
else return $this->_captcha_default($label, $description);
|
||||
}
|
||||
|
||||
|
@ -747,6 +749,15 @@ class Factory {
|
|||
);
|
||||
return $this->wrap($label.$this->wrap($captcha,$this->_input_wrap_class));
|
||||
}
|
||||
|
||||
protected function _captcha_recaptcha3() {
|
||||
$label = Form::label(' ', null, array('class'=>$this->_label_class));
|
||||
$captcha = Form::recaptcha3(
|
||||
Zira\Config::get('recaptcha3_site_key',''),
|
||||
str_replace('-', '_', $this->_id)
|
||||
);
|
||||
return $this->wrap($label.$this->wrap($captcha,$this->_input_wrap_class));
|
||||
}
|
||||
|
||||
public function validate() {
|
||||
if (!$this->getValidator()->validate()) {
|
||||
|
|
|
@ -239,6 +239,18 @@ class Form {
|
|||
$html .= Helper::tag_close('div');
|
||||
return $html;
|
||||
}
|
||||
|
||||
public static function recaptcha3($site_key, $action, $wrapper_class='recaptcha3') {
|
||||
$html = Helper::tag_open('div',array('class'=>$wrapper_class));
|
||||
$html .= Helper::tag('div', null, array(
|
||||
'class' => 'g-recaptcha3',
|
||||
'data-sitekey' => $site_key,
|
||||
'data-action' => $action
|
||||
));
|
||||
$html .= Helper::tag('div', Zira\Locale::t('Anti-Bot is not active.').' '.Zira\Locale::t('Please wait').'...', array('data-error'=>Zira\Locale::t('Anti-Bot is not active.'),'data-success'=>Zira\Locale::t('Anti-Bot is active.'),'class'=>'g-recaptcha3-message'));
|
||||
$html .= Helper::tag_close('div');
|
||||
return $html;
|
||||
}
|
||||
|
||||
public static function generateCaptcha() {
|
||||
$token = Request::get('token');
|
||||
|
@ -341,6 +353,32 @@ class Form {
|
|||
}
|
||||
return $result_data['success'];
|
||||
}
|
||||
|
||||
public static function isRecaptcha3Valid($secret_key, $response_value, $action) {
|
||||
if (!$secret_key || !$response_value || !$action) return false;
|
||||
$data = http_build_query(array(
|
||||
'secret' => $secret_key,
|
||||
'response' => $response_value
|
||||
));
|
||||
$options = array(
|
||||
'http' => array(
|
||||
'method' => 'POST',
|
||||
'header' => 'Content-type: application/x-www-form-urlencoded',
|
||||
'content' => $data
|
||||
)
|
||||
);
|
||||
$context = stream_context_create($options);
|
||||
try {
|
||||
$result = file_get_contents(Zira\Models\Captcha::RECAPTCHA_VALIDATE_URL, false, $context);
|
||||
if (!$result) throw new \Exception('An error occurred');
|
||||
$result_data = json_decode($result, true);
|
||||
if (empty($result_data) || !array_key_exists('success', $result_data)) throw new \Exception('An error occurred');
|
||||
if (!array_key_exists('score', $result_data) || !array_key_exists('action', $result_data)) throw new \Exception('An error occurred');
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
return $result_data['success'] && $result_data['action']==$action && floatval($result_data['score'])>=Zira\Models\Captcha::RECAPTCHA_v3_MIN_SCORE;
|
||||
}
|
||||
|
||||
public static function getValue($token,$name,$method=Request::POST) {
|
||||
$_name = self::getFieldName($token, $name);
|
||||
|
|
|
@ -17,6 +17,7 @@ class Validator {
|
|||
protected $_fields = array();
|
||||
protected $_message = '';
|
||||
protected $_error_field = '';
|
||||
protected $_form_id = '';
|
||||
|
||||
const TYPE_STRING = 'string';
|
||||
const TYPE_NUMBER = 'number';
|
||||
|
@ -42,6 +43,14 @@ class Validator {
|
|||
public function getToken() {
|
||||
return $this->_token;
|
||||
}
|
||||
|
||||
public function setFormId($id) {
|
||||
$this->_form_id = $id;
|
||||
}
|
||||
|
||||
public function getFormId() {
|
||||
return $this->_form_id;
|
||||
}
|
||||
|
||||
public function setMethod($method) {
|
||||
$this->_method = $method;
|
||||
|
@ -388,6 +397,7 @@ class Validator {
|
|||
$captcha_type = Zira\Config::get('captcha_type', Zira\Models\Captcha::TYPE_DEFAULT);
|
||||
if ($captcha_type == Zira\Models\Captcha::TYPE_NONE) return true;
|
||||
else if ($captcha_type == Zira\Models\Captcha::TYPE_RECAPTCHA) return $this->_validateCaptchaRecaptcha($field);
|
||||
else if ($captcha_type == Zira\Models\Captcha::TYPE_RECAPTCHA_v3) return $this->_validateCaptchaRecaptcha3($field);
|
||||
else return $this->_validateCaptchaDefault($field);
|
||||
}
|
||||
|
||||
|
@ -398,11 +408,16 @@ class Validator {
|
|||
protected function _validateCaptchaRecaptcha(array $field) {
|
||||
return Form::isRecaptchaValid(Zira\Config::get('recaptcha_secret_key', ''), Zira\Request::post(Zira\Models\Captcha::RECAPTCHA_RESPONSE_INPUT));
|
||||
}
|
||||
|
||||
protected function _validateCaptchaRecaptcha3(array $field) {
|
||||
return Form::isRecaptcha3Valid(Zira\Config::get('recaptcha3_secret_key', ''), Zira\Request::post(Zira\Models\Captcha::RECAPTCHA_RESPONSE_INPUT), str_replace('-', '_', $this->getFormId()));
|
||||
}
|
||||
|
||||
public function registerCaptchaLazy($form_id, $message) {
|
||||
$captcha_type = Zira\Config::get('captcha_type', Zira\Models\Captcha::TYPE_DEFAULT);
|
||||
if ($captcha_type == Zira\Models\Captcha::TYPE_NONE) return;
|
||||
else if ($captcha_type == Zira\Models\Captcha::TYPE_RECAPTCHA) return $this->_registerCaptchaLazyRecaptcha($form_id, $message);
|
||||
else if ($captcha_type == Zira\Models\Captcha::TYPE_RECAPTCHA_v3) return $this->_registerCaptchaLazyRecaptcha3($form_id, $message);
|
||||
else return $this->_registerCaptchaLazyDefault($form_id, $message);
|
||||
}
|
||||
|
||||
|
@ -424,11 +439,21 @@ class Validator {
|
|||
'message' => $message
|
||||
);
|
||||
}
|
||||
|
||||
protected function _registerCaptchaLazyRecaptcha3($form_id, $message) {
|
||||
$this->_fields []= array(
|
||||
'type' => self::TYPE_CAPTCHA_LAZY,
|
||||
'name' => CAPTCHA_NAME,
|
||||
'form_id' => $form_id,
|
||||
'message' => $message
|
||||
);
|
||||
}
|
||||
|
||||
protected function validateCaptchaLazy(array $field) {
|
||||
$captcha_type = Zira\Config::get('captcha_type', Zira\Models\Captcha::TYPE_DEFAULT);
|
||||
if ($captcha_type == Zira\Models\Captcha::TYPE_NONE) return true;
|
||||
else if ($captcha_type == Zira\Models\Captcha::TYPE_RECAPTCHA) return $this->_validateCaptchaLazyRecaptcha($field);
|
||||
else if ($captcha_type == Zira\Models\Captcha::TYPE_RECAPTCHA_v3) return $this->_validateCaptchaLazyRecaptcha3($field);
|
||||
else return $this->_validateCaptchaLazyDefault($field);
|
||||
}
|
||||
|
||||
|
@ -451,6 +476,16 @@ class Validator {
|
|||
return Form::isRecaptchaValid(Zira\Config::get('recaptcha_secret_key', ''), Zira\Request::post(Zira\Models\Captcha::RECAPTCHA_RESPONSE_INPUT));
|
||||
}
|
||||
}
|
||||
|
||||
protected function _validateCaptchaLazyRecaptcha3(array $field) {
|
||||
if (Zira\Request::post(Zira\Models\Captcha::RECAPTCHA_RESPONSE_INPUT)===null && !Zira\Models\Captcha::isActive($field['form_id'])) {
|
||||
Zira\Models\Captcha::register($field['form_id']);
|
||||
return true;
|
||||
} else {
|
||||
Zira\Models\Captcha::register($field['form_id']);
|
||||
return Form::isRecaptcha3Valid(Zira\Config::get('recaptcha3_secret_key', ''), Zira\Request::post(Zira\Models\Captcha::RECAPTCHA_RESPONSE_INPUT), str_replace('-', '_', $this->getFormId()));
|
||||
}
|
||||
}
|
||||
|
||||
public function registerExists($field,$class,$property,$message) {
|
||||
$this->_fields []= array(
|
||||
|
|
|
@ -17,10 +17,12 @@ class Captcha extends Orm {
|
|||
const TYPE_NONE = 'none';
|
||||
const TYPE_DEFAULT = 'default';
|
||||
const TYPE_RECAPTCHA = 'recaptcha';
|
||||
const TYPE_RECAPTCHA_v3 = 'recaptcha3';
|
||||
|
||||
const RECAPTCHA_JS_URL = 'https://www.google.com/recaptcha/api.js';
|
||||
const RECAPTCHA_VALIDATE_URL = 'https://www.google.com/recaptcha/api/siteverify';
|
||||
const RECAPTCHA_RESPONSE_INPUT = 'g-recaptcha-response';
|
||||
const RECAPTCHA_v3_MIN_SCORE = .5;
|
||||
|
||||
public static function getTable() {
|
||||
return self::$table;
|
||||
|
@ -67,7 +69,8 @@ class Captcha extends Orm {
|
|||
return array(
|
||||
self::TYPE_NONE => \Zira\Locale::t('Do not use'),
|
||||
self::TYPE_DEFAULT => \Zira\Locale::t('Default'),
|
||||
self::TYPE_RECAPTCHA => \Zira\Locale::t('Google reCaptcha')
|
||||
self::TYPE_RECAPTCHA => \Zira\Locale::t('Google reCaptcha v2'),
|
||||
self::TYPE_RECAPTCHA_v3 => \Zira\Locale::t('Google reCaptcha v3')
|
||||
);
|
||||
}
|
||||
}
|
|
@ -363,8 +363,11 @@ class View {
|
|||
if (self::$_render_js_strings) {
|
||||
$js_scripts .= Helper::tag_open('script', array('type'=>'text/javascript'));
|
||||
$js_scripts .= 'zira_base = \''.Helper::baseUrl('').'\';';
|
||||
if (Config::get('captcha_type', Models\Captcha::TYPE_DEFAULT)==Models\Captcha::TYPE_RECAPTCHA) {
|
||||
$captcha_type = Config::get('captcha_type', Models\Captcha::TYPE_DEFAULT);
|
||||
if ($captcha_type==Models\Captcha::TYPE_RECAPTCHA) {
|
||||
$js_scripts .= 'zira_recaptcha_url = \''.Models\Captcha::RECAPTCHA_JS_URL.'?hl='.(Locale::getLanguage()).'&render=explicit&onload=zira_recaptcha_onload\';';
|
||||
} else if ($captcha_type==Models\Captcha::TYPE_RECAPTCHA_v3) {
|
||||
$js_scripts .= 'zira_recaptcha3_url = \''.Models\Captcha::RECAPTCHA_JS_URL.'?hl='.(Locale::getLanguage()).'&render='.Config::get('recaptcha3_site_key','').'&onload=zira_recaptcha3_onload\';';
|
||||
}
|
||||
$js_scripts .= 'zira_scroll_effects_enabled = '.(Config::get('site_scroll_effects',1) ? 'true' : 'false').';';
|
||||
$js_scripts .= 'zira_show_images_description = '.(Config::get('site_parse_images',1) ? 'true' : 'false').';';
|
||||
|
|
Loading…
Reference in a new issue