From 17e7ae140e1a8495f4c784bcefb5ee37ff8f749b Mon Sep 17 00:00:00 2001 From: Ivan Nikolskiy Date: Mon, 9 Jun 2025 23:31:18 +0200 Subject: [PATCH] Change captcha logic --- django_hoptcha/decorators.py | 4 +- .../static/django_hoptcha/hoptcha.js | 50 ++++++++++--------- 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/django_hoptcha/decorators.py b/django_hoptcha/decorators.py index 091f5da..3ff2d30 100755 --- a/django_hoptcha/decorators.py +++ b/django_hoptcha/decorators.py @@ -121,9 +121,9 @@ def hoptcha_protected( if not token or not verify_token(token): return response(request) if response else JsonResponse({ - "error": "CAPTCHA", + "captcha": True, "url": f"{GENERATE_URL}?{urlencode({'client_key': PUBLIC_KEY, 'timestamp': int(time.time() * 1000), 'type': type})}" - }, status=400) + }, status=200) else: cache.delete(cache_key) # reset counter if passed return view_func(request, *args, **kwargs) diff --git a/django_hoptcha/static/django_hoptcha/hoptcha.js b/django_hoptcha/static/django_hoptcha/hoptcha.js index 3d614b3..22f0e8e 100755 --- a/django_hoptcha/static/django_hoptcha/hoptcha.js +++ b/django_hoptcha/static/django_hoptcha/hoptcha.js @@ -56,34 +56,38 @@ body: JSON.stringify(payload) }) .then(response => { - if (!response.ok) { - return response.json().then(data => { - throw { status: response.status, data }; - }); - } - return response.json(); + return response.json().then(data => { + return { ok: response.ok, data }; + }); }) - .then(data => { - if (onSuccess) onSuccess(data); - }) - .catch(err => { - const error = err.data?.error || 'Something went wrong.'; - const captcha_url = err.data?.url; + .then(({ ok, data }) => { + const captchaNeeded = data?.captcha === true; + const captchaUrl = data?.url; - if (!captcha_url) { - if (onError) onError(error); - else console.error(error); + if (captchaNeeded && captchaUrl) { + // Register retry callback + window._captchaSuccessCallback = function (token) { + payload.captcha_token = token; + window.hoptchaPost(url, payload, onSuccess, onError, onCaptcha); + }; + + const render = onCaptcha || window.renderCaptchaStep; + render(captchaUrl); return; } - // Register callback - window._captchaSuccessCallback = function (token) { - payload.captcha_token = token; - window.hoptchaPost(url, payload, onSuccess, onError, onCaptcha); - }; - - const render = onCaptcha || window.renderCaptchaStep; - render(captcha_url); + if (ok) { + if (onSuccess) onSuccess(data); + } else { + const error = data?.error || 'Something went wrong.'; + if (onError) onError(error); + else console.error(error); + } + }) + .catch(err => { + const fallback = typeof err === 'string' ? err : err?.data?.error || 'Something went wrong.'; + if (onError) onError(fallback); + else console.error(fallback); }); }; })(window);