blob: 80861828fb5e2e198480dcd335ed0aaf013ba528 [file] [log] [blame]
# Copyright 2016 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Functions to help display attachments and compute quotas."""
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import
import base64
import hashlib
import hmac
import six
from framework import urls
from services import secrets_svc
from tracker import tracker_helpers
VIEWABLE_IMAGE_TYPES = [
'image/jpeg', 'image/gif', 'image/png', 'image/x-png', 'image/webp',
]
VIEWABLE_VIDEO_TYPES = [
'video/ogg', 'video/mp4', 'video/mpg', 'video/mpeg', 'video/webm',
'video/quicktime',
]
MAX_PREVIEW_FILESIZE = 15 * 1024 * 1024 # 15 MB
def IsViewableImage(mimetype_charset, filesize):
"""Return true if we can safely display such an image in the browser.
Args:
mimetype_charset: string with the mimetype string that we got back
from the 'file' command. It may have just the mimetype, or it
may have 'foo/bar; charset=baz'.
filesize: int length of the file in bytes.
Returns:
True iff we should allow the user to view a thumbnail or safe version
of the image in the browser. False if this might not be safe to view,
in which case we only offer a download link.
"""
mimetype = mimetype_charset.split(';', 1)[0]
return (mimetype in VIEWABLE_IMAGE_TYPES and
filesize < MAX_PREVIEW_FILESIZE)
def IsViewableVideo(mimetype_charset, filesize):
"""Return true if we can safely display such a video in the browser.
Args:
mimetype_charset: string with the mimetype string that we got back
from the 'file' command. It may have just the mimetype, or it
may have 'foo/bar; charset=baz'.
filesize: int length of the file in bytes.
Returns:
True iff we should allow the user to watch the video in the page.
"""
mimetype = mimetype_charset.split(';', 1)[0]
return (mimetype in VIEWABLE_VIDEO_TYPES and
filesize < MAX_PREVIEW_FILESIZE)
def IsViewableText(mimetype, filesize):
"""Return true if we can safely display such a file as escaped text."""
return (mimetype.startswith('text/') and
filesize < MAX_PREVIEW_FILESIZE)
def SignAttachmentID(aid):
"""One-way hash of attachment ID to make it harder for people to scan."""
digester = hmac.new(secrets_svc.GetXSRFKey(), digestmod=hashlib.md5)
digester.update(six.ensure_binary(str(aid)))
return six.ensure_str(base64.urlsafe_b64encode(digester.digest()))
def GetDownloadURL(attachment_id):
"""Return a relative URL to download an attachment to local disk."""
return 'attachment?aid=%s&signed_aid=%s' % (
attachment_id, SignAttachmentID(attachment_id))
def GetViewURL(attach, download_url, project_name):
"""Return a relative URL to view an attachment in the browser."""
if IsViewableImage(attach.mimetype, attach.filesize):
return download_url + '&inline=1'
elif IsViewableVideo(attach.mimetype, attach.filesize):
return download_url + '&inline=1'
elif IsViewableText(attach.mimetype, attach.filesize):
return tracker_helpers.FormatRelativeIssueURL(
project_name, urls.ISSUE_ATTACHMENT_TEXT,
aid=attach.attachment_id)
else:
return None
def GetThumbnailURL(attach, download_url):
"""Return a relative URL to view an attachment thumbnail."""
if IsViewableImage(attach.mimetype, attach.filesize):
return download_url + '&inline=1&thumb=1'
else:
return None
def GetVideoURL(attach, download_url):
"""Return a relative URL to view an attachment thumbnail."""
if IsViewableVideo(attach.mimetype, attach.filesize):
return download_url + '&inline=1'
else:
return None