ScanPage.hpp

1. Overview

The ScanPage.hpp header defines the ScanPage class, a GTKmm (GTK4) UI component responsible for BastionGuard’s file and folder scanning workflow. The page provides both manual scanning (user-selected file/folder) and automatic monitoring (downloads and system locations) using an inotify-based engine. It integrates with a ClamAV subprocess for on-device scanning and optionally performs a cloud reputation check via MalwareBazaar, guarded by an API key and a privacy disclaimer.

Functionally, ScanPage provides:

  • Folder and file selection via GTK dialogs, with a “Scan” action
  • On-device scan execution via a ClamAV subprocess (async output parsing)
  • Auto-scan toggle for downloads/system monitoring
  • Inotify-based recursive monitoring with duplicate watch avoidance
  • Results presentation in a log view and an infected-files list
  • Cloud reputation checks (MalwareBazaar) with API key persistence
  • Special handling for AUR (Arch Linux) package build detection
  • Thread-safe, batched log buffering to keep the UI responsive

2. Dependencies and Includes

#include <gtkmm.h>
#include <giomm.h>
#include <glibmm.h>
#include <glib/gi18n.h>

#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <filesystem>
#include <mutex>
  • gtkmm.h – GTK4 widgets, containers, dialogs, and signals
  • giomm.h – GIO async APIs and Gio::Subprocess integration
  • glibmm.h – GLib main-loop helpers, IO sources, and utilities
  • glib/gi18n.h – gettext macro _() for localization-ready UI strings
  • <filesystem> – path operations and existence checks
  • <unordered_map> / <unordered_set> – watch bookkeeping and deduplication
  • <mutex> – log batching synchronization

3. Class Declaration and Scope

class ScanPage : public Gtk::Box

The class derives from Gtk::Box, enabling composition as a page in the main application navigation stack. The constructor takes a reference to a parent window to anchor dialogs and modal alerts.

explicit ScanPage(Gtk::Window& parent);

4. Public Interface

4.1 Constructor

explicit ScanPage(Gtk::Window& parent);

Initializes the scan UI, binds signals for user actions (choose folder/file, start scan, toggle auto-scan), prepares buffers and list widgets, loads persisted configuration, and sets up monitoring state as configured.


5. UI Components

ScanPage provides a composite layout made of manual scan controls, an auto-scan toggle, a text-based log output view, and an infected-file list area. It also includes a dedicated section for cloud API key management.

5.1 Manual Scan Controls

Gtk::Box buttonBox{Gtk::Orientation::HORIZONTAL, 5};
Gtk::Button btnChooseFolder{_("Seleziona cartella")};
Gtk::Button btnChooseFile{_("Seleziona file")};
Gtk::Button btnScan{_("Scansiona")};
  • btnChooseFolder – opens a folder chooser dialog
  • btnChooseFile – opens a file chooser dialog
  • btnScan – triggers scanning of the selected path
  • buttonBox – horizontal container providing consistent spacing

5.2 Auto-Scan Controls

Gtk::Box autoScanBox{Gtk::Orientation::HORIZONTAL, 6};
Gtk::Label autoScanLabel;
Gtk::Switch autoScanSwitch;
bool autoScanEnabled = true;

Toggle that enables/disables automatic monitoring and scanning of downloads/system paths. The autoScanEnabled flag caches the current state.


5.3 Log View

Gtk::TextView textView;
Glib::RefPtr<Gtk::TextBuffer> textBuffer;

Text-based output panel showing scan progress, warnings, detections, and cloud results. Updates are batched to avoid overloading the GTK main loop.


5.4 Infected Files List

Gtk::ListBox fileListBox;

List widget used to present detected infected files or items requiring attention. Entries are typically added as detections occur.


5.5 Cloud API Key UI

Gtk::Box apiKeyActionsBox{Gtk::Orientation::HORIZONTAL, 6};
Glib::RefPtr<Gtk::SizeGroup> apiKeySizeGroup;

Gtk::Box apiKeyBox{Gtk::Orientation::HORIZONTAL, 6};
Gtk::Entry apiKeyEntry;
Gtk::Button btnShowApiKey;
Gtk::Button btnApiKeySave{"Salva"};
Gtk::Button btnPrivacy;

bool apiKeyVisible = false;
std::string malwareBazaarApiKey;
  • apiKeyEntry – API key input field for MalwareBazaar cloud checks
  • btnShowApiKey – toggles key visibility
  • btnApiKeySave – persists the API key (cloud configuration)
  • btnPrivacy – shows a privacy disclaimer related to cloud queries
  • apiKeySizeGroup – aligns control sizing for consistent layout

6. Internal State and Data Model

ScanPage maintains state for scan execution, monitoring, watch bookkeeping, and batched logging.

6.1 ClamAV Subprocess State

Glib::RefPtr<Gio::Subprocess> subprocess;
Glib::RefPtr<Gio::InputStream> stdoutStream;
Glib::RefPtr<Gio::DataInputStream> dataStream;
  • subprocess – ClamAV scanner process instance
  • stdoutStream – raw stream for process output
  • dataStream – structured reader for line-based parsing

6.2 Log Batch Buffer

std::mutex logMutex;
std::vector<std::string> pendingLog;
bool logFlushScheduled = false;
  • pendingLog – queued messages awaiting insertion into the GTK buffer
  • logMutex – protects concurrent access to the queue
  • logFlushScheduled – prevents redundant UI flush scheduling

6.3 Manual Scan State

std::string selectedPath;
std::vector<std::string> infectedFilesBuffer;
bool scanInProgress = false;
  • selectedPath – current file/folder selected by the user
  • infectedFilesBuffer – collection used to accumulate detections
  • scanInProgress – guard to prevent overlapping scan runs

6.4 Download Directory Detection

std::vector<std::string> knownDownloadDirs;

Cache of directories considered “known download locations” derived from browser heuristics and XDG user dirs.


6.5 Inotify Monitoring State

int inotifyFd = -1;
Glib::RefPtr<Glib::IOSource> inotifySource;

std::unordered_map<int, std::string> watchMap;
std::unordered_set<std::string> alreadyWatched;
  • inotifyFd – inotify file descriptor
  • inotifySource – GLib IO source binding inotify events to the main loop
  • watchMap – watch descriptor to path mapping
  • alreadyWatched – deduplication set to avoid redundant recursive watches

7. User Actions (Callbacks)

void onChooseFolder();
void onChooseFile();
void onStartScan();

void onChooseFolderFinish(const Glib::RefPtr<Gio::AsyncResult>& result,
                          Glib::RefPtr<Gtk::FileDialog> dialog);

void onChooseFileFinish(const Glib::RefPtr<Gio::AsyncResult>& result,
                        Glib::RefPtr<Gtk::FileDialog> dialog);
  • onChooseFolder() – initiates async folder selection
  • onChooseFile() – initiates async file selection
  • onStartScan() – starts a scan for the current selection
  • onChooseFolderFinish() / onChooseFileFinish() – finalize selection and update internal state

7.1 API Key and Privacy Actions

void onApiKeySaveClicked();
void onToggleApiKeyVisibility();
void showCloudPrivacyDisclaimer();
  • onApiKeySaveClicked() – persists the MalwareBazaar API key
  • onToggleApiKeyVisibility() – shows/hides key contents in the entry field
  • showCloudPrivacyDisclaimer() – displays privacy messaging for cloud checks

8. Internal Logic

8.1 Logging Pipeline

void enqueueLog(const std::string& msg);
void flushLog();

Implements a batched log write pattern to reduce UI churn. Messages are collected into pendingLog under a mutex and flushed to textBuffer on the GTK main loop.


8.2 Configuration Persistence

void saveConfig();
void loadConfig();

void saveCloudConfig();
void loadCloudConfig();

Separates general page configuration from cloud-specific configuration to keep sensitive cloud settings isolated and easier to manage.


8.3 Subprocess Output Handling

void readOutput(const Glib::RefPtr<Gio::AsyncResult>& result);
void addFileToList(const std::string& filepath);

Parses ClamAV subprocess output asynchronously and updates the UI. Detected items are added to the infected-files list as appropriate.


8.4 Download Directory Discovery

std::vector<std::string> detectBrowserDownloadDirs();
std::vector<std::string> getXdgUserDirs();
bool isOutsideKnownDownloadDirs(const std::string& path);

Locates common download directories using browser heuristics and XDG user directory definitions, then uses this knowledge to focus automatic monitoring where it is most valuable.


8.5 Inotify Engine

void addInotifyRecursive(const std::string& path);
bool onInotifyEvent(Glib::IOCondition cond);
void handleInotifyFileEvent(const std::string& path, uint32_t mask);
  • addInotifyRecursive() – recursively registers watchers on a directory tree
  • onInotifyEvent() – IO callback invoked when inotify events are available
  • handleInotifyFileEvent() – routes file events to auto-scan logic

8.6 Automatic Monitoring Controls

void enableAutoScanDownloads();
void enableGlobalDownloadMonitor();
void disableAllMonitors();

Enables or disables automatic file monitoring. These methods coordinate watch registration, cleanup, and state transitions based on the autoScanSwitch setting.


8.7 Automatic Scan Heuristics

void scanFileAutomatically(const std::string& filepath);
bool isInterestingDownload(const std::string& path);
std::string resolveFinalDownloadedFile(const std::string& path);

Determines whether a file should be scanned automatically and attempts to resolve temporary or partial download artifacts to the final file (browser-dependent behavior).


8.8 AUR (Arch Linux) Handling

void onAurPkgbuildDetected(const std::string& path);
void scanAurAuto(const std::string& path);

Implements special-case handling for detected AUR-related files (e.g., PKGBUILD), enabling additional scrutiny in contexts where user-downloaded build scripts may pose risk.


8.9 Cloud Reputation Checks (MalwareBazaar)

void cloudCheckMalwareBazaar(const std::string& filepath);
void cloudCheckMalwareBazaarWorker(const std::string& filepath);

Performs an optional cloud lookup for a scanned file. The worker variant is designed for background execution, while the main entry point coordinates UI updates and result reporting.


8.10 Infected File Handling

void handleInfectedFile(const std::string& filepath);
void handleInfectedFiles(const std::vector<std::string>& files);
void handleInfectedFileWithName(const std::string& filepath, const std::string& virusName);

Centralizes detection handling, including per-file processing, batch handling, and cases where the detection name is explicitly available.


8.11 Alert and Safety Helpers

void showAlertWindow(const std::string& file, const std::string& family);
void logMessage(const std::string& msg);
bool safeExists(const std::string& p) noexcept;
  • showAlertWindow() – graphical fallback alert for detections
  • logMessage() – unified logging method (typically routes through the batching system)
  • safeExists() – existence check hardened for error conditions

9. Auto-Update (Scheduled Refresh)

Automatic behavior is event-driven rather than timer-driven. The page relies on inotify events delivered through a GLib IO source (inotifySource) to respond to filesystem changes in monitored directories.


10. Settings Storage

The page declares separate persistence routines for general configuration and cloud configuration:

void saveConfig();
void loadConfig();

void saveCloudConfig();
void loadCloudConfig();

Storage locations and formats are implementation-defined. Cloud settings should be protected appropriately, and UI should clearly disclose what is stored and where.


11. Helper Functions and Filesystem Layout

The component interacts with user directories and download locations identified via XDG conventions and browser-specific heuristics. Monitoring is performed recursively, and a deduplication strategy prevents re-watching the same directories.


12. Runtime and Security Considerations

  • Main-loop safety: UI updates must occur on the GTK main thread. Background work (cloud checks, heavy parsing) should be marshaled back safely.
  • Subprocess containment: ClamAV execution should enforce timeouts, handle exit codes, and sanitize paths passed to the scanner to avoid command injection.
  • Watch scalability: recursive inotify watches can be expensive; implement limits, avoid duplication (alreadyWatched), and handle inotify exhaustion gracefully.
  • Privacy and cloud checks: cloud lookups can leak file fingerprints or metadata; require explicit consent and provide clear disclaimers (btnPrivacy).
  • Secrets handling: API keys should be stored securely and never written to logs. Limit visibility with apiKeyVisible and protect configuration at rest.
  • Auto-scan policy: automatic scanning should apply only to “interesting” downloads to reduce noise and prevent scanning sensitive paths unnecessarily.
  • Safe file resolution: temporary download files should be resolved to their final paths before scanning (resolveFinalDownloadedFile()) to avoid partial-file false positives.