1. Overview
The Quarantine module provides a user-facing interface to manage files isolated by BastionGuard. It lists quarantined items and allows the user to perform two controlled actions:
- Restore a quarantined file to its original location (via the quarantine backend)
- Delete a quarantined file permanently (via the quarantine backend)
The module is implemented as a GTKmm (GTK4) page. It continuously keeps the list synchronized with the quarantine directory using a filesystem monitor, with an additional periodic refresh fallback.
2. User Interface Structure
2.1 Layout
The page is implemented as a vertical container (Gtk::Box) containing:
- A
Gtk::ListBox(listBox) where quarantine rows are rendered - An empty-state label (
emptyLabel) displayed when no quarantined files exist
The empty label is centered both horizontally and vertically and displays:
No files in quarantine
2.2 Quarantine Rows
Each quarantined file is represented as a row composed of:
- A filename label (left-aligned, expandable)
- A Restore button
- A Delete button
Row structure:
[ FILENAME ] [ Restore ] [ Delete ]
3. Directory Monitoring and Refresh Model
3.1 Directory Monitor
To keep the list synchronized in near real time, the module creates a directory monitor using Gio::File::monitor_directory().
The monitor is installed by updateMonitor(), which:
- Resets any previous monitor instance
- Ensures the quarantine directory exists (creates it if missing)
- Attaches a filesystem change callback
On any directory change event, the callback onDirChanged(...) triggers a full refresh by calling:
refreshList()
3.2 Periodic Refresh Fallback
In addition to the filesystem monitor, a fallback refresh is scheduled every 10 seconds. This ensures the UI remains correct even on filesystems or environments where directory notifications may not fire reliably.
Fallback timer:
Glib::signal_timeout().connect(..., 10000)
The callback is the same list rebuild function:
bool QuarantinePage::refreshList()
4. List Rendering Logic
4.1 Full Rebuild Strategy
refreshList() rebuilds the entire list on each refresh. The process is:
- Remove all existing children from the list box
- Read the quarantine directory path from the quarantine backend
- Enumerate directory entries and render one row per valid quarantined file
- Show or hide the empty-state label depending on results
4.2 File Filtering Rules
During directory iteration, the module applies the following filters:
- Only regular files are listed (
entry.is_regular_file()) - Metadata files are ignored (files with extension
.meta)
This ensures the UI presents only user-relevant quarantined payload files, not internal quarantine metadata.
5. Restore and Delete Actions
5.1 Restore
When the user clicks Restore, the module calls the quarantine backend:
Quarantine::restore(fullPath)
If the restore succeeds, the list is immediately refreshed.
5.2 Delete
When the user clicks Delete, the module calls:
Quarantine::remove(fullPath)
If deletion succeeds, the list is refreshed.
6. Change Handling
Filesystem changes are handled using a simple strategy: any monitor event triggers a full list rebuild. The change callback does not attempt to interpret event types; it simply calls:
refreshList()
This approach prioritizes correctness and simplicity over incremental UI updates.
7. Design and Security Considerations
- Backend authority: restore/delete actions are delegated to the
Quarantinebackend, ensuring consistent enforcement of quarantine rules and metadata handling. - UI correctness: the combined use of a filesystem monitor and periodic fallback refresh reduces the risk of stale UI state.
- Metadata isolation: the UI explicitly filters out
.metafiles to avoid exposing internal quarantine metadata to the user. - Controlled operations: the only supported operations are restore and delete; no direct editing or execution paths exist in the UI layer.