Skip to content

Commit

Permalink
[IMP] Improve security for the asynchronous export by linking the att…
Browse files Browse the repository at this point in the history
…achment to a record only visible to the user
  • Loading branch information
apineux committed Apr 25, 2019
1 parent 3296852 commit fe89ae8
Show file tree
Hide file tree
Showing 8 changed files with 36 additions and 41 deletions.
1 change: 1 addition & 0 deletions base_export_async/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
'data': [
'views/assets.xml',
'security/ir.model.access.csv',
'security/ir_rule.xml',
'data/config_parameter.xml',
'data/cron.xml',
],
Expand Down
4 changes: 2 additions & 2 deletions base_export_async/data/cron.xml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="to_delete_attachment" model="ir.cron">
<field name="name">Delete export generated attachment</field>
<field name="model_id" ref="model_ir_attachment"/>
<field name="name">Delete Generated Exports</field>
<field name="model_id" ref="model_delay_export"/>
<field name="state">code</field>
<field name="code">model.cron_delete()</field>
<field name='interval_number'>1</field>
Expand Down
1 change: 0 additions & 1 deletion base_export_async/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# Copyright 2019 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from . import attachment
from . import delay_export
31 changes: 0 additions & 31 deletions base_export_async/models/attachment.py

This file was deleted.

18 changes: 16 additions & 2 deletions base_export_async/models/delay_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ class DelayExport(models.Model):
_name = 'delay.export'
_description = 'Allow to delay the export'

user_id = fields.Many2one('res.users', string='User', index=True)

@api.model
def delay_export(self, data):
params = json.loads(data.get('data'))
Expand Down Expand Up @@ -65,13 +67,16 @@ def export(self, params):
xls = ExcelExport()
result = xls.from_data(columns_headers, import_data)

export_record = self.sudo().create({'user_id': user.id})

name = "{}.{}".format(model_name, export_format)
attachment = self.env['ir.attachment'].create({
'name': name,
'datas': base64.b64encode(result),
'datas_fname': name,
'type': 'binary',
'to_delete': True,
'res_model': self._name,
'res_id': export_record.id,
})

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

time_to_live = self.env. \
time_to_live = self.sudo().env. \
ref('base_export_async.attachment_time_to_live').value
date_today = fields.Date.from_string(fields.Date.today())
expiration_date = fields.Date.to_string(
Expand All @@ -104,3 +109,12 @@ def export(self, params):
""").format(url, expiration_date),
'auto_delete': True,
})

@api.model
def cron_delete(self):
time_to_live = self.env. \
ref('base_export_async.attachment_time_to_live').value
date_today = fields.Date.from_string(fields.Date.today())
date_to_delete = fields.Date.to_string(
date_today + relativedelta(days=-int(time_to_live)))
self.search([('create_date', '<=', date_to_delete)]).unlink()
3 changes: 2 additions & 1 deletion base_export_async/security/ir.model.access.csv
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_delay_export,delay.export.user,model_delay_export,,1,1,1,1
access_delay_export,delay.export.user,model_delay_export,base.group_user,1,0,0,0
access_delay_export_sudo,delay.export.sudo,model_delay_export,base.group_no_one,1,1,1,1
13 changes: 13 additions & 0 deletions base_export_async/security/ir_rule.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="delay_export_user_only" model="ir.rule">
<field name="name">Only user can read delay.export</field>
<field name="model_id" ref="model_delay_export"/>
<field name="groups" eval="[(4, ref('base.group_user'))]"/>
<field name="perm_read" eval="True"/>
<field name="perm_create" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_unlink" eval="False"/>
<field name="domain_force">[('user_id', '=', user.id)]</field>
</record>
</odoo>
6 changes: 2 additions & 4 deletions base_export_async/tests/test_base_export_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ def test_export_csv(self):
self.assertEqual(len(new_mail), 1)
self.assertEqual(new_attachment.datas_fname,
"res.partner.csv")
self.assertTrue(new_attachment.to_delete)

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

def test_cron_delete(self):
""" Check that cron delete attachment after TTL"""
Expand All @@ -80,9 +78,9 @@ def test_cron_delete(self):
date_to_delete = fields.Date.to_string(
date_today + relativedelta(days=-int(time_to_live)))
# Update create_date with today - TTL
new_attachment.write({
self.delay_export_obj.search([]).write({
'create_date': date_to_delete
})
self.env['ir.attachment'].sudo().cron_delete()
self.delay_export_obj.sudo().cron_delete()
# The attachment must be deleted
self.assertFalse(new_attachment.exists())

0 comments on commit fe89ae8

Please sign in to comment.