Initial WebhookServer implementation
Add the .NET 8 solution scaffolded against PLAN.md. Three projects share WebhookServer.Core (models, auth, execution, storage, IPC, callbacks) and WebhookServer.Service hosts an embedded Kestrel listener plus the named-pipe admin server. WebhookServer.Gui is a thin MVVM client over the pipe. Includes 25 unit tests covering HMAC verification, bearer auth, IP allowlist parsing, arg-template rendering, DPAPI round-trip, and the encrypt-on-save config store. Install/uninstall PowerShell scripts default to LocalSystem and accept a domain user or gMSA via -ServiceAccount. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
using System.Runtime.Versioning;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace WebhookServer.Core.Storage;
|
||||
|
||||
/// <summary>
|
||||
/// DPAPI helpers using <see cref="DataProtectionScope.LocalMachine"/> so the same machine
|
||||
/// (regardless of which Windows account the service runs under) can decrypt config secrets.
|
||||
/// Wire format is plain base64 of the protected blob — caller wraps in JSON.
|
||||
/// </summary>
|
||||
[SupportedOSPlatform("windows")]
|
||||
public static class DpapiSecret
|
||||
{
|
||||
public static string Protect(string plaintext)
|
||||
{
|
||||
if (string.IsNullOrEmpty(plaintext)) return "";
|
||||
var bytes = Encoding.UTF8.GetBytes(plaintext);
|
||||
var blob = ProtectedData.Protect(bytes, optionalEntropy: null, DataProtectionScope.LocalMachine);
|
||||
return Convert.ToBase64String(blob);
|
||||
}
|
||||
|
||||
public static string Unprotect(string base64)
|
||||
{
|
||||
if (string.IsNullOrEmpty(base64)) return "";
|
||||
var blob = Convert.FromBase64String(base64);
|
||||
var bytes = ProtectedData.Unprotect(blob, optionalEntropy: null, DataProtectionScope.LocalMachine);
|
||||
return Encoding.UTF8.GetString(bytes);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user