using System.Security.AccessControl; using System.Security.Principal; namespace Remiss.Core.Security; /// /// En jobb-isolerad temp-mapp för PDF:er som innehåller patientdata. /// /// Ligger under LOCALAPPDATA (användarprofil), inte %TEMP%. /// ACL låses till nuvarande användare + SYSTEM + Administrators. /// skriver över och raderar allt – körs även vid fel. /// /// 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 } } }