77 lines
2.7 KiB
C#
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;
|
|
}
|
|
}
|