Implemented support for enabling/disabling encryption

This commit is contained in:
Kenneth Skovhede
2024-08-20 17:10:34 +02:00
parent ae6d5112f8
commit ff196eb284
4 changed files with 52 additions and 5 deletions
@@ -39,6 +39,7 @@ namespace Duplicati.Server.Database
public const int ANY_BACKUP_ID = -1;
public const int SERVER_SETTINGS_ID = -2;
private readonly Dictionary<string, Backup> m_temporaryBackups = new Dictionary<string, Backup>();
private readonly bool m_encryptSensitiveFields;
private static HashSet<string> _encryptedFields =
BackendLoader.Backends.SelectMany(x => x.SupportedCommands ?? [])
.Concat(EncryptionLoader.Modules.SelectMany(x => x.SupportedCommands ?? []))
@@ -54,7 +55,9 @@ namespace Duplicati.Server.Database
])
.ToHashSet(StringComparer.OrdinalIgnoreCase);
public Connection(System.Data.IDbConnection connection, bool disableFieldEncryption)
{
m_encryptSensitiveFields = !disableFieldEncryption;
m_connection = connection;
m_errorcmd = m_connection.CreateCommand();
m_errorcmd.CommandText = @"INSERT INTO ""ErrorLog"" (""BackupID"", ""Message"", ""Exception"", ""Timestamp"") VALUES (?,?,?,?)";
@@ -64,6 +67,31 @@ namespace Duplicati.Server.Database
this.ApplicationSettings = new ServerSettings(this);
}
public void ReWriteAllFieldsIfEncryptionChanged()
{
var activeToken = m_encryptSensitiveFields
? "enc-v1-canary"
: "no-encryption";
// The token is automatically decrypted when the settings are loaded
// In case the password has changed, this will fail and return the encrypted
// hex-string, but will crash before reaching this point
if (this.ApplicationSettings.EncryptionCanaryToken != activeToken)
{
var backups = this.Backups;
foreach (var b in backups)
{
((Backup)b).LoadChildren(this);
AddOrUpdateBackup(b, false, null);
}
this.SetSettings(this.GetSettings(ANY_BACKUP_ID), ANY_BACKUP_ID);
this.ApplicationSettings.EncryptionCanaryToken = m_encryptSensitiveFields
? EncryptedFieldHelper.Encrypt(activeToken)
: activeToken;
}
}
public void LogError(string backupid, string message, Exception ex)
{
lock (m_lock)
@@ -222,7 +250,7 @@ namespace Duplicati.Server.Database
lock (m_lock)
using (var tr = transaction == null ? m_connection.BeginTransaction() : null)
{
List<ISetting> intercepted = values.ToList();
if (m_encryptSensitiveFields)
values = values.Select(x => new Setting
{
Filter = x.Filter,
@@ -582,7 +610,7 @@ namespace Duplicati.Server.Database
n.Name,
n.Description ?? "" , // Description is optional but the column is set to NOT NULL, an additional check is welcome
string.Join(",", n.Tags ?? new string[0]),
EncryptedFieldHelper.Encrypt(n.TargetURL)
m_encryptSensitiveFields ? EncryptedFieldHelper.Encrypt(n.TargetURL) : n.TargetURL,
update ? item.ID : n.DBPath
};
});
@@ -1,4 +1,4 @@
// Copyright (C) 2024, The Duplicati Team
// Copyright (C) 2024, The Duplicati Team
// https://duplicati.com, hello@duplicati.com
//
// Permission is hereby granted, free of charge, to any person obtaining a
@@ -59,6 +59,7 @@ namespace Duplicati.Server.Database
public const string PBKDF_CONFIG = "pbkdf-config";
public const string AUTOGENERATED_PASSPHRASE = "autogenerated-passphrase";
public const string DISABLE_VISUAL_CAPTCHA = "disable-visual-captcha";
public const string ENCRYPTION_CANARY_TOKEN = "encryption-canary-token";
}
private readonly Dictionary<string, string> settings;
@@ -651,6 +652,20 @@ namespace Duplicati.Server.Database
SaveSettings();
}
}
public string EncryptionCanaryToken
{
get
{
return settings[CONST.ENCRYPTION_CANARY_TOKEN];
}
set
{
lock (databaseConnection.m_lock)
settings[CONST.ENCRYPTION_CANARY_TOKEN] = value;
SaveSettings();
}
}
}
}
+2
View File
@@ -46,6 +46,8 @@ Error message: {0}", error); }
public static string TempdirShort { get { return LC.L(@"Temporary storage folder"); } }
public static string WebserverResetJwtConfigDescription { get { return LC.L(@"Reset the JWT configuration, invalidating any issued login tokens"); } }
public static string WebserverDisableVisualCaptchaDescription { get { return LC.L(@"Disable the visual captcha"); } }
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"); } }
}
internal static class Scheduler
{
+4 -2
View File
@@ -252,7 +252,6 @@ namespace Duplicati.Server
DataConnection.FixInvalidBackupId();
DataConnection.ApplicationSettings.UpgradePasswordToKBDF();
CreateApplicationInstance(writeToConsole);
StartOrStopUsageReporter();
@@ -290,6 +289,8 @@ namespace Duplicati.Server
PingPongThread.Start();
}
DataConnection.ReWriteAllFieldsIfEncryptionChanged();
ServerStartedEvent.Set();
ApplicationExitEvent.WaitOne();
}
@@ -705,7 +706,7 @@ namespace Duplicati.Server
throw new Exception(Strings.Program.DatabaseOpenError(ex.Message));
}
return new Database.Connection(con);
return new Database.Connection(con, Library.Utility.Utility.ParseBoolOption(commandlineOptions, "disable-db-encryption"));
}
public static void StartOrStopUsageReporter()
@@ -829,6 +830,7 @@ namespace Duplicati.Server
new Duplicati.Library.Interface.CommandLineArgument("ping-pong-keepalive", Duplicati.Library.Interface.CommandLineArgument.ArgumentType.Boolean, Strings.Program.PingpongkeepaliveShort, Strings.Program.PingpongkeepaliveLong),
new Duplicati.Library.Interface.CommandLineArgument("log-retention", Duplicati.Library.Interface.CommandLineArgument.ArgumentType.Timespan, Strings.Program.LogretentionShort, Strings.Program.LogretentionLong, DEFAULT_LOG_RETENTION),
new Duplicati.Library.Interface.CommandLineArgument("server-datafolder", Duplicati.Library.Interface.CommandLineArgument.ArgumentType.Path, Strings.Program.ServerdatafolderShort, Strings.Program.ServerdatafolderLong(DATAFOLDER_ENV_NAME), System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), Library.AutoUpdater.AutoUpdateSettings.AppName)),
new Duplicati.Library.Interface.CommandLineArgument("disable-db-encryption", Duplicati.Library.Interface.CommandLineArgument.ArgumentType.Boolean, Strings.Program.DisabledbencryptionShort, Strings.Program.DisabledbencryptionLong),
];
private static bool ReadOptionsFromFile(string filename, ref Library.Utility.IFilter filter, List<string> cargs, Dictionary<string, string> options)