Datensicherheit: Backup, Verschlüsselung, App-Sperre (Kapitel 13.3)

Automatisches rollierendes Backup der Datenbank beim Start mit
Wiederherstellung über die Einstellungen, versionierte Schema-Migration,
optionale Passwort-Verschlüsselung der LiteDB-Datei und eine App-Sperre
nach Inaktivität mit eigenem Passwort.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-13 13:07:36 +02:00
co-authored by Claude Sonnet 5
parent db1afff7e4
commit 48d07a2b99
25 changed files with 1228 additions and 21 deletions
+74
View File
@@ -0,0 +1,74 @@
using LehrerApp.Core.Services;
using Xunit;
namespace LehrerApp.Tests;
public sealed class AppLockServiceTests
{
[Fact]
public void NeueKonfiguration_IstStandardmaessigDeaktiviert()
{
using var temp = new TempAppData();
var service = new AppLockService(temp.Path);
Assert.False(service.IsEnabled);
Assert.False(service.HasPassword);
}
[Fact]
public void SetPassword_VerifyPassword_KorrektesPasswortWirdAkzeptiert()
{
using var temp = new TempAppData();
var service = new AppLockService(temp.Path);
service.SetPassword("geheim123");
Assert.True(service.HasPassword);
Assert.True(service.VerifyPassword("geheim123"));
Assert.False(service.VerifyPassword("falsch"));
}
[Fact]
public void Configure_WirdUeberNeueInstanzHinwegPersistiert()
{
using var temp = new TempAppData();
var first = new AppLockService(temp.Path);
first.SetPassword("geheim123");
first.Configure(enabled: true, timeoutMinutes: 15);
var second = new AppLockService(temp.Path);
Assert.True(second.IsEnabled);
Assert.Equal(15, second.TimeoutMinutes);
Assert.True(second.VerifyPassword("geheim123"));
}
[Fact]
public void VerifyPassword_OhneGesetztesPasswort_GibtFalseZurueck()
{
using var temp = new TempAppData();
var service = new AppLockService(temp.Path);
Assert.False(service.VerifyPassword("irgendwas"));
}
[Fact]
public void Configure_TimeoutUnterEinerMinute_WirdAufEineMinuteBegrenzt()
{
using var temp = new TempAppData();
var service = new AppLockService(temp.Path);
service.Configure(enabled: true, timeoutMinutes: 0);
Assert.Equal(1, service.TimeoutMinutes);
}
private sealed class TempAppData : IDisposable
{
public string Path { get; } = System.IO.Path.Combine(
System.IO.Path.GetTempPath(), $"lehrerapp-applock-tests-{Guid.NewGuid():N}");
public TempAppData() => Directory.CreateDirectory(Path);
public void Dispose() { if (Directory.Exists(Path)) Directory.Delete(Path, recursive: true); }
}
}