Wizard Window Core Component – UI-Driven Setup Orchestration

1. Component role

This file is a core component of the BastionGuard Wizard. It implements the primary GTK-based wizard window that drives the initial system configuration, collects user choices, and orchestrates privileged and non-privileged setup steps in a controlled sequence.

In practical terms, the Wizard Window provides:

  • a step-by-step UI (welcome → resolver → firewall → nftables → certificates → webserver → native host → user agent → banks → summary);
  • toggle-based selection of setup actions;
  • centralized logging into a GUI log view with timestamps;
  • a worker-thread execution model to keep the UI responsive;
  • a “single authentication” strategy for privileged operations, to avoid multiple password prompts.

2. Privilege handling and single authentication strategy

2.1 Root-session tracking

The global flag g_wizard_root_session_started is used as an internal indicator that an elevated session has already been initiated. When it is set, subsequent privileged operations can be executed without re-triggering Polkit authentication logic in the helper wrapper.

2.2 Safe quoting for shell execution

The helper shell_quote() escapes strings to be safely embedded in shell commands. This is critical because the Wizard dynamically builds commands that include file paths and user-provided values (e.g., web ports, extension IDs, script paths).

2.3 elev_cmd wrapper

elev_cmd(inner, action_id) is the Wizard’s central privilege wrapper:

  • If the process is already running as root (geteuid()==0) or the wizard session is marked as started, it runs /bin/bash -c directly.
  • Otherwise it prefers pkexec (Polkit), using --action-id when supported, and falls back to sudo.

This ensures compatibility across Polkit versions and distributions while reducing repeated prompts.


3. Wizard window UI structure

3.1 Navigation model

The Wizard uses:

  • a left sidebar of step buttons (Gtk::ToggleButton) for direct navigation;
  • a central stack (m_stack) holding each page widget;
  • a right-side navigation panel with Back/Next/Finish/Cancel.

Navigation state is controlled by:

  • set_page(idx): updates the visible page in the stack and the active sidebar button;
  • update_nav(): enables/disables buttons depending on the current step and whether the wizard is running;
  • on_next(), on_back(), on_finish(), on_cancel(): event handlers wired to UI buttons.

3.2 Pages and user options

The constructor sets up a sequence of pages, each representing a setup domain:

  • Resolver: enables local DNS resolver integration (127.0.0.1), plus browser DoH policies.
  • Firewall: opens required ports and adjusts user group memberships for log access.
  • Advanced Firewall (nftables): optional installation and activation if no other firewall is active.
  • Certificates: creates a local CA and server certificate and installs the CA into the OS trust store.
  • Webserver: configures nginx ports and vhost templates; includes distro selection and port entry fields.
  • Native Host: installs browser Native Messaging Host manifests (user-level) for extension integration.
  • User Agent: enables user-agent services for active users, with a “Run now” action.
  • Banks list (MISP): downloads the official bank warning list JSON to the user’s data directory.
  • Summary: generates and displays a final selection overview and execution log.

4. Logging and UI responsiveness

4.1 Thread-safe GUI logging

Logging is implemented using:

  • a mutex-protected queue (m_log_queue);
  • a GTK dispatcher (m_dispatcher) that flushes queued log lines into a Gtk::TextBuffer on the main thread;
  • timestamping for each log entry ([HH:MM:SS]).

This prevents UI thread violations while allowing background worker tasks to emit progress messages.

4.2 Background execution

The wizard executes long-running work in m_worker, a dedicated std::thread created by start_execution(). This keeps the UI responsive during system configuration.

Completion is signaled through m_done_dispatcher, which calls finish_execution(m_result_ok) on the main thread.


5. Execution pipeline and sequencing

5.1 on_finish(): pre-steps and orchestration

When the user clicks Execute:

  1. The wizard writes a persistent config marker (config.json) indicating the wizard was completed.
  2. If selected, it enables the User Agent service immediately.
  3. If selected and no firewall is active, it installs nftables configuration.
  4. It runs the network setup script BastionGuard-net-setup.sh (via pkexec subprocess) before the main privileged batch.
  5. If selected, it downloads the MISP banks list at user-level (no admin rights).
  6. Finally it starts the main combined execution flow (start_execution()worker_run()).

5.2 start_execution(): pre-authentication

start_execution() implements a “pre-auth” step by running pkexec /bin/true once. This warms up Polkit authentication and reduces friction during subsequent privileged operations.

5.3 worker_run(): combined privileged batch

worker_run() assembles a command list (cmds) and executes it in one elevated script using run_all_elevated_steps(). This is the primary “single prompt” mechanism.

Notable ordering rules:

  • Absolute pre-step: ClamAV daemon setup is inserted first and treated as critical.
  • Locale pre-step: the locale generation script (en_US.UTF-8) runs early to prevent locale-related failures later.
  • Selected steps: resolver override, firewall rules, certificates, and webserver config are appended based on toggles.
  • Service restart: the phishing scanner service is restarted at the end of the privileged batch (best-effort).

5.4 Post privileged batch

After privileged steps complete, user-level tasks can still run:

  • Native Messaging Host installation (user-level manifests) is executed after the privileged batch.

6. Key setup tasks implemented by this component

6.1 Browser DoH policy configuration

configure_browser_doh() installs policies for:

  • Firefox via /usr/lib/firefox/distribution/policies.json
  • Chromium-based browsers via managed policy JSON under /etc

If not running as root, it writes a temporary file and installs it using an elevated install -m 644 command invoked through elev_cmd().

6.2 NGINX web configuration

The wizard supports:

  • detecting nginx presence;
  • reading current listen ports from common nginx config locations;
  • generating config files from packaged templates with placeholder substitution;
  • applying changes through an elevated temporary script, followed by nginx -t and a service restart.

6.3 MISP banks list download

download_bank_list_user() fetches the MISP warning list JSON via curl and saves it to:

~/.local/share/BastionGuard/banks.json

This step explicitly avoids requiring administrative privileges.


7. Completion and user feedback

finish_execution() presents a final GTK dialog:

  • success: confirmation plus guidance (e.g., browser restart for Native Host);
  • failure: warning dialog advising the user to inspect the log output.

In both cases, it emits m_signal_finished to notify the rest of the application that the wizard flow ended.