Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
254 changes: 254 additions & 0 deletions encrypted_field/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
================
Encrypted Field
================

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:placeholder !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/licence-LGPL--3-blue.png
:target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html
:alt: License: LGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fserver--tools-lightgray.png?logo=github
:target: https://github.com/OCA/server-tools/tree/17.0/encrypted_field
:alt: OCA/server-tools

|badge1| |badge2| |badge3|

Encrypted field type for storing sensitive data in Odoo 17 (SSN, Tax IDs, etc.)

**Features:**

* **Encrypted field type** - Extends ``fields.Char`` with transparent encryption
* **Fernet encryption** - AES-128-CBC with HMAC-SHA256 via ``cryptography`` library
* **Masking** - Show last4, first4, or full masking for unauthorized users
* **Formatting** - Built-in patterns for SSN, EIN, phone, credit card
* **Group-based access** - Control who can reveal decrypted values
* **Reveal widget** - Eye icon button to show/hide values in forms
* **Audit logging** - Track who accessed decrypted values
* **Key rotation** - Wizard to safely rotate encryption keys
* **Migration tool** - Encrypt existing plaintext data in-place

**Table of contents**

.. contents::
:local:

Installation
============

1. Install the cryptography package::

pip install cryptography

2. Generate an encryption key::

python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"

3. Add the key to odoo.conf::

encryption_key = your-generated-key-here

4. Install the module via Apps.

Configuration
=============

Field Parameters
----------------

+-----------------+---------------+-----------+-----------------------------------------------+
| Parameter | Type | Default | Description |
+=================+===============+===========+===============================================+
| ``string`` | str | None | Field label |
+-----------------+---------------+-----------+-----------------------------------------------+
| ``encrypt_groups`` | str | None | Comma-separated group XML IDs for reveal |
+-----------------+---------------+-----------+-----------------------------------------------+
| ``mask`` | str/callable | ``full`` | Masking mode: ``last4``, ``first4``, ``full`` |
+-----------------+---------------+-----------+-----------------------------------------------+
| ``audit`` | bool | True | Log access to decrypted values |
+-----------------+---------------+-----------+-----------------------------------------------+
| ``format_pattern`` | str | None | Format pattern: ``ssn``, ``ein``, ``phone`` |
+-----------------+---------------+-----------+-----------------------------------------------+

Built-in Format Patterns
------------------------

+----------------+------------------------+------------------+
| Name | Pattern | Example |
+================+========================+==================+
| ``ssn`` | ``###-##-####`` | 123-45-6789 |
+----------------+------------------------+------------------+
| ``ein`` | ``##-#######`` | 12-3456789 |
+----------------+------------------------+------------------+
| ``phone`` | ``(###) ###-####`` | (555) 123-4567 |
+----------------+------------------------+------------------+
| ``credit_card``| ``####-####-####-####``| 1234-5678-9012 |
+----------------+------------------------+------------------+

Security Groups
---------------

+---------------------------+---------------------------------------------------+
| Group | Description |
+===========================+===================================================+
| Encryption Auditor | Can view audit logs (read-only oversight) |
+---------------------------+---------------------------------------------------+
| Encryption Administrator | Can rotate keys and run migrations |
+---------------------------+---------------------------------------------------+

**Note**: These groups control access to admin tools only. Who can *reveal* encrypted
field values is controlled by the ``encrypt_groups`` parameter on each field.

Usage
=====

Adding a NEW encrypted field
----------------------------

.. code-block:: python

from odoo import models
from odoo.addons.encrypted_field.fields import Encrypted

class HrEmployee(models.Model):
_inherit = 'hr.employee'

ssn = Encrypted(
string='SSN',
encrypt_groups='hr.group_hr_manager',
mask='last4',
format_pattern='ssn',
)

Then add it to the view with the ``encrypted`` widget:

.. code-block:: xml

<field name="work_email" position="after">
<field name="ssn" widget="encrypted"/>
</field>

Overriding an EXISTING field
----------------------------

If the model uses delegation inheritance (``_inherits``), you must also define
the field on the child model:

.. code-block:: python

# res_partner.py
class ResPartner(models.Model):
_inherit = 'res.partner'

vat = Encrypted(
string='Tax ID',
encrypt_groups='account.group_account_manager',
mask='last4',
)

# res_users.py - REQUIRED for delegation inheritance!
class ResUsers(models.Model):
_inherit = 'res.users'

vat = fields.Char(
related='partner_id.vat',
string='Tax ID',
readonly=False,
)

Programmatic Access
-------------------

.. code-block:: python

# Get unmasked value (respects access control, logs access)
unmasked = record.get_unmasked_value('ssn')

# Direct field access always returns masked
masked = record.ssn # Returns '***-**-6789'

Migrating Existing Data
-----------------------

1. Go to **Settings > Technical > Encryption > Encrypt Existing Data**
2. Select the fields to encrypt
3. Click **Preview** to see how many records will be encrypted
4. Click **Encrypt Data** to encrypt in-place

Key Rotation
------------

1. Go to **Settings > Technical > Encryption > Rotate Encryption Key**
2. A new key is auto-generated
3. Click **Preview** to see affected records
4. Click **Rotate Keys** to execute

The wizard will re-encrypt all data with the new key and update ``odoo.conf``
automatically. No restart needed.

Known issues / Roadmap
======================

Limitations
-----------

* **Search/Filter NOT Supported** - Encrypted fields cannot be searched.
This raises an error by design.

* **Sorting NOT Recommended** - Results are sorted by encrypted blob,
not actual value.

* **Reporting Limitations** - Cannot group by encrypted fields or use
in pivot tables. Export always shows masked values.

* **Key Loss = Data Loss** - If you lose your encryption key, all encrypted
data is PERMANENTLY UNRECOVERABLE.

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/OCA/server-tools/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and
welcomed `feedback <https://github.com/OCA/server-tools/issues/new>`_.

Do not contact contributors directly about support or help with technical issues.

Credits
=======

Authors
-------

* Jim Kring

Contributors
------------

* Jim Kring <jim@qlf.com>

Maintainers
-----------

This module is maintained by the OCA.

.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org

OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.

This module is part of the `OCA/server-tools <https://github.com/OCA/server-tools/tree/17.0/encrypted_field>`_ project on GitHub.

You are welcome to contribute. To learn how please visit
https://odoo-community.org/page/Contribute.
1 change: 1 addition & 0 deletions encrypted_field/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import fields, models, wizards
34 changes: 34 additions & 0 deletions encrypted_field/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"name": "Encrypted Field",
"version": "17.0.1.0.0",
"category": "Technical",
"summary": "Encrypted field types for sensitive data storage",
"author": "Odoo Community Association (OCA)",
"website": "https://github.com/OCA/server-tools",
"maintainers": ["jimkring"],
"license": "LGPL-3",
"depends": ["base"],
"external_dependencies": {
"python": ["cryptography"],
},
"data": [
"security/security.xml",
"security/ir.model.access.csv",
"wizards/key_rotation_wizard_views.xml",
"wizards/migration_wizard_views.xml",
"views/audit_log_views.xml",
"views/menu.xml",
],
"demo": [
"demo/demo.xml",
],
"assets": {
"web.assets_backend": [
"encrypted_field/static/src/js/encrypted_field.esm.js",
"encrypted_field/static/src/xml/encrypted_field.xml",
],
},
"installable": True,
"application": False,
"auto_install": False,
}
10 changes: 10 additions & 0 deletions encrypted_field/demo/demo.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<!-- Demo: Add encryption groups to demo user -->
<record id="base.user_demo" model="res.users">
<field
name="groups_id"
eval="[(4, ref('encrypted_field.group_encryption_auditor'))]"
/>
</record>
</odoo>
1 change: 1 addition & 0 deletions encrypted_field/fields/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .encrypted import Encrypted
Loading
Loading