Realtime Alert GUI Service (TCP Listener + Token Gate + GTK Queue)

1. Overview

This module implements the Realtime Ransomware Alert GUI service for BastionGuard. It runs as a dedicated GTK4 (gtkmm) application that listens for local detection events sent by the Anti-Ransomware daemon over a loopback TCP channel. When a valid event is received, the service presents an AlertWindowRealtime dialog to the user and serializes multiple alerts through a FIFO queue.

To prevent unauthorized alert injection, incoming events are protected by a shared secret token. The GUI copies the system token into the user’s home on startup, enforces strict file permissions, and validates all incoming messages before rendering any UI.


2. Responsibilities

  • Initialize a GTK application dedicated to real-time alerts (org.BastionGuard.realtime.alert)
  • Bootstrap localization using ~/.config/BastionGuard/lang.conf + gettext
  • Load and apply UI CSS (BastionGuard.css)
  • Provision and load the per-user security token
  • Run a background TCP listener on 127.0.0.1:1025 and accept detection events
  • Validate messages (token + filtering) and enqueue alerts
  • Show alerts sequentially using AlertWindowRealtime and support “Ignore All”
  • Persist operational diagnostics to a user log file

3. Application Lifecycle

3.1 GTK Application Container

The service creates a GTK application instance with a stable application ID:

Gtk::Application::create("org.BastionGuard.realtime.alert")

The application is held open using app->hold() to prevent exiting when no dialog is visible. This is necessary because alerts arrive asynchronously from the daemon.


3.2 Startup Sequence

At construction time, the service performs a strict initialization order:

  1. resolve_paths() – determine HOME and create the user data directory
  2. ensure_user_token() – copy system token into user scope and set permissions
  3. load_token() – read the token into memory

During run(), it then:

  1. load_css() – apply BastionGuard stylesheet
  2. start_tcp_listener() – start listener thread
  3. app->run() – enter GTK main loop

4. Paths, State, and Logging

4.1 Home Resolution and Base Directory

The module derives the effective user home directory using:

  • Preferred: $HOME
  • Fallback: getpwuid(getuid())
  • Fallback: /tmp (last resort)

A user base directory is created:

~/.local/share/BastionGuard/

and is used for:

  • Token path: ~/.local/share/BastionGuard/ransomware.token
  • GUI log path: ~/.local/share/BastionGuard/alert-gui.log

4.2 User Log

Operational diagnostics are appended to a per-user log file via:

log_user(msg)

This is intentionally lightweight (best-effort file append). The log is used for debugging token issues, listener startup failures, and message filtering decisions.


5. Token Provisioning and Validation

5.1 Token Copy (System → User)

The GUI enforces a controlled trust boundary by copying the system token into the user’s home:

  • System token: /etc/BastionGuard/ransomware.token
  • User token: ~/.local/share/BastionGuard/ransomware.token

On startup, ensure_user_token():

  1. Requires the system token to exist; otherwise logs an error
  2. Removes any existing user token (forced refresh)
  3. Copies the system token into the user path
  4. Applies strict ownership and permissions:
    • chmod(0600)
    • chown(getuid(), getgid())

This prevents other local users from reading the token and reduces the chance of stale token mismatches.


5.2 Token Load

load_token() reads the first line of the user token file into SECURITY_TOKEN. If the file is missing or empty, the service logs an error and will subsequently reject all incoming messages (token mismatch).


6. TCP Listener: Local Event Ingestion

6.1 Listener Configuration

The listener runs in a detached background thread and binds exclusively to loopback:

  • Address: 127.0.0.1
  • Port: 1025
  • Protocol: TCP
  • Socket option: SO_REUSEADDR

The service enters a blocking accept() loop while the global flag running is true. Each accepted connection is read once into a fixed buffer and then closed.


6.2 Message Format

Incoming messages are expected to follow a simple delimiter format:

<token>|<file>|<family>

Messages missing two delimiters are ignored.


6.3 Filtering Rules

Before an alert is accepted, two filters are applied:

  • Internal-log suppression: events referencing antiransom_inotify.log are ignored to avoid feedback loops
  • Token validation: if token != SECURITY_TOKEN, the message is rejected and logged

Only validated events proceed to UI presentation.


6.4 Thread-to-GTK Dispatch

Because GTK operations must run on the main loop, accepted events are marshaled using:

Glib::signal_idle().connect_once(...)

This ensures that enqueue_alert(file, family) executes safely on the GTK thread.


7. Alert Queue and Window Serialization

7.1 Queue Semantics

Validated alerts are stored in:

std::queue<std::pair<std::string,std::string>> alertQueue

The queue prevents multiple concurrent dialogs and enforces a deterministic FIFO user experience.


7.2 enqueue_alert()

Adds the event and triggers UI presentation if no dialog is currently visible:

  • Push (file, family)
  • If current_window is null → call show_next()

7.3 show_next()

Creates and displays the next AlertWindowRealtime:

  • Skips if a window is already active or if the queue is empty
  • Pops the next alert
  • Constructs AlertWindowRealtime(file, family, alertQueue.size()) so the dialog can show how many are pending
  • Wires signals:
    • Ignore All: clears the queue and hides the current window
    • Hide: deletes the window, resets pointer, and displays the next alert
  • Displays via set_visible(true)

The “delete on hide” lifecycle ensures no stale dialog objects remain while preserving a straightforward sequential flow.


8. UI Styling

The service loads and registers the BastionGuard stylesheet:

resource("BastionGuard.css")

as a display-level provider at application priority. This ensures the alert dialogs match the main UI theme even when the realtime alert service runs as a standalone component.


9. Localization Bootstrap

Before GTK startup, the module loads language environment overrides from:

~/.config/BastionGuard/lang.conf

It then applies locale and initializes gettext:

  • setlocale(LC_ALL, "")
  • bindtextdomain("BastionGuard", LOCALEDIR)
  • bind_textdomain_codeset("BastionGuard", "UTF-8")
  • textdomain("BastionGuard")

This ensures that all UI strings and log messages using _() are localized consistently.


10. Security and Operational Considerations

  • Local-only exposure: binding to 127.0.0.1 prevents remote injection, but local processes can still attempt to connect.
  • Shared secret gate: the token check provides an additional authorization layer, reducing risk from untrusted local clients.
  • Token handling: forced refresh ensures the user token stays in sync with system policy; strict 0600 permissions reduce disclosure risk.
  • Message validation: the protocol is intentionally simple; malformed messages are ignored without crashing the listener.
  • Thread safety: UI operations are marshaled to the GTK main loop via Glib::signal_idle().
  • Alert storm controls: FIFO queueing and “Ignore All” provide a safe UX under high detection volumes.
  • Shutdown behavior: the listener thread is detached; stopping relies on the global running flag and process termination semantics.

In summary, the Realtime Alert GUI Service is a standalone, hardened UI endpoint that receives local ransomware detection events through a token-protected TCP channel, validates and filters them, and presents alerts sequentially to the user using a consistent BastionGuard visual style and localization pipeline.