Browse Source

#405: remakemisagochecksums

Rafał Pitoń 10 years ago
parent
commit
e4420e30a3

+ 16 - 5
misago/acl/models.py

@@ -1,8 +1,10 @@
 from django.db import models
 from django.db import models
+from django.dispatch import receiver
 
 
 from misago.core import serializer
 from misago.core import serializer
 
 
 from misago.acl import version as acl_version
 from misago.acl import version as acl_version
+from misago.core.signals import secret_key_changed
 
 
 
 
 class BaseRole(models.Model):
 class BaseRole(models.Model):
@@ -30,11 +32,8 @@ class BaseRole(models.Model):
         try:
         try:
             return self.permissions_cache
             return self.permissions_cache
         except AttributeError:
         except AttributeError:
-            try:
-                self.permissions_cache = serializer.loads(
-                    self.pickled_permissions)
-            except Exception:
-                self.permissions_cache = {}
+            self.permissions_cache = serializer.loads(
+                self.pickled_permissions)
         return self.permissions_cache
         return self.permissions_cache
 
 
     @permissions.setter
     @permissions.setter
@@ -45,3 +44,15 @@ class BaseRole(models.Model):
 
 
 class Role(BaseRole):
 class Role(BaseRole):
     pass
     pass
+
+
+"""
+Signal handlers
+"""
+@receiver(secret_key_changed)
+def update_roles_pickles(sender, **kwargs):
+    for role in Role.objects.iterator():
+        if role.pickled_permissions:
+            role.pickled_permissions = serializer.regenerate_checksum(
+                role.pickled_permissions)
+            role.save(update_fields=['pickled_permissions'])

+ 14 - 0
misago/conf/models.py

@@ -1,6 +1,8 @@
 from django.db import models
 from django.db import models
+from django.dispatch import receiver
 
 
 from misago.core import serializer
 from misago.core import serializer
+from misago.core.signals import secret_key_changed
 
 
 from misago.conf import hydrators
 from misago.conf import hydrators
 
 
@@ -90,3 +92,15 @@ class Setting(models.Model):
     def field_extra(self, new_extra):
     def field_extra(self, new_extra):
         if new_extra:
         if new_extra:
             self.pickled_field_extra = serializer.dumps(new_extra)
             self.pickled_field_extra = serializer.dumps(new_extra)
+
+
+"""
+Signal handlers
+"""
+@receiver(secret_key_changed)
+def update_settings_pickles(sender, **kwargs):
+    for setting in Setting.objects.iterator():
+        if setting.pickled_field_extra:
+            setting.pickled_field_extra = serializer.regenerate_checksum(
+                setting.pickled_field_extra)
+            setting.save(update_fields=['pickled_field_extra'])

+ 21 - 0
misago/core/management/commands/remakemisagochecksums.py

@@ -0,0 +1,21 @@
+from django.core.management.base import BaseCommand
+from django.utils.encoding import force_str
+from django.utils.six.moves import input
+
+from misago.core.signals import secret_key_changed
+
+
+class Command(BaseCommand):
+    help = 'Regenerates Misago checksums after SECRET_KEY changed.'
+
+    def handle(self, *args, **options):
+        message = force_str("This will replace all checksums "
+                            "in database with new ones, marking "
+                            "all data as trusted. Are you sure "
+                            "you wish to continue? [Y/n]")
+        if input(message).strip().lower() == "y":
+            self.stdout.write("\nRegenerating checksums...")
+            secret_key_changed.send(self)
+            self.stdout.write("\nDone!")
+        else:
+            self.stdout.write("\nAborted!")

+ 6 - 0
misago/core/serializer.py

@@ -26,3 +26,9 @@ def dumps(wet):
     base = base64.encodestring(pickle.dumps(wet, pickle.HIGHEST_PROTOCOL))
     base = base64.encodestring(pickle.dumps(wet, pickle.HIGHEST_PROTOCOL))
     checksum = _checksum(base)
     checksum = _checksum(base)
     return '%s%s' % (checksum, base)
     return '%s%s' % (checksum, base)
+
+
+def regenerate_checksum(dry):
+    base = dry[14:]
+    checksum = _checksum(base)
+    return '%s%s' % (checksum, base)

+ 4 - 0
misago/core/signals.py

@@ -0,0 +1,4 @@
+import django.dispatch
+
+
+secret_key_changed = django.dispatch.Signal()

+ 16 - 0
misago/forums/models.py

@@ -1,10 +1,14 @@
 from django.db import models
 from django.db import models
+from django.dispatch import receiver
 from django.utils.translation import ugettext_lazy as _
 from django.utils.translation import ugettext_lazy as _
+
 from mptt.managers import TreeManager
 from mptt.managers import TreeManager
 from mptt.models import MPTTModel, TreeForeignKey
 from mptt.models import MPTTModel, TreeForeignKey
 
 
 from misago.acl import version as acl_version
 from misago.acl import version as acl_version
 from misago.acl.models import BaseRole
 from misago.acl.models import BaseRole
+from misago.core import serializer
+from misago.core.signals import secret_key_changed
 from misago.core.utils import subset_markdown, slugify
 from misago.core.utils import subset_markdown, slugify
 
 
 
 
@@ -89,3 +93,15 @@ class RoleForumACL(models.Model):
     role = models.ForeignKey('misago_acl.Role', related_name='forums_acls')
     role = models.ForeignKey('misago_acl.Role', related_name='forums_acls')
     forum = models.ForeignKey('Forum', related_name='forum_role_set')
     forum = models.ForeignKey('Forum', related_name='forum_role_set')
     forum_role = models.ForeignKey(ForumRole)
     forum_role = models.ForeignKey(ForumRole)
+
+
+"""
+Signal handlers
+"""
+@receiver(secret_key_changed)
+def update_roles_pickles(sender, **kwargs):
+    for role in ForumRole.objects.iterator():
+        if role.pickled_permissions:
+            role.pickled_permissions = serializer.regenerate_checksum(
+                role.pickled_permissions)
+            role.save(update_fields=['pickled_permissions'])

+ 15 - 1
misago/users/models/user.py

@@ -5,6 +5,7 @@ from django.contrib.auth.models import (AbstractBaseUser, PermissionsMixin,
                                         AnonymousUser as DjangoAnonymousUser)
                                         AnonymousUser as DjangoAnonymousUser)
 from django.core.mail import send_mail
 from django.core.mail import send_mail
 from django.db import models, transaction
 from django.db import models, transaction
+from django.dispatch import receiver
 from django.utils import timezone
 from django.utils import timezone
 from django.utils.translation import ugettext_lazy as _
 from django.utils.translation import ugettext_lazy as _
 
 
@@ -12,11 +13,12 @@ from misago.acl import get_user_acl
 from misago.acl.models import Role
 from misago.acl.models import Role
 from misago.conf import settings
 from misago.conf import settings
 from misago.core.utils import slugify
 from misago.core.utils import slugify
+from misago.core.signals import secret_key_changed
 
 
 from misago.users.models.rank import Rank
 from misago.users.models.rank import Rank
 from misago.users import avatars
 from misago.users import avatars
 from misago.users.signals import delete_user_content, username_changed
 from misago.users.signals import delete_user_content, username_changed
-from misago.users.signatures import is_user_signature_valid
+from misago.users.signatures import is_user_signature_valid, make_checksum
 from misago.users.utils import hash_email
 from misago.users.utils import hash_email
 
 
 
 
@@ -425,3 +427,15 @@ class AnonymousUser(DjangoAnonymousUser):
 
 
     def update_acl_key(self):
     def update_acl_key(self):
         raise TypeError("Can't update ACL key on anonymous users")
         raise TypeError("Can't update ACL key on anonymous users")
+
+
+"""
+Signal handlers
+"""
+@receiver(secret_key_changed)
+def update_signatures_checksums(sender, **kwargs):
+    for user in User.objects.iterator():
+        if user.signature:
+            signature_checksum = make_checksum(user.signature_parsed, user)
+            user.signature_checksum = signature_checksum
+            user.save(update_fields=['signature_checksum'])

+ 1 - 1
misago/users/signatures.py

@@ -20,5 +20,5 @@ def is_user_signature_valid(user):
         return False
         return False
 
 
 
 
-def _make_checksum(parsed_signature, user):
+def make_checksum(parsed_signature, user):
     return checksums.make_checksum(parsed_signature, [user.pk])
     return checksums.make_checksum(parsed_signature, [user.pk])