justin 0b7c20a1fa v0.1.3: hide-to-tray + tray toggle + context menu fix (#6)
* GUI: hide-to-tray on X button; tray persists until explicit Exit

The minimize-to-tray behavior already worked, but clicking the X button
killed the GUI process and took the tray with it. That made "tray when
the GUI window is closed" a UX dead end - the only way to get the tray
was to leave the window minimized.

Now:
  - X button / Alt+F4 -> hide window, tray stays alive
  - Tray double-click -> reopens window
  - File -> Exit (or tray's Exit menu) -> truly quits the process

Wired by adding a RealExitRequested event on MainViewModel that the
window subscribes to (so File -> Exit sets the ExitForReal flag before
calling Shutdown), and a parallel onExit callback on TrayIcon for the
tray menu's Exit item. The Closing handler checks ExitForReal: if
false (X / Alt+F4) it cancels the close and hides; if true, it disposes
the tray and lets the close proceed.

Auto-start at login is still TBD - if you want the tray to be there
without manually launching the GUI after a reboot, that's a separate
Task Scheduler entry. Skipping for now.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Add File -> Minimize to tray toggle (default on)

Adds a checkable MenuItem so the user can opt out of the hide-to-tray
behavior. Persisted per-user to %APPDATA%\WebhookServer\gui.json so the
choice survives restarts.

When ticked (default): X / Alt+F4 / minimize hide to tray, GUI process
keeps running, tray icon persists.

When unticked: X actually closes the app, minimize is a regular
Windows minimize.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Fix endpoint-row context menu: bindings via PlacementTarget.Tag

The ContextMenu lived in its own popup visual tree, so the menu items'
RelativeSource={RelativeSource AncestorType=Window} couldn't find the
Window and the bindings silently failed - none of Edit / Copy URL /
Toggle / Delete actually fired their commands.

Standard WPF workaround: park MainViewModel on each DataGridRow's Tag
(still in the Window's visual tree, so the row Setter binding resolves)
and reach it from the menu items via PlacementTarget.Tag. The toggle
command parameter likewise comes from PlacementTarget.DataContext (the
EndpointConfig the row represents).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* v0.1.3

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 11:31:42 -04:00

Webhook Server

A Windows-native webhook server that runs PowerShell, cmd / .bat, or any executable in response to incoming HTTP requests. Endpoints are configured in a desktop GUI; the actual server runs as a Windows Service so it survives reboots and works without anyone logged in.

Designed for sysadmins who want to wire up tools like Zerto pre/post scripts, GitHub webhooks, monitoring alerts, or backup jobs to Windows-side automation — without writing a custom listener every time.

Quickstart

  1. Download the latest installer: https://github.com/recklessop/webhook-server/releases/latest
  2. Run it. UAC accept → next, next, finish. Adds a Start Menu entry, registers and starts the Windows Service.
  3. Open Webhook Server from the Start Menu (auto-elevates).
  4. File → New endpoint, configure a slug + script, save, hit the URL.

Full first-time walkthrough: docs/installation.md

Highlights

  • Many endpoints, one service. Each webhook is a configured URL slug mapped to a script or command.
  • Per-endpoint auth — HMAC signature (GitHub / Stripe / Slack style), bearer token, or none.
  • Per-endpoint IP allowlist. Restrict by IP or CIDR. Empty list = open. Checked before auth so blocked IPs get a fast 403.
  • Per-endpoint Run As — run the hook as the service account (default), the user logged in at the keyboard (for UI hooks), or a named domain/local user via password.
  • Flexible execution. Windows PowerShell 5.1, PowerShell 7+, cmd / .bat, or any .exe.
  • Flexible input — any combination of: JSON body to stdin, query / headers as env vars, {{body.foo.bar}} template expansion into argv.
  • Sync or async per endpoint. Sync returns exit code + stdout / stderr to the caller; async returns 202 immediately.
  • Outbound callbacks. Optional per-endpoint URL the service POSTs run results to after the script finishes. HMAC-signed, retry-with-backoff. Required for async callers who want to know what happened.
  • Configurable network — bind to specific NICs, set the URL host shown in the GUI, configure trusted reverse proxies.
  • HTTPS optional. Bind a .pfx or cert-store thumbprint from the GUI.
  • Secrets at rest — bearer tokens, HMAC keys, RunAs passwords, and PFX passwords are DPAPI-encrypted (LocalMachine scope) in config.json.
  • Auto-snapshots. Every config save writes a Config Checkpoint; restore to any point with one click. Last 30 retained.

Architecture

+------------------+   named pipe    +-------------------------------+
|   GUI (WPF)      | <-------------> |  Windows Service              |
|  add / edit /    |  SYSTEM+admin   |  - Kestrel: hook listener     |
|  view logs       |  ACL'd          |  - Admin pipe server          |
+------------------+                 |  - Executor (process runner)  |
                                     |  - Callback dispatcher        |
                                     |  - Serilog file logging       |
                                     +-------------------------------+
                                                 |
                                     C:\ProgramData\WebhookServer\
                                       - config.json   (DPAPI-encrypted)
                                       - backups\      (auto-snapshots)
                                       - logs\         (daily rolling)

Documentation

Everything you need to operate the server:

Recipes:

A ready-to-drop-in Zerto-side script is included at scripts/examples/zerto-post-failover.ps1.

Requirements

  • Windows 10 / 11 / Server 2019+
  • x64
  • .NET 8 SDK to build (the released installer includes everything else)

Building from source

git clone https://github.com/recklessop/webhook-server.git
cd webhook-server

# Dev install (publishes + copies to C:\Program Files\WebhookServer + registers service)
powershell -ExecutionPolicy Bypass -File scripts\deploy.ps1

# Or build the installer locally (requires Inno Setup 6: winget install JRSoftware.InnoSetup)
powershell -ExecutionPolicy Bypass -File scripts\build-installer.ps1

License

TBD.

S
Description
Windows webhook server: HTTP requests trigger PowerShell or any executable, configured via a desktop GUI, running as a Windows Service. Built for Zerto pre/post scripts, GitHub webhooks, monitoring alerts - anywhere a Windows-side script needs to fire on HTTP.
https://jpaul.me Readme MIT 586 KiB
Languages
C# 75.6%
PowerShell 20.6%
Inno Setup 3.8%