Files
webhook-server/src/WebhookServer.Core/Models/ProtectedString.cs
T
justin 8ecfe84540 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>
2026-05-07 22:04:52 -04:00

30 lines
1.0 KiB
C#

using System.Text.Json.Serialization;
namespace WebhookServer.Core.Models;
/// <summary>
/// A secret value. <see cref="Encrypted"/> is the persistent (DPAPI-protected) form;
/// <see cref="Plaintext"/> is transient — the GUI sets it when submitting a new value
/// over the named pipe, and the service sets it after decrypting on load. Disk JSON
/// must never carry plaintext: <see cref="Storage.ConfigStore.SaveAsync"/> encrypts
/// then clears <see cref="Plaintext"/> before writing.
/// </summary>
public sealed class ProtectedString
{
[JsonPropertyName("encrypted")]
public string? Encrypted { get; set; }
[JsonPropertyName("plaintext")]
public string? Plaintext { get; set; }
[JsonIgnore]
public bool HasValue =>
!string.IsNullOrEmpty(Encrypted) || !string.IsNullOrEmpty(Plaintext);
public static ProtectedString FromPlaintext(string value) =>
new() { Plaintext = value };
public static ProtectedString FromEncrypted(string base64) =>
new() { Encrypted = base64 };
}