async def test_create_torrent(self):
        """
        Testing whether the API returns a proper base64 encoded torrent
        """
        torrent_path = self.files_path / "video.avi.torrent"
        expected_tdef = TorrentDef.load(torrent_path)
        export_dir = self.temporary_directory()

        post_data = {
            "files": [self.files_path / "video.avi",
                      self.files_path / "video.avi.torrent"],
            "description": "Video of my cat",
            "trackers": "http://localhost/announce",
            "name": "test_torrent",
            "export_dir": export_dir
        }
        response_dict = await self.do_request('createtorrent?download=1', 200, None, 'POST', post_data)
        torrent = base64.b64decode(response_dict["torrent"])
        tdef = TorrentDef.load_from_memory(torrent)

        # Copy expected creation date and created by (Tribler version) from actual result
        creation_date = tdef.get_creation_date()
        expected_tdef.metainfo[b"creation date"] = creation_date
        expected_tdef.metainfo[b"created by"] = tdef.metainfo[b'created by']

        self.assertEqual(dir(expected_tdef), dir(tdef))
        self.assertTrue((export_dir / "test_torrent.torrent").exists())
Example #2
0
def create_fake_download_and_state():
    """
    Create a fake download and state which can be passed to the global download callback.
    """
    tdef = TorrentDef()
    tdef.get_infohash = lambda: b'aaaa'
    fake_peer = {'extended_version': 'Tribler', 'id': 'a' * 20, 'dtotal': 10 * 1024 * 1024}
    fake_download = Mock()
    fake_download.get_def = lambda: tdef
    fake_download.get_def().get_name_as_unicode = lambda: "test.iso"
    fake_download.get_peerlist = lambda: [fake_peer]
    fake_download.hidden = False
    fake_download.checkpoint = lambda: succeed(None)
    fake_download.stop = lambda: succeed(None)
    fake_download.shutdown = lambda: succeed(None)
    dl_state = Mock()
    dl_state.get_infohash = lambda: b'aaaa'
    dl_state.get_status = lambda: DLSTATUS_SEEDING
    dl_state.get_download = lambda: fake_download
    fake_config = Mock()
    fake_config.get_hops = lambda: 0
    fake_config.get_safe_seeding = lambda: True
    fake_download.config = fake_config

    return fake_download, dl_state
Example #3
0
 def test_get_name_utf8(self):
     """
     Check whether we can successfully get the UTF-8 encoded torrent name when using a different encoding
     """
     t = TorrentDef()
     t.set_name(b'\xA1\xC0')
     self.assertEqual(t.get_name_utf8(), u'\xa1\xc0')
Example #4
0
    def test_get_files_with_length(self):
        name_bytes = b'\xe8\xaf\xad\xe8\xa8\x80\xe5\xa4\x84\xe7\x90\x86'
        name_unicode = name_bytes.decode()
        t = TorrentDef()
        t.metainfo = {
            b'info': {
                b'files': [{
                    b'path.utf-8': [name_bytes],
                    b'length': 123
                }, {
                    b'path.utf-8': [b'file.txt'],
                    b'length': 456
                }]
            }
        }
        self.assertEqual(t.get_files_with_length(), [(Path(name_unicode), 123),
                                                     (Path('file.txt'), 456)])

        t.metainfo = {
            b'info': {
                b'files': [{
                    b'path': [name_bytes],
                    b'length': 123
                }, {
                    b'path': [b'file.txt'],
                    b'length': 456
                }]
            }
        }
        self.assertEqual(t.get_files_with_length(), [(Path(name_unicode), 123),
                                                     (Path('file.txt'), 456)])

        t.metainfo = {
            b'info': {
                b'files': [{
                    b'path': [b'test\xff' + name_bytes],
                    b'length': 123
                }, {
                    b'path': [b'file.txt'],
                    b'length': 456
                }]
            }
        }
        self.assertEqual(t.get_files_with_length(),
                         [(Path('test?????????????'), 123),
                          (Path('file.txt'), 456)])

        t.metainfo = {
            b'info': {
                b'files': [{
                    b'path.utf-8': [b'test\xff' + name_bytes],
                    b'length': 123
                }, {
                    b'path': [b'file.txt'],
                    b'length': 456
                }]
            }
        }
        self.assertEqual(t.get_files_with_length(), [(Path('file.txt'), 456)])
Example #5
0
    def test_get_nr_pieces(self):
        """
        Test getting the number of pieces from a TorrentDef
        """
        tdef = TorrentDef()
        self.assertEqual(tdef.get_nr_pieces(), 0)

        tdef.metainfo = {b'info': {b'pieces': b'a' * 40}}
        self.assertEqual(tdef.get_nr_pieces(), 2)
Example #6
0
async def test_load_from_url(file_server, tmpdir):
    shutil.copyfile(TORRENT_UBUNTU_FILE, tmpdir / 'ubuntu.torrent')

    torrent_url = 'http://localhost:%d/ubuntu.torrent' % file_server
    torrent_def = await TorrentDef.load_from_url(torrent_url)
    assert torrent_def.get_metainfo() == TorrentDef.load(
        TORRENT_UBUNTU_FILE).get_metainfo()
    assert torrent_def.infohash == TorrentDef.load(
        TORRENT_UBUNTU_FILE).infohash
Example #7
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))
Example #8
0
def test_is_private():
    """
    Test whether the private field from an existing torrent is correctly read
    """
    privatefn = TESTS_DATA_DIR / "private.torrent"
    publicfn = TESTS_DATA_DIR / "bak_single.torrent"

    t1 = TorrentDef.load(privatefn)
    t2 = TorrentDef.load(publicfn)

    assert t1.is_private()
    assert not t2.is_private()
Example #9
0
    def test_is_private(self):
        """
        Test whether the private field from an existing torrent is correctly read
        """
        privatefn = TESTS_DATA_DIR / "private.torrent"
        publicfn = TESTS_DATA_DIR / "bak_single.torrent"

        t1 = TorrentDef.load(privatefn)
        t2 = TorrentDef.load(publicfn)

        self.assertTrue(t1.is_private())
        self.assertFalse(t2.is_private())
Example #10
0
    async def setup_tunnel_seeder(self, hops):
        """
        Setup the seeder.
        """
        from tribler_core.session import Session
        self.seed_config = self.config.copy()
        self.seed_config._state_dir = self.getRootStateDir(2)
        self.seed_config.set_libtorrent_enabled(hops == 0)
        self.seed_config.set_tunnel_community_socks5_listen_ports(
            self.get_ports(5))
        if self.session2 is None:
            self.session2 = Session(self.seed_config)
            self.session2.upgrader_enabled = False
            await self.session2.start()

        tdef = TorrentDef()
        tdef.add_content(TESTS_DATA_DIR / "video.avi")
        tdef.set_tracker("http://localhost/announce")
        torrentfn = self.session2.config.get_state_dir() / "gen.torrent"
        tdef.save(torrent_filepath=torrentfn)
        self.seed_tdef = tdef

        if hops > 0:  # Safe seeding enabled
            self.tunnel_community_seeder = await self.load_tunnel_community_in_session(
                self.session2, start_lt=True)
            self.tunnel_community_seeder.build_tunnels(hops)
        else:
            await self.sanitize_network(self.session2)

        dscfg = DownloadConfig()
        dscfg.set_dest_dir(
            TESTS_DATA_DIR)  # basedir of the file we are seeding
        dscfg.set_hops(hops)
        d = self.session2.dlmgr.start_download(tdef=tdef, config=dscfg)
        d.set_state_callback(self.seeder_state_callback)
Example #11
0
def test_tdef(state_dir):
    tdef = TorrentDef()
    sourcefn = TESTS_DATA_DIR / 'video.avi'
    tdef.add_content(sourcefn)
    tdef.set_tracker("http://localhost/announce")
    torrentfn = state_dir / "gen.torrent"
    tdef.save(torrentfn)
    return tdef
Example #12
0
    async def post_commit(self, request):
        channel_pk, channel_id = self.get_channel_from_request(request)
        with db_session:
            if channel_id == 0:
                for t in self.session.mds.CollectionNode.commit_all_channels():
                    self.session.gigachannel_manager.updated_my_channel(TorrentDef.load_from_dict(t))
            else:
                coll = self.session.mds.CollectionNode.get(public_key=database_blob(channel_pk), id_=channel_id)
                if not coll:
                    return RESTResponse({"success": False}, status=HTTP_NOT_FOUND)
                torrent_dict = coll.commit_channel_torrent()
                if torrent_dict:
                    self.session.gigachannel_manager.updated_my_channel(TorrentDef.load_from_dict(torrent_dict))

        return RESTResponse({"success": True})
Example #13
0
    def test_add_content_dir(self):
        """
        Test whether adding a single content directory with two files is working correctly
        """
        t = TorrentDef()
        torrent_dir = TESTS_DATA_DIR / "contentdir"
        t.add_content(torrent_dir / "file.txt")
        t.add_content(torrent_dir / "otherfile.txt")
        t.save()

        metainfo = t.get_metainfo()
        self.assertEqual(len(metainfo[b'info'][b'files']), 2)
Example #14
0
    def test_add_content_piece_length(self):
        """
        Add a single file with piece length to a TorrentDef
        """
        t = TorrentDef()
        fn = TESTS_DATA_DIR / VIDEO_FILE_NAME
        t.add_content(fn)
        t.set_piece_length(2**16)
        t.save()

        metainfo = t.get_metainfo()
        self.assertEqual(metainfo[b'info'][b'piece length'], 2**16)
Example #15
0
    async def test_load_from_url(self):
        # Setup file server to serve torrent file
        self.session_base_dir = mkdtemp(suffix="_tribler_test_load_from_url")
        files_path = self.session_base_dir / 'http_torrent_files'
        os.mkdir(files_path)
        shutil.copyfile(TORRENT_UBUNTU_FILE, files_path / 'ubuntu.torrent')

        file_server_port = self.get_port()
        await self.setUpFileServer(file_server_port, files_path)

        torrent_url = 'http://localhost:%d/ubuntu.torrent' % file_server_port
        torrent_def = await TorrentDef.load_from_url(torrent_url)
        self.assertEqual(torrent_def.get_metainfo(),
                         TorrentDef.load(TORRENT_UBUNTU_FILE).get_metainfo())
        self.assertEqual(torrent_def.infohash,
                         TorrentDef.load(TORRENT_UBUNTU_FILE).infohash)
Example #16
0
def convert_config_to_tribler75(state_dir):
    """
    Convert the download config files from Tribler 7.4 to 7.5 format.
    """
    for filename in (state_dir / STATEDIR_CHECKPOINT_DIR).glob('*.conf'):
        try:
            config = DownloadConfig.load(filename)

            # Convert resume data
            resumedata = config.get_engineresumedata()
            if b'mapped_files' in resumedata:
                resumedata.pop(b'mapped_files')
                config.set_engineresumedata(resumedata)
                config.write(str(filename))

            # Convert metainfo
            metainfo = config.get_metainfo()
            if not config.config['download_defaults'].get(
                    'selected_files') or not metainfo:
                continue  # no conversion needed/possible, selected files will be reset to their default (i.e., all files)
            tdef = TorrentDef.load_from_dict(metainfo)
            config.set_selected_files([
                tdef.get_index_of_file_in_files(fn) for fn in
                config.config['download_defaults'].pop('selected_files')
            ])
            config.write(str(filename))
        except ConfigObjParseError:
            logger.error("Could not parse %s file so removing it", filename)
            os.remove(filename)
Example #17
0
 def test_tdef_init(self):
     """
     Test initializing a TorrentDef object
     """
     tdef_params = TorrentDef(
         torrent_parameters={'announce': 'http://test.com'})
     self.assertIn('announce', tdef_params.torrent_parameters)
Example #18
0
def test_tdef_init():
    """
    Test initializing a TorrentDef object
    """
    tdef_params = TorrentDef(
        torrent_parameters={'announce': 'http://test.com'})
    assert 'announce' in tdef_params.torrent_parameters
Example #19
0
    def check_watch_folder(self):
        if not self.session.config.get_watch_folder_path().is_dir():
            return

        # Make sure that we pass a str to os.walk
        watch_dir = str(self.session.config.get_watch_folder_path())

        for root, _, files in os.walk(watch_dir):
            root = path_util.Path(root)
            for name in files:
                if not name.endswith(".torrent"):
                    continue

                try:
                    tdef = TorrentDef.load(root / name)
                    if not tdef.get_metainfo():
                        self.cleanup_torrent_file(root, name)
                        continue
                except:  # torrent appears to be corrupt
                    self.cleanup_torrent_file(root, name)
                    continue

                infohash = tdef.get_infohash()

                if not self.session.dlmgr.download_exists(infohash):
                    self._logger.info("Starting download from torrent file %s", name)
                    dl_config = DownloadConfig()

                    anon_enabled = self.session.config.get_default_anonymity_enabled()
                    default_num_hops = self.session.config.get_default_number_hops()
                    dl_config.set_hops(default_num_hops if anon_enabled else 0)
                    dl_config.set_safe_seeding(self.session.config.get_default_safeseeding_enabled())
                    dl_config.set_dest_dir(self.session.config.get_default_destination_dir())
                    self.session.dlmgr.start_download(tdef=tdef, config=dl_config)
Example #20
0
    def test_restore_torrent_in_channel(self):
        """
        Test if the torrent scheduled for deletion is restored/updated after the user tries to re-add it.
        """
        channel_metadata = self.mds.ChannelMetadata.create_channel(
            'test', 'test')
        tdef = TorrentDef.load(TORRENT_UBUNTU_FILE)
        md = channel_metadata.add_torrent_to_channel(tdef, None)

        # Check correct re-add
        md.status = TODELETE
        md_updated = channel_metadata.add_torrent_to_channel(tdef, None)
        self.assertEqual(UPDATED, md.status)
        self.assertEqual(md_updated, md)
        self.assertTrue(md.has_valid_signature)

        # Check update of torrent properties from a new tdef
        md.status = TODELETE
        new_tracker_address = u'http://tribler.org/announce'
        tdef.torrent_parameters[b'announce'] = new_tracker_address.encode(
            'utf-8')
        md_updated = channel_metadata.add_torrent_to_channel(tdef, None)
        self.assertEqual(md_updated, md)
        self.assertEqual(md.status, UPDATED)
        self.assertEqual(md.tracker_info, new_tracker_address)
        self.assertTrue(md.has_valid_signature)
        # In addition, check that the trackers table was properly updated
        self.assertEqual(len(md.health.trackers), 2)
Example #21
0
 def test_commit_channel_torrent(self):
     channel = self.mds.ChannelMetadata.create_channel('test', 'test')
     tdef = TorrentDef.load(TORRENT_UBUNTU_FILE)
     channel.add_torrent_to_channel(tdef, None)
     # The first run should return the infohash, the second should return None, because nothing was really done
     self.assertTrue(channel.commit_channel_torrent())
     self.assertFalse(channel.commit_channel_torrent())
Example #22
0
    def update_trackers(self, infohash, trackers):
        """ Update the trackers for a download.
        :param infohash: infohash of the torrent that needs to be updated
        :param trackers: A list of tracker urls.
        """
        download = self.get_download(infohash)
        if download:
            old_def = download.get_def()
            old_trackers = old_def.get_trackers_as_single_tuple()
            new_trackers = list(set(trackers) - set(old_trackers))
            all_trackers = list(old_trackers) + new_trackers

            if new_trackers:
                # Add new trackers to the download
                download.add_trackers(new_trackers)

                # Create a new TorrentDef
                if isinstance(old_def, TorrentDefNoMetainfo):
                    new_def = TorrentDefNoMetainfo(old_def.get_infohash(),
                                                   old_def.get_name(),
                                                   download.get_magnet_link())
                else:
                    metainfo = old_def.get_metainfo()
                    if len(all_trackers) > 1:
                        metainfo["announce-list"] = [all_trackers]
                    else:
                        metainfo["announce"] = all_trackers[0]
                    new_def = TorrentDef.load_from_dict(metainfo)

                # Set TorrentDef + checkpoint
                download.set_def(new_def)
                download.checkpoint()
Example #23
0
    def on_metadata_received_alert(self, _):
        torrent_info = get_info_from_handle(self.handle)
        if not torrent_info:
            return

        metadata = {
            b'info': bdecode_compat(torrent_info.metadata()),
            b'leechers': 0,
            b'seeders': 0
        }
        trackers = [
            tracker['url'].encode('utf-8')
            for tracker in self.handle.trackers()
        ]
        if len(trackers) > 1:
            metadata[b"announce-list"] = [trackers]
        elif trackers:
            metadata[b"announce"] = trackers[0]

        for peer in self.handle.get_peer_info():
            if peer.progress == 1:
                metadata[b"seeders"] += 1
            else:
                metadata[b"leechers"] += 1

        try:
            self.tdef = TorrentDef.load_from_dict(metadata)
        except ValueError as ve:
            self._logger.exception(ve)
            return

        self.set_selected_files()
        self.checkpoint()
Example #24
0
        def add_torrents_from_dir(self, torrents_dir, recursive=False):
            torrents_list = []
            errors_list = []

            def rec_gen(dir_):
                for root, _, filenames in os.walk(dir_):
                    for fn in filenames:
                        yield Path(root) / fn

            filename_generator = rec_gen(torrents_dir) if recursive else os.listdir(torrents_dir)
            # Build list of .torrents to process
            torrents_list_generator = (Path(torrents_dir, f) for f in filename_generator)
            torrents_list = [f for f in torrents_list_generator if f.is_file() and f.suffix == ".torrent"]

            # 100 is a reasonable chunk size for commits
            for chunk in chunks(torrents_list, 100):
                for f in chunk:
                    try:
                        self.add_torrent_to_channel(TorrentDef.load(f))
                    except DuplicateTorrentFileError:
                        pass
                    except Exception:  # pylint: disable=W0703
                        # Have to use the broad exception clause because Py3 versions of libtorrent
                        # generate generic Exceptions
                        errors_list.append(f)
                # Optimization to drop excess cache
                orm.commit()

            return torrents_list, errors_list
Example #25
0
    def add_torrent(self, file, relative_path):
        _logger.info(f'Add torrent: {file}')

        directory = self.get_directory(relative_path)
        decoded_torrent = libtorrent.bdecode(file.read_bytes())
        directory.add_torrent_to_channel(TorrentDef(metainfo=decoded_torrent),
                                         None)
Example #26
0
def test_restore_torrent_in_channel(metadata_store):
    """
    Test if the torrent scheduled for deletion is restored/updated after the user tries to re-add it.
    """
    channel_metadata = metadata_store.ChannelMetadata.create_channel(
        'test', 'test')
    tdef = TorrentDef.load(TORRENT_UBUNTU_FILE)
    md = channel_metadata.add_torrent_to_channel(tdef, None)

    # Check correct re-add
    md.status = TODELETE
    md_updated = channel_metadata.add_torrent_to_channel(tdef, None)
    assert UPDATED == md.status
    assert md_updated == md
    assert md.has_valid_signature

    # Check update of torrent properties from a new tdef
    md.status = TODELETE
    new_tracker_address = 'http://tribler.org/announce'
    tdef.torrent_parameters[b'announce'] = new_tracker_address.encode('utf-8')
    md_updated = channel_metadata.add_torrent_to_channel(tdef, None)
    assert md_updated == md
    assert md.status == UPDATED
    assert md.tracker_info == new_tracker_address
    assert md.has_valid_signature
    # In addition, check that the trackers table was properly updated
    assert len(md.health.trackers) == 2
Example #27
0
 def test_get_name_as_unicode(self):
     name_bytes = b'\xe8\xaf\xad\xe8\xa8\x80\xe5\xa4\x84\xe7\x90\x86'
     name_unicode = name_bytes.decode()
     t = TorrentDef()
     t.metainfo = {b'info': {b'name.utf-8': name_bytes}}
     self.assertEqual(t.get_name_as_unicode(), name_unicode)
     t.metainfo = {b'info': {b'name': name_bytes}}
     self.assertEqual(t.get_name_as_unicode(), name_unicode)
     t.metainfo = {b'info': {b'name': b'test\xff' + name_bytes}}
     self.assertEqual(t.get_name_as_unicode(), 'test?????????????')
Example #28
0
def test_updated_my_channel(enable_chant, personal_channel, channel_manager,
                            mock_dlmgr, session, tmpdir):
    tdef = TorrentDef.load_from_dict(update_metainfo)
    session.dlmgr.start_download = Mock()
    session.dlmgr.download_exists = lambda *_: False
    session.mds.channels_dir = "bla"
    session.config.get_state_dir = lambda: Path(tmpdir / "foo")
    channel_manager.updated_my_channel(tdef)
    session.dlmgr.start_download.assert_called_once()
Example #29
0
def personal_channel(session):
    global update_metainfo
    with db_session:
        chan = session.mds.ChannelMetadata.create_channel(title="my test chan",
                                                          description="test")
        tdef = TorrentDef.load(TORRENT_UBUNTU_FILE)
        chan.add_torrent_to_channel(tdef, None)
        update_metainfo = chan.commit_channel_torrent()
        return chan
Example #30
0
    def start_download(self,
                       torrent_file=None,
                       tdef=None,
                       config=None,
                       checkpoint_disabled=False,
                       hidden=False):
        self._logger.debug("Starting download: filename: %s, torrent def: %s",
                           torrent_file, tdef)

        # the priority of the parameters is: (1) tdef, (2) torrent_file.
        # so if we have tdef, and torrent_file will be ignored, and so on.
        if tdef is None:
            if torrent_file is None:
                raise ValueError(
                    "Torrent file must be provided if tdef is not given")
            # try to get the torrent from the given torrent file
            tdef = TorrentDef.load(torrent_file)

        assert tdef is not None, "tdef MUST not be None after loading torrent"

        config = config or DownloadConfig()
        infohash = tdef.get_infohash()
        download = self.get_download(infohash)

        if download and infohash not in self.metainfo_requests:
            new_trackers = list(
                set(tdef.get_trackers_as_single_tuple()) -
                set(download.get_def().get_trackers_as_single_tuple()))
            if new_trackers:
                self.update_trackers(tdef.get_infohash(), new_trackers)
            return download

        # Create the destination directory if it does not exist yet
        try:
            if not config.get_dest_dir().is_dir():
                os.makedirs(config.get_dest_dir())
        except OSError:
            self._logger.error(
                "Unable to create the download destination directory.")

        if config.get_time_added() == 0:
            config.set_time_added(int(timemod.time()))

        # Create the download
        download = Download(self.tribler_session, tdef, dummy=self.dummy_mode)
        atp = download.setup(config,
                             checkpoint_disabled=checkpoint_disabled,
                             hidden=hidden or config.get_bootstrap_download())
        # Keep metainfo downloads in self.downloads for now because we will need to remove it later,
        # and removing the download at this point will stop us from receiving any further alerts.
        if infohash not in self.metainfo_requests or self.metainfo_requests[
                infohash][0] == download:
            self.downloads[infohash] = download
        if not self.dummy_mode:
            self.start_handle(download, atp)
        return download