mirror of https://github.com/Jackett/Jackett
Refactor controllers for ASP.NET Core (Authentication disabled for now)
This commit is contained in:
parent
a752683965
commit
f162902b36
|
@ -1,39 +1,37 @@
|
|||
using Newtonsoft.Json.Linq;
|
||||
using Jackett.Common.Models.Config;
|
||||
using Jackett.Common.Services.Interfaces;
|
||||
using Jackett.Common.Utils;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NLog;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using System.Web.Http;
|
||||
using Jackett.Common.Models.Config;
|
||||
using Jackett.Common.Services.Interfaces;
|
||||
using Jackett.Common.Utils;
|
||||
|
||||
namespace Jackett.Controllers
|
||||
namespace Jackett.Server.Controllers
|
||||
{
|
||||
[AllowAnonymous]
|
||||
[JackettAPINoCache]
|
||||
public class BlackholeController : ApiController
|
||||
//[AllowAnonymous]
|
||||
[ResponseCache(Location = ResponseCacheLocation.None, NoStore = true)]
|
||||
[Route("bh/{indexerID}")]
|
||||
public class BlackholeController : Controller
|
||||
{
|
||||
private Logger logger;
|
||||
private IIndexerManagerService indexerService;
|
||||
private readonly ServerConfig serverConfig;
|
||||
IProtectionService protectionService;
|
||||
private IProtectionService protectionService;
|
||||
|
||||
public BlackholeController(IIndexerManagerService i, Logger l, ServerConfig config, IProtectionService ps)
|
||||
{
|
||||
logger = l;
|
||||
indexerService = i;
|
||||
serverConfig = config;
|
||||
|
||||
protectionService = ps;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IHttpActionResult> Blackhole(string indexerID, string path, string jackett_apikey, string file)
|
||||
public async Task<IActionResult> Blackhole(string indexerID, string path, string jackett_apikey, string file)
|
||||
{
|
||||
|
||||
var jsonReply = new JObject();
|
||||
try
|
||||
{
|
||||
|
@ -47,7 +45,7 @@ namespace Jackett.Controllers
|
|||
if (serverConfig.APIKey != jackett_apikey)
|
||||
throw new Exception("Incorrect API key");
|
||||
|
||||
path = Encoding.UTF8.GetString(HttpServerUtility.UrlTokenDecode(path));
|
||||
path = WebUtility.UrlDecode(path);
|
||||
path = protectionService.UnProtect(path);
|
||||
var remoteFile = new Uri(path, UriKind.RelativeOrAbsolute);
|
||||
var fileExtension = ".torrent";
|
||||
|
@ -81,9 +79,9 @@ namespace Jackett.Controllers
|
|||
if (string.IsNullOrWhiteSpace(file))
|
||||
fileName += fileExtension;
|
||||
else
|
||||
fileName += "-"+StringUtil.MakeValidFileName(file + fileExtension, '_', false); // call MakeValidFileName() again to avoid any possibility of path traversal attacks
|
||||
fileName += "-" + StringUtil.MakeValidFileName(file + fileExtension, '_', false); // call MakeValidFileName() again to avoid any possibility of path traversal attacks
|
||||
|
||||
File.WriteAllBytes(Path.Combine(serverConfig.BlackholeDir, fileName), downloadBytes);
|
||||
System.IO.File.WriteAllBytes(Path.Combine(serverConfig.BlackholeDir, fileName), downloadBytes);
|
||||
jsonReply["result"] = "success";
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
|
|
@ -1,26 +1,24 @@
|
|||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using System.Web.Http;
|
||||
using BencodeNET.Parsing;
|
||||
using BencodeNET.Parsing;
|
||||
using Jackett.Common.Models.Config;
|
||||
using Jackett.Common.Services.Interfaces;
|
||||
using Jackett.Common.Utils;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.WebUtilities;
|
||||
using NLog;
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Jackett.Controllers
|
||||
namespace Jackett.Server.Controllers
|
||||
{
|
||||
[AllowAnonymous]
|
||||
[JackettAPINoCache]
|
||||
public class DownloadController : ApiController
|
||||
//[AllowAnonymous]
|
||||
[ResponseCache(Location = ResponseCacheLocation.None, NoStore = true)]
|
||||
[Route("dl/{indexerID}")]
|
||||
public class DownloadController : Controller
|
||||
{
|
||||
private ServerConfig config;
|
||||
private Logger logger;
|
||||
private IIndexerManagerService indexerService;
|
||||
private IIndexerManagerService indexerService;
|
||||
private IProtectionService protectionService;
|
||||
|
||||
public DownloadController(IIndexerManagerService i, Logger l, IProtectionService ps, ServerConfig serverConfig)
|
||||
|
@ -32,7 +30,7 @@ namespace Jackett.Controllers
|
|||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<HttpResponseMessage> Download(string indexerID, string path, string jackett_apikey, string file)
|
||||
public async Task<IActionResult> Download(string indexerID, string path, string jackett_apikey, string file)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -41,14 +39,14 @@ namespace Jackett.Controllers
|
|||
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.");
|
||||
return Forbid("This indexer is not configured.");
|
||||
}
|
||||
|
||||
path = Encoding.UTF8.GetString(HttpServerUtility.UrlTokenDecode(path));
|
||||
path = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(path));
|
||||
path = protectionService.UnProtect(path);
|
||||
|
||||
if (config.APIKey != jackett_apikey)
|
||||
return new HttpResponseMessage(HttpStatusCode.Unauthorized);
|
||||
return Unauthorized();
|
||||
|
||||
var target = new Uri(path, UriKind.RelativeOrAbsolute);
|
||||
var downloadBytes = await indexer.Download(target);
|
||||
|
@ -65,9 +63,7 @@ namespace Jackett.Controllers
|
|||
)
|
||||
{
|
||||
var magneturi = Encoding.UTF8.GetString(downloadBytes);
|
||||
var response = Request.CreateResponse(HttpStatusCode.Moved);
|
||||
response.Headers.Location = new Uri(magneturi);
|
||||
return response;
|
||||
return Redirect(new Uri(magneturi).ToString());
|
||||
}
|
||||
|
||||
// This will fix torrents where the keys are not sorted, and thereby not supported by Sonarr.
|
||||
|
@ -75,19 +71,14 @@ namespace Jackett.Controllers
|
|||
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;
|
||||
string 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 new HttpResponseMessage(HttpStatusCode.NotFound);
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,21 +1,18 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web.Http;
|
||||
using System.Web.Http.Controllers;
|
||||
using System.Web.Http.Filters;
|
||||
using Jackett.Common;
|
||||
using Jackett.Common.Indexers;
|
||||
using Jackett.Common.Indexers;
|
||||
using Jackett.Common.Models;
|
||||
using Jackett.Common.Services.Interfaces;
|
||||
using Jackett.Common.Utils;
|
||||
using Jackett.Utils;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NLog;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Jackett.Controllers
|
||||
namespace Jackett.Server.Controllers
|
||||
{
|
||||
public interface IIndexerController
|
||||
{
|
||||
|
@ -23,19 +20,17 @@ namespace Jackett.Controllers
|
|||
IIndexer CurrentIndexer { get; set; }
|
||||
}
|
||||
|
||||
public class RequiresIndexerAttribute : ActionFilterAttribute
|
||||
public class RequiresIndexer : IActionFilter
|
||||
{
|
||||
public override void OnActionExecuting(HttpActionContext actionContext)
|
||||
public void OnActionExecuting(ActionExecutingContext context)
|
||||
{
|
||||
base.OnActionExecuting(actionContext);
|
||||
|
||||
var controller = actionContext.ControllerContext.Controller;
|
||||
var controller = context.Controller;
|
||||
if (!(controller is IIndexerController))
|
||||
return;
|
||||
|
||||
var indexerController = controller as IIndexerController;
|
||||
|
||||
var parameters = actionContext.RequestContext.RouteData.Values;
|
||||
var parameters = context.RouteData.Values;
|
||||
|
||||
if (!parameters.ContainsKey("indexerId"))
|
||||
{
|
||||
|
@ -51,15 +46,23 @@ namespace Jackett.Controllers
|
|||
var indexer = indexerService.GetIndexer(indexerId);
|
||||
indexerController.CurrentIndexer = indexer;
|
||||
}
|
||||
|
||||
public void OnActionExecuted(ActionExecutedContext context)
|
||||
{
|
||||
// do something after the action executes
|
||||
}
|
||||
}
|
||||
|
||||
[RoutePrefix("api/v2.0/indexers")]
|
||||
[JackettAuthorized]
|
||||
[JackettAPINoCache]
|
||||
public class IndexerApiController : ApiController, IIndexerController
|
||||
[Route("api/v2.0/indexers")]
|
||||
//[JackettAuthorized]
|
||||
[ResponseCache(Location = ResponseCacheLocation.None, NoStore = true)]
|
||||
public class IndexerApiController : Controller, IIndexerController
|
||||
{
|
||||
public IIndexerManagerService IndexerService { get; private set; }
|
||||
public IIndexer CurrentIndexer { get; set; }
|
||||
private Logger logger;
|
||||
private IServerService serverService;
|
||||
private ICacheService cacheService;
|
||||
|
||||
public IndexerApiController(IIndexerManagerService indexerManagerService, IServerService ss, ICacheService c, Logger logger)
|
||||
{
|
||||
|
@ -70,16 +73,17 @@ namespace Jackett.Controllers
|
|||
}
|
||||
|
||||
[HttpGet]
|
||||
[RequiresIndexer]
|
||||
public async Task<IHttpActionResult> Config()
|
||||
[TypeFilter(typeof(RequiresIndexer))]
|
||||
[Route("{indexerId?}/Config")]
|
||||
public async Task<IActionResult> Config()
|
||||
{
|
||||
var config = await CurrentIndexer.GetConfigurationForSetup();
|
||||
return Ok(config.ToJson(null));
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ActionName("Config")]
|
||||
[RequiresIndexer]
|
||||
[Route("{indexerId?}/Config")]
|
||||
[TypeFilter(typeof(RequiresIndexer))]
|
||||
public async Task UpdateConfig([FromBody]Common.Models.DTO.ConfigItem[] config)
|
||||
{
|
||||
try
|
||||
|
@ -111,14 +115,16 @@ namespace Jackett.Controllers
|
|||
}
|
||||
|
||||
[HttpPost]
|
||||
[RequiresIndexer]
|
||||
public async Task Test()
|
||||
[Route("{indexerid}/[action]")]
|
||||
[TypeFilter(typeof(RequiresIndexer))]
|
||||
public async Task<IActionResult> Test()
|
||||
{
|
||||
JToken jsonReply = new JObject();
|
||||
try
|
||||
{
|
||||
await IndexerService.TestIndexer(CurrentIndexer.ID);
|
||||
CurrentIndexer.LastError = null;
|
||||
return NoContent();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -134,8 +140,8 @@ namespace Jackett.Controllers
|
|||
}
|
||||
|
||||
[HttpDelete]
|
||||
[RequiresIndexer]
|
||||
[Route("{indexerId}")]
|
||||
[TypeFilter(typeof(RequiresIndexer))]
|
||||
[Route("{indexerid}")]
|
||||
public void Delete()
|
||||
{
|
||||
IndexerService.DeleteIndexer(CurrentIndexer.ID);
|
||||
|
@ -160,14 +166,10 @@ namespace Jackett.Controllers
|
|||
var link = result.Link;
|
||||
var file = StringUtil.MakeValidFileName(result.Title, '_', false);
|
||||
result.Link = serverService.ConvertToProxyLink(link, serverUrl, result.TrackerId, "dl", file);
|
||||
if (result.Link != null && result.Link.Scheme != "magnet" && !string.IsNullOrWhiteSpace(Engine.ServerConfig.BlackholeDir))
|
||||
if (result.Link != null && result.Link.Scheme != "magnet" && !string.IsNullOrWhiteSpace(serverService.GetBlackholeDirectory()))
|
||||
result.BlackholeLink = serverService.ConvertToProxyLink(link, serverUrl, result.TrackerId, "bh", file);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private Logger logger;
|
||||
private IServerService serverService;
|
||||
private ICacheService cacheService;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,59 +1,73 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web.Http;
|
||||
using System.Web.Http.Controllers;
|
||||
using System.Web.Http.Filters;
|
||||
using System.Xml.Linq;
|
||||
using Jackett.Common;
|
||||
using Jackett.Common;
|
||||
using Jackett.Common.Indexers;
|
||||
using Jackett.Common.Indexers.Meta;
|
||||
using Jackett.Common.Models;
|
||||
using Jackett.Common.Models.DTO;
|
||||
using Jackett.Common.Services.Interfaces;
|
||||
using Jackett.Common.Utils;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using NLog;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Jackett.Controllers
|
||||
namespace Jackett.Server.Controllers
|
||||
{
|
||||
public class RequiresApiKeyAttribute : AuthorizationFilterAttribute
|
||||
public class RequiresApiKey : IActionFilter
|
||||
{
|
||||
public override void OnAuthorization(HttpActionContext actionContext)
|
||||
public IServerService serverService;
|
||||
|
||||
public RequiresApiKey(IServerService ss)
|
||||
{
|
||||
var validApiKey = Engine.ServerConfig.APIKey;
|
||||
var queryParams = actionContext.Request.GetQueryNameValuePairs();
|
||||
serverService = ss;
|
||||
}
|
||||
|
||||
public void OnActionExecuting(ActionExecutingContext context)
|
||||
{
|
||||
var validApiKey = serverService.GetApiKey();
|
||||
var queryParams = context.HttpContext.Request.Query;
|
||||
var queryApiKey = queryParams.Where(x => x.Key == "apikey" || x.Key == "passkey").Select(x => x.Value).FirstOrDefault();
|
||||
|
||||
#if DEBUG
|
||||
if (Debugger.IsAttached)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (queryApiKey != validApiKey)
|
||||
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
|
||||
{
|
||||
context.Result = new UnauthorizedResult();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnActionExecuted(ActionExecutedContext context)
|
||||
{
|
||||
// do something after the action executes
|
||||
}
|
||||
}
|
||||
|
||||
public class RequiresConfiguredIndexerAttribute : ActionFilterAttribute
|
||||
public class RequiresConfiguredIndexer : IActionFilter
|
||||
{
|
||||
public override void OnActionExecuting(HttpActionContext actionContext)
|
||||
public void OnActionExecuting(ActionExecutingContext context)
|
||||
{
|
||||
var controller = actionContext.ControllerContext.Controller;
|
||||
var controller = context.Controller;
|
||||
if (!(controller is IIndexerController))
|
||||
return;
|
||||
|
||||
var indexerController = controller as IIndexerController;
|
||||
|
||||
var parameters = actionContext.RequestContext.RouteData.Values;
|
||||
var parameters = context.RouteData.Values;
|
||||
|
||||
if (!parameters.ContainsKey("indexerId"))
|
||||
{
|
||||
indexerController.CurrentIndexer = null;
|
||||
actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "Invalid parameter");
|
||||
context.Result = new UnauthorizedResult();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -61,7 +75,7 @@ namespace Jackett.Controllers
|
|||
if (indexerId.IsNullOrEmptyOrWhitespace())
|
||||
{
|
||||
indexerController.CurrentIndexer = null;
|
||||
actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "Invalid parameter");
|
||||
context.Result = new UnauthorizedResult();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -71,63 +85,68 @@ namespace Jackett.Controllers
|
|||
if (indexer == null)
|
||||
{
|
||||
indexerController.CurrentIndexer = null;
|
||||
actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "Invalid parameter");
|
||||
context.Result = new UnauthorizedResult();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!indexer.IsConfigured)
|
||||
{
|
||||
indexerController.CurrentIndexer = null;
|
||||
actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "Indexer is not configured");
|
||||
context.Result = new UnauthorizedResult();
|
||||
return;
|
||||
}
|
||||
|
||||
indexerController.CurrentIndexer = indexer;
|
||||
}
|
||||
|
||||
public void OnActionExecuted(ActionExecutedContext context)
|
||||
{
|
||||
// do something after the action executes
|
||||
}
|
||||
}
|
||||
|
||||
public class RequiresValidQueryAttribute : RequiresConfiguredIndexerAttribute
|
||||
public class RequiresValidQuery : IActionFilter
|
||||
{
|
||||
public override void OnActionExecuting(HttpActionContext actionContext)
|
||||
public void OnActionExecuting(ActionExecutingContext context)
|
||||
{
|
||||
base.OnActionExecuting(actionContext);
|
||||
if (actionContext.Response != null)
|
||||
return;
|
||||
//TODO: Not sure what this is meant to do
|
||||
//if (context.HttpContext.Response != null)
|
||||
// return;
|
||||
|
||||
var controller = actionContext.ControllerContext.Controller;
|
||||
var controller = context.Controller;
|
||||
if (!(controller is IResultController))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var resultController = controller as IResultController;
|
||||
|
||||
var query = actionContext.ActionArguments.First().Value;
|
||||
var query = context.ActionArguments.First().Value;
|
||||
var queryType = query.GetType();
|
||||
var converter = queryType.GetMethod("ToTorznabQuery", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public);
|
||||
if (converter == null)
|
||||
actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, "");
|
||||
{
|
||||
context.Result = new BadRequestResult();
|
||||
}
|
||||
|
||||
var converted = converter.Invoke(null, new object[] { query });
|
||||
var torznabQuery = converted as TorznabQuery;
|
||||
resultController.CurrentQuery = torznabQuery;
|
||||
|
||||
if (queryType == typeof(ApiSearch)) // Skip CanHandleQuery() check for manual search (CurrentIndexer isn't used during manul search)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!resultController.CurrentIndexer.CanHandleQuery(resultController.CurrentQuery))
|
||||
actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, $"{resultController.CurrentIndexer.ID} does not support the requested query. Please check the capabilities (t=caps) and make sure the search mode and categories are supported.");
|
||||
{
|
||||
context.Result = new BadRequestObjectResult($"{resultController.CurrentIndexer.ID} does not support the requested query. Please check the capabilities (t=caps) and make sure the search mode and categories are supported.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class JsonResponseAttribute : ActionFilterAttribute
|
||||
{
|
||||
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
|
||||
public void OnActionExecuted(ActionExecutedContext context)
|
||||
{
|
||||
base.OnActionExecuted(actionExecutedContext);
|
||||
|
||||
if (actionExecutedContext.Exception != null)
|
||||
throw new Exception("Error while executing request", actionExecutedContext.Exception);
|
||||
|
||||
var content = actionExecutedContext.Response.Content as ObjectContent;
|
||||
actionExecutedContext.Response.Content = new JsonContent(content.Value);
|
||||
// do something after the action executes
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,12 +155,13 @@ namespace Jackett.Controllers
|
|||
TorznabQuery CurrentQuery { get; set; }
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
[JackettAPINoCache]
|
||||
[RoutePrefix("api/v2.0/indexers")]
|
||||
[RequiresApiKey]
|
||||
[RequiresValidQuery]
|
||||
public class ResultsController : ApiController, IResultController
|
||||
//[AllowAnonymous]
|
||||
[ResponseCache(Location = ResponseCacheLocation.None, NoStore = true)]
|
||||
[Route("api/v2.0/indexers/{indexerId}/results")]
|
||||
[TypeFilter(typeof(RequiresApiKey))]
|
||||
[TypeFilter(typeof(RequiresConfiguredIndexer))]
|
||||
[TypeFilter(typeof(RequiresValidQuery))]
|
||||
public class ResultsController : Controller, IResultController
|
||||
{
|
||||
public IIndexerManagerService IndexerService { get; private set; }
|
||||
public IIndexer CurrentIndexer { get; set; }
|
||||
|
@ -155,13 +175,39 @@ namespace Jackett.Controllers
|
|||
this.logger = logger;
|
||||
}
|
||||
|
||||
[Route("")]
|
||||
[HttpGet]
|
||||
public async Task<ManualSearchResult> Results([FromUri]ApiSearch request)
|
||||
public async Task<IActionResult> Results([FromQuery] ApiSearch requestt)
|
||||
{
|
||||
//TODO: Better way to parse querystring
|
||||
|
||||
ApiSearch request = new ApiSearch();
|
||||
|
||||
foreach (var t in Request.Query)
|
||||
{
|
||||
if (t.Key == "Tracker[]")
|
||||
{
|
||||
request.Tracker = t.Value.ToString().Split(",");
|
||||
}
|
||||
|
||||
if (t.Key == "Category[]")
|
||||
{
|
||||
request.Category = t.Value.ToString().Split(",").Select(Int32.Parse).ToArray();
|
||||
}
|
||||
|
||||
if (t.Key == "query")
|
||||
{
|
||||
request.Query = t.Value.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
var manualResult = new ManualSearchResult();
|
||||
var trackers = IndexerService.GetAllIndexers().Where(t => t.IsConfigured);
|
||||
var trackers = IndexerService.GetAllIndexers().ToList().Where(t => t.IsConfigured);
|
||||
if (request.Tracker != null)
|
||||
{
|
||||
trackers = trackers.Where(t => request.Tracker.Contains(t.ID));
|
||||
}
|
||||
|
||||
trackers = trackers.Where(t => t.CanHandleQuery(CurrentQuery));
|
||||
|
||||
var tasks = trackers.ToList().Select(t => t.ResultsForQuery(CurrentQuery)).ToList();
|
||||
|
@ -235,18 +281,16 @@ namespace Jackett.Controllers
|
|||
ConfigureCacheResults(manualResult.Results);
|
||||
|
||||
logger.Info(string.Format("Manual search for \"{0}\" on {1} with {2} results.", CurrentQuery.SanitizedSearchTerm, string.Join(", ", manualResult.Indexers.Select(i => i.ID)), manualResult.Results.Count()));
|
||||
return manualResult;
|
||||
return Json(manualResult);
|
||||
}
|
||||
|
||||
[Route("[action]/{ignored?}")]
|
||||
[HttpGet]
|
||||
public async Task<IHttpActionResult> Torznab([FromUri]Common.Models.DTO.TorznabRequest request)
|
||||
public async Task<IActionResult> Torznab([FromQuery]TorznabRequest request)
|
||||
{
|
||||
if (string.Equals(CurrentQuery.QueryType, "caps", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
return ResponseMessage(new HttpResponseMessage()
|
||||
{
|
||||
Content = new StringContent(CurrentIndexer.TorznabCaps.ToXml(), Encoding.UTF8, "application/xml")
|
||||
});
|
||||
return Content(CurrentIndexer.TorznabCaps.ToXml(), "application/rss+xml", Encoding.UTF8);
|
||||
}
|
||||
|
||||
// indexers - returns a list of all included indexers (meta indexers only)
|
||||
|
@ -254,7 +298,7 @@ namespace Jackett.Controllers
|
|||
{
|
||||
if (!(CurrentIndexer is BaseMetaIndexer)) // shouldn't be needed because CanHandleQuery should return false
|
||||
{
|
||||
logger.Warn($"A search request with t=indexers from {Request.GetOwinContext().Request.RemoteIpAddress} was made but the indexer {CurrentIndexer.DisplayName} isn't a meta indexer.");
|
||||
logger.Warn($"A search request with t=indexers from {Request.HttpContext.Connection.RemoteIpAddress} was made but the indexer {CurrentIndexer.DisplayName} isn't a meta indexer.");
|
||||
return GetErrorXML(203, "Function Not Available: this isn't a meta indexer");
|
||||
}
|
||||
var CurrentBaseMetaIndexer = (BaseMetaIndexer)CurrentIndexer;
|
||||
|
@ -281,30 +325,27 @@ namespace Jackett.Controllers
|
|||
)
|
||||
);
|
||||
|
||||
return ResponseMessage(new HttpResponseMessage()
|
||||
{
|
||||
Content = new StringContent(xdoc.Declaration.ToString() + Environment.NewLine + xdoc.ToString(), Encoding.UTF8, "application/xml")
|
||||
});
|
||||
return Content(xdoc.Declaration.ToString() + Environment.NewLine + xdoc.ToString(), "application/xml", Encoding.UTF8);
|
||||
}
|
||||
|
||||
if (CurrentQuery.ImdbID != null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(CurrentQuery.SearchTerm))
|
||||
{
|
||||
logger.Warn($"A search request from {Request.GetOwinContext().Request.RemoteIpAddress} was made containing q and imdbid.");
|
||||
logger.Warn($"A search request from {Request.HttpContext.Connection.RemoteIpAddress} was made containing q and imdbid.");
|
||||
return GetErrorXML(201, "Incorrect parameter: please specify either imdbid or q");
|
||||
}
|
||||
|
||||
CurrentQuery.ImdbID = ParseUtil.GetFullImdbID(CurrentQuery.ImdbID); // normalize ImdbID
|
||||
if (CurrentQuery.ImdbID == null)
|
||||
{
|
||||
logger.Warn($"A search request from {Request.GetOwinContext().Request.RemoteIpAddress} was made with an invalid imdbid.");
|
||||
logger.Warn($"A search request from {Request.HttpContext.Connection.RemoteIpAddress} was made with an invalid imdbid.");
|
||||
return GetErrorXML(201, "Incorrect parameter: invalid imdbid format");
|
||||
}
|
||||
|
||||
if (!CurrentIndexer.TorznabCaps.SupportsImdbSearch)
|
||||
{
|
||||
logger.Warn($"A search request with imdbid from {Request.GetOwinContext().Request.RemoteIpAddress} was made but the indexer {CurrentIndexer.DisplayName} doesn't support it.");
|
||||
logger.Warn($"A search request with imdbid from {Request.HttpContext.Connection.RemoteIpAddress} was made but the indexer {CurrentIndexer.DisplayName} doesn't support it.");
|
||||
return GetErrorXML(203, "Function Not Available: imdbid is not supported by this indexer");
|
||||
}
|
||||
}
|
||||
|
@ -361,13 +402,12 @@ namespace Jackett.Controllers
|
|||
|
||||
var xml = resultPage.ToXml(new Uri(serverUrl));
|
||||
// Force the return as XML
|
||||
return ResponseMessage(new HttpResponseMessage()
|
||||
{
|
||||
Content = new StringContent(xml, Encoding.UTF8, "application/rss+xml")
|
||||
});
|
||||
|
||||
return Content(xml, "application/rss+xml", Encoding.UTF8);
|
||||
}
|
||||
|
||||
public IHttpActionResult GetErrorXML(int code, string description)
|
||||
[Route("[action]/{ignored?}")]
|
||||
public IActionResult GetErrorXML(int code, string description)
|
||||
{
|
||||
var xdoc = new XDocument(
|
||||
new XDeclaration("1.0", "UTF-8", null),
|
||||
|
@ -378,16 +418,12 @@ namespace Jackett.Controllers
|
|||
);
|
||||
|
||||
var xml = xdoc.Declaration.ToString() + Environment.NewLine + xdoc.ToString();
|
||||
|
||||
return ResponseMessage(new HttpResponseMessage()
|
||||
{
|
||||
Content = new StringContent(xml, Encoding.UTF8, "application/xml")
|
||||
});
|
||||
return Content(xml, "application/xml", Encoding.UTF8);
|
||||
}
|
||||
|
||||
[Route("[action]/{ignored?}")]
|
||||
[HttpGet]
|
||||
[JsonResponse]
|
||||
public async Task<TorrentPotatoResponse> Potato([FromUri]TorrentPotatoRequest request)
|
||||
public async Task<TorrentPotatoResponse> Potato([FromQuery]TorrentPotatoRequest request)
|
||||
{
|
||||
var result = await CurrentIndexer.ResultsForQuery(CurrentQuery);
|
||||
|
||||
|
@ -431,6 +467,7 @@ namespace Jackett.Controllers
|
|||
return potatoResponse;
|
||||
}
|
||||
|
||||
[Route("[action]/{ignored?}")]
|
||||
private void ConfigureCacheResults(IEnumerable<TrackerCacheResult> results)
|
||||
{
|
||||
var serverUrl = serverService.GetServerUrl(Request);
|
||||
|
@ -439,9 +476,8 @@ namespace Jackett.Controllers
|
|||
var link = result.Link;
|
||||
var file = StringUtil.MakeValidFileName(result.Title, '_', false);
|
||||
result.Link = serverService.ConvertToProxyLink(link, serverUrl, result.TrackerId, "dl", file);
|
||||
if (result.Link != null && result.Link.Scheme != "magnet" && !string.IsNullOrWhiteSpace(Engine.ServerConfig.BlackholeDir))
|
||||
if (result.Link != null && result.Link.Scheme != "magnet" && !string.IsNullOrWhiteSpace(serverService.GetBlackholeDirectory()))
|
||||
result.BlackholeLink = serverService.ConvertToProxyLink(link, serverUrl, result.TrackerId, "bh", file);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,23 +1,20 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Web.Http;
|
||||
using Jackett.Common;
|
||||
using Jackett.Common.Models;
|
||||
using Jackett.Common.Models;
|
||||
using Jackett.Common.Models.Config;
|
||||
using Jackett.Common.Services.Interfaces;
|
||||
using Jackett.Common.Utils;
|
||||
using Jackett.Utils;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using NLog;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Jackett.Controllers
|
||||
namespace Jackett.Server.Controllers
|
||||
{
|
||||
[RoutePrefix("api/v2.0/server")]
|
||||
[JackettAuthorized]
|
||||
[JackettAPINoCache]
|
||||
public class ServerConfigurationController : ApiController
|
||||
[Route("api/v2.0/server/[action]")]
|
||||
//[JackettAuthorized]
|
||||
[ResponseCache(Location = ResponseCacheLocation.None, NoStore = true)]
|
||||
public class ServerConfigurationController : Controller
|
||||
{
|
||||
private readonly IConfigurationService configService;
|
||||
private ServerConfig serverConfig;
|
||||
|
@ -29,7 +26,7 @@ namespace Jackett.Controllers
|
|||
private ILogCacheService logCache;
|
||||
private Logger logger;
|
||||
|
||||
public ServerConfigurationController(IConfigurationService c, IServerService s, IProcessService p, IIndexerManagerService i, ISecuityService ss, IUpdateService u, ILogCacheService lc, Logger l, ServerConfig sc)
|
||||
public ServerConfigurationController(IConfigurationService c, IServerService s, IProcessService p, IIndexerManagerService i, ISecuityService ss, IUpdateService u, ILogCacheService lc, Logger l, ServerConfig sc)
|
||||
{
|
||||
configService = c;
|
||||
serverConfig = sc;
|
||||
|
@ -65,14 +62,13 @@ namespace Jackett.Controllers
|
|||
[HttpGet]
|
||||
public Common.Models.DTO.ServerConfig Config()
|
||||
{
|
||||
|
||||
var dto = new Common.Models.DTO.ServerConfig(serverService.notices, serverConfig, configService.GetVersion());
|
||||
return dto;
|
||||
}
|
||||
|
||||
[ActionName("Config")]
|
||||
[HttpPost]
|
||||
public void UpdateConfig([FromBody]Common.Models.DTO.ServerConfig config)
|
||||
public IActionResult UpdateConfig([FromBody]Common.Models.DTO.ServerConfig config)
|
||||
{
|
||||
var originalPort = serverConfig.Port;
|
||||
var originalAllowExternal = serverConfig.AllowExternal;
|
||||
|
@ -95,16 +91,16 @@ namespace Jackett.Controllers
|
|||
serverConfig.UpdateDisabled = updateDisabled;
|
||||
serverConfig.UpdatePrerelease = preRelease;
|
||||
serverConfig.BasePathOverride = basePathOverride;
|
||||
serverConfig.RuntimeSettings.BasePath = Engine.Server.BasePath();
|
||||
serverConfig.RuntimeSettings.BasePath = serverService.BasePath();
|
||||
configService.SaveConfig(serverConfig);
|
||||
|
||||
Engine.SetLogLevel(logging ? LogLevel.Debug : LogLevel.Info);
|
||||
Initialisation.SetLogLevel(logging ? LogLevel.Debug : LogLevel.Info);
|
||||
serverConfig.RuntimeSettings.TracingEnabled = logging;
|
||||
|
||||
if (omdbApiKey != serverConfig.OmdbApiKey)
|
||||
{
|
||||
serverConfig.OmdbApiKey = omdbApiKey;
|
||||
configService.SaveConfig(serverConfig);
|
||||
configService.SaveConfig(serverConfig);
|
||||
// HACK
|
||||
indexerService.InitAggregateIndexer();
|
||||
}
|
||||
|
@ -128,7 +124,6 @@ namespace Jackett.Controllers
|
|||
|
||||
if (port != serverConfig.Port || external != serverConfig.AllowExternal)
|
||||
{
|
||||
|
||||
if (ServerUtil.RestrictedPorts.Contains(port))
|
||||
throw new Exception("The port you have selected is restricted, try a different one.");
|
||||
|
||||
|
@ -147,7 +142,8 @@ namespace Jackett.Controllers
|
|||
{
|
||||
try
|
||||
{
|
||||
processService.StartProcessAndLog(System.Windows.Forms.Application.ExecutablePath, "--ReserveUrls", true);
|
||||
//TODO
|
||||
//processService.StartProcessAndLog(System.Windows.Forms.Application.ExecutablePath, "--ReserveUrls", true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
@ -163,15 +159,15 @@ namespace Jackett.Controllers
|
|||
serverService.ReserveUrls(true);
|
||||
}
|
||||
}
|
||||
|
||||
(new Thread(() =>
|
||||
{
|
||||
Thread.Sleep(500);
|
||||
serverService.Stop();
|
||||
Engine.BuildContainer(serverConfig.RuntimeSettings, new WebApi2Module());
|
||||
Engine.Server.Initalize();
|
||||
Engine.Server.Start();
|
||||
})).Start();
|
||||
//TODO
|
||||
//(new Thread(() =>
|
||||
//{
|
||||
// Thread.Sleep(500);
|
||||
// serverService.Stop();
|
||||
// Engine.BuildContainer(serverConfig.RuntimeSettings, new WebApi2Module());
|
||||
// Engine.Server.Initalize();
|
||||
// Engine.Server.Start();
|
||||
//})).Start();
|
||||
}
|
||||
|
||||
if (saveDir != serverConfig.BlackholeDir)
|
||||
|
@ -187,8 +183,10 @@ namespace Jackett.Controllers
|
|||
serverConfig.BlackholeDir = saveDir;
|
||||
configService.SaveConfig(serverConfig);
|
||||
}
|
||||
|
||||
|
||||
serverConfig.ConfigChanged();
|
||||
|
||||
return Json(serverConfig);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
|
@ -196,7 +194,5 @@ namespace Jackett.Controllers
|
|||
{
|
||||
return logCache.Logs;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,21 +1,20 @@
|
|||
using System.IO;
|
||||
using Jackett.Common.Models.Config;
|
||||
using Jackett.Common.Services.Interfaces;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using MimeMapping;
|
||||
using NLog;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web.Http;
|
||||
using Jackett.Common.Models.Config;
|
||||
using Jackett.Common.Services.Interfaces;
|
||||
using Jackett.Utils;
|
||||
using MimeMapping;
|
||||
using NLog;
|
||||
|
||||
namespace Jackett.Controllers
|
||||
namespace Jackett.Server.Controllers
|
||||
{
|
||||
[RoutePrefix("UI")]
|
||||
[JackettAuthorized]
|
||||
[JackettAPINoCache]
|
||||
public class WebUIController : ApiController
|
||||
[Route("UI/[action]")]
|
||||
//[JackettAuthorized]
|
||||
[ResponseCache(Location = ResponseCacheLocation.None, NoStore = true)]
|
||||
public class WebUIController : Controller
|
||||
{
|
||||
private IConfigurationService config;
|
||||
private ServerConfig serverConfig;
|
||||
|
@ -42,50 +41,50 @@ namespace Jackett.Controllers
|
|||
}
|
||||
|
||||
[HttpGet]
|
||||
[AllowAnonymous]
|
||||
public IHttpActionResult Logout()
|
||||
//[AllowAnonymous]
|
||||
public IActionResult Logout()
|
||||
{
|
||||
var ctx = Request.GetOwinContext();
|
||||
var authManager = ctx.Authentication;
|
||||
authManager.SignOut("ApplicationCookie");
|
||||
return Redirect("UI/Dashboard");
|
||||
var ctx = Request.HttpContext;
|
||||
//TODO
|
||||
//var authManager = ctx.Authentication;
|
||||
//authManager.SignOut("ApplicationCookie");
|
||||
return Redirect("Dashboard");
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpPost]
|
||||
[AllowAnonymous]
|
||||
//[AllowAnonymous]
|
||||
public async Task<HttpResponseMessage> Dashboard()
|
||||
{
|
||||
if (Request.RequestUri.Query != null && Request.RequestUri.Query.Contains("logout"))
|
||||
if (Request.Path != null && Request.Path.ToString().Contains("logout"))
|
||||
{
|
||||
var file = GetFile("login.html");
|
||||
securityService.Logout(file);
|
||||
return file;
|
||||
}
|
||||
|
||||
//TODO
|
||||
|
||||
if (securityService.CheckAuthorised(Request))
|
||||
{
|
||||
return GetFile("index.html");
|
||||
//if (securityService.CheckAuthorised(Request))
|
||||
//{
|
||||
return GetFile("index.html");
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
var formData = await Request.Content.ReadAsFormDataAsync();
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// var formData = await Request.ReadFormAsync();
|
||||
|
||||
if (formData != null && securityService.HashPassword(formData["password"]) == serverConfig.AdminPassword)
|
||||
{
|
||||
var file = GetFile("index.html");
|
||||
securityService.Login(file);
|
||||
return file;
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetFile("login.html");
|
||||
}
|
||||
}
|
||||
// if (formData != null && securityService.HashPassword(formData["password"]) == serverConfig.AdminPassword)
|
||||
// {
|
||||
// var file = GetFile("index.html");
|
||||
// securityService.Login(file);
|
||||
// return file;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// return GetFile("login.html");
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Jackett.Server.Controllers
|
||||
{
|
||||
[Route("api/[controller]")]
|
||||
public class ValuesController : Controller
|
||||
{
|
||||
// GET api/values
|
||||
[HttpGet]
|
||||
public IEnumerable<string> Get()
|
||||
{
|
||||
return new string[] { "value1", "value2" };
|
||||
}
|
||||
|
||||
// GET api/values/5
|
||||
[HttpGet("{id}")]
|
||||
public string Get(int id)
|
||||
{
|
||||
return "value";
|
||||
}
|
||||
|
||||
// POST api/values
|
||||
[HttpPost]
|
||||
public void Post([FromBody]string value)
|
||||
{
|
||||
}
|
||||
|
||||
// PUT api/values/5
|
||||
[HttpPut("{id}")]
|
||||
public void Put(int id, [FromBody]string value)
|
||||
{
|
||||
}
|
||||
|
||||
// DELETE api/values/5
|
||||
[HttpDelete("{id}")]
|
||||
public void Delete(int id)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue