[FIX] mail: delegate document attachment check to message when posting

When creating a <mail.message> with attachments a manual check is done on
given attachemnts to ensure user have rights to read them. Indeed otherwise
user could simply give attachments from a protected document when posting
on a document he can read and try to gain information about those.

However sometimes user can post and create messages without having read
access on the document, e.g. when being notified and answering in a multi
company environment.

In this commit we consider that creating a message with attachments linked
to the same document does not require an additional check for attachments.
The check is performed at message level (see its custom 'check_access_rule')
and is considered sufficient. However attachments linked to other documents
using model and res_id are still checked.

This fix helps greening the 'test_post_wo_access' test recently introduced.

Task-3213982 (Mail: fix 'multi-company' post support)

X-original-commit: odoo/odoo@bab0549904
Part-of: odoo/odoo#114511
This commit is contained in:
Thibault Delavallée
2023-03-07 18:03:03 +01:00
parent 5c5282ba15
commit 37c100a87d
+31 -8
View File
@@ -612,20 +612,43 @@ class Message(models.Model):
messages = super(Message, self).create(values_list)
check_attachment_access = []
if all(isinstance(command, int) or command[0] in (4, 6) for values in values_list for command in values['attachment_ids']):
# link back attachments to records, to filter out attachments linked to
# the same records as the message (considered as ok if message is ok)
# and check rights on other documents
attachments_tocheck = self.env['ir.attachment']
doc_to_attachment_ids = defaultdict(set)
if all(isinstance(command, int) or command[0] in (4, 6)
for values in values_list
for command in values['attachment_ids']):
for values in values_list:
message_attachment_ids = set()
for command in values['attachment_ids']:
if isinstance(command, int):
check_attachment_access += [command]
message_attachment_ids.add(command)
elif command[0] == 6:
check_attachment_access += command[2]
message_attachment_ids |= set(command[2])
else: # command[0] == 4:
check_attachment_access += [command[1]]
message_attachment_ids.add(command[1])
if message_attachment_ids:
key = (values.get('model'), values.get('res_id'))
doc_to_attachment_ids[key] |= message_attachment_ids
attachment_ids_all = {
attachment_id
for doc_attachment_ids in doc_to_attachment_ids
for attachment_id in doc_attachment_ids
}
AttachmentSudo = self.env['ir.attachment'].sudo().with_prefetch(list(attachment_ids_all))
for (model, res_id), doc_attachment_ids in doc_to_attachment_ids.items():
# check only attachments belonging to another model, access already
# checked on message for other attachments
attachments_tocheck += AttachmentSudo.browse(doc_attachment_ids).filtered(
lambda att: att.res_model != model or att.res_id != res_id
).sudo(False)
else:
check_attachment_access = messages.mapped('attachment_ids').ids # fallback on read if any unknow command
if check_attachment_access:
self.env['ir.attachment'].browse(check_attachment_access).check(mode='read')
attachments_tocheck = messages.attachment_ids # fallback on read if any unknown command
if attachments_tocheck:
attachments_tocheck.check('read')
for message, values, tracking_values_cmd in zip(messages, values_list, tracking_values_list):
if tracking_values_cmd: