Native per-endpoint identity instead of the schtasks bridge:
- Service (default) keeps the existing path - hooks inherit the service
account (SYSTEM by default, or whatever you installed under).
- SpecificUser binds ProcessStartInfo.UserName / Password / Domain so
the hook runs in a batch logon session as the named account. Useful
for AD-write hooks that should NOT run as SYSTEM.
- InteractiveUser uses WTSQueryUserToken(WTSGetActiveConsoleSessionId)
+ DuplicateTokenEx + CreateProcessAsUser to drop the child into the
logged-in user's session with their environment block. This is the
real fix for "calc.exe should pop up on my desktop" - no Task
Scheduler bridge required. Stdio is captured via inheritable
anonymous pipes so the hook still returns stdout/stderr to the
caller normally.
Implementation:
- New RunAsMode enum + RunAsConfig model on EndpointConfig
- ConfigStore round-trips RunAs.Password through DPAPI alongside
bearer/HMAC/PFX secrets
- AdminPipeServer's secret-merge logic preserves the encrypted blob
when the GUI saves an endpoint without re-typing the password
- New WebhookServer.Core.Execution.Native namespace with NativeMethods
(P/Invoke) and InteractiveProcessLauncher (token-based launcher)
- ProcessExecutor branches on RunAs.Mode; the Service/SpecificUser
paths share .NET's Process; InteractiveUser uses the launcher
- GUI editor gets a "Run as" section: dropdown + conditional
username/password/load-profile fields under SpecificUser
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
GUI:
- URL column in endpoint grid + Copy URL toolbar button so the full
http://host:port/hook/<slug> is one click away
- Double-click a row to open the edit dialog
- Bearer/HMAC sections in the editor hide when the auth mode doesn't
use them, and reappear with previously-entered values when switched
back
- Log panel auto-scroll checkbox (default on) plus 3s polling so log
entries stream in without manual refresh
- Secret fields are now plain text with a Copy button. Anyone who can
open the admin-pipe-ACL'd GUI is already SYSTEM-equivalent on the
host, so masking the value just made recovery harder. PFX password
in Server Settings gets the same treatment.
Service:
- Admin pipe ops log info-level lines on every mutation
(create/update/delete/enable/disable/update-config/bind-https) so
GUI activity is visible in the Serilog file
- /hook/{slug} accepts GET as well as POST so a browser smoke-test
works without curl
- /favicon.ico returns 204 so browser hits don't pollute logs with 404s
- AdminPipeServer no longer strips plaintext secrets when sending
config to the GUI; the pipe ACL already restricts to SYSTEM/Admins
Scripts:
- New deploy.ps1: stops + republishes + copies binaries to
C:\Program Files\WebhookServer + (re)installs the Windows Service
- install-service.ps1 now uses sc.exe argv splatting consistently for
both create and config paths
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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>