Files
lserp_cs_6.0/插件库/Lskj.AgentPet.Host/WindowsCredentialStore.cs
2026-08-14 14:28:28 +08:00

77 lines
2.7 KiB
C#

using System.Runtime.InteropServices;
using System.Text;
namespace Lskj.AgentPet.Host;
internal static class WindowsCredentialStore
{
internal const string DefaultAstrBotTarget = "Langsu.Lserp.AstrBot.ApiKey";
private const uint CredentialTypeGeneric = 1;
private const int MaximumSecretBytes = 2048;
public static void PopulateAstrBotApiKey(IDictionary<string, string?> environment)
{
ArgumentNullException.ThrowIfNull(environment);
if (environment.TryGetValue("LSERP_ASTRBOT_API_KEY", out string? configured)
&& !string.IsNullOrWhiteSpace(configured)) return;
string target = environment.TryGetValue("LSERP_ASTRBOT_CREDENTIAL_TARGET", out string? custom)
&& !string.IsNullOrWhiteSpace(custom)
? custom.Trim()
: DefaultAstrBotTarget;
if (target.Length is < 8 or > 128) return;
string? secret = ReadGenericSecret(target);
if (!string.IsNullOrWhiteSpace(secret)) environment["LSERP_ASTRBOT_API_KEY"] = secret;
}
private static string? ReadGenericSecret(string target)
{
if (!OperatingSystem.IsWindows()) return null;
if (!CredRead(target, CredentialTypeGeneric, 0, out nint address) || address == 0)
return null;
try
{
NativeCredential credential = Marshal.PtrToStructure<NativeCredential>(address);
if (credential.CredentialBlob == 0
|| credential.CredentialBlobSize is 0 or > MaximumSecretBytes)
return null;
byte[] bytes = new byte[credential.CredentialBlobSize];
Marshal.Copy(credential.CredentialBlob, bytes, 0, bytes.Length);
return Encoding.Unicode.GetString(bytes).TrimEnd('\0').Trim();
}
finally
{
CredFree(address);
}
}
[DllImport("advapi32.dll", EntryPoint = "CredReadW", CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CredRead(
string target,
uint type,
int reservedFlag,
out nint credential);
[DllImport("advapi32.dll", SetLastError = false)]
private static extern void CredFree(nint buffer);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct NativeCredential
{
public uint Flags;
public uint Type;
public nint TargetName;
public nint Comment;
public System.Runtime.InteropServices.ComTypes.FILETIME LastWritten;
public uint CredentialBlobSize;
public nint CredentialBlob;
public uint Persist;
public uint AttributeCount;
public nint Attributes;
public nint TargetAlias;
public nint UserName;
}
}