feat(security): 新增网站安全扩展模块并支持修改手机脱敏验证
This commit is contained in:
1 parent
224f86ec08
commit
af72364078
30 files changed
+1389
-73
No files matched your search
@@ -824,16 +824,30 @@
|
||||
|
||||
function sendPhoneCode(button, form, stage) {
|
||||
if (!form || button.disabled) return;
|
||||
var phone = String((form.querySelector('[name="phone"]') || {}).value || '').trim();
|
||||
if (!phone) { notyf('请输入手机号', 'warning'); return; }
|
||||
var payload = { stage: stage };
|
||||
if (stage === 'verify_old_phone') {
|
||||
var dialog = form.closest('[data-account-dialog="phone"]');
|
||||
var boxes = dialog ? phoneDigitBoxes(dialog) : [];
|
||||
if (boxes.length) {
|
||||
var hiddenLength = parseInt(dialog.querySelector('[data-aksrt-phone-digits]').getAttribute('data-hidden-length'), 10) || boxes.length;
|
||||
var middle = phoneDigitsValue(dialog);
|
||||
if (middle.length !== hiddenLength) { notyf('请先补全手机号缺失的数字', 'warning'); return; }
|
||||
payload.middle = middle;
|
||||
}
|
||||
} else {
|
||||
var phone = String((form.querySelector('[name="phone"]') || {}).value || '').trim();
|
||||
if (!phone) { notyf('请输入手机号', 'warning'); return; }
|
||||
payload.phone = phone;
|
||||
}
|
||||
runCaptcha('bind_phone', form).then(function (captchaPayload) {
|
||||
if (captchaPayload === null) return null;
|
||||
var restRoot = settingsRestRoot();
|
||||
var nonce = settingsRestNonce();
|
||||
Object.keys(captchaPayload || {}).forEach(function (key) { payload[key] = captchaPayload[key]; });
|
||||
var request = fetch(restRoot + '/user/phone-code', {
|
||||
method: 'POST', credentials: 'same-origin',
|
||||
headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': nonce },
|
||||
body: JSON.stringify(Object.assign({ phone: phone, stage: stage }, captchaPayload || {}))
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
button.disabled = true;
|
||||
return request;
|
||||
@@ -902,6 +916,116 @@
|
||||
}).finally(function () { resetCaptcha('bind_phone', form); });
|
||||
}
|
||||
|
||||
/* ---- 修改手机:脱敏中间位数字框(格数随号码长度变化) ---- */
|
||||
function phoneDigitBoxes(dialog) {
|
||||
return Array.prototype.slice.call(dialog.querySelectorAll('[data-aksrt-phone-digits] .aksrt-phone-digit'));
|
||||
}
|
||||
|
||||
function phoneDigitsValue(dialog) {
|
||||
return phoneDigitBoxes(dialog).map(function (input) { return String(input.value || '').replace(/\D/g, ''); }).join('');
|
||||
}
|
||||
|
||||
function setPhoneDigitsError(dialog, message) {
|
||||
var group = dialog.querySelector('[data-aksrt-phone-digits]');
|
||||
var error = dialog.querySelector('[data-aksrt-phone-digits-error]');
|
||||
if (error) {
|
||||
error.textContent = message || '';
|
||||
error.hidden = !message;
|
||||
}
|
||||
if (group) group.classList.toggle('has-error', !!message);
|
||||
}
|
||||
|
||||
function hidePhoneCodeArea(dialog, options) {
|
||||
var area = dialog.querySelector('[data-aksrt-phone-code-area]');
|
||||
if (!area) return;
|
||||
var wasVisible = !area.hidden;
|
||||
area.hidden = true;
|
||||
area.querySelectorAll('.account-code-send,[data-aksrt-sms-trigger]').forEach(resetCountdown);
|
||||
if (wasVisible && options && options.destroyCode) {
|
||||
// 中间位被修改:销毁服务端已发放的老号验证码状态。
|
||||
fetch(settingsRestRoot() + '/user/phone-code', {
|
||||
method: 'POST', credentials: 'same-origin',
|
||||
headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': settingsRestNonce() },
|
||||
body: JSON.stringify({ stage: 'reset_old_phone' })
|
||||
}).catch(function () {});
|
||||
}
|
||||
}
|
||||
|
||||
function verifyPhoneMiddle(dialog) {
|
||||
var group = dialog.querySelector('[data-aksrt-phone-digits]');
|
||||
var boxes = phoneDigitBoxes(dialog);
|
||||
if (!group || !boxes.length) return;
|
||||
var hiddenLength = parseInt(group.getAttribute('data-hidden-length'), 10) || boxes.length;
|
||||
var middle = phoneDigitsValue(dialog);
|
||||
if (middle.length !== hiddenLength) return;
|
||||
|
||||
dialog.__aksrtPhoneMatchTicket = (dialog.__aksrtPhoneMatchTicket || 0) + 1;
|
||||
var ticket = dialog.__aksrtPhoneMatchTicket;
|
||||
fetch(settingsRestRoot() + '/user/phone-match', {
|
||||
method: 'POST', credentials: 'same-origin',
|
||||
headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': settingsRestNonce() },
|
||||
body: JSON.stringify({ middle: middle })
|
||||
}).then(function (response) { return response.json().then(function (payload) { return { ok: response.ok, payload: payload }; }); }).then(function (result) {
|
||||
if (ticket !== dialog.__aksrtPhoneMatchTicket) return;
|
||||
if (result.ok && result.payload.success) {
|
||||
var area = dialog.querySelector('[data-aksrt-phone-code-area]');
|
||||
if (area) area.hidden = false;
|
||||
setPhoneDigitsError(dialog, '');
|
||||
} else {
|
||||
hidePhoneCodeArea(dialog, { destroyCode: true });
|
||||
setPhoneDigitsError(dialog, (result.payload && result.payload.message) || '填写的号码与绑定手机号不一致');
|
||||
}
|
||||
}).catch(function () {
|
||||
if (ticket === dialog.__aksrtPhoneMatchTicket) {
|
||||
hidePhoneCodeArea(dialog, { destroyCode: false });
|
||||
setPhoneDigitsError(dialog, '网络错误,请重试');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function initPhoneDigits(dialog) {
|
||||
var boxes = phoneDigitBoxes(dialog);
|
||||
if (!boxes.length || dialog.dataset.aksrtDigitsBound === 'true') return;
|
||||
dialog.dataset.aksrtDigitsBound = 'true';
|
||||
|
||||
boxes.forEach(function (input, index) {
|
||||
input.addEventListener('input', function () {
|
||||
var value = String(input.value || '').replace(/\D/g, '');
|
||||
input.value = value === '' ? '' : value.charAt(value.length - 1);
|
||||
hidePhoneCodeArea(dialog, { destroyCode: true });
|
||||
setPhoneDigitsError(dialog, '');
|
||||
if (input.value !== '' && index < boxes.length - 1) boxes[index + 1].focus();
|
||||
verifyPhoneMiddle(dialog);
|
||||
});
|
||||
input.addEventListener('keydown', function (event) {
|
||||
if (event.key === 'Backspace' && !input.value && index > 0) {
|
||||
event.preventDefault();
|
||||
boxes[index - 1].value = '';
|
||||
boxes[index - 1].focus();
|
||||
hidePhoneCodeArea(dialog, { destroyCode: true });
|
||||
setPhoneDigitsError(dialog, '');
|
||||
} else if (event.key === 'ArrowLeft' && index > 0) {
|
||||
boxes[index - 1].focus();
|
||||
} else if (event.key === 'ArrowRight' && index < boxes.length - 1) {
|
||||
boxes[index + 1].focus();
|
||||
}
|
||||
});
|
||||
input.addEventListener('paste', function (event) {
|
||||
var text = String((event.clipboardData || window.clipboardData).getData('text') || '');
|
||||
var digits = text.replace(/\D/g, '');
|
||||
if (!digits) return;
|
||||
event.preventDefault();
|
||||
for (var offset = 0; offset < boxes.length - index && offset < digits.length; offset++) {
|
||||
boxes[index + offset].value = digits.charAt(offset);
|
||||
}
|
||||
boxes[Math.min(index + digits.length, boxes.length - 1)].focus();
|
||||
hidePhoneCodeArea(dialog, { destroyCode: true });
|
||||
setPhoneDigitsError(dialog, '');
|
||||
verifyPhoneMiddle(dialog);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function sendRecoveryCode(button, form) {
|
||||
if (!form || button.disabled) return;
|
||||
var target = String((form.querySelector('[name="target"]') || {}).value || '').trim();
|
||||
@@ -1031,6 +1155,7 @@
|
||||
});
|
||||
});
|
||||
} else if (type === 'phone') {
|
||||
initPhoneDigits(dialog);
|
||||
dialog.querySelectorAll('[data-aksrt-sms-trigger]').forEach(function (button) {
|
||||
button.addEventListener('click', function () { sendPhoneCode(button, button.closest('form'), button.getAttribute('data-aksrt-sms-scene')); });
|
||||
});
|
||||
@@ -1054,6 +1179,15 @@
|
||||
if (!shell || !shell.classList.contains('aksrt-user-settings-modal')) return;
|
||||
shell.querySelectorAll('.account-code-send,[data-aksrt-sms-trigger],[data-account-recovery-send]').forEach(resetCountdown);
|
||||
shell.querySelectorAll('form').forEach(function (form) { form.reset(); });
|
||||
shell.querySelectorAll('[data-account-dialog="phone"]').forEach(function (dialog) {
|
||||
dialog.querySelectorAll('.aksrt-phone-digit').forEach(function (input) { input.value = ''; });
|
||||
var group = dialog.querySelector('[data-aksrt-phone-digits]');
|
||||
if (group) group.classList.remove('has-error');
|
||||
var error = dialog.querySelector('[data-aksrt-phone-digits-error]');
|
||||
if (error) { error.hidden = true; error.textContent = ''; }
|
||||
var area = dialog.querySelector('[data-aksrt-phone-code-area]');
|
||||
if (area) area.hidden = !!group;
|
||||
});
|
||||
}
|
||||
|
||||
if (document.documentElement.dataset.aksrtSettingsModalCleanupInitialized !== 'true') {
|
||||
|
||||
Reference in new issue
Block a user