Merge pull request #4116 from cvium/add_known_proxies

Add Known Proxies to system configuration
This commit is contained in:
Bond-009 2020-09-10 14:10:26 +00:00 committed by GitHub
commit 4447589460
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 65 additions and 67 deletions

View File

@ -28,7 +28,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
var authorization = _authContext.GetAuthorizationInfo(requestContext); var authorization = _authContext.GetAuthorizationInfo(requestContext);
var user = authorization.User; var user = authorization.User;
return _sessionManager.LogSessionActivity(authorization.Client, authorization.Version, authorization.DeviceId, authorization.Device, requestContext.Request.RemoteIp(), user); return _sessionManager.LogSessionActivity(authorization.Client, authorization.Version, authorization.DeviceId, authorization.Device, requestContext.GetNormalizedRemoteIp(), user);
} }
public SessionInfo GetSession(object requestContext) public SessionInfo GetSession(object requestContext)

View File

@ -1,6 +1,7 @@
using System.Security.Claims; using System.Security.Claims;
using Jellyfin.Api.Helpers; using Jellyfin.Api.Helpers;
using Jellyfin.Data.Enums; using Jellyfin.Data.Enums;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Net; using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
@ -69,7 +70,7 @@ namespace Jellyfin.Api.Auth
return false; return false;
} }
var ip = RequestHelpers.NormalizeIp(_httpContextAccessor.HttpContext.Connection.RemoteIpAddress).ToString(); var ip = _httpContextAccessor.HttpContext.GetNormalizedRemoteIp();
var isInLocalNetwork = _networkManager.IsInLocalNetwork(ip); var isInLocalNetwork = _networkManager.IsInLocalNetwork(ip);
// User cannot access remotely and user is remote // User cannot access remotely and user is remote
if (!user.HasPermission(PermissionKind.EnableRemoteAccess) && !isInLocalNetwork) if (!user.HasPermission(PermissionKind.EnableRemoteAccess) && !isInLocalNetwork)

View File

@ -9,6 +9,7 @@ using Jellyfin.Api.Constants;
using Jellyfin.Api.Helpers; using Jellyfin.Api.Helpers;
using Jellyfin.Api.Models.MediaInfoDtos; using Jellyfin.Api.Models.MediaInfoDtos;
using Jellyfin.Api.Models.VideoDtos; using Jellyfin.Api.Models.VideoDtos;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Devices; using MediaBrowser.Controller.Devices;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Net;
@ -165,7 +166,7 @@ namespace Jellyfin.Api.Controllers
enableTranscoding, enableTranscoding,
allowVideoStreamCopy, allowVideoStreamCopy,
allowAudioStreamCopy, allowAudioStreamCopy,
Request.HttpContext.Connection.RemoteIpAddress.ToString()); Request.HttpContext.GetNormalizedRemoteIp());
} }
_mediaInfoHelper.SortMediaSources(info, maxStreamingBitrate); _mediaInfoHelper.SortMediaSources(info, maxStreamingBitrate);

View File

@ -9,6 +9,7 @@ using System.Threading.Tasks;
using Jellyfin.Api.Attributes; using Jellyfin.Api.Attributes;
using Jellyfin.Api.Constants; using Jellyfin.Api.Constants;
using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Net; using MediaBrowser.Common.Net;
using MediaBrowser.Controller; using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Configuration;
@ -178,8 +179,8 @@ namespace Jellyfin.Api.Controllers
{ {
return new EndPointInfo return new EndPointInfo
{ {
IsLocal = Request.HttpContext.Connection.LocalIpAddress.Equals(Request.HttpContext.Connection.RemoteIpAddress), IsLocal = HttpContext.IsLocal(),
IsInNetwork = _network.IsInLocalNetwork(Request.HttpContext.Connection.RemoteIpAddress.ToString()) IsInNetwork = _network.IsInLocalNetwork(HttpContext.GetNormalizedRemoteIp())
}; };
} }

View File

@ -8,6 +8,7 @@ using Jellyfin.Api.Attributes;
using Jellyfin.Api.Constants; using Jellyfin.Api.Constants;
using Jellyfin.Api.Helpers; using Jellyfin.Api.Helpers;
using Jellyfin.Api.Models.StreamingDtos; using Jellyfin.Api.Models.StreamingDtos;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Devices; using MediaBrowser.Controller.Devices;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.MediaEncoding;
@ -160,7 +161,7 @@ namespace Jellyfin.Api.Controllers
true, true,
true, true,
true, true,
Request.HttpContext.Connection.RemoteIpAddress.ToString()); Request.HttpContext.GetNormalizedRemoteIp());
} }
_mediaInfoHelper.SortMediaSources(info, maxStreamingBitrate); _mediaInfoHelper.SortMediaSources(info, maxStreamingBitrate);

View File

@ -7,6 +7,7 @@ using Jellyfin.Api.Constants;
using Jellyfin.Api.Helpers; using Jellyfin.Api.Helpers;
using Jellyfin.Api.Models.UserDtos; using Jellyfin.Api.Models.UserDtos;
using Jellyfin.Data.Enums; using Jellyfin.Data.Enums;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Net; using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Authentication; using MediaBrowser.Controller.Authentication;
using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Configuration;
@ -117,7 +118,7 @@ namespace Jellyfin.Api.Controllers
return NotFound("User not found"); return NotFound("User not found");
} }
var result = _userManager.GetUserDto(user, HttpContext.Connection.RemoteIpAddress.ToString()); var result = _userManager.GetUserDto(user, HttpContext.GetNormalizedRemoteIp());
return result; return result;
} }
@ -203,7 +204,7 @@ namespace Jellyfin.Api.Controllers
DeviceName = auth.Device, DeviceName = auth.Device,
Password = request.Pw, Password = request.Pw,
PasswordSha1 = request.Password, PasswordSha1 = request.Password,
RemoteEndPoint = HttpContext.Connection.RemoteIpAddress.ToString(), RemoteEndPoint = HttpContext.GetNormalizedRemoteIp(),
Username = request.Username Username = request.Username
}).ConfigureAwait(false); }).ConfigureAwait(false);
@ -212,7 +213,7 @@ namespace Jellyfin.Api.Controllers
catch (SecurityException e) catch (SecurityException e)
{ {
// rethrow adding IP address to message // rethrow adding IP address to message
throw new SecurityException($"[{HttpContext.Connection.RemoteIpAddress}] {e.Message}", e); throw new SecurityException($"[{HttpContext.GetNormalizedRemoteIp()}] {e.Message}", e);
} }
} }
@ -246,7 +247,7 @@ namespace Jellyfin.Api.Controllers
catch (SecurityException e) catch (SecurityException e)
{ {
// rethrow adding IP address to message // rethrow adding IP address to message
throw new SecurityException($"[{HttpContext.Connection.RemoteIpAddress}] {e.Message}", e); throw new SecurityException($"[{HttpContext.GetNormalizedRemoteIp()}] {e.Message}", e);
} }
} }
@ -290,7 +291,7 @@ namespace Jellyfin.Api.Controllers
user.Username, user.Username,
request.CurrentPw, request.CurrentPw,
request.CurrentPw, request.CurrentPw,
HttpContext.Connection.RemoteIpAddress.ToString(), HttpContext.GetNormalizedRemoteIp(),
false).ConfigureAwait(false); false).ConfigureAwait(false);
if (success == null) if (success == null)
@ -496,7 +497,7 @@ namespace Jellyfin.Api.Controllers
await _userManager.ChangePassword(newUser, request.Password).ConfigureAwait(false); await _userManager.ChangePassword(newUser, request.Password).ConfigureAwait(false);
} }
var result = _userManager.GetUserDto(newUser, HttpContext.Connection.RemoteIpAddress.ToString()); var result = _userManager.GetUserDto(newUser, HttpContext.GetNormalizedRemoteIp());
return result; return result;
} }
@ -511,8 +512,8 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
public async Task<ActionResult<ForgotPasswordResult>> ForgotPassword([FromBody] string? enteredUsername) public async Task<ActionResult<ForgotPasswordResult>> ForgotPassword([FromBody] string? enteredUsername)
{ {
var isLocal = HttpContext.Connection.RemoteIpAddress.Equals(HttpContext.Connection.LocalIpAddress) var isLocal = HttpContext.IsLocal()
|| _networkManager.IsInLocalNetwork(HttpContext.Connection.RemoteIpAddress.ToString()); || _networkManager.IsInLocalNetwork(HttpContext.GetNormalizedRemoteIp());
var result = await _userManager.StartForgotPasswordProcess(enteredUsername, isLocal).ConfigureAwait(false); var result = await _userManager.StartForgotPasswordProcess(enteredUsername, isLocal).ConfigureAwait(false);
@ -559,7 +560,7 @@ namespace Jellyfin.Api.Controllers
if (filterByNetwork) if (filterByNetwork)
{ {
if (!_networkManager.IsInLocalNetwork(HttpContext.Connection.RemoteIpAddress.ToString())) if (!_networkManager.IsInLocalNetwork(HttpContext.GetNormalizedRemoteIp()))
{ {
users = users.Where(i => i.HasPermission(PermissionKind.EnableRemoteAccess)); users = users.Where(i => i.HasPermission(PermissionKind.EnableRemoteAccess));
} }
@ -567,7 +568,7 @@ namespace Jellyfin.Api.Controllers
var result = users var result = users
.OrderBy(u => u.Username) .OrderBy(u => u.Username)
.Select(i => _userManager.GetUserDto(i, HttpContext.Connection.RemoteIpAddress.ToString())); .Select(i => _userManager.GetUserDto(i, HttpContext.GetNormalizedRemoteIp()));
return result; return result;
} }

View File

@ -8,6 +8,7 @@ using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Jellyfin.Api.Models.StreamingDtos; using Jellyfin.Api.Models.StreamingDtos;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Net; using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Devices; using MediaBrowser.Controller.Devices;
@ -198,12 +199,12 @@ namespace Jellyfin.Api.Helpers
if (!string.IsNullOrWhiteSpace(subtitleGroup)) if (!string.IsNullOrWhiteSpace(subtitleGroup))
{ {
AddSubtitles(state, subtitleStreams, builder, _httpContextAccessor.HttpContext.Request.HttpContext.User); AddSubtitles(state, subtitleStreams, builder, _httpContextAccessor.HttpContext.User);
} }
AppendPlaylist(builder, state, playlistUrl, totalBitrate, subtitleGroup); AppendPlaylist(builder, state, playlistUrl, totalBitrate, subtitleGroup);
if (EnableAdaptiveBitrateStreaming(state, isLiveStream, enableAdaptiveBitrateStreaming, _httpContextAccessor.HttpContext.Request.HttpContext.Connection.RemoteIpAddress)) if (EnableAdaptiveBitrateStreaming(state, isLiveStream, enableAdaptiveBitrateStreaming, _httpContextAccessor.HttpContext.GetNormalizedRemoteIp()))
{ {
var requestedVideoBitrate = state.VideoRequest == null ? 0 : state.VideoRequest.VideoBitRate ?? 0; var requestedVideoBitrate = state.VideoRequest == null ? 0 : state.VideoRequest.VideoBitRate ?? 0;
@ -334,11 +335,10 @@ namespace Jellyfin.Api.Helpers
} }
} }
private bool EnableAdaptiveBitrateStreaming(StreamState state, bool isLiveStream, bool enableAdaptiveBitrateStreaming, IPAddress ipAddress) private bool EnableAdaptiveBitrateStreaming(StreamState state, bool isLiveStream, bool enableAdaptiveBitrateStreaming, string ipAddress)
{ {
// Within the local network this will likely do more harm than good. // Within the local network this will likely do more harm than good.
var ip = RequestHelpers.NormalizeIp(ipAddress).ToString(); if (_networkManager.IsInLocalNetwork(ipAddress))
if (_networkManager.IsInLocalNetwork(ip))
{ {
return false; return false;
} }

View File

@ -6,6 +6,7 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Jellyfin.Data.Entities; using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums; using Jellyfin.Data.Enums;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Net; using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Devices; using MediaBrowser.Controller.Devices;
@ -498,7 +499,7 @@ namespace Jellyfin.Api.Helpers
true, true,
true, true,
true, true,
httpRequest.HttpContext.Connection.RemoteIpAddress.ToString()); httpRequest.HttpContext.GetNormalizedRemoteIp());
} }
else else
{ {

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using Jellyfin.Data.Enums; using Jellyfin.Data.Enums;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Session; using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Querying; using MediaBrowser.Model.Querying;
@ -119,7 +120,7 @@ namespace Jellyfin.Api.Helpers
authorization.Version, authorization.Version,
authorization.DeviceId, authorization.DeviceId,
authorization.Device, authorization.Device,
request.HttpContext.Connection.RemoteIpAddress.ToString(), request.HttpContext.GetNormalizedRemoteIp(),
user); user);
if (session == null) if (session == null)
@ -172,10 +173,5 @@ namespace Jellyfin.Api.Helpers
.Select(i => i!.Value) .Select(i => i!.Value)
.ToArray(); .ToArray();
} }
internal static IPAddress NormalizeIp(IPAddress ip)
{
return ip.IsIPv4MappedToIPv6 ? ip.MapToIPv4() : ip;
}
} }
} }

View File

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net;
using System.Reflection; using System.Reflection;
using Jellyfin.Api.Auth; using Jellyfin.Api.Auth;
using Jellyfin.Api.Auth.DefaultAuthorizationPolicy; using Jellyfin.Api.Auth.DefaultAuthorizationPolicy;
@ -28,6 +29,7 @@ using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen; using Swashbuckle.AspNetCore.SwaggerGen;
using AuthenticationSchemes = Jellyfin.Api.Constants.AuthenticationSchemes;
namespace Jellyfin.Server.Extensions namespace Jellyfin.Server.Extensions
{ {
@ -136,8 +138,9 @@ namespace Jellyfin.Server.Extensions
/// </summary> /// </summary>
/// <param name="serviceCollection">The service collection.</param> /// <param name="serviceCollection">The service collection.</param>
/// <param name="pluginAssemblies">An IEnumerable containing all plugin assemblies with API controllers.</param> /// <param name="pluginAssemblies">An IEnumerable containing all plugin assemblies with API controllers.</param>
/// <param name="knownProxies">A list of all known proxies to trust for X-Forwarded-For.</param>
/// <returns>The MVC builder.</returns> /// <returns>The MVC builder.</returns>
public static IMvcBuilder AddJellyfinApi(this IServiceCollection serviceCollection, IEnumerable<Assembly> pluginAssemblies) public static IMvcBuilder AddJellyfinApi(this IServiceCollection serviceCollection, IEnumerable<Assembly> pluginAssemblies, IReadOnlyList<string> knownProxies)
{ {
IMvcBuilder mvcBuilder = serviceCollection IMvcBuilder mvcBuilder = serviceCollection
.AddCors() .AddCors()
@ -145,6 +148,13 @@ namespace Jellyfin.Server.Extensions
.Configure<ForwardedHeadersOptions>(options => .Configure<ForwardedHeadersOptions>(options =>
{ {
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto; options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
for (var i = 0; i < knownProxies.Count; i++)
{
if (IPAddress.TryParse(knownProxies[i], out var address))
{
options.KnownProxies.Add(address);
}
}
}) })
.AddMvc(opts => .AddMvc(opts =>
{ {

View File

@ -32,13 +32,13 @@ namespace Jellyfin.Server.Middleware
/// <returns>The async task.</returns> /// <returns>The async task.</returns>
public async Task Invoke(HttpContext httpContext, INetworkManager networkManager, IServerConfigurationManager serverConfigurationManager) public async Task Invoke(HttpContext httpContext, INetworkManager networkManager, IServerConfigurationManager serverConfigurationManager)
{ {
if (httpContext.Request.IsLocal()) if (httpContext.IsLocal())
{ {
await _next(httpContext).ConfigureAwait(false); await _next(httpContext).ConfigureAwait(false);
return; return;
} }
var remoteIp = httpContext.Request.RemoteIp(); var remoteIp = httpContext.GetNormalizedRemoteIp();
if (serverConfigurationManager.Configuration.EnableRemoteAccess) if (serverConfigurationManager.Configuration.EnableRemoteAccess)
{ {

View File

@ -1,6 +1,7 @@
using System.Diagnostics; using System.Diagnostics;
using System.Globalization; using System.Globalization;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Configuration;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions; using Microsoft.AspNetCore.Http.Extensions;
@ -69,7 +70,7 @@ namespace Jellyfin.Server.Middleware
_logger.LogWarning( _logger.LogWarning(
"Slow HTTP Response from {url} to {remoteIp} in {elapsed:g} with Status Code {statusCode}", "Slow HTTP Response from {url} to {remoteIp} in {elapsed:g} with Status Code {statusCode}",
context.Request.GetDisplayUrl(), context.Request.GetDisplayUrl(),
context.Connection.RemoteIpAddress, context.GetNormalizedRemoteIp(),
watch.Elapsed, watch.Elapsed,
context.Response.StatusCode); context.Response.StatusCode);
} }

View File

@ -52,7 +52,7 @@ namespace Jellyfin.Server
{ {
options.HttpsPort = _serverApplicationHost.HttpsPort; options.HttpsPort = _serverApplicationHost.HttpsPort;
}); });
services.AddJellyfinApi(_serverApplicationHost.GetApiPluginAssemblies()); services.AddJellyfinApi(_serverApplicationHost.GetApiPluginAssemblies(), _serverConfigurationManager.Configuration.KnownProxies);
services.AddJellyfinApiSwagger(); services.AddJellyfinApiSwagger();
@ -103,6 +103,7 @@ namespace Jellyfin.Server
mainApp.UseDeveloperExceptionPage(); mainApp.UseDeveloperExceptionPage();
} }
mainApp.UseForwardedHeaders();
mainApp.UseMiddleware<ExceptionMiddleware>(); mainApp.UseMiddleware<ExceptionMiddleware>();
mainApp.UseMiddleware<ResponseTimeMiddleware>(); mainApp.UseMiddleware<ResponseTimeMiddleware>();

View File

@ -1,5 +1,4 @@
using System.Net; using System.Net;
using MediaBrowser.Common.Net;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
namespace MediaBrowser.Common.Extensions namespace MediaBrowser.Common.Extensions
@ -10,54 +9,33 @@ namespace MediaBrowser.Common.Extensions
public static class HttpContextExtensions public static class HttpContextExtensions
{ {
/// <summary> /// <summary>
/// Checks the origin of the HTTP request. /// Checks the origin of the HTTP context.
/// </summary> /// </summary>
/// <param name="request">The incoming HTTP request.</param> /// <param name="context">The incoming HTTP context.</param>
/// <returns><c>true</c> if the request is coming from LAN, <c>false</c> otherwise.</returns> /// <returns><c>true</c> if the request is coming from LAN, <c>false</c> otherwise.</returns>
public static bool IsLocal(this HttpRequest request) public static bool IsLocal(this HttpContext context)
{ {
return (request.HttpContext.Connection.LocalIpAddress == null return (context.Connection.LocalIpAddress == null
&& request.HttpContext.Connection.RemoteIpAddress == null) && context.Connection.RemoteIpAddress == null)
|| request.HttpContext.Connection.LocalIpAddress.Equals(request.HttpContext.Connection.RemoteIpAddress); || context.Connection.LocalIpAddress.Equals(context.Connection.RemoteIpAddress);
} }
/// <summary> /// <summary>
/// Extracts the remote IP address of the caller of the HTTP request. /// Extracts the remote IP address of the caller of the HTTP context.
/// </summary> /// </summary>
/// <param name="request">The HTTP request.</param> /// <param name="context">The HTTP context.</param>
/// <returns>The remote caller IP address.</returns> /// <returns>The remote caller IP address.</returns>
public static string RemoteIp(this HttpRequest request) public static string GetNormalizedRemoteIp(this HttpContext context)
{ {
var cachedRemoteIp = request.HttpContext.Items["RemoteIp"]?.ToString(); // Default to the loopback address if no RemoteIpAddress is specified (i.e. during integration tests)
if (!string.IsNullOrEmpty(cachedRemoteIp)) var ip = context.Connection.RemoteIpAddress ?? IPAddress.Loopback;
{
return cachedRemoteIp;
}
IPAddress ip;
// "Real" remote ip might be in X-Forwarded-For of X-Real-Ip
// (if the server is behind a reverse proxy for example)
if (!IPAddress.TryParse(request.Headers[CustomHeaderNames.XForwardedFor].ToString(), out ip))
{
if (!IPAddress.TryParse(request.Headers[CustomHeaderNames.XRealIP].ToString(), out ip))
{
ip = request.HttpContext.Connection.RemoteIpAddress;
// Default to the loopback address if no RemoteIpAddress is specified (i.e. during integration tests)
ip ??= IPAddress.Loopback;
}
}
if (ip.IsIPv4MappedToIPv6) if (ip.IsIPv4MappedToIPv6)
{ {
ip = ip.MapToIPv4(); ip = ip.MapToIPv4();
} }
var normalizedIp = ip.ToString(); return ip.ToString();
request.HttpContext.Items["RemoteIp"] = normalizedIp;
return normalizedIp;
} }
} }
} }

View File

@ -268,6 +268,11 @@ namespace MediaBrowser.Model.Configuration
/// </summary> /// </summary>
public string[] CorsHosts { get; set; } public string[] CorsHosts { get; set; }
/// <summary>
/// Gets or sets the known proxies.
/// </summary>
public string[] KnownProxies { get; set; }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ServerConfiguration" /> class. /// Initializes a new instance of the <see cref="ServerConfiguration" /> class.
/// </summary> /// </summary>
@ -378,6 +383,7 @@ namespace MediaBrowser.Model.Configuration
EnableSlowResponseWarning = true; EnableSlowResponseWarning = true;
SlowResponseThresholdMs = 500; SlowResponseThresholdMs = 500;
CorsHosts = new[] { "*" }; CorsHosts = new[] { "*" };
KnownProxies = Array.Empty<string>();
} }
} }