commits
tags
using System.Security.AccessControl;
using System.Security.Principal;
namespace Remiss.Core.Security;
/// <summary>
/// En jobb-isolerad temp-mapp för PDF:er som innehåller patientdata.
/// <list type="bullet">
/// <item>Ligger under LOCALAPPDATA (användarprofil), inte %TEMP%.</item>
/// <item>ACL låses till nuvarande användare + SYSTEM + Administrators.</item>
/// <item><see cref="Dispose"/> skriver över och raderar allt – körs även vid fel.</item>
/// </list>
/// </summary>
public sealed class SecureTempStore : IDisposable
{
public string Root { get; }
public SecureTempStore(string baseDir)
{
Directory.CreateDirectory(baseDir);
Root = Path.Combine(baseDir, "job-" + Guid.NewGuid().ToString("N"));
var dir = Directory.CreateDirectory(Root);
TryRestrictAccess(dir);
}
public string NewFile(string name) => Path.Combine(Root, name);
[System.Runtime.Versioning.SupportedOSPlatform("windows")]
private static void TryRestrictAccess(DirectoryInfo dir)
{
try
{
var security = new DirectorySecurity();
security.SetAccessRuleProtection(isProtected: true, preserveInheritance: false);
const InheritanceFlags inherit = InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit;
var me = WindowsIdentity.GetCurrent().User!;
security.AddAccessRule(new FileSystemAccessRule(
me, FileSystemRights.FullControl, inherit, PropagationFlags.None, AccessControlType.Allow));
var admins = new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null);
security.AddAccessRule(new FileSystemAccessRule(
admins, FileSystemRights.FullControl, inherit, PropagationFlags.None, AccessControlType.Allow));
var system = new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null);
security.AddAccessRule(new FileSystemAccessRule(
system, FileSystemRights.FullControl, inherit, PropagationFlags.None, AccessControlType.Allow));
dir.SetAccessControl(security);
}
catch
{
// Bäst-möjligt: profilmappen är redan användar-scopad även utan detta.
}
}
public void Dispose()
{
try
{
if (!Directory.Exists(Root))
return;
foreach (var file in Directory.EnumerateFiles(Root, "*", SearchOption.AllDirectories))
SecureFile.Shred(file);
Directory.Delete(Root, recursive: true);
}
catch
{
// ignore – nästa körning städar kvarvarande job-* mappar vid behov
}
}
}