56 lines
2.0 KiB
C#
56 lines
2.0 KiB
C#
using System.Security.AccessControl;
|
|
using System.Security.Cryptography;
|
|
using System.Text;
|
|
using System.Text.Json;
|
|
|
|
namespace PatchProbe.Cli.Auth;
|
|
|
|
internal sealed class DpapiCredentialStore : IDeviceCredentialStore
|
|
{
|
|
// %ProgramData%\PatchProbe\device.cred — machine-scoped, survives user changes
|
|
internal static readonly string StorePath = Path.Combine(
|
|
Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData),
|
|
"PatchProbe", "device.cred");
|
|
|
|
public bool IsEnrolled => File.Exists(StorePath);
|
|
|
|
public DeviceCredentials Load()
|
|
{
|
|
var cipher = File.ReadAllBytes(StorePath);
|
|
var plain = ProtectedData.Unprotect(cipher, null, DataProtectionScope.LocalMachine);
|
|
return JsonSerializer.Deserialize<DeviceCredentials>(Encoding.UTF8.GetString(plain))
|
|
?? throw new InvalidOperationException("Credential file is corrupt or empty.");
|
|
}
|
|
|
|
public void Save(DeviceCredentials credentials)
|
|
{
|
|
var dir = Path.GetDirectoryName(StorePath)!;
|
|
Directory.CreateDirectory(dir);
|
|
|
|
var plain = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(credentials));
|
|
var cipher = ProtectedData.Protect(plain, null, DataProtectionScope.LocalMachine);
|
|
|
|
File.WriteAllBytes(StorePath, cipher);
|
|
RestrictToAdmins(StorePath);
|
|
}
|
|
|
|
public void Delete()
|
|
{
|
|
if (File.Exists(StorePath))
|
|
File.Delete(StorePath);
|
|
}
|
|
|
|
private static void RestrictToAdmins(string path)
|
|
{
|
|
var fi = new FileInfo(path);
|
|
var acl = fi.GetAccessControl();
|
|
// Break inheritance; grant only SYSTEM and Administrators full control
|
|
acl.SetAccessRuleProtection(isProtected: true, preserveInheritance: false);
|
|
acl.AddAccessRule(new FileSystemAccessRule(
|
|
"SYSTEM", FileSystemRights.FullControl, AccessControlType.Allow));
|
|
acl.AddAccessRule(new FileSystemAccessRule(
|
|
"Administrators", FileSystemRights.FullControl, AccessControlType.Allow));
|
|
fi.SetAccessControl(acl);
|
|
}
|
|
}
|