nacl-middleware


Namenacl-middleware JSON
Version 0.0.9 PyPI version JSON
download
home_pageNone
Summaryaiohttp compatible pynacl middleware
upload_time2024-04-15 20:31:40
maintainerNone
docs_urlNone
authorNone
requires_pythonNone
licenseGNU General Public License v3 or later (GPLv3+)
keywords pynacle middleware aiohttp
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            The Nacl Middleware
===================

.. image:: https://readthedocs.org/projects/nacl-middleware/badge/?version=latest
    :target: https://nacl-middleware.readthedocs.io/en/latest/?badge=latest
    :alt: Documentation Status

.. image:: https://github.com/CosmicDNA/nacl_middleware/actions/workflows/pytest.yml/badge.svg
    :target: https://github.com/CosmicDNA/nacl_middleware/actions/workflows/pytest.yml
    :alt: Python Tests

The Nacl Middleware is an aiohttp compatible middleware that provides NaCl encryption for authentication in both HTTP requests and websockets. It allows you to securely handle encrypted messages and sender’s public keys from query parameters. Upon successful decoding, it forwards the request to the appropriate handler, whether it’s a websocket or an HTTP request.


Usage
-----

The middleware uses assymetric keys encryption and it is installed on the server. The middleware assumes that the client will be sending the following GET parameters:


+-------------------+----------------------------------------------------+
| parameter         | Description                                        |
+===================+====================================================+
| publicKey         | The client's public key                            |
+-------------------+----------------------------------------------------+
| encryptedMessage  | The encrypted message by the client for the server |
+-------------------+----------------------------------------------------+


Example Server Code
^^^^^^^^^^^^^^^^^^^

.. code-block:: python

    from aiohttp.web import Application, Response, run_app
    from nacl_middleware import nacl_middleware, Nacl, MailBox

    pynacl = Nacl()
    public_key_hex = pynacl.decoded_public_key()
    print(public_key_hex)

    app = Application(middlewares=[
        nacl_middleware(pynacl.private_key)
    ])

    async def thanks_handler(request):
        decrypted_message = request['decrypted_message']
        mail_box: MailBox = request['mail_box']
        if decrypted_message == 'Thank you!':
            text = 'You are welcome!'
        text = "Pardon me?"
        return Response(text = mail_box.box(text))

    app.router.add_get('/handle_thanks', thanks_handler)

    run_app(app)


Example Client Code
^^^^^^^^^^^^^^^^^^^

.. code-block:: python

    from aiohttp import ClientSession
    from asyncio import run
    from nacl_middleware import MailBox, Nacl

    pynacl = Nacl()
    server_hex_public_key = "cbe3b3cf345b24bd050db13bb5f1165f47f36f7151bbba9b27bdef0922674f4d"

    async def main():
        mail_box = MailBox(pynacl.private_key, server_hex_public_key)

        def get_params(message):
            return {
                "publicKey": pynacl.decoded_public_key(),
                "encryptedMessage": mail_box.box(message)
            }

        async with ClientSession() as session:
            async with session.get('http://localhost:8080/handle_thanks', params=get_params('Thank you!')) as response:
                encryted_reply = await response.text()
                reply = mail_box.unbox(encryted_reply)
                print("Reply:", reply)

    run(main())

.. warning::

    Make sure the server's public key in this client code example is correctly set to the public key print by the server's example code in the console.

.. tip::
   Add a path to get the server's public key to the middleware's route exclusion to allow the server's public key to be obtained by sending a GET request to the server's public key endpoint with, for example:

    .. code-block:: python

        from aiohttp.web import Application, Response, run_app
        from nacl_middleware import nacl_middleware, Nacl, MailBox

        pynacl = Nacl()
        public_key_hex = pynacl.decoded_public_key()
        print(public_key_hex)

        app = Application(middlewares=[
            nacl_middleware(pynacl.private_key)
        ])

        async def thanks_handler(request):
            decrypted_message = request['decrypted_message']
            mail_box: MailBox = request['mail_box']
            if decrypted_message == 'Thank you!':
                text = 'You are welcome!'
            text = "Pardon me?"
            return Response(text = mail_box.box(text))

        app.router.add_get('/handle_thanks', thanks_handler)

        async def get_public_key(request):
            return Response(text = public_key_hex)

        app.router.add_get("/get_public_key", get_public_key)

        run_app(app)


Development
===========

Project Configuration
---------------------

To start, clone the project with:

.. code-block:: shell

    git clone https://github.com/CosmicDNA/nacl_middleware

Then enter the cloned folder and create a new virtualenv:

.. code-block:: shell

    cd nacl-middleware
    python3 -m  venv .venv

Activate the just created virtualenv with:

.. code-block:: shell

    . .venv/bin/activate

Install the dependencies with the command:

.. code-block:: shell

    pip install -e .[test]

Testing
-------

Run the test suite with the command:

.. code-block:: shell

    pytest -s

Testing with SSL
----------------

Certificates Creation
^^^^^^^^^^^^^^^^^^^^^

.. note::

    The following topics consider the project's root folder as the working directory.


Generate a Client Key and Certificate Signing Request (CSR)
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

To generate a client key and CSR, run ``openssl`` command in the terminal:

.. code-block:: shell

    # Generate a private key (client.key)
    openssl genpkey -algorithm RSA -out client.key

    # Create a certificate signing request (client.csr)
    openssl req -new -key client.key -out client.csr

Generate Self-Signed SSL Certificates
"""""""""""""""""""""""""""""""""""""

For the server, generate the self signed certificates with:

.. code-block:: shell

    openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout selfsigned.key -out selfsigned.crt

You will be prompted to answer some questions during the certificate generation process. Make sure to set the Common Name (CN) to your server’s domain name (e.g., localhost).

Sign the CSR using your CA's private key
""""""""""""""""""""""""""""""""""""""""

Lastly, sign the CSR using the server's CA's private key

.. code-block:: shell

    openssl x509 -req -in client.csr -CA selfsigned.crt -CAkey selfsigned.key -CAcreateserial -out client.crt -days 365

Configuration
^^^^^^^^^^^^^

Once a pytest run has generated a ``config.json`` file, you can edit it and add:

.. code-block:: json

    {
        "ssl": {
            "cert_path": "selfsigned.crt",
            "key_path": "selfsigned.key"
        }
    }

You should now be able to perform the test with SSL enabled.

.. code-block:: shell

    pytest -s

.. tip::

    Removing the ``ssl`` section from config.json deactivates SSL within both client and server modules.

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "nacl-middleware",
    "maintainer": null,
    "docs_url": null,
    "requires_python": null,
    "maintainer_email": null,
    "keywords": "pynacle, middleware, aiohttp",
    "author": null,
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/77/d3/0d61353ec10a32e89c8a67ee3d55ccbe9f4a4fa9eeef2f19892fa5b206a0/nacl_middleware-0.0.9.tar.gz",
    "platform": null,
    "description": "The Nacl Middleware\n===================\n\n.. image:: https://readthedocs.org/projects/nacl-middleware/badge/?version=latest\n    :target: https://nacl-middleware.readthedocs.io/en/latest/?badge=latest\n    :alt: Documentation Status\n\n.. image:: https://github.com/CosmicDNA/nacl_middleware/actions/workflows/pytest.yml/badge.svg\n    :target: https://github.com/CosmicDNA/nacl_middleware/actions/workflows/pytest.yml\n    :alt: Python Tests\n\nThe Nacl Middleware is an aiohttp compatible middleware that provides NaCl encryption for authentication in both HTTP requests and websockets. It allows you to securely handle encrypted messages and sender\u2019s public keys from query parameters. Upon successful decoding, it forwards the request to the appropriate handler, whether it\u2019s a websocket or an HTTP request.\n\n\nUsage\n-----\n\nThe middleware uses assymetric keys encryption and it is installed on the server. The middleware assumes that the client will be sending the following GET parameters:\n\n\n+-------------------+----------------------------------------------------+\n| parameter         | Description                                        |\n+===================+====================================================+\n| publicKey         | The client's public key                            |\n+-------------------+----------------------------------------------------+\n| encryptedMessage  | The encrypted message by the client for the server |\n+-------------------+----------------------------------------------------+\n\n\nExample Server Code\n^^^^^^^^^^^^^^^^^^^\n\n.. code-block:: python\n\n    from aiohttp.web import Application, Response, run_app\n    from nacl_middleware import nacl_middleware, Nacl, MailBox\n\n    pynacl = Nacl()\n    public_key_hex = pynacl.decoded_public_key()\n    print(public_key_hex)\n\n    app = Application(middlewares=[\n        nacl_middleware(pynacl.private_key)\n    ])\n\n    async def thanks_handler(request):\n        decrypted_message = request['decrypted_message']\n        mail_box: MailBox = request['mail_box']\n        if decrypted_message == 'Thank you!':\n            text = 'You are welcome!'\n        text = \"Pardon me?\"\n        return Response(text = mail_box.box(text))\n\n    app.router.add_get('/handle_thanks', thanks_handler)\n\n    run_app(app)\n\n\nExample Client Code\n^^^^^^^^^^^^^^^^^^^\n\n.. code-block:: python\n\n    from aiohttp import ClientSession\n    from asyncio import run\n    from nacl_middleware import MailBox, Nacl\n\n    pynacl = Nacl()\n    server_hex_public_key = \"cbe3b3cf345b24bd050db13bb5f1165f47f36f7151bbba9b27bdef0922674f4d\"\n\n    async def main():\n        mail_box = MailBox(pynacl.private_key, server_hex_public_key)\n\n        def get_params(message):\n            return {\n                \"publicKey\": pynacl.decoded_public_key(),\n                \"encryptedMessage\": mail_box.box(message)\n            }\n\n        async with ClientSession() as session:\n            async with session.get('http://localhost:8080/handle_thanks', params=get_params('Thank you!')) as response:\n                encryted_reply = await response.text()\n                reply = mail_box.unbox(encryted_reply)\n                print(\"Reply:\", reply)\n\n    run(main())\n\n.. warning::\n\n    Make sure the server's public key in this client code example is correctly set to the public key print by the server's example code in the console.\n\n.. tip::\n   Add a path to get the server's public key to the middleware's route exclusion to allow the server's public key to be obtained by sending a GET request to the server's public key endpoint with, for example:\n\n    .. code-block:: python\n\n        from aiohttp.web import Application, Response, run_app\n        from nacl_middleware import nacl_middleware, Nacl, MailBox\n\n        pynacl = Nacl()\n        public_key_hex = pynacl.decoded_public_key()\n        print(public_key_hex)\n\n        app = Application(middlewares=[\n            nacl_middleware(pynacl.private_key)\n        ])\n\n        async def thanks_handler(request):\n            decrypted_message = request['decrypted_message']\n            mail_box: MailBox = request['mail_box']\n            if decrypted_message == 'Thank you!':\n                text = 'You are welcome!'\n            text = \"Pardon me?\"\n            return Response(text = mail_box.box(text))\n\n        app.router.add_get('/handle_thanks', thanks_handler)\n\n        async def get_public_key(request):\n            return Response(text = public_key_hex)\n\n        app.router.add_get(\"/get_public_key\", get_public_key)\n\n        run_app(app)\n\n\nDevelopment\n===========\n\nProject Configuration\n---------------------\n\nTo start, clone the project with:\n\n.. code-block:: shell\n\n    git clone https://github.com/CosmicDNA/nacl_middleware\n\nThen enter the cloned folder and create a new virtualenv:\n\n.. code-block:: shell\n\n    cd nacl-middleware\n    python3 -m  venv .venv\n\nActivate the just created virtualenv with:\n\n.. code-block:: shell\n\n    . .venv/bin/activate\n\nInstall the dependencies with the command:\n\n.. code-block:: shell\n\n    pip install -e .[test]\n\nTesting\n-------\n\nRun the test suite with the command:\n\n.. code-block:: shell\n\n    pytest -s\n\nTesting with SSL\n----------------\n\nCertificates Creation\n^^^^^^^^^^^^^^^^^^^^^\n\n.. note::\n\n    The following topics consider the project's root folder as the working directory.\n\n\nGenerate a Client Key and Certificate Signing Request (CSR)\n\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\n\nTo generate a client key and CSR, run ``openssl`` command in the terminal:\n\n.. code-block:: shell\n\n    # Generate a private key (client.key)\n    openssl genpkey -algorithm RSA -out client.key\n\n    # Create a certificate signing request (client.csr)\n    openssl req -new -key client.key -out client.csr\n\nGenerate Self-Signed SSL Certificates\n\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\n\nFor the server, generate the self signed certificates with:\n\n.. code-block:: shell\n\n    openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout selfsigned.key -out selfsigned.crt\n\nYou will be prompted to answer some questions during the certificate generation process. Make sure to set the Common Name (CN) to your server\u2019s domain name (e.g., localhost).\n\nSign the CSR using your CA's private key\n\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\n\nLastly, sign the CSR using the server's CA's private key\n\n.. code-block:: shell\n\n    openssl x509 -req -in client.csr -CA selfsigned.crt -CAkey selfsigned.key -CAcreateserial -out client.crt -days 365\n\nConfiguration\n^^^^^^^^^^^^^\n\nOnce a pytest run has generated a ``config.json`` file, you can edit it and add:\n\n.. code-block:: json\n\n    {\n        \"ssl\": {\n            \"cert_path\": \"selfsigned.crt\",\n            \"key_path\": \"selfsigned.key\"\n        }\n    }\n\nYou should now be able to perform the test with SSL enabled.\n\n.. code-block:: shell\n\n    pytest -s\n\n.. tip::\n\n    Removing the ``ssl`` section from config.json deactivates SSL within both client and server modules.\n",
    "bugtrack_url": null,
    "license": "GNU General Public License v3 or later (GPLv3+)",
    "summary": "aiohttp compatible pynacl middleware",
    "version": "0.0.9",
    "project_urls": null,
    "split_keywords": [
        "pynacle",
        " middleware",
        " aiohttp"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "154d19b128c215c8a279186a55e80d6e2cb6e0d431d7b5831de8cd6515ba6d1b",
                "md5": "c1f6be8e498a55763983722bd5056c8d",
                "sha256": "569f516d5d654e27028fe2d0570a765c4f9537043ba9be3eabe34e6e35f257d6"
            },
            "downloads": -1,
            "filename": "nacl_middleware-0.0.9-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "c1f6be8e498a55763983722bd5056c8d",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": null,
            "size": 6941,
            "upload_time": "2024-04-15T20:31:39",
            "upload_time_iso_8601": "2024-04-15T20:31:39.447890Z",
            "url": "https://files.pythonhosted.org/packages/15/4d/19b128c215c8a279186a55e80d6e2cb6e0d431d7b5831de8cd6515ba6d1b/nacl_middleware-0.0.9-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "77d30d61353ec10a32e89c8a67ee3d55ccbe9f4a4fa9eeef2f19892fa5b206a0",
                "md5": "9c91d8885bf13597e15df603fcec0fb7",
                "sha256": "9c9f4d68e2731ee9758133dd6b357525e656474c2abecc8c85fdb3a0037badfa"
            },
            "downloads": -1,
            "filename": "nacl_middleware-0.0.9.tar.gz",
            "has_sig": false,
            "md5_digest": "9c91d8885bf13597e15df603fcec0fb7",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": null,
            "size": 7496,
            "upload_time": "2024-04-15T20:31:40",
            "upload_time_iso_8601": "2024-04-15T20:31:40.954742Z",
            "url": "https://files.pythonhosted.org/packages/77/d3/0d61353ec10a32e89c8a67ee3d55ccbe9f4a4fa9eeef2f19892fa5b206a0/nacl_middleware-0.0.9.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-04-15 20:31:40",
    "github": false,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "lcname": "nacl-middleware"
}
        
Elapsed time: 0.25811s