Metadata-Version: 2.1
Name: django-hCaptcha
Version: 0.2.0
Summary: Django hCaptcha provides a simple way to protect your django forms using hCaptcha
Home-page: https://github.com/AndrejZbin
Author: Andrej Zbín
Author-email: zbin.andrej@gmail.com
License: BSD-3-Clause
Platform: UNKNOWN
Classifier: Environment :: Web Environment
Classifier: Framework :: Django
Classifier: Framework :: Django :: 2.2
Classifier: Framework :: Django :: 3.2
Classifier: Framework :: Django :: 4.0
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
License-File: LICENSE

===============
Django hCaptcha
===============

Django hCaptcha provides a simple way to protect your django forms using `hCaptcha <https://www.hcaptcha.com/>`_.

Configuration
-------------

Add "hcaptcha" to your INSTALLED_APPS setting like this::

    INSTALLED_APPS = [
        ...
        'hcaptcha',
    ]

For development purposes no further configuration is required. By default, django-hCaptcha will use dummy keys.

For production, you'll need to obtain your hCaptcha site key and secret key and add them to you settings::

    HCAPTCHA_SITEKEY = '<your sitekey>'
    HCAPTCHA_SECRET = '<your secret key>'


You can also configure your hCaptcha widget globally (`see all options <https://docs.hcaptcha.com/configuration>`_)::

    HCAPTCHA_DEFAULT_CONFIG = {
        'onload': 'name_of_js_function',
        'render': 'explicit',
        'theme': 'dark',  # do not use data- prefix
        'size': 'compact',  # do not use data- prefix
        ...
    }

If you need to, you can also override default hcaptcha endpoints::


    HCAPTCHA_JS_API_URL = 'https://hcaptcha.com/1/api.js'
    HCAPTCHA_VERIFY_URL = 'https://hcaptcha.com/siteverify'

Use proxies::

     HCAPTCHA_PROXIES = {
        'http': 'http://127.0.0.1:8000',
     }

Change default verification timeout::

    HCAPTCHA_TIMEOUT = 5



Usage
-----------

Simply add hCaptchaField to your forms::

    from hcaptcha.fields import hCaptchaField

    class Forms(forms.Form):
        ....
        hcaptcha = hCaptchaField()
        ....

In your template, if you need to, you can then use `{{ form.hcaptcha }}` to access the field. 

You can override default config by passing additional arguments::

    class Forms(forms.Form):
        ....
        hcaptcha = hCaptchaField(theme='dark', size='compact')
        ....


How it Works
------------------

When a form is submitted by a user, hCaptcha's JavaScript will send two POST parameters to your backend, `g-captcha-resposne` and `h-captcha-response`. These will be received by your app and will be used to complete the `hcaptcha` form field in your backend code.

When your app receives these two values, the following will happen:
 
 - Your backend will send these values to the hCaptcha servers
 - Their servers will indicate whether the values in the fields are correct
 - If so, your `hcaptcha` form field will validate correctly
 
Unit Tests
--------------
You will need to disable the hCaptcha field in your unit tests, since your tests obviously cannot complete the hCaptcha successfully. One way to do so might be something like:

.. code-block:: python

    from unittest.mock import MagicMock, patch

    from django.test import TestCase

    @patch("hcaptcha.fields.hCaptchaField.validate", return_value=True)
    class ContactTest(TestCase):
        test_msg = {
            "name": "pandora",
            "message": "xyz",
            "hcaptcha": "xxx",  # Any truthy value is fine
        }

        def test_something(self, mock: MagicMock) -> None:
            response = self.client.post("/contact/", self.test_msg)
            self.assertEqual(response.status_code, HTTP_302_FOUND)


