From 56ee561ca2368d9713c1ac3b0f7f8718cd41e452 Mon Sep 17 00:00:00 2001 From: Jared Goodwin Date: Fri, 6 Jan 2023 16:48:03 -0800 Subject: [PATCH] Bug - Proto forwarded header not being seen by ASP.NET Core. (#554) * Set permissions on log file so non-elevated process can write to it. * Replace more instances of static Logger with ILogger. * Add default Docker host to known proxies. * Update Immense.RemoteControl * Update Immense.RemoteControl --- Agent/Services/AppLauncherLinux.cs | 23 ++++++-- Agent/Services/AppLauncherWin.cs | 15 +++-- Agent/Services/UpdaterLinux.cs | 29 ++++++---- Agent/Services/UpdaterMac.cs | 27 +++++---- Agent/Services/UpdaterWin.cs | 29 ++++++---- README.md | 10 +++- Remotely.sln | 4 +- Server/API/ClientDownloadsController.cs | 14 ++--- Server/{Dockerfile-local => Dockerfile.local} | 0 Server/{Dockerfile-old => Dockerfile.old} | 0 ...ockerfile-rootless => Dockerfile.rootless} | 0 Server/Program.cs | 3 + Shared/Services/FileLogger.cs | 57 +++++++++++++------ Shared/Services/ProcessInvoker.cs | 10 +++- Shared/Utilities/Logger.cs | 3 +- submodules/Immense.RemoteControl | 2 +- 16 files changed, 149 insertions(+), 77 deletions(-) rename Server/{Dockerfile-local => Dockerfile.local} (100%) rename Server/{Dockerfile-old => Dockerfile.old} (100%) rename Server/{Dockerfile-rootless => Dockerfile.rootless} (100%) diff --git a/Agent/Services/AppLauncherLinux.cs b/Agent/Services/AppLauncherLinux.cs index 73f6c90c..e37e43d8 100644 --- a/Agent/Services/AppLauncherLinux.cs +++ b/Agent/Services/AppLauncherLinux.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.SignalR.Client; +using Microsoft.Extensions.Logging; using Remotely.Agent.Interfaces; using Remotely.Shared.Models; using Remotely.Shared.Services; @@ -20,11 +21,16 @@ namespace Remotely.Agent.Services private readonly string _rcBinaryPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Desktop", EnvironmentHelper.DesktopExecutableFileName); private readonly IProcessInvoker _processInvoker; private readonly ConnectionInfo _connectionInfo; + private readonly ILogger _logger; - public AppLauncherLinux(ConfigService configService, IProcessInvoker processInvoker) + public AppLauncherLinux( + ConfigService configService, + IProcessInvoker processInvoker, + ILogger logger) { _processInvoker = processInvoker; _connectionInfo = configService.GetConnectionInfo(); + _logger = logger; } @@ -52,7 +58,7 @@ namespace Remotely.Agent.Services } catch (Exception ex) { - Logger.Write(ex); + _logger.LogError(ex, "Error while getting current X11 user."); } } @@ -64,7 +70,12 @@ namespace Remotely.Agent.Services psi.Environment.Add("DISPLAY", display); psi.Environment.Add("XAUTHORITY", xauthority); - Logger.Write($"Attempting to launch screen caster with username {username}, xauthority {xauthority}, display {display}, and args {args}."); + _logger.LogInformation( + "Attempting to launch screen caster with username {username}, xauthority {xauthority}, display {display}, and args {args}.", + username, + xauthority, + display, + args); return Process.Start(psi).Id; } @@ -123,7 +134,7 @@ namespace Remotely.Agent.Services } catch (Exception ex) { - Logger.Write(ex); + _logger.LogError(ex, "Error while starting chat."); await hubConnection.SendAsync("DisplayMessage", "Chat service failed to start on target device.", "Failed to start chat service.", "bg-danger", userConnectionId); } return -1; @@ -159,7 +170,7 @@ namespace Remotely.Agent.Services } catch (Exception ex) { - Logger.Write(ex); + _logger.LogError(ex, "Error while launching remote control."); await hubConnection.SendAsync("DisplayMessage", "Remote control failed to start on target device.", "Failed to start remote control.", "bg-danger", userConnectionId); } } @@ -182,7 +193,7 @@ namespace Remotely.Agent.Services catch (Exception ex) { await hubConnection.SendAsync("SendConnectionFailedToViewers", viewerIDs); - Logger.Write(ex); + _logger.LogError(ex, "Error while restarting screen caster."); throw; } } diff --git a/Agent/Services/AppLauncherWin.cs b/Agent/Services/AppLauncherWin.cs index 48a537af..90a7231a 100644 --- a/Agent/Services/AppLauncherWin.cs +++ b/Agent/Services/AppLauncherWin.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.SignalR.Client; +using Microsoft.Extensions.Logging; using Remotely.Agent.Interfaces; using Remotely.Shared.Models; using Remotely.Shared.Utilities; @@ -18,11 +19,13 @@ namespace Remotely.Agent.Services public class AppLauncherWin : IAppLauncher { private readonly ConnectionInfo _connectionInfo; + private readonly ILogger _logger; private readonly string _rcBinaryPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Desktop", EnvironmentHelper.DesktopExecutableFileName); - public AppLauncherWin(ConfigService configService) + public AppLauncherWin(ConfigService configService, ILogger logger) { _connectionInfo = configService.GetConnectionInfo(); + _logger = logger; } public async Task LaunchChatService(string pipeName, string userConnectionId, string requesterName, string orgName, string orgId, HubConnection hubConnection) @@ -78,7 +81,7 @@ namespace Remotely.Agent.Services } catch (Exception ex) { - Logger.Write(ex); + _logger.LogError(ex, "Error while launching chat."); await hubConnection.SendAsync("DisplayMessage", "Chat service failed to start on target device.", "Failed to start chat service.", @@ -148,7 +151,7 @@ namespace Remotely.Agent.Services } catch (Exception ex) { - Logger.Write(ex); + _logger.LogError(ex, "Error while launching remote control."); await hubConnection.SendAsync("DisplayMessage", "Remote control failed to start on target device.", "Failed to start remote control.", @@ -161,7 +164,7 @@ namespace Remotely.Agent.Services try { // Start Desktop app. - Logger.Write("Restarting screen caster."); + _logger.LogInformation("Restarting screen caster."); if (WindowsIdentity.GetCurrent().IsSystem) { // Give a little time for session changing, etc. @@ -186,7 +189,7 @@ namespace Remotely.Agent.Services if (!result) { - Logger.Write("Failed to relaunch screen caster."); + _logger.LogWarning("Failed to relaunch screen caster."); await hubConnection.SendAsync("SendConnectionFailedToViewers", viewerIDs); await hubConnection.SendAsync("DisplayMessage", "Remote control failed to start on target device.", @@ -212,7 +215,7 @@ namespace Remotely.Agent.Services catch (Exception ex) { await hubConnection.SendAsync("SendConnectionFailedToViewers", viewerIDs); - Logger.Write(ex); + _logger.LogError(ex, "Error while restarting screen caster."); throw; } } diff --git a/Agent/Services/UpdaterLinux.cs b/Agent/Services/UpdaterLinux.cs index 27dc3916..a8ec45e8 100644 --- a/Agent/Services/UpdaterLinux.cs +++ b/Agent/Services/UpdaterLinux.cs @@ -1,4 +1,5 @@ -using Remotely.Agent.Interfaces; +using Microsoft.Extensions.Logging; +using Remotely.Agent.Interfaces; using Remotely.Shared.Utilities; using System; using System.Collections.Generic; @@ -22,15 +23,21 @@ namespace Remotely.Agent.Services private readonly ConfigService _configService; private readonly IUpdateDownloader _updateDownloader; private readonly IHttpClientFactory _httpClientFactory; + private readonly ILogger _logger; private readonly SemaphoreSlim _installLatestVersionLock = new(1, 1); private readonly System.Timers.Timer _updateTimer = new(TimeSpan.FromHours(6).TotalMilliseconds); private DateTimeOffset _lastUpdateFailure; - public UpdaterLinux(ConfigService configService, IUpdateDownloader updateDownloader, IHttpClientFactory httpClientFactory) + public UpdaterLinux( + ConfigService configService, + IUpdateDownloader updateDownloader, + IHttpClientFactory httpClientFactory, + ILogger logger) { _configService = configService; _updateDownloader = updateDownloader; _httpClientFactory = httpClientFactory; + _logger = logger; } @@ -62,7 +69,7 @@ namespace Remotely.Agent.Services if (_lastUpdateFailure.AddDays(1) > DateTimeOffset.Now) { - Logger.Write("Skipping update check due to previous failure. Restart the service to try again, or manually install the update."); + _logger.LogInformation("Skipping update check due to previous failure. Restart the service to try again, or manually install the update."); return; } @@ -89,23 +96,23 @@ namespace Remotely.Agent.Services if (response.StatusCode == HttpStatusCode.NotModified) { - Logger.Write("Service Updater: Version is current."); + _logger.LogInformation("Service Updater: Version is current."); return; } - Logger.Write("Service Updater: Update found."); + _logger.LogInformation("Service Updater: Update found."); await InstallLatestVersion(); } catch (WebException ex) when ((ex.Response as HttpWebResponse).StatusCode == HttpStatusCode.NotModified) { - Logger.Write("Service Updater: Version is current."); + _logger.LogInformation("Service Updater: Version is current."); return; } catch (Exception ex) { - Logger.Write(ex); + _logger.LogError(ex, "Error while checking for updates."); } finally { @@ -122,7 +129,7 @@ namespace Remotely.Agent.Services var connectionInfo = _configService.GetConnectionInfo(); var serverUrl = connectionInfo.Host; - Logger.Write("Service Updater: Downloading install package."); + _logger.LogInformation("Service Updater: Downloading install package."); var downloadId = Guid.NewGuid().ToString(); var zipPath = Path.Combine(Path.GetTempPath(), "RemotelyUpdate.zip"); @@ -155,7 +162,7 @@ namespace Remotely.Agent.Services using var httpClient = _httpClientFactory.CreateClient(); using var response = httpClient.GetAsync($"{serverUrl}/api/AgentUpdate/ClearDownload/{downloadId}"); - Logger.Write("Launching installer to perform update."); + _logger.LogInformation("Launching installer to perform update."); Process.Start("sudo", $"chmod +x {installerPath}").WaitForExit(); @@ -163,12 +170,12 @@ namespace Remotely.Agent.Services } catch (WebException ex) when (ex.Status == WebExceptionStatus.Timeout) { - Logger.Write("Timed out while waiting to download update.", Shared.Enums.EventType.Warning); + _logger.LogWarning("Timed out while waiting to download update."); _lastUpdateFailure = DateTimeOffset.Now; } catch (Exception ex) { - Logger.Write(ex); + _logger.LogError(ex, "Error while installing latest version."); _lastUpdateFailure = DateTimeOffset.Now; } finally diff --git a/Agent/Services/UpdaterMac.cs b/Agent/Services/UpdaterMac.cs index 981f1449..991e5033 100644 --- a/Agent/Services/UpdaterMac.cs +++ b/Agent/Services/UpdaterMac.cs @@ -1,3 +1,4 @@ +using Microsoft.Extensions.Logging; using Remotely.Agent.Interfaces; using Remotely.Shared.Utilities; using System; @@ -23,15 +24,21 @@ namespace Remotely.Agent.Services private readonly ConfigService _configService; private readonly IHttpClientFactory _httpClientFactory; private readonly IUpdateDownloader _updateDownloader; + private readonly ILogger _logger; private readonly SemaphoreSlim _installLatestVersionLock = new(1, 1); private DateTimeOffset _lastUpdateFailure; private readonly System.Timers.Timer _updateTimer = new(TimeSpan.FromHours(6).TotalMilliseconds); - public UpdaterMac(ConfigService configService, IUpdateDownloader updateDownloader, IHttpClientFactory httpClientFactory) + public UpdaterMac( + ConfigService configService, + IUpdateDownloader updateDownloader, + IHttpClientFactory httpClientFactory, + ILogger logger) { _configService = configService; _httpClientFactory = httpClientFactory; _updateDownloader = updateDownloader; + _logger = logger; } @@ -63,7 +70,7 @@ namespace Remotely.Agent.Services if (_lastUpdateFailure.AddDays(1) > DateTimeOffset.Now) { - Logger.Write("Skipping update check due to previous failure. Restart the service to try again, or manually install the update."); + _logger.LogInformation("Skipping update check due to previous failure. Restart the service to try again, or manually install the update."); return; } @@ -90,23 +97,23 @@ namespace Remotely.Agent.Services if (response.StatusCode == HttpStatusCode.NotModified) { - Logger.Write("Service Updater: Version is current."); + _logger.LogInformation("Service Updater: Version is current."); return; } - Logger.Write("Service Updater: Update found."); + _logger.LogInformation("Service Updater: Update found."); await InstallLatestVersion(); } catch (WebException ex) when ((ex.Response as HttpWebResponse).StatusCode == HttpStatusCode.NotModified) { - Logger.Write("Service Updater: Version is current."); + _logger.LogInformation("Service Updater: Version is current."); return; } catch (Exception ex) { - Logger.Write(ex); + _logger.LogError(ex, "Error while checking for updates."); } finally { @@ -123,7 +130,7 @@ namespace Remotely.Agent.Services var connectionInfo = _configService.GetConnectionInfo(); var serverUrl = connectionInfo.Host; - Logger.Write("Service Updater: Downloading install package."); + _logger.LogInformation("Service Updater: Downloading install package."); var downloadId = Guid.NewGuid().ToString(); var zipPath = Path.Combine(Path.GetTempPath(), "RemotelyUpdate.zip"); @@ -141,7 +148,7 @@ namespace Remotely.Agent.Services using var httpClient = _httpClientFactory.CreateClient(); using var response = httpClient.GetAsync($"{serverUrl}/api/AgentUpdate/ClearDownload/{downloadId}"); - Logger.Write("Launching installer to perform update."); + _logger.LogInformation("Launching installer to perform update."); Process.Start("sudo", $"chmod +x {installerPath}").WaitForExit(); @@ -149,12 +156,12 @@ namespace Remotely.Agent.Services } catch (WebException ex) when (ex.Status == WebExceptionStatus.Timeout) { - Logger.Write("Timed out while waiting to download update.", Shared.Enums.EventType.Warning); + _logger.LogWarning("Timed out while waiting to download update."); _lastUpdateFailure = DateTimeOffset.Now; } catch (Exception ex) { - Logger.Write(ex); + _logger.LogError(ex, "Error while installing latest version."); _lastUpdateFailure = DateTimeOffset.Now; } finally diff --git a/Agent/Services/UpdaterWin.cs b/Agent/Services/UpdaterWin.cs index 818d3aa0..a6a10432 100644 --- a/Agent/Services/UpdaterWin.cs +++ b/Agent/Services/UpdaterWin.cs @@ -1,4 +1,5 @@ -using Remotely.Agent.Interfaces; +using Microsoft.Extensions.Logging; +using Remotely.Agent.Interfaces; using Remotely.Shared.Utilities; using System; using System.Diagnostics; @@ -17,16 +18,22 @@ namespace Remotely.Agent.Services private readonly ConfigService _configService; private readonly IUpdateDownloader _updateDownloader; private readonly IHttpClientFactory _httpClientFactory; + private readonly ILogger _logger; private readonly SemaphoreSlim _installLatestVersionLock = new(1, 1); private readonly System.Timers.Timer _updateTimer = new(TimeSpan.FromHours(6).TotalMilliseconds); private DateTimeOffset _lastUpdateFailure; - public UpdaterWin(ConfigService configService, IUpdateDownloader updateDownloader, IHttpClientFactory httpClientFactory) + public UpdaterWin( + ConfigService configService, + IUpdateDownloader updateDownloader, + IHttpClientFactory httpClientFactory, + ILogger logger) { _configService = configService; _updateDownloader = updateDownloader; _httpClientFactory = httpClientFactory; + _logger = logger; } public async Task BeginChecking() @@ -58,7 +65,7 @@ namespace Remotely.Agent.Services if (_lastUpdateFailure.AddDays(1) > DateTimeOffset.Now) { - Logger.Write("Skipping update check due to previous failure. Updating will be tried again after 24 hours have passed."); + _logger.LogInformation("Skipping update check due to previous failure. Updating will be tried again after 24 hours have passed."); return; } @@ -85,24 +92,24 @@ namespace Remotely.Agent.Services using var response = await httpClient.SendAsync(request); if (response.StatusCode == HttpStatusCode.NotModified) { - Logger.Write("Service Updater: Version is current."); + _logger.LogInformation("Service Updater: Version is current."); return; } - Logger.Write("Service Updater: Update found."); + _logger.LogInformation("Service Updater: Update found."); await InstallLatestVersion(); } catch (WebException ex) when ((ex.Response as HttpWebResponse).StatusCode == HttpStatusCode.NotModified) { - Logger.Write("Service Updater: Version is current."); + _logger.LogInformation("Service Updater: Version is current."); return; } catch (Exception ex) { - Logger.Write(ex); + _logger.LogError(ex, "Error while checking for updates."); } finally { @@ -119,7 +126,7 @@ namespace Remotely.Agent.Services var connectionInfo = _configService.GetConnectionInfo(); var serverUrl = connectionInfo.Host; - Logger.Write("Service Updater: Downloading install package."); + _logger.LogInformation("Service Updater: Downloading install package."); var downloadId = Guid.NewGuid().ToString(); var zipPath = Path.Combine(Path.GetTempPath(), "RemotelyUpdate.zip"); @@ -143,18 +150,18 @@ namespace Remotely.Agent.Services proc.Kill(); } - Logger.Write("Launching installer to perform update."); + _logger.LogInformation("Launching installer to perform update."); Process.Start(installerPath, $"-install -quiet -path {zipPath} -serverurl {serverUrl} -organizationid {connectionInfo.OrganizationID}"); } catch (WebException ex) when (ex.Status == WebExceptionStatus.Timeout) { - Logger.Write("Timed out while waiting to download update.", Shared.Enums.EventType.Warning); + _logger.LogWarning("Timed out while waiting to download update."); _lastUpdateFailure = DateTimeOffset.Now; } catch (Exception ex) { - Logger.Write(ex); + _logger.LogError(ex, "Error while installing latest version."); _lastUpdateFailure = DateTimeOffset.Now; } finally diff --git a/README.md b/README.md index d7be015e..afec7b1c 100644 --- a/README.md +++ b/README.md @@ -26,8 +26,14 @@ mkdir -p /var/www/remotely docker run -d --name remotely --restart unless-stopped -p 5000:5000 -v /var/www/remotely:/remotely-data immybot/remotely:latest ``` -## HTTPS Configuration -When using HTTPS with a reverse proxy (e.g. Caddy or Nginx), be sure to set `RedirectToHttps` to `true` (which is the default) in `appsettings.json`. This is needed for the server to set the correct scheme when embedding the server URL in the clients. The scheme is supposed to be updated by the ForwardedHeaders feature, but it doesn't appear to be working in some scenarios. +## Important: HTTPS and Reverse Proxies +When using a reverse proxy, Remotely uses forwarded headers to determine the scheme (http/https) and host (server URL) to embed in the installers and remote control files when they are downloaded. To avoid injection attacks, ASP.NET Core defaults to only accepting forwarded headers from loopback addresses. + +Remotely will also add the default Docker host IP (172.17.0.1). + +**If you are using a non-default configuration, you must add the reverse proxy address to the `KnownProxies` array in appsettings.json.** + +Remotely will not work if it receives forwarded requests from addresses that aren't in that list. ## After Installation - Data for Remotely will be saved in `/var/www/remotely/` within two files: appsettings.json and Remotely.db. diff --git a/Remotely.sln b/Remotely.sln index 742e53ec..f05c4ba4 100644 --- a/Remotely.sln +++ b/Remotely.sln @@ -72,8 +72,8 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docker", "Docker", "{963B5555-30AE-428E-9686-59C4B6FEC052}" ProjectSection(SolutionItems) = preProject .docker\Dockerfile = .docker\Dockerfile - .docker\Dockerfile-old = .docker\Dockerfile-old - .docker\Dockerfile-rootless = .docker\Dockerfile-rootless + .docker\Dockerfile.old = .docker\Dockerfile.old + .docker\Dockerfile.rootless = .docker\Dockerfile.rootless .docker\DockerMain.sh = .docker\DockerMain.sh EndProjectSection EndProject diff --git a/Server/API/ClientDownloadsController.cs b/Server/API/ClientDownloadsController.cs index 7ded4841..c1113093 100644 --- a/Server/API/ClientDownloadsController.cs +++ b/Server/API/ClientDownloadsController.cs @@ -3,6 +3,8 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Extensions; using Microsoft.AspNetCore.Mvc; +using Microsoft.Build.Framework; +using Microsoft.Extensions.Logging; using Remotely.Server.Auth; using Remotely.Server.Services; using Remotely.Shared; @@ -23,22 +25,18 @@ namespace Remotely.Server.API [ApiController] public class ClientDownloadsController : ControllerBase { - private readonly IApplicationConfig _appConfig; private readonly IEmbeddedServerDataSearcher _embeddedDataSearcher; private readonly SemaphoreSlim _fileLock = new(1,1); private readonly IWebHostEnvironment _hostEnv; + public ClientDownloadsController( IWebHostEnvironment hostEnv, - IApplicationConfig appConfig, IEmbeddedServerDataSearcher embeddedDataSearcher) { _hostEnv = hostEnv; - _appConfig = appConfig; _embeddedDataSearcher = embeddedDataSearcher; } - private string EffectiveScheme => _appConfig.RedirectToHttps ? "https" : Request.Scheme; - [HttpGet("desktop/{platformID}")] public async Task GetDesktop(string platformID) { @@ -132,7 +130,7 @@ namespace Remotely.Server.API var hostIndex = fileContents.IndexOf("HostName="); var orgIndex = fileContents.IndexOf("Organization="); - fileContents[hostIndex] = $"HostName=\"{EffectiveScheme}://{Request.Host}\""; + fileContents[hostIndex] = $"HostName=\"{Request.Scheme}://{Request.Host}\""; fileContents[orgIndex] = $"Organization=\"{organizationId}\""; var fileBytes = Encoding.UTF8.GetBytes(string.Join("\n", fileContents)); return File(fileBytes, "application/octet-stream", fileName); @@ -140,7 +138,7 @@ namespace Remotely.Server.API private async Task GetDesktopFile(string filePath, string organizationId = null) { - var serverUrl = $"{EffectiveScheme}://{Request.Host}"; + var serverUrl = $"{Request.Scheme}://{Request.Host}"; var embeddedData = new EmbeddedServerData(new Uri(serverUrl), organizationId); var result = await _embeddedDataSearcher.GetRewrittenStream(filePath, embeddedData); @@ -163,7 +161,7 @@ namespace Remotely.Server.API case "WindowsInstaller": { var filePath = Path.Combine(_hostEnv.WebRootPath, "Content", "Remotely_Installer.exe"); - var serverUrl = $"{EffectiveScheme}://{Request.Host}"; + var serverUrl = $"{Request.Scheme}://{Request.Host}"; var embeddedData = new EmbeddedServerData(new Uri(serverUrl), organizationId); var result = await _embeddedDataSearcher.GetRewrittenStream(filePath, embeddedData); diff --git a/Server/Dockerfile-local b/Server/Dockerfile.local similarity index 100% rename from Server/Dockerfile-local rename to Server/Dockerfile.local diff --git a/Server/Dockerfile-old b/Server/Dockerfile.old similarity index 100% rename from Server/Dockerfile-old rename to Server/Dockerfile.old diff --git a/Server/Dockerfile-rootless b/Server/Dockerfile.rootless similarity index 100% rename from Server/Dockerfile-rootless rename to Server/Dockerfile.rootless diff --git a/Server/Program.cs b/Server/Program.cs index edb3ae7b..9d8f3643 100644 --- a/Server/Program.cs +++ b/Server/Program.cs @@ -131,6 +131,9 @@ services.Configure(options => options.ForwardedHeaders = ForwardedHeaders.All; options.ForwardLimit = null; + // Default Docker host. We want to allow forwarded headers from this address. + options.KnownProxies.Add(IPAddress.Parse("172.17.0.1")); + if (knownProxies?.Any() == true) { foreach (var proxy in knownProxies) diff --git a/Shared/Services/FileLogger.cs b/Shared/Services/FileLogger.cs index ca0325de..0f6cff53 100644 --- a/Shared/Services/FileLogger.cs +++ b/Shared/Services/FileLogger.cs @@ -1,10 +1,12 @@ using Microsoft.Extensions.Logging; using Remotely.Shared.Extensions; +using Remotely.Shared.Utilities; using System; using System.Collections.Concurrent; using System.Diagnostics; using System.IO; using System.Linq; +using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; @@ -19,6 +21,7 @@ namespace Remotely.Shared.Services private readonly string _applicationName; private readonly string _categoryName; private readonly System.Timers.Timer _sinkTimer = new(5000) { AutoReset = false }; + public FileLogger(string applicationName, string categoryName) { _applicationName = applicationName?.SanitizeFileName() ?? string.Empty; @@ -74,22 +77,12 @@ namespace Remotely.Shared.Services public bool IsEnabled(LogLevel logLevel) { - switch (logLevel) + return logLevel switch { -#if DEBUG - case LogLevel.Trace: - case LogLevel.Debug: - return true; -#endif - case LogLevel.Information: - case LogLevel.Warning: - case LogLevel.Error: - case LogLevel.Critical: - return true; - case LogLevel.None: - default: - return false; - } + LogLevel.Trace or LogLevel.Debug => EnvironmentHelper.IsDebug, + LogLevel.Information or LogLevel.Warning or LogLevel.Error or LogLevel.Critical => true, + _ => false, + }; } public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) @@ -106,7 +99,7 @@ namespace Remotely.Shared.Services } catch (Exception ex) { - Console.WriteLine($"Error queueing log entry: {ex.Message}"); + Debug.WriteLine($"Error queueing log entry: {ex.Message}"); } } @@ -133,10 +126,38 @@ namespace Remotely.Shared.Services private void CheckLogFileExists() { - Directory.CreateDirectory(Path.GetDirectoryName(LogPath)!); + _ = Directory.CreateDirectory(Path.GetDirectoryName(LogPath)!); + if (!File.Exists(LogPath)) { File.Create(LogPath).Close(); + + try + { + if (OperatingSystem.IsWindows()) + { + Process.Start("cmd", $"/c icacls \"{LogPath}\" /grant Users:M").WaitForExit(1_000); + } + else if (OperatingSystem.IsLinux()) + { + Process.Start("sudo", $"chmod 775 {LogPath}").WaitForExit(1_000); + } + } + catch (Exception ex) + { + Debug.WriteLine($"Error modifying log file permissions: {ex.Message}"); + } + } + + if (File.Exists(LogPath)) + { + var fi = new FileInfo(LogPath); + while (fi.Length > 1_000_000) + { + var content = File.ReadAllLines(LogPath); + File.WriteAllLines(LogPath, content.Skip(10)); + fi = new FileInfo(LogPath); + } } } @@ -195,7 +216,7 @@ namespace Remotely.Shared.Services } catch (Exception ex) { - Console.WriteLine($"Error writing log entry: {ex.Message}"); + Debug.WriteLine($"Error writing log entry: {ex.Message}"); } finally { diff --git a/Shared/Services/ProcessInvoker.cs b/Shared/Services/ProcessInvoker.cs index 8cf77f19..c2496a77 100644 --- a/Shared/Services/ProcessInvoker.cs +++ b/Shared/Services/ProcessInvoker.cs @@ -1,5 +1,6 @@ using System; using System.Diagnostics; +using Microsoft.Extensions.Logging; using Remotely.Shared.Utilities; namespace Remotely.Shared.Services @@ -11,6 +12,13 @@ namespace Remotely.Shared.Services public class ProcessInvoker : IProcessInvoker { + private readonly ILogger _logger; + + public ProcessInvoker(ILogger logger) + { + _logger = logger; + } + public string InvokeProcessOutput(string command, string arguments) { try @@ -30,7 +38,7 @@ namespace Remotely.Shared.Services } catch (Exception ex) { - Logger.Write(ex, "Failed to start process."); + _logger.LogError(ex, "Failed to start process."); return string.Empty; } } diff --git a/Shared/Utilities/Logger.cs b/Shared/Utilities/Logger.cs index 233b7fd6..8ba729a2 100644 --- a/Shared/Utilities/Logger.cs +++ b/Shared/Utilities/Logger.cs @@ -1,4 +1,5 @@ using Remotely.Shared.Enums; +using Remotely.Shared.Services; using Remotely.Shared.Utilities; using System; using System.Diagnostics; @@ -154,7 +155,7 @@ namespace Remotely.Shared.Utilities File.Create(LogPath).Close(); if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { - Process.Start("sudo", $"chmod 777 {LogPath}").WaitForExit(); + Process.Start("sudo", $"chmod 775 {LogPath}").WaitForExit(); } } if (File.Exists(LogPath)) diff --git a/submodules/Immense.RemoteControl b/submodules/Immense.RemoteControl index b7d93772..a2b9a545 160000 --- a/submodules/Immense.RemoteControl +++ b/submodules/Immense.RemoteControl @@ -1 +1 @@ -Subproject commit b7d9377237fcb1d60060ad8d3470815920975df0 +Subproject commit a2b9a545671c05ad156404ca82879c9de0f0c0f8