import hashlib import secrets from datetime import timedelta from django.utils import timezone from infrasynth.shared.settings_utils import get_setting from ..models import ALTCHAChallenge class ALTCHAService: """Proof-of-work challenge for anti-spam protection.""" def create_challenge(self) -> dict: difficulty = get_setting("INFRASYNTH_SECURITY", "ALTCHA_DIFFICULTY", 10000) expiry_seconds = get_setting("INFRASYNTH_SECURITY", "ALTCHA_CHALLENGE_EXPIRY_SECONDS", 300) challenge_id = secrets.token_hex(32) salt = secrets.token_hex(16) expires_at = timezone.now() + timedelta(seconds=expiry_seconds) ALTCHAChallenge.objects.create( challenge_id=challenge_id, salt=salt, difficulty=difficulty, expires_at=expires_at, ) return { "challenge_id": challenge_id, "salt": salt, "difficulty": difficulty, "algorithm": "SHA-256", } def verify(self, challenge_id: str, solution: str, number: int) -> bool: try: challenge = ALTCHAChallenge.objects.get(challenge_id=challenge_id, is_verified=False) except ALTCHAChallenge.DoesNotExist: return False if challenge.expires_at < timezone.now(): return False expected = hashlib.sha256(f"{challenge.salt}{number}".encode()).hexdigest() if solution != expected: return False challenge.is_verified = True challenge.save(update_fields=["is_verified"]) return True def compute_solution(self, salt: str, difficulty: int) -> tuple[str, int]: number = 0 while True: h = hashlib.sha256(f"{salt}{number}".encode()).hexdigest() if h.startswith("0" * (difficulty // 10000)): return h, number number += 1