Merge pull request 'fix(captcha): 1:1 align bind-phone and real status contracts' (#110) from worktree-captcha-wire-through into main
Reviewed-on: CYL/wordpress-theme-aksrt#110
This commit is contained in:
@@ -154,32 +154,38 @@ onMounted(async () => {
|
||||
const d = res.data
|
||||
const svc = res.services || {}
|
||||
|
||||
const captcha = d.captcha || svc.captcha || {}
|
||||
const captchaOn = !!(captcha.enabled && captcha.configured)
|
||||
const captchaScenes = captcha.scenes || {}
|
||||
const audit = d.content_audit || svc.audit || {}
|
||||
const ipGeo = d.ip_geo || svc.ip_geo || {}
|
||||
|
||||
securityItems.value[0].value = d.email_gate_enabled ? '已开启' : '未开启'
|
||||
securityItems.value[0].color = d.email_gate_enabled ? '#52c41a' : '#8a909c'
|
||||
securityItems.value[1].value = d.captcha_enabled ? '已开启' : '未开启'
|
||||
securityItems.value[1].color = d.captcha_enabled ? '#52c41a' : '#8a909c'
|
||||
securityItems.value[1].value = captchaOn ? '已开启' : '未开启'
|
||||
securityItems.value[1].color = captchaOn ? '#52c41a' : '#8a909c'
|
||||
|
||||
if (svc.audit?.enabled) {
|
||||
securityItems.value[2].value = svc.audit.configured ? '已配置' : '待补全'
|
||||
securityItems.value[2].color = svc.audit.configured ? '#52c41a' : '#faad14'
|
||||
if (audit.enabled) {
|
||||
securityItems.value[2].value = audit.configured ? '已配置' : '待补全'
|
||||
securityItems.value[2].color = audit.configured ? '#52c41a' : '#faad14'
|
||||
} else {
|
||||
securityItems.value[2].value = '未开启'
|
||||
securityItems.value[2].color = '#8a909c'
|
||||
}
|
||||
|
||||
if (svc.ip_geo?.enabled) {
|
||||
securityItems.value[3].value = svc.ip_geo.configured ? '已配置' : '待补全'
|
||||
securityItems.value[3].color = svc.ip_geo.configured ? '#52c41a' : '#faad14'
|
||||
if (ipGeo.enabled) {
|
||||
securityItems.value[3].value = ipGeo.configured ? '已配置' : '待补全'
|
||||
securityItems.value[3].color = ipGeo.configured ? '#52c41a' : '#faad14'
|
||||
} else {
|
||||
securityItems.value[3].value = '未开启'
|
||||
securityItems.value[3].color = '#8a909c'
|
||||
}
|
||||
|
||||
features.value[0].enabled = !!d.email_gate_enabled
|
||||
features.value[1].enabled = !!d.captcha_comment_enabled
|
||||
features.value[2].enabled = !!d.captcha_download_enabled
|
||||
features.value[3].enabled = !!(svc.audit?.enabled ?? d.content_audit_enabled)
|
||||
features.value[4].enabled = !!(svc.ip_geo?.enabled ?? d.ip_geo_enabled)
|
||||
features.value[1].enabled = !!captchaScenes.comment
|
||||
features.value[2].enabled = !!captcha.download_active
|
||||
features.value[3].enabled = !!audit.enabled
|
||||
features.value[4].enabled = !!ipGeo.enabled
|
||||
|
||||
if (d.risk_switches) {
|
||||
riskSwitches.value = { ...riskSwitches.value, ...d.risk_switches }
|
||||
|
||||
@@ -136,8 +136,8 @@ onMounted(async () => {
|
||||
services.value[0].status = svc.sms?.provider || (s.sms_enabled ? '已启用' : '未配置')
|
||||
services.value[1].available = !!(svc.wechat?.available ?? s.wechat_enabled)
|
||||
services.value[1].status = svc.wechat?.provider || (s.wechat_enabled ? '已启用' : '未配置')
|
||||
services.value[2].available = !!(svc.captcha?.available ?? s.captcha_enabled)
|
||||
services.value[2].status = svc.captcha?.provider || (s.captcha_enabled ? '已启用' : '未配置')
|
||||
services.value[2].available = !!(svc.captcha?.available ?? svc.captcha?.configured)
|
||||
services.value[2].status = svc.captcha?.provider || (svc.captcha?.enabled ? '已启用' : '未配置')
|
||||
services.value[3].available = !!(svc.push?.available ?? s.baidu_push_enabled)
|
||||
services.value[3].status = svc.push?.provider || (s.baidu_push_enabled ? '已启用' : '未配置')
|
||||
services.value[4].available = !!(svc.audit?.available ?? s.content_audit_enabled)
|
||||
|
||||
@@ -64,6 +64,7 @@ export const permissionsSchemas = {
|
||||
{ label: '用户登录', value: 'login' },
|
||||
{ label: '用户注册', value: 'register' },
|
||||
{ label: '绑定第三方', value: 'bind' },
|
||||
{ label: '绑定手机', value: 'bind_phone' },
|
||||
{ label: '找回密码', value: 'lostpassword' },
|
||||
{ label: '修改密码', value: 'change_password' },
|
||||
{ label: '更改邮箱', value: 'change_email' },
|
||||
|
||||
@@ -443,7 +443,7 @@
|
||||
m.classList.remove('is-open');
|
||||
document.body.style.overflow = '';
|
||||
var f = m.querySelector('form');
|
||||
var sceneMap = { 'pwd-modal': 'change_password', 'email-modal': 'change_email' };
|
||||
var sceneMap = { 'pwd-modal': 'change_password', 'email-modal': 'change_email', 'phone-modal': 'bind_phone' };
|
||||
var scene = m.id && sceneMap[m.id] ? sceneMap[m.id] : '';
|
||||
var store = window.AKSRTCaptchaState && window.AKSRTCaptchaState.scenes ? window.AKSRTCaptchaState.scenes : null;
|
||||
if (f) {
|
||||
@@ -687,4 +687,93 @@
|
||||
initNotifications();
|
||||
initSettings();
|
||||
}
|
||||
|
||||
// 绑定手机
|
||||
(function initBindPhone() {
|
||||
var form = document.getElementById('aksrt-bind-phone-form');
|
||||
if (!form) return;
|
||||
form.addEventListener('submit', function (e) {
|
||||
e.preventDefault();
|
||||
var phoneEl = form.querySelector('[name="phone"]');
|
||||
var codeEl = form.querySelector('[name="code"]');
|
||||
var phone = phoneEl ? String(phoneEl.value || '').trim() : '';
|
||||
var code = codeEl ? String(codeEl.value || '').trim() : '';
|
||||
if (!/^1[3-9]\d{9}$/.test(phone)) {
|
||||
showToast('请输入正确的手机号');
|
||||
return;
|
||||
}
|
||||
if (!code) {
|
||||
showToast('请输入短信验证码');
|
||||
return;
|
||||
}
|
||||
var submitBtn = form.querySelector('[type="submit"]');
|
||||
if (submitBtn) {
|
||||
submitBtn.disabled = true;
|
||||
submitBtn.textContent = '绑定中...';
|
||||
}
|
||||
function collectCaptcha(formEl) {
|
||||
var out = {};
|
||||
[
|
||||
'captcha_verified', 'tencent_ticket', 'tencent_randstr', 'tencent_sid',
|
||||
'cf_turnstile_response', 'geetest_lot_number', 'geetest_captcha_output',
|
||||
'geetest_pass_token', 'geetest_gen_time', 'aliyun_captcha_verify_param'
|
||||
].forEach(function (name) {
|
||||
var el = formEl.querySelector('[name="' + name + '"]');
|
||||
if (el && el.value) out[name] = el.value;
|
||||
});
|
||||
return out;
|
||||
}
|
||||
function resetCaptcha() {
|
||||
try {
|
||||
var store = window.AKSRTCaptchaState && window.AKSRTCaptchaState.scenes;
|
||||
if (store && store.bind_phone && typeof store.bind_phone.reset === 'function') {
|
||||
store.bind_phone.reset();
|
||||
}
|
||||
} catch (err) {}
|
||||
}
|
||||
function doBind() {
|
||||
var captcha = collectCaptcha(form);
|
||||
var restRoot = (window.aksrtData && aksrtData.apiUrl) || '/wp-json/aksrt/v1';
|
||||
var nonce = (window.aksrtData && aksrtData.restNonce) || '';
|
||||
fetch(String(restRoot).replace(/\/$/, '') + '/auth/bind-phone', {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-WP-Nonce': nonce
|
||||
},
|
||||
body: JSON.stringify(Object.assign({ phone: phone, code: code }, captcha))
|
||||
})
|
||||
.then(function (r) { return r.json().then(function (j) { return { ok: r.ok, json: j }; }); })
|
||||
.then(function (res) {
|
||||
if (res.ok && res.json && res.json.success) {
|
||||
showToast((res.json.message) || '绑定成功');
|
||||
setTimeout(function () { window.location.reload(); }, 600);
|
||||
return;
|
||||
}
|
||||
resetCaptcha();
|
||||
showToast((res.json && (res.json.message || res.json.error)) || '绑定失败');
|
||||
if (submitBtn) {
|
||||
submitBtn.disabled = false;
|
||||
submitBtn.textContent = '确认绑定';
|
||||
}
|
||||
})
|
||||
.catch(function () {
|
||||
resetCaptcha();
|
||||
showToast('网络错误');
|
||||
if (submitBtn) {
|
||||
submitBtn.disabled = false;
|
||||
submitBtn.textContent = '确认绑定';
|
||||
}
|
||||
});
|
||||
}
|
||||
var store = window.AKSRTCaptchaState && window.AKSRTCaptchaState.scenes;
|
||||
if (store && store.bind_phone && typeof store.bind_phone.verify === 'function') {
|
||||
store.bind_phone.verify(doBind);
|
||||
} else {
|
||||
doBind();
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
})();
|
||||
|
||||
@@ -148,13 +148,6 @@ class AKSRT_Admin_Extension_Controller extends AKSRT_Admin_Controller_Base {
|
||||
$flat["{$key}_provider"] = (string) ($svc['provider'] ?? '');
|
||||
}
|
||||
|
||||
// 保留旧布尔字段兼容
|
||||
$flat['sms_enabled'] = !empty($services['sms']['enabled']);
|
||||
$flat['wechat_enabled'] = !empty($services['wechat']['enabled']);
|
||||
$flat['captcha_enabled'] = !empty($services['captcha']['enabled']);
|
||||
$flat['baidu_push_enabled'] = !empty($services['push']['enabled']);
|
||||
$flat['content_audit_enabled'] = !empty($services['audit']['enabled']);
|
||||
|
||||
return $this->success([
|
||||
'data' => $flat,
|
||||
'services' => $services,
|
||||
@@ -173,12 +166,11 @@ class AKSRT_Admin_Extension_Controller extends AKSRT_Admin_Controller_Base {
|
||||
$email_gate_enabled = false;
|
||||
}
|
||||
|
||||
$captcha_summary = function_exists('aksrt_get_captcha_status_summary')
|
||||
$captcha = function_exists('aksrt_get_captcha_status_summary')
|
||||
? aksrt_get_captcha_status_summary()
|
||||
: ['enabled' => false, 'configured' => false, 'scenes' => []];
|
||||
$captcha_comment_enabled = !empty($captcha_summary['scenes']['comment']);
|
||||
: ['enabled' => false, 'provider' => '', 'configured' => false, 'scenes' => []];
|
||||
$features = class_exists('AKSRT_Settings') ? AKSRT_Settings::get_cms_features() : [];
|
||||
$captcha_download_enabled = !empty($features['download_captcha']) && !empty($captcha_summary['scenes']['download']);
|
||||
$scenes = is_array($captcha['scenes'] ?? null) ? $captcha['scenes'] : [];
|
||||
|
||||
$risk_switches = [
|
||||
'show_unapproved_comments' => !empty($settings['show_unapproved_comments']),
|
||||
@@ -189,14 +181,22 @@ class AKSRT_Admin_Extension_Controller extends AKSRT_Admin_Controller_Base {
|
||||
return $this->success([
|
||||
'data' => [
|
||||
'email_gate_enabled' => $email_gate_enabled,
|
||||
'captcha_comment_enabled' => $captcha_comment_enabled,
|
||||
'captcha_download_enabled' => $captcha_download_enabled,
|
||||
'content_audit_enabled' => !empty($services['audit']['enabled']),
|
||||
'content_audit_configured' => !empty($services['audit']['configured']),
|
||||
'ip_geo_enabled' => !empty($services['ip_geo']['enabled']),
|
||||
'ip_geo_configured' => !empty($services['ip_geo']['configured']),
|
||||
'captcha_enabled' => !empty($captcha_summary['enabled']) && !empty($captcha_summary['configured']),
|
||||
'captcha_summary' => $captcha_summary,
|
||||
'captcha' => [
|
||||
'enabled' => !empty($captcha['enabled']),
|
||||
'provider' => (string) ($captcha['provider'] ?? ''),
|
||||
'configured' => !empty($captcha['configured']),
|
||||
'scenes' => $scenes,
|
||||
'download_required' => !empty($features['download_captcha']),
|
||||
'download_active' => !empty($features['download_captcha']) && !empty($scenes['download']),
|
||||
],
|
||||
'content_audit' => [
|
||||
'enabled' => !empty($services['audit']['enabled']),
|
||||
'configured' => !empty($services['audit']['configured']),
|
||||
],
|
||||
'ip_geo' => [
|
||||
'enabled' => !empty($services['ip_geo']['enabled']),
|
||||
'configured' => !empty($services['ip_geo']['configured']),
|
||||
],
|
||||
'risk_switches' => $risk_switches,
|
||||
'services' => $services,
|
||||
],
|
||||
|
||||
@@ -37,6 +37,7 @@ class AKSRT_Admin_Schema_Permissions {
|
||||
['label' => '用户登录', 'value' => 'login'],
|
||||
['label' => '用户注册', 'value' => 'register'],
|
||||
['label' => '绑定第三方', 'value' => 'bind'],
|
||||
['label' => '绑定手机', 'value' => 'bind_phone'],
|
||||
['label' => '找回密码', 'value' => 'lostpassword'],
|
||||
['label' => '修改密码', 'value' => 'change_password'],
|
||||
['label' => '更改邮箱', 'value' => 'change_email'],
|
||||
|
||||
@@ -425,6 +425,13 @@ trait AKSRT_Auth_Service_Part_1b {
|
||||
return ['success' => false, 'error' => __('手机号格式不正确', 'aksrt')];
|
||||
}
|
||||
|
||||
if (function_exists('aksrt_require_captcha')) {
|
||||
$captcha_result = aksrt_require_captcha('bind_phone', $post);
|
||||
if ($captcha_result !== true) {
|
||||
return ['success' => false, 'error' => $captcha_result];
|
||||
}
|
||||
}
|
||||
|
||||
// 验证 SMS 验证码
|
||||
if (class_exists('AKSRT_SMS')) {
|
||||
$verify_result = AKSRT_SMS::get_instance()->verify_code($phone, $code);
|
||||
|
||||
@@ -32,6 +32,7 @@ function aksrt_captcha_scenes(): array {
|
||||
'login' => __('用户登录', 'aksrt'),
|
||||
'register' => __('用户注册', 'aksrt'),
|
||||
'bind' => __('绑定第三方', 'aksrt'),
|
||||
'bind_phone' => __('绑定手机', 'aksrt'),
|
||||
'lostpassword' => __('找回密码', 'aksrt'),
|
||||
'change_password' => __('修改密码', 'aksrt'),
|
||||
'change_email' => __('更改邮箱', 'aksrt'),
|
||||
@@ -621,7 +622,22 @@ var triggerCaptcha=function(){ showTip('验证码加载中,请稍候', '#e67e2
|
||||
function findForm(){
|
||||
form=box.closest('form');
|
||||
if(!form&&C.scene==='comment') form=document.getElementById('commentform');
|
||||
if(!form&&C.scene==='login') form=document.getElementById('aksrt-login-form')||document.querySelector('.auth-form');
|
||||
if(!form&&(C.scene==='login'||C.scene==='register')){
|
||||
form=document.getElementById('aksrt-login-form')
|
||||
||document.getElementById('aksrt-modal-login-form')
|
||||
||document.getElementById('sign-login-form')
|
||||
||document.getElementById('aksrt-phone-login-form')
|
||||
||document.getElementById('aksrt-modal-register-form')
|
||||
||document.getElementById('sign-register-form')
|
||||
||document.getElementById('aksrt-phone-register-form')
|
||||
||document.querySelector('.auth-form')
|
||||
||document.querySelector('.sign-form');
|
||||
}
|
||||
if(!form&&C.scene==='bind_phone'){
|
||||
form=document.getElementById('aksrt-bind-phone-form')
|
||||
||document.querySelector('[data-aksrt-bind-phone-form]')
|
||||
||document.querySelector('.auth-form');
|
||||
}
|
||||
return form;
|
||||
}
|
||||
|
||||
|
||||
@@ -266,6 +266,17 @@ trait AKSRT_Scripts_Part_1b {
|
||||
$version,
|
||||
true
|
||||
);
|
||||
// 绑定手机短信发送按钮依赖 sign-register 的 data-aksrt-sms-trigger 契约
|
||||
$sign_register_js = get_template_directory() . '/assets/js/sign-register.js';
|
||||
if (file_exists($sign_register_js)) {
|
||||
wp_enqueue_script(
|
||||
'aksrt-sign-register',
|
||||
$base_uri . '/assets/js/sign-register.js',
|
||||
['aksrt-route-user-center'],
|
||||
(string) filemtime($sign_register_js),
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -96,3 +96,32 @@ extract($context, EXTR_SKIP); // phpcs:ignore WordPress.PHP.DontExtract.extract_
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="phone-modal" class="aksrt-modal" hidden>
|
||||
<div class="aksrt-modal__dialog" role="dialog" aria-modal="true" aria-labelledby="phone-modal-title">
|
||||
<div class="aksrt-modal__header">
|
||||
<h3 id="phone-modal-title"><?php esc_html_e('绑定手机', 'aksrt'); ?></h3>
|
||||
<button type="button" class="aksrt-modal__close" data-modal-close="phone-modal" aria-label="<?php esc_attr_e('关闭', 'aksrt'); ?>">×</button>
|
||||
</div>
|
||||
<form id="aksrt-bind-phone-form" class="aksrt-modal__body" data-aksrt-bind-phone-form>
|
||||
<div class="form-field">
|
||||
<label for="bind-phone-input"><?php esc_html_e('手机号', 'aksrt'); ?></label>
|
||||
<input type="tel" id="bind-phone-input" name="phone" data-aksrt-phone-input maxlength="11" autocomplete="tel" required placeholder="<?php esc_attr_e('请输入手机号', 'aksrt'); ?>">
|
||||
</div>
|
||||
<div class="form-field form-field--code">
|
||||
<label for="bind-phone-code"><?php esc_html_e('短信验证码', 'aksrt'); ?></label>
|
||||
<div class="input-wrap input-wrap--code">
|
||||
<input type="text" id="bind-phone-code" name="code" maxlength="8" autocomplete="one-time-code" required placeholder="<?php esc_attr_e('请输入验证码', 'aksrt'); ?>">
|
||||
<button type="button" class="btn-secondary btn-sm" data-aksrt-sms-trigger data-aksrt-sms-scene="bind_phone" data-aksrt-sms-phone="#bind-phone-input"><?php esc_html_e('获取验证码', 'aksrt'); ?></button>
|
||||
</div>
|
||||
</div>
|
||||
<?php if (function_exists('aksrt_render_captcha')) : ?>
|
||||
<?php aksrt_render_captcha('bind_phone'); ?>
|
||||
<?php endif; ?>
|
||||
<div class="aksrt-modal__actions">
|
||||
<button type="submit" class="btn-primary"><?php esc_html_e('确认绑定', 'aksrt'); ?></button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -36,6 +36,18 @@ defined('ABSPATH') || exit;
|
||||
<button type="button" class="btn-primary btn-sm security-trigger" data-modal="email-modal">
|
||||
<?php esc_html_e('更改', 'aksrt'); ?>
|
||||
</button>
|
||||
<div class="security-action-item">
|
||||
<div class="security-action-info">
|
||||
<span class="security-action-icon"><i class="fas fa-mobile-alt" aria-hidden="true"></i></span>
|
||||
<div class="security-action-text">
|
||||
<span class="security-action-title"><?php esc_html_e('绑定手机', 'aksrt'); ?></span>
|
||||
<span class="security-action-desc"><?php esc_html_e('绑定手机号后可使用短信验证码登录', 'aksrt'); ?></span>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn-primary btn-sm security-trigger" data-modal="phone-modal">
|
||||
<?php esc_html_e('绑定', 'aksrt'); ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user