diff --git a/assets/admin/pages/LoginPage.tsx b/assets/admin/pages/LoginPage.tsx index f707a9be..6b4e3778 100644 --- a/assets/admin/pages/LoginPage.tsx +++ b/assets/admin/pages/LoginPage.tsx @@ -4,6 +4,7 @@ import { toast } from 'sonner'; import { EyeIcon, EyeSlashIcon } from '@heroicons/react/24/outline'; import { useAuthStore } from '../stores/authStore'; import PwaLoginCard from '../components/ui/PwaLoginCard'; +import Altcha from '../components/ui/Altcha'; import { sanitizeMobileInput } from '../lib/utils'; type Mode = 'password' | 'sms' | 'forgot'; @@ -37,6 +38,8 @@ export default function LoginPage() { const [forgotLoading, setForgotLoading] = useState(false); const [cooldown, setCooldown] = useState(0); + // آخرین payload حل‌شده‌ی ALTCHA برای مرحله‌ی جاری (یک‌بارمصرف؛ بین مراحل ریست می‌شود). + const [altcha, setAltcha] = useState(''); const timerRef = useRef | null>(null); useEffect(() => () => { if (timerRef.current) clearInterval(timerRef.current); }, []); @@ -57,6 +60,7 @@ export default function LoginPage() { setForgotStep(1); setForgotMobile(''); setForgotCode(''); setForgotUuid(''); setForgotPass(''); setForgotPass2(''); setCooldown(0); + setAltcha(''); if (timerRef.current) { clearInterval(timerRef.current); } }; @@ -84,10 +88,11 @@ export default function LoginPage() { const res = await fetch('/api/v1/user/send-code', { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ mobile }), + body: JSON.stringify({ mobile, altcha }), }); const json = await res.json(); if (!res.ok) { toast.error(json?.errors?.[0]?.message ?? 'خطا در ارسال کد'); return; } + setAltcha(''); onSuccess(json.uuid); startCooldown(); toast.success('کد تأیید ارسال شد'); @@ -117,7 +122,7 @@ export default function LoginPage() { const lRes = await fetch('/api/v1/user/otp-login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ grant }), + body: JSON.stringify({ grant, altcha }), }); const lJson = await lRes.json(); if (!lRes.ok) { toast.error(lJson?.errors?.[0]?.message ?? 'کاربری با این شماره یافت نشد'); return; } @@ -157,7 +162,7 @@ export default function LoginPage() { const res = await fetch('/api/v1/user/reset-password', { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ grant: forgotGrant, new_password: forgotPass }), + body: JSON.stringify({ grant: forgotGrant, new_password: forgotPass, altcha }), }); const json = await res.json(); if (!res.ok) { toast.error(json?.errors?.[0]?.message ?? 'خطا در تغییر رمز'); return; } @@ -267,6 +272,7 @@ export default function LoginPage() { value={smsMobile} onChange={(e) => setSmsMobile(sanitizeMobileInput(e.target.value))} onKeyDown={(e) => e.key === 'Enter' && handleSmsSend()} /> +
- ورود به پنل + @@ -557,6 +557,9 @@ + + + @@ -593,6 +596,15 @@ var overlay = document.getElementById('regOverlay'); var submitBtn = document.getElementById('regSubmitBtn'); var selectedType = null; +// payload حل‌شده‌ی ALTCHA (یک‌بارمصرف؛ در prod الزامی است) +var regAltchaPayload = ''; +var regAltchaEl = document.getElementById('regAltcha'); +if (regAltchaEl) +regAltchaEl.addEventListener('statechange', function (e) { +if (e.detail && e.detail.state === 'verified') +regAltchaPayload = e.detail.payload; +}); + function openRegModal() { overlay.style.display = 'block'; document.body.style.overflow = 'hidden'; @@ -674,7 +686,8 @@ body: JSON.stringify( type: selectedType, name: name, mobile: mobile, -info: info || null +info: info || null, +altcha: regAltchaPayload } ) }).then(function (r) { @@ -692,15 +705,24 @@ showMsg(errMsg, 'error'); submitBtn.disabled = false; submitBtn.style.opacity = '1'; submitBtn.textContent = 'ارسال درخواست'; +resetRegAltcha(); } }).catch(function () { showMsg('خطا در اتصال به سرور', 'error'); submitBtn.disabled = false; submitBtn.style.opacity = '1'; submitBtn.textContent = 'ارسال درخواست'; +resetRegAltcha(); }); }; +// challenge یک‌بارمصرف است؛ بعد از خطا یک challenge تازه بگیر. +function resetRegAltcha() { +regAltchaPayload = ''; +if (regAltchaEl && typeof regAltchaEl.reset === 'function') +regAltchaEl.reset(); +} + function showMsg(text, type) { var msg = document.getElementById('regMsg'); msg.textContent = text; @@ -709,6 +731,132 @@ msg.style.background = type === 'success' ? '#dcfce7' : '#fef2f2'; msg.style.color = type === 'success' ? '#16a34a' : '#ef4444'; msg.style.border = type === 'success' ? '1px solid #bbf7d0' : '1px solid #fecaca'; } +})(); + + + + + +