BastionGuard Secure GUI

1. Overview

BastionGuard Secure GUI is a GTK4/gtkmm front-end that allows the user to select a trusted payment/e-commerce domain from a configuration allowlist and launch the BastionGuard-secure sandboxed browsing flow as a subprocess. The GUI is designed as a lightweight selector/launcher and intentionally delegates security enforcement to the underlying secure entry point.


2. Primary Responsibilities

  • Render a minimal GUI with consistent BastionGuard styling (sidebar + content).
  • Load the payment allowlist from ~/.config/BastionGuard/payments.json ("list" array).
  • Offer a dropdown selector for trusted domains.
  • Launch the secure browsing flow by running BastionGuard-secure <url> via Gio::Subprocess.
  • Terminate the sandbox subprocess on window close/cancel (best-effort SIGTERM).
  • Initialize i18n early by loading language environment from ~/.config/BastionGuard/lang.conf.

3. Key Dependencies

  • GTK4 / gtkmm:
    • Gtk::Window, Gtk::Box, Gtk::HeaderBar, Gtk::DropDown, Gtk::MessageDialog
    • Gtk::Application
    • Gtk::StringList
  • GIO / giomm:
    • Gio::Subprocess for launching the secure sandbox entry point.
    • wait_check_async for non-blocking completion handling.
  • gettext/glib i18n:
    • bindtextdomain, textdomain, _()
  • nlohmann/json for parsing payments.json.
  • Internal project utilities:
    • StyleProvider.hppload_style()
    • Resource.hppresource(...) used to load embedded assets (icons, sidebar logo).

4. File/Config Contracts

4.1 Payments allowlist

The GUI loads payment domains from:

~/.config/BastionGuard/payments.json

Expected schema (minimum):

{
  "list": [
    "paypal.com",
    "stripe.com"
  ]
}

If the file is missing or invalid, the GUI falls back to a default entry (paypal.com) to avoid an empty dropdown.


4.2 Language environment configuration

The GUI loads environment variables from:

~/.config/BastionGuard/lang.conf

Format:

LANG=it_IT.UTF-8
LC_ALL=it_IT.UTF-8

Each valid line is applied via setenv(key, val, 1) before calling setlocale() and initializing gettext.


5. UI Structure

5.1 Window characteristics

  • Fixed-size window: 640×300 default
  • Non-resizable
  • Custom header bar with minimize/close icons
  • Sidebar layout consistent with other BastionGuard windows

5.2 Widgets and layout

  • Sidebar:
    • Logo image: resource("logo-sidebar.png")
    • Brand label: “BastionGuard”
  • Content area:
    • Instruction label (translated via _())
    • Gtk::DropDown populated by Gtk::StringList
    • Hint label describing the config source (payments.json)
    • Action buttons:
      • Cancel
      • Open in Secure Browser

6. Domain Loading Logic

6.1 Path resolution

The payments config path is derived from:

Glib::get_user_config_dir() + "/BastionGuard/payments.json"

6.2 JSON validation rules

The loader enforces these conditions:

  • The file must exist and be readable.
  • The JSON root must be an object.
  • The object must contain "list" as an array.
  • Each element in "list" must be a string.

If any validation step fails, the GUI logs warnings to stderr and returns an empty list (triggering fallback).


7. Secure Sandbox Launch Flow

7.1 Selection → URL construction

When the user clicks Open in Secure Browser:

  1. Read selected index from the dropdown.
  2. Validate index bounds.
  3. Read domain string and validate non-empty.
  4. Build URL as: https://<domain>.

7.2 Subprocess execution

The secure flow is started via:

Gio::Subprocess::create({"BastionGuard-secure", url}, Gio::Subprocess::Flags::NONE)

Behavioral notes:

  • The GUI disables itself (set_sensitive(false)) during execution to avoid multiple launches.
  • wait_check_async is used to avoid blocking the UI thread.
  • When the subprocess completes, the GUI hides itself (current behavior: close-on-finish).

8. Process Termination and Cleanup

8.1 Cancel button

  • Calls terminate_sandbox()
  • Hides the window

8.2 Window close path

on_close_request() overrides the close behavior and ensures:

  • terminate_sandbox() is called before returning control to GTK.

8.3 Termination strategy

The termination routine uses a best-effort approach:

  1. If a subprocess exists, send SIGTERM via send_signal(SIGTERM).
  2. If this fails, attempt force_exit() as fallback.

This is intended to avoid leaving orphaned secure browsing processes after the user closes the launcher UI.


9. Internationalization (i18n) Initialization Order

The program intentionally loads language configuration before gettext setup:

  1. Load lang.conf and call setenv() for each key/value.
  2. Apply locale via std::setlocale(LC_ALL, "").
  3. Initialize gettext via:
    • bindtextdomain("BastionGuard", LOCALEDIR)
    • bind_textdomain_codeset("BastionGuard", "UTF-8")
    • textdomain("BastionGuard")

This prevents inconsistent translations caused by locale being applied after gettext initialization.


10. Styling and Assets

  • load_style() is called during application startup to apply the BastionGuard CSS theme.
  • Assets are loaded through the internal resource() helper:
    • logo-sidebar.png
    • icon-minimize.png
    • icon-close.png

11. Error Handling Strategy

  • Non-fatal issues (missing icons, missing config, JSON errors) are logged to stderr and the UI continues with fallback behaviors.
  • Launch errors (Gio::Subprocess::create exceptions) show a modal warning dialog and re-enable the window.
  • Validation errors for selection/domain show a warning dialog and do not launch the subprocess.

12. Execution Summary

  1. Load language environment overrides (lang.conf).
  2. Initialize locale + gettext.
  3. Create GTK application and load global style.
  4. Show SecureGuiWindow.
  5. Load allowlisted domains from payments.json and populate dropdown.
  6. On Open: spawn BastionGuard-secure for the selected domain via Gio::Subprocess.
  7. On Cancel/Close: terminate subprocess best-effort and exit.