import hashlib import hmac import secrets import base64 import json import time class AltchaChallenge: """Self-hosted Altcha challenge generator and verifier.""" def __init__(self, hmac_key=None): self.hmac_key = hmac_key or secrets.token_hex(32) def create_challenge(self, max_number=100000): """Generate a new Altcha challenge.""" salt = secrets.token_hex(12) secret_number = secrets.randbelow(max_number) + 1 # Create the challenge string that needs to be solved challenge_data = f"{salt}{secret_number}" challenge = hashlib.sha256(challenge_data.encode()).hexdigest() # Create signature for verification signature = hmac.new( self.hmac_key.encode(), challenge.encode(), hashlib.sha256 ).hexdigest() return { "algorithm": "SHA-256", "challenge": challenge, "maxnumber": max_number, "salt": salt, "signature": signature } def verify_solution(self, payload): """Verify an Altcha solution payload.""" try: # Decode base64 payload decoded = base64.b64decode(payload).decode('utf-8') data = json.loads(decoded) algorithm = data.get('algorithm', '') challenge = data.get('challenge', '') number = data.get('number', 0) salt = data.get('salt', '') signature = data.get('signature', '') # Verify algorithm if algorithm.upper() != 'SHA-256': return False # Verify signature expected_signature = hmac.new( self.hmac_key.encode(), challenge.encode(), hashlib.sha256 ).hexdigest() if not hmac.compare_digest(signature, expected_signature): return False # Verify the solution challenge_data = f"{salt}{number}" computed_challenge = hashlib.sha256(challenge_data.encode()).hexdigest() return hmac.compare_digest(computed_challenge, challenge) except Exception: return False _altcha_instances = {} def get_altcha(hmac_key): """Get or create an Altcha instance for the given HMAC key.""" if hmac_key not in _altcha_instances: _altcha_instances[hmac_key] = AltchaChallenge(hmac_key) return _altcha_instances[hmac_key]