Skip to content

Commit 8149682

Browse files
committed
feat: add logging for verification errors, disabled state, and replay attacks
- Add a module-level logger using logging.getLogger(__name__) - Log a warning when ALTCHA_VERIFICATION_ENABLED is False, making it clear that the CAPTCHA provides no protection in that state - Log a warning with the exception message when verification raises an unexpected error, aiding debugging without leaking details to the user - Log a warning when verification returns a failed result, including the error detail from the altcha library - Log a warning with the challenge hash when a replay attack is detected - Log a warning with the exception message when payload decoding fails Signed-off-by: Hervé Le Roy <hleroy@hleroy.com>
1 parent 9d0895f commit 8149682

1 file changed

Lines changed: 17 additions & 2 deletions

File tree

django_altcha/__init__.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import base64
99
import datetime
1010
import json
11+
import logging
1112

1213
from django import forms
1314
from django.core.cache import caches
@@ -23,6 +24,8 @@
2324

2425
from .conf import get_setting
2526

27+
logger = logging.getLogger(__name__)
28+
2629
__version__ = "0.10.0"
2730
VERSION = __version__
2831

@@ -225,9 +228,15 @@ def __init__(self, *args, **kwargs):
225228
kwargs["widget"] = self.widget(options=widget_options)
226229
super().__init__(*args, **kwargs)
227230

231+
def log_warning(self, message):
232+
logger.warning(message)
233+
228234
def validate(self, value):
229235
"""Validate the CAPTCHA token and verify its authenticity."""
230236
if not get_setting("ALTCHA_VERIFICATION_ENABLED"):
237+
self.log_warning(
238+
"ALTCHA verification is disabled. CAPTCHA provides no protection."
239+
)
231240
return
232241

233242
super().validate(value)
@@ -243,10 +252,12 @@ def validate(self, value):
243252
hmac_key=get_hmac_key(),
244253
check_expires=True,
245254
)
246-
except Exception:
255+
except Exception as e:
256+
self.log_warning(f"ALTCHA verification error: {e}")
247257
raise forms.ValidationError(self.error_messages["error"], code="error")
248258

249259
if not verified:
260+
self.log_warning(f"ALTCHA verification failed: {error}")
250261
raise forms.ValidationError(self.error_messages["invalid"], code="invalid")
251262

252263
self.replay_attack_protection(payload=value)
@@ -257,10 +268,14 @@ def replay_attack_protection(self, payload):
257268
# Decode payload from base64 and parse JSON to extract the challenge
258269
payload_data = json.loads(base64.b64decode(payload).decode())
259270
challenge = payload_data["challenge"]
260-
except Exception:
271+
except Exception as e:
272+
self.log_warning(f"ALTCHA failed to decode payload: {e}")
261273
raise forms.ValidationError(self.error_messages["error"], code="error")
262274

263275
if is_challenge_used(challenge):
276+
self.log_warning(
277+
f"ALTCHA replay attack detected for challenge: {challenge}"
278+
)
264279
raise forms.ValidationError(self.error_messages["replay"], code="invalid")
265280

266281
# Mark as used for the same duration as challenge expiration

0 commit comments

Comments
 (0)