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,32 @@
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace WebhookServer.Core.Auth;
|
||||
|
||||
public static class BearerVerifier
|
||||
{
|
||||
private const string Prefix = "Bearer ";
|
||||
|
||||
/// <summary>
|
||||
/// Compares the value of an Authorization header against an expected secret in fixed time.
|
||||
/// </summary>
|
||||
public static AuthResult Verify(string? authorizationHeader, string expectedSecret)
|
||||
{
|
||||
if (string.IsNullOrEmpty(expectedSecret))
|
||||
return AuthResult.Fail("server secret not configured");
|
||||
|
||||
if (string.IsNullOrEmpty(authorizationHeader))
|
||||
return AuthResult.Fail("missing Authorization header");
|
||||
|
||||
if (!authorizationHeader.StartsWith(Prefix, StringComparison.Ordinal))
|
||||
return AuthResult.Fail("Authorization header is not a Bearer token");
|
||||
|
||||
var presented = authorizationHeader.AsSpan(Prefix.Length).Trim();
|
||||
var presentedBytes = Encoding.UTF8.GetBytes(presented.ToString());
|
||||
var expectedBytes = Encoding.UTF8.GetBytes(expectedSecret);
|
||||
|
||||
return CryptographicOperations.FixedTimeEquals(presentedBytes, expectedBytes)
|
||||
? AuthResult.Ok()
|
||||
: AuthResult.Fail("bearer token mismatch");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user