mirror of
https://github.com/Sonarr/Sonarr.git
synced 2025-02-22 12:51:52 +02:00
Added API key authentication
This commit is contained in:
parent
689f27bee6
commit
57fdbe6e08
@ -27,7 +27,10 @@ namespace NzbDrone.Api.Authentication
|
||||
private Response RequiresAuthentication(NancyContext context)
|
||||
{
|
||||
Response response = null;
|
||||
if (context.CurrentUser == null && _authenticationService.Enabled)
|
||||
|
||||
if (!context.Request.Path.StartsWith("/api/") &&
|
||||
context.CurrentUser == null &&
|
||||
_authenticationService.Enabled)
|
||||
{
|
||||
response = new Response { StatusCode = HttpStatusCode.Unauthorized };
|
||||
}
|
||||
|
50
NzbDrone.Api/Authentication/EnableStatelessAuthInNancy.cs
Normal file
50
NzbDrone.Api/Authentication/EnableStatelessAuthInNancy.cs
Normal file
@ -0,0 +1,50 @@
|
||||
using System.Linq;
|
||||
using Nancy;
|
||||
using Nancy.Bootstrapper;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
using NzbDrone.Core.Configuration;
|
||||
|
||||
namespace NzbDrone.Api.Authentication
|
||||
{
|
||||
public interface IEnableStatelessAuthInNancy
|
||||
{
|
||||
void Register(IPipelines pipelines);
|
||||
}
|
||||
|
||||
public class EnableStatelessAuthInNancy : IEnableStatelessAuthInNancy
|
||||
{
|
||||
private readonly IConfigFileProvider _configFileProvider;
|
||||
|
||||
public EnableStatelessAuthInNancy(IConfigFileProvider configFileProvider)
|
||||
{
|
||||
_configFileProvider = configFileProvider;
|
||||
}
|
||||
|
||||
public void Register(IPipelines pipelines)
|
||||
{
|
||||
pipelines.BeforeRequest.AddItemToEndOfPipeline(ValidateApiKey);
|
||||
}
|
||||
|
||||
public Response ValidateApiKey(NancyContext context)
|
||||
{
|
||||
Response response = null;
|
||||
var apiKey = context.Request.Headers["ApiKey"].FirstOrDefault();
|
||||
|
||||
if (!RuntimeInfo.IsProduction &&
|
||||
(context.Request.UserHostAddress.Equals("localhost") ||
|
||||
context.Request.UserHostAddress.Equals("127.0.0.1") ||
|
||||
context.Request.UserHostAddress.Equals("::1")))
|
||||
{
|
||||
return response;
|
||||
}
|
||||
|
||||
if (context.Request.Path.StartsWith("/api/") &&
|
||||
(apiKey == null || !apiKey.Equals(_configFileProvider.ApiKey)))
|
||||
{
|
||||
response = new Response { StatusCode = HttpStatusCode.Unauthorized };
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,20 +1,28 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Nancy;
|
||||
using Nancy.Responses;
|
||||
using NLog;
|
||||
using NzbDrone.Common;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
using NzbDrone.Core.Configuration;
|
||||
|
||||
namespace NzbDrone.Api.Frontend.Mappers
|
||||
{
|
||||
public class IndexHtmlMapper : StaticResourceMapperBase
|
||||
{
|
||||
private readonly IDiskProvider _diskProvider;
|
||||
private readonly IConfigFileProvider _configFileProvider;
|
||||
private readonly string _indexPath;
|
||||
|
||||
public IndexHtmlMapper(IAppFolderInfo appFolderInfo, IDiskProvider diskProvider, Logger logger)
|
||||
public IndexHtmlMapper(IAppFolderInfo appFolderInfo,
|
||||
IDiskProvider diskProvider,
|
||||
IConfigFileProvider configFileProvider,
|
||||
Logger logger)
|
||||
: base(diskProvider, logger)
|
||||
{
|
||||
_diskProvider = diskProvider;
|
||||
_configFileProvider = configFileProvider;
|
||||
_indexPath = Path.Combine(appFolderInfo.StartUpFolder, "UI", "index.html");
|
||||
}
|
||||
|
||||
@ -30,7 +38,21 @@ namespace NzbDrone.Api.Frontend.Mappers
|
||||
|
||||
public override Response GetResponse(string resourceUrl)
|
||||
{
|
||||
string content;
|
||||
var response = base.GetResponse(resourceUrl);
|
||||
var stream = new MemoryStream();
|
||||
|
||||
response.Contents.Invoke(stream);
|
||||
stream.Position = 0;
|
||||
|
||||
using (var reader = new StreamReader(stream))
|
||||
{
|
||||
content = reader.ReadToEnd();
|
||||
}
|
||||
|
||||
content = content.Replace("API_KEY", _configFileProvider.ApiKey);
|
||||
|
||||
response = new StreamResponse(() => StringToStream(content), response.ContentType);
|
||||
response.Headers["X-UA-Compatible"] = "IE=edge";
|
||||
|
||||
return response;
|
||||
@ -51,6 +73,5 @@ namespace NzbDrone.Api.Frontend.Mappers
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -24,13 +24,10 @@ namespace NzbDrone.Api.Frontend.Mappers
|
||||
{
|
||||
_caseSensitive = true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
protected abstract string Map(string resourceUrl);
|
||||
|
||||
|
||||
public abstract bool CanHandle(string resourceUrl);
|
||||
|
||||
public virtual Response GetResponse(string resourceUrl)
|
||||
|
@ -31,6 +31,7 @@ namespace NzbDrone.Api
|
||||
|
||||
container.Resolve<DatabaseTarget>().Register();
|
||||
container.Resolve<IEnableBasicAuthInNancy>().Register(pipelines);
|
||||
container.Resolve<IEnableStatelessAuthInNancy>().Register(pipelines);
|
||||
container.Resolve<IEventAggregator>().PublishEvent(new ApplicationStartedEvent());
|
||||
|
||||
ApplicationPipelines.OnError.AddItemToEndOfPipeline(container.Resolve<NzbDroneErrorPipeline>().HandleException);
|
||||
|
@ -74,6 +74,7 @@
|
||||
<Link>Properties\SharedAssemblyInfo.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="Authentication\AuthenticationService.cs" />
|
||||
<Compile Include="Authentication\EnableStatelessAuthInNancy.cs" />
|
||||
<Compile Include="Authentication\EnableBasicAuthInNancy.cs" />
|
||||
<Compile Include="Authentication\NzbDroneUser.cs" />
|
||||
<Compile Include="Calendar\CalendarModule.cs" />
|
||||
|
@ -26,6 +26,7 @@ namespace NzbDrone.Core.Configuration
|
||||
string Password { get; }
|
||||
string LogLevel { get; }
|
||||
string Branch { get; }
|
||||
string ApiKey { get; }
|
||||
bool Torrent { get; }
|
||||
}
|
||||
|
||||
@ -95,6 +96,14 @@ namespace NzbDrone.Core.Configuration
|
||||
get { return GetValueBoolean("LaunchBrowser", true); }
|
||||
}
|
||||
|
||||
public string ApiKey
|
||||
{
|
||||
get
|
||||
{
|
||||
return GetValue("ApiKey", Guid.NewGuid().ToString().Replace("-", ""));
|
||||
}
|
||||
}
|
||||
|
||||
public bool Torrent
|
||||
{
|
||||
get { return GetValueBoolean("Torrent", false, persist: false); }
|
||||
|
@ -20,9 +20,15 @@ define(function () {
|
||||
|
||||
delete xhr.data;
|
||||
}
|
||||
if (xhr) {
|
||||
if (!xhr.headers) {
|
||||
xhr.headers = {};
|
||||
}
|
||||
|
||||
xhr.headers["ApiKey"] = window.NzbDrone.ApiKey;
|
||||
}
|
||||
|
||||
return original.apply(this, arguments);
|
||||
};
|
||||
};
|
||||
|
||||
});
|
@ -1,10 +1,12 @@
|
||||
window.NzbDrone = {};
|
||||
window.NzbDrone.ApiRoot = '/api';
|
||||
|
||||
var statusText = $.ajax({
|
||||
type : 'GET',
|
||||
url : window.NzbDrone.ApiRoot + '/system/status',
|
||||
async: false
|
||||
async: false,
|
||||
headers: {
|
||||
ApiKey: window.NzbDrone.ApiKey
|
||||
}
|
||||
}).responseText;
|
||||
|
||||
window.NzbDrone.ServerStatus = JSON.parse(statusText);
|
||||
|
15
UI/app.js
15
UI/app.js
@ -33,12 +33,19 @@ require.config({
|
||||
$: {
|
||||
exports: '$',
|
||||
|
||||
init: function () {
|
||||
deps :
|
||||
[
|
||||
'Mixins/jquery.ajax'
|
||||
],
|
||||
|
||||
init: function (AjaxMixin) {
|
||||
require(
|
||||
[
|
||||
'jQuery/ToTheTop',
|
||||
'Instrumentation/ErrorHandler'
|
||||
]);
|
||||
|
||||
AjaxMixin.apply($);
|
||||
}
|
||||
|
||||
},
|
||||
@ -75,14 +82,10 @@ require.config({
|
||||
backbone: {
|
||||
deps :
|
||||
[
|
||||
'Mixins/backbone.ajax',
|
||||
'underscore',
|
||||
'$'
|
||||
],
|
||||
exports: 'Backbone',
|
||||
init : function (AjaxMixin) {
|
||||
AjaxMixin.apply(Backbone);
|
||||
}
|
||||
exports: 'Backbone'
|
||||
},
|
||||
|
||||
|
||||
|
@ -60,6 +60,12 @@
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
|
||||
<script type="text/javascript">
|
||||
window.NzbDrone = {};
|
||||
window.NzbDrone.ApiKey = 'API_KEY';
|
||||
</script>
|
||||
|
||||
<script src="/polyfills.js"></script>
|
||||
<script src="/JsLibraries/jquery.js"></script>
|
||||
<script src="/JsLibraries/messenger.js"></script>
|
||||
|
Loading…
x
Reference in New Issue
Block a user