Adrià Vilanova Martínez | f19ea43 | 2024-01-23 20:20:52 +0100 | [diff] [blame] | 1 | # Copyright 2016 The Chromium Authors |
| 2 | # Use of this source code is governed by a BSD-style license that can be |
| 3 | # found in the LICENSE file. |
Copybara | 854996b | 2021-09-07 19:36:02 +0000 | [diff] [blame] | 4 | |
| 5 | """Functions to help display attachments and compute quotas.""" |
| 6 | from __future__ import print_function |
| 7 | from __future__ import division |
| 8 | from __future__ import absolute_import |
| 9 | |
| 10 | import base64 |
Adrià Vilanova Martínez | f19ea43 | 2024-01-23 20:20:52 +0100 | [diff] [blame] | 11 | import hashlib |
Copybara | 854996b | 2021-09-07 19:36:02 +0000 | [diff] [blame] | 12 | import hmac |
Adrià Vilanova Martínez | f19ea43 | 2024-01-23 20:20:52 +0100 | [diff] [blame] | 13 | import six |
Copybara | 854996b | 2021-09-07 19:36:02 +0000 | [diff] [blame] | 14 | |
| 15 | from framework import urls |
| 16 | from services import secrets_svc |
| 17 | from tracker import tracker_helpers |
| 18 | |
| 19 | |
| 20 | VIEWABLE_IMAGE_TYPES = [ |
| 21 | 'image/jpeg', 'image/gif', 'image/png', 'image/x-png', 'image/webp', |
| 22 | ] |
| 23 | VIEWABLE_VIDEO_TYPES = [ |
| 24 | 'video/ogg', 'video/mp4', 'video/mpg', 'video/mpeg', 'video/webm', |
| 25 | 'video/quicktime', |
| 26 | ] |
| 27 | MAX_PREVIEW_FILESIZE = 15 * 1024 * 1024 # 15 MB |
| 28 | |
| 29 | |
| 30 | def IsViewableImage(mimetype_charset, filesize): |
| 31 | """Return true if we can safely display such an image in the browser. |
| 32 | |
| 33 | Args: |
| 34 | mimetype_charset: string with the mimetype string that we got back |
| 35 | from the 'file' command. It may have just the mimetype, or it |
| 36 | may have 'foo/bar; charset=baz'. |
| 37 | filesize: int length of the file in bytes. |
| 38 | |
| 39 | Returns: |
| 40 | True iff we should allow the user to view a thumbnail or safe version |
| 41 | of the image in the browser. False if this might not be safe to view, |
| 42 | in which case we only offer a download link. |
| 43 | """ |
| 44 | mimetype = mimetype_charset.split(';', 1)[0] |
| 45 | return (mimetype in VIEWABLE_IMAGE_TYPES and |
| 46 | filesize < MAX_PREVIEW_FILESIZE) |
| 47 | |
| 48 | |
| 49 | def IsViewableVideo(mimetype_charset, filesize): |
| 50 | """Return true if we can safely display such a video in the browser. |
| 51 | |
| 52 | Args: |
| 53 | mimetype_charset: string with the mimetype string that we got back |
| 54 | from the 'file' command. It may have just the mimetype, or it |
| 55 | may have 'foo/bar; charset=baz'. |
| 56 | filesize: int length of the file in bytes. |
| 57 | |
| 58 | Returns: |
| 59 | True iff we should allow the user to watch the video in the page. |
| 60 | """ |
| 61 | mimetype = mimetype_charset.split(';', 1)[0] |
| 62 | return (mimetype in VIEWABLE_VIDEO_TYPES and |
| 63 | filesize < MAX_PREVIEW_FILESIZE) |
| 64 | |
| 65 | |
| 66 | def IsViewableText(mimetype, filesize): |
| 67 | """Return true if we can safely display such a file as escaped text.""" |
| 68 | return (mimetype.startswith('text/') and |
| 69 | filesize < MAX_PREVIEW_FILESIZE) |
| 70 | |
| 71 | |
| 72 | def SignAttachmentID(aid): |
| 73 | """One-way hash of attachment ID to make it harder for people to scan.""" |
Adrià Vilanova Martínez | f19ea43 | 2024-01-23 20:20:52 +0100 | [diff] [blame] | 74 | digester = hmac.new(secrets_svc.GetXSRFKey(), digestmod=hashlib.md5) |
| 75 | digester.update(six.ensure_binary(str(aid))) |
| 76 | return six.ensure_str(base64.urlsafe_b64encode(digester.digest())) |
Copybara | 854996b | 2021-09-07 19:36:02 +0000 | [diff] [blame] | 77 | |
| 78 | |
| 79 | def GetDownloadURL(attachment_id): |
| 80 | """Return a relative URL to download an attachment to local disk.""" |
| 81 | return 'attachment?aid=%s&signed_aid=%s' % ( |
| 82 | attachment_id, SignAttachmentID(attachment_id)) |
| 83 | |
| 84 | |
| 85 | def GetViewURL(attach, download_url, project_name): |
| 86 | """Return a relative URL to view an attachment in the browser.""" |
| 87 | if IsViewableImage(attach.mimetype, attach.filesize): |
| 88 | return download_url + '&inline=1' |
| 89 | elif IsViewableVideo(attach.mimetype, attach.filesize): |
| 90 | return download_url + '&inline=1' |
| 91 | elif IsViewableText(attach.mimetype, attach.filesize): |
| 92 | return tracker_helpers.FormatRelativeIssueURL( |
| 93 | project_name, urls.ISSUE_ATTACHMENT_TEXT, |
| 94 | aid=attach.attachment_id) |
| 95 | else: |
| 96 | return None |
| 97 | |
| 98 | |
| 99 | def GetThumbnailURL(attach, download_url): |
| 100 | """Return a relative URL to view an attachment thumbnail.""" |
| 101 | if IsViewableImage(attach.mimetype, attach.filesize): |
| 102 | return download_url + '&inline=1&thumb=1' |
| 103 | else: |
| 104 | return None |
| 105 | |
| 106 | |
| 107 | def GetVideoURL(attach, download_url): |
| 108 | """Return a relative URL to view an attachment thumbnail.""" |
| 109 | if IsViewableVideo(attach.mimetype, attach.filesize): |
| 110 | return download_url + '&inline=1' |
| 111 | else: |
| 112 | return None |