示例#1
0
    def test_not_secure_token(self, p_urllib2, p_logging):
        def mocked_urlopen(request):
            return StringIO("""
            <?xml version="1.0"?>
            <Response>
              <Message>Error</Message>
              <MessageCode>7.5</MessageCode>
              <Errors>
                <Error>
                  <ErrorCode>8.1</ErrorCode>
                  <ErrorName>Short URL is not protected</ErrorName>
                  <Description>bla bla</Description>
                  <Suggestion>ble ble</Suggestion>
                </Error>
              </Errors>
            </Response>
            """)
        p_urllib2.urlopen = mocked_urlopen
        eq_(vidly.tokenize('abc123', 60), '')

        # do it a second time and it should be cached
        def mocked_urlopen_different(request):
            return StringIO("""
            Anything different
            """)
        p_urllib2.urlopen = mocked_urlopen_different
        eq_(vidly.tokenize('abc123', 60), '')
示例#2
0
    def test_secure_token(self, p_urllib2):

        event = Event.objects.get(title='Test event')
        submission = VidlySubmission.objects.create(event=event, tag='xyz123')

        tokenize_calls = []  # globally scope mutable

        def mocked_urlopen(request):
            tokenize_calls.append(1)
            return StringIO("""
            <?xml version="1.0"?>
            <Response>
              <Message>OK</Message>
              <MessageCode>7.4</MessageCode>
              <Success>
                <MediaShortLink>8r9e0o</MediaShortLink>
                <Token>MXCsxINnVtycv6j02ZVIlS4FcWP</Token>
              </Success>
            </Response>
            """)

        p_urllib2.urlopen = mocked_urlopen
        eq_(vidly.tokenize(submission.tag, 60), 'MXCsxINnVtycv6j02ZVIlS4FcWP')
        eq_(len(tokenize_calls), 1)
        # do it a second time
        eq_(vidly.tokenize(submission.tag, 60), 'MXCsxINnVtycv6j02ZVIlS4FcWP')
        eq_(len(tokenize_calls), 1)  # caching for the win!

        submission.token_protection = True
        submission.save()

        eq_(vidly.tokenize(submission.tag, 60), 'MXCsxINnVtycv6j02ZVIlS4FcWP')
        eq_(len(tokenize_calls), 2)  # cache got invalidated
示例#3
0
    def test_secure_token(self, p_urllib2):

        event = Event.objects.get(title="Test event")
        submission = VidlySubmission.objects.create(event=event, tag="xyz123")

        tokenize_calls = []  # globally scope mutable

        def mocked_urlopen(request):
            tokenize_calls.append(1)
            return StringIO(
                """
            <?xml version="1.0"?>
            <Response>
              <Message>OK</Message>
              <MessageCode>7.4</MessageCode>
              <Success>
                <MediaShortLink>8r9e0o</MediaShortLink>
                <Token>MXCsxINnVtycv6j02ZVIlS4FcWP</Token>
              </Success>
            </Response>
            """
            )

        p_urllib2.urlopen = mocked_urlopen
        eq_(vidly.tokenize(submission.tag, 60), "MXCsxINnVtycv6j02ZVIlS4FcWP")
        eq_(len(tokenize_calls), 1)
        # do it a second time
        eq_(vidly.tokenize(submission.tag, 60), "MXCsxINnVtycv6j02ZVIlS4FcWP")
        eq_(len(tokenize_calls), 1)  # caching for the win!

        submission.token_protection = True
        submission.save()

        eq_(vidly.tokenize(submission.tag, 60), "MXCsxINnVtycv6j02ZVIlS4FcWP")
        eq_(len(tokenize_calls), 2)  # cache got invalidated
示例#4
0
    def _set_csp_update(self, response, event):
        """Hack alert!
        We need to, potentially, update the CSP at run time if the
        video you're trying to watch is a Vid.ly video.
        Vid.ly is embedded by simply using `https://vid.ly/:shortcode`
        but internally they will redirect to a AWS CloudFront domain
        which we might not have prepared in our CSP settings.
        So let's update that on the fly.
        """
        cache_key = 'custom_csp_update:{}'.format(event.id)
        update = cache.get(cache_key)
        if update is not None:
            # it was set, use that and exit early
            if update:
                response._csp_update = update
            return

        if not event.template:
            return
        if event.is_upcoming() or event.is_live():
            return
        if 'vid.ly' not in event.template.name.lower():
            return
        if not event.template_environment.get('tag'):
            return

        token = None
        if not event.is_public():
            token = vidly.tokenize(event.template_environment['tag'], 90)

        update = {}
        webm_url = 'https://vid.ly/{}?content=video&format=webm'.format(
            event.template_environment['tag'])
        if token:
            webm_url += '&token={}'.format(token)
        head_response = requests.head(webm_url)
        if head_response.status_code == 302:
            update['media-src'] = urlparse.urlparse(
                head_response.headers['Location']).netloc

        poster_url = 'https://vid.ly/{}/poster'.format(
            event.template_environment['tag'])
        if token:
            poster_url += '?token={}'.format(token)
        head_response = requests.head(poster_url)
        if head_response.status_code == 302:
            update['img-src'] = urlparse.urlparse(
                head_response.headers['Location']).netloc

        cache.set(cache_key, update, 60)
        # Now we've figured out what headers to update, set it on the response
        if update:
            response._csp_update = update
示例#5
0
def get_vidly_csp_headers(tag, private=False):
    token = None
    if private:
        token = vidly.tokenize(tag, 90)

    headers = {}

    def get_netloc(type_, url_format):
        netloc = None
        try:
            found = VidlyTagDomain.objects.get(
                tag=tag,
                type=type_,
            )
            if found.private != private:
                # The tag has changed!
                found.delete()
                raise VidlyTagDomain.DoesNotExist
            else:
                netloc = found.domain
        except VidlyTagDomain.DoesNotExist:
            url = url_format.format(
                tag
            )
            if token:
                url += '&token={}'.format(token)
            head_response = requests.head(url)
            if head_response.status_code == 302:
                netloc = urlparse.urlparse(
                    head_response.headers['Location']
                ).netloc
                assert netloc, head_response.headers['Location']
                VidlyTagDomain.objects.create(
                    tag=tag,
                    type=type_,
                    private=private,
                    domain=netloc,
                )
        return netloc

    media_netloc = get_netloc('webm', settings.VIDLY_VIDEO_URL_FORMAT)
    if media_netloc:
        headers['media-src'] = media_netloc

    img_netloc = get_netloc('poster', settings.VIDLY_POSTER_URL_FORMAT)
    if img_netloc:
        headers['img-src'] = img_netloc

    return headers
示例#6
0
 def test_secure_token(self, p_urllib2, p_logging):
     def mocked_urlopen(request):
         return StringIO("""
         <?xml version="1.0"?>
         <Response>
           <Message>OK</Message>
           <MessageCode>7.4</MessageCode>
           <Success>
             <MediaShortLink>8r9e0o</MediaShortLink>
             <Token>MXCsxINnVtycv6j02ZVIlS4FcWP</Token>
           </Success>
         </Response>
         """)
     p_urllib2.urlopen = mocked_urlopen
     eq_(vidly.tokenize('xyz123', 60),
         'MXCsxINnVtycv6j02ZVIlS4FcWP')
示例#7
0
def get_vidly_csp_headers(tag, private=False):
    token = None
    if private:
        token = vidly.tokenize(tag, 90)

    headers = {}

    def get_netloc(type_, url_format):
        netloc = None
        try:
            found = VidlyTagDomain.objects.get(
                tag=tag,
                type=type_,
            )
            if found.private != private:
                # The tag has changed!
                found.delete()
                raise VidlyTagDomain.DoesNotExist
            else:
                netloc = found.domain
        except VidlyTagDomain.DoesNotExist:
            url = url_format.format(tag)
            if token:
                url += '&token={}'.format(token)
            head_response = requests.head(url)
            if head_response.status_code == 302:
                netloc = urlparse.urlparse(
                    head_response.headers['Location']).netloc
                assert netloc, head_response.headers['Location']
                VidlyTagDomain.objects.create(
                    tag=tag,
                    type=type_,
                    private=private,
                    domain=netloc,
                )
        return netloc

    media_netloc = get_netloc('webm', settings.VIDLY_VIDEO_URL_FORMAT)
    if media_netloc:
        headers['media-src'] = media_netloc

    img_netloc = get_netloc('poster', settings.VIDLY_POSTER_URL_FORMAT)
    if img_netloc:
        headers['img-src'] = img_netloc

    return headers
示例#8
0
 def test_invalid_response_token(self, p_urllib2, p_logging):
     def mocked_urlopen(request):
         return StringIO("""
         <?xml version="1.0"?>
         <Response>
           <Message>Error</Message>
           <MessageCode>99</MessageCode>
           <Errors>
             <Error>
               <ErrorCode>0.0</ErrorCode>
               <ErrorName>Some other error</ErrorName>
               <Description>bla bla</Description>
               <Suggestion>ble ble</Suggestion>
             </Error>
           </Errors>
         </Response>
         """)
     p_urllib2.urlopen = mocked_urlopen
     eq_(vidly.tokenize('def123', 60), None)
     p_logging.error.asert_called_with(
         "Unable fetch token for tag 'abc123'"
     )
示例#9
0
def get_video_url(event, use_https, save_locally, verbose=False):
    if event.upload:
        return event.upload.url, None
    elif event.template and 'Vid.ly' in event.template.name:
        assert event.template_environment.get('tag'), "No Vid.ly tag value"

        token_protected = event.privacy != Event.PRIVACY_PUBLIC
        hd = False
        qs = (VidlySubmission.objects.filter(event=event).filter(
            tag=event.template_environment['tag']))

        for submission in qs.order_by('-submission_time')[:1]:
            hd = submission.hd
            token_protected = submission.token_protection

        tag = event.template_environment['tag']
        video_url = '%s/%s?content=video&format=' % (
            settings.VIDLY_BASE_URL,
            tag,
        )
        if hd:
            video_url += 'hd_mp4'
        else:
            video_url += 'mp4'

        if token_protected:
            video_url += '&token=%s' % vidly.tokenize(tag, 60)
    elif event.template and 'Ogg Video' in event.template.name:
        assert event.template_environment.get('url'), "No Ogg Video url value"
        video_url = event.template_environment['url']
    elif event.template and 'YouTube' in event.template.name:
        assert event.template_environment.get('id'), "No YouTube ID value"
        video_url = 'https://www.youtube.com/watch?v={}'.format(
            event.template_environment['id'])
        return video_url, None
    else:
        raise AssertionError("Not valid template")

    response = requests.head(video_url)
    _count = 0
    while response.status_code in (302, 301):
        video_url = response.headers['Location']
        response = requests.head(video_url)
        _count += 1
        if _count > 5:
            # just too many times
            break

    response = requests.head(video_url)
    assert response.status_code == 200, response.status_code
    if verbose:  # pragma: no cover
        if response.headers.get('Content-Length'):
            print("Content-Length: %s" %
                  (filesizeformat(int(response.headers['Content-Length'])), ))

    if not use_https:
        video_url = video_url.replace('https://', 'http://')

    if save_locally:
        # store it in a temporary location
        dir_ = tempfile.mkdtemp('videoinfo')
        if 'Vid.ly' in event.template.name:
            filepath = os.path.join(dir_, '%s.mp4' % tag)
        else:
            filepath = os.path.join(
                dir_, os.path.basename(urlparse.urlparse(video_url).path))
        t0 = time.time()
        _download_file(video_url, filepath)
        t1 = time.time()
        if verbose:  # pragma: no cover
            seconds = int(t1 - t0)
            print "Took", show_duration(seconds, include_seconds=True),
            print "to download"
        video_url = filepath
    else:
        filepath = None

    return video_url, filepath
示例#10
0
def _get_video_url(event, use_https, save_locally, verbose=False):
    if event.template and 'Vid.ly' in event.template.name:
        assert event.template_environment.get('tag'), "No Vid.ly tag value"

        token_protected = event.privacy != Event.PRIVACY_PUBLIC
        hd = False
        qs = (
            VidlySubmission.objects
            .filter(event=event)
            .filter(tag=event.template_environment['tag'])
        )

        for submission in qs.order_by('-submission_time')[:1]:
            hd = submission.hd
            token_protected = submission.token_protection

        tag = event.template_environment['tag']
        video_url = '%s/%s?content=video&format=' % (
            settings.VIDLY_BASE_URL,
            tag,
        )
        if hd:
            video_url += 'hd_mp4'
        else:
            video_url += 'mp4'

        if token_protected:
            video_url += '&token=%s' % vidly.tokenize(tag, 60)
    elif event.template and 'Ogg Video' in event.template.name:
        assert event.template_environment.get('url'), "No Ogg Video url value"
        video_url = event.template_environment['url']
    else:
        raise AssertionError("Not valid template")

    response = requests.head(video_url)
    _count = 0
    while response.status_code in (302, 301):
        video_url = response.headers['Location']
        response = requests.head(video_url)
        _count += 1
        if _count > 5:
            # just too many times
            break

    response = requests.head(video_url)
    assert response.status_code == 200, response.status_code
    if verbose:  # pragma: no cover
        if response.headers.get('Content-Length'):
            print (
                "Content-Length: %s" % (
                    filesizeformat(int(response.headers['Content-Length'])),
                )
            )

    if not use_https:
        video_url = video_url.replace('https://', 'http://')

    if save_locally:
        # store it in a temporary location
        dir_ = tempfile.mkdtemp('videoinfo')
        if 'Vid.ly' in event.template.name:
            filepath = os.path.join(dir_, '%s.mp4' % tag)
        else:
            filepath = os.path.join(
                dir_,
                os.path.basename(urlparse.urlparse(video_url).path)
            )
        t0 = time.time()
        _download_file(video_url, filepath)
        t1 = time.time()
        if verbose:  # pragma: no cover
            seconds = int(t1 - t0)
            print "Took", show_duration(seconds, include_seconds=True),
            print "to download"
        video_url = filepath
    else:
        filepath = None

    return video_url, filepath
示例#11
0
def get_vidly_csp_headers(tag, private=False):
    token = None
    if private:
        token = vidly.tokenize(tag, 90)

    headers = {}

    def get_netloc(type_, url_format):
        netloc = None
        try:
            found = VidlyTagDomain.objects.get(
                tag=tag,
                type=type_,
            )
            if found.private != private:
                # The tag has changed!
                found.delete()
                raise VidlyTagDomain.DoesNotExist
            elif found.domain == 'm.vid.ly':  # pragma: no cover
                # In a previous life, airmozilla might have attempted to
                # look up what the CDN domain was and if it failed,
                # Vid.ly would just redirect to 'https://m.vid.ly' which
                # is NOT the right CDN domain. We shouldn't have stored
                # that.
                # This knowledge was added in June 2017 and from now on
                # we never save this as the domain so it should cease.
                found.delete()
                raise VidlyTagDomain.DoesNotExist
            else:
                netloc = found.domain
        except VidlyTagDomain.DoesNotExist:
            url = url_format.format(tag)
            if token:
                url += '&token={}'.format(token)
            head_response = requests.head(url)
            if head_response.status_code == 302:
                if head_response.headers['Location'] == 'https://m.vid.ly':
                    # Basically, it didn't work.
                    # When vid.ly can't redirect to the actual file, for
                    # some reason it instead redirects to the exact
                    # URL 'https://m.vid.ly'. For example:
                    #
                    #   curl -v https://vid.ly/l1c2w5/blalbla
                    #   ...
                    #   < HTTP/1.1 302 Found
                    #   ...
                    #   < Location: https://m.vid.ly
                    #
                    # Odd right? But it basically means to use that we
                    # we not able to do the lookup. Sorry.
                    return
                netloc = urlparse.urlparse(
                    head_response.headers['Location']).netloc
                assert netloc, head_response.headers['Location']

                VidlyTagDomain.objects.create(
                    tag=tag,
                    type=type_,
                    private=private,
                    domain=netloc,
                )
        return netloc

    media_netloc = get_netloc('webm', settings.VIDLY_VIDEO_URL_FORMAT)
    if media_netloc:
        headers['media-src'] = media_netloc
        # In almost all cases, the poster image is on the same domain
        # as the video. So let's use that.
        # Later we're going to try to do a specific lookup for the poster.
        # If that's better/different that becomes the added domain
        # for 'img-src' instead.
        headers['img-src'] = media_netloc
        # There is no way to pre-lookup what the actual CDN domain is
        # for the webvtt.vtt file is so let's hope for the best and
        # reuse the the domain for media on the connect-src too.
        headers['connect-src'] = media_netloc

    lock_cache_key = 'poster_netloc_failed:{}'.format(tag)
    if not cache.get(lock_cache_key):
        img_netloc = get_netloc('poster', settings.VIDLY_POSTER_URL_FORMAT)
        if img_netloc:
            headers['img-src'] = img_netloc
        else:
            # If that failed, don't bother trying again. For a while.
            cache.set(lock_cache_key, True, 60 * 60)

    return headers
示例#12
0
def fetch_duration(
    event, save=False, save_locally=False, verbose=False, use_https=True,
):
    assert 'Vid.ly' in event.template.name, "Not a Vid.ly template"
    assert event.template_environment.get('tag'), "No Vid.ly tag in template"

    hd = False
    # This is commented out for the time being because we don't need the
    # HD version to just capture the duration.
    # qs = VidlySubmission.objects.filter(event=event)
    # for submission in qs.order_by('-submission_time')[:1]:
    #     hd = submission.hd

    tag = event.template_environment['tag']
    vidly_url = 'https://vid.ly/%s?content=video&format=' % tag
    if hd:
        vidly_url += 'hd_mp4'
    else:
        vidly_url += 'mp4'

    if event.privacy != Event.PRIVACY_PUBLIC:
        vidly_url += '&token=%s' % vidly.tokenize(tag, 60)

    response = requests.head(vidly_url)
    if response.status_code == 302:
        vidly_url = response.headers['Location']

    response = requests.head(vidly_url)
    assert response.status_code == 200, response.status_code
    if verbose:  # pragma: no cover
        if response.headers['Content-Length']:
            print "Content-Length:",
            print filesizeformat(int(response.headers['Content-Length']))

    if not use_https:
        vidly_url = vidly_url.replace('https://', 'http://')

    if save_locally:
        # store it in a temporary location
        dir_ = tempfile.mkdtemp('videoinfo')
        filepath = os.path.join(dir_, '%s.mp4' % tag)
        t0 = time.time()
        _download_file(vidly_url, filepath)
        t1 = time.time()
        if verbose:  # pragma: no cover
            seconds = int(t1 - t0)
            print "Took", show_duration(seconds, include_seconds=True),
            print "to download"
        vidly_url = filepath

    try:
        ffmpeg_location = getattr(
            settings,
            'FFMPEG_LOCATION',
            'ffmpeg'
        )
        command = [
            ffmpeg_location,
            '-i',
            vidly_url,
        ]
        if verbose:  # pragma: no cover
            print ' '.join(command)
        out, err = subprocess.Popen(
            command,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE
        ).communicate()

        matches = REGEX.findall(err)
        if matches:
            found, = matches
            hours = int(found[0])
            minutes = int(found[1])
            minutes += hours * 60
            seconds = int(found[2])
            seconds += minutes * 60
            if save:
                event.duration = seconds
                event.save()
            return seconds
        elif verbose:  # pragma: no cover
            print "No Duration output. Error:"
            print err
    finally:
        if save_locally:
            if os.path.isfile(filepath):
                shutil.rmtree(os.path.dirname(filepath))
示例#13
0
def get_vidly_csp_headers(tag, private=False):
    token = None
    if private:
        token = vidly.tokenize(tag, 90)

    headers = {}

    def get_netloc(type_, url_format):
        netloc = None
        try:
            found = VidlyTagDomain.objects.get(
                tag=tag,
                type=type_,
            )
            if found.private != private:
                # The tag has changed!
                found.delete()
                raise VidlyTagDomain.DoesNotExist
            elif found.domain == 'm.vid.ly':  # pragma: no cover
                # In a previous life, airmozilla might have attempted to
                # look up what the CDN domain was and if it failed,
                # Vid.ly would just redirect to 'https://m.vid.ly' which
                # is NOT the right CDN domain. We shouldn't have stored
                # that.
                # This knowledge was added in June 2017 and from now on
                # we never save this as the domain so it should cease.
                found.delete()
                raise VidlyTagDomain.DoesNotExist
            else:
                netloc = found.domain
        except VidlyTagDomain.DoesNotExist:
            url = url_format.format(
                tag
            )
            if token:
                url += '&token={}'.format(token)
            head_response = requests.head(url)
            if head_response.status_code == 302:
                if head_response.headers['Location'] == 'https://m.vid.ly':
                    # Basically, it didn't work.
                    # When vid.ly can't redirect to the actual file, for
                    # some reason it instead redirects to the exact
                    # URL 'https://m.vid.ly'. For example:
                    #
                    #   curl -v https://vid.ly/l1c2w5/blalbla
                    #   ...
                    #   < HTTP/1.1 302 Found
                    #   ...
                    #   < Location: https://m.vid.ly
                    #
                    # Odd right? But it basically means to use that we
                    # we not able to do the lookup. Sorry.
                    return
                netloc = urlparse.urlparse(
                    head_response.headers['Location']
                ).netloc
                assert netloc, head_response.headers['Location']

                VidlyTagDomain.objects.create(
                    tag=tag,
                    type=type_,
                    private=private,
                    domain=netloc,
                )
        return netloc

    media_netloc = get_netloc('webm', settings.VIDLY_VIDEO_URL_FORMAT)
    if media_netloc:
        headers['media-src'] = media_netloc
        # In almost all cases, the poster image is on the same domain
        # as the video. So let's use that.
        # Later we're going to try to do a specific lookup for the poster.
        # If that's better/different that becomes the added domain
        # for 'img-src' instead.
        headers['img-src'] = media_netloc
        # There is no way to pre-lookup what the actual CDN domain is
        # for the webvtt.vtt file is so let's hope for the best and
        # reuse the the domain for media on the connect-src too.
        headers['connect-src'] = media_netloc

    lock_cache_key = 'poster_netloc_failed:{}'.format(tag)
    if not cache.get(lock_cache_key):
        img_netloc = get_netloc('poster', settings.VIDLY_POSTER_URL_FORMAT)
        if img_netloc:
            headers['img-src'] = img_netloc
        else:
            # If that failed, don't bother trying again. For a while.
            cache.set(lock_cache_key, True, 60 * 60)

    return headers