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:1025and accept detection events - Validate messages (token + filtering) and enqueue alerts
- Show alerts sequentially using
AlertWindowRealtimeand 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:
resolve_paths()– determine HOME and create the user data directoryensure_user_token()– copy system token into user scope and set permissionsload_token()– read the token into memory
During run(), it then:
load_css()– apply BastionGuard stylesheetstart_tcp_listener()– start listener threadapp->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():
- Requires the system token to exist; otherwise logs an error
- Removes any existing user token (forced refresh)
- Copies the system token into the user path
- 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.logare 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_windowis null → callshow_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.1prevents 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
0600permissions 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
runningflag 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.