fix(captcha): 1:1 align bind-phone and real status contracts

Add bind_phone captcha scene across schema/runtime/UI, require captcha on
phone bind, return real captcha status objects instead of legacy option
aliases, and harden form discovery for page-sign auth forms.
This commit is contained in:
kate522 committed 2026-07-13 21:14:31 +08:00
1 parent fa1ab52b8b
commit 7a4419d0dd
11 files changed
+210 -38

No files matched your search

@@ -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' },
+90 -1
View File
@@ -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();
}
});
})();
})();