mirror of
https://github.com/suitenumerique/docs.git
synced 2026-09-23 18:15:10 +02:00
Object storage metadata keys are case insensitive per the S3 specification, but implementations don't agree on the case they give back. When head_object returns a capitalized "Status", updating the attachment status added a second, lowercase entry instead of replacing it, and the copy request ended up carrying two x-amz-meta-status headers. Ceph RadosGW loses one of them behind a proxy, which invalidates the request signature. The same assumption was made when reading the status back in media-auth and media-check, where an attachment stored on such a backend stayed in "processing" forever. Metadata read from the storage is now normalized to lowercase keys before being consumed or copied over. Signed-off-by: risk-alt <aldu6974@gmail.com>
54 lines
1.7 KiB
Python
54 lines
1.7 KiB
Python
"""Malware detection callbacks"""
|
|
|
|
import logging
|
|
|
|
from django.core.files.storage import default_storage
|
|
|
|
from lasuite.malware_detection.enums import ReportStatus
|
|
|
|
from core.enums import DocumentAttachmentStatus
|
|
from core.models import Document
|
|
from core.utils.dicts import lowercase_keys
|
|
|
|
logger = logging.getLogger(__name__)
|
|
security_logger = logging.getLogger("docs.security")
|
|
|
|
|
|
def malware_detection_callback(file_path, status, error_info, **kwargs):
|
|
"""Malware detection callback"""
|
|
|
|
if status == ReportStatus.SAFE:
|
|
logger.info("File %s is safe", file_path)
|
|
# Get existing metadata
|
|
s3_client = default_storage.connection.meta.client
|
|
bucket_name = default_storage.bucket_name
|
|
head_resp = s3_client.head_object(Bucket=bucket_name, Key=file_path)
|
|
metadata = lowercase_keys(head_resp.get("Metadata", {}))
|
|
metadata.update({"status": DocumentAttachmentStatus.READY.value})
|
|
# Update status in metadata
|
|
s3_client.copy_object(
|
|
Bucket=bucket_name,
|
|
CopySource={"Bucket": bucket_name, "Key": file_path},
|
|
Key=file_path,
|
|
ContentType=head_resp.get("ContentType"),
|
|
Metadata=metadata,
|
|
MetadataDirective="REPLACE",
|
|
)
|
|
return
|
|
|
|
document_id = kwargs.get("document_id")
|
|
security_logger.warning(
|
|
"File %s for document %s is infected with malware. Error info: %s",
|
|
file_path,
|
|
document_id,
|
|
error_info,
|
|
)
|
|
|
|
# Remove the file from the document and change the status to unsafe
|
|
document = Document.objects.get(pk=document_id)
|
|
document.attachments.remove(file_path)
|
|
document.save(update_fields=["attachments"])
|
|
|
|
# Delete the file from the storage
|
|
default_storage.delete(file_path)
|