From 60fdd540ab9347757e09ea928f38cb18a56deb29 Mon Sep 17 00:00:00 2001 From: Andrea Stagi Date: Thu, 24 Sep 2015 12:53:08 +0200 Subject: [PATCH 1/3] Add sha1 field --- .../migrations/0005_attachment_sha1.py | 20 ++++++++++++++++ taiga/projects/attachments/models.py | 24 +++++++++++++++++-- taiga/projects/attachments/serializers.py | 6 ++--- 3 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 taiga/projects/attachments/migrations/0005_attachment_sha1.py diff --git a/taiga/projects/attachments/migrations/0005_attachment_sha1.py b/taiga/projects/attachments/migrations/0005_attachment_sha1.py new file mode 100644 index 00000000..c67043e1 --- /dev/null +++ b/taiga/projects/attachments/migrations/0005_attachment_sha1.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('attachments', '0004_auto_20150508_1141'), + ] + + operations = [ + migrations.AddField( + model_name='attachment', + name='sha1', + field=models.CharField(default='', verbose_name='sha1', max_length=40, blank=True), + preserve_default=True, + ), + ] \ No newline at end of file diff --git a/taiga/projects/attachments/models.py b/taiga/projects/attachments/models.py index 61c590e4..30fa5c22 100644 --- a/taiga/projects/attachments/models.py +++ b/taiga/projects/attachments/models.py @@ -68,6 +68,7 @@ class Attachment(models.Model): upload_to=get_attachment_file_path, verbose_name=_("attached file")) + sha1 = models.CharField(default="", max_length=40, verbose_name=_("sha1"), blank=True) is_deprecated = models.BooleanField(default=False, verbose_name=_("is deprecated")) description = models.TextField(null=False, blank=True, verbose_name=_("description")) @@ -83,11 +84,30 @@ class Attachment(models.Model): ("view_attachment", "Can view attachment"), ) + def __init__(self, *args, **kwargs): + super(Attachment, self).__init__(*args, **kwargs) + self._orig_attached_file = self.attached_file + + def _generate_sha1(self, blocksize=65536): + hasher = hashlib.sha1() + while True: + buff = self.attached_file.file.read(blocksize) + if not buff: + break + hasher.update(buff) + self.sha1 = hasher.hexdigest() + def save(self, *args, **kwargs): if not self._importing or not self.modified_date: self.modified_date = timezone.now() - - return super().save(*args, **kwargs) + if self.attached_file: + if not self.sha1 or self.attached_file != self._orig_attached_file: + self._generate_sha1() + save = super().save(*args, **kwargs) + self._orig_attached_file = self.attached_file + if self.attached_file: + self.attached_file.file.close() + return save def __str__(self): return "Attachment: {}".format(self.id) diff --git a/taiga/projects/attachments/serializers.py b/taiga/projects/attachments/serializers.py index 878b0e3c..f255fa8e 100644 --- a/taiga/projects/attachments/serializers.py +++ b/taiga/projects/attachments/serializers.py @@ -34,8 +34,8 @@ class AttachmentSerializer(serializers.ModelSerializer): model = models.Attachment fields = ("id", "project", "owner", "name", "attached_file", "size", "url", "description", "is_deprecated", "created_date", "modified_date", - "object_id", "order") - read_only_fields = ("owner", "created_date", "modified_date") + "object_id", "order", "sha1") + read_only_fields = ("owner", "created_date", "modified_date", "sha1") def get_url(self, obj): - return obj.attached_file.url + return obj.attached_file.url \ No newline at end of file From 9f47e5f396188c89088856168bda39454923bd41 Mon Sep 17 00:00:00 2001 From: Andrea Stagi Date: Thu, 24 Sep 2015 12:54:18 +0200 Subject: [PATCH 2/3] Add generate_sha1 command --- .../attachments/management/commands/__init__.py | 0 .../attachments/management/commands/generate_sha1.py | 12 ++++++++++++ 2 files changed, 12 insertions(+) create mode 100644 taiga/projects/attachments/management/commands/__init__.py create mode 100644 taiga/projects/attachments/management/commands/generate_sha1.py diff --git a/taiga/projects/attachments/management/commands/__init__.py b/taiga/projects/attachments/management/commands/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/taiga/projects/attachments/management/commands/generate_sha1.py b/taiga/projects/attachments/management/commands/generate_sha1.py new file mode 100644 index 00000000..d982681c --- /dev/null +++ b/taiga/projects/attachments/management/commands/generate_sha1.py @@ -0,0 +1,12 @@ +from django.core.management.base import BaseCommand, CommandError +from django.db import transaction + +from taiga.projects.attachments.models import Attachment + + +class Command(BaseCommand): + + @transaction.atomic + def handle(self, *args, **options): + for attachment in Attachment.objects.all(): + attachment.save() From 5e8c6c5fc1174c93e3603c28d64d18d1edd6d9af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Barrag=C3=A1n=20Merino?= Date: Fri, 25 Sep 2015 18:52:44 +0200 Subject: [PATCH 3/3] Update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f625aa5c..60a77eaf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ - Add externall apps: now Taiga can integrate with hundreds of applications and service. - Improve searching system, now full text searchs are supported - Improve export system, now is more efficient and prevents possible crashes with heavy projects. +- Add sha1 hash to attachments to verify the integrity of files (thanks to [@astagi](https://github.com/astagi)). - i18n. - Add italian (it) translation. - Add polish (pl) translation.