diff --git a/django_altcha/__init__.py b/django_altcha/__init__.py index 015f00e..d3ad3be 100644 --- a/django_altcha/__init__.py +++ b/django_altcha/__init__.py @@ -8,6 +8,7 @@ import base64 import datetime import json +import logging from django import forms from django.core.cache import caches @@ -23,6 +24,8 @@ from .conf import get_setting +logger = logging.getLogger(__name__) + __version__ = "0.10.0" VERSION = __version__ @@ -225,9 +228,15 @@ def __init__(self, *args, **kwargs): kwargs["widget"] = self.widget(options=widget_options) super().__init__(*args, **kwargs) + def log_warning(self, message): + logger.warning(message) + def validate(self, value): """Validate the CAPTCHA token and verify its authenticity.""" if not get_setting("ALTCHA_VERIFICATION_ENABLED"): + self.log_warning( + "ALTCHA verification is disabled. CAPTCHA provides no protection." + ) return super().validate(value) @@ -243,10 +252,12 @@ def validate(self, value): hmac_key=get_hmac_key(), check_expires=True, ) - except Exception: + except Exception as e: + self.log_warning("ALTCHA verification error: %s" % e) raise forms.ValidationError(self.error_messages["error"], code="error") if not verified: + self.log_warning("ALTCHA verification failed: %s" % error) raise forms.ValidationError(self.error_messages["invalid"], code="invalid") self.replay_attack_protection(payload=value) @@ -257,10 +268,14 @@ def replay_attack_protection(self, payload): # Decode payload from base64 and parse JSON to extract the challenge payload_data = json.loads(base64.b64decode(payload).decode()) challenge = payload_data["challenge"] - except Exception: + except Exception as e: + self.log_warning("ALTCHA failed to decode payload: %s" % e) raise forms.ValidationError(self.error_messages["error"], code="error") if is_challenge_used(challenge): + self.log_warning( + "ALTCHA replay attack detected for challenge: %s" % challenge + ) raise forms.ValidationError(self.error_messages["replay"], code="invalid") # Mark as used for the same duration as challenge expiration