Esempio n. 1
0
        string ToString(int formatVersion)
        {
            var sb = new StringBuilder();

            sb.Append("magnet:?");
            if (formatVersion == 1)
            {
                sb.Append("xt=urn:btih:");
                sb.Append(InfoHash.ToHex());
            }
            else if (formatVersion == 2)
            {
                sb.Append("xt=urn:btmh");
                throw new NotSupportedException("Need to add support for the new 'multihash' thing");
            }
            else
            {
                throw new NotSupportedException();
            }

            if (!string.IsNullOrEmpty(Name))
            {
                sb.Append("&dn=");
                sb.Append(Name.UrlEncodeUTF8());
            }

            foreach (var tracker in AnnounceUrls)
            {
                sb.Append("&tr=");
                sb.Append(tracker.UrlEncodeUTF8());
            }

            foreach (var webseed in Webseeds)
            {
                sb.Append("&as=");
                sb.Append(webseed.UrlEncodeUTF8());
            }

            return(sb.ToString());
        }
Esempio n. 2
0
        void ParseMagnetLink(string url)
        {
            string[] splitStr = url.Split('?');
            if (splitStr.Length == 0 || splitStr[0] != "magnet:")
            {
                throw new FormatException("The magnet link must start with 'magnet:?'.");
            }

            if (splitStr.Length == 1)
            {
                return;//no parametter
            }
            string[] parameters = splitStr[1].Split('&', ';');

            for (int i = 0; i < parameters.Length; i++)
            {
                string[] keyval = parameters[i].Split('=');
                if (keyval.Length != 2)
                {
                    throw new FormatException("A field-value pair of the magnet link contain more than one equal'.");
                }
                switch (keyval[0].Substring(0, 2))
                {
                case "xt":    //exact topic
                    if (InfoHash != null)
                    {
                        throw new FormatException("More than one infohash in magnet link is not allowed.");
                    }

                    string val = keyval[1].Substring(9);
                    switch (keyval[1].Substring(0, 9))
                    {
                    case "urn:sha1:":        //base32 hash
                    case "urn:btih:":
                        if (val.Length == 32)
                        {
                            InfoHash = InfoHash.FromBase32(val);
                        }
                        else if (val.Length == 40)
                        {
                            InfoHash = InfoHash.FromHex(val);
                        }
                        else
                        {
                            throw new FormatException("Infohash must be base32 or hex encoded.");
                        }
                        break;
                    }
                    break;

                case "tr":     //address tracker
                    var bytes = UriHelper.UrlDecode(keyval[1]);
                    AnnounceUrls.Add(Encoding.UTF8.GetString(bytes, 0, bytes.Length));
                    break;

                case "as":    //Acceptable Source
                    Webseeds.Add(keyval[1]);
                    break;

                case "dn":    //display name
                    var name = UriHelper.UrlDecode(keyval[1]);
                    Name = Encoding.UTF8.GetString(name, 0, name.Length);
                    break;

                case "xl":    //exact length
                case "xs":    // eXact Source - P2P link.
                case "kt":    //keyword topic
                case "mt":    //manifest topic
                    //not supported for moment
                    break;

                default:
                    //not supported
                    break;
                }
            }
        }
Esempio n. 3
0
        protected void LoadInternal(BEncodedDictionary torrentInformation)
        {
            Check.TorrentInformation(torrentInformation);
            originalDictionary = torrentInformation;
            torrentPath        = "";

            try
            {
                foreach (KeyValuePair <BEncodedString, BEncodedValue> keypair in torrentInformation)
                {
                    switch (keypair.Key.Text)
                    {
                    case ("announce"):
                        // Ignore this if we have an announce-list
                        if (torrentInformation.ContainsKey("announce-list"))
                        {
                            break;
                        }
                        announceUrls.Add(new RawTrackerTier());
                        announceUrls[0].Add(keypair.Value.ToString());
                        break;

                    case ("creation date"):
                        try
                        {
                            try
                            {
                                creationDate = creationDate.AddSeconds(long.Parse(keypair.Value.ToString()));
                            }
                            catch (Exception e)
                            {
                                if (e is ArgumentOutOfRangeException)
                                {
                                    creationDate = creationDate.AddMilliseconds(long.Parse(keypair.Value.ToString()));
                                }
                                else
                                {
                                    throw;
                                }
                            }
                        }
                        catch (Exception e)
                        {
                            if (e is ArgumentOutOfRangeException)
                            {
                                throw new BEncodingException("Argument out of range exception when adding seconds to creation date.", e);
                            }
                            else if (e is FormatException)
                            {
                                throw new BEncodingException(String.Format("Could not parse {0} into a number", keypair.Value), e);
                            }
                            else
                            {
                                throw;
                            }
                        }
                        break;

                    case ("nodes"):
                        nodes = (BEncodedList)keypair.Value;
                        break;

                    case ("comment.utf-8"):
                        if (keypair.Value.ToString().Length != 0)
                        {
                            comment = keypair.Value.ToString();           // Always take the UTF-8 version
                        }
                        break;                                            // even if there's an existing value

                    case ("comment"):
                        if (String.IsNullOrEmpty(comment))
                        {
                            comment = keypair.Value.ToString();
                        }
                        break;

                    case ("publisher-url.utf-8"):                         // Always take the UTF-8 version
                        publisherUrl = keypair.Value.ToString();          // even if there's an existing value
                        break;

                    case ("publisher-url"):
                        if (String.IsNullOrEmpty(publisherUrl))
                        {
                            publisherUrl = keypair.Value.ToString();
                        }
                        break;

                    case ("azureus_properties"):
                        azureusProperties = keypair.Value;
                        break;

                    case ("created by"):
                        createdBy = keypair.Value.ToString();
                        break;

                    case ("encoding"):
                        encoding = keypair.Value.ToString();
                        break;

                    case ("info"):
                        using (SHA1 s = HashAlgoFactory.Create <SHA1>())
                            infoHash = new InfoHash(s.ComputeHash(keypair.Value.Encode()));
                        ProcessInfo(((BEncodedDictionary)keypair.Value));
                        break;

                    case ("name"):                                                   // Handled elsewhere
                        break;

                    case ("announce-list"):
                        if (keypair.Value is BEncodedString)
                        {
                            break;
                        }
                        BEncodedList announces = (BEncodedList)keypair.Value;

                        for (int j = 0; j < announces.Count; j++)
                        {
                            if (announces[j] is BEncodedList)
                            {
                                BEncodedList  bencodedTier = (BEncodedList)announces[j];
                                List <string> tier         = new List <string>(bencodedTier.Count);

                                for (int k = 0; k < bencodedTier.Count; k++)
                                {
                                    tier.Add(bencodedTier[k].ToString());
                                }

                                Toolbox.Randomize <string>(tier);

                                RawTrackerTier collection = new RawTrackerTier();
                                for (int k = 0; k < tier.Count; k++)
                                {
                                    collection.Add(tier[k]);
                                }

                                if (collection.Count != 0)
                                {
                                    announceUrls.Add(collection);
                                }
                            }
                            else
                            {
                                throw new BEncodingException(String.Format("Non-BEncodedList found in announce-list (found {0})",
                                                                           announces[j].GetType()));
                            }
                        }
                        break;

                    case ("httpseeds"):
                        // This form of web-seeding is not supported.
                        break;

                    case ("url-list"):
                        if (keypair.Value is BEncodedString)
                        {
                            getRightHttpSeeds.Add(((BEncodedString)keypair.Value).Text);
                        }
                        else if (keypair.Value is BEncodedList)
                        {
                            foreach (BEncodedString str in (BEncodedList)keypair.Value)
                            {
                                GetRightHttpSeeds.Add(str.Text);
                            }
                        }
                        break;

                    default:
                        break;
                    }
                }
            }
            catch (Exception e)
            {
                if (e is BEncodingException)
                {
                    throw;
                }
                else
                {
                    throw new BEncodingException("", e);
                }
            }
        }
Esempio n. 4
0
        /// <summary>
        /// Parses a magnet link from the given Uri. The uri should be in the form magnet:?xt=urn:btih:
        /// </summary>
        /// <param name="uri"></param>
        /// <returns></returns>
        public static MagnetLink FromUri(Uri uri)
        {
            InfoHash infoHash     = null;
            string   name         = null;
            var      announceUrls = new List <string> ();
            var      webSeeds     = new List <string> ();
            long?    size         = null;

            if (uri.Scheme != "magnet")
            {
                throw new FormatException("Magnet links must start with 'magnet:'.");
            }

            string[] parameters = uri.Query.Substring(1).Split('&');
            for (int i = 0; i < parameters.Length; i++)
            {
                string[] keyval = parameters[i].Split('=');
                if (keyval.Length != 2)
                {
                    // Skip anything we don't understand. Urls could theoretically contain many
                    // unknown parameters.
                    continue;
                }
                switch (keyval[0].Substring(0, 2))
                {
                case "xt":    //exact topic
                    string val = keyval[1].Substring(9);
                    switch (keyval[1].Substring(0, 9))
                    {
                    case "urn:sha1:":        //base32 hash
                    case "urn:btih:":
                        if (infoHash != null)
                        {
                            throw new FormatException("More than one infohash in magnet link is not allowed.");
                        }

                        if (val.Length == 32)
                        {
                            infoHash = InfoHash.FromBase32(val);
                        }
                        else if (val.Length == 40)
                        {
                            infoHash = InfoHash.FromHex(val);
                        }
                        else
                        {
                            throw new FormatException("Infohash must be base32 or hex encoded.");
                        }
                        break;

                    case "urn:btmh:":
                        // placeholder to parse v2 multihash
                        break;
                    }
                    break;

                case "tr":    //address tracker
                    announceUrls.Add(keyval[1].UrlDecodeUTF8());
                    break;

                case "as":    //Acceptable Source
                    webSeeds.Add(keyval[1].UrlDecodeUTF8());
                    break;

                case "dn":    //display name
                    name = keyval[1].UrlDecodeUTF8();
                    break;

                case "xl":    //exact length
                    size = long.Parse(keyval[1]);
                    break;

                //case "xs":// eXact Source - P2P link.
                //case "kt"://keyword topic
                //case "mt"://manifest topic
                // Unused
                //break;
                default:
                    // Unknown/unsupported
                    break;
                }
            }

            if (infoHash == null)
            {
                throw new FormatException("The magnet link did not contain a valid 'xt' parameter referencing the infohash");
            }

            return(new MagnetLink(infoHash, name, announceUrls, webSeeds, size));
        }
Esempio n. 5
0
        /// <summary>
        /// Parses a magnet link from the given Uri. The uri should be in the form magnet:?xt=urn:btih:
        /// </summary>
        /// <param name="uri"></param>
        /// <returns></returns>
        public static MagnetLink FromUri(Uri uri)
        {
            InfoHash infoHash     = null;
            string   name         = null;
            var      announceUrls = new RawTrackerTier();
            var      webSeeds     = new List <string> ();
            long?    size         = null;

            if (uri.Scheme != "magnet")
            {
                throw new FormatException("Magnet links must start with 'magnet:'.");
            }

            string[] parameters = uri.Query.Substring(1).Split('&');
            for (int i = 0; i < parameters.Length; i++)
            {
                string[] keyval = parameters[i].Split('=');
                if (keyval.Length != 2)
                {
                    throw new FormatException("A field-value pair of the magnet link contain more than one equal'.");
                }
                switch (keyval[0].Substring(0, 2))
                {
                case "xt":    //exact topic
                    if (infoHash != null)
                    {
                        throw new FormatException("More than one infohash in magnet link is not allowed.");
                    }

                    string val = keyval[1].Substring(9);
                    switch (keyval[1].Substring(0, 9))
                    {
                    case "urn:sha1:":        //base32 hash
                    case "urn:btih:":
                        if (val.Length == 32)
                        {
                            infoHash = InfoHash.FromBase32(val);
                        }
                        else if (val.Length == 40)
                        {
                            infoHash = InfoHash.FromHex(val);
                        }
                        else
                        {
                            throw new FormatException("Infohash must be base32 or hex encoded.");
                        }
                        break;
                    }
                    break;

                case "tr":     //address tracker
                    announceUrls.Add(keyval[1].UrlDecodeUTF8());
                    break;

                case "as":    //Acceptable Source
                    webSeeds.Add(keyval[1].UrlDecodeUTF8());
                    break;

                case "dn":    //display name
                    name = keyval[1].UrlDecodeUTF8();
                    break;

                case "xl":    //exact length
                    size = long.Parse(keyval [1]);
                    break;

                case "xs":    // eXact Source - P2P link.
                case "kt":    //keyword topic
                case "mt":    //manifest topic
                    //not supported for moment
                    break;

                default:
                    //not supported
                    break;
                }
            }

            return(new MagnetLink(infoHash, name, announceUrls, webSeeds, size));
        }
Esempio n. 6
0
 public void InvalidHex()
 {
     Assert.Throws <ArgumentException> (() => {
         InfoHash.FromHex("123123123123123123123");
     });
 }
Esempio n. 7
0
 public void NullHex()
 {
     Assert.Throws <ArgumentNullException> (() => {
         InfoHash.FromHex(null);
     });
 }
Esempio n. 8
0
 public PeersFoundEventArgs(InfoHash infoHash, List <Peer> peers)
 {
     this.peers    = peers;
     this.infoHash = infoHash;
 }
Esempio n. 9
0
 public void InvalidBase32()
 {
     Assert.Throws <ArgumentException> (() => InfoHash.FromBase32("YNCKHTQCWBTRNJIV4WNAE52SJUQCZO5"));
     Assert.Throws <ArgumentException> (() => InfoHash.FromBase32("YNCKHTQCWBTRNJIV4WNAE52SJUQCZO5?"));
 }
 public static InfoHashes FromV1(InfoHash infoHash)
 => new InfoHashes(infoHash, null);
 public static InfoHashes FromV2(InfoHash infoHash)
 => new InfoHashes(null, infoHash);
Esempio n. 12
0
        void LoadInternal(BEncodedDictionary torrentInformation, InfoHash infoHash)
        {
            Check.TorrentInformation(torrentInformation);
            AnnounceUrls = new List <IList <string> > ().AsReadOnly();

            foreach (KeyValuePair <BEncodedString, BEncodedValue> keypair in torrentInformation)
            {
                switch (keypair.Key.Text)
                {
                case ("announce"):
                    // Ignore this if we have an announce-list
                    if (torrentInformation.ContainsKey("announce-list"))
                    {
                        break;
                    }
                    AnnounceUrls = new List <IList <string> > {
                        new List <string> {
                            keypair.Value.ToString()
                        }.AsReadOnly()
                    }.AsReadOnly();
                    break;

                case ("creation date"):
                    try {
                        try {
                            CreationDate = UnixEpoch.AddSeconds(long.Parse(keypair.Value.ToString()));
                        } catch (Exception e) {
                            if (e is ArgumentOutOfRangeException)
                            {
                                CreationDate = UnixEpoch.AddMilliseconds(long.Parse(keypair.Value.ToString()));
                            }
                            else
                            {
                                throw;
                            }
                        }
                    } catch (Exception e) {
                        if (e is ArgumentOutOfRangeException)
                        {
                            throw new BEncodingException("Argument out of range exception when adding seconds to creation date.", e);
                        }
                        else if (e is FormatException)
                        {
                            throw new BEncodingException($"Could not parse {keypair.Value} into a number", e);
                        }
                        else
                        {
                            throw;
                        }
                    }
                    break;

                case ("nodes"):
                    if (keypair.Value is BEncodedList list)
                    {
                        Nodes = list;
                    }
                    break;

                case ("comment.utf-8"):
                    if (keypair.Value.ToString().Length != 0)
                    {
                        Comment = keypair.Value.ToString();            // Always take the UTF-8 version
                    }
                    break;                                             // even if there's an existing value

                case ("comment"):
                    if (string.IsNullOrEmpty(Comment))
                    {
                        Comment = keypair.Value.ToString();
                    }
                    break;

                case ("publisher-url.utf-8"):                          // Always take the UTF-8 version
                    PublisherUrl = keypair.Value.ToString();           // even if there's an existing value
                    break;

                case ("publisher-url"):
                    if (string.IsNullOrEmpty(PublisherUrl))
                    {
                        PublisherUrl = keypair.Value.ToString();
                    }
                    break;

                case ("created by"):
                    CreatedBy = keypair.Value.ToString();
                    break;

                case ("encoding"):
                    Encoding = keypair.Value.ToString();
                    break;

                case ("info"):
                    InfoHash = infoHash;
                    ProcessInfo(((BEncodedDictionary)keypair.Value));
                    break;

                case ("name"):                                                   // Handled elsewhere
                    break;

                case ("announce-list"):
                    if (keypair.Value is BEncodedString)
                    {
                        break;
                    }

                    var result    = new List <IList <string> > ();
                    var announces = (BEncodedList)keypair.Value;
                    for (int j = 0; j < announces.Count; j++)
                    {
                        if (announces[j] is BEncodedList bencodedTier)
                        {
                            var tier = new List <string> (bencodedTier.Count);

                            for (int k = 0; k < bencodedTier.Count; k++)
                            {
                                tier.Add(bencodedTier[k].ToString());
                            }

                            Toolbox.Randomize(tier);

                            var resultTier = new List <string> ();
                            for (int k = 0; k < tier.Count; k++)
                            {
                                resultTier.Add(tier[k]);
                            }

                            if (resultTier.Count != 0)
                            {
                                result.Add(tier.AsReadOnly());
                            }
                        }
                        else
                        {
                            throw new BEncodingException(
                                      $"Non-BEncodedList found in announce-list (found {announces[j].GetType ()})");
                        }
                    }
                    if (result.Count > 0)
                    {
                        AnnounceUrls = result.AsReadOnly();
                    }
                    break;

                case ("httpseeds"):
                    // This form of web-seeding is not supported.
                    break;

                case ("url-list"):
                    if (keypair.Value is BEncodedString httpSeedString)
                    {
                        HttpSeeds.Add(httpSeedString.Text);
                    }
                    else if (keypair.Value is BEncodedList httpSeedList)
                    {
                        foreach (BEncodedString str in httpSeedList)
                        {
                            HttpSeeds.Add(str.Text);
                        }
                    }
                    break;

                default:
                    break;
                }
            }
        }
Esempio n. 13
0
 public override int GetHashCode()
 => InfoHash.GetHashCode();
 public MagnetLink(InfoHash infoHash, string?name = null, IList <string>?announceUrls = null, IEnumerable <string>?webSeeds = null, long?size = null)
     : this(InfoHashes.FromInfoHash(infoHash), name, announceUrls, webSeeds, size)
 {
 }
Esempio n. 15
0
        /// <summary>
        /// 从给定的Uri解析磁铁链接. uri必须为[magnet:?xt=urn:btih:]开头的Uri对象
        /// </summary>
        /// <param name="uri">以[magnet:?xt=urn:btih:]开头的Uri对象</param>
        /// <returns></returns>
        public static MagnetLink FromUri(Uri uri)
        {
            InfoHash infoHash     = null;
            string   name         = null;
            var      announceUrls = new RawTrackerTier();
            var      webSeeds     = new List <string> ();
            long?    size         = null;

            if (uri.Scheme != "magnet")
            {
                throw new FormatException("磁力链接必须为'magnet:'开头.");
            }

            string[] parameters = uri.Query.Substring(1).Split('&');
            for (int i = 0; i < parameters.Length; i++)
            {
                string[] keyval = parameters[i].Split('=');
                if (keyval.Length != 2)
                {
                    // Skip anything we don't understand. Urls could theoretically contain many
                    // unknown parameters.
                    continue;
                }
                switch (keyval[0].Substring(0, 2))
                {
                case "xt":    //exact topic
                    if (infoHash != null)
                    {
                        throw new FormatException("磁铁链接中不允许有多个infohash.");
                    }

                    string val = keyval[1].Substring(9);
                    switch (keyval[1].Substring(0, 9))
                    {
                    case "urn:sha1:":        //base32 hash
                    case "urn:btih:":
                        if (val.Length == 32)
                        {
                            infoHash = InfoHash.FromBase32(val);
                        }
                        else if (val.Length == 40)
                        {
                            infoHash = InfoHash.FromHex(val);
                        }
                        else
                        {
                            throw new FormatException("Infohash必须是Base32或十六进制编码.");
                        }
                        break;
                    }
                    break;

                case "tr":    //address tracker
                    announceUrls.Add(keyval[1].UrlDecodeUTF8());
                    break;

                case "as":    //Acceptable Source
                    webSeeds.Add(keyval[1].UrlDecodeUTF8());
                    break;

                case "dn":    //display name
                    name = keyval[1].UrlDecodeUTF8();
                    break;

                case "xl":    //exact length
                    size = long.Parse(keyval[1]);
                    break;

                //case "xs":// eXact Source - P2P link.
                //case "kt"://keyword topic
                //case "mt"://manifest topic
                // Unused
                //break;
                default:
                    // Unknown/unsupported
                    break;
                }
            }

            if (infoHash == null)
            {
                throw new FormatException("磁铁链接不包含引用infohash的有效\"xt\"参数");
            }

            return(new MagnetLink(infoHash, name, announceUrls, webSeeds, size));
        }
Esempio n. 16
0
        void ParseMagnetLink(string url)
        {
            string[] splitStr = url.Split('?');
            if (splitStr.Length == 0 || splitStr[0] != "magnet:")
            {
                throw new FormatException("The magnet link must start with 'magnet:?'.");
            }

            if (splitStr.Length == 1)
            {
                return;//no parametter
            }
            string[] parameters = splitStr[1].Split('&', ';');

            for (int i = 0; i < parameters.Length; i++)
            {
                string[] keyval = parameters[i].Split('=');
                if (keyval.Length != 2)
                {
                    throw new FormatException("A field-value pair of the magnet link contain more than one equal'.");
                }
                switch (keyval[0].Substring(0, 2))
                {
                case "xt":    //exact topic
                    if (InfoHash != null)
                    {
                        throw new FormatException("More than one infohash in magnet link is not allowed.");
                    }

                    string val = keyval[1].Substring(9);
                    //TODO: Support more hash encoding scheme
                    //https://en.wikipedia.org/wiki/Magnet_URI_scheme#URN.2C_containing_hash_.28xt.29
                    switch (keyval[1].Substring(0, 9))
                    {
                    case "urn:sha1:":        //base32 hash
                    case "urn:btih:":
                        if (val.Length == 32)
                        {
                            InfoHash = InfoHash.FromBase32(val);
                        }
                        else if (val.Length == 40)
                        {
                            InfoHash = InfoHash.FromHex(val);
                        }
                        else
                        {
                            throw new FormatException("Infohash must be base32 or hex encoded.");
                        }
                        break;

                    default:
                        throw new FormatException("Infohash must be base32 or hex encoded.");
                    }
                    break;

                case "dn":    //display name
                    Name = System.Web.HttpUtility.UrlDecode(keyval[1]);
                    break;

                default:
                    //not supported
                    break;
                }
            }
        }