From 01130f4cd542155f042c0dbbecbd2df192cdcc50 Mon Sep 17 00:00:00 2001 From: Kenneth Skovhede Date: Thu, 19 Feb 2026 17:30:57 +0100 Subject: [PATCH] Implemented option to enable folder-status service (disabled by default). --- .../RestAPI/Database/ServerSettings.cs | 7 +++++++ Duplicati/Library/RestAPI/Strings.cs | 1 + Duplicati/Server/Program.cs | 6 +++++- Duplicati/Server/WebServerLoader.cs | 5 +++++ .../Duplicati.ShellExtension.csproj | 20 ------------------- .../Services/FolderStatusService.cs | 8 ++++++++ 6 files changed, 26 insertions(+), 21 deletions(-) diff --git a/Duplicati/Library/RestAPI/Database/ServerSettings.cs b/Duplicati/Library/RestAPI/Database/ServerSettings.cs index 6fb0b2267..7569cab8c 100644 --- a/Duplicati/Library/RestAPI/Database/ServerSettings.cs +++ b/Duplicati/Library/RestAPI/Database/ServerSettings.cs @@ -82,6 +82,7 @@ namespace Duplicati.Server.Database public const string REMOTE_CONTROL_STORAGE_API_ID = "remote-control-storage-api-id"; public const string REMOTE_CONTROL_STORAGE_API_KEY = "remote-control-storage-api-key"; public const string REMOTE_CONTROL_STORAGE_ENDPOINT_URL = "remote-control-storage-endpoint-url"; + public const string ENABLE_FOLDER_STATUS_SERVICE = "enable-folder-status-service"; } private readonly Dictionary settings; @@ -708,6 +709,12 @@ namespace Duplicati.Server.Database set => SetAndSaveSetting(CONST.REMOTE_CONTROL_STORAGE_ENDPOINT_URL, value); } + public bool EnableFolderStatusService + { + get => Utility.ParseBool(settings[CONST.ENABLE_FOLDER_STATUS_SERVICE], false); + set => SetAndSaveSetting(CONST.ENABLE_FOLDER_STATUS_SERVICE, value.ToString()); + } + public string? BackupListSortOrder { get diff --git a/Duplicati/Library/RestAPI/Strings.cs b/Duplicati/Library/RestAPI/Strings.cs index 5c5b3ac62..695751ff7 100644 --- a/Duplicati/Library/RestAPI/Strings.cs +++ b/Duplicati/Library/RestAPI/Strings.cs @@ -80,6 +80,7 @@ Error message: {0}", error); } public static string WebserverPreAuthTokensDescription { get { return LC.L(@"A list of pre-authenticated tokens, separated with semicolons. These can be used in cases where the authentication is provided by a proxy. Each token must be at least 10 characters and not contain extended characters. The token must be provided by setting the header on each request to contain: Authentication: PreAuth "); } } public static string WebserverDisableApiExtensionsDescription { get { return LC.L(@"Disable the API extensions reported by the server. This will not disable the functionality, but will not report the extensions in the API responses. Use this option to degrade the server to a more basic API."); } } public static string WebserverTokenDurationDescription { get { return LC.L(@"The duration of the refresh tokens issued by the server. This value indicates how much time can pass without activity before the user is asked to log in again. The value must be greater than zero and is capped at 30 days."); } } + public static string WebserverEnableFolderStatusServiceDescription { get { return LC.L(@"Enable the folder status service for showing overlay icons in the file explorer"); } } public static string DisabledbencryptionLong { get { return LC.L(@"Use this option to disable database encryption of sensitive fields"); } } public static string DisabledbencryptionShort { get { return LC.L(@"Disable database encryption"); } } public static string LogwindowseventlogLong { get { return LC.L(@"Use this option to log to the Windows event log. The provided name is in the format Log:Source. If no log name is provided, ""Duplicati 2"" is used."); } } diff --git a/Duplicati/Server/Program.cs b/Duplicati/Server/Program.cs index 7b520f1c2..966d20762 100644 --- a/Duplicati/Server/Program.cs +++ b/Duplicati/Server/Program.cs @@ -572,13 +572,16 @@ namespace Duplicati.Server connection.ApplicationSettings.EnableForeverTokens(); if (commandlineOptions.ContainsKey(WebServerLoader.OPTION_WEBSERVICE_DISABLE_SIGNIN_TOKENS)) - connection.ApplicationSettings.DisableSigninTokens = Library.Utility.Utility.ParseBool(commandlineOptions[WebServerLoader.OPTION_WEBSERVICE_DISABLE_SIGNIN_TOKENS], true); + connection.ApplicationSettings.DisableSigninTokens = Library.Utility.Utility.ParseBoolOption(commandlineOptions, WebServerLoader.OPTION_WEBSERVICE_DISABLE_SIGNIN_TOKENS); if (commandlineOptions.ContainsKey(WebServerLoader.OPTION_WEBSERVICE_DISABLEAPIEXTENSIONS)) connection.ApplicationSettings.DisabledAPIExtensions = commandlineOptions.GetValueOrDefault(WebServerLoader.OPTION_WEBSERVICE_DISABLEAPIEXTENSIONS)? .Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) .ToHashSet(StringComparer.OrdinalIgnoreCase) ?? []; + if (commandlineOptions.ContainsKey(WebServerLoader.OPTION_WEBSERVICE_ENABLE_FOLDER_STATUS_SERVICE)) + connection.ApplicationSettings.EnableFolderStatusService = Library.Utility.Utility.ParseBoolOption(commandlineOptions, WebServerLoader.OPTION_WEBSERVICE_ENABLE_FOLDER_STATUS_SERVICE); + if (commandlineOptions.ContainsKey(WebServerLoader.OPTION_WEBSERVICE_PASSWORD)) connection.ApplicationSettings.SetWebserverPassword(commandlineOptions[WebServerLoader.OPTION_WEBSERVICE_PASSWORD]); @@ -1149,6 +1152,7 @@ namespace Duplicati.Server new CommandLineArgument(WebServerLoader.OPTION_WEBSERVICE_CORS_ORIGINS, CommandLineArgument.ArgumentType.Path, Strings.Program.WebserverCorsOriginsDescription, Strings.Program.WebserverCorsOriginsDescription, WebServerLoader.DEFAULT_OPTION_SPAPATHS), new CommandLineArgument(WebServerLoader.OPTION_WEBSERVICE_PRE_AUTH_TOKENS, CommandLineArgument.ArgumentType.String, Strings.Program.WebserverPreAuthTokensDescription, Strings.Program.WebserverPreAuthTokensDescription), new CommandLineArgument(WebServerLoader.OPTION_WEBSERVICE_TOKENDURATION, CommandLineArgument.ArgumentType.Timespan, Strings.Program.WebserverTokenDurationDescription, Strings.Program.WebserverTokenDurationDescription, WebServerLoader.DEFAULT_OPTION_TOKENDURATION), + new CommandLineArgument(WebServerLoader.OPTION_WEBSERVICE_ENABLE_FOLDER_STATUS_SERVICE, CommandLineArgument.ArgumentType.Boolean, Strings.Program.WebserverEnableFolderStatusServiceDescription, Strings.Program.WebserverEnableFolderStatusServiceDescription), new CommandLineArgument(PING_PONG_KEEPALIVE_OPTION, CommandLineArgument.ArgumentType.Boolean, Strings.Program.PingpongkeepaliveShort, Strings.Program.PingpongkeepaliveLong), new CommandLineArgument(DISABLE_UPDATE_CHECK_OPTION, CommandLineArgument.ArgumentType.Boolean, Strings.Program.DisableupdatecheckShort, Strings.Program.DisableupdatecheckLong), new CommandLineArgument(LOG_RETENTION_OPTION, CommandLineArgument.ArgumentType.Timespan, Strings.Program.LogretentionShort, Strings.Program.LogretentionLong, DEFAULT_LOG_RETENTION), diff --git a/Duplicati/Server/WebServerLoader.cs b/Duplicati/Server/WebServerLoader.cs index 790dd20b0..780e1dff4 100644 --- a/Duplicati/Server/WebServerLoader.cs +++ b/Duplicati/Server/WebServerLoader.cs @@ -156,6 +156,11 @@ public static class WebServerLoader /// public const string OPTION_WEBSERVICE_DISABLEAPIEXTENSIONS = "webservice-disable-api-extensions"; + /// + /// Enables the folder status service for the TrayIcon + /// + public const string OPTION_WEBSERVICE_ENABLE_FOLDER_STATUS_SERVICE = "webservice-enable-folder-status-service"; + /// /// The default listening interface /// diff --git a/Duplicati/ShellExtension/Duplicati.ShellExtension.csproj b/Duplicati/ShellExtension/Duplicati.ShellExtension.csproj index fa077582c..36e9d0e06 100644 --- a/Duplicati/ShellExtension/Duplicati.ShellExtension.csproj +++ b/Duplicati/ShellExtension/Duplicati.ShellExtension.csproj @@ -1,23 +1,3 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/Duplicati/WebserverCore/Services/FolderStatusService.cs b/Duplicati/WebserverCore/Services/FolderStatusService.cs index c0728ba0a..54e6de644 100644 --- a/Duplicati/WebserverCore/Services/FolderStatusService.cs +++ b/Duplicati/WebserverCore/Services/FolderStatusService.cs @@ -23,6 +23,7 @@ using Duplicati.Server.Database; using Duplicati.Server.Serialization.Interface; using Duplicati.WebserverCore.Abstractions; using Duplicati.WebserverCore.Dto; +using Duplicati.WebserverCore.Exceptions; namespace Duplicati.WebserverCore.Services; @@ -51,7 +52,11 @@ public class FolderStatusService : IFolderStatusService /// public IEnumerable GetAllFolderStatuses() { + if (!_connection.ApplicationSettings.EnableFolderStatusService) + throw new ServiceUnavailableException("Folder status service is disabled"); + var results = new List(); + var activeBackupIds = GetActiveBackupIds(); var backups = _connection.Backups; @@ -87,6 +92,9 @@ public class FolderStatusService : IFolderStatusService /// public FolderStatusDto GetFolderStatus(string path) { + if (!_connection.ApplicationSettings.EnableFolderStatusService) + throw new ServiceUnavailableException("Folder status service is disabled"); + if (string.IsNullOrEmpty(path)) { return new FolderStatusDto