From 00cbadea2c5ea8c717808fb4e8b11004509dc379 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 11 Nov 2016 02:24:36 -0500 Subject: update core project --- .../IO/ManagedFileSystem.cs | 5 + Emby.Common.Implementations/Net/NetSocket.cs | 6 +- Emby.Common.Implementations/Net/UdpSocket.cs | 2 +- .../Networking/BaseNetworkManager.cs | 485 -------------------- .../Networking/NetworkManager.cs | 506 +++++++++++++++++++++ Emby.Server.Core/FFMpeg/FFMpegLoader.cs | 240 ++++++++++ Emby.Server.Core/Localization/TextLocalizer.cs | 25 + .../Security/AuthenticationRepository.cs | 317 +++++++++++++ Emby.Server.Core/project.json | 7 + .../Emby.Server.Implementations.csproj | 5 + .../IO/MbLinkShortcutHandler.cs | 55 +++ MediaBrowser.Common/Net/INetworkManager.cs | 7 - .../Devices/CameraUploadsFolder.cs | 67 --- .../MediaBrowser.Controller.csproj | 2 - .../Playlists/ManualPlaylistsFolder.cs | 53 --- MediaBrowser.Model/IO/IFileSystem.cs | 2 + .../Devices/CameraUploadsFolder.cs | 67 +++ .../MediaBrowser.Server.Implementations.csproj | 6 +- .../Playlists/ManualPlaylistsFolder.cs | 53 +++ .../MediaBrowser.Server.Mono.csproj | 8 +- MediaBrowser.Server.Mono/Native/MonoApp.cs | 3 +- MediaBrowser.Server.Mono/Native/MonoFileSystem.cs | 21 + MediaBrowser.Server.Mono/Program.cs | 3 +- .../ApplicationHost.cs | 20 +- .../Cryptography/CertificateGenerator.cs | 2 +- .../FFMpeg/FFMpegLoader.cs | 249 ---------- .../MbLinkShortcutHandler.cs | 55 --- .../MediaBrowser.Server.Startup.Common.csproj | 5 - .../Networking/NetworkManager.cs | 50 -- .../Security/AuthenticationRepository.cs | 317 ------------- .../TextLocalizer.cs | 25 - MediaBrowser.ServerApplication/MainStartup.cs | 1 + .../MediaBrowser.ServerApplication.csproj | 7 +- .../Native/WindowsApp.cs | 1 - .../Networking/NetworkManager.cs | 2 +- 35 files changed, 1334 insertions(+), 1345 deletions(-) delete mode 100644 Emby.Common.Implementations/Networking/BaseNetworkManager.cs create mode 100644 Emby.Common.Implementations/Networking/NetworkManager.cs create mode 100644 Emby.Server.Core/FFMpeg/FFMpegLoader.cs create mode 100644 Emby.Server.Core/Localization/TextLocalizer.cs create mode 100644 Emby.Server.Core/Security/AuthenticationRepository.cs create mode 100644 Emby.Server.Implementations/IO/MbLinkShortcutHandler.cs delete mode 100644 MediaBrowser.Controller/Devices/CameraUploadsFolder.cs delete mode 100644 MediaBrowser.Controller/Playlists/ManualPlaylistsFolder.cs create mode 100644 MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs create mode 100644 MediaBrowser.Server.Implementations/Playlists/ManualPlaylistsFolder.cs create mode 100644 MediaBrowser.Server.Mono/Native/MonoFileSystem.cs delete mode 100644 MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegLoader.cs delete mode 100644 MediaBrowser.Server.Startup.Common/MbLinkShortcutHandler.cs delete mode 100644 MediaBrowser.Server.Startup.Common/Networking/NetworkManager.cs delete mode 100644 MediaBrowser.Server.Startup.Common/Security/AuthenticationRepository.cs delete mode 100644 MediaBrowser.Server.Startup.Common/TextLocalizer.cs diff --git a/Emby.Common.Implementations/IO/ManagedFileSystem.cs b/Emby.Common.Implementations/IO/ManagedFileSystem.cs index 37b4575987..81ca8dcff2 100644 --- a/Emby.Common.Implementations/IO/ManagedFileSystem.cs +++ b/Emby.Common.Implementations/IO/ManagedFileSystem.cs @@ -761,5 +761,10 @@ namespace Emby.Common.Implementations.IO var searchOption = recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly; return Directory.EnumerateFileSystemEntries(path, "*", searchOption); } + + public virtual void SetExecutable(string path) + { + + } } } diff --git a/Emby.Common.Implementations/Net/NetSocket.cs b/Emby.Common.Implementations/Net/NetSocket.cs index 72faa41a9a..faa1a81e2d 100644 --- a/Emby.Common.Implementations/Net/NetSocket.cs +++ b/Emby.Common.Implementations/Net/NetSocket.cs @@ -23,7 +23,7 @@ namespace Emby.Common.Implementations.Net { get { - return BaseNetworkManager.ToIpEndPointInfo((IPEndPoint)Socket.LocalEndPoint); + return NetworkManager.ToIpEndPointInfo((IPEndPoint)Socket.LocalEndPoint); } } @@ -31,7 +31,7 @@ namespace Emby.Common.Implementations.Net { get { - return BaseNetworkManager.ToIpEndPointInfo((IPEndPoint)Socket.RemoteEndPoint); + return NetworkManager.ToIpEndPointInfo((IPEndPoint)Socket.RemoteEndPoint); } } @@ -64,7 +64,7 @@ namespace Emby.Common.Implementations.Net public void Bind(IpEndPointInfo endpoint) { - var nativeEndpoint = BaseNetworkManager.ToIPEndPoint(endpoint); + var nativeEndpoint = NetworkManager.ToIPEndPoint(endpoint); Socket.Bind(nativeEndpoint); } diff --git a/Emby.Common.Implementations/Net/UdpSocket.cs b/Emby.Common.Implementations/Net/UdpSocket.cs index 244b37bb41..eca82034b0 100644 --- a/Emby.Common.Implementations/Net/UdpSocket.cs +++ b/Emby.Common.Implementations/Net/UdpSocket.cs @@ -175,7 +175,7 @@ namespace Emby.Common.Implementations.Net return null; } - return BaseNetworkManager.ToIpEndPointInfo(endpoint); + return NetworkManager.ToIpEndPointInfo(endpoint); } private void ProcessResponse(IAsyncResult asyncResult) diff --git a/Emby.Common.Implementations/Networking/BaseNetworkManager.cs b/Emby.Common.Implementations/Networking/BaseNetworkManager.cs deleted file mode 100644 index f1ac8413be..0000000000 --- a/Emby.Common.Implementations/Networking/BaseNetworkManager.cs +++ /dev/null @@ -1,485 +0,0 @@ -using MediaBrowser.Model.Logging; -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Net; -using System.Net.NetworkInformation; -using System.Net.Sockets; -using System.Threading.Tasks; -using MediaBrowser.Model.Extensions; -using MediaBrowser.Model.Net; - -namespace Emby.Common.Implementations.Networking -{ - public abstract class BaseNetworkManager - { - protected ILogger Logger { get; private set; } - private DateTime _lastRefresh; - - protected BaseNetworkManager(ILogger logger) - { - Logger = logger; - } - - private List _localIpAddresses; - private readonly object _localIpAddressSyncLock = new object(); - - public IEnumerable GetLocalIpAddresses() - { - const int cacheMinutes = 5; - - lock (_localIpAddressSyncLock) - { - var forceRefresh = (DateTime.UtcNow - _lastRefresh).TotalMinutes >= cacheMinutes; - - if (_localIpAddresses == null || forceRefresh) - { - var addresses = GetLocalIpAddressesInternal().Select(ToIpAddressInfo).ToList(); - - _localIpAddresses = addresses; - _lastRefresh = DateTime.UtcNow; - - return addresses; - } - } - - return _localIpAddresses; - } - - private IEnumerable GetLocalIpAddressesInternal() - { - var list = GetIPsDefault() - .ToList(); - - if (list.Count == 0) - { - list.AddRange(GetLocalIpAddressesFallback().Result); - } - - return list.Where(FilterIpAddress).DistinctBy(i => i.ToString()); - } - - private bool FilterIpAddress(IPAddress address) - { - var addressString = address.ToString(); - - if (addressString.StartsWith("169.", StringComparison.OrdinalIgnoreCase)) - { - return false; - } - - return true; - } - - public bool IsInPrivateAddressSpace(string endpoint) - { - if (string.Equals(endpoint, "::1", StringComparison.OrdinalIgnoreCase)) - { - return true; - } - - // Handle ipv4 mapped to ipv6 - endpoint = endpoint.Replace("::ffff:", string.Empty); - - // Private address space: - // http://en.wikipedia.org/wiki/Private_network - - if (endpoint.StartsWith("172.", StringComparison.OrdinalIgnoreCase)) - { - return Is172AddressPrivate(endpoint); - } - - return - - endpoint.StartsWith("localhost", StringComparison.OrdinalIgnoreCase) || - endpoint.StartsWith("127.", StringComparison.OrdinalIgnoreCase) || - endpoint.StartsWith("10.", StringComparison.OrdinalIgnoreCase) || - endpoint.StartsWith("192.168", StringComparison.OrdinalIgnoreCase) || - endpoint.StartsWith("169.", StringComparison.OrdinalIgnoreCase); - } - - private bool Is172AddressPrivate(string endpoint) - { - for (var i = 16; i <= 31; i++) - { - if (endpoint.StartsWith("172." + i.ToString(CultureInfo.InvariantCulture) + ".", StringComparison.OrdinalIgnoreCase)) - { - return true; - } - } - - return false; - } - - public bool IsInLocalNetwork(string endpoint) - { - return IsInLocalNetworkInternal(endpoint, true); - } - - public bool IsInLocalNetworkInternal(string endpoint, bool resolveHost) - { - if (string.IsNullOrWhiteSpace(endpoint)) - { - throw new ArgumentNullException("endpoint"); - } - - IPAddress address; - if (IPAddress.TryParse(endpoint, out address)) - { - var addressString = address.ToString(); - - int lengthMatch = 100; - if (address.AddressFamily == AddressFamily.InterNetwork) - { - lengthMatch = 4; - if (IsInPrivateAddressSpace(addressString)) - { - return true; - } - } - else if (address.AddressFamily == AddressFamily.InterNetworkV6) - { - lengthMatch = 10; - if (IsInPrivateAddressSpace(endpoint)) - { - return true; - } - } - - // Should be even be doing this with ipv6? - if (addressString.Length >= lengthMatch) - { - var prefix = addressString.Substring(0, lengthMatch); - - if (GetLocalIpAddresses().Any(i => i.ToString().StartsWith(prefix, StringComparison.OrdinalIgnoreCase))) - { - return true; - } - } - } - else if (resolveHost) - { - Uri uri; - if (Uri.TryCreate(endpoint, UriKind.RelativeOrAbsolute, out uri)) - { - try - { - var host = uri.DnsSafeHost; - Logger.Debug("Resolving host {0}", host); - - address = GetIpAddresses(host).Result.FirstOrDefault(); - - if (address != null) - { - Logger.Debug("{0} resolved to {1}", host, address); - - return IsInLocalNetworkInternal(address.ToString(), false); - } - } - catch (InvalidOperationException) - { - // Can happen with reverse proxy or IIS url rewriting - } - catch (Exception ex) - { - Logger.ErrorException("Error resovling hostname", ex); - } - } - } - - return false; - } - - private Task GetIpAddresses(string hostName) - { - return Dns.GetHostAddressesAsync(hostName); - } - - private List GetIPsDefault() - { - NetworkInterface[] interfaces; - - try - { - var validStatuses = new[] { OperationalStatus.Up, OperationalStatus.Unknown }; - - interfaces = NetworkInterface.GetAllNetworkInterfaces() - .Where(i => validStatuses.Contains(i.OperationalStatus)) - .ToArray(); - } - catch (Exception ex) - { - Logger.ErrorException("Error in GetAllNetworkInterfaces", ex); - return new List(); - } - - return interfaces.SelectMany(network => - { - - try - { - Logger.Debug("Querying interface: {0}. Type: {1}. Status: {2}", network.Name, network.NetworkInterfaceType, network.OperationalStatus); - - var properties = network.GetIPProperties(); - - return properties.UnicastAddresses - .Where(i => i.IsDnsEligible) - .Select(i => i.Address) - .Where(i => i.AddressFamily == AddressFamily.InterNetwork) - .ToList(); - } - catch (Exception ex) - { - Logger.ErrorException("Error querying network interface", ex); - return new List(); - } - - }).DistinctBy(i => i.ToString()) - .ToList(); - } - - private async Task> GetLocalIpAddressesFallback() - { - var host = await Dns.GetHostEntryAsync(Dns.GetHostName()).ConfigureAwait(false); - - // Reverse them because the last one is usually the correct one - // It's not fool-proof so ultimately the consumer will have to examine them and decide - return host.AddressList - .Where(i => i.AddressFamily == AddressFamily.InterNetwork) - .Reverse(); - } - - /// - /// Gets a random port number that is currently available - /// - /// System.Int32. - public int GetRandomUnusedPort() - { - var listener = new TcpListener(IPAddress.Any, 0); - listener.Start(); - var port = ((IPEndPoint)listener.LocalEndpoint).Port; - listener.Stop(); - return port; - } - - /// - /// Returns MAC Address from first Network Card in Computer - /// - /// [string] MAC Address - public string GetMacAddress() - { - return NetworkInterface.GetAllNetworkInterfaces() - .Where(i => i.NetworkInterfaceType != NetworkInterfaceType.Loopback) - .Select(i => BitConverter.ToString(i.GetPhysicalAddress().GetAddressBytes())) - .FirstOrDefault(); - } - - /// - /// Parses the specified endpointstring. - /// - /// The endpointstring. - /// IPEndPoint. - public IPEndPoint Parse(string endpointstring) - { - return Parse(endpointstring, -1).Result; - } - - /// - /// Parses the specified endpointstring. - /// - /// The endpointstring. - /// The defaultport. - /// IPEndPoint. - /// Endpoint descriptor may not be empty. - /// - private static async Task Parse(string endpointstring, int defaultport) - { - if (String.IsNullOrEmpty(endpointstring) - || endpointstring.Trim().Length == 0) - { - throw new ArgumentException("Endpoint descriptor may not be empty."); - } - - if (defaultport != -1 && - (defaultport < IPEndPoint.MinPort - || defaultport > IPEndPoint.MaxPort)) - { - throw new ArgumentException(String.Format("Invalid default port '{0}'", defaultport)); - } - - string[] values = endpointstring.Split(new char[] { ':' }); - IPAddress ipaddy; - int port = -1; - - //check if we have an IPv6 or ports - if (values.Length <= 2) // ipv4 or hostname - { - port = values.Length == 1 ? defaultport : GetPort(values[1]); - - //try to use the address as IPv4, otherwise get hostname - if (!IPAddress.TryParse(values[0], out ipaddy)) - ipaddy = await GetIPfromHost(values[0]).ConfigureAwait(false); - } - else if (values.Length > 2) //ipv6 - { - //could [a:b:c]:d - if (values[0].StartsWith("[") && values[values.Length - 2].EndsWith("]")) - { - string ipaddressstring = String.Join(":", values.Take(values.Length - 1).ToArray()); - ipaddy = IPAddress.Parse(ipaddressstring); - port = GetPort(values[values.Length - 1]); - } - else //[a:b:c] or a:b:c - { - ipaddy = IPAddress.Parse(endpointstring); - port = defaultport; - } - } - else - { - throw new FormatException(String.Format("Invalid endpoint ipaddress '{0}'", endpointstring)); - } - - if (port == -1) - throw new ArgumentException(String.Format("No port specified: '{0}'", endpointstring)); - - return new IPEndPoint(ipaddy, port); - } - - protected static readonly CultureInfo UsCulture = new CultureInfo("en-US"); - - /// - /// Gets the port. - /// - /// The p. - /// System.Int32. - /// - private static int GetPort(string p) - { - int port; - - if (!Int32.TryParse(p, out port) - || port < IPEndPoint.MinPort - || port > IPEndPoint.MaxPort) - { - throw new FormatException(String.Format("Invalid end point port '{0}'", p)); - } - - return port; - } - - /// - /// Gets the I pfrom host. - /// - /// The p. - /// IPAddress. - /// - private static async Task GetIPfromHost(string p) - { - var hosts = await Dns.GetHostAddressesAsync(p).ConfigureAwait(false); - - if (hosts == null || hosts.Length == 0) - throw new ArgumentException(String.Format("Host not found: {0}", p)); - - return hosts[0]; - } - - public IpAddressInfo ParseIpAddress(string ipAddress) - { - IpAddressInfo info; - if (TryParseIpAddress(ipAddress, out info)) - { - return info; - } - - throw new ArgumentException("Invalid ip address: " + ipAddress); - } - - public bool TryParseIpAddress(string ipAddress, out IpAddressInfo ipAddressInfo) - { - IPAddress address; - if (IPAddress.TryParse(ipAddress, out address)) - { - ipAddressInfo = ToIpAddressInfo(address); - return true; - } - - ipAddressInfo = null; - return false; - } - - public static IpEndPointInfo ToIpEndPointInfo(IPEndPoint endpoint) - { - if (endpoint == null) - { - return null; - } - - return new IpEndPointInfo(ToIpAddressInfo(endpoint.Address), endpoint.Port); - } - - public static IPEndPoint ToIPEndPoint(IpEndPointInfo endpoint) - { - if (endpoint == null) - { - return null; - } - - return new IPEndPoint(ToIPAddress(endpoint.IpAddress), endpoint.Port); - } - - public static IPAddress ToIPAddress(IpAddressInfo address) - { - if (address.Equals(IpAddressInfo.Any)) - { - return IPAddress.Any; - } - if (address.Equals(IpAddressInfo.IPv6Any)) - { - return IPAddress.IPv6Any; - } - if (address.Equals(IpAddressInfo.Loopback)) - { - return IPAddress.Loopback; - } - if (address.Equals(IpAddressInfo.IPv6Loopback)) - { - return IPAddress.IPv6Loopback; - } - - return IPAddress.Parse(address.Address); - } - - public static IpAddressInfo ToIpAddressInfo(IPAddress address) - { - if (address.Equals(IPAddress.Any)) - { - return IpAddressInfo.Any; - } - if (address.Equals(IPAddress.IPv6Any)) - { - return IpAddressInfo.IPv6Any; - } - if (address.Equals(IPAddress.Loopback)) - { - return IpAddressInfo.Loopback; - } - if (address.Equals(IPAddress.IPv6Loopback)) - { - return IpAddressInfo.IPv6Loopback; - } - return new IpAddressInfo - { - Address = address.ToString(), - AddressFamily = address.AddressFamily == AddressFamily.InterNetworkV6 ? IpAddressFamily.InterNetworkV6 : IpAddressFamily.InterNetwork - }; - } - - public async Task GetHostAddressesAsync(string host) - { - var addresses = await Dns.GetHostAddressesAsync(host).ConfigureAwait(false); - return addresses.Select(ToIpAddressInfo).ToArray(); - } - } -} diff --git a/Emby.Common.Implementations/Networking/NetworkManager.cs b/Emby.Common.Implementations/Networking/NetworkManager.cs new file mode 100644 index 0000000000..e336973377 --- /dev/null +++ b/Emby.Common.Implementations/Networking/NetworkManager.cs @@ -0,0 +1,506 @@ +using MediaBrowser.Model.Logging; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Net; +using System.Net.NetworkInformation; +using System.Net.Sockets; +using System.Threading.Tasks; +using MediaBrowser.Model.Extensions; +using MediaBrowser.Model.Net; +using MediaBrowser.Model.IO; +using MediaBrowser.Common.Net; + +namespace Emby.Common.Implementations.Networking +{ + public class NetworkManager : INetworkManager + { + protected ILogger Logger { get; private set; } + private DateTime _lastRefresh; + + public NetworkManager(ILogger logger) + { + Logger = logger; + } + + private List _localIpAddresses; + private readonly object _localIpAddressSyncLock = new object(); + + public IEnumerable GetLocalIpAddresses() + { + const int cacheMinutes = 5; + + lock (_localIpAddressSyncLock) + { + var forceRefresh = (DateTime.UtcNow - _lastRefresh).TotalMinutes >= cacheMinutes; + + if (_localIpAddresses == null || forceRefresh) + { + var addresses = GetLocalIpAddressesInternal().Select(ToIpAddressInfo).ToList(); + + _localIpAddresses = addresses; + _lastRefresh = DateTime.UtcNow; + + return addresses; + } + } + + return _localIpAddresses; + } + + private IEnumerable GetLocalIpAddressesInternal() + { + var list = GetIPsDefault() + .ToList(); + + if (list.Count == 0) + { + list.AddRange(GetLocalIpAddressesFallback().Result); + } + + return list.Where(FilterIpAddress).DistinctBy(i => i.ToString()); + } + + private bool FilterIpAddress(IPAddress address) + { + var addressString = address.ToString(); + + if (addressString.StartsWith("169.", StringComparison.OrdinalIgnoreCase)) + { + return false; + } + + return true; + } + + public bool IsInPrivateAddressSpace(string endpoint) + { + if (string.Equals(endpoint, "::1", StringComparison.OrdinalIgnoreCase)) + { + return true; + } + + // Handle ipv4 mapped to ipv6 + endpoint = endpoint.Replace("::ffff:", string.Empty); + + // Private address space: + // http://en.wikipedia.org/wiki/Private_network + + if (endpoint.StartsWith("172.", StringComparison.OrdinalIgnoreCase)) + { + return Is172AddressPrivate(endpoint); + } + + return + + endpoint.StartsWith("localhost", StringComparison.OrdinalIgnoreCase) || + endpoint.StartsWith("127.", StringComparison.OrdinalIgnoreCase) || + endpoint.StartsWith("10.", StringComparison.OrdinalIgnoreCase) || + endpoint.StartsWith("192.168", StringComparison.OrdinalIgnoreCase) || + endpoint.StartsWith("169.", StringComparison.OrdinalIgnoreCase); + } + + private bool Is172AddressPrivate(string endpoint) + { + for (var i = 16; i <= 31; i++) + { + if (endpoint.StartsWith("172." + i.ToString(CultureInfo.InvariantCulture) + ".", StringComparison.OrdinalIgnoreCase)) + { + return true; + } + } + + return false; + } + + public bool IsInLocalNetwork(string endpoint) + { + return IsInLocalNetworkInternal(endpoint, true); + } + + public bool IsInLocalNetworkInternal(string endpoint, bool resolveHost) + { + if (string.IsNullOrWhiteSpace(endpoint)) + { + throw new ArgumentNullException("endpoint"); + } + + IPAddress address; + if (IPAddress.TryParse(endpoint, out address)) + { + var addressString = address.ToString(); + + int lengthMatch = 100; + if (address.AddressFamily == AddressFamily.InterNetwork) + { + lengthMatch = 4; + if (IsInPrivateAddressSpace(addressString)) + { + return true; + } + } + else if (address.AddressFamily == AddressFamily.InterNetworkV6) + { + lengthMatch = 10; + if (IsInPrivateAddressSpace(endpoint)) + { + return true; + } + } + + // Should be even be doing this with ipv6? + if (addressString.Length >= lengthMatch) + { + var prefix = addressString.Substring(0, lengthMatch); + + if (GetLocalIpAddresses().Any(i => i.ToString().StartsWith(prefix, StringComparison.OrdinalIgnoreCase))) + { + return true; + } + } + } + else if (resolveHost) + { + Uri uri; + if (Uri.TryCreate(endpoint, UriKind.RelativeOrAbsolute, out uri)) + { + try + { + var host = uri.DnsSafeHost; + Logger.Debug("Resolving host {0}", host); + + address = GetIpAddresses(host).Result.FirstOrDefault(); + + if (address != null) + { + Logger.Debug("{0} resolved to {1}", host, address); + + return IsInLocalNetworkInternal(address.ToString(), false); + } + } + catch (InvalidOperationException) + { + // Can happen with reverse proxy or IIS url rewriting + } + catch (Exception ex) + { + Logger.ErrorException("Error resovling hostname", ex); + } + } + } + + return false; + } + + private Task GetIpAddresses(string hostName) + { + return Dns.GetHostAddressesAsync(hostName); + } + + private List GetIPsDefault() + { + NetworkInterface[] interfaces; + + try + { + var validStatuses = new[] { OperationalStatus.Up, OperationalStatus.Unknown }; + + interfaces = NetworkInterface.GetAllNetworkInterfaces() + .Where(i => validStatuses.Contains(i.OperationalStatus)) + .ToArray(); + } + catch (Exception ex) + { + Logger.ErrorException("Error in GetAllNetworkInterfaces", ex); + return new List(); + } + + return interfaces.SelectMany(network => + { + + try + { + Logger.Debug("Querying interface: {0}. Type: {1}. Status: {2}", network.Name, network.NetworkInterfaceType, network.OperationalStatus); + + var properties = network.GetIPProperties(); + + return properties.UnicastAddresses + .Where(i => i.IsDnsEligible) + .Select(i => i.Address) + .Where(i => i.AddressFamily == AddressFamily.InterNetwork) + .ToList(); + } + catch (Exception ex) + { + Logger.ErrorException("Error querying network interface", ex); + return new List(); + } + + }).DistinctBy(i => i.ToString()) + .ToList(); + } + + private async Task> GetLocalIpAddressesFallback() + { + var host = await Dns.GetHostEntryAsync(Dns.GetHostName()).ConfigureAwait(false); + + // Reverse them because the last one is usually the correct one + // It's not fool-proof so ultimately the consumer will have to examine them and decide + return host.AddressList + .Where(i => i.AddressFamily == AddressFamily.InterNetwork) + .Reverse(); + } + + /// + /// Gets a random port number that is currently available + /// + /// System.Int32. + public int GetRandomUnusedPort() + { + var listener = new TcpListener(IPAddress.Any, 0); + listener.Start(); + var port = ((IPEndPoint)listener.LocalEndpoint).Port; + listener.Stop(); + return port; + } + + /// + /// Returns MAC Address from first Network Card in Computer + /// + /// [string] MAC Address + public string GetMacAddress() + { + return NetworkInterface.GetAllNetworkInterfaces() + .Where(i => i.NetworkInterfaceType != NetworkInterfaceType.Loopback) + .Select(i => BitConverter.ToString(i.GetPhysicalAddress().GetAddressBytes())) + .FirstOrDefault(); + } + + /// + /// Parses the specified endpointstring. + /// + /// The endpointstring. + /// IPEndPoint. + public IPEndPoint Parse(string endpointstring) + { + return Parse(endpointstring, -1).Result; + } + + /// + /// Parses the specified endpointstring. + /// + /// The endpointstring. + /// The defaultport. + /// IPEndPoint. + /// Endpoint descriptor may not be empty. + /// + private static async Task Parse(string endpointstring, int defaultport) + { + if (String.IsNullOrEmpty(endpointstring) + || endpointstring.Trim().Length == 0) + { + throw new ArgumentException("Endpoint descriptor may not be empty."); + } + + if (defaultport != -1 && + (defaultport < IPEndPoint.MinPort + || defaultport > IPEndPoint.MaxPort)) + { + throw new ArgumentException(String.Format("Invalid default port '{0}'", defaultport)); + } + + string[] values = endpointstring.Split(new char[] { ':' }); + IPAddress ipaddy; + int port = -1; + + //check if we have an IPv6 or ports + if (values.Length <= 2) // ipv4 or hostname + { + port = values.Length == 1 ? defaultport : GetPort(values[1]); + + //try to use the address as IPv4, otherwise get hostname + if (!IPAddress.TryParse(values[0], out ipaddy)) + ipaddy = await GetIPfromHost(values[0]).ConfigureAwait(false); + } + else if (values.Length > 2) //ipv6 + { + //could [a:b:c]:d + if (values[0].StartsWith("[") && values[values.Length - 2].EndsWith("]")) + { + string ipaddressstring = String.Join(":", values.Take(values.Length - 1).ToArray()); + ipaddy = IPAddress.Parse(ipaddressstring); + port = GetPort(values[values.Length - 1]); + } + else //[a:b:c] or a:b:c + { + ipaddy = IPAddress.Parse(endpointstring); + port = defaultport; + } + } + else + { + throw new FormatException(String.Format("Invalid endpoint ipaddress '{0}'", endpointstring)); + } + + if (port == -1) + throw new ArgumentException(String.Format("No port specified: '{0}'", endpointstring)); + + return new IPEndPoint(ipaddy, port); + } + + protected static readonly CultureInfo UsCulture = new CultureInfo("en-US"); + + /// + /// Gets the port. + /// + /// The p. + /// System.Int32. + /// + private static int GetPort(string p) + { + int port; + + if (!Int32.TryParse(p, out port) + || port < IPEndPoint.MinPort + || port > IPEndPoint.MaxPort) + { + throw new FormatException(String.Format("Invalid end point port '{0}'", p)); + } + + return port; + } + + /// + /// Gets the I pfrom host. + /// + /// The p. + /// IPAddress. + /// + private static async Task GetIPfromHost(string p) + { + var hosts = await Dns.GetHostAddressesAsync(p).ConfigureAwait(false); + + if (hosts == null || hosts.Length == 0) + throw new ArgumentException(String.Format("Host not found: {0}", p)); + + return hosts[0]; + } + + public IpAddressInfo ParseIpAddress(string ipAddress) + { + IpAddressInfo info; + if (TryParseIpAddress(ipAddress, out info)) + { + return info; + } + + throw new ArgumentException("Invalid ip address: " + ipAddress); + } + + public bool TryParseIpAddress(string ipAddress, out IpAddressInfo ipAddressInfo) + { + IPAddress address; + if (IPAddress.TryParse(ipAddress, out address)) + { + ipAddressInfo = ToIpAddressInfo(address); + return true; + } + + ipAddressInfo = null; + return false; + } + + public static IpEndPointInfo ToIpEndPointInfo(IPEndPoint endpoint) + { + if (endpoint == null) + { + return null; + } + + return new IpEndPointInfo(ToIpAddressInfo(endpoint.Address), endpoint.Port); + } + + public static IPEndPoint ToIPEndPoint(IpEndPointInfo endpoint) + { + if (endpoint == null) + { + return null; + } + + return new IPEndPoint(ToIPAddress(endpoint.IpAddress), endpoint.Port); + } + + public static IPAddress ToIPAddress(IpAddressInfo address) + { + if (address.Equals(IpAddressInfo.Any)) + { + return IPAddress.Any; + } + if (address.Equals(IpAddressInfo.IPv6Any)) + { + return IPAddress.IPv6Any; + } + if (address.Equals(IpAddressInfo.Loopback)) + { + return IPAddress.Loopback; + } + if (address.Equals(IpAddressInfo.IPv6Loopback)) + { + return IPAddress.IPv6Loopback; + } + + return IPAddress.Parse(address.Address); + } + + public static IpAddressInfo ToIpAddressInfo(IPAddress address) + { + if (address.Equals(IPAddress.Any)) + { + return IpAddressInfo.Any; + } + if (address.Equals(IPAddress.IPv6Any)) + { + return IpAddressInfo.IPv6Any; + } + if (address.Equals(IPAddress.Loopback)) + { + return IpAddressInfo.Loopback; + } + if (address.Equals(IPAddress.IPv6Loopback)) + { + return IpAddressInfo.IPv6Loopback; + } + return new IpAddressInfo + { + Address = address.ToString(), + AddressFamily = address.AddressFamily == AddressFamily.InterNetworkV6 ? IpAddressFamily.InterNetworkV6 : IpAddressFamily.InterNetwork + }; + } + + public async Task GetHostAddressesAsync(string host) + { + var addresses = await Dns.GetHostAddressesAsync(host).ConfigureAwait(false); + return addresses.Select(ToIpAddressInfo).ToArray(); + } + + /// + /// Gets the network shares. + /// + /// The path. + /// IEnumerable{NetworkShare}. + public IEnumerable GetNetworkShares(string path) + { + return new List(); + } + + /// + /// Gets available devices within the domain + /// + /// PC's in the Domain + public IEnumerable GetNetworkDevices() + { + return new List(); + } + } +} diff --git a/Emby.Server.Core/FFMpeg/FFMpegLoader.cs b/Emby.Server.Core/FFMpeg/FFMpegLoader.cs new file mode 100644 index 0000000000..6b090102ab --- /dev/null +++ b/Emby.Server.Core/FFMpeg/FFMpegLoader.cs @@ -0,0 +1,240 @@ +using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Net; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Logging; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Emby.Server.Core; +using Emby.Server.Core.FFMpeg; + +namespace Emby.Server.Core.FFMpeg +{ + public class FFMpegLoader + { + private readonly IHttpClient _httpClient; + private readonly IApplicationPaths _appPaths; + private readonly ILogger _logger; + private readonly IZipClient _zipClient; + private readonly IFileSystem _fileSystem; + private readonly FFMpegInstallInfo _ffmpegInstallInfo; + + public FFMpegLoader(ILogger logger, IApplicationPaths appPaths, IHttpClient httpClient, IZipClient zipClient, IFileSystem fileSystem, FFMpegInstallInfo ffmpegInstallInfo) + { + _logger = logger; + _appPaths = appPaths; + _httpClient = httpClient; + _zipClient = zipClient; + _fileSystem = fileSystem; + _ffmpegInstallInfo = ffmpegInstallInfo; + } + + public async Task GetFFMpegInfo(StartupOptions options, IProgress progress) + { + var customffMpegPath = options.GetOption("-ffmpeg"); + var customffProbePath = options.GetOption("-ffprobe"); + + if (!string.IsNullOrWhiteSpace(customffMpegPath) && !string.IsNullOrWhiteSpace(customffProbePath)) + { + return new FFMpegInfo + { + ProbePath = customffProbePath, + EncoderPath = customffMpegPath, + Version = "external" + }; + } + + var downloadInfo = _ffmpegInstallInfo; + + var version = downloadInfo.Version; + + if (string.Equals(version, "path", StringComparison.OrdinalIgnoreCase)) + { + return new FFMpegInfo + { + ProbePath = downloadInfo.FFProbeFilename, + EncoderPath = downloadInfo.FFMpegFilename, + Version = version + }; + } + + if (string.Equals(version, "0", StringComparison.OrdinalIgnoreCase)) + { + return new FFMpegInfo(); + } + + var rootEncoderPath = Path.Combine(_appPaths.ProgramDataPath, "ffmpeg"); + var versionedDirectoryPath = Path.Combine(rootEncoderPath, version); + + var info = new FFMpegInfo + { + ProbePath = Path.Combine(versionedDirectoryPath, downloadInfo.FFProbeFilename), + EncoderPath = Path.Combine(versionedDirectoryPath, downloadInfo.FFMpegFilename), + Version = version + }; + + _fileSystem.CreateDirectory(versionedDirectoryPath); + + var excludeFromDeletions = new List { versionedDirectoryPath }; + + if (!_fileSystem.FileExists(info.ProbePath) || !_fileSystem.FileExists(info.EncoderPath)) + { + // ffmpeg not present. See if there's an older version we can start with + var existingVersion = GetExistingVersion(info, rootEncoderPath); + + // No older version. Need to download and block until complete + if (existingVersion == null) + { + var success = await DownloadFFMpeg(downloadInfo, versionedDirectoryPath, progress).ConfigureAwait(false); + if (!success) + { + return new FFMpegInfo(); + } + } + else + { + info = existingVersion; + versionedDirectoryPath = Path.GetDirectoryName(info.EncoderPath); + excludeFromDeletions.Add(versionedDirectoryPath); + } + } + + // Allow just one of these to be overridden, if desired. + if (!string.IsNullOrWhiteSpace(customffMpegPath)) + { + info.EncoderPath = customffMpegPath; + } + if (!string.IsNullOrWhiteSpace(customffProbePath)) + { + info.EncoderPath = customffProbePath; + } + + return info; + } + + private FFMpegInfo GetExistingVersion(FFMpegInfo info, string rootEncoderPath) + { + var encoderFilename = Path.GetFileName(info.EncoderPath); + var probeFilename = Path.GetFileName(info.ProbePath); + + foreach (var directory in Directory.EnumerateDirectories(rootEncoderPath, "*", SearchOption.TopDirectoryOnly) + .ToList()) + { + var allFiles = Directory.EnumerateFiles(directory, "*", SearchOption.AllDirectories).ToList(); + + var encoder = allFiles.FirstOrDefault(i => string.Equals(Path.GetFileName(i), encoderFilename, StringComparison.OrdinalIgnoreCase)); + var probe = allFiles.FirstOrDefault(i => string.Equals(Path.GetFileName(i), probeFilename, StringComparison.OrdinalIgnoreCase)); + + if (!string.IsNullOrWhiteSpace(encoder) && + !string.IsNullOrWhiteSpace(probe)) + { + return new FFMpegInfo + { + EncoderPath = encoder, + ProbePath = probe, + Version = Path.GetFileName(Path.GetDirectoryName(probe)) + }; + } + } + + return null; + } + + private async Task DownloadFFMpeg(FFMpegInstallInfo downloadinfo, string directory, IProgress progress) + { + foreach (var url in downloadinfo.DownloadUrls) + { + progress.Report(0); + + try + { + var tempFile = await _httpClient.GetTempFile(new HttpRequestOptions + { + Url = url, + CancellationToken = CancellationToken.None, + Progress = progress + + }).ConfigureAwait(false); + + ExtractFFMpeg(downloadinfo, tempFile, directory); + return true; + } + catch (Exception ex) + { + _logger.ErrorException("Error downloading {0}", ex, url); + } + } + return false; + } + + private void ExtractFFMpeg(FFMpegInstallInfo downloadinfo, string tempFile, string targetFolder) + { + _logger.Info("Extracting ffmpeg from {0}", tempFile); + + var tempFolder = Path.Combine(_appPaths.TempDirectory, Guid.NewGuid().ToString()); + + _fileSystem.CreateDirectory(tempFolder); + + try + { + ExtractArchive(downloadinfo, tempFile, tempFolder); + + var files = Directory.EnumerateFiles(tempFolder, "*", SearchOption.AllDirectories) + .ToList(); + + foreach (var file in files.Where(i => + { + var filename = Path.GetFileName(i); + + return + string.Equals(filename, downloadinfo.FFProbeFilename, StringComparison.OrdinalIgnoreCase) || + string.Equals(filename, downloadinfo.FFMpegFilename, StringComparison.OrdinalIgnoreCase); + })) + { + var targetFile = Path.Combine(targetFolder, Path.GetFileName(file)); + _fileSystem.CopyFile(file, targetFile, true); + SetFilePermissions(targetFile); + } + } + finally + { + DeleteFile(tempFile); + } + } + + private void SetFilePermissions(string path) + { + _fileSystem.SetExecutable(path); + } + + private void ExtractArchive(FFMpegInstallInfo downloadinfo, string archivePath, string targetPath) + { + _logger.Info("Extracting {0} to {1}", archivePath, targetPath); + + if (string.Equals(downloadinfo.ArchiveType, "7z", StringComparison.OrdinalIgnoreCase)) + { + _zipClient.ExtractAllFrom7z(archivePath, targetPath, true); + } + else if (string.Equals(downloadinfo.ArchiveType, "gz", StringComparison.OrdinalIgnoreCase)) + { + _zipClient.ExtractAllFromTar(archivePath, targetPath, true); + } + } + + private void DeleteFile(string path) + { + try + { + _fileSystem.DeleteFile(path); + } + catch (IOException ex) + { + _logger.ErrorException("Error deleting temp file {0}", ex, path); + } + } + + } +} diff --git a/Emby.Server.Core/Localization/TextLocalizer.cs b/Emby.Server.Core/Localization/TextLocalizer.cs new file mode 100644 index 0000000000..016d596590 --- /dev/null +++ b/Emby.Server.Core/Localization/TextLocalizer.cs @@ -0,0 +1,25 @@ +using System; +using System.Globalization; +using System.Linq; +using System.Text; +using Emby.Server.Implementations.Localization; + +namespace Emby.Server.Core.Localization +{ + public class TextLocalizer : ITextLocalizer + { + public string RemoveDiacritics(string text) + { + return String.Concat( + text.Normalize(NormalizationForm.FormD) + .Where(ch => CharUnicodeInfo.GetUnicodeCategory(ch) != + UnicodeCategory.NonSpacingMark) + ).Normalize(NormalizationForm.FormC); + } + + public string NormalizeFormKD(string text) + { + return text.Normalize(NormalizationForm.FormKD); + } + } +} diff --git a/Emby.Server.Core/Security/AuthenticationRepository.cs b/Emby.Server.Core/Security/AuthenticationRepository.cs new file mode 100644 index 0000000000..eaf91c710e --- /dev/null +++ b/Emby.Server.Core/Security/AuthenticationRepository.cs @@ -0,0 +1,317 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Globalization; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using Emby.Server.Core.Data; +using MediaBrowser.Controller; +using MediaBrowser.Controller.Security; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Querying; + +namespace Emby.Server.Core.Security +{ + public class AuthenticationRepository : BaseSqliteRepository, IAuthenticationRepository + { + private readonly IServerApplicationPaths _appPaths; + private readonly CultureInfo _usCulture = new CultureInfo("en-US"); + + public AuthenticationRepository(ILogManager logManager, IServerApplicationPaths appPaths, IDbConnector connector) + : base(logManager, connector) + { + _appPaths = appPaths; + DbFilePath = Path.Combine(appPaths.DataPath, "authentication.db"); + } + + public async Task Initialize() + { + using (var connection = await CreateConnection().ConfigureAwait(false)) + { + string[] queries = { + + "create table if not exists AccessTokens (Id GUID PRIMARY KEY, AccessToken TEXT NOT NULL, DeviceId TEXT, AppName TEXT, AppVersion TEXT, DeviceName TEXT, UserId TEXT, IsActive BIT, DateCreated DATETIME NOT NULL, DateRevoked DATETIME)", + "create index if not exists idx_AccessTokens on AccessTokens(Id)" + }; + + connection.RunQueries(queries, Logger); + + connection.AddColumn(Logger, "AccessTokens", "AppVersion", "TEXT"); + } + } + + public Task Create(AuthenticationInfo info, CancellationToken cancellationToken) + { + info.Id = Guid.NewGuid().ToString("N"); + + return Update(info, cancellationToken); + } + + public async Task Update(AuthenticationInfo info, CancellationToken cancellationToken) + { + if (info == null) + { + throw new ArgumentNullException("info"); + } + + cancellationToken.ThrowIfCancellationRequested(); + + using (var connection = await CreateConnection().ConfigureAwait(false)) + { + using (var saveInfoCommand = connection.CreateCommand()) + { + saveInfoCommand.CommandText = "replace into AccessTokens (Id, AccessToken, DeviceId, AppName, AppVersion, DeviceName, UserId, IsActive, DateCreated, DateRevoked) values (@Id, @AccessToken, @DeviceId, @AppName, @AppVersion, @DeviceName, @UserId, @IsActive, @DateCreated, @DateRevoked)"; + + saveInfoCommand.Parameters.Add(saveInfoCommand, "@Id"); + saveInfoCommand.Parameters.Add(saveInfoCommand, "@AccessToken"); + saveInfoCommand.Parameters.Add(saveInfoCommand, "@DeviceId"); + saveInfoCommand.Parameters.Add(saveInfoCommand, "@AppName"); + saveInfoCommand.Parameters.Add(saveInfoCommand, "@AppVersion"); + saveInfoCommand.Parameters.Add(saveInfoCommand, "@DeviceName"); + saveInfoCommand.Parameters.Add(saveInfoCommand, "@UserId"); + saveInfoCommand.Parameters.Add(saveInfoCommand, "@IsActive"); + saveInfoCommand.Parameters.Add(saveInfoCommand, "@DateCreated"); + saveInfoCommand.Parameters.Add(saveInfoCommand, "@DateRevoked"); + + IDbTransaction transaction = null; + + try + { + transaction = connection.BeginTransaction(); + + var index = 0; + + saveInfoCommand.GetParameter(index++).Value = new Guid(info.Id); + saveInfoCommand.GetParameter(index++).Value = info.AccessToken; + saveInfoCommand.GetParameter(index++).Value = info.DeviceId; + saveInfoCommand.GetParameter(index++).Value = info.AppName; + saveInfoCommand.GetParameter(index++).Value = info.AppVersion; + saveInfoCommand.GetParameter(index++).Value = info.DeviceName; + saveInfoCommand.GetParameter(index++).Value = info.UserId; + saveInfoCommand.GetParameter(index++).Value = info.IsActive; + saveInfoCommand.GetParameter(index++).Value = info.DateCreated; + saveInfoCommand.GetParameter(index++).Value = info.DateRevoked; + + saveInfoCommand.Transaction = transaction; + + saveInfoCommand.ExecuteNonQuery(); + + transaction.Commit(); + } + catch (OperationCanceledException) + { + if (transaction != null) + { + transaction.Rollback(); + } + + throw; + } + catch (Exception e) + { + Logger.ErrorException("Failed to save record:", e); + + if (transaction != null) + { + transaction.Rollback(); + } + + throw; + } + finally + { + if (transaction != null) + { + transaction.Dispose(); + } + } + } + } + } + + private const string BaseSelectText = "select Id, AccessToken, DeviceId, AppName, AppVersion, DeviceName, UserId, IsActive, DateCreated, DateRevoked from AccessTokens"; + + public QueryResult Get(AuthenticationInfoQuery query) + { + if (query == null) + { + throw new ArgumentNullException("query"); + } + + using (var connection = CreateConnection(true).Result) + { + using (var cmd = connection.CreateCommand()) + { + cmd.CommandText = BaseSelectText; + + var whereClauses = new List(); + + var startIndex = query.StartIndex ?? 0; + + if (!string.IsNullOrWhiteSpace(query.AccessToken)) + { + whereClauses.Add("AccessToken=@AccessToken"); + cmd.Parameters.Add(cmd, "@AccessToken", DbType.String).Value = query.AccessToken; + } + + if (!string.IsNullOrWhiteSpace(query.UserId)) + { + whereClauses.Add("UserId=@UserId"); + cmd.Parameters.Add(cmd, "@UserId", DbType.String).Value = query.UserId; + } + + if (!string.IsNullOrWhiteSpace(query.DeviceId)) + { + whereClauses.Add("DeviceId=@DeviceId"); + cmd.Parameters.Add(cmd, "@DeviceId", DbType.String).Value = query.DeviceId; + } + + if (query.IsActive.HasValue) + { + whereClauses.Add("IsActive=@IsActive"); + cmd.Parameters.Add(cmd, "@IsActive", DbType.Boolean).Value = query.IsActive.Value; + } + + if (query.HasUser.HasValue) + { + if (query.HasUser.Value) + { + whereClauses.Add("UserId not null"); + } + else + { + whereClauses.Add("UserId is null"); + } + } + + var whereTextWithoutPaging = whereClauses.Count == 0 ? + string.Empty : + " where " + string.Join(" AND ", whereClauses.ToArray()); + + if (startIndex > 0) + { + var pagingWhereText = whereClauses.Count == 0 ? + string.Empty : + " where " + string.Join(" AND ", whereClauses.ToArray()); + + whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM AccessTokens {0} ORDER BY DateCreated LIMIT {1})", + pagingWhereText, + startIndex.ToString(_usCulture))); + } + + var whereText = whereClauses.Count == 0 ? + string.Empty : + " where " + string.Join(" AND ", whereClauses.ToArray()); + + cmd.CommandText += whereText; + + cmd.CommandText += " ORDER BY DateCreated"; + + if (query.Limit.HasValue) + { + cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(_usCulture); + } + + cmd.CommandText += "; select count (Id) from AccessTokens" + whereTextWithoutPaging; + + var list = new List(); + var count = 0; + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) + { + while (reader.Read()) + { + list.Add(Get(reader)); + } + + if (reader.NextResult() && reader.Read()) + { + count = reader.GetInt32(0); + } + } + + return new QueryResult() + { + Items = list.ToArray(), + TotalRecordCount = count + }; + } + } + } + + public AuthenticationInfo Get(string id) + { + if (string.IsNullOrEmpty(id)) + { + throw new ArgumentNullException("id"); + } + + using (var connection = CreateConnection(true).Result) + { + var guid = new Guid(id); + + using (var cmd = connection.CreateCommand()) + { + cmd.CommandText = BaseSelectText + " where Id=@Id"; + + cmd.Parameters.Add(cmd, "@Id", DbType.Guid).Value = guid; + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow)) + { + if (reader.Read()) + { + return Get(reader); + } + } + } + + return null; + } + } + + private AuthenticationInfo Get(IDataReader reader) + { + var info = new AuthenticationInfo + { + Id = reader.GetGuid(0).ToString("N"), + AccessToken = reader.GetString(1) + }; + + if (!reader.IsDBNull(2)) + { + info.DeviceId = reader.GetString(2); + } + + if (!reader.IsDBNull(3)) + { + info.AppName = reader.GetString(3); + } + + if (!reader.IsDBNull(4)) + { + info.AppVersion = reader.GetString(4); + } + + if (!reader.IsDBNull(5)) + { + info.DeviceName = reader.GetString(5); + } + + if (!reader.IsDBNull(6)) + { + info.UserId = reader.GetString(6); + } + + info.IsActive = reader.GetBoolean(7); + info.DateCreated = reader.GetDateTime(8).ToUniversalTime(); + + if (!reader.IsDBNull(9)) + { + info.DateRevoked = reader.GetDateTime(9).ToUniversalTime(); + } + + return info; + } + } +} diff --git a/Emby.Server.Core/project.json b/Emby.Server.Core/project.json index e4e4741b13..8e120c8a11 100644 --- a/Emby.Server.Core/project.json +++ b/Emby.Server.Core/project.json @@ -28,6 +28,9 @@ }, "Emby.Server.Implementations": { "target": "project" + }, + "MediaBrowser.Server.Implementations": { + "target": "project" } } }, @@ -36,6 +39,7 @@ "dependencies": { "NETStandard.Library": "1.6.0", "System.AppDomain": "2.0.11", + "System.Globalization.Extensions": "4.0.1", "MediaBrowser.Model": { "target": "project" }, @@ -53,6 +57,9 @@ }, "Emby.Server.Implementations": { "target": "project" + }, + "MediaBrowser.Server.Implementations": { + "target": "project" } } } diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index 438edf212f..f65b8ac4aa 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -92,6 +92,7 @@ + @@ -270,6 +271,10 @@ {442b5058-dcaf-4263-bb6a-f21e31120a1b} MediaBrowser.Providers + + {2e781478-814d-4a48-9d80-bff206441a65} + MediaBrowser.Server.Implementations + ..\ThirdParty\ServiceStack\ServiceStack.dll diff --git a/Emby.Server.Implementations/IO/MbLinkShortcutHandler.cs b/Emby.Server.Implementations/IO/MbLinkShortcutHandler.cs new file mode 100644 index 0000000000..0b1391ae02 --- /dev/null +++ b/Emby.Server.Implementations/IO/MbLinkShortcutHandler.cs @@ -0,0 +1,55 @@ +using System; +using System.IO; +using MediaBrowser.Common.IO; +using MediaBrowser.Controller.IO; +using MediaBrowser.Model.IO; + +namespace Emby.Server.Implementations.IO +{ + public class MbLinkShortcutHandler : IShortcutHandler + { + private readonly IFileSystem _fileSystem; + + public MbLinkShortcutHandler(IFileSystem fileSystem) + { + _fileSystem = fileSystem; + } + + public string Extension + { + get { return ".mblink"; } + } + + public string Resolve(string shortcutPath) + { + if (string.IsNullOrEmpty(shortcutPath)) + { + throw new ArgumentNullException("filenshortcutPathame"); + } + + if (string.Equals(Path.GetExtension(shortcutPath), ".mblink", StringComparison.OrdinalIgnoreCase)) + { + var path = _fileSystem.ReadAllText(shortcutPath); + + return _fileSystem.NormalizePath(path); + } + + return null; + } + + public void Create(string shortcutPath, string targetPath) + { + if (string.IsNullOrEmpty(shortcutPath)) + { + throw new ArgumentNullException("shortcutPath"); + } + + if (string.IsNullOrEmpty(targetPath)) + { + throw new ArgumentNullException("targetPath"); + } + + _fileSystem.WriteAllText(shortcutPath, targetPath); + } + } +} diff --git a/MediaBrowser.Common/Net/INetworkManager.cs b/MediaBrowser.Common/Net/INetworkManager.cs index 779db0a828..5ac701f820 100644 --- a/MediaBrowser.Common/Net/INetworkManager.cs +++ b/MediaBrowser.Common/Net/INetworkManager.cs @@ -54,12 +54,5 @@ namespace MediaBrowser.Common.Net bool TryParseIpAddress(string ipAddress, out IpAddressInfo ipAddressInfo); Task GetHostAddressesAsync(string host); - - /// - /// Generates a self signed certificate at the locatation specified by . - /// - /// The path to generate the certificate. - /// The common name for the certificate. - void GenerateSelfSignedSslCertificate(string certificatePath, string hostname); } } \ No newline at end of file diff --git a/MediaBrowser.Controller/Devices/CameraUploadsFolder.cs b/MediaBrowser.Controller/Devices/CameraUploadsFolder.cs deleted file mode 100644 index 979a929ca7..0000000000 --- a/MediaBrowser.Controller/Devices/CameraUploadsFolder.cs +++ /dev/null @@ -1,67 +0,0 @@ -using MediaBrowser.Common.Configuration; -using MediaBrowser.Controller.Entities; -using System; -using System.IO; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using MediaBrowser.Common.IO; -using MediaBrowser.Controller.IO; -using MediaBrowser.Model.IO; -using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Serialization; - -namespace MediaBrowser.Server.Implementations.Devices -{ - public class CameraUploadsFolder : BasePluginFolder, ISupportsUserSpecificView - { - public CameraUploadsFolder() - { - Name = "Camera Uploads"; - } - - public override bool IsVisible(User user) - { - if (!user.Policy.EnableAllFolders && !user.Policy.EnabledFolders.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase)) - { - return false; - } - - return base.IsVisible(user) && HasChildren(); - } - - [IgnoreDataMember] - public override string CollectionType - { - get { return Model.Entities.CollectionType.Photos; } - } - - public override string GetClientTypeName() - { - return typeof(CollectionFolder).Name; - } - - private bool? _hasChildren; - private bool HasChildren() - { - if (!_hasChildren.HasValue) - { - _hasChildren = LibraryManager.GetItemIds(new InternalItemsQuery { ParentId = Id }).Count > 0; - } - - return _hasChildren.Value; - } - - protected override Task ValidateChildrenInternal(IProgress progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService) - { - _hasChildren = null; - return base.ValidateChildrenInternal(progress, cancellationToken, recursive, refreshChildMetadata, refreshOptions, directoryService); - } - - [IgnoreDataMember] - public bool EnableUserSpecificView - { - get { return true; } - } - } -} diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index d867b15123..518daa6d75 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -77,7 +77,6 @@ - @@ -218,7 +217,6 @@ - diff --git a/MediaBrowser.Controller/Playlists/ManualPlaylistsFolder.cs b/MediaBrowser.Controller/Playlists/ManualPlaylistsFolder.cs deleted file mode 100644 index 07773d846b..0000000000 --- a/MediaBrowser.Controller/Playlists/ManualPlaylistsFolder.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using MediaBrowser.Common.Configuration; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Playlists; -using MediaBrowser.Model.IO; -using MediaBrowser.Model.Querying; -using MediaBrowser.Model.Serialization; - -namespace MediaBrowser.Server.Implementations.Playlists -{ - public class PlaylistsFolder : BasePluginFolder - { - public PlaylistsFolder() - { - Name = "Playlists"; - } - - public override bool IsVisible(User user) - { - return base.IsVisible(user) && GetChildren(user, true).Any(); - } - - protected override IEnumerable GetEligibleChildrenForRecursiveChildren(User user) - { - return base.GetEligibleChildrenForRecursiveChildren(user).OfType(); - } - - [IgnoreDataMember] - public override bool IsHidden - { - get - { - return true; - } - } - - [IgnoreDataMember] - public override string CollectionType - { - get { return MediaBrowser.Model.Entities.CollectionType.Playlists; } - } - - protected override Task> GetItemsInternal(InternalItemsQuery query) - { - query.Recursive = false; - return base.GetItemsInternal(query); - } - } -} - diff --git a/MediaBrowser.Model/IO/IFileSystem.cs b/MediaBrowser.Model/IO/IFileSystem.cs index d2bb355203..f219d92959 100644 --- a/MediaBrowser.Model/IO/IFileSystem.cs +++ b/MediaBrowser.Model/IO/IFileSystem.cs @@ -312,6 +312,8 @@ namespace MediaBrowser.Model.IO string GetFullPath(string path); List GetDrives(); + + void SetExecutable(string path); } public enum FileOpenMode diff --git a/MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs b/MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs new file mode 100644 index 0000000000..979a929ca7 --- /dev/null +++ b/MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs @@ -0,0 +1,67 @@ +using MediaBrowser.Common.Configuration; +using MediaBrowser.Controller.Entities; +using System; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Common.IO; +using MediaBrowser.Controller.IO; +using MediaBrowser.Model.IO; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Serialization; + +namespace MediaBrowser.Server.Implementations.Devices +{ + public class CameraUploadsFolder : BasePluginFolder, ISupportsUserSpecificView + { + public CameraUploadsFolder() + { + Name = "Camera Uploads"; + } + + public override bool IsVisible(User user) + { + if (!user.Policy.EnableAllFolders && !user.Policy.EnabledFolders.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase)) + { + return false; + } + + return base.IsVisible(user) && HasChildren(); + } + + [IgnoreDataMember] + public override string CollectionType + { + get { return Model.Entities.CollectionType.Photos; } + } + + public override string GetClientTypeName() + { + return typeof(CollectionFolder).Name; + } + + private bool? _hasChildren; + private bool HasChildren() + { + if (!_hasChildren.HasValue) + { + _hasChildren = LibraryManager.GetItemIds(new InternalItemsQuery { ParentId = Id }).Count > 0; + } + + return _hasChildren.Value; + } + + protected override Task ValidateChildrenInternal(IProgress progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService) + { + _hasChildren = null; + return base.ValidateChildrenInternal(progress, cancellationToken, recursive, refreshChildMetadata, refreshOptions, directoryService); + } + + [IgnoreDataMember] + public bool EnableUserSpecificView + { + get { return true; } + } + } +} diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index 16c45f2e51..3bfbff6e67 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -44,13 +44,11 @@ Properties\SharedVersion.cs + + - - {e383961b-9356-4d5d-8233-9a1079d03055} - Emby.Server.Implementations - {9142EEFA-7570-41E1-BFCC-468BB571AF2F} MediaBrowser.Common diff --git a/MediaBrowser.Server.Implementations/Playlists/ManualPlaylistsFolder.cs b/MediaBrowser.Server.Implementations/Playlists/ManualPlaylistsFolder.cs new file mode 100644 index 0000000000..07773d846b --- /dev/null +++ b/MediaBrowser.Server.Implementations/Playlists/ManualPlaylistsFolder.cs @@ -0,0 +1,53 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Playlists; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Querying; +using MediaBrowser.Model.Serialization; + +namespace MediaBrowser.Server.Implementations.Playlists +{ + public class PlaylistsFolder : BasePluginFolder + { + public PlaylistsFolder() + { + Name = "Playlists"; + } + + public override bool IsVisible(User user) + { + return base.IsVisible(user) && GetChildren(user, true).Any(); + } + + protected override IEnumerable GetEligibleChildrenForRecursiveChildren(User user) + { + return base.GetEligibleChildrenForRecursiveChildren(user).OfType(); + } + + [IgnoreDataMember] + public override bool IsHidden + { + get + { + return true; + } + } + + [IgnoreDataMember] + public override string CollectionType + { + get { return MediaBrowser.Model.Entities.CollectionType.Playlists; } + } + + protected override Task> GetItemsInternal(InternalItemsQuery query) + { + query.Recursive = false; + return base.GetItemsInternal(query); + } + } +} + diff --git a/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj b/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj index d59725d1d1..b62d99a136 100644 --- a/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj +++ b/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj @@ -77,9 +77,6 @@ True - - ..\ThirdParty\ServiceStack\ServiceStack.Interfaces.dll - ..\ThirdParty\MediaBrowser.IsoMounting.Linux\MediaBrowser.IsoMounting.Linux.dll @@ -103,12 +100,17 @@ + + + {e383961b-9356-4d5d-8233-9a1079d03055} + Emby.Server.Implementations + {b90ab8f2-1bff-4568-a3fd-2a338a435a75} MediaBrowser.Server.Startup.Common diff --git a/MediaBrowser.Server.Mono/Native/MonoApp.cs b/MediaBrowser.Server.Mono/Native/MonoApp.cs index 59c95316c1..6e7a677aee 100644 --- a/MediaBrowser.Server.Mono/Native/MonoApp.cs +++ b/MediaBrowser.Server.Mono/Native/MonoApp.cs @@ -7,12 +7,11 @@ using System; using System.Collections.Generic; using System.Reflection; using System.Text.RegularExpressions; +using Emby.Common.Implementations.Networking; using Emby.Server.Core; using Emby.Server.Core.Data; using Emby.Server.Core.FFMpeg; using MediaBrowser.Model.System; -using MediaBrowser.Server.Startup.Common.FFMpeg; -using MediaBrowser.Server.Startup.Common.Networking; using OperatingSystem = MediaBrowser.Server.Startup.Common.OperatingSystem; namespace MediaBrowser.Server.Mono.Native diff --git a/MediaBrowser.Server.Mono/Native/MonoFileSystem.cs b/MediaBrowser.Server.Mono/Native/MonoFileSystem.cs new file mode 100644 index 0000000000..9639566947 --- /dev/null +++ b/MediaBrowser.Server.Mono/Native/MonoFileSystem.cs @@ -0,0 +1,21 @@ +using Emby.Common.Implementations.IO; +using MediaBrowser.Model.Logging; +using Mono.Unix.Native; + +namespace MediaBrowser.Server.Mono.Native +{ + public class MonoFileSystem : ManagedFileSystem + { + public MonoFileSystem(ILogger logger, bool supportsAsyncFileStreams, bool enableManagedInvalidFileNameChars) : base(logger, supportsAsyncFileStreams, enableManagedInvalidFileNameChars) + { + } + + public override void SetExecutable(string path) + { + // Linux: File permission to 666, and user's execute bit + Logger.Info("Syscall.chmod {0} FilePermissions.DEFFILEMODE | FilePermissions.S_IRWXU | FilePermissions.S_IXGRP | FilePermissions.S_IXOTH", path); + + Syscall.chmod(path, FilePermissions.DEFFILEMODE | FilePermissions.S_IRWXU | FilePermissions.S_IXGRP | FilePermissions.S_IXOTH); + } + } +} diff --git a/MediaBrowser.Server.Mono/Program.cs b/MediaBrowser.Server.Mono/Program.cs index d453596278..7d687bb545 100644 --- a/MediaBrowser.Server.Mono/Program.cs +++ b/MediaBrowser.Server.Mono/Program.cs @@ -15,6 +15,7 @@ using System.Threading.Tasks; using Emby.Common.Implementations.IO; using Emby.Common.Implementations.Logging; using Emby.Server.Core; +using Emby.Server.Implementations.IO; namespace MediaBrowser.Server.Mono { @@ -76,7 +77,7 @@ namespace MediaBrowser.Server.Mono // Allow all https requests ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(delegate { return true; }); - var fileSystem = new ManagedFileSystem(logManager.GetLogger("FileSystem"), false, false); + var fileSystem = new MonoFileSystem(logManager.GetLogger("FileSystem"), false, false); fileSystem.AddShortcutHandler(new MbLinkShortcutHandler(fileSystem)); var nativeApp = new MonoApp(options, logManager.GetLogger("App")); diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs index 6d7ec699d9..0646c71fda 100644 --- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs +++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs @@ -48,9 +48,6 @@ using MediaBrowser.Model.Updates; using MediaBrowser.Providers.Chapters; using MediaBrowser.Providers.Manager; using MediaBrowser.Providers.Subtitles; -using MediaBrowser.Server.Implementations; -using MediaBrowser.Server.Implementations.Devices; -using MediaBrowser.Server.Startup.Common.FFMpeg; using MediaBrowser.WebDashboard.Api; using MediaBrowser.XbmcMetadata.Providers; using System; @@ -69,6 +66,7 @@ using Emby.Common.Implementations; using Emby.Common.Implementations.Archiving; using Emby.Common.Implementations.Networking; using Emby.Common.Implementations.Reflection; +using Emby.Common.Implementations.Security; using Emby.Common.Implementations.Serialization; using Emby.Common.Implementations.TextEncoding; using Emby.Common.Implementations.Updates; @@ -93,8 +91,11 @@ using Emby.Server.Core.Activity; using Emby.Server.Core.Configuration; using Emby.Server.Core.Data; using Emby.Server.Core.Devices; +using Emby.Server.Core.FFMpeg; +using Emby.Server.Core.Localization; using Emby.Server.Core.Migrations; using Emby.Server.Core.Notifications; +using Emby.Server.Core.Security; using Emby.Server.Core.Social; using Emby.Server.Core.Sync; using Emby.Server.Implementations.Activity; @@ -134,7 +135,6 @@ using MediaBrowser.Model.Social; using MediaBrowser.Model.Text; using MediaBrowser.Model.Xml; using MediaBrowser.Server.Startup.Common.IO; -using MediaBrowser.Server.Startup.Common.Security; using OpenSubtitlesHandler; using ServiceStack; using SocketHttpListener.Primitives; @@ -817,8 +817,8 @@ namespace MediaBrowser.Server.Startup.Common string encoderPath = null; string probePath = null; - var info = await new FFMpegLoader(Logger, ApplicationPaths, HttpClient, ZipClient, FileSystemManager, NativeApp.Environment, NativeApp.GetFfmpegInstallInfo()) - .GetFFMpegInfo(NativeApp.Environment, _startupOptions, progress).ConfigureAwait(false); + var info = await new FFMpegLoader(Logger, ApplicationPaths, HttpClient, ZipClient, FileSystemManager, NativeApp.GetFfmpegInstallInfo()) + .GetFFMpegInfo(_startupOptions, progress).ConfigureAwait(false); encoderPath = info.EncoderPath; probePath = info.ProbePath; @@ -1079,7 +1079,7 @@ namespace MediaBrowser.Server.Startup.Common try { - NetworkManager.GenerateSelfSignedSslCertificate(certPath, certHost); + CertificateGenerator.CreateSelfSignCertificatePfx(certPath, certHost, Logger); } catch (Exception ex) { @@ -1213,12 +1213,12 @@ namespace MediaBrowser.Server.Startup.Common // Common implementations list.Add(typeof(TaskManager).Assembly); - // MediaBrowser.Server implementations - list.Add(typeof(ServerApplicationPaths).Assembly); - // Emby.Server implementations list.Add(typeof(InstallationManager).Assembly); + // Emby.Server.Core + list.Add(typeof(ServerApplicationPaths).Assembly); + // MediaEncoding list.Add(typeof(MediaEncoder).Assembly); diff --git a/MediaBrowser.Server.Startup.Common/Cryptography/CertificateGenerator.cs b/MediaBrowser.Server.Startup.Common/Cryptography/CertificateGenerator.cs index f36b14cae2..f5a337505b 100644 --- a/MediaBrowser.Server.Startup.Common/Cryptography/CertificateGenerator.cs +++ b/MediaBrowser.Server.Startup.Common/Cryptography/CertificateGenerator.cs @@ -5,7 +5,7 @@ using System.Security.Cryptography; namespace Emby.Common.Implementations.Security { - internal class CertificateGenerator + public class CertificateGenerator { private const string MonoTestRootAgency = "v/4nALBxCE+9JgEC0LnDUvKh6e96PwTpN4Rj+vWnqKT7IAp1iK/JjuqvAg6DQ2vTfv0dTlqffmHH51OyioprcT5nzxcSTsZb/9jcHScG0s3/FRIWnXeLk/fgm7mSYhjUaHNI0m1/NTTktipicjKxo71hGIg9qucCWnDum+Krh/k=AQAB

9jbKxMXEruW2CfZrzhxtull4O8P47+mNsEL+9gf9QsRO1jJ77C+jmzfU6zbzjf8+ViK+q62tCMdC1ZzulwdpXQ==

x5+p198l1PkK0Ga2mRh0SIYSykENpY2aLXoyZD/iUpKYAvATm0/wvKNrE4dKJyPCA+y3hfTdgVag+SP9avvDTQ==ISSjCvXsUfbOGG05eddN1gXxL2pj+jegQRfjpk7RAsnWKvNExzhqd5x+ZuNQyc6QH5wxun54inP4RTUI0P/IaQ==R815VQmR3RIbPqzDXzv5j6CSH6fYlcTiQRtkBsUnzhWmkd/y3XmamO+a8zJFjOCCx9CcjpVuGziivBqi65lVPQ==iYiu0KwMWI/dyqN3RJYUzuuLj02/oTD1pYpwo2rvNCXU1Q5VscOeu2DpNg1gWqI+1RrRCsEoaTNzXB1xtKNlSw==nIfh1LYF8fjRBgMdAH/zt9UKHWiaCnc+jXzq5tkR8HVSKTVdzitD8bl1JgAfFQD8VjSXiCJqluexy/B5SGrCXQ49c78NIQj0hD+J13Y8/E0fUbW1QYbhj6Ff7oHyhaYe1WOQfkp2t/h+llHOdt1HRf7bt7dUknYp7m8bQKGxoYE=
"; diff --git a/MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegLoader.cs b/MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegLoader.cs deleted file mode 100644 index 08e6b435b5..0000000000 --- a/MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegLoader.cs +++ /dev/null @@ -1,249 +0,0 @@ -using MediaBrowser.Common.Configuration; -using MediaBrowser.Common.Net; -using MediaBrowser.Model.IO; -using MediaBrowser.Model.Logging; -using Mono.Unix.Native; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Emby.Server.Core; -using Emby.Server.Core.FFMpeg; - -namespace MediaBrowser.Server.Startup.Common.FFMpeg -{ - public class FFMpegLoader - { - private readonly IHttpClient _httpClient; - private readonly IApplicationPaths _appPaths; - private readonly ILogger _logger; - private readonly IZipClient _zipClient; - private readonly IFileSystem _fileSystem; - private readonly NativeEnvironment _environment; - private readonly FFMpegInstallInfo _ffmpegInstallInfo; - - public FFMpegLoader(ILogger logger, IApplicationPaths appPaths, IHttpClient httpClient, IZipClient zipClient, IFileSystem fileSystem, NativeEnvironment environment, FFMpegInstallInfo ffmpegInstallInfo) - { - _logger = logger; - _appPaths = appPaths; - _httpClient = httpClient; - _zipClient = zipClient; - _fileSystem = fileSystem; - _environment = environment; - _ffmpegInstallInfo = ffmpegInstallInfo; - } - - public async Task GetFFMpegInfo(NativeEnvironment environment, StartupOptions options, IProgress progress) - { - var customffMpegPath = options.GetOption("-ffmpeg"); - var customffProbePath = options.GetOption("-ffprobe"); - - if (!string.IsNullOrWhiteSpace(customffMpegPath) && !string.IsNullOrWhiteSpace(customffProbePath)) - { - return new FFMpegInfo - { - ProbePath = customffProbePath, - EncoderPath = customffMpegPath, - Version = "external" - }; - } - - var downloadInfo = _ffmpegInstallInfo; - - var version = downloadInfo.Version; - - if (string.Equals(version, "path", StringComparison.OrdinalIgnoreCase)) - { - return new FFMpegInfo - { - ProbePath = downloadInfo.FFProbeFilename, - EncoderPath = downloadInfo.FFMpegFilename, - Version = version - }; - } - - if (string.Equals(version, "0", StringComparison.OrdinalIgnoreCase)) - { - return new FFMpegInfo(); - } - - var rootEncoderPath = Path.Combine(_appPaths.ProgramDataPath, "ffmpeg"); - var versionedDirectoryPath = Path.Combine(rootEncoderPath, version); - - var info = new FFMpegInfo - { - ProbePath = Path.Combine(versionedDirectoryPath, downloadInfo.FFProbeFilename), - EncoderPath = Path.Combine(versionedDirectoryPath, downloadInfo.FFMpegFilename), - Version = version - }; - - _fileSystem.CreateDirectory(versionedDirectoryPath); - - var excludeFromDeletions = new List { versionedDirectoryPath }; - - if (!_fileSystem.FileExists(info.ProbePath) || !_fileSystem.FileExists(info.EncoderPath)) - { - // ffmpeg not present. See if there's an older version we can start with - var existingVersion = GetExistingVersion(info, rootEncoderPath); - - // No older version. Need to download and block until complete - if (existingVersion == null) - { - var success = await DownloadFFMpeg(downloadInfo, versionedDirectoryPath, progress).ConfigureAwait(false); - if (!success) - { - return new FFMpegInfo(); - } - } - else - { - info = existingVersion; - versionedDirectoryPath = Path.GetDirectoryName(info.EncoderPath); - excludeFromDeletions.Add(versionedDirectoryPath); - } - } - - // Allow just one of these to be overridden, if desired. - if (!string.IsNullOrWhiteSpace(customffMpegPath)) - { - info.EncoderPath = customffMpegPath; - } - if (!string.IsNullOrWhiteSpace(customffProbePath)) - { - info.EncoderPath = customffProbePath; - } - - return info; - } - - private FFMpegInfo GetExistingVersion(FFMpegInfo info, string rootEncoderPath) - { - var encoderFilename = Path.GetFileName(info.EncoderPath); - var probeFilename = Path.GetFileName(info.ProbePath); - - foreach (var directory in Directory.EnumerateDirectories(rootEncoderPath, "*", SearchOption.TopDirectoryOnly) - .ToList()) - { - var allFiles = Directory.EnumerateFiles(directory, "*", SearchOption.AllDirectories).ToList(); - - var encoder = allFiles.FirstOrDefault(i => string.Equals(Path.GetFileName(i), encoderFilename, StringComparison.OrdinalIgnoreCase)); - var probe = allFiles.FirstOrDefault(i => string.Equals(Path.GetFileName(i), probeFilename, StringComparison.OrdinalIgnoreCase)); - - if (!string.IsNullOrWhiteSpace(encoder) && - !string.IsNullOrWhiteSpace(probe)) - { - return new FFMpegInfo - { - EncoderPath = encoder, - ProbePath = probe, - Version = Path.GetFileName(Path.GetDirectoryName(probe)) - }; - } - } - - return null; - } - - private async Task DownloadFFMpeg(FFMpegInstallInfo downloadinfo, string directory, IProgress progress) - { - foreach (var url in downloadinfo.DownloadUrls) - { - progress.Report(0); - - try - { - var tempFile = await _httpClient.GetTempFile(new HttpRequestOptions - { - Url = url, - CancellationToken = CancellationToken.None, - Progress = progress - - }).ConfigureAwait(false); - - ExtractFFMpeg(downloadinfo, tempFile, directory); - return true; - } - catch (Exception ex) - { - _logger.ErrorException("Error downloading {0}", ex, url); - } - } - return false; - } - - private void ExtractFFMpeg(FFMpegInstallInfo downloadinfo, string tempFile, string targetFolder) - { - _logger.Info("Extracting ffmpeg from {0}", tempFile); - - var tempFolder = Path.Combine(_appPaths.TempDirectory, Guid.NewGuid().ToString()); - - _fileSystem.CreateDirectory(tempFolder); - - try - { - ExtractArchive(downloadinfo, tempFile, tempFolder); - - var files = Directory.EnumerateFiles(tempFolder, "*", SearchOption.AllDirectories) - .ToList(); - - foreach (var file in files.Where(i => - { - var filename = Path.GetFileName(i); - - return - string.Equals(filename, downloadinfo.FFProbeFilename, StringComparison.OrdinalIgnoreCase) || - string.Equals(filename, downloadinfo.FFMpegFilename, StringComparison.OrdinalIgnoreCase); - })) - { - var targetFile = Path.Combine(targetFolder, Path.GetFileName(file)); - _fileSystem.CopyFile(file, targetFile, true); - SetFilePermissions(targetFile); - } - } - finally - { - DeleteFile(tempFile); - } - } - - private void SetFilePermissions(string path) - { - // Linux: File permission to 666, and user's execute bit - if (_environment.OperatingSystem == OperatingSystem.Bsd || _environment.OperatingSystem == OperatingSystem.Linux || _environment.OperatingSystem == OperatingSystem.Osx) - { - _logger.Info("Syscall.chmod {0} FilePermissions.DEFFILEMODE | FilePermissions.S_IRWXU | FilePermissions.S_IXGRP | FilePermissions.S_IXOTH", path); - - Syscall.chmod(path, FilePermissions.DEFFILEMODE | FilePermissions.S_IRWXU | FilePermissions.S_IXGRP | FilePermissions.S_IXOTH); - } - } - - private void ExtractArchive(FFMpegInstallInfo downloadinfo, string archivePath, string targetPath) - { - _logger.Info("Extracting {0} to {1}", archivePath, targetPath); - - if (string.Equals(downloadinfo.ArchiveType, "7z", StringComparison.OrdinalIgnoreCase)) - { - _zipClient.ExtractAllFrom7z(archivePath, targetPath, true); - } - else if (string.Equals(downloadinfo.ArchiveType, "gz", StringComparison.OrdinalIgnoreCase)) - { - _zipClient.ExtractAllFromTar(archivePath, targetPath, true); - } - } - - private void DeleteFile(string path) - { - try - { - _fileSystem.DeleteFile(path); - } - catch (IOException ex) - { - _logger.ErrorException("Error deleting temp file {0}", ex, path); - } - } - - } -} diff --git a/MediaBrowser.Server.Startup.Common/MbLinkShortcutHandler.cs b/MediaBrowser.Server.Startup.Common/MbLinkShortcutHandler.cs deleted file mode 100644 index 26318365b6..0000000000 --- a/MediaBrowser.Server.Startup.Common/MbLinkShortcutHandler.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System; -using System.IO; -using MediaBrowser.Common.IO; -using MediaBrowser.Controller.IO; -using MediaBrowser.Model.IO; - -namespace MediaBrowser.Server.Startup.Common -{ - public class MbLinkShortcutHandler : IShortcutHandler - { - private readonly IFileSystem _fileSystem; - - public MbLinkShortcutHandler(IFileSystem fileSystem) - { - _fileSystem = fileSystem; - } - - public string Extension - { - get { return ".mblink"; } - } - - public string Resolve(string shortcutPath) - { - if (string.IsNullOrEmpty(shortcutPath)) - { - throw new ArgumentNullException("filenshortcutPathame"); - } - - if (string.Equals(Path.GetExtension(shortcutPath), ".mblink", StringComparison.OrdinalIgnoreCase)) - { - var path = _fileSystem.ReadAllText(shortcutPath); - - return _fileSystem.NormalizePath(path); - } - - return null; - } - - public void Create(string shortcutPath, string targetPath) - { - if (string.IsNullOrEmpty(shortcutPath)) - { - throw new ArgumentNullException("shortcutPath"); - } - - if (string.IsNullOrEmpty(targetPath)) - { - throw new ArgumentNullException("targetPath"); - } - - File.WriteAllText(shortcutPath, targetPath); - } - } -} diff --git a/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj b/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj index 79c1356de3..4bbd86060e 100644 --- a/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj +++ b/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj @@ -113,7 +113,6 @@ - @@ -140,13 +139,9 @@ - - - -
diff --git a/MediaBrowser.Server.Startup.Common/Networking/NetworkManager.cs b/MediaBrowser.Server.Startup.Common/Networking/NetworkManager.cs deleted file mode 100644 index bd260bf873..0000000000 --- a/MediaBrowser.Server.Startup.Common/Networking/NetworkManager.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System.Collections.Generic; -using Emby.Common.Implementations.Networking; -using Emby.Common.Implementations.Security; -using MediaBrowser.Common.Net; -using MediaBrowser.Model.IO; -using MediaBrowser.Model.Logging; -using MediaBrowser.Model.Net; - -namespace MediaBrowser.Server.Startup.Common.Networking -{ - /// - /// Class NetUtils - /// - public class NetworkManager : BaseNetworkManager, INetworkManager - { - public NetworkManager(ILogger logger) - : base(logger) - { - } - - /// - /// Gets the network shares. - /// - /// The path. - /// IEnumerable{NetworkShare}. - public IEnumerable GetNetworkShares(string path) - { - return new List(); - } - - /// - /// Gets available devices within the domain - /// - /// PC's in the Domain - public IEnumerable GetNetworkDevices() - { - return new List(); - } - - /// - /// Generates a self signed certificate at the locatation specified by . - /// - /// The path to generate the certificate. - /// The common name for the certificate. - public void GenerateSelfSignedSslCertificate(string certificatePath, string hostname) - { - CertificateGenerator.CreateSelfSignCertificatePfx(certificatePath, hostname, Logger); - } - } -} diff --git a/MediaBrowser.Server.Startup.Common/Security/AuthenticationRepository.cs b/MediaBrowser.Server.Startup.Common/Security/AuthenticationRepository.cs deleted file mode 100644 index 0cf9f0879a..0000000000 --- a/MediaBrowser.Server.Startup.Common/Security/AuthenticationRepository.cs +++ /dev/null @@ -1,317 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data; -using System.Globalization; -using System.IO; -using System.Threading; -using System.Threading.Tasks; -using Emby.Server.Core.Data; -using MediaBrowser.Controller; -using MediaBrowser.Controller.Security; -using MediaBrowser.Model.Logging; -using MediaBrowser.Model.Querying; - -namespace MediaBrowser.Server.Startup.Common.Security -{ - public class AuthenticationRepository : BaseSqliteRepository, IAuthenticationRepository - { - private readonly IServerApplicationPaths _appPaths; - private readonly CultureInfo _usCulture = new CultureInfo("en-US"); - - public AuthenticationRepository(ILogManager logManager, IServerApplicationPaths appPaths, IDbConnector connector) - : base(logManager, connector) - { - _appPaths = appPaths; - DbFilePath = Path.Combine(appPaths.DataPath, "authentication.db"); - } - - public async Task Initialize() - { - using (var connection = await CreateConnection().ConfigureAwait(false)) - { - string[] queries = { - - "create table if not exists AccessTokens (Id GUID PRIMARY KEY, AccessToken TEXT NOT NULL, DeviceId TEXT, AppName TEXT, AppVersion TEXT, DeviceName TEXT, UserId TEXT, IsActive BIT, DateCreated DATETIME NOT NULL, DateRevoked DATETIME)", - "create index if not exists idx_AccessTokens on AccessTokens(Id)" - }; - - connection.RunQueries(queries, Logger); - - connection.AddColumn(Logger, "AccessTokens", "AppVersion", "TEXT"); - } - } - - public Task Create(AuthenticationInfo info, CancellationToken cancellationToken) - { - info.Id = Guid.NewGuid().ToString("N"); - - return Update(info, cancellationToken); - } - - public async Task Update(AuthenticationInfo info, CancellationToken cancellationToken) - { - if (info == null) - { - throw new ArgumentNullException("info"); - } - - cancellationToken.ThrowIfCancellationRequested(); - - using (var connection = await CreateConnection().ConfigureAwait(false)) - { - using (var saveInfoCommand = connection.CreateCommand()) - { - saveInfoCommand.CommandText = "replace into AccessTokens (Id, AccessToken, DeviceId, AppName, AppVersion, DeviceName, UserId, IsActive, DateCreated, DateRevoked) values (@Id, @AccessToken, @DeviceId, @AppName, @AppVersion, @DeviceName, @UserId, @IsActive, @DateCreated, @DateRevoked)"; - - saveInfoCommand.Parameters.Add(saveInfoCommand, "@Id"); - saveInfoCommand.Parameters.Add(saveInfoCommand, "@AccessToken"); - saveInfoCommand.Parameters.Add(saveInfoCommand, "@DeviceId"); - saveInfoCommand.Parameters.Add(saveInfoCommand, "@AppName"); - saveInfoCommand.Parameters.Add(saveInfoCommand, "@AppVersion"); - saveInfoCommand.Parameters.Add(saveInfoCommand, "@DeviceName"); - saveInfoCommand.Parameters.Add(saveInfoCommand, "@UserId"); - saveInfoCommand.Parameters.Add(saveInfoCommand, "@IsActive"); - saveInfoCommand.Parameters.Add(saveInfoCommand, "@DateCreated"); - saveInfoCommand.Parameters.Add(saveInfoCommand, "@DateRevoked"); - - IDbTransaction transaction = null; - - try - { - transaction = connection.BeginTransaction(); - - var index = 0; - - saveInfoCommand.GetParameter(index++).Value = new Guid(info.Id); - saveInfoCommand.GetParameter(index++).Value = info.AccessToken; - saveInfoCommand.GetParameter(index++).Value = info.DeviceId; - saveInfoCommand.GetParameter(index++).Value = info.AppName; - saveInfoCommand.GetParameter(index++).Value = info.AppVersion; - saveInfoCommand.GetParameter(index++).Value = info.DeviceName; - saveInfoCommand.GetParameter(index++).Value = info.UserId; - saveInfoCommand.GetParameter(index++).Value = info.IsActive; - saveInfoCommand.GetParameter(index++).Value = info.DateCreated; - saveInfoCommand.GetParameter(index++).Value = info.DateRevoked; - - saveInfoCommand.Transaction = transaction; - - saveInfoCommand.ExecuteNonQuery(); - - transaction.Commit(); - } - catch (OperationCanceledException) - { - if (transaction != null) - { - transaction.Rollback(); - } - - throw; - } - catch (Exception e) - { - Logger.ErrorException("Failed to save record:", e); - - if (transaction != null) - { - transaction.Rollback(); - } - - throw; - } - finally - { - if (transaction != null) - { - transaction.Dispose(); - } - } - } - } - } - - private const string BaseSelectText = "select Id, AccessToken, DeviceId, AppName, AppVersion, DeviceName, UserId, IsActive, DateCreated, DateRevoked from AccessTokens"; - - public QueryResult Get(AuthenticationInfoQuery query) - { - if (query == null) - { - throw new ArgumentNullException("query"); - } - - using (var connection = CreateConnection(true).Result) - { - using (var cmd = connection.CreateCommand()) - { - cmd.CommandText = BaseSelectText; - - var whereClauses = new List(); - - var startIndex = query.StartIndex ?? 0; - - if (!string.IsNullOrWhiteSpace(query.AccessToken)) - { - whereClauses.Add("AccessToken=@AccessToken"); - cmd.Parameters.Add(cmd, "@AccessToken", DbType.String).Value = query.AccessToken; - } - - if (!string.IsNullOrWhiteSpace(query.UserId)) - { - whereClauses.Add("UserId=@UserId"); - cmd.Parameters.Add(cmd, "@UserId", DbType.String).Value = query.UserId; - } - - if (!string.IsNullOrWhiteSpace(query.DeviceId)) - { - whereClauses.Add("DeviceId=@DeviceId"); - cmd.Parameters.Add(cmd, "@DeviceId", DbType.String).Value = query.DeviceId; - } - - if (query.IsActive.HasValue) - { - whereClauses.Add("IsActive=@IsActive"); - cmd.Parameters.Add(cmd, "@IsActive", DbType.Boolean).Value = query.IsActive.Value; - } - - if (query.HasUser.HasValue) - { - if (query.HasUser.Value) - { - whereClauses.Add("UserId not null"); - } - else - { - whereClauses.Add("UserId is null"); - } - } - - var whereTextWithoutPaging = whereClauses.Count == 0 ? - string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); - - if (startIndex > 0) - { - var pagingWhereText = whereClauses.Count == 0 ? - string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); - - whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM AccessTokens {0} ORDER BY DateCreated LIMIT {1})", - pagingWhereText, - startIndex.ToString(_usCulture))); - } - - var whereText = whereClauses.Count == 0 ? - string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); - - cmd.CommandText += whereText; - - cmd.CommandText += " ORDER BY DateCreated"; - - if (query.Limit.HasValue) - { - cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(_usCulture); - } - - cmd.CommandText += "; select count (Id) from AccessTokens" + whereTextWithoutPaging; - - var list = new List(); - var count = 0; - - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) - { - while (reader.Read()) - { - list.Add(Get(reader)); - } - - if (reader.NextResult() && reader.Read()) - { - count = reader.GetInt32(0); - } - } - - return new QueryResult() - { - Items = list.ToArray(), - TotalRecordCount = count - }; - } - } - } - - public AuthenticationInfo Get(string id) - { - if (string.IsNullOrEmpty(id)) - { - throw new ArgumentNullException("id"); - } - - using (var connection = CreateConnection(true).Result) - { - var guid = new Guid(id); - - using (var cmd = connection.CreateCommand()) - { - cmd.CommandText = BaseSelectText + " where Id=@Id"; - - cmd.Parameters.Add(cmd, "@Id", DbType.Guid).Value = guid; - - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow)) - { - if (reader.Read()) - { - return Get(reader); - } - } - } - - return null; - } - } - - private AuthenticationInfo Get(IDataReader reader) - { - var info = new AuthenticationInfo - { - Id = reader.GetGuid(0).ToString("N"), - AccessToken = reader.GetString(1) - }; - - if (!reader.IsDBNull(2)) - { - info.DeviceId = reader.GetString(2); - } - - if (!reader.IsDBNull(3)) - { - info.AppName = reader.GetString(3); - } - - if (!reader.IsDBNull(4)) - { - info.AppVersion = reader.GetString(4); - } - - if (!reader.IsDBNull(5)) - { - info.DeviceName = reader.GetString(5); - } - - if (!reader.IsDBNull(6)) - { - info.UserId = reader.GetString(6); - } - - info.IsActive = reader.GetBoolean(7); - info.DateCreated = reader.GetDateTime(8).ToUniversalTime(); - - if (!reader.IsDBNull(9)) - { - info.DateRevoked = reader.GetDateTime(9).ToUniversalTime(); - } - - return info; - } - } -} diff --git a/MediaBrowser.Server.Startup.Common/TextLocalizer.cs b/MediaBrowser.Server.Startup.Common/TextLocalizer.cs deleted file mode 100644 index c578199a07..0000000000 --- a/MediaBrowser.Server.Startup.Common/TextLocalizer.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using System.Globalization; -using System.Linq; -using System.Text; -using Emby.Server.Implementations.Localization; - -namespace MediaBrowser.Server.Startup.Common -{ - public class TextLocalizer : ITextLocalizer - { - public string RemoveDiacritics(string text) - { - return String.Concat( - text.Normalize(NormalizationForm.FormD) - .Where(ch => CharUnicodeInfo.GetUnicodeCategory(ch) != - UnicodeCategory.NonSpacingMark) - ).Normalize(NormalizationForm.FormC); - } - - public string NormalizeFormKD(string text) - { - return text.Normalize(NormalizationForm.FormKD); - } - } -} diff --git a/MediaBrowser.ServerApplication/MainStartup.cs b/MediaBrowser.ServerApplication/MainStartup.cs index 2d97cbdf7a..f2967e14a0 100644 --- a/MediaBrowser.ServerApplication/MainStartup.cs +++ b/MediaBrowser.ServerApplication/MainStartup.cs @@ -21,6 +21,7 @@ using Emby.Common.Implementations.IO; using Emby.Common.Implementations.Logging; using Emby.Server.Core; using Emby.Server.Core.Browser; +using Emby.Server.Implementations.IO; using ImageMagickSharp; using MediaBrowser.Common.Net; diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj index 2c78c22c92..b082b14d8b 100644 --- a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj +++ b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj @@ -82,9 +82,6 @@ ..\packages\Patterns.Logging.1.0.0.6\lib\portable-net45+win8\Patterns.Logging.dll True - - ..\ThirdParty\ServiceStack\ServiceStack.Interfaces.dll - @@ -1064,6 +1061,10 @@ {08fff49b-f175-4807-a2b5-73b0ebd9f716} Emby.Drawing + + {e383961b-9356-4d5d-8233-9a1079d03055} + Emby.Server.Implementations + {4fd51ac5-2c16-4308-a993-c3a84f3b4582} MediaBrowser.Api diff --git a/MediaBrowser.ServerApplication/Native/WindowsApp.cs b/MediaBrowser.ServerApplication/Native/WindowsApp.cs index 8424bf5746..d0f8239fec 100644 --- a/MediaBrowser.ServerApplication/Native/WindowsApp.cs +++ b/MediaBrowser.ServerApplication/Native/WindowsApp.cs @@ -15,7 +15,6 @@ using MediaBrowser.Common.IO; using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.System; -using MediaBrowser.Server.Startup.Common.FFMpeg; using OperatingSystem = MediaBrowser.Server.Startup.Common.OperatingSystem; namespace MediaBrowser.ServerApplication.Native diff --git a/MediaBrowser.ServerApplication/Networking/NetworkManager.cs b/MediaBrowser.ServerApplication/Networking/NetworkManager.cs index 7b4379abf0..ed99dcc061 100644 --- a/MediaBrowser.ServerApplication/Networking/NetworkManager.cs +++ b/MediaBrowser.ServerApplication/Networking/NetworkManager.cs @@ -13,7 +13,7 @@ namespace MediaBrowser.ServerApplication.Networking /// /// Class NetUtils /// - public class NetworkManager : Server.Startup.Common.Networking.NetworkManager + public class NetworkManager : Emby.Common.Implementations.Networking.NetworkManager { public NetworkManager(ILogger logger) : base(logger) -- cgit v1.2.3