# Django Secured Fields
[![GitHub](https://img.shields.io/github/license/C0D1UM/django-secured-fields)](https://github.com/C0D1UM/django-secured-fields/blob/main/LICENSE)
[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/C0D1UM/django-secured-fields/ci.yml?branch=main)](https://github.com/C0D1UM/django-secured-fields/actions/workflows/ci.yml)
[![codecov](https://codecov.io/gh/C0D1UM/django-secured-fields/branch/main/graph/badge.svg?token=PN19DJ3SDF)](https://codecov.io/gh/C0D1UM/django-secured-fields)
[![PyPI](https://img.shields.io/pypi/v/django-secured-fields)](https://pypi.org/project/django-secured-fields/)
[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/django-secured-fields)](https://github.com/C0D1UM/django-secured-fields)
Django encrypted fields with search enabled.
## Features
- Automatically encrypt/decrypt field value using [cryptography](https://github.com/pyca/cryptography)'s [Fernet](https://cryptography.io/en/latest/fernet)
- Built-in search lookup on the encrypted fields from [hashlib](https://docs.python.org/3/library/hashlib.html)'s _SHA-256_ hash value. `in` and `isnull` lookup also supported.
- Supports most of available Django fields including `BinaryField`, `JSONField`, and `FileField`.
## Installation
```bash
pip install django-secured-fields
```
## Setup
1. Add `secured_fields` into `INSTALLED_APPS`
```python
# settings.py
INSTALLED_APPS = [
...
'secured_fields',
]
```
2. Generate a new key using for encryption
```bash
$ python manage.py generate_key
KEY: TtY8MAeXuhdKDd1HfGUwim-vQ8H7fXyRQ9J8pTi_-lg=
HASH_SALT: 500d492e
```
3. Put generated key and hash salt in settings
```python
# settings.py
SECURED_FIELDS_KEY = 'TtY8MAeXuhdKDd1HfGUwim-vQ8H7fXyRQ9J8pTi_-lg='
SECURED_FIELDS_HASH_SALT = '500d492e' # optional
```
## Usage
### Simple Usage
```python
# models.py
import secured_fields
phone_number = secured_fields.EncryptedCharField(max_length=10)
```
### Enable Searching
```python
# models.py
import secured_fields
id_card_number = secured_fields.EncryptedCharField(max_length=18, searchable=True)
```
## Supported Fields
- `EncryptedBinaryField`
- `EncryptedBooleanField`
- `EncryptedCharField`
- `EncryptedDateField`
- `EncryptedDateTimeField`
- `EncryptedDecimalField`
- `EncryptedFileField`
- `EncryptedImageField`
- `EncryptedIntegerField`
- `EncryptedJSONField`
- `EncryptedTextField`
## Settings
| Key | Required | Default | Description |
| --- | -------- | ------- | ----------- |
| `SECURED_FIELDS_KEY` | Yes | | Key for using in encryption/decryption with Fernet. Usually generated from `python manage.py generate_key`. |
| `SECURED_FIELDS_HASH_SALT` | No | `''` | Salt to append after the field value before hashing. Usually generated from `python manage.py generate_key`. |
| `SECURED_FIELDS_FILE_STORAGE` | No | `'secured_fields.storage.EncryptedFileSystemStorage'` | File storage class used for storing encrypted file/image fields. See [EncryptedStorageMixin](#encryptedstoragemixin) |
## APIs
### Field Arguments
| Name | Type | Required | Default | Description |
| ---- | ---- | -------- | ------- | ----------- |
| `searchable` | `bool` | No | `False` | Enable search function |
### Encryption
```python
> from secured_fields.fernet import get_fernet
> data = b'test'
> encrypted_data = get_fernet().encrypt(data)
> encrypted_data
b'gAAAAABh2_Ry_thxLTuFFXeMc9hNttah82979JPuMSjnssRB0DmbgwdtEU5dapBgISOST_a_egDc66EG_ZtVu_EqF_69djJwuA=='
> get_fernet().decrypt(encrypted_data)
b'test'
```
### `EncryptedMixin`
If you have a field which does not supported by the package, you can use `EncryptedMixin` to enable encryption and search functionality for that custom field.
```python
import secured_fields
from django.db import models
class EncryptedUUIDField(secured_fields.EncryptedMixin, models.UUIDField):
pass
task_id = EncryptedUUIDField(searchable=True)
```
### `EncryptedStorageMixin`
If you use a custom file storage class (e.g. defined in `settings.py`'s `DEFAULT_FILE_STORAGE`), you can enable file encryption using `EncryptedStorageMixin`.
```python
import secured_fields
from minio_storage.storage import MinioMediaStorage
class EncryptedMinioMediaStorage(
secured_fields.EncryptedStorageMixin,
MinioMediaStorage,
):
pass
```
## Known Limitation
- `in` lookup on `JSONField` is not available
- Large files are not performance-friendly at the moment (see [#2](https://github.com/C0D1UM/django-secured-fields/issues/2))
- Search on `BinaryField` does not supported at the moment (see [#6](https://github.com/C0D1UM/django-secured-fields/issues/6))
- Changing `searchable` value in a field with the records in the database is not supported (see [#7](https://github.com/C0D1UM/django-secured-fields/issues/7))
## Development
### Requirements
- Docker
- Poetry
- MySQL Client
- `brew install mysql-client`
- `echo 'export PATH="/usr/local/opt/mysql-client/bin:$PATH"' >> ~/.bash_profile`
### Running Project
1. Start backend databases
```bash
make up-db
```
2. Run tests (see: [Testing](#testing))
### Linting
```bash
make lint
```
### Testing
```bash
make test
```
### Fix Formatting
```bash
make yapf
```
Raw data
{
"_id": null,
"home_page": "https://github.com/C0D1UM/django-secured-fields",
"name": "django-secured-fields",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.8,<4.0",
"maintainer_email": "",
"keywords": "django,encrypted,fields,drf,django-rest,restframework,search,encryption,hash",
"author": "CODIUM",
"author_email": "support@codium.co",
"download_url": "https://files.pythonhosted.org/packages/a5/ec/7320355481172933f729922c5d8b056e47248b8aea59cc42f8245aca09d8/django_secured_fields-0.4.2.tar.gz",
"platform": null,
"description": "# Django Secured Fields\n\n[![GitHub](https://img.shields.io/github/license/C0D1UM/django-secured-fields)](https://github.com/C0D1UM/django-secured-fields/blob/main/LICENSE)\n[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/C0D1UM/django-secured-fields/ci.yml?branch=main)](https://github.com/C0D1UM/django-secured-fields/actions/workflows/ci.yml)\n[![codecov](https://codecov.io/gh/C0D1UM/django-secured-fields/branch/main/graph/badge.svg?token=PN19DJ3SDF)](https://codecov.io/gh/C0D1UM/django-secured-fields)\n[![PyPI](https://img.shields.io/pypi/v/django-secured-fields)](https://pypi.org/project/django-secured-fields/) \n[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/django-secured-fields)](https://github.com/C0D1UM/django-secured-fields)\n\nDjango encrypted fields with search enabled.\n\n## Features\n\n- Automatically encrypt/decrypt field value using [cryptography](https://github.com/pyca/cryptography)'s [Fernet](https://cryptography.io/en/latest/fernet)\n- Built-in search lookup on the encrypted fields from [hashlib](https://docs.python.org/3/library/hashlib.html)'s _SHA-256_ hash value. `in` and `isnull` lookup also supported.\n- Supports most of available Django fields including `BinaryField`, `JSONField`, and `FileField`.\n\n## Installation\n\n```bash\npip install django-secured-fields\n```\n\n## Setup\n\n1. Add `secured_fields` into `INSTALLED_APPS`\n\n ```python\n # settings.py\n\n INSTALLED_APPS = [\n ...\n 'secured_fields',\n ]\n ```\n\n2. Generate a new key using for encryption\n\n ```bash\n $ python manage.py generate_key\n KEY: TtY8MAeXuhdKDd1HfGUwim-vQ8H7fXyRQ9J8pTi_-lg=\n HASH_SALT: 500d492e\n ```\n\n3. Put generated key and hash salt in settings\n\n ```python\n # settings.py\n\n SECURED_FIELDS_KEY = 'TtY8MAeXuhdKDd1HfGUwim-vQ8H7fXyRQ9J8pTi_-lg='\n SECURED_FIELDS_HASH_SALT = '500d492e' # optional\n ```\n\n## Usage\n\n### Simple Usage\n\n```python\n# models.py\nimport secured_fields\n\nphone_number = secured_fields.EncryptedCharField(max_length=10)\n```\n\n### Enable Searching\n\n```python\n# models.py\nimport secured_fields\n\nid_card_number = secured_fields.EncryptedCharField(max_length=18, searchable=True)\n```\n\n## Supported Fields\n\n- `EncryptedBinaryField`\n- `EncryptedBooleanField`\n- `EncryptedCharField`\n- `EncryptedDateField`\n- `EncryptedDateTimeField`\n- `EncryptedDecimalField`\n- `EncryptedFileField`\n- `EncryptedImageField`\n- `EncryptedIntegerField`\n- `EncryptedJSONField`\n- `EncryptedTextField`\n\n## Settings\n\n| Key | Required | Default | Description |\n| --- | -------- | ------- | ----------- |\n| `SECURED_FIELDS_KEY` | Yes | | Key for using in encryption/decryption with Fernet. Usually generated from `python manage.py generate_key`. |\n| `SECURED_FIELDS_HASH_SALT` | No | `''` | Salt to append after the field value before hashing. Usually generated from `python manage.py generate_key`. |\n| `SECURED_FIELDS_FILE_STORAGE` | No | `'secured_fields.storage.EncryptedFileSystemStorage'` | File storage class used for storing encrypted file/image fields. See [EncryptedStorageMixin](#encryptedstoragemixin) |\n\n## APIs\n\n### Field Arguments\n\n| Name | Type | Required | Default | Description |\n| ---- | ---- | -------- | ------- | ----------- |\n| `searchable` | `bool` | No | `False` | Enable search function |\n\n### Encryption\n\n```python\n> from secured_fields.fernet import get_fernet\n\n> data = b'test'\n\n> encrypted_data = get_fernet().encrypt(data)\n> encrypted_data\nb'gAAAAABh2_Ry_thxLTuFFXeMc9hNttah82979JPuMSjnssRB0DmbgwdtEU5dapBgISOST_a_egDc66EG_ZtVu_EqF_69djJwuA=='\n\n> get_fernet().decrypt(encrypted_data)\nb'test'\n```\n\n### `EncryptedMixin`\n\nIf you have a field which does not supported by the package, you can use `EncryptedMixin` to enable encryption and search functionality for that custom field.\n\n```python\nimport secured_fields\nfrom django.db import models\n\nclass EncryptedUUIDField(secured_fields.EncryptedMixin, models.UUIDField):\n pass\n\ntask_id = EncryptedUUIDField(searchable=True)\n```\n\n### `EncryptedStorageMixin`\n\nIf you use a custom file storage class (e.g. defined in `settings.py`'s `DEFAULT_FILE_STORAGE`), you can enable file encryption using `EncryptedStorageMixin`.\n\n```python\nimport secured_fields\nfrom minio_storage.storage import MinioMediaStorage\n\nclass EncryptedMinioMediaStorage(\n secured_fields.EncryptedStorageMixin,\n MinioMediaStorage,\n):\n pass\n```\n\n## Known Limitation\n\n- `in` lookup on `JSONField` is not available\n- Large files are not performance-friendly at the moment (see [#2](https://github.com/C0D1UM/django-secured-fields/issues/2))\n- Search on `BinaryField` does not supported at the moment (see [#6](https://github.com/C0D1UM/django-secured-fields/issues/6))\n- Changing `searchable` value in a field with the records in the database is not supported (see [#7](https://github.com/C0D1UM/django-secured-fields/issues/7))\n\n## Development\n\n### Requirements\n\n- Docker\n- Poetry\n- MySQL Client\n - `brew install mysql-client`\n - `echo 'export PATH=\"/usr/local/opt/mysql-client/bin:$PATH\"' >> ~/.bash_profile`\n\n### Running Project\n\n1. Start backend databases\n\n ```bash\n make up-db\n ```\n\n2. Run tests (see: [Testing](#testing))\n\n### Linting\n\n```bash\nmake lint\n```\n\n### Testing\n\n```bash\nmake test\n```\n\n### Fix Formatting\n\n```bash\nmake yapf\n```\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "",
"version": "0.4.2",
"split_keywords": [
"django",
"encrypted",
"fields",
"drf",
"django-rest",
"restframework",
"search",
"encryption",
"hash"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "a2b8f0efc4876bc6a1a568ad381429823174bce67c85f5c513a9bdb59a57c3c2",
"md5": "1249f7cbb3f88294d7e3ece109ab80bc",
"sha256": "890ba706f6da5e43b7b92d1d5df2ea57a9b57e2b887b53793a0b9401a6c1eadc"
},
"downloads": -1,
"filename": "django_secured_fields-0.4.2-py3-none-any.whl",
"has_sig": false,
"md5_digest": "1249f7cbb3f88294d7e3ece109ab80bc",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8,<4.0",
"size": 10087,
"upload_time": "2023-01-06T06:09:35",
"upload_time_iso_8601": "2023-01-06T06:09:35.615660Z",
"url": "https://files.pythonhosted.org/packages/a2/b8/f0efc4876bc6a1a568ad381429823174bce67c85f5c513a9bdb59a57c3c2/django_secured_fields-0.4.2-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "a5ec7320355481172933f729922c5d8b056e47248b8aea59cc42f8245aca09d8",
"md5": "37bfec5afa0aa92087008f25045da6d4",
"sha256": "073ce06ae638e37a0f215e98c3c504915848891d01d9710b7f969465b7cb3ccb"
},
"downloads": -1,
"filename": "django_secured_fields-0.4.2.tar.gz",
"has_sig": false,
"md5_digest": "37bfec5afa0aa92087008f25045da6d4",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8,<4.0",
"size": 9645,
"upload_time": "2023-01-06T06:09:37",
"upload_time_iso_8601": "2023-01-06T06:09:37.218735Z",
"url": "https://files.pythonhosted.org/packages/a5/ec/7320355481172933f729922c5d8b056e47248b8aea59cc42f8245aca09d8/django_secured_fields-0.4.2.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-01-06 06:09:37",
"github": true,
"gitlab": false,
"bitbucket": false,
"github_user": "C0D1UM",
"github_project": "django-secured-fields",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "django-secured-fields"
}