test_attachments_proxy.py 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. import pytest
  2. from django.urls import reverse
  3. from ...acl.models import Role
  4. from ...acl.test import patch_user_acl
  5. from ...conf import settings
  6. from ...conf.test import override_dynamic_settings
  7. from ..models import Attachment, AttachmentType
  8. from ..test import post_thread
  9. @pytest.fixture
  10. def attachment_type(db):
  11. return AttachmentType.objects.order_by("id").first()
  12. @pytest.fixture
  13. def attachment(attachment_type, post, user):
  14. return Attachment.objects.create(
  15. secret="secret",
  16. filetype=attachment_type,
  17. post=post,
  18. uploader=user,
  19. uploader_name=user.username,
  20. uploader_slug=user.slug,
  21. filename="test.txt",
  22. file="test.txt",
  23. size=1000,
  24. )
  25. @pytest.fixture
  26. def image(post, user):
  27. return Attachment.objects.create(
  28. secret="secret",
  29. filetype=AttachmentType.objects.get(mimetypes="image/png"),
  30. post=post,
  31. uploader=user,
  32. uploader_name=user.username,
  33. uploader_slug=user.slug,
  34. filename="test.png",
  35. image="test.png",
  36. size=1000,
  37. )
  38. @pytest.fixture
  39. def image_with_thumbnail(post, user):
  40. return Attachment.objects.create(
  41. secret="secret",
  42. filetype=AttachmentType.objects.get(mimetypes="image/png"),
  43. post=post,
  44. uploader=user,
  45. uploader_name=user.username,
  46. uploader_slug=user.slug,
  47. filename="test.png",
  48. image="test.png",
  49. thumbnail="test-thumbnail.png",
  50. size=1000,
  51. )
  52. @pytest.fixture
  53. def other_users_attachment(attachment, other_user):
  54. attachment.uploader = other_user
  55. attachment.save()
  56. return attachment
  57. @pytest.fixture
  58. def orphaned_attachment(attachment):
  59. attachment.post = None
  60. attachment.save()
  61. return attachment
  62. @pytest.fixture
  63. def other_users_orphaned_attachment(other_users_attachment):
  64. other_users_attachment.post = None
  65. other_users_attachment.save()
  66. return other_users_attachment
  67. def assert_403(response):
  68. assert response.status_code == 302
  69. assert response["location"].endswith(settings.MISAGO_ATTACHMENT_403_IMAGE)
  70. def assert_404(response):
  71. assert response.status_code == 302
  72. assert response["location"].endswith(settings.MISAGO_ATTACHMENT_404_IMAGE)
  73. def test_proxy_redirects_client_to_attachment_file(client, attachment):
  74. response = client.get(attachment.get_absolute_url())
  75. assert response.status_code == 302
  76. assert response["location"].endswith("test.txt")
  77. def test_proxy_redirects_client_to_attachment_image(client, image):
  78. response = client.get(image.get_absolute_url())
  79. assert response.status_code == 302
  80. assert response["location"].endswith("test.png")
  81. def test_proxy_redirects_client_to_attachment_thumbnail(client, image_with_thumbnail):
  82. response = client.get(image_with_thumbnail.get_thumbnail_url())
  83. assert response.status_code == 302
  84. assert response["location"].endswith("test-thumbnail.png")
  85. def test_proxy_redirects_to_404_image_for_nonexistant_attachment(db, client):
  86. response = client.get(
  87. reverse("misago:attachment", kwargs={"pk": 1, "secret": "secret"})
  88. )
  89. assert_404(response)
  90. def test_proxy_redirects_to_404_image_for_url_with_invalid_attachment_secret(
  91. client, attachment
  92. ):
  93. response = client.get(
  94. reverse("misago:attachment", kwargs={"pk": attachment.id, "secret": "invalid"})
  95. )
  96. assert_404(response)
  97. @patch_user_acl({"can_download_other_users_attachments": False})
  98. def test_proxy_redirects_to_403_image_for_user_without_permission_to_see_attachment(
  99. user_client, other_users_attachment
  100. ):
  101. response = user_client.get(other_users_attachment.get_absolute_url())
  102. assert_403(response)
  103. def test_thumbnail_proxy_redirects_to_404_for_non_image_attachment(client, attachment):
  104. response = client.get(
  105. reverse(
  106. "misago:attachment-thumbnail",
  107. kwargs={"pk": attachment.pk, "secret": attachment.secret},
  108. )
  109. )
  110. assert_404(response)
  111. def test_thumbnail_proxy_redirects_to_regular_image_for_image_without_thumbnail(
  112. client, image
  113. ):
  114. response = client.get(
  115. reverse(
  116. "misago:attachment-thumbnail",
  117. kwargs={"pk": image.pk, "secret": image.secret},
  118. )
  119. )
  120. assert response.status_code == 302
  121. assert response["location"].endswith("test.png")
  122. def test_thumbnail_proxy_redirects_to_thumbnail_image(client, image_with_thumbnail):
  123. response = client.get(
  124. reverse(
  125. "misago:attachment-thumbnail",
  126. kwargs={
  127. "pk": image_with_thumbnail.pk,
  128. "secret": image_with_thumbnail.secret,
  129. },
  130. )
  131. )
  132. assert response.status_code == 302
  133. assert response["location"].endswith("test-thumbnail.png")
  134. def test_proxy_blocks_user_from_their_orphaned_attachment(
  135. user_client, orphaned_attachment
  136. ):
  137. response = user_client.get(orphaned_attachment.get_absolute_url())
  138. assert_404(response)
  139. def test_proxy_redirects_user_to_their_orphaned_attachment_if_link_has_shva_key(
  140. user_client, orphaned_attachment
  141. ):
  142. response = user_client.get("%s?shva=1" % orphaned_attachment.get_absolute_url())
  143. assert response.status_code == 302
  144. assert response["location"].endswith("test.txt")
  145. def test_proxy_blocks_user_from_other_users_orphaned_attachment(
  146. user_client, other_users_orphaned_attachment
  147. ):
  148. response = user_client.get(other_users_orphaned_attachment.get_absolute_url())
  149. assert_404(response)
  150. def test_proxy_blocks_user_from_other_users_orphaned_attachment_if_link_has_shva_key(
  151. user_client, other_users_orphaned_attachment
  152. ):
  153. response = user_client.get(
  154. "%s?shva=1" % other_users_orphaned_attachment.get_absolute_url()
  155. )
  156. assert_404(response)
  157. def test_proxy_redirects_staff_to_other_users_orphaned_attachment(
  158. staff_client, orphaned_attachment
  159. ):
  160. response = staff_client.get("%s?shva=1" % orphaned_attachment.get_absolute_url())
  161. assert response.status_code == 302
  162. assert response["location"].endswith("test.txt")
  163. def test_proxy_blocks_user_from_attachment_with_disabled_type(
  164. user_client, attachment, attachment_type
  165. ):
  166. attachment_type.status = AttachmentType.DISABLED
  167. attachment_type.save()
  168. response = user_client.get(attachment.get_absolute_url())
  169. assert_403(response)
  170. @pytest.fixture
  171. def role(db):
  172. return Role.objects.create(name="Test")
  173. @pytest.fixture
  174. def limited_attachment_type(attachment_type, role):
  175. attachment_type.limit_downloads_to.add(role)
  176. return attachment_type
  177. def test_proxy_blocks_user_without_role_from_attachment_with_limited_type(
  178. user_client, attachment, limited_attachment_type
  179. ):
  180. response = user_client.get(attachment.get_absolute_url())
  181. assert_403(response)
  182. def test_proxy_allows_user_with_role_to_download_attachment_with_limited_type(
  183. user, user_client, role, attachment, limited_attachment_type
  184. ):
  185. user.roles.add(role)
  186. response = user_client.get(attachment.get_absolute_url())
  187. assert response.status_code == 302
  188. assert response["location"].endswith("test.txt")
  189. def test_proxy_allows_staff_user_without_role_to_download_attachment_with_limited_type(
  190. staff_client, role, attachment, limited_attachment_type
  191. ):
  192. response = staff_client.get(attachment.get_absolute_url())
  193. assert response.status_code == 302
  194. assert response["location"].endswith("test.txt")
  195. @override_dynamic_settings(attachment_403_image="custom-403-image.png")
  196. @patch_user_acl({"can_download_other_users_attachments": False})
  197. def test_proxy_uses_custom_permission_denied_image_if_one_is_set(
  198. user_client, other_users_attachment
  199. ):
  200. response = user_client.get(other_users_attachment.get_absolute_url())
  201. assert response.status_code == 302
  202. assert response["location"].endswith("custom-403-image.png")
  203. @override_dynamic_settings(attachment_404_image="custom-404-image.png")
  204. def test_proxy_uses_custom_not_found_image_if_one_is_set(db, client):
  205. response = client.get(
  206. reverse("misago:attachment", kwargs={"pk": 1, "secret": "secret"})
  207. )
  208. assert response.status_code == 302
  209. assert response["location"].endswith("custom-404-image.png")