From 0e0595f441b5949060004bfb3cd7a4799bdaf8a5 Mon Sep 17 00:00:00 2001 From: Florian da Costa Date: Thu, 11 Apr 2019 17:13:51 +0200 Subject: [PATCH 01/14] [12.0] Add data_encryption This module come from the previous module keychain. It has been heavely refactored to be compatible with server_environment module. For this it has been split into 2 modules data_encryption and server_environment_data_encryption --- data_encryption/__init__.py | 1 + data_encryption/__manifest__.py | 24 ++++ data_encryption/models/__init__.py | 1 + data_encryption/models/encrypted_data.py | 138 +++++++++++++++++++ data_encryption/readme/CONFIGURE.rst | 21 +++ data_encryption/readme/CONTRIBUTORS.rst | 2 + data_encryption/readme/DESCRIPTION.rst | 3 + data_encryption/readme/ROADMAP.rst | 5 + data_encryption/security/ir.model.access.csv | 2 + data_encryption/tests/__init__.py | 1 + data_encryption/tests/common.py | 39 ++++++ data_encryption/tests/test_data_encrypt.py | 99 +++++++++++++ 12 files changed, 336 insertions(+) create mode 100644 data_encryption/__init__.py create mode 100644 data_encryption/__manifest__.py create mode 100644 data_encryption/models/__init__.py create mode 100644 data_encryption/models/encrypted_data.py create mode 100644 data_encryption/readme/CONFIGURE.rst create mode 100644 data_encryption/readme/CONTRIBUTORS.rst create mode 100644 data_encryption/readme/DESCRIPTION.rst create mode 100644 data_encryption/readme/ROADMAP.rst create mode 100644 data_encryption/security/ir.model.access.csv create mode 100644 data_encryption/tests/__init__.py create mode 100644 data_encryption/tests/common.py create mode 100644 data_encryption/tests/test_data_encrypt.py diff --git a/data_encryption/__init__.py b/data_encryption/__init__.py new file mode 100644 index 0000000..0650744 --- /dev/null +++ b/data_encryption/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/data_encryption/__manifest__.py b/data_encryption/__manifest__.py new file mode 100644 index 0000000..501f45a --- /dev/null +++ b/data_encryption/__manifest__.py @@ -0,0 +1,24 @@ +# Copyright <2019> Akretion +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +{ + "name": "Encryption data", + "summary": "Store accounts and credentials encrypted by environment", + "version": "12.0.1.0.0", + "development_status": 'Alpha', + "category": "Tools", + "website": "https://github/oca/server-env", + "author": "Akretion, Odoo Community Association (OCA)", + "license": "AGPL-3", + "application": False, + "installable": True, + "external_dependencies": { + "python": [ + 'cryptography'], + }, + "depends": [ + "base", + ], + "data": [ + "security/ir.model.access.csv", + ], +} diff --git a/data_encryption/models/__init__.py b/data_encryption/models/__init__.py new file mode 100644 index 0000000..da8f5b3 --- /dev/null +++ b/data_encryption/models/__init__.py @@ -0,0 +1 @@ +from . import encrypted_data diff --git a/data_encryption/models/encrypted_data.py b/data_encryption/models/encrypted_data.py new file mode 100644 index 0000000..5e103b6 --- /dev/null +++ b/data_encryption/models/encrypted_data.py @@ -0,0 +1,138 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +import logging +import json + +from odoo import api, fields, models +from odoo.exceptions import AccessError, ValidationError +from odoo.tools.config import config +from odoo.tools.translate import _ +from odoo.tools import ormcache + +_logger = logging.getLogger(__name__) + +try: + from cryptography.fernet import Fernet, InvalidToken +except ImportError as err: # pragma: no cover + _logger.debug(err) + + +class EncryptedData(models.Model): + """Model to store encrypted data by environment (prod, preprod...)""" + + _name = 'encrypted.data' + _description = 'Store any encrypted data by environment' + + name = fields.Char( + required=True, readonly=True, index=True, + help="Technical name") + environment = fields.Char( + required=True, + index=True, + help="Concerned Odoo environment (prod, preprod...)") + encrypted_data = fields.Binary() + + _sql_constraints = [ + ('name_environment_uniq', 'unique (name, environment)', + 'You can not store multiple encrypted data for the same record and \ + environment') + ] + + def _decrypt_data(self, env): + self.ensure_one() + cipher = self._get_cipher(env) + try: + return cipher.decrypt(self.encrypted_data).decode() + except InvalidToken: + raise ValidationError(_( + "Password has been encrypted with a different " + "key. Unless you can recover the previous key, " + "this password is unreadable.")) + + @api.model + @ormcache('self._uid', 'name', 'env') + def _encrypted_get(self, name, env=None): + if self.env.context.get('bin_size'): + self = self.with_context(bin_size=False) + if not self.env.user._is_superuser(): + raise AccessError( + _("Encrypted data can only be read as superuser")) + if not env: + env = self._retrieve_env() + encrypted_rec = self.search( + [('name', '=', name), ('environment', '=', env)]) + if not encrypted_rec: + return None + return encrypted_rec._decrypt_data(env) + + @api.model + @ormcache('self._uid', 'name', 'env') + def _encrypted_read_json(self, name, env=None): + data = self._encrypted_get(name, env=env) + if not data: + return {} + try: + return json.loads(data) + except (ValueError, TypeError): + raise ValidationError( + _("The data you are trying to read are not in a json format")) + + @staticmethod + def _retrieve_env(): + """Return the current environment + Raise if none is found + """ + current = config.get('running_env', False) + if not current: + raise ValidationError( + _('No environment found, please check your running_env ' + 'entry in your config file.')) + return current + + @classmethod + def _get_cipher(cls, env): + """Return a cipher using the key of environment. + force_env = name of the env key. + Useful for encoding against one precise env + """ + key_name = 'encryption_key_%s' % env + key_str = config.get(key_name) + if not key_str: + raise ValidationError(_( + "No '%s' entry found in config file. " + "Use a key similar to: %s") % (key_name, Fernet.generate_key()) + ) + # key should be in bytes format + key = key_str.encode() + return Fernet(key) + + @api.model + def _encrypt_data(self, data, env): + cipher = self._get_cipher(env) + if not isinstance(data, bytes): + data = data.encode() + return cipher.encrypt(data or '') + + @api.model + def _encrypted_store(self, name, data, env=None): + if not self.env.user._is_superuser(): + raise AccessError( + _("You can only encrypt data as superuser")) + if not env: + env = self._retrieve_env() + encrypted_data = self._encrypt_data(data, env) + existing_data = self.search( + [('name', '=', name), ('environment', '=', env)]) + if existing_data: + existing_data.write({'encrypted_data': encrypted_data}) + else: + self.create({ + 'name': name, + 'environment': env, + 'encrypted_data': encrypted_data, + }) + self._encrypted_get.clear_cache(self) + self._encrypted_read_json.clear_cache(self) + + @api.model + def _encrypted_store_json(self, name, json_data, env=None): + return self._encrypted_store(name, json.dumps(json_data), env=env) diff --git a/data_encryption/readme/CONFIGURE.rst b/data_encryption/readme/CONFIGURE.rst new file mode 100644 index 0000000..69b4773 --- /dev/null +++ b/data_encryption/readme/CONFIGURE.rst @@ -0,0 +1,21 @@ +To configure this module, you need to edit the main configuration file +of your instance, and add a directive called ``running_env``. Commonly +used values are 'dev', 'test', 'production':: + + [options] + running_env=dev + + +You also need to set the encryption key(s). The main idea is to have different +encryption keys for your different environment, to avoid the possibility to retrieve +crucial information from the production environment in a developement environment, for instance. +So, if your running environment is 'dev':: + + [options] + encryption_key_dev=fyeMIx9XVPBBky5XZeLDxVc9dFKy7Uzas3AoyMarHPA= + +In the configuration file of your production environment, you may want to configure +all your other environments encryption key. This way, from production you can encrypt and decrypt +data for all environments. + +You can generate keys with python -c 'from cryptography.fernet import Fernet; print Fernet.generate_key()'. diff --git a/data_encryption/readme/CONTRIBUTORS.rst b/data_encryption/readme/CONTRIBUTORS.rst new file mode 100644 index 0000000..3017ba2 --- /dev/null +++ b/data_encryption/readme/CONTRIBUTORS.rst @@ -0,0 +1,2 @@ +* Raphaël Reverdy +* Florian da Costa diff --git a/data_encryption/readme/DESCRIPTION.rst b/data_encryption/readme/DESCRIPTION.rst new file mode 100644 index 0000000..9c4dc15 --- /dev/null +++ b/data_encryption/readme/DESCRIPTION.rst @@ -0,0 +1,3 @@ +This module allows to encrypt and decrypt data. This module is not usable +by itself, it is a low level module which should work as a base for others. +An example is the module server_environment_data_encryption diff --git a/data_encryption/readme/ROADMAP.rst b/data_encryption/readme/ROADMAP.rst new file mode 100644 index 0000000..71a6a12 --- /dev/null +++ b/data_encryption/readme/ROADMAP.rst @@ -0,0 +1,5 @@ +For now the encryption is dependent on the environment. It has been designed +to store the same kind of data with different values depending on the environement +(dev, preprod, prod...). +An improvement could be to split this in 2 modules. But the environment stuff +is not a big constraint. diff --git a/data_encryption/security/ir.model.access.csv b/data_encryption/security/ir.model.access.csv new file mode 100644 index 0000000..ddbd5f7 --- /dev/null +++ b/data_encryption/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_encrypted_data,access_encrypted_data,model_encrypted_data,base.group_system,0,0,0,0 diff --git a/data_encryption/tests/__init__.py b/data_encryption/tests/__init__.py new file mode 100644 index 0000000..d686b32 --- /dev/null +++ b/data_encryption/tests/__init__.py @@ -0,0 +1 @@ +from . import test_data_encrypt diff --git a/data_encryption/tests/common.py b/data_encryption/tests/common.py new file mode 100644 index 0000000..f044569 --- /dev/null +++ b/data_encryption/tests/common.py @@ -0,0 +1,39 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo.tests.common import TransactionCase +from odoo.tools.config import config + + +import logging + +_logger = logging.getLogger(__name__) + +try: + from cryptography.fernet import Fernet +except ImportError as err: # pragma: no cover + _logger.debug(err) + + +class CommonDataEncrypted(TransactionCase): + + def setUp(self): + super().setUp() + + self.encrypted_data = self.env['encrypted.data'] + self.set_new_key_env('test') + self.old_running_env = config.get('running_env', '') + config['running_env'] = 'test' + self.crypted_data_name = 'test_model,1' + + def set_new_key_env(self, environment): + crypting_key = Fernet.generate_key() + # The key is encoded to bytes in the module, because in real life + # the key com from the config file and is not in a binary format. + # So we decode here to avoid having a special behavior because of + # the tests. + config['encryption_key_{}'.format(environment)] = \ + crypting_key.decode() + + def tearDown(self): + config['running_env'] = self.old_running_env + return super().tearDown() diff --git a/data_encryption/tests/test_data_encrypt.py b/data_encryption/tests/test_data_encrypt.py new file mode 100644 index 0000000..6e42722 --- /dev/null +++ b/data_encryption/tests/test_data_encrypt.py @@ -0,0 +1,99 @@ +# © 2016 Akretion Raphaël REVERDY +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from .common import CommonDataEncrypted +from odoo.tools.config import config +from odoo.exceptions import AccessError, ValidationError + + +import logging + +_logger = logging.getLogger(__name__) + +try: + from cryptography.fernet import Fernet +except ImportError as err: # pragma: no cover + _logger.debug(err) + + +class TestDataEncrypted(CommonDataEncrypted): + + def test_store_data_no_superuser(self): + # only superuser can use this model + admin = self.env.ref('base.user_admin') + with self.assertRaises(AccessError): + self.encrypted_data.sudo(admin.id)._encrypted_store( + self.crypted_data_name, "My config") + + def test_store_data_noenv_set(self): + config.pop('running_env', None) + with self.assertRaises(ValidationError): + self.encrypted_data.sudo()._encrypted_store( + self.crypted_data_name, "My config") + + def test_store_data_nokey_set(self): + config.pop('encryption_key_test', None) + with self.assertRaises(ValidationError): + self.encrypted_data.sudo()._encrypted_store( + self.crypted_data_name, "My config") + + def test_get_data_decrypted_and_cache(self): + self.encrypted_data.sudo()._encrypted_store( + 'test_model,1', "My config") + data = self.encrypted_data.sudo()._encrypted_get( + self.crypted_data_name) + self.assertEqual(data, "My config") + + # Test cache really depends on user (super user) else any user could + # access the data + admin = self.env.ref('base.user_admin') + with self.assertRaises(AccessError): + self.encrypted_data.sudo(admin)._encrypted_get( + self.crypted_data_name) + + # Change value should invalidate cache + self.encrypted_data.sudo()._encrypted_store( + 'test_model,1', "Other Config") + new_data = self.encrypted_data.sudo()._encrypted_get( + self.crypted_data_name) + self.assertEqual(new_data, "Other Config") + + def test_get_data_wrong_key(self): + self.encrypted_data.sudo()._encrypted_store( + 'test_model,1', "My config") + new_key = Fernet.generate_key() + config['encryption_key_test'] = new_key.decode() + with self.assertRaises(ValidationError): + self.encrypted_data.sudo()._encrypted_get( + self.crypted_data_name) + + def test_get_empty_data(self): + empty_data = self.encrypted_data.sudo()._encrypted_get( + self.crypted_data_name) + self.assertEqual(empty_data, None) + + def test_get_wrong_json(self): + self.encrypted_data.sudo()._encrypted_store( + self.crypted_data_name, 'config') + with self.assertRaises(ValidationError): + self.encrypted_data.sudo()._encrypted_read_json( + self.crypted_data_name) + + def test_get_good_json(self): + self.encrypted_data.sudo()._encrypted_store_json( + self.crypted_data_name, {'key': 'value'}) + data = self.encrypted_data.sudo()._encrypted_read_json( + self.crypted_data_name) + self.assertEqual(data, {'key': 'value'}) + + def test_get_empty_json(self): + data = self.encrypted_data.sudo()._encrypted_read_json( + self.crypted_data_name) + self.assertEqual(data, {}) + + def test_get_data_with_bin_size_context(self): + self.encrypted_data.sudo()._encrypted_store( + self.crypted_data_name, "test") + data = self.encrypted_data.sudo().with_context(bin_size=True).\ + _encrypted_get(self.crypted_data_name) + self.assertEqual(data, "test") From a66d0237fbd2a59a19eedd3ba034f25cd7dced18 Mon Sep 17 00:00:00 2001 From: oca-travis Date: Fri, 27 Mar 2020 16:50:14 +0000 Subject: [PATCH 02/14] [UPD] Update data_encryption.pot --- data_encryption/i18n/data_encryption.pot | 121 +++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 data_encryption/i18n/data_encryption.pot diff --git a/data_encryption/i18n/data_encryption.pot b/data_encryption/i18n/data_encryption.pot new file mode 100644 index 0000000..38f2f21 --- /dev/null +++ b/data_encryption/i18n/data_encryption.pot @@ -0,0 +1,121 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * data_encryption +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: data_encryption +#: model:ir.model.fields,help:data_encryption.field_encrypted_data__environment +msgid "Concerned Odoo environment (prod, preprod...)" +msgstr "" + +#. module: data_encryption +#: model:ir.model.fields,field_description:data_encryption.field_encrypted_data__create_uid +msgid "Created by" +msgstr "" + +#. module: data_encryption +#: model:ir.model.fields,field_description:data_encryption.field_encrypted_data__create_date +msgid "Created on" +msgstr "" + +#. module: data_encryption +#: model:ir.model.fields,field_description:data_encryption.field_encrypted_data__display_name +msgid "Display Name" +msgstr "" + +#. module: data_encryption +#: model:ir.model.fields,field_description:data_encryption.field_encrypted_data__encrypted_data +msgid "Encrypted Data" +msgstr "" + +#. module: data_encryption +#: code:addons/data_encryption/models/encrypted_data.py:58 +#, python-format +msgid "Encrypted data can only be read as superuser" +msgstr "" + +#. module: data_encryption +#: model:ir.model.fields,field_description:data_encryption.field_encrypted_data__environment +msgid "Environment" +msgstr "" + +#. module: data_encryption +#: model:ir.model.fields,field_description:data_encryption.field_encrypted_data__id +msgid "ID" +msgstr "" + +#. module: data_encryption +#: model:ir.model.fields,field_description:data_encryption.field_encrypted_data____last_update +msgid "Last Modified on" +msgstr "" + +#. module: data_encryption +#: model:ir.model.fields,field_description:data_encryption.field_encrypted_data__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: data_encryption +#: model:ir.model.fields,field_description:data_encryption.field_encrypted_data__write_date +msgid "Last Updated on" +msgstr "" + +#. module: data_encryption +#: model:ir.model.fields,field_description:data_encryption.field_encrypted_data__name +msgid "Name" +msgstr "" + +#. module: data_encryption +#: code:addons/data_encryption/models/encrypted_data.py:100 +#, python-format +msgid "No '%s' entry found in config file. Use a key similar to: %s" +msgstr "" + +#. module: data_encryption +#: code:addons/data_encryption/models/encrypted_data.py:87 +#, python-format +msgid "No environment found, please check your running_env entry in your config file." +msgstr "" + +#. module: data_encryption +#: code:addons/data_encryption/models/encrypted_data.py:46 +#, python-format +msgid "Password has been encrypted with a different key. Unless you can recover the previous key, this password is unreadable." +msgstr "" + +#. module: data_encryption +#: model:ir.model,name:data_encryption.model_encrypted_data +msgid "Store any encrypted data by environment" +msgstr "" + +#. module: data_encryption +#: model:ir.model.fields,help:data_encryption.field_encrypted_data__name +msgid "Technical name" +msgstr "" + +#. module: data_encryption +#: code:addons/data_encryption/models/encrypted_data.py:77 +#, python-format +msgid "The data you are trying to read are not in a json format" +msgstr "" + +#. module: data_encryption +#: sql_constraint:encrypted.data:0 +msgid "You can not store multiple encrypted data for the same record and environment" +msgstr "" + +#. module: data_encryption +#: code:addons/data_encryption/models/encrypted_data.py:119 +#, python-format +msgid "You can only encrypt data as superuser" +msgstr "" + From 185f0c1e995d485383b2a507be35570368f3adce Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Fri, 27 Mar 2020 16:59:06 +0000 Subject: [PATCH 03/14] [UPD] README.rst --- data_encryption/README.rst | 115 +++++ data_encryption/static/description/index.html | 460 ++++++++++++++++++ 2 files changed, 575 insertions(+) create mode 100644 data_encryption/README.rst create mode 100644 data_encryption/static/description/index.html diff --git a/data_encryption/README.rst b/data_encryption/README.rst new file mode 100644 index 0000000..837afa9 --- /dev/null +++ b/data_encryption/README.rst @@ -0,0 +1,115 @@ +=============== +Encryption data +=============== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Alpha-red.png + :target: https://odoo-community.org/page/development-status + :alt: Alpha +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fserver--env-lightgray.png?logo=github + :target: https://github.com/OCA/server-env/tree/12.0/data_encryption + :alt: OCA/server-env +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/server-env-12-0/server-env-12-0-data_encryption + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/254/12.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module allows to encrypt and decrypt data. This module is not usable +by itself, it is a low level module which should work as a base for others. +An example is the module server_environment_data_encryption + +.. IMPORTANT:: + This is an alpha version, the data model and design can change at any time without warning. + Only for development or testing purpose, do not use in production. + `More details on development status `_ + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +To configure this module, you need to edit the main configuration file +of your instance, and add a directive called ``running_env``. Commonly +used values are 'dev', 'test', 'production':: + + [options] + running_env=dev + + +You also need to set the encryption key(s). The main idea is to have different +encryption keys for your different environment, to avoid the possibility to retrieve +crucial information from the production environment in a developement environment, for instance. +So, if your running environment is 'dev':: + + [options] + encryption_key_dev=fyeMIx9XVPBBky5XZeLDxVc9dFKy7Uzas3AoyMarHPA= + +In the configuration file of your production environment, you may want to configure +all your other environments encryption key. This way, from production you can encrypt and decrypt +data for all environments. + +You can generate keys with python -c 'from cryptography.fernet import Fernet; print Fernet.generate_key()'. + +Known issues / Roadmap +====================== + +For now the encryption is dependent on the environment. It has been designed +to store the same kind of data with different values depending on the environement +(dev, preprod, prod...). +An improvement could be to split this in 2 modules. But the environment stuff +is not a big constraint. + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Akretion + +Contributors +~~~~~~~~~~~~ + +* Raphaël Reverdy +* Florian da Costa + +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-env `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/data_encryption/static/description/index.html b/data_encryption/static/description/index.html new file mode 100644 index 0000000..b832f77 --- /dev/null +++ b/data_encryption/static/description/index.html @@ -0,0 +1,460 @@ + + + + + + +Encryption data + + + +
+

Encryption data

+ + +

Alpha License: AGPL-3 OCA/server-env Translate me on Weblate Try me on Runbot

+

This module allows to encrypt and decrypt data. This module is not usable +by itself, it is a low level module which should work as a base for others. +An example is the module server_environment_data_encryption

+
+

Important

+

This is an alpha version, the data model and design can change at any time without warning. +Only for development or testing purpose, do not use in production. +More details on development status

+
+

Table of contents

+ +
+

Configuration

+

To configure this module, you need to edit the main configuration file +of your instance, and add a directive called running_env. Commonly +used values are ‘dev’, ‘test’, ‘production’:

+
+[options]
+running_env=dev
+
+

You also need to set the encryption key(s). The main idea is to have different +encryption keys for your different environment, to avoid the possibility to retrieve +crucial information from the production environment in a developement environment, for instance. +So, if your running environment is ‘dev’:

+
+[options]
+encryption_key_dev=fyeMIx9XVPBBky5XZeLDxVc9dFKy7Uzas3AoyMarHPA=
+
+

In the configuration file of your production environment, you may want to configure +all your other environments encryption key. This way, from production you can encrypt and decrypt +data for all environments.

+

You can generate keys with python -c ‘from cryptography.fernet import Fernet; print Fernet.generate_key()’.

+
+
+

Known issues / Roadmap

+

For now the encryption is dependent on the environment. It has been designed +to store the same kind of data with different values depending on the environement +(dev, preprod, prod…). +An improvement could be to split this in 2 modules. But the environment stuff +is not a big constraint.

+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +feedback.

+

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

+
+
+

Credits

+
+

Authors

+
    +
  • Akretion
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

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-env project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + From 36016cbff108a2754f7a307810060dd964188a36 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Fri, 27 Mar 2020 16:59:06 +0000 Subject: [PATCH 04/14] [ADD] icon.png --- data_encryption/static/description/icon.png | Bin 0 -> 9455 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 data_encryption/static/description/icon.png diff --git a/data_encryption/static/description/icon.png b/data_encryption/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3a0328b516c4980e8e44cdb63fd945757ddd132d GIT binary patch literal 9455 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 z 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 Xviia!U7SGha1wx#SCgwmn*{w2TRX*I literal 0 HcmV?d00001 From df274a2e4125dde7d3a05b92cddf0f5264442284 Mon Sep 17 00:00:00 2001 From: Thomas Binsfeld Date: Fri, 2 Oct 2020 11:21:36 +0200 Subject: [PATCH 05/14] [REF] data_encryption: Black python code --- data_encryption/__manifest__.py | 15 +--- data_encryption/models/encrypted_data.py | 90 +++++++++++++--------- data_encryption/tests/common.py | 16 ++-- data_encryption/tests/test_data_encrypt.py | 71 ++++++++++------- 4 files changed, 109 insertions(+), 83 deletions(-) diff --git a/data_encryption/__manifest__.py b/data_encryption/__manifest__.py index 501f45a..292f6f0 100644 --- a/data_encryption/__manifest__.py +++ b/data_encryption/__manifest__.py @@ -4,21 +4,14 @@ "name": "Encryption data", "summary": "Store accounts and credentials encrypted by environment", "version": "12.0.1.0.0", - "development_status": 'Alpha', + "development_status": "Alpha", "category": "Tools", "website": "https://github/oca/server-env", "author": "Akretion, Odoo Community Association (OCA)", "license": "AGPL-3", "application": False, "installable": True, - "external_dependencies": { - "python": [ - 'cryptography'], - }, - "depends": [ - "base", - ], - "data": [ - "security/ir.model.access.csv", - ], + "external_dependencies": {"python": ["cryptography"],}, + "depends": ["base",], + "data": ["security/ir.model.access.csv",], } diff --git a/data_encryption/models/encrypted_data.py b/data_encryption/models/encrypted_data.py index 5e103b6..3353c53 100644 --- a/data_encryption/models/encrypted_data.py +++ b/data_encryption/models/encrypted_data.py @@ -19,22 +19,26 @@ except ImportError as err: # pragma: no cover class EncryptedData(models.Model): """Model to store encrypted data by environment (prod, preprod...)""" - _name = 'encrypted.data' - _description = 'Store any encrypted data by environment' + _name = "encrypted.data" + _description = "Store any encrypted data by environment" name = fields.Char( - required=True, readonly=True, index=True, - help="Technical name") + required=True, readonly=True, index=True, help="Technical name" + ) environment = fields.Char( required=True, index=True, - help="Concerned Odoo environment (prod, preprod...)") + help="Concerned Odoo environment (prod, preprod...)", + ) encrypted_data = fields.Binary() _sql_constraints = [ - ('name_environment_uniq', 'unique (name, environment)', - 'You can not store multiple encrypted data for the same record and \ - environment') + ( + "name_environment_uniq", + "unique (name, environment)", + "You can not store multiple encrypted data for the same record and \ + environment", + ) ] def _decrypt_data(self, env): @@ -43,29 +47,34 @@ class EncryptedData(models.Model): try: return cipher.decrypt(self.encrypted_data).decode() except InvalidToken: - raise ValidationError(_( - "Password has been encrypted with a different " - "key. Unless you can recover the previous key, " - "this password is unreadable.")) + raise ValidationError( + _( + "Password has been encrypted with a different " + "key. Unless you can recover the previous key, " + "this password is unreadable." + ) + ) @api.model - @ormcache('self._uid', 'name', 'env') + @ormcache("self._uid", "name", "env") def _encrypted_get(self, name, env=None): - if self.env.context.get('bin_size'): + if self.env.context.get("bin_size"): self = self.with_context(bin_size=False) if not self.env.user._is_superuser(): raise AccessError( - _("Encrypted data can only be read as superuser")) + _("Encrypted data can only be read as superuser") + ) if not env: env = self._retrieve_env() encrypted_rec = self.search( - [('name', '=', name), ('environment', '=', env)]) + [("name", "=", name), ("environment", "=", env)] + ) if not encrypted_rec: return None return encrypted_rec._decrypt_data(env) @api.model - @ormcache('self._uid', 'name', 'env') + @ormcache("self._uid", "name", "env") def _encrypted_read_json(self, name, env=None): data = self._encrypted_get(name, env=env) if not data: @@ -74,18 +83,22 @@ class EncryptedData(models.Model): return json.loads(data) except (ValueError, TypeError): raise ValidationError( - _("The data you are trying to read are not in a json format")) + _("The data you are trying to read are not in a json format") + ) @staticmethod def _retrieve_env(): """Return the current environment Raise if none is found """ - current = config.get('running_env', False) + current = config.get("running_env", False) if not current: raise ValidationError( - _('No environment found, please check your running_env ' - 'entry in your config file.')) + _( + "No environment found, please check your running_env " + "entry in your config file." + ) + ) return current @classmethod @@ -94,12 +107,15 @@ class EncryptedData(models.Model): force_env = name of the env key. Useful for encoding against one precise env """ - key_name = 'encryption_key_%s' % env + key_name = "encryption_key_%s" % env key_str = config.get(key_name) if not key_str: - raise ValidationError(_( - "No '%s' entry found in config file. " - "Use a key similar to: %s") % (key_name, Fernet.generate_key()) + raise ValidationError( + _( + "No '%s' entry found in config file. " + "Use a key similar to: %s" + ) + % (key_name, Fernet.generate_key()) ) # key should be in bytes format key = key_str.encode() @@ -110,26 +126,28 @@ class EncryptedData(models.Model): cipher = self._get_cipher(env) if not isinstance(data, bytes): data = data.encode() - return cipher.encrypt(data or '') + return cipher.encrypt(data or "") @api.model - def _encrypted_store(self, name, data, env=None): + def _encrypted_store(self, name, data, env=None): if not self.env.user._is_superuser(): - raise AccessError( - _("You can only encrypt data as superuser")) + raise AccessError(_("You can only encrypt data as superuser")) if not env: env = self._retrieve_env() encrypted_data = self._encrypt_data(data, env) existing_data = self.search( - [('name', '=', name), ('environment', '=', env)]) + [("name", "=", name), ("environment", "=", env)] + ) if existing_data: - existing_data.write({'encrypted_data': encrypted_data}) + existing_data.write({"encrypted_data": encrypted_data}) else: - self.create({ - 'name': name, - 'environment': env, - 'encrypted_data': encrypted_data, - }) + self.create( + { + "name": name, + "environment": env, + "encrypted_data": encrypted_data, + } + ) self._encrypted_get.clear_cache(self) self._encrypted_read_json.clear_cache(self) diff --git a/data_encryption/tests/common.py b/data_encryption/tests/common.py index f044569..0ab30b8 100644 --- a/data_encryption/tests/common.py +++ b/data_encryption/tests/common.py @@ -15,15 +15,14 @@ except ImportError as err: # pragma: no cover class CommonDataEncrypted(TransactionCase): - def setUp(self): super().setUp() - self.encrypted_data = self.env['encrypted.data'] - self.set_new_key_env('test') - self.old_running_env = config.get('running_env', '') - config['running_env'] = 'test' - self.crypted_data_name = 'test_model,1' + self.encrypted_data = self.env["encrypted.data"] + self.set_new_key_env("test") + self.old_running_env = config.get("running_env", "") + config["running_env"] = "test" + self.crypted_data_name = "test_model,1" def set_new_key_env(self, environment): crypting_key = Fernet.generate_key() @@ -31,9 +30,8 @@ class CommonDataEncrypted(TransactionCase): # the key com from the config file and is not in a binary format. # So we decode here to avoid having a special behavior because of # the tests. - config['encryption_key_{}'.format(environment)] = \ - crypting_key.decode() + config["encryption_key_{}".format(environment)] = crypting_key.decode() def tearDown(self): - config['running_env'] = self.old_running_env + config["running_env"] = self.old_running_env return super().tearDown() diff --git a/data_encryption/tests/test_data_encrypt.py b/data_encryption/tests/test_data_encrypt.py index 6e42722..1cbb997 100644 --- a/data_encryption/tests/test_data_encrypt.py +++ b/data_encryption/tests/test_data_encrypt.py @@ -17,83 +17,100 @@ except ImportError as err: # pragma: no cover class TestDataEncrypted(CommonDataEncrypted): - def test_store_data_no_superuser(self): # only superuser can use this model - admin = self.env.ref('base.user_admin') + admin = self.env.ref("base.user_admin") with self.assertRaises(AccessError): self.encrypted_data.sudo(admin.id)._encrypted_store( - self.crypted_data_name, "My config") + self.crypted_data_name, "My config" + ) def test_store_data_noenv_set(self): - config.pop('running_env', None) + config.pop("running_env", None) with self.assertRaises(ValidationError): self.encrypted_data.sudo()._encrypted_store( - self.crypted_data_name, "My config") + self.crypted_data_name, "My config" + ) def test_store_data_nokey_set(self): - config.pop('encryption_key_test', None) + config.pop("encryption_key_test", None) with self.assertRaises(ValidationError): self.encrypted_data.sudo()._encrypted_store( - self.crypted_data_name, "My config") + self.crypted_data_name, "My config" + ) def test_get_data_decrypted_and_cache(self): self.encrypted_data.sudo()._encrypted_store( - 'test_model,1', "My config") + "test_model,1", "My config" + ) data = self.encrypted_data.sudo()._encrypted_get( - self.crypted_data_name) + self.crypted_data_name + ) self.assertEqual(data, "My config") # Test cache really depends on user (super user) else any user could # access the data - admin = self.env.ref('base.user_admin') + admin = self.env.ref("base.user_admin") with self.assertRaises(AccessError): self.encrypted_data.sudo(admin)._encrypted_get( - self.crypted_data_name) + self.crypted_data_name + ) # Change value should invalidate cache self.encrypted_data.sudo()._encrypted_store( - 'test_model,1', "Other Config") + "test_model,1", "Other Config" + ) new_data = self.encrypted_data.sudo()._encrypted_get( - self.crypted_data_name) + self.crypted_data_name + ) self.assertEqual(new_data, "Other Config") def test_get_data_wrong_key(self): self.encrypted_data.sudo()._encrypted_store( - 'test_model,1', "My config") + "test_model,1", "My config" + ) new_key = Fernet.generate_key() - config['encryption_key_test'] = new_key.decode() + config["encryption_key_test"] = new_key.decode() with self.assertRaises(ValidationError): - self.encrypted_data.sudo()._encrypted_get( - self.crypted_data_name) + self.encrypted_data.sudo()._encrypted_get(self.crypted_data_name) def test_get_empty_data(self): empty_data = self.encrypted_data.sudo()._encrypted_get( - self.crypted_data_name) + self.crypted_data_name + ) self.assertEqual(empty_data, None) def test_get_wrong_json(self): self.encrypted_data.sudo()._encrypted_store( - self.crypted_data_name, 'config') + self.crypted_data_name, "config" + ) with self.assertRaises(ValidationError): self.encrypted_data.sudo()._encrypted_read_json( - self.crypted_data_name) + self.crypted_data_name + ) def test_get_good_json(self): self.encrypted_data.sudo()._encrypted_store_json( - self.crypted_data_name, {'key': 'value'}) + self.crypted_data_name, {"key": "value"} + ) data = self.encrypted_data.sudo()._encrypted_read_json( - self.crypted_data_name) - self.assertEqual(data, {'key': 'value'}) + self.crypted_data_name + ) + self.assertEqual(data, {"key": "value"}) def test_get_empty_json(self): data = self.encrypted_data.sudo()._encrypted_read_json( - self.crypted_data_name) + self.crypted_data_name + ) self.assertEqual(data, {}) def test_get_data_with_bin_size_context(self): self.encrypted_data.sudo()._encrypted_store( - self.crypted_data_name, "test") - data = self.encrypted_data.sudo().with_context(bin_size=True).\ - _encrypted_get(self.crypted_data_name) + self.crypted_data_name, "test" + ) + data = ( + self.encrypted_data.sudo() + .with_context(bin_size=True) + ._encrypted_get(self.crypted_data_name) + ) self.assertEqual(data, "test") From 2e3f0e6b9950674845933b81db0fef353a8159b1 Mon Sep 17 00:00:00 2001 From: Thomas Binsfeld Date: Fri, 2 Oct 2020 11:21:36 +0200 Subject: [PATCH 06/14] [MIG] data_encryption: Migration to 13.0 --- data_encryption/__manifest__.py | 8 +-- data_encryption/models/encrypted_data.py | 43 ++++++---------- data_encryption/tests/common.py | 5 +- data_encryption/tests/test_data_encrypt.py | 60 +++++++--------------- 4 files changed, 39 insertions(+), 77 deletions(-) diff --git a/data_encryption/__manifest__.py b/data_encryption/__manifest__.py index 292f6f0..afec603 100644 --- a/data_encryption/__manifest__.py +++ b/data_encryption/__manifest__.py @@ -3,7 +3,7 @@ { "name": "Encryption data", "summary": "Store accounts and credentials encrypted by environment", - "version": "12.0.1.0.0", + "version": "13.0.1.0.0", "development_status": "Alpha", "category": "Tools", "website": "https://github/oca/server-env", @@ -11,7 +11,7 @@ "license": "AGPL-3", "application": False, "installable": True, - "external_dependencies": {"python": ["cryptography"],}, - "depends": ["base",], - "data": ["security/ir.model.access.csv",], + "external_dependencies": {"python": ["cryptography"]}, + "depends": ["base"], + "data": ["security/ir.model.access.csv"], } diff --git a/data_encryption/models/encrypted_data.py b/data_encryption/models/encrypted_data.py index 3353c53..f49b9b7 100644 --- a/data_encryption/models/encrypted_data.py +++ b/data_encryption/models/encrypted_data.py @@ -1,12 +1,12 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -import logging import json +import logging from odoo import api, fields, models from odoo.exceptions import AccessError, ValidationError +from odoo.tools import ormcache from odoo.tools.config import config from odoo.tools.translate import _ -from odoo.tools import ormcache _logger = logging.getLogger(__name__) @@ -22,15 +22,11 @@ class EncryptedData(models.Model): _name = "encrypted.data" _description = "Store any encrypted data by environment" - name = fields.Char( - required=True, readonly=True, index=True, help="Technical name" - ) + name = fields.Char(required=True, readonly=True, index=True, help="Technical name") environment = fields.Char( - required=True, - index=True, - help="Concerned Odoo environment (prod, preprod...)", + required=True, index=True, help="Concerned Odoo environment (prod, preprod...)", ) - encrypted_data = fields.Binary() + encrypted_data = fields.Binary(attachment=False) _sql_constraints = [ ( @@ -60,15 +56,13 @@ class EncryptedData(models.Model): def _encrypted_get(self, name, env=None): if self.env.context.get("bin_size"): self = self.with_context(bin_size=False) - if not self.env.user._is_superuser(): + if not self.env.su: raise AccessError( - _("Encrypted data can only be read as superuser") + _("Encrypted data can only be read with suspended security (sudo)") ) if not env: env = self._retrieve_env() - encrypted_rec = self.search( - [("name", "=", name), ("environment", "=", env)] - ) + encrypted_rec = self.search([("name", "=", name), ("environment", "=", env)]) if not encrypted_rec: return None return encrypted_rec._decrypt_data(env) @@ -111,10 +105,7 @@ class EncryptedData(models.Model): key_str = config.get(key_name) if not key_str: raise ValidationError( - _( - "No '%s' entry found in config file. " - "Use a key similar to: %s" - ) + _("No '%s' entry found in config file. " "Use a key similar to: %s") % (key_name, Fernet.generate_key()) ) # key should be in bytes format @@ -130,23 +121,19 @@ class EncryptedData(models.Model): @api.model def _encrypted_store(self, name, data, env=None): - if not self.env.user._is_superuser(): - raise AccessError(_("You can only encrypt data as superuser")) + if not self.env.su: + raise AccessError( + _("You can only encrypt data with suspended security (sudo)") + ) if not env: env = self._retrieve_env() encrypted_data = self._encrypt_data(data, env) - existing_data = self.search( - [("name", "=", name), ("environment", "=", env)] - ) + existing_data = self.search([("name", "=", name), ("environment", "=", env)]) if existing_data: existing_data.write({"encrypted_data": encrypted_data}) else: self.create( - { - "name": name, - "environment": env, - "encrypted_data": encrypted_data, - } + {"name": name, "environment": env, "encrypted_data": encrypted_data} ) self._encrypted_get.clear_cache(self) self._encrypted_read_json.clear_cache(self) diff --git a/data_encryption/tests/common.py b/data_encryption/tests/common.py index 0ab30b8..a57377d 100644 --- a/data_encryption/tests/common.py +++ b/data_encryption/tests/common.py @@ -1,11 +1,10 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +import logging + from odoo.tests.common import TransactionCase from odoo.tools.config import config - -import logging - _logger = logging.getLogger(__name__) try: diff --git a/data_encryption/tests/test_data_encrypt.py b/data_encryption/tests/test_data_encrypt.py index 1cbb997..7f25053 100644 --- a/data_encryption/tests/test_data_encrypt.py +++ b/data_encryption/tests/test_data_encrypt.py @@ -1,13 +1,13 @@ # © 2016 Akretion Raphaël REVERDY # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from .common import CommonDataEncrypted -from odoo.tools.config import config -from odoo.exceptions import AccessError, ValidationError - - import logging +from odoo.exceptions import AccessError, ValidationError +from odoo.tools.config import config + +from .common import CommonDataEncrypted + _logger = logging.getLogger(__name__) try: @@ -21,7 +21,7 @@ class TestDataEncrypted(CommonDataEncrypted): # only superuser can use this model admin = self.env.ref("base.user_admin") with self.assertRaises(AccessError): - self.encrypted_data.sudo(admin.id)._encrypted_store( + self.encrypted_data.with_user(admin.id)._encrypted_store( self.crypted_data_name, "My config" ) @@ -40,74 +40,50 @@ class TestDataEncrypted(CommonDataEncrypted): ) def test_get_data_decrypted_and_cache(self): - self.encrypted_data.sudo()._encrypted_store( - "test_model,1", "My config" - ) - data = self.encrypted_data.sudo()._encrypted_get( - self.crypted_data_name - ) + self.encrypted_data.sudo()._encrypted_store("test_model,1", "My config") + data = self.encrypted_data.sudo()._encrypted_get(self.crypted_data_name) self.assertEqual(data, "My config") # Test cache really depends on user (super user) else any user could # access the data admin = self.env.ref("base.user_admin") with self.assertRaises(AccessError): - self.encrypted_data.sudo(admin)._encrypted_get( - self.crypted_data_name - ) + self.encrypted_data.with_user(admin)._encrypted_get(self.crypted_data_name) # Change value should invalidate cache - self.encrypted_data.sudo()._encrypted_store( - "test_model,1", "Other Config" - ) - new_data = self.encrypted_data.sudo()._encrypted_get( - self.crypted_data_name - ) + self.encrypted_data.sudo()._encrypted_store("test_model,1", "Other Config") + new_data = self.encrypted_data.sudo()._encrypted_get(self.crypted_data_name) self.assertEqual(new_data, "Other Config") def test_get_data_wrong_key(self): - self.encrypted_data.sudo()._encrypted_store( - "test_model,1", "My config" - ) + self.encrypted_data.sudo()._encrypted_store("test_model,1", "My config") new_key = Fernet.generate_key() config["encryption_key_test"] = new_key.decode() with self.assertRaises(ValidationError): self.encrypted_data.sudo()._encrypted_get(self.crypted_data_name) def test_get_empty_data(self): - empty_data = self.encrypted_data.sudo()._encrypted_get( - self.crypted_data_name - ) + empty_data = self.encrypted_data.sudo()._encrypted_get(self.crypted_data_name) self.assertEqual(empty_data, None) def test_get_wrong_json(self): - self.encrypted_data.sudo()._encrypted_store( - self.crypted_data_name, "config" - ) + self.encrypted_data.sudo()._encrypted_store(self.crypted_data_name, "config") with self.assertRaises(ValidationError): - self.encrypted_data.sudo()._encrypted_read_json( - self.crypted_data_name - ) + self.encrypted_data.sudo()._encrypted_read_json(self.crypted_data_name) def test_get_good_json(self): self.encrypted_data.sudo()._encrypted_store_json( self.crypted_data_name, {"key": "value"} ) - data = self.encrypted_data.sudo()._encrypted_read_json( - self.crypted_data_name - ) + data = self.encrypted_data.sudo()._encrypted_read_json(self.crypted_data_name) self.assertEqual(data, {"key": "value"}) def test_get_empty_json(self): - data = self.encrypted_data.sudo()._encrypted_read_json( - self.crypted_data_name - ) + data = self.encrypted_data.sudo()._encrypted_read_json(self.crypted_data_name) self.assertEqual(data, {}) def test_get_data_with_bin_size_context(self): - self.encrypted_data.sudo()._encrypted_store( - self.crypted_data_name, "test" - ) + self.encrypted_data.sudo()._encrypted_store(self.crypted_data_name, "test") data = ( self.encrypted_data.sudo() .with_context(bin_size=True) From 54ec240e93f97e49a87c7ebedd4220a20652bbd4 Mon Sep 17 00:00:00 2001 From: Mourad Date: Mon, 12 Oct 2020 14:07:41 +0200 Subject: [PATCH 07/14] [IMP] server_environment_data_encryption, data_encryption: black, isort, prettier --- data_encryption/models/encrypted_data.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/data_encryption/models/encrypted_data.py b/data_encryption/models/encrypted_data.py index f49b9b7..d9dbc67 100644 --- a/data_encryption/models/encrypted_data.py +++ b/data_encryption/models/encrypted_data.py @@ -24,7 +24,9 @@ class EncryptedData(models.Model): name = fields.Char(required=True, readonly=True, index=True, help="Technical name") environment = fields.Char( - required=True, index=True, help="Concerned Odoo environment (prod, preprod...)", + required=True, + index=True, + help="Concerned Odoo environment (prod, preprod...)", ) encrypted_data = fields.Binary(attachment=False) @@ -83,7 +85,7 @@ class EncryptedData(models.Model): @staticmethod def _retrieve_env(): """Return the current environment - Raise if none is found + Raise if none is found """ current = config.get("running_env", False) if not current: From bcf6c5d08ded201f004b7ee35d5d2eb11dec49ac Mon Sep 17 00:00:00 2001 From: Mourad Date: Mon, 12 Oct 2020 15:32:19 +0200 Subject: [PATCH 08/14] [MIG] server_environment_data_encryption, data_encryption: Migration to 14.0 note: exclude tests/fixtures from pre-commit check --- data_encryption/__manifest__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data_encryption/__manifest__.py b/data_encryption/__manifest__.py index afec603..3655a5d 100644 --- a/data_encryption/__manifest__.py +++ b/data_encryption/__manifest__.py @@ -3,10 +3,10 @@ { "name": "Encryption data", "summary": "Store accounts and credentials encrypted by environment", - "version": "13.0.1.0.0", + "version": "14.0.1.0.0", "development_status": "Alpha", "category": "Tools", - "website": "https://github/oca/server-env", + "website": "https://github.com/OCA/server-env", "author": "Akretion, Odoo Community Association (OCA)", "license": "AGPL-3", "application": False, From 55f08d50784335b80fbee5bb0bf20a1010bc1840 Mon Sep 17 00:00:00 2001 From: oca-travis Date: Fri, 5 Mar 2021 10:42:49 +0000 Subject: [PATCH 09/14] [UPD] Update data_encryption.pot --- data_encryption/i18n/data_encryption.pot | 37 ++++++++++++++---------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/data_encryption/i18n/data_encryption.pot b/data_encryption/i18n/data_encryption.pot index 38f2f21..b330981 100644 --- a/data_encryption/i18n/data_encryption.pot +++ b/data_encryption/i18n/data_encryption.pot @@ -1,12 +1,12 @@ # Translation of Odoo Server. # This file contains the translation of the following modules: -# * data_encryption +# * data_encryption # msgid "" msgstr "" -"Project-Id-Version: Odoo Server 12.0\n" +"Project-Id-Version: Odoo Server 14.0\n" "Report-Msgid-Bugs-To: \n" -"Last-Translator: <>\n" +"Last-Translator: \n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -39,9 +39,9 @@ msgid "Encrypted Data" msgstr "" #. module: data_encryption -#: code:addons/data_encryption/models/encrypted_data.py:58 +#: code:addons/data_encryption/models/encrypted_data.py:0 #, python-format -msgid "Encrypted data can only be read as superuser" +msgid "Encrypted data can only be read with suspended security (sudo)" msgstr "" #. module: data_encryption @@ -75,21 +75,25 @@ msgid "Name" msgstr "" #. module: data_encryption -#: code:addons/data_encryption/models/encrypted_data.py:100 +#: code:addons/data_encryption/models/encrypted_data.py:0 #, python-format msgid "No '%s' entry found in config file. Use a key similar to: %s" msgstr "" #. module: data_encryption -#: code:addons/data_encryption/models/encrypted_data.py:87 +#: code:addons/data_encryption/models/encrypted_data.py:0 #, python-format -msgid "No environment found, please check your running_env entry in your config file." +msgid "" +"No environment found, please check your running_env entry in your config " +"file." msgstr "" #. module: data_encryption -#: code:addons/data_encryption/models/encrypted_data.py:46 +#: code:addons/data_encryption/models/encrypted_data.py:0 #, python-format -msgid "Password has been encrypted with a different key. Unless you can recover the previous key, this password is unreadable." +msgid "" +"Password has been encrypted with a different key. Unless you can recover the" +" previous key, this password is unreadable." msgstr "" #. module: data_encryption @@ -103,19 +107,20 @@ msgid "Technical name" msgstr "" #. module: data_encryption -#: code:addons/data_encryption/models/encrypted_data.py:77 +#: code:addons/data_encryption/models/encrypted_data.py:0 #, python-format msgid "The data you are trying to read are not in a json format" msgstr "" #. module: data_encryption -#: sql_constraint:encrypted.data:0 -msgid "You can not store multiple encrypted data for the same record and environment" +#: model:ir.model.constraint,message:data_encryption.constraint_encrypted_data_name_environment_uniq +msgid "" +"You can not store multiple encrypted data for the same record and " +"environment" msgstr "" #. module: data_encryption -#: code:addons/data_encryption/models/encrypted_data.py:119 +#: code:addons/data_encryption/models/encrypted_data.py:0 #, python-format -msgid "You can only encrypt data as superuser" +msgid "You can only encrypt data with suspended security (sudo)" msgstr "" - From c70713f488c7222d5de90bcfd7d8681e2c5c2385 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Fri, 5 Mar 2021 10:47:35 +0000 Subject: [PATCH 10/14] [UPD] README.rst --- data_encryption/README.rst | 10 +++++----- data_encryption/static/description/index.html | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/data_encryption/README.rst b/data_encryption/README.rst index 837afa9..bf41e95 100644 --- a/data_encryption/README.rst +++ b/data_encryption/README.rst @@ -14,13 +14,13 @@ Encryption data :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fserver--env-lightgray.png?logo=github - :target: https://github.com/OCA/server-env/tree/12.0/data_encryption + :target: https://github.com/OCA/server-env/tree/14.0/data_encryption :alt: OCA/server-env .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png - :target: https://translation.odoo-community.org/projects/server-env-12-0/server-env-12-0-data_encryption + :target: https://translation.odoo-community.org/projects/server-env-14-0/server-env-14-0-data_encryption :alt: Translate me on Weblate .. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png - :target: https://runbot.odoo-community.org/runbot/254/12.0 + :target: https://runbot.odoo-community.org/runbot/254/14.0 :alt: Try me on Runbot |badge1| |badge2| |badge3| |badge4| |badge5| @@ -79,7 +79,7 @@ Bug Tracker Bugs are tracked on `GitHub Issues `_. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us smashing it by providing a detailed and welcomed -`feedback `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -110,6 +110,6 @@ 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-env `_ project on GitHub. +This module is part of the `OCA/server-env `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/data_encryption/static/description/index.html b/data_encryption/static/description/index.html index b832f77..e35494d 100644 --- a/data_encryption/static/description/index.html +++ b/data_encryption/static/description/index.html @@ -367,7 +367,7 @@ ul.auto-toc { !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> -

Alpha License: AGPL-3 OCA/server-env Translate me on Weblate Try me on Runbot

+

Alpha License: AGPL-3 OCA/server-env Translate me on Weblate Try me on Runbot

This module allows to encrypt and decrypt data. This module is not usable by itself, it is a low level module which should work as a base for others. An example is the module server_environment_data_encryption

@@ -426,7 +426,7 @@ is not a big constraint.

Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us smashing it by providing a detailed and welcomed -feedback.

+feedback.

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

@@ -451,7 +451,7 @@ If you spotted it first, help us smashing it by providing a detailed and welcome

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-env project on GitHub.

+

This module is part of the OCA/server-env project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

From d9eb1d7ff7c324f2413bb9ba91af1b942b76d209 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dept=2E=20T=C3=A9cnico?= Date: Wed, 16 Feb 2022 11:37:42 +0000 Subject: [PATCH 11/14] Added translation using Weblate (Catalan) --- data_encryption/i18n/ca.po | 127 +++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 data_encryption/i18n/ca.po diff --git a/data_encryption/i18n/ca.po b/data_encryption/i18n/ca.po new file mode 100644 index 0000000..266b4bb --- /dev/null +++ b/data_encryption/i18n/ca.po @@ -0,0 +1,127 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * data_encryption +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: ca\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#. module: data_encryption +#: model:ir.model.fields,help:data_encryption.field_encrypted_data__environment +msgid "Concerned Odoo environment (prod, preprod...)" +msgstr "" + +#. module: data_encryption +#: model:ir.model.fields,field_description:data_encryption.field_encrypted_data__create_uid +msgid "Created by" +msgstr "" + +#. module: data_encryption +#: model:ir.model.fields,field_description:data_encryption.field_encrypted_data__create_date +msgid "Created on" +msgstr "" + +#. module: data_encryption +#: model:ir.model.fields,field_description:data_encryption.field_encrypted_data__display_name +msgid "Display Name" +msgstr "" + +#. module: data_encryption +#: model:ir.model.fields,field_description:data_encryption.field_encrypted_data__encrypted_data +msgid "Encrypted Data" +msgstr "" + +#. module: data_encryption +#: code:addons/data_encryption/models/encrypted_data.py:0 +#, python-format +msgid "Encrypted data can only be read with suspended security (sudo)" +msgstr "" + +#. module: data_encryption +#: model:ir.model.fields,field_description:data_encryption.field_encrypted_data__environment +msgid "Environment" +msgstr "" + +#. module: data_encryption +#: model:ir.model.fields,field_description:data_encryption.field_encrypted_data__id +msgid "ID" +msgstr "" + +#. module: data_encryption +#: model:ir.model.fields,field_description:data_encryption.field_encrypted_data____last_update +msgid "Last Modified on" +msgstr "" + +#. module: data_encryption +#: model:ir.model.fields,field_description:data_encryption.field_encrypted_data__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: data_encryption +#: model:ir.model.fields,field_description:data_encryption.field_encrypted_data__write_date +msgid "Last Updated on" +msgstr "" + +#. module: data_encryption +#: model:ir.model.fields,field_description:data_encryption.field_encrypted_data__name +msgid "Name" +msgstr "" + +#. module: data_encryption +#: code:addons/data_encryption/models/encrypted_data.py:0 +#, python-format +msgid "No '%s' entry found in config file. Use a key similar to: %s" +msgstr "" + +#. module: data_encryption +#: code:addons/data_encryption/models/encrypted_data.py:0 +#, python-format +msgid "" +"No environment found, please check your running_env entry in your config " +"file." +msgstr "" + +#. module: data_encryption +#: code:addons/data_encryption/models/encrypted_data.py:0 +#, python-format +msgid "" +"Password has been encrypted with a different key. Unless you can recover the" +" previous key, this password is unreadable." +msgstr "" + +#. module: data_encryption +#: model:ir.model,name:data_encryption.model_encrypted_data +msgid "Store any encrypted data by environment" +msgstr "" + +#. module: data_encryption +#: model:ir.model.fields,help:data_encryption.field_encrypted_data__name +msgid "Technical name" +msgstr "" + +#. module: data_encryption +#: code:addons/data_encryption/models/encrypted_data.py:0 +#, python-format +msgid "The data you are trying to read are not in a json format" +msgstr "" + +#. module: data_encryption +#: model:ir.model.constraint,message:data_encryption.constraint_encrypted_data_name_environment_uniq +msgid "" +"You can not store multiple encrypted data for the same record and " +"environment" +msgstr "" + +#. module: data_encryption +#: code:addons/data_encryption/models/encrypted_data.py:0 +#, python-format +msgid "You can only encrypt data with suspended security (sudo)" +msgstr "" From 949674d06c6c10ed61b95160336886cebe0ae153 Mon Sep 17 00:00:00 2001 From: Florian da Costa Date: Sun, 9 Oct 2022 16:25:46 +0200 Subject: [PATCH 12/14] [IMP] data_encryption: black, isort, prettier --- data_encryption/models/encrypted_data.py | 15 +++++++++------ requirements.txt | 2 ++ setup/data_encryption/odoo/addons/data_encryption | 1 + setup/data_encryption/setup.py | 6 ++++++ 4 files changed, 18 insertions(+), 6 deletions(-) create mode 100644 requirements.txt create mode 120000 setup/data_encryption/odoo/addons/data_encryption create mode 100644 setup/data_encryption/setup.py diff --git a/data_encryption/models/encrypted_data.py b/data_encryption/models/encrypted_data.py index d9dbc67..2e95265 100644 --- a/data_encryption/models/encrypted_data.py +++ b/data_encryption/models/encrypted_data.py @@ -44,14 +44,14 @@ class EncryptedData(models.Model): cipher = self._get_cipher(env) try: return cipher.decrypt(self.encrypted_data).decode() - except InvalidToken: + except InvalidToken as exc: raise ValidationError( _( "Password has been encrypted with a different " "key. Unless you can recover the previous key, " "this password is unreadable." ) - ) + ) from exc @api.model @ormcache("self._uid", "name", "env") @@ -77,10 +77,10 @@ class EncryptedData(models.Model): return {} try: return json.loads(data) - except (ValueError, TypeError): + except (ValueError, TypeError) as exc: raise ValidationError( _("The data you are trying to read are not in a json format") - ) + ) from exc @staticmethod def _retrieve_env(): @@ -107,8 +107,11 @@ class EncryptedData(models.Model): key_str = config.get(key_name) if not key_str: raise ValidationError( - _("No '%s' entry found in config file. " "Use a key similar to: %s") - % (key_name, Fernet.generate_key()) + _( + "No '%(key_name)s' entry found in config file. " + "Use a key similar to: %(key)s" + ) + % {"key_name": key_name, "key": Fernet.generate_key()} ) # key should be in bytes format key = key_str.encode() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..368c5c2 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +# generated from manifests external_dependencies +cryptography diff --git a/setup/data_encryption/odoo/addons/data_encryption b/setup/data_encryption/odoo/addons/data_encryption new file mode 120000 index 0000000..2aee058 --- /dev/null +++ b/setup/data_encryption/odoo/addons/data_encryption @@ -0,0 +1 @@ +../../../../data_encryption \ No newline at end of file diff --git a/setup/data_encryption/setup.py b/setup/data_encryption/setup.py new file mode 100644 index 0000000..28c57bb --- /dev/null +++ b/setup/data_encryption/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) From 069323b40f2ff5653029bb7922f9736d6a6caa06 Mon Sep 17 00:00:00 2001 From: Florian da Costa Date: Sun, 9 Oct 2022 16:31:28 +0200 Subject: [PATCH 13/14] [16][MIG] Migration of data_encryption --- data_encryption/__manifest__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data_encryption/__manifest__.py b/data_encryption/__manifest__.py index 3655a5d..fac10cb 100644 --- a/data_encryption/__manifest__.py +++ b/data_encryption/__manifest__.py @@ -3,7 +3,7 @@ { "name": "Encryption data", "summary": "Store accounts and credentials encrypted by environment", - "version": "14.0.1.0.0", + "version": "16.0.1.0.0", "development_status": "Alpha", "category": "Tools", "website": "https://github.com/OCA/server-env", From 2e2fef10560697805658c0713fb671fa81f054cd Mon Sep 17 00:00:00 2001 From: David Beal Date: Thu, 28 Jul 2022 12:17:07 +0200 Subject: [PATCH 14/14] FIX data_encryption: typo --- data_encryption/README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data_encryption/README.rst b/data_encryption/README.rst index bf41e95..6356515 100644 --- a/data_encryption/README.rst +++ b/data_encryption/README.rst @@ -62,7 +62,7 @@ In the configuration file of your production environment, you may want to config all your other environments encryption key. This way, from production you can encrypt and decrypt data for all environments. -You can generate keys with python -c 'from cryptography.fernet import Fernet; print Fernet.generate_key()'. +You can generate keys with python -c 'from cryptography.fernet import Fernet; print(Fernet.generate_key())'. Known issues / Roadmap ======================