Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions django_altcha/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import base64
import datetime
import json
import logging

from django import forms
from django.core.cache import caches
Expand All @@ -23,6 +24,8 @@

from .conf import get_setting

logger = logging.getLogger(__name__)

__version__ = "0.10.0"
VERSION = __version__

Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand All @@ -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
Expand Down