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