using System.Security.Cryptography;
using System.Text;
namespace LlamaApp.Common;
///
/// One-way helper around Windows DPAPI for secrets persisted in
/// settings.json (currently the Hugging Face access token). The token
/// grants the user's HF private/gated-repo access, and a plaintext per-user
/// file is readable by every process running as that user — DPAPI's
/// CurrentUser scope binds the blob to this user on this machine, so a
/// copied/stolen settings file no longer carries a working credential.
///
/// Best-effort by design: anything unprotectable (a file from another
/// machine/user, corruption, or a missing DPAPI on a non-Windows host) reads
/// back as empty and the UI simply treats the token as unset.
///
public static class SecretProtector
{
///
/// Encrypts for the current user (DPAPI,
/// CurrentUser scope) and returns it as base64. Empty input yields
/// the empty string — an unset secret stays unset on disk.
///
public static string Protect(string plain)
{
if (string.IsNullOrEmpty(plain)) return "";
var encrypted = ProtectedData.Protect(
Encoding.UTF8.GetBytes(plain), optionalEntropy: null, DataProtectionScope.CurrentUser);
return Convert.ToBase64String(encrypted);
}
///
/// Decrypts a blob. Empty input yields the empty
/// string; any failure (wrong machine/user, corruption, non-Windows) also
/// yields the empty string rather than throwing — the caller treats the
/// secret as unset.
///
public static string Unprotect(string? protectedBase64)
{
if (string.IsNullOrWhiteSpace(protectedBase64)) return "";
try
{
var decrypted = ProtectedData.Unprotect(
Convert.FromBase64String(protectedBase64), optionalEntropy: null, DataProtectionScope.CurrentUser);
return Encoding.UTF8.GetString(decrypted);
}
catch
{
return "";
}
}
}