Beispiel #1
0
def test_parse_magnetlink_lowercase():
    """
    Test if a lowercase magnet link can be parsed
    """
    _, hashed, _ = parse_magnetlink(
        'magnet:?xt=urn:btih:apctqfwnowubxzoidazgaj2ba6fs6juc')

    assert hashed == b"\x03\xc58\x16\xcdu\xa8\x1b\xe5\xc8\x182`'A\x07\x8b/&\x82"
Beispiel #2
0
def test_parse_magnetlink_uppercase():
    """
    Test if an uppercase magnet link can be parsed
    """
    _, hashed, _ = parse_magnetlink(
        'magnet:?xt=urn:btih:APCTQFWNOWUBXZOIDAZGAJ2BA6FS6JUC')

    assert hashed == b"\x03\xc58\x16\xcdu\xa8\x1b\xe5\xc8\x182`'A\x07\x8b/&\x82"
Beispiel #3
0
 def test_parse_magnetlink_valid(self):
     result = parse_magnetlink("magnet:?xt=urn:ed2k:354B15E68FB8F36D7CD88FF94116CDC1&xl=10826029&dn=mediawiki-1.15.1"
                               ".tar.gz&xt=urn:tree:tiger:7N5OAMRNGMSSEUE3ORHOKWN4WWIQ5X4EBOOTLJY&xt=urn:btih:QHQXPY"
                               "WMACKDWKP47RRVIV7VOURXFE5Q&tr=http%3A%2F%2Ftracker.example.org%2Fannounce.php%3Fuk"
                               "%3D1111111111%26&as=http%3A%2F%2Fdownload.wikimedia.org%2Fmediawiki%2F1.15%2Fmediawi"
                               "ki-1.15.1.tar.gz&xs=http%3A%2F%2Fcache.example.org%2FXRX2PEFXOOEJFRVUCX6HMZMKS5TWG4K"
                               "5&xs=dchub://example.org")
     self.assertEqual(result, ('mediawiki-1.15.1.tar.gz', b'\x81\xe1w\xe2\xcc\x00\x94;)\xfc\xfccTW\xf5u#r\x93\xb0',
                               ['http://tracker.example.org/announce.php?uk=1111111111&']))
Beispiel #4
0
 async def start_download_from_uri(self, uri, config=None):
     if uri.startswith("http"):
         tdef = await TorrentDef.load_from_url(uri)
         return self.start_download(tdef=tdef, config=config)
     if uri.startswith("magnet:"):
         name, infohash, _ = parse_magnetlink(uri)
         if infohash is None:
             raise RuntimeError("Missing infohash")
         if infohash in self.metainfo_cache:
             tdef = TorrentDef.load_from_dict(self.metainfo_cache[infohash]['meta_info'])
         else:
             tdef = TorrentDefNoMetainfo(infohash, "Unknown name" if name is None else name, url=uri)
         return self.start_download(tdef=tdef, config=config)
     if uri.startswith("file:"):
         argument = url2pathname(uri[5:])
         return self.start_download(torrent_file=argument, config=config)
     raise Exception("invalid uri")
Beispiel #5
0
    async def start_download_from_uri(self, uri, config=None):
        scheme = scheme_from_uri(uri)

        if scheme in (HTTP_SCHEME, HTTPS_SCHEME):
            tdef = await TorrentDef.load_from_url(uri)
            return self.start_download(tdef=tdef, config=config)
        if scheme == MAGNET_SCHEME:
            name, infohash, _ = parse_magnetlink(uri)
            if infohash is None:
                raise RuntimeError("Missing infohash")
            if infohash in self.metainfo_cache:
                tdef = TorrentDef.load_from_dict(self.metainfo_cache[infohash]['meta_info'])
            else:
                tdef = TorrentDefNoMetainfo(infohash, "Unknown name" if name is None else name, url=uri)
            return self.start_download(tdef=tdef, config=config)
        if scheme == FILE_SCHEME:
            file = uri_to_path(uri)
            return self.start_download(torrent_file=file, config=config)
        raise Exception("invalid uri")
Beispiel #6
0
 def get_trackers_as_single_tuple(self):
     if self.url and self.url.startswith('magnet:'):
         _, _, trs = parse_magnetlink(self.url)
         return tuple(trs)
     return ()
Beispiel #7
0
def test_parse_magnetlink_nomagnet():
    result = parse_magnetlink("http://")
    assert result == (None, None, [])
Beispiel #8
0
    async def get_torrent_info(self, request):
        args = request.query

        hops = None
        if 'hops' in args:
            try:
                hops = int(args['hops'])
            except ValueError:
                return RESTResponse(
                    {
                        "error":
                        f"wrong value of 'hops' parameter: {repr(args['hops'])}"
                    },
                    status=HTTP_BAD_REQUEST)

        if 'uri' not in args or not args['uri']:
            return RESTResponse({"error": "uri parameter missing"},
                                status=HTTP_BAD_REQUEST)

        uri = args['uri']
        if uri.startswith('file:'):
            try:
                filename = url2pathname(uri[5:])
                tdef = TorrentDef.load(filename)
                metainfo = tdef.get_metainfo()
            except (TypeError, RuntimeError):
                return RESTResponse(
                    {"error": "error while decoding torrent file"},
                    status=HTTP_INTERNAL_SERVER_ERROR)
        elif uri.startswith('http'):
            try:
                async with ClientSession(raise_for_status=True) as session:
                    response = await session.get(uri)
                    response = await response.read()
            except (ServerConnectionError, ClientResponseError) as e:
                return RESTResponse({"error": str(e)},
                                    status=HTTP_INTERNAL_SERVER_ERROR)

            if response.startswith(b'magnet'):
                _, infohash, _ = parse_magnetlink(response)
                if infohash:
                    metainfo = await self.session.dlmgr.get_metainfo(
                        infohash, timeout=60, hops=hops, url=response)
            else:
                metainfo = bdecode_compat(response)
        elif uri.startswith('magnet'):
            infohash = parse_magnetlink(uri)[1]
            if infohash is None:
                return RESTResponse({"error": "missing infohash"},
                                    status=HTTP_BAD_REQUEST)
            metainfo = await self.session.dlmgr.get_metainfo(infohash,
                                                             timeout=60,
                                                             hops=hops,
                                                             url=uri)
        else:
            return RESTResponse({"error": "invalid uri"},
                                status=HTTP_BAD_REQUEST)

        if not metainfo:
            return RESTResponse({"error": "metainfo error"},
                                status=HTTP_INTERNAL_SERVER_ERROR)

        if not isinstance(metainfo, dict) or b'info' not in metainfo:
            self._logger.warning("Received metainfo is not a valid dictionary")
            return RESTResponse({"error": "invalid response"},
                                status=HTTP_INTERNAL_SERVER_ERROR)

        # Add the torrent to GigaChannel as a free-for-all entry, so others can search it
        self.session.mds.TorrentMetadata.add_ffa_from_dict(
            tdef_to_metadata_dict(TorrentDef.load_from_dict(metainfo)))

        # TODO(Martijn): store the stuff in a database!!!
        # TODO(Vadim): this means cache the downloaded torrent in a binary storage, like LevelDB
        infohash = hashlib.sha1(bencode(metainfo[b'info'])).digest()

        download = self.session.dlmgr.downloads.get(infohash)
        metainfo_request = self.session.dlmgr.metainfo_requests.get(
            infohash, [None])[0]
        download_is_metainfo_request = download == metainfo_request

        # Check if the torrent is already in the downloads
        encoded_metainfo = deepcopy(metainfo)

        # FIXME: json.dumps garbles binary data that is used by the 'pieces' field
        # However, this is fine as long as the GUI does not use this field.
        encoded_metainfo[b'info'][b'pieces'] = hexlify(
            encoded_metainfo[b'info'][b'pieces']).encode('utf-8')
        encoded_metainfo = hexlify(
            json.dumps(recursive_unicode(encoded_metainfo, ignore_errors=True),
                       ensure_ascii=False).encode('utf-8'))
        return RESTResponse({
            "metainfo":
            encoded_metainfo,
            "download_exists":
            download and not download_is_metainfo_request
        })
Beispiel #9
0
    async def add_torrent_to_channel(self, request):
        channel_pk, channel_id = self.get_channel_from_request(request)
        with db_session:
            channel = self.session.mds.CollectionNode.get(
                public_key=database_blob(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:"):
                async with ClientSession() as session:
                    response = await session.get(uri)
                    data = await response.read()
                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.session.mds.torrent_exists_in_personal_channel(xt)
                     or channel.copy_torrent_from_infohash(xt))):
                    return RESTResponse({"added": 1})

                meta_info = await self.session.dlmgr.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_util.isabs(torrents_dir):
                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})
Beispiel #10
0
 def test_parse_magnetlink_nomagnet(self):
     result = parse_magnetlink("http://")
     self.assertEqual(result, (None, None, []))