blob: f782f22a58943016f40a2ad5c63df833a40dac6d [file] [log] [blame]
Copybara854996b2021-09-07 19:36:02 +00001# Copyright 2016 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style
3# license that can be found in the LICENSE file or at
4# https://developers.google.com/open-source/licenses/bsd
5
6"""Tests for monorail.tracker.issueattachment."""
7from __future__ import print_function
8from __future__ import division
9from __future__ import absolute_import
10
11import unittest
12
Copybara854996b2021-09-07 19:36:02 +000013from google.appengine.ext import testbed
14
Adrià Vilanova Martínez9f9ade52022-10-10 23:20:11 +020015try:
16 from mox3 import mox
17except ImportError:
18 import mox
Copybara854996b2021-09-07 19:36:02 +000019import webapp2
20
21from framework import gcs_helpers
22from framework import permissions
Copybara854996b2021-09-07 19:36:02 +000023from proto import tracker_pb2
24from services import service_manager
25from testing import fake
26from testing import testing_helpers
27from tracker import attachment_helpers
28from tracker import issueattachment
Copybara854996b2021-09-07 19:36:02 +000029
30
31class IssueattachmentTest(unittest.TestCase):
32
33 def setUp(self):
34 self.mox = mox.Mox()
35 self.testbed = testbed.Testbed()
36 self.testbed.activate()
37 self.testbed.init_memcache_stub()
38 self.testbed.init_app_identity_stub()
39 self.testbed.init_urlfetch_stub()
40 self.attachment_data = ""
41
Copybara854996b2021-09-07 19:36:02 +000042 services = service_manager.Services(
43 project=fake.ProjectService(),
44 config=fake.ConfigService(),
45 issue=fake.IssueService(),
46 user=fake.UserService())
47 self.project = services.project.TestAddProject('proj')
48 self.servlet = issueattachment.AttachmentPage(
49 'req', webapp2.Response(), services=services)
50 services.user.TestAddUser('commenter@example.com', 111)
51 self.issue = fake.MakeTestIssue(
52 self.project.project_id, 1, 'summary', 'New', 111)
53 services.issue.TestAddIssue(self.issue)
54 self.comment = tracker_pb2.IssueComment(
55 id=123, issue_id=self.issue.issue_id,
56 project_id=self.project.project_id, user_id=111,
57 content='this is a comment')
58 services.issue.TestAddComment(self.comment, self.issue.local_id)
59 self.attachment = tracker_pb2.Attachment(
60 attachment_id=54321, filename='hello.txt', filesize=23432,
61 mimetype='text/plain', gcs_object_id='/pid/attachments/object_id')
62 services.issue.TestAddAttachment(
63 self.attachment, self.comment.id, self.issue.issue_id)
64 self.orig_sign_attachment_id = attachment_helpers.SignAttachmentID
65 attachment_helpers.SignAttachmentID = (
66 lambda aid: 'signed_%d' % aid)
67
68 def tearDown(self):
69 self.mox.UnsetStubs()
70 self.mox.ResetAll()
71 self.testbed.deactivate()
Copybara854996b2021-09-07 19:36:02 +000072 attachment_helpers.SignAttachmentID = self.orig_sign_attachment_id
73
74 def testGatherPageData_NotFound(self):
75 aid = 12345
76 path = '/p/proj/issues/attachment?aid=%s&signed_aid=signed_%d' % (
77 aid, aid)
78 # But, no such attachment is in the database.
79 _request, mr = testing_helpers.GetRequestObjects(
80 project=self.project, path=path,
81 perms=permissions.EMPTY_PERMISSIONSET)
82 with self.assertRaises(webapp2.HTTPException) as cm:
83 self.servlet.GatherPageData(mr)
84 self.assertEqual(404, cm.exception.code)
85
86 # TODO(jrobbins): test cases for missing comment and missing issue.
87
88 def testGatherPageData_PermissionDenied(self):
89 aid = self.attachment.attachment_id
90 path = '/p/proj/issues/attachment?aid=%s&signed_aid=signed_%d' % (
91 aid, aid)
92 _request, mr = testing_helpers.GetRequestObjects(
93 project=self.project, path=path,
94 perms=permissions.EMPTY_PERMISSIONSET) # not even VIEW
95 self.assertRaises(
96 permissions.PermissionException,
97 self.servlet.GatherPageData, mr)
98
99 _request, mr = testing_helpers.GetRequestObjects(
100 project=self.project, path=path,
101 perms=permissions.READ_ONLY_PERMISSIONSET) # includes VIEW
102
103 # issue is now deleted
104 self.issue.deleted = True
105 self.assertRaises(
106 permissions.PermissionException,
107 self.servlet.GatherPageData, mr)
108 self.issue.deleted = False
109
110 # issue is now restricted
111 self.issue.labels.extend(['Restrict-View-PermYouLack'])
112 self.assertRaises(
113 permissions.PermissionException,
114 self.servlet.GatherPageData, mr)
115
116 def testGatherPageData_Download_WithDisposition(self):
117 aid = self.attachment.attachment_id
118 self.mox.StubOutWithMock(gcs_helpers, 'MaybeCreateDownload')
119 gcs_helpers.MaybeCreateDownload(
120 'app_default_bucket',
121 '/pid/attachments/object_id',
122 self.attachment.filename).AndReturn(True)
123 self.mox.StubOutWithMock(gcs_helpers, 'SignUrl')
124 gcs_helpers.SignUrl(
125 'app_default_bucket',
126 '/pid/attachments/object_id-download'
127 ).AndReturn('googleusercontent.com/...-download...')
128 self.mox.StubOutWithMock(self.servlet, 'redirect')
129 path = '/p/proj/issues/attachment?aid=%s&signed_aid=signed_%d' % (
130 aid, aid)
131 _request, mr = testing_helpers.GetRequestObjects(
132 project=self.project, path=path,
133 perms=permissions.READ_ONLY_PERMISSIONSET) # includes VIEW
134 self.servlet.redirect(
135 mox.And(mox.StrContains('googleusercontent.com'),
136 mox.StrContains('-download')), abort=True)
137 self.mox.ReplayAll()
138 self.servlet.GatherPageData(mr)
139 self.mox.VerifyAll()
140
141 def testGatherPageData_Download_WithoutDisposition(self):
142 aid = self.attachment.attachment_id
143 path = '/p/proj/issues/attachment?aid=%s&signed_aid=signed_%d' % (
144 aid, aid)
145 self.mox.StubOutWithMock(gcs_helpers, 'MaybeCreateDownload')
146 gcs_helpers.MaybeCreateDownload(
147 'app_default_bucket',
148 '/pid/attachments/object_id',
149 self.attachment.filename).AndReturn(False)
150 self.mox.StubOutWithMock(gcs_helpers, 'SignUrl')
151 gcs_helpers.SignUrl(
152 'app_default_bucket',
153 '/pid/attachments/object_id'
154 ).AndReturn('googleusercontent.com/...')
155 self.mox.StubOutWithMock(self.servlet, 'redirect')
156 _request, mr = testing_helpers.GetRequestObjects(
157 project=self.project, path=path,
158 perms=permissions.READ_ONLY_PERMISSIONSET) # includes VIEW
159 self.servlet.redirect(
160 mox.And(mox.StrContains('googleusercontent.com'),
161 mox.Not(mox.StrContains('-download'))), abort=True)
162 self.mox.ReplayAll()
163 self.servlet.GatherPageData(mr)
164 self.mox.VerifyAll()
165
166 def testGatherPageData_DownloadBadFilename(self):
167 aid = self.attachment.attachment_id
168 path = '/p/proj/issues/attachment?aid=%s&signed_aid=signed_%d' % (
169 aid, aid)
170 self.attachment.filename = '<script>alert("xsrf")</script>.txt';
171 safe_filename = 'attachment-%d.dat' % aid
172 self.mox.StubOutWithMock(gcs_helpers, 'MaybeCreateDownload')
173 gcs_helpers.MaybeCreateDownload(
174 'app_default_bucket',
175 '/pid/attachments/object_id',
176 safe_filename).AndReturn(True)
177 self.mox.StubOutWithMock(gcs_helpers, 'SignUrl')
178 gcs_helpers.SignUrl(
179 'app_default_bucket',
180 '/pid/attachments/object_id-download'
181 ).AndReturn('googleusercontent.com/...-download...')
182 self.mox.StubOutWithMock(self.servlet, 'redirect')
183 _request, mr = testing_helpers.GetRequestObjects(
184 project=self.project,
185 path=path,
186 perms=permissions.READ_ONLY_PERMISSIONSET) # includes VIEW
187 self.servlet.redirect(mox.And(
188 mox.Not(mox.StrContains(self.attachment.filename)),
189 mox.StrContains('googleusercontent.com')), abort=True)
190 self.mox.ReplayAll()
191 self.servlet.GatherPageData(mr)
192 self.mox.VerifyAll()