fix(captcha): wire scene switches and rename menu to 人机验证
- Admin: 登录权限 → 人机验证; 停用场景 → 启用场景 (opt-in) - Normalize enabled_scenarios with legacy disabled_scenarios BC - Sign-in: never soft-bypass captcha; cancel unlocks button - Captcha JS: cancel path finishes pending callback as false
This commit is contained in:
@@ -46,9 +46,13 @@ function aksrt_captcha_scenes(): array {
|
||||
* 默认配置结构。
|
||||
*/
|
||||
function aksrt_captcha_default_config(): array {
|
||||
$all_scenes = array_keys(aksrt_captcha_scenes());
|
||||
return [
|
||||
'enabled' => false,
|
||||
'active_provider' => '',
|
||||
// Positive list: checked scenes require captcha. Default all scenes.
|
||||
'enabled_scenarios' => $all_scenes,
|
||||
// Legacy mirror kept for BC consumers / admin summaries.
|
||||
'disabled_scenarios' => [],
|
||||
'tencent' => [],
|
||||
'aliyun' => [],
|
||||
@@ -57,6 +61,24 @@ function aksrt_captcha_default_config(): array {
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize a list of captcha scene keys against the whitelist.
|
||||
*
|
||||
* @param mixed $raw
|
||||
* @return array<int, string>
|
||||
*/
|
||||
function aksrt_captcha_sanitize_scene_list($raw): array {
|
||||
$list = is_array($raw) ? $raw : [];
|
||||
$clean = [];
|
||||
foreach ($list as $scene) {
|
||||
$scene = sanitize_key((string) $scene);
|
||||
if ($scene !== '' && array_key_exists($scene, aksrt_captcha_scenes()) && !in_array($scene, $clean, true)) {
|
||||
$clean[] = $scene;
|
||||
}
|
||||
}
|
||||
return array_values($clean);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取人机验证完整配置(规范化,不合并历史脏键)。
|
||||
*
|
||||
@@ -68,20 +90,26 @@ function aksrt_get_captcha_config(): array {
|
||||
$cfg = [];
|
||||
}
|
||||
|
||||
$default = aksrt_captcha_default_config();
|
||||
$all_scenes = array_keys(aksrt_captcha_scenes());
|
||||
$provider = isset($cfg['active_provider']) ? sanitize_key((string) $cfg['active_provider']) : '';
|
||||
if (!in_array($provider, aksrt_captcha_providers(), true)) {
|
||||
$provider = '';
|
||||
}
|
||||
|
||||
$disabled = isset($cfg['disabled_scenarios']) ? (array) $cfg['disabled_scenarios'] : [];
|
||||
$disabled = array_values(array_filter(array_map('sanitize_key', $disabled), function ($s) {
|
||||
return array_key_exists($s, aksrt_captcha_scenes());
|
||||
}));
|
||||
if (array_key_exists('enabled_scenarios', $cfg)) {
|
||||
// Explicit positive list (may be empty = no scenes).
|
||||
$enabled = aksrt_captcha_sanitize_scene_list($cfg['enabled_scenarios']);
|
||||
} else {
|
||||
// Legacy: only disabled list stored → all minus disabled.
|
||||
$disabled_legacy = aksrt_captcha_sanitize_scene_list($cfg['disabled_scenarios'] ?? []);
|
||||
$enabled = array_values(array_diff($all_scenes, $disabled_legacy));
|
||||
}
|
||||
$disabled = array_values(array_diff($all_scenes, $enabled));
|
||||
|
||||
$result = [
|
||||
'enabled' => !empty($cfg['enabled']),
|
||||
'active_provider' => $provider,
|
||||
'enabled_scenarios' => $enabled,
|
||||
'disabled_scenarios' => $disabled,
|
||||
];
|
||||
foreach (aksrt_captcha_providers() as $p) {
|
||||
@@ -146,7 +174,11 @@ function aksrt_is_captcha_enabled_for($scene): bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !in_array($scene, $cfg['disabled_scenarios'], true);
|
||||
$enabled = isset($cfg['enabled_scenarios']) && is_array($cfg['enabled_scenarios'])
|
||||
? $cfg['enabled_scenarios']
|
||||
: array_values(array_diff(array_keys(aksrt_captcha_scenes()), (array) ($cfg['disabled_scenarios'] ?? [])));
|
||||
|
||||
return in_array($scene, $enabled, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -546,7 +578,7 @@ function aksrt_render_captcha($scene = 'comment') {
|
||||
echo '<div class="aksrt-captcha-misconfig" style="font-size:12px;color:#d03050;margin:8px 0;">';
|
||||
echo esc_html(sprintf(
|
||||
/* translators: %s: captcha provider key */
|
||||
__('人机验证服务商「%s」已启用但凭据未配齐,前台已跳过渲染。请到「功能&权限 → 登录权限」补全配置。', 'aksrt'),
|
||||
__('人机验证服务商「%s」已启用但凭据未配齐,前台已跳过渲染。请到「功能&权限 → 人机验证」补全配置。', 'aksrt'),
|
||||
$provider
|
||||
));
|
||||
echo '</div>';
|
||||
@@ -701,7 +733,7 @@ function submitForm(){
|
||||
verified=true; hField.value='1';
|
||||
if(C.scene==='download') syncDownloadSiblings(true);
|
||||
if(typeof pendingAction==='function'){
|
||||
var action=pendingAction; pendingAction=null; action(); return;
|
||||
finishPending(true); return;
|
||||
}
|
||||
setTimeout(resetVerificationState, 3000);
|
||||
submitNativeForm();
|
||||
@@ -717,18 +749,24 @@ function showTip(msg, color){
|
||||
function showLoading(){ box.innerHTML='<div style="text-align:center;padding:20px;color:#9ca3af;">验证码加载中...</div>'; }
|
||||
function clearLoading(){ box.innerHTML=''; }
|
||||
|
||||
root.scenes[C.scene]={
|
||||
function finishPending(ok){
|
||||
var action=pendingAction; pendingAction=null;
|
||||
if(typeof action==='function'){ action(!!ok); }
|
||||
}
|
||||
|
||||
function cancelPending(msg){
|
||||
if(msg) showTip(msg, '#e67e22');
|
||||
finishPending(false);
|
||||
}
|
||||
|
||||
root.scenes[C.scene]={
|
||||
verify:function(callback){
|
||||
var retry=0;
|
||||
function run(){
|
||||
if(verified || hField.value==='1'){
|
||||
if(typeof callback==='function') callback();
|
||||
return;
|
||||
}
|
||||
pendingAction=(typeof callback==='function')?callback:null;
|
||||
triggerCaptcha();
|
||||
if(verified || hField.value==='1'){
|
||||
if(typeof callback==='function') callback(true);
|
||||
return;
|
||||
}
|
||||
run();
|
||||
pendingAction=(typeof callback==='function')?function(ok){ callback(ok!==false); }:null;
|
||||
triggerCaptcha();
|
||||
},
|
||||
reset:resetVerificationState
|
||||
};
|
||||
@@ -744,7 +782,7 @@ function loadTencent(){
|
||||
triggerCaptcha=function(){
|
||||
if(!capIns){
|
||||
capIns=new TencentCaptcha(C.tc.app_id, function(res){
|
||||
if(res.ret===2) return;
|
||||
if(res.ret===2){ cancelPending('已取消验证'); return; }
|
||||
if(res.ret===0 && res.ticket){
|
||||
if(res.ticket.indexOf('trerror_')===0){
|
||||
showTip('验证码服务异常,请刷新页面重试', '#e67e22'); return;
|
||||
@@ -803,7 +841,7 @@ function loadCloudflare(){
|
||||
'<div class="aksrt-captcha-modal-body"><p class="aksrt-captcha-modal-hint">请完成验证后继续操作</p>'+
|
||||
'<div id="modalWidget_'+C.uid+'" class="aksrt-captcha-modal-widget"></div></div></div>';
|
||||
document.body.appendChild(cfModal);
|
||||
var cancelFn=function(){ cfVerifying=false; closeModal(); showTip('验证码已取消', '#e67e22'); };
|
||||
var cancelFn=function(){ cfVerifying=false; closeModal(); cancelPending('已取消验证'); };
|
||||
cfModal.querySelector('.aksrt-captcha-modal-backdrop').addEventListener('click', cancelFn);
|
||||
cfModal.querySelector('.aksrt-captcha-modal-close').addEventListener('click', cancelFn);
|
||||
renderWidget();
|
||||
@@ -828,7 +866,7 @@ function loadGeetest(){
|
||||
var product=(C.gt && C.gt.product) ? String(C.gt.product) : 'bind';
|
||||
if(!captchaId){
|
||||
clearLoading();
|
||||
showTip('极验 Captcha ID 未配置,请到后台「功能&权限 → 登录权限」填写并保存', '#e74c3c');
|
||||
showTip('极验 Captcha ID 未配置,请到后台「功能&权限 → 人机验证」填写并保存', '#e74c3c');
|
||||
return;
|
||||
}
|
||||
function render(){
|
||||
|
||||
Reference in New Issue
Block a user