Metadata-Version: 2.1
Name: pyramid-csp
Version: 0.1.0
Summary: Content Security Policy add-on for Pyramid.
Home-page: https://github.com/luhn/pyramid-csp
Author: Theron Luhn
Author-email: theron@luhn.com
Classifier: Development Status :: 4 - Beta
Classifier: Framework :: Pyramid
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Programming Language :: Python
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pyramid>=2
Provides-Extra: testing
Requires-Dist: pytest~=7.4; extra == "testing"
Requires-Dist: webtest~=3.0; extra == "testing"
Provides-Extra: linting
Requires-Dist: ruff~=0.1.6; extra == "linting"
Requires-Dist: black~=23.11; extra == "linting"
Requires-Dist: isort~=5.12; extra == "linting"

# pyramid-csp

`pyramid-csp` is a simple Pyramid add-on for adding a `Content-Security-Policy` header your HTTP responses

For more information on Content Security Policies, see https://content-security-policy.com/

## Setup

There are two ways of including `pyramid-csp` in your application:

The first is adding `pyramid_csp` to the `pyramid.includes` section of your application settings.

```
[app:main]
pyramid.includes = pyramid_csp
```

The second is using the `Configurator.include` function.

```python
config.include("pyramid.csp")
```

## Basic Usage

The most basic usage of `pyramid-csp` is to set the `csp.policy` setting.
This setting should be a valid CSP and will be added to the response headers.

```
[app:main]
csp.policy = default-src https://example.com
```

```
>> curl -i http://localhost:8000
...
Content-Security-Policy: default-src https://example.com
...
```

You can also create a policy by programmatically adding sources with the `add_csp_source` configuration method.
(This will work in addition to the `csp.policy` setting.)
The first argument is the directive name

```python
config.add_csp_source("default-src", "'self'")
```

```
>> curl -i http://localhost:8000
...
Content-Security-Policy: default-src https://example.com 'self'
...
```

The request object also contains an `add_csp_source` method,
which works the same as the configurator method but will only add the source for that request.

```python
def myview(context, request):
    nonce = secrets.token_urlsafe()
    request.add_csp_source("default-src", f"'nonce-{nonce}'")
    return Response(body="<h1>Hello</h1>", content_type="text/html")
```

**Note:** If no sources are defined for the `default-src` directive, `'none'` is automatically added.

## Preset Sources

`pyramid-src` provides the `CSPSources` object, which contains several preset sources.
For example:

```python
from pyramid_csp import CSPSources


def includeme(config):
    config.add_csp_source("default-src", CSPSources.UNSAFE_EVAL)
```

The `CSPSources` object has the following properties:

- `WILDCARD` — `*`
- `NONE` — `'none'`
- `SELF` — `'self'`
- `DATA` — `data:`
- `HTTPS` — `https:`
- `UNSAFE_INLINE` — `'unsafe-inline'`
- `UNSAFE_EVAL` — `'unsafe-eval'`
- `STRICT_DYNAMIC` — `'strict-dynamic'`
- `UNSAFE_HASHES` — `'unsafe-hashes'`

The object also offers several methods for generating sources:

- `https(domain)` — `https://{domain}`
- `nonce(nonce)` — `'nonce-{nonce}'`
- `hash(alg, h)` — `'{alg}-{h}'`
  (`h` should be a binary hash digest or a base64-encoded string.
  If binary, it will be base64-encoded.)
- `sha256(h)` — `'sha256-{h}'`
- `sha384(h)` — `'sha384-{h}'`
- `sha512(h)` — `'sha512-{h}'`

## Nonces

`pyramid-csp` adds a `csp_nonce` property to the request object,
containing a crytographically secure random nonce token.
If accessed, the nonce token will be added to the CSP.


```python
def myview(context, request):
    body = '<script nonce="{ request.csp_nonce }">alert("Hello!");</script>'
    return Response(body=body, content_type="text/html")
```

```
>> curl -i http://localhost:8000/
...
Content-Security-Policy: default-src 'nonce-ZtynG2MXgOPkqWgHyqf8wrR8jOeprIA2qDMKJuOfEXw'
...
<script nonce="ZtynG2MXgOPkqWgHyqf8wrR8jOeprIA2qDMKJuOfEXw">alert("Hello!")</script>
```

By default, the nonce will only be added to the `default-src` directive.
To add it to a different directive, use the `csp.nonce_directives` setting.
Multiple directives can be separated with a comma.

```
[app:main]
csp.nonce_directives = script-src, style-src
```

```python
def myview(context, request):
    body = '<script nonce="{ request.csp_nonce }">alert("Hello!");</script>'
    return Response(body=body, content_type="text/html")
```

```
>> curl -i http://localhost:8000/
...
Content-Security-Policy: default-src 'none'; script-src 'nonce-vyjGpdvTnH6x7-eL-RvVMmxx4KNMTfX9WoLdmgijv2c'; script-src 'nonce-vyjGpdvTnH6x7-eL-RvVMmxx4KNMTfX9WoLdmgijv2c'
...
<script nonce="vyjGpdvTnH6x7-eL-RvVMmxx4KNMTfX9WoLdmgijv2c">alert("Hello!")</script>
```

For more information CSP nonces, see https://content-security-policy.com/nonce/
