Minor fixes

This commit is contained in:
Ivan Nikolskiy 2025-05-28 01:46:30 +02:00
parent 41a3c25fae
commit 0e40f0691e
5 changed files with 83 additions and 21 deletions

65
.gitignore vendored Normal file
View File

@ -0,0 +1,65 @@
test
# Python
__pycache__/
*.py[cod]
*.pyo
*.pyd
*.so
# Virtual environments
env/
venv/
ENV/
*.egg-info/
.eggs/
# Django migrations
**/migrations/
!*/migrations/__init__.py
# SQLite database
*.sqlite3
*.db
# IDEs and editors
.vscode/
.idea/
*.swp
*~
# OS files
.DS_Store
Thumbs.db
# Static/media cache (optional, uncomment if needed)
# staticfiles/
# media/
# Logs
*.log
# Coverage & testing
htmlcov/
coverage.xml
.tox/
.nox/
.pytest_cache/
# dotenv or secrets
.env
.env.*
# Redis dump or cache (if using)
*.rdb
# Node (if using JS build tools)
node_modules/
# Docker
*.pid
*.tar
*.sock
docker-compose.override.yml

View File

@ -130,11 +130,10 @@ function startPasswordReset() {
You may optionally pass a custom onCaptcha renderer if you want to override the default iframe design:
```javascript
hoptchaPost('/users/send-reset/', payload, onSuccess, onError, function customCaptchaRenderer(url, key, callback) {
hoptchaPost('/users/send-reset/', payload, onSuccess, onError, function customCaptchaRenderer(url) {
// Your custom UI logic here
showCustomModal();
renderMyCustomCaptchaIframe(url, key);
window._captchaSuccessCallback = callback;
renderMyCustomCaptchaIframe(url);
});
```
@ -184,10 +183,9 @@ The `@ratelimit` decorator enforces strict rate limits while `@hoptcha_protected
You can override the default iframe and style using the optional onCaptcha parameter in the hoptchaPost() JavaScript function. This is useful if you want to match your apps branding or use modals.
```javascript
hoptchaPost('/endpoint', payload, onSuccess, onError, function renderCustom(url, key, cb) {
hoptchaPost('/endpoint', payload, onSuccess, onError, function renderCustom(url, key) {
// Replace container with your custom implementation
$('#myCustomCaptchaArea').html(`<iframe src="${url}?client_key=${key}"></iframe>`);
window._captchaSuccessCallback = cb;
});
```

View File

@ -22,6 +22,9 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
import time
from urllib.parse import urlencode
from functools import wraps
from django.core.cache import cache
from django.http import JsonResponse
@ -92,11 +95,11 @@ def hoptcha_protected(
if not token or not verify_token(token):
return response(request) if response else JsonResponse({
"error": "CAPTCHA",
"url": GENERATE_URL,
"key": PUBLIC_KEY
"url": f"{GENERATE_URL}?{urlencode({'client_key': PUBLIC_KEY, 'timestamp': int(time.time() * 1000)})}"
}, status=400)
else:
cache.delete(cache_key) # reset counter if passed
return view_func(request, *args, **kwargs)
timeout_val = timeout * (2 ** (attempts - threshold)) if backoff and attempts >= threshold else timeout
cache.set(cache_key, attempts + 1, timeout=timeout_val)

View File

@ -21,21 +21,16 @@
/**
* Renders the Hoptcha iframe inside #hoptcha-container.
* @param {string} captcha_url - The Hoptcha URL endpoint.
* @param {string} client_key - The client public key.
* @param {function} onSuccessCallback - Called with token when CAPTCHA is solved.
* @param {string} url - The Hoptcha URL endpoint.
*/
window.renderCaptchaStep = function(captcha_url, client_key, onSuccessCallback) {
window.renderCaptchaStep = function(url) {
$('#hoptcha-container').html(`
<iframe
id="captcha-iframe"
src="${captcha_url}?client_key=${client_key}"
src=${url}
style="width: 100%; height: 250px; border: none; border-radius: 12px;"
></iframe>
`);
// Register callback
window._captchaSuccessCallback = onSuccessCallback;
};
/**
@ -51,19 +46,21 @@
}).fail(xhr => {
const error = xhr.responseJSON ? xhr.responseJSON.error : 'Something went wrong.';
const captcha_url = xhr.responseJSON?.url;
const client_key = xhr.responseJSON?.key;
if (!captcha_url || !client_key) {
if (!captcha_url) {
if (onError) onError(error);
else console.error(error);
return;
}
const render = onCaptcha || window.renderCaptchaStep;
render(captcha_url, client_key, function(token) {
// 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);
});
};

View File

@ -4,4 +4,3 @@
style="width: 100%; height: 250px; border: none; border-radius: 12px;">
</iframe>
</div>
<script src="{% static 'django_hoptcha/hoptcha.js' %}"></script>