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