Skip to content
API Documentation
BastionGuard™
QuarantinePage.cpp
Go to the documentation of this file.
1/*
2 * BastionGuard™
3 * Copyright (C) 2025–2026 Calogero Scarnà
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 *
17 * BastionGuard™ is a trademark of Calogero Scarnà.
18 * The BastionGuard™ name and branding are not licensed under the GPL.
19 */
20
21#include "Resource.hpp"
22#include "QuarantinePage.hpp"
23#include "Quarantine.hpp"
24#include <gtkmm.h>
25#include <giomm.h>
26#include <filesystem>
27#include <iostream>
28#include <glib/gi18n.h>
29
30namespace fs = std::filesystem;
31
33: Gtk::Box(Gtk::Orientation::VERTICAL, 8),
34 emptyLabel(_("Nessun file in quarantena"))
35{
36 set_margin(12);
37
38 emptyLabel.set_halign(Gtk::Align::CENTER);
39 emptyLabel.set_valign(Gtk::Align::CENTER);
40
41 append(listBox);
42 append(emptyLabel);
43
44
47
48
49Glib::signal_timeout().connect(
50 sigc::mem_fun(*this, &QuarantinePage::refreshList), 10000);
51
52}
53
55
56 monitor.reset();
57
58
59 const std::string qpath = Quarantine::getQuarantinePath();
60 try {
61 if (!fs::exists(qpath)) {
62 fs::create_directories(qpath);
63 }
64 } catch (const std::exception& e) {
65 std::cerr << _("❌ Errore creazione cartella quarantena: ") << e.what() << std::endl;
66 }
67
68 try {
69 auto gfile = Gio::File::create_for_path(qpath);
70 monitor = gfile->monitor_directory();
71 if (monitor) {
72 monitor->signal_changed().connect(
73 sigc::mem_fun(*this, &QuarantinePage::onDirChanged));
74 }
75 } catch (const Glib::Error& ex) {
76 std::cerr << _("⚠ Errore attivazione monitor quarantena: ")
77 << ex.what() << std::endl;
78 }
79}
80
82
83 auto children = listBox.get_children();
84 for (auto* w : children) {
85 listBox.remove(*w);
86 }
87
88 const std::string quarantineDir = Quarantine::getQuarantinePath();
89 if (!fs::exists(quarantineDir)) {
90 emptyLabel.show();
91 return true;
92 }
93
94 bool any = false;
95 std::error_code ec_q;
96 for (const auto& entry : fs::directory_iterator(quarantineDir, ec_q)) {
97 if (ec_q) break;
98 std::error_code ec_type;
99 const fs::file_status status = entry.symlink_status(ec_type);
100 if (ec_type || !fs::is_regular_file(status))
101 continue;
102
103 // Un file .meta è un sidecar solo quando esiste il payload con lo
104 // stesso nome senza l'ultima estensione. In questo modo un malware
105 // reale chiamato, per esempio, sample.meta resta visibile nella GUI.
106 if (entry.path().extension() == ".meta") {
107 fs::path payload = entry.path();
108 payload.replace_extension();
109
110 std::error_code ec_payload;
111 const fs::file_status payload_status =
112 fs::symlink_status(payload, ec_payload);
113
114 if (!ec_payload && fs::is_regular_file(payload_status))
115 continue;
116 }
117
118 any = true;
119
120
121 auto rowBox = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::HORIZONTAL, 8);
122
123 auto name = entry.path().filename().string();
124 auto lbl = Gtk::make_managed<Gtk::Label>(name);
125 lbl->set_hexpand(true);
126 lbl->set_halign(Gtk::Align::START);
127
128 auto btnRestore = Gtk::make_managed<Gtk::Button>();
129 btnRestore->set_label(_("Ripristina"));
130
131 auto btnDelete = Gtk::make_managed<Gtk::Button>();
132 btnDelete->set_label(_("Elimina"));
133
134 const std::string fullPath = entry.path().string();
135
136 btnRestore->signal_clicked().connect([this, fullPath]() {
137 if (Quarantine::restore(fullPath)) {
138 refreshList();
139 }
140 });
141 btnDelete->signal_clicked().connect([this, fullPath]() {
142 if (Quarantine::remove(fullPath)) {
143 refreshList();
144 }
145 });
146
147 rowBox->append(*lbl);
148 rowBox->append(*btnRestore);
149 rowBox->append(*btnDelete);
150
151 listBox.append(*rowBox);
152 }
153
154 if (!any) {
155 emptyLabel.show();
156 } else {
157 emptyLabel.hide();
158 }
159
160 return true;
161}
162
163void QuarantinePage::onRestoreFile(const std::string& filepath) {
164 if (Quarantine::restore(filepath)) {
165 refreshList();
166 }
167}
168
169void QuarantinePage::onDeleteFile(const std::string& filepath) {
170 if (Quarantine::remove(filepath)) {
171 refreshList();
172 }
173}
174
175void QuarantinePage::onDirChanged(const Glib::RefPtr<Gio::File>&,
176 const Glib::RefPtr<Gio::File>&,
177 Gio::FileMonitor::Event)
178{
179 refreshList();
180}
#define _(s)
void onDirChanged(const Glib::RefPtr< Gio::File > &file, const Glib::RefPtr< Gio::File > &other_file, Gio::FileMonitor::Event event)
void onRestoreFile(const std::string &filepath)
Glib::RefPtr< Gio::FileMonitor > monitor
void onDeleteFile(const std::string &filepath)
Gtk::ListBox listBox
Gtk::Label emptyLabel
static bool restore(const std::string &quarantinedFile)
static bool remove(const std::string &quarantinedFile)
static std::string getQuarantinePath()