8ecfe84540
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>
30 lines
1.0 KiB
C#
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 };
|
|
}
|