public async Task <HttpResponseMessage> Download(string indexerID, string path, string jackett_apikey, string file) { try { var indexer = indexerService.GetWebIndexer(indexerID); if (!indexer.IsConfigured) { logger.Warn(string.Format("Rejected a request to {0} which is unconfigured.", indexer.DisplayName)); return(Request.CreateResponse(HttpStatusCode.Forbidden, "This indexer is not configured.")); } path = Encoding.UTF8.GetString(HttpServerUtility.UrlTokenDecode(path)); path = protectionService.UnProtect(path); if (config.APIKey != jackett_apikey) { return(new HttpResponseMessage(HttpStatusCode.Unauthorized)); } var target = new Uri(path, UriKind.RelativeOrAbsolute); var downloadBytes = await indexer.Download(target); // handle magnet URLs if (downloadBytes.Length >= 7 && downloadBytes[0] == 0x6d && // m downloadBytes[1] == 0x61 && // a downloadBytes[2] == 0x67 && // g downloadBytes[3] == 0x6e && // n downloadBytes[4] == 0x65 && // e downloadBytes[5] == 0x74 && // t downloadBytes[6] == 0x3a // : ) { var magneturi = Encoding.UTF8.GetString(downloadBytes); var response = Request.CreateResponse(HttpStatusCode.Moved); response.Headers.Location = new Uri(magneturi); return(response); } // This will fix torrents where the keys are not sorted, and thereby not supported by Sonarr. var parser = new BencodeParser(); var torrentDictionary = parser.Parse(downloadBytes); byte[] sortedDownloadBytes = torrentDictionary.EncodeAsBytes(); var result = new HttpResponseMessage(HttpStatusCode.OK); result.Content = new ByteArrayContent(sortedDownloadBytes); result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/x-bittorrent"); result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = StringUtil.MakeValidFileName(file, '_', false) + ".torrent" // call MakeValidFileName again to avoid any kind of injection attack }; return(result); } catch (Exception e) { logger.Error(e, "Error downloading " + indexerID + " " + path); return(new HttpResponseMessage(HttpStatusCode.NotFound)); } }
public async Task <IHttpActionResult> Blackhole(string indexerID, string path, string jackett_apikey, string file) { var jsonReply = new JObject(); try { var indexer = indexerService.GetWebIndexer(indexerID); if (!indexer.IsConfigured) { logger.Warn(string.Format("Rejected a request to {0} which is unconfigured.", indexer.DisplayName)); throw new Exception("This indexer is not configured."); } if (serverConfig.APIKey != jackett_apikey) { throw new Exception("Incorrect API key"); } path = Encoding.UTF8.GetString(HttpServerUtility.UrlTokenDecode(path)); path = protectionService.UnProtect(path); var remoteFile = new Uri(path, UriKind.RelativeOrAbsolute); var downloadBytes = await indexer.Download(remoteFile); if (string.IsNullOrWhiteSpace(serverConfig.BlackholeDir)) { throw new Exception("Blackhole directory not set!"); } if (!Directory.Exists(serverConfig.BlackholeDir)) { throw new Exception("Blackhole directory does not exist: " + serverConfig.BlackholeDir); } var fileName = DateTime.Now.Ticks.ToString() + "-" + StringUtil.MakeValidFileName(indexer.DisplayName, '_', false); if (string.IsNullOrWhiteSpace(file)) { fileName += ".torrent"; } else { fileName += "-" + StringUtil.MakeValidFileName(file, '_', false); // call MakeValidFileName() again to avoid any possibility of path traversal attacks } File.WriteAllBytes(Path.Combine(serverConfig.BlackholeDir, fileName), downloadBytes); jsonReply["result"] = "success"; } catch (Exception ex) { logger.Error(ex, "Error downloading to blackhole " + indexerID + " " + path); jsonReply["result"] = "error"; jsonReply["error"] = ex.Message; } return(Json(jsonReply)); }
public async Task <HttpResponseMessage> Download(string indexerID, string path, string jackett_apikey, string file) { try { var indexer = indexerService.GetWebIndexer(indexerID); if (!indexer.IsConfigured) { logger.Warn(string.Format("Rejected a request to {0} which is unconfigured.", indexer.DisplayName)); return(Request.CreateResponse(HttpStatusCode.Forbidden, "This indexer is not configured.")); } path = Encoding.UTF8.GetString(HttpServerUtility.UrlTokenDecode(path)); path = protectionService.UnProtect(path); if (serverService.Config.APIKey != jackett_apikey) { return(new HttpResponseMessage(HttpStatusCode.Unauthorized)); } var target = new Uri(path, UriKind.RelativeOrAbsolute); var downloadBytes = await indexer.Download(target); // This will fix torrents where the keys are not sorted, and thereby not supported by Sonarr. var torrentDictionary = BEncodedDictionary.DecodeTorrent(downloadBytes); downloadBytes = torrentDictionary.Encode(); var result = new HttpResponseMessage(HttpStatusCode.OK); result.Content = new ByteArrayContent(downloadBytes); result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/x-bittorrent"); result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = StringUtil.MakeValidFileName(file, '_', false) // call MakeValidFileName again to avoid any kind of injection attack }; return(result); } catch (Exception e) { logger.Error(e, "Error downloading " + indexerID + " " + path); return(new HttpResponseMessage(HttpStatusCode.NotFound)); } }
public async Task <IActionResult> DownloadImage(string indexerID, string path, string jackett_apikey, string file) { try { if (serverConfig.APIKey != jackett_apikey) { return(Unauthorized()); } var indexer = indexerService.GetWebIndexer(indexerID); if (!indexer.IsConfigured) { logger.Warn($"Rejected a request to {indexer.DisplayName} which is unconfigured."); return(Forbid("This indexer is not configured.")); } path = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(path)); path = protectionService.UnProtect(path); var target = new Uri(path, UriKind.RelativeOrAbsolute); var response = await indexer.DownloadImage(target); if (response.Status != System.Net.HttpStatusCode.OK && response.Status != System.Net.HttpStatusCode.Continue && response.Status != System.Net.HttpStatusCode.PartialContent) { return(new StatusCodeResult((int)response.Status)); } var contentType = response.Headers.ContainsKey("content-type") ? response.Headers["content-type"].First() : "image/jpeg"; return(File(response.ContentBytes, contentType)); } catch (Exception e) { logger.Debug($"Error downloading image. indexer: {indexerID} path: {path}\n{e}"); return(new StatusCodeResult((int)System.Net.HttpStatusCode.InternalServerError)); } }
public async Task <IActionResult> Blackhole(string indexerID, string path, string jackett_apikey, string file) { var jsonReply = new JObject(); try { if (serverConfig.APIKey != jackett_apikey) { return(Unauthorized()); } var indexer = indexerService.GetWebIndexer(indexerID); if (!indexer.IsConfigured) { logger.Warn(string.Format("Rejected a request to {0} which is unconfigured.", indexer.DisplayName)); throw new Exception("This indexer is not configured."); } path = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(path)); path = protectionService.UnProtect(path); var remoteFile = new Uri(path, UriKind.RelativeOrAbsolute); var fileExtension = ".torrent"; byte[] downloadBytes; if (remoteFile.OriginalString.StartsWith("magnet")) { downloadBytes = Encoding.UTF8.GetBytes(remoteFile.OriginalString); } else { downloadBytes = await indexer.Download(remoteFile); } // handle magnet URLs if (downloadBytes.Length >= 7 && downloadBytes[0] == 0x6d && // m downloadBytes[1] == 0x61 && // a downloadBytes[2] == 0x67 && // g downloadBytes[3] == 0x6e && // n downloadBytes[4] == 0x65 && // e downloadBytes[5] == 0x74 && // t downloadBytes[6] == 0x3a // : ) { fileExtension = ".magnet"; } if (string.IsNullOrWhiteSpace(serverConfig.BlackholeDir)) { throw new Exception("Blackhole directory not set!"); } if (!Directory.Exists(serverConfig.BlackholeDir)) { throw new Exception("Blackhole directory does not exist: " + serverConfig.BlackholeDir); } var fileName = DateTime.Now.Ticks.ToString() + "-" + StringUtil.MakeValidFileName(indexer.DisplayName, '_', false); if (string.IsNullOrWhiteSpace(file)) { fileName += fileExtension; } else { fileName += "-" + StringUtil.MakeValidFileName(file + fileExtension, '_', false); // call MakeValidFileName() again to avoid any possibility of path traversal attacks } System.IO.File.WriteAllBytes(Path.Combine(serverConfig.BlackholeDir, fileName), downloadBytes); jsonReply["result"] = "success"; } catch (Exception ex) { logger.Error(ex, "Error downloading to blackhole " + indexerID + " " + path); jsonReply["result"] = "error"; jsonReply["error"] = ex.Message; } return(Json(jsonReply)); }
public async Task <IActionResult> Download(string indexerID, string path, string jackett_apikey, string file) { try { if (serverConfig.APIKey != jackett_apikey) { return(Unauthorized()); } var indexer = indexerService.GetWebIndexer(indexerID); if (!indexer.IsConfigured) { logger.Warn(string.Format("Rejected a request to {0} which is unconfigured.", indexer.DisplayName)); return(Forbid("This indexer is not configured.")); } path = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(path)); path = protectionService.UnProtect(path); var target = new Uri(path, UriKind.RelativeOrAbsolute); var downloadBytes = await indexer.Download(target); // handle magnet URLs if (downloadBytes.Length >= 7 && downloadBytes[0] == 0x6d && // m downloadBytes[1] == 0x61 && // a downloadBytes[2] == 0x67 && // g downloadBytes[3] == 0x6e && // n downloadBytes[4] == 0x65 && // e downloadBytes[5] == 0x74 && // t downloadBytes[6] == 0x3a // : ) { // some sites provide magnet links with non-ascii characters, the only way to be sure the url // is well encoded is to unscape and escape again // https://github.com/Jackett/Jackett/issues/5372 // https://github.com/Jackett/Jackett/issues/4761 var magneturi = Uri.EscapeUriString(Uri.UnescapeDataString(Encoding.UTF8.GetString(downloadBytes))); return(Redirect(magneturi)); } // This will fix torrents where the keys are not sorted, and thereby not supported by Sonarr. byte[] sortedDownloadBytes = null; try { var parser = new BencodeParser(); var torrentDictionary = parser.Parse(downloadBytes); sortedDownloadBytes = torrentDictionary.EncodeAsBytes(); } catch (Exception e) { var content = indexer.Encoding.GetString(downloadBytes); logger.Error(content); throw new Exception("BencodeParser failed", e); } var fileName = StringUtil.MakeValidFileName(file, '_', false) + ".torrent"; // call MakeValidFileName again to avoid any kind of injection attack return(File(sortedDownloadBytes, "application/x-bittorrent", fileName)); } catch (Exception e) { logger.Error(e, "Error downloading " + indexerID + " " + path); return(NotFound()); } }
public async Task <IActionResult> Download(string indexerID, string path, string jackett_apikey, string file) { try { if (serverConfig.APIKey != jackett_apikey) { return(Unauthorized()); } var indexer = indexerService.GetWebIndexer(indexerID); if (!indexer.IsConfigured) { logger.Warn($"Rejected a request to {indexer.DisplayName} which is unconfigured."); return(Forbid("This indexer is not configured.")); } path = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(path)); path = protectionService.UnProtect(path); var target = new Uri(path, UriKind.RelativeOrAbsolute); var downloadBytes = await indexer.Download(target); // handle magnet URLs if (downloadBytes.Length >= 7 && downloadBytes[0] == 0x6d && // m downloadBytes[1] == 0x61 && // a downloadBytes[2] == 0x67 && // g downloadBytes[3] == 0x6e && // n downloadBytes[4] == 0x65 && // e downloadBytes[5] == 0x74 && // t downloadBytes[6] == 0x3a // : ) { var magnetUrl = Encoding.UTF8.GetString(downloadBytes); return(Redirect(magnetUrl)); } // This will fix torrents where the keys are not sorted, and thereby not supported by Sonarr. byte[] sortedDownloadBytes = null; try { var parser = new BencodeParser(); var torrentDictionary = parser.Parse(downloadBytes); sortedDownloadBytes = torrentDictionary.EncodeAsBytes(); } catch (Exception e) { var content = indexer.Encoding.GetString(downloadBytes); logger.Error(content); throw new Exception("BencodeParser failed", e); } var fileName = StringUtil.MakeValidFileName(file, '_', false) + ".torrent"; // call MakeValidFileName again to avoid any kind of injection attack return(File(sortedDownloadBytes, "application/x-bittorrent", fileName)); } catch (Exception e) { logger.Error($"Error downloading. indexer: {indexerID} path: {path}\n{e}"); return(NotFound()); } }