implement JS password scoring, td_stock approve logicc

This commit is contained in:
Thanakorn S
2026-04-30 15:14:42 +07:00
parent db5c47b6ca
commit ac4fd9a5ad
3147 changed files with 1298 additions and 343 deletions
+26 -44
View File
@@ -5,6 +5,9 @@
?>
<body>
<!-- zxcvbn JS: client-side password strength scoring, no server round-trip -->
<script src="https://cdn.jsdelivr.net/npm/zxcvbn@4.4.2/dist/zxcvbn.js"></script>
<?php require '../include_topbar.php'; ?>
<?php require '../include_setting_sidebar.php'; ?>
@@ -318,12 +321,8 @@
// ═══════════════════════════════════════════════════════
// State
// ═══════════════════════════════════════════════════════
var pw_score = -1;
var pw_debounce = null;
var pw_check_xhr = null;
var reset_pw_score = -1;
var reset_pw_debounce = null;
var reset_pw_check_xhr = null;
var pw_score = -1;
var reset_pw_score = -1;
var user_email = ''; // stored on retrieve, used for modal masking
function mask_email(email) {
@@ -448,9 +447,8 @@
// CHANGE PASSWORD
// ═══════════════════════════════════════════════════════
function on_new_password_input(pw) {
clearTimeout(pw_debounce);
if (!pw) { reset_strength_ui('pw'); update_pw_button(); return; }
pw_debounce = setTimeout(() => check_strength(pw, 'pw'), 350);
check_strength(pw, 'pw');
}
function check_confirm_match() {
@@ -474,6 +472,7 @@
}
function change_password() {
if (pw_score < 3) { bootbox.alert('Please choose a stronger password.'); return; }
return ajax_request({
url: '<?php echo $server_url?>setting/api/engine/change_password.php',
autoPrepare: false,
@@ -542,9 +541,8 @@
}
function on_reset_password_input(pw) {
clearTimeout(reset_pw_debounce);
if (!pw) { reset_strength_ui('reset'); update_reset_button(); return; }
reset_pw_debounce = setTimeout(() => check_strength(pw, 'reset'), 350);
check_strength(pw, 'reset');
}
function check_reset_confirm_match() {
@@ -568,6 +566,7 @@
}
function confirm_reset_password() {
if (reset_pw_score < 3) { bootbox.alert('Please choose a stronger password.'); return; }
return ajax_request({
url: '<?php echo $server_url?>setting/api/engine/reset_password_otp.php',
autoPrepare: false,
@@ -595,45 +594,28 @@
// prefix = 'pw' | 'reset'
// ═══════════════════════════════════════════════════════
function check_strength(pw, prefix) {
// Abort pending request
if (prefix === 'pw' && pw_check_xhr) pw_check_xhr.abort();
if (prefix === 'reset' && reset_pw_check_xhr) reset_pw_check_xhr.abort();
const user_inputs = [
$('#name').val(), $('#surname').val(),
$('#username').val(), user_email
].filter(Boolean);
const xhr = $.ajax({
url: '<?php echo $server_url?>setting/api/engine/check_password.php',
type: 'POST',
dataType: 'json',
data: { json: JSON.stringify({
otp: document.getElementById('session-context').dataset.otp,
company_id: document.getElementById('session-context').dataset.companyId,
action: 'read',
password: pw,
})},
headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') },
success: function(res) {
const score = res.score ?? -1;
const result = zxcvbn(pw, user_inputs);
const score = result.score;
if (prefix === 'pw') pw_score = score;
if (prefix === 'reset') reset_pw_score = score;
if (prefix === 'pw') pw_score = score;
if (prefix === 'reset') reset_pw_score = score;
const bar = prefix === 'pw' ? '#pw_strength_bar' : '#reset_strength_bar';
const label = prefix === 'pw' ? '#pw_strength_label' : '#reset_strength_label';
const feedback = prefix === 'pw' ? '#pw_feedback' : '#reset_feedback';
const bar = prefix === 'pw' ? '#pw_strength_bar' : '#reset_strength_bar';
const label = prefix === 'pw' ? '#pw_strength_label' : '#reset_strength_label';
const feedback = prefix === 'pw' ? '#pw_feedback' : '#reset_feedback';
if (score < 0) { reset_strength_ui(prefix); return; }
const lvl = STRENGTH_LEVELS[score];
$(bar).css({ width: lvl.pct + '%', backgroundColor: lvl.color });
$(label).text(lvl.label).css('color', lvl.color);
$(feedback).text(result.feedback.warning || result.feedback.suggestions[0] || '');
const lvl = STRENGTH_LEVELS[score];
$(bar).css({ width: lvl.pct + '%', backgroundColor: lvl.color });
$(label).text(lvl.label).css('color', lvl.color);
$(feedback).text(res.feedback || '');
if (prefix === 'pw') { check_confirm_match(); update_pw_button(); }
if (prefix === 'reset') { check_reset_confirm_match(); update_reset_button(); }
}
});
if (prefix === 'pw') pw_check_xhr = xhr;
if (prefix === 'reset') reset_pw_check_xhr = xhr;
if (prefix === 'pw') { check_confirm_match(); update_pw_button(); }
if (prefix === 'reset') { check_reset_confirm_match(); update_reset_button(); }
}
function reset_strength_ui(prefix) {