Skip to content

Commit fe89ae8

Browse files
committed
[IMP] Improve security for the asynchronous export by linking the attachment to a record only visible to the user
1 parent 3296852 commit fe89ae8

8 files changed

Lines changed: 36 additions & 41 deletions

File tree

base_export_async/__manifest__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
'data': [
1818
'views/assets.xml',
1919
'security/ir.model.access.csv',
20+
'security/ir_rule.xml',
2021
'data/config_parameter.xml',
2122
'data/cron.xml',
2223
],

base_export_async/data/cron.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<odoo>
33
<record id="to_delete_attachment" model="ir.cron">
4-
<field name="name">Delete export generated attachment</field>
5-
<field name="model_id" ref="model_ir_attachment"/>
4+
<field name="name">Delete Generated Exports</field>
5+
<field name="model_id" ref="model_delay_export"/>
66
<field name="state">code</field>
77
<field name="code">model.cron_delete()</field>
88
<field name='interval_number'>1</field>
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
# Copyright 2019 ACSONE SA/NV
22
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
33

4-
from . import attachment
54
from . import delay_export

base_export_async/models/attachment.py

Lines changed: 0 additions & 31 deletions
This file was deleted.

base_export_async/models/delay_export.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ class DelayExport(models.Model):
2020
_name = 'delay.export'
2121
_description = 'Allow to delay the export'
2222

23+
user_id = fields.Many2one('res.users', string='User', index=True)
24+
2325
@api.model
2426
def delay_export(self, data):
2527
params = json.loads(data.get('data'))
@@ -65,13 +67,16 @@ def export(self, params):
6567
xls = ExcelExport()
6668
result = xls.from_data(columns_headers, import_data)
6769

70+
export_record = self.sudo().create({'user_id': user.id})
71+
6872
name = "{}.{}".format(model_name, export_format)
6973
attachment = self.env['ir.attachment'].create({
7074
'name': name,
7175
'datas': base64.b64encode(result),
7276
'datas_fname': name,
7377
'type': 'binary',
74-
'to_delete': True,
78+
'res_model': self._name,
79+
'res_id': export_record.id,
7580
})
7681

7782
url = "{}/web/content/ir.attachment/{}/datas/{}?download=true".format(
@@ -80,7 +85,7 @@ def export(self, params):
8085
attachment.name,
8186
)
8287

83-
time_to_live = self.env. \
88+
time_to_live = self.sudo().env. \
8489
ref('base_export_async.attachment_time_to_live').value
8590
date_today = fields.Date.from_string(fields.Date.today())
8691
expiration_date = fields.Date.to_string(
@@ -104,3 +109,12 @@ def export(self, params):
104109
""").format(url, expiration_date),
105110
'auto_delete': True,
106111
})
112+
113+
@api.model
114+
def cron_delete(self):
115+
time_to_live = self.env. \
116+
ref('base_export_async.attachment_time_to_live').value
117+
date_today = fields.Date.from_string(fields.Date.today())
118+
date_to_delete = fields.Date.to_string(
119+
date_today + relativedelta(days=-int(time_to_live)))
120+
self.search([('create_date', '<=', date_to_delete)]).unlink()
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
2-
access_delay_export,delay.export.user,model_delay_export,,1,1,1,1
2+
access_delay_export,delay.export.user,model_delay_export,base.group_user,1,0,0,0
3+
access_delay_export_sudo,delay.export.sudo,model_delay_export,base.group_no_one,1,1,1,1
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<odoo>
3+
<record id="delay_export_user_only" model="ir.rule">
4+
<field name="name">Only user can read delay.export</field>
5+
<field name="model_id" ref="model_delay_export"/>
6+
<field name="groups" eval="[(4, ref('base.group_user'))]"/>
7+
<field name="perm_read" eval="True"/>
8+
<field name="perm_create" eval="False"/>
9+
<field name="perm_write" eval="False"/>
10+
<field name="perm_unlink" eval="False"/>
11+
<field name="domain_force">[('user_id', '=', user.id)]</field>
12+
</record>
13+
</odoo>

base_export_async/tests/test_base_export_async.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ def test_export_csv(self):
5353
self.assertEqual(len(new_mail), 1)
5454
self.assertEqual(new_attachment.datas_fname,
5555
"res.partner.csv")
56-
self.assertTrue(new_attachment.to_delete)
5756

5857
def test_export_xls(self):
5958
""" Check that the export generate an attachment and email"""
@@ -66,7 +65,6 @@ def test_export_xls(self):
6665
self.assertEqual(len(new_mail), 1)
6766
self.assertEqual(new_attachment.datas_fname,
6867
"res.partner.xls")
69-
self.assertTrue(new_attachment.to_delete)
7068

7169
def test_cron_delete(self):
7270
""" Check that cron delete attachment after TTL"""
@@ -80,9 +78,9 @@ def test_cron_delete(self):
8078
date_to_delete = fields.Date.to_string(
8179
date_today + relativedelta(days=-int(time_to_live)))
8280
# Update create_date with today - TTL
83-
new_attachment.write({
81+
self.delay_export_obj.search([]).write({
8482
'create_date': date_to_delete
8583
})
86-
self.env['ir.attachment'].sudo().cron_delete()
84+
self.delay_export_obj.sudo().cron_delete()
8785
# The attachment must be deleted
8886
self.assertFalse(new_attachment.exists())

0 commit comments

Comments
 (0)