{"id":9457,"library":"altcha","title":"ALTCHA Library","description":"The `altcha` library provides tools for creating and verifying ALTCHA challenges, a privacy-friendly, self-hosted, and free alternative to CAPTCHA. It allows Python applications to generate cryptographic proof-of-work challenges and validate responses from clients, protecting against bots and spam. The current version is 2.0.0, and it follows an infrequent but impactful release cadence, with major versions introducing API changes.","status":"active","version":"2.0.0","language":"en","source_language":"en","source_url":"https://github.com/altcha-org/altcha-lib-py","tags":["captcha","security","anti-bot","challenge","proof-of-work","privacy"],"install":[{"cmd":"pip install altcha","lang":"bash","label":"Install stable version"}],"dependencies":[],"imports":[{"note":"The main Altcha class is now directly available from the top-level package since v2.0.0.","wrong":"from altcha.challenge import Altcha","symbol":"Altcha","correct":"from altcha import Altcha"},{"symbol":"ChallengeResult","correct":"from altcha import ChallengeResult"}],"quickstart":{"code":"import os\nimport time\nfrom altcha import Altcha, ChallengeResult\n\n# Initialize Altcha with your secret key\n# IMPORTANT: Replace 'altcha-dev-secret-key...' with a strong, random, 32+ character key\n# and set it via an environment variable in production (e.g., ALTCHA_SECRET_KEY).\nsecret_key = os.environ.get('ALTCHA_SECRET_KEY', 'altcha-dev-secret-key-1234567890abcdef')\n\nif secret_key == 'altcha-dev-secret-key-1234567890abcdef':\n    print(\"WARNING: Using a default development secret key. Set ALTCHA_SECRET_KEY environment variable with a strong, random key in production!\")\n\naltcha = Altcha(secret_key)\n\n# --- QUICKSTART PART 1: Generate a Challenge ---\nprint(\"\\n--- Generating a Challenge ---\")\n# The 'challenge_obj' contains all necessary fields for the client.\nchallenge_obj = altcha.generate_challenge()\nchallenge_for_client = challenge_obj.to_json() # This JSON string is what you send to the client.\nprint(f\"Generated Challenge (for client): {challenge_for_client}\")\n\n# In a real scenario, the client-side JavaScript library would solve this challenge\n# and send back the original challenge data along with a computed 'response' string.\n\n# --- QUICKSTART PART 2: Verify a Challenge Response ---\nprint(\"\\n--- Verifying a Challenge Response ---\")\n\n# For demonstration, we'll use a hardcoded valid challenge/response pair.\n# This 'solved_client_response' simulates what a client would send back after solving.\n# The 'response' field comes from the client-side JS library's computation.\nsolved_client_response = {\n    \"challenge\": \"b4e4d7730e6a8e8073b64c748c5a21e421e421e4\", \n    \"signature\": \"283738b52a16d8a39e99279a059c259687e35b7501a4e1d1f042657d47833072\",\n    \"algorithm\": \"sha1\", \n    \"salt\": \"altcha_salt\",\n    \"expire\": int(time.time() + 3600), # Ensure expiry is in the future for verification.\n    \"response\": \"sha1:1000:altcha_salt:s/h0QhQ2L2yYmYg5X2V5Q5R5R5Q5Y5h5y5Q5L2xY=\"\n}\n\ntry:\n    verification_result: ChallengeResult = altcha.verify(solved_client_response)\n    if verification_result.verified:\n        print(\"✅ Challenge Verified Successfully!\")\n    else:\n        print(f\"❌ Challenge Verification Failed: {verification_result.error}\")\n        # Common errors: 'challenge_expired', 'invalid_signature', 'incorrect_proof'\nexcept ValueError as e:\n    print(f\"❌ Verification Error (ValueError): {e}\")\n\n# --- QUICKSTART PART 3: Demonstrate an Invalid Response ---\nprint(\"\\n--- Demonstrating an Invalid Response ---\")\n# An example where the challenge hash is intentionally wrong.\ninvalid_response_data = {\n    \"challenge\": \"wrong_challenge_hash\", \n    \"signature\": solved_client_response[\"signature\"],\n    \"algorithm\": solved_client_response[\"algorithm\"],\n    \"salt\": solved_client_response[\"salt\"],\n    \"expire\": solved_client_response[\"expire\"],\n    \"response\": solved_client_response[\"response\"]\n}\n\ntry:\n    invalid_result = altcha.verify(invalid_response_data)\n    if not invalid_result.verified:\n        print(f\"✅ Invalid challenge handled correctly. Error: {invalid_result.error}\")\n    else:\n        print(\"❌ Unexpected: Invalid challenge was verified.\")\nexcept ValueError as e:\n    print(f\"✅ Invalid challenge handled correctly with ValueError: {e}\")","lang":"python","description":"This quickstart demonstrates how to initialize the `Altcha` object with a secret key, generate a challenge to be sent to a client, and then verify a client's response. It includes a hardcoded example of a valid client response for successful verification, and an example of an invalid response for error handling. Remember to replace the placeholder secret key with a strong, random key in production."},"warnings":[{"fix":"Migrate your code to use `altcha = Altcha(secret_key)` and then call `altcha.generate_challenge()` and `altcha.verify(client_response_data)`.","message":"Version 2.0.0 introduces significant breaking changes compared to 1.x. The primary API now revolves around the `Altcha` class, which must be initialized with a secret key. Top-level functions like `generate_challenge` and `verify_challenge` are removed; their functionality is now available as methods on an `Altcha` instance.","severity":"breaking","affected_versions":">=2.0.0"},{"fix":"Always use a strong, unique secret key. Store it securely (e.g., in environment variables) and ensure the same key is used for both generating and verifying challenges.","message":"The `secret_key` used for initializing the `Altcha` object is critical. It must be a strong, random string (at least 32 characters long) and kept consistent between challenge generation and verification. Any mismatch or compromise of this key will lead to verification failures or security vulnerabilities.","severity":"gotcha","affected_versions":"All"},{"fix":"Ensure you integrate the ALTCHA client-side JavaScript library into your frontend application to properly solve and send challenge responses to your Python backend.","message":"This Python library handles only the server-side logic (challenge generation and verification). A separate client-side JavaScript library (or custom client implementation) is required to solve the challenges and provide the 'response' string that this library then verifies.","severity":"gotcha","affected_versions":"All"},{"fix":"Configure a reasonable expiry time for challenges (e.g., a few minutes) and ensure your server processes client responses promptly. Clients should also attempt to solve and submit challenges within the expiry window.","message":"Challenges have an `expire` timestamp. If a client's response is received and verified after this timestamp, the verification will fail with a `challenge_expired` error.","severity":"gotcha","affected_versions":"All"}],"env_vars":null,"last_verified":"2026-04-17T00:00:00.000Z","next_check":"2026-07-16T00:00:00.000Z","problems":[{"fix":"Initialize the `Altcha` class and call its `verify` method: `altcha_instance = Altcha(secret_key); result = altcha_instance.verify(client_response_data)`.","cause":"You are attempting to use the old v1.x top-level `verify_challenge` function in altcha v2.x.","error":"AttributeError: module 'altcha' has no attribute 'verify_challenge'"},{"fix":"Provide a strong, random secret key that is at least 32 characters long. Example: `Altcha('your-strong-random-secret-key-of-32-chars')`.","cause":"The `secret_key` provided when initializing `Altcha` is too short or invalid.","error":"ValueError: Secret key must be a string of at least 32 characters."},{"fix":"Ensure challenges are generated with a realistic expiry (e.g., a few minutes into the future) and client responses are processed within that time frame. Check system clocks for synchronization issues.","cause":"The `expire` timestamp included in the client's response data indicates that the challenge is no longer valid.","error":"Challenge verification failed: challenge_expired"},{"fix":"Verify that the `secret_key` used to initialize `Altcha` on the server is identical to the one used for challenge generation. Ensure the challenge data (`challenge`, `salt`, `expire`) sent to the client and received back has not been altered.","cause":"The signature provided by the client does not match the signature computed by the server using its `secret_key` or the challenge data has been tampered with.","error":"Challenge verification failed: invalid_signature"}]}