Exemple #1
0
def test_create_invalid_tdef():
    """
    Test whether creating invalid TorrentDef objects result in ValueErrors
    """
    invalid_metainfo = {}
    with pytest.raises(ValueError):
        TorrentDef.load_from_memory(bencode(invalid_metainfo))

    invalid_metainfo = {b'info': {}}
    with pytest.raises(ValueError):
        TorrentDef.load_from_memory(bencode(invalid_metainfo))
Exemple #2
0
async def test_get_torrentinfo(mock_dlmgr, tmp_path, rest_api, endpoint):
    """
    Testing whether the API returns a correct dictionary with torrent info.
    """
    endpoint.download_manager = mock_dlmgr

    shutil.copyfile(TORRENT_UBUNTU_FILE, tmp_path / 'ubuntu.torrent')

    def verify_valid_dict(json_data):
        metainfo_dict = json.loads(unhexlify(json_data['metainfo']))
        # FIXME: This check is commented out because json.dump garbles pieces binary data during transfer.
        # To fix it, we must switch to some encoding scheme that is able to encode and decode raw binary
        # fields in the dicts.
        # However, for this works fine at the moment because we never use pieces data in the GUI.
        # assert TorrentDef.load_from_dict(metainfo_dict)
        assert 'info' in metainfo_dict

    def path_to_url(path):
        return urllib.request.pathname2url(str(path))

    mock_dlmgr.downloads = {}
    mock_dlmgr.metainfo_requests = {}
    mock_dlmgr.get_channel_downloads = lambda: []
    mock_dlmgr.shutdown = lambda: succeed(None)
    mock_dlmgr.notifier = Mock()

    await do_request(rest_api, 'torrentinfo', expected_code=400)
    await do_request(rest_api, 'torrentinfo?uri=def', expected_code=400)

    path = "file:" + path_to_url(TESTS_DATA_DIR / "bak_single.torrent")
    verify_valid_dict(await do_request(rest_api,
                                       f'torrentinfo?uri={path}',
                                       expected_code=200))

    # Corrupt file
    path = "file:" + path_to_url(TESTS_DATA_DIR / "test_rss.xml")
    await do_request(rest_api, f'torrentinfo?uri={path}', expected_code=500)

    path = "http://localhost:1234/ubuntu.torrent"

    async def mock_http_query(*_):
        with open(tmp_path / "ubuntu.torrent", 'rb') as f:
            return f.read()

    with patch(
            "tribler_core.components.libtorrent.restapi.torrentinfo_endpoint.query_http_uri",
            new=mock_http_query):
        verify_valid_dict(await
                          do_request(rest_api,
                                     f'torrentinfo?uri={quote_plus(path)}',
                                     expected_code=200))

    path = quote_plus(f'magnet:?xt=urn:btih:{hexlify(UBUNTU_1504_INFOHASH)}'
                      f'&dn=test torrent&tr=http://ubuntu.org/ann')

    hops_list = []

    with open(TESTS_DATA_DIR / "ubuntu-15.04-desktop-amd64.iso.torrent",
              mode='rb') as torrent_file:
        torrent_data = torrent_file.read()
        tdef = TorrentDef.load_from_memory(torrent_data)
    metainfo_dict = tdef_to_metadata_dict(
        TorrentDef.load_from_memory(torrent_data))

    def get_metainfo(infohash, timeout=20, hops=None, url=None):
        if hops is not None:
            hops_list.append(hops)
        assert url
        assert url == unquote_plus(path)
        return succeed(tdef.get_metainfo())

    mock_dlmgr.get_metainfo = get_metainfo
    verify_valid_dict(await do_request(rest_api,
                                       f'torrentinfo?uri={path}',
                                       expected_code=200))

    path = 'magnet:?xt=urn:ed2k:354B15E68FB8F36D7CD88FF94116CDC1'  # No infohash
    await do_request(rest_api, f'torrentinfo?uri={path}', expected_code=400)

    path = quote_plus(f"magnet:?xt=urn:btih:{'a' * 40}&dn=test torrent")
    mock_dlmgr.get_metainfo = lambda *_, **__: succeed(None)
    await do_request(rest_api, f'torrentinfo?uri={path}', expected_code=500)

    # Ensure that correct torrent metadata was sent through notifier (to MetadataStore)
    mock_dlmgr.notifier.notify.assert_called_with(
        NTFY.TORRENT_METADATA_ADDED.value, metainfo_dict)

    mock_dlmgr.get_metainfo = get_metainfo
    verify_valid_dict(await do_request(rest_api,
                                       f'torrentinfo?uri={path}',
                                       expected_code=200))

    await do_request(rest_api,
                     f'torrentinfo?uri={path}&hops=0',
                     expected_code=200)
    assert [0] == hops_list

    await do_request(rest_api,
                     f'torrentinfo?uri={path}&hops=foo',
                     expected_code=400)

    path = 'http://fdsafksdlafdslkdksdlfjs9fsafasdf7lkdzz32.n38/324.torrent'
    await do_request(rest_api, f'torrentinfo?uri={path}', expected_code=500)

    mock_download = Mock()
    path = quote_plus(
        f'magnet:?xt=urn:btih:{hexlify(UBUNTU_1504_INFOHASH)}&dn=test torrent')
    mock_dlmgr.downloads = {UBUNTU_1504_INFOHASH: mock_download}
    result = await do_request(rest_api,
                              f'torrentinfo?uri={path}',
                              expected_code=200)
    assert result["download_exists"]

    # Check that we do not return "downloads_exists" if the download is metainfo only download
    mock_dlmgr.downloads = {UBUNTU_1504_INFOHASH: mock_download}
    mock_dlmgr.metainfo_requests = {UBUNTU_1504_INFOHASH: [mock_download]}
    result = await do_request(rest_api,
                              f'torrentinfo?uri={path}',
                              expected_code=200)
    assert not result["download_exists"]

    # Check that we return "downloads_exists" if there is a metainfo download for the infohash,
    # but there is also a regular download for the same infohash
    mock_dlmgr.downloads = {UBUNTU_1504_INFOHASH: mock_download}
    mock_dlmgr.metainfo_requests = {UBUNTU_1504_INFOHASH: [Mock()]}
    result = await do_request(rest_api,
                              f'torrentinfo?uri={path}',
                              expected_code=200)
    assert result["download_exists"]
Exemple #3
0
    async def add_torrent_to_channel(self, request):
        channel_pk, channel_id = self.get_channel_from_request(request)
        with db_session:
            channel = self.mds.CollectionNode.get(public_key=channel_pk, id_=channel_id)
        if not channel:
            return RESTResponse({"error": "Unknown channel"}, status=HTTP_NOT_FOUND)

        parameters = await request.json()

        extra_info = {}
        if parameters.get('description', None):
            extra_info = {'description': parameters['description']}

        # First, check whether we did upload a magnet link or URL
        if parameters.get('uri', None):
            uri = parameters['uri']
            if uri.startswith("http:") or uri.startswith("https:"):
                data = await _fetch_uri(uri)
                tdef = TorrentDef.load_from_memory(data)
            elif uri.startswith("magnet:"):
                _, xt, _ = parse_magnetlink(uri)
                if (
                    xt
                    and is_infohash(codecs.encode(xt, 'hex'))
                    and (self.mds.torrent_exists_in_personal_channel(xt) or channel.copy_torrent_from_infohash(xt))
                ):
                    return RESTResponse({"added": 1})

                meta_info = await self.download_manager.get_metainfo(xt, timeout=30, url=uri)
                if not meta_info:
                    raise RuntimeError("Metainfo timeout")
                tdef = TorrentDef.load_from_dict(meta_info)
            else:
                return RESTResponse({"error": "unknown uri type"}, status=HTTP_BAD_REQUEST)

            added = 0
            if tdef:
                channel.add_torrent_to_channel(tdef, extra_info)
                added = 1
            return RESTResponse({"added": added})

        torrents_dir = None
        if parameters.get('torrents_dir', None):
            torrents_dir = parameters['torrents_dir']
            if not Path(torrents_dir).is_absolute():
                return RESTResponse({"error": "the torrents_dir should point to a directory"}, status=HTTP_BAD_REQUEST)

        recursive = False
        if parameters.get('recursive'):
            recursive = parameters['recursive']
            if not torrents_dir:
                return RESTResponse(
                    {"error": "the torrents_dir parameter should be provided when the recursive parameter is set"},
                    status=HTTP_BAD_REQUEST,
                )

        if torrents_dir:
            torrents_list, errors_list = channel.add_torrents_from_dir(torrents_dir, recursive)
            return RESTResponse({"added": len(torrents_list), "errors": errors_list})

        if not parameters.get('torrent', None):
            return RESTResponse({"error": "torrent parameter missing"}, status=HTTP_BAD_REQUEST)

        # Try to parse the torrent data
        # Any errors will be handled by the error_middleware
        torrent = base64.b64decode(parameters['torrent'])
        torrent_def = TorrentDef.load_from_memory(torrent)
        channel.add_torrent_to_channel(torrent_def, extra_info)
        return RESTResponse({"added": 1})
Exemple #4
0
async def test_get_torrentinfo(tmp_path, rest_api,
                               endpoint: TorrentInfoEndpoint):
    """
    Testing whether the API returns a correct dictionary with torrent info.
    """
    def _path(file):
        return path_to_uri(TESTS_DATA_DIR / file)

    shutil.copyfile(TORRENT_UBUNTU_FILE, tmp_path / 'ubuntu.torrent')

    def verify_valid_dict(json_data):
        metainfo_dict = json.loads(unhexlify(json_data['metainfo']))
        assert 'info' in metainfo_dict

    url = 'torrentinfo'
    await do_request(rest_api, url, expected_code=400)
    await do_request(rest_api, url, params={'uri': 'def'}, expected_code=400)

    response = await do_request(rest_api,
                                url,
                                params={'uri': _path('bak_single.torrent')},
                                expected_code=200)
    verify_valid_dict(response)

    # Corrupt file
    await do_request(rest_api,
                     url,
                     params={'uri': _path('test_rss.xml')},
                     expected_code=500)

    path = "http://localhost:1234/ubuntu.torrent"

    async def mock_http_query(*_):
        with open(tmp_path / "ubuntu.torrent", 'rb') as f:
            return f.read()

    with patch(
            "tribler_core.components.libtorrent.restapi.torrentinfo_endpoint.query_http_uri",
            new=mock_http_query):
        verify_valid_dict(await do_request(rest_api,
                                           url,
                                           params={'uri': path},
                                           expected_code=200))

    path = quote_plus(f'magnet:?xt=urn:btih:{hexlify(UBUNTU_1504_INFOHASH)}'
                      f'&dn=test torrent&tr=http://ubuntu.org/ann')

    hops_list = []

    with open(TESTS_DATA_DIR / "ubuntu-15.04-desktop-amd64.iso.torrent",
              mode='rb') as torrent_file:
        torrent_data = torrent_file.read()
        tdef = TorrentDef.load_from_memory(torrent_data)
    metainfo_dict = tdef_to_metadata_dict(
        TorrentDef.load_from_memory(torrent_data))

    def get_metainfo(infohash, timeout=20, hops=None, url=None):
        if hops is not None:
            hops_list.append(hops)
        assert url
        assert url == unquote_plus(path)
        return succeed(tdef.get_metainfo())

    endpoint.download_manager.get_metainfo = get_metainfo
    verify_valid_dict(await do_request(rest_api,
                                       f'torrentinfo?uri={path}',
                                       expected_code=200))

    path = 'magnet:?xt=urn:ed2k:354B15E68FB8F36D7CD88FF94116CDC1'  # No infohash
    await do_request(rest_api, f'torrentinfo?uri={path}', expected_code=400)

    path = quote_plus(f"magnet:?xt=urn:btih:{'a' * 40}&dn=test torrent")
    endpoint.download_manager.get_metainfo = lambda *_, **__: succeed(None)
    await do_request(rest_api, f'torrentinfo?uri={path}', expected_code=500)

    # Ensure that correct torrent metadata was sent through notifier (to MetadataStore)
    endpoint.download_manager.notifier[
        notifications.torrent_metadata_added].assert_called_with(metainfo_dict)

    endpoint.download_manager.get_metainfo = get_metainfo
    verify_valid_dict(await do_request(rest_api,
                                       f'torrentinfo?uri={path}',
                                       expected_code=200))

    await do_request(rest_api,
                     f'torrentinfo?uri={path}&hops=0',
                     expected_code=200)
    assert [0] == hops_list

    await do_request(rest_api,
                     f'torrentinfo?uri={path}&hops=foo',
                     expected_code=400)

    path = 'http://fdsafksdlafdslkdksdlfjs9fsafasdf7lkdzz32.n38/324.torrent'
    await do_request(rest_api, f'torrentinfo?uri={path}', expected_code=500)

    mock_download = MagicMock()
    path = quote_plus(
        f'magnet:?xt=urn:btih:{hexlify(UBUNTU_1504_INFOHASH)}&dn=test torrent')
    endpoint.download_manager.downloads = {UBUNTU_1504_INFOHASH: mock_download}
    result = await do_request(rest_api,
                              f'torrentinfo?uri={path}',
                              expected_code=200)
    assert result["download_exists"]

    # Check that we do not return "downloads_exists" if the download is metainfo only download
    endpoint.download_manager.downloads = {UBUNTU_1504_INFOHASH: mock_download}
    endpoint.download_manager.metainfo_requests = {
        UBUNTU_1504_INFOHASH: [mock_download]
    }
    result = await do_request(rest_api,
                              f'torrentinfo?uri={path}',
                              expected_code=200)
    assert not result["download_exists"]

    # Check that we return "downloads_exists" if there is a metainfo download for the infohash,
    # but there is also a regular download for the same infohash
    endpoint.download_manager.downloads = {UBUNTU_1504_INFOHASH: mock_download}
    endpoint.download_manager.metainfo_requests = {
        UBUNTU_1504_INFOHASH: [MagicMock()]
    }
    result = await do_request(rest_api,
                              f'torrentinfo?uri={path}',
                              expected_code=200)
    assert result["download_exists"]