Skip to content
API Documentation
BastionGuard™
SettingsPage.cpp File Reference

Go to the source code of this file.

Classes

struct  MailSignatureConfig
struct  MailRelayProfile
struct  MailSecurityConfig
struct  TbSmtpEntry
struct  TbIdentityEntry

Namespaces

namespace  anonymous_namespace{SettingsPage.cpp}

Enumerations

enum class  BypassKind {
  Invalid , Domain , IPv4 , IPv6 ,
  CIDR
}

Functions

static bool anonymous_namespace{SettingsPage.cpp}::run_cmd (const std::vector< std::string > &argv, std::string *out_stdout=nullptr, bool silence_stderr=true)
static bool anonymous_namespace{SettingsPage.cpp}::pkexec_servicectl (const std::vector< std::string > &args, std::string *out_stdout=nullptr)
static std::string mail_json_path_user ()
static std::string iso_today_yyyy_mm_dd ()
static std::vector< std::string > split_semicolon_list (const std::string &input)
static std::string join_semicolon_list (const std::vector< std::string > &items)
static std::string make_profile_id (const std::string &label)
static void ensure_mail_json_exists ()
static bool run_privhelper_and_capture (const std::vector< std::string > &args, std::string &stdout_out, std::string &stderr_out, int &exit_status)
static bool write_mail_config_temp_json (const MailSecurityConfig &cfg, std::string &out_path)
static void append_to_textbuffer (const Glib::RefPtr< Gtk::TextBuffer > &buffer, const Glib::ustring &text)
static MailSecurityConfig load_mail_security_config ()
static bool save_mail_security_config (const MailSecurityConfig &cfg)
static std::string build_email_signature_preview_html (const MailSignatureConfig &sig)
static bool is_clamav_signature_file (const std::filesystem::path &p)
static Gtk::Window * create_log_popup (Gtk::Widget *owner, const Glib::RefPtr< Gtk::TextBuffer > &buffer)
static std::vector< std::filesystem::path > list_clamav_signatures (const std::filesystem::path &dir)
static std::string payments_json_path_user ()
static bool tb_parse_pref_line (const std::string &line, std::string &key, std::string &value)
static std::map< std::string, std::map< std::string, std::string > > tb_parse_ini_file (const std::string &path)
static std::string tb_find_default_profile ()
static std::vector< MailRelayProfile > tb_import_profiles (std::string &err_out)
static std::string normalize_domain_or_url (const std::string &in_raw)
static void ensure_payments_json_exists ()
static std::vector< std::string > load_payments_domains ()
static bool save_payments_domains (const std::vector< std::string > &domains_in, bool enabled_flag)
static bool update_payments_enabled_only (bool enabled_flag)
static std::string elev_cmd (const std::string &inner)
static bool write_temp_script_and_elevate (const std::string &script_contents, std::string *out_log=nullptr, int *exit_code=nullptr)
std::pair< int, int > read_webports_conf ()
bool copy_with_pkexec (const std::string &src, const std::string &dst)
bool restart_service (const std::string &svc)
bool update_ports_in_file (const std::string &file, int http_port, int https_port)
std::string detect_distro ()
static std::string detect_webserver ()
std::pair< int, int > read_current_ports (const std::string &)
bool update_webserver_ports (const std::string &websrv, int http_port, int https_port)
std::string anonymous_namespace{SettingsPage.cpp}::choose_clamd_conf_target ()
bool anonymous_namespace{SettingsPage.cpp}::atomic_install_with_pkexec (const std::string &tmp_src, const std::string &target)
bool anonymous_namespace{SettingsPage.cpp}::isServiceActive (const std::string &service, bool user=false)
bool isClamonaccRunning ()
static std::string normalize_locale (std::string s)
static std::vector< std::string > load_proxy_bypass_domains ()
static bool save_proxy_bypass_domains (const std::vector< std::string > &domains)
static BypassKind classify_bypass_entry (const std::string &s_in)
void show_service_error_dialog (const Glib::ustring &msg, const std::string &service)

Variables

static bool updatingToggle = false
static std::map< std::string, bool > toggleControlled

Enumeration Type Documentation

◆ BypassKind

enum class BypassKind
strong
Enumerator
Invalid 
Domain 
IPv4 
IPv6 
CIDR 

Definition at line 3885 of file SettingsPage.cpp.

Function Documentation

◆ append_to_textbuffer()

void append_to_textbuffer ( const Glib::RefPtr< Gtk::TextBuffer > & buffer,
const Glib::ustring & text )
static

Definition at line 332 of file SettingsPage.cpp.

334{
335 buffer->insert(buffer->end(), text);
336 auto mark = buffer->create_mark(buffer->end());
337}

References append_to_textbuffer().

Referenced by append_to_textbuffer().

◆ build_email_signature_preview_html()

std::string build_email_signature_preview_html ( const MailSignatureConfig & sig)
static

Definition at line 488 of file SettingsPage.cpp.

488 {
489 std::ostringstream html;
490
491 html << "<table cellpadding=\"0\" cellspacing=\"0\" border=\"0\" "
492 << "style=\"font-family:Arial,Helvetica,sans-serif;font-size:14px;color:#212529;\">"
493 << "<tr>";
494
495 if (!sig.logo_path.empty()) {
496 html << "<td style=\"vertical-align:top;padding-right:12px;\">"
497 << "<img src=\"file://" << sig.logo_path << "\" alt=\"logo\" width=\"72\" "
498 << "style=\"display:block;border:0;\">"
499 << "</td>";
500 }
501
502 html << "<td style=\"vertical-align:top;\">";
503
504 if (!sig.display_name.empty()) {
505 html << "<div style=\"font-size:16px;font-weight:700;color:#0d6efd;\">"
506 << sig.display_name << "</div>";
507 }
508
509 {
510 std::string roleLine;
511 if (!sig.job_title.empty()) roleLine += sig.job_title;
512 if (!sig.job_title.empty() && !sig.company.empty()) roleLine += " · ";
513 if (!sig.company.empty()) roleLine += sig.company;
514
515 if (!roleLine.empty()) {
516 html << "<div style=\"font-size:13px;color:#6c757d;\">"
517 << roleLine << "</div>";
518 }
519 }
520
521 html << "<div style=\"margin-top:8px;\">";
522
523 if (!sig.website.empty()) {
524 html << "<a href=\"" << sig.website << "\" "
525 << "style=\"color:#0d6efd;text-decoration:none;\">"
526 << sig.website << "</a><br>";
527 }
528
529 if (!sig.phone.empty()) {
530 html << "<span style=\"color:#212529;\">" << sig.phone << "</span><br>";
531 }
532
533 html << "<span style=\"color:#6c757d;\">Protected by BastionGuard</span>";
534 html << "</div>";
535 html << "</td></tr></table>";
536
537 return html.str();
538}
std::string display_name

References build_email_signature_preview_html(), MailSignatureConfig::company, MailSignatureConfig::display_name, MailSignatureConfig::job_title, MailSignatureConfig::logo_path, MailSignatureConfig::phone, and MailSignatureConfig::website.

Referenced by build_email_signature_preview_html().

◆ classify_bypass_entry()

BypassKind classify_bypass_entry ( const std::string & s_in)
static

Definition at line 3887 of file SettingsPage.cpp.

3887 {
3888 if (s_in.empty()) return BypassKind::Invalid;
3889
3890 // Strip eventuali bracket IPv6: [::1] → ::1
3891 std::string s = s_in;
3892 if (s.size() >= 2 && s.front() == '[' && s.back() == ']')
3893 s = s.substr(1, s.size() - 2);
3894
3895 // Caso CIDR: c'è uno slash, tipo "1.2.3.0/24" o "2a01::/32"
3896 auto slash = s.find('/');
3897 if (slash != std::string::npos) {
3898 const std::string addr = s.substr(0, slash);
3899 const std::string mask = s.substr(slash + 1);
3900 if (addr.empty() || mask.empty()) return BypassKind::Invalid;
3901
3902 // mask numerica
3903 for (char c : mask) if (!std::isdigit(static_cast<unsigned char>(c)))
3904 return BypassKind::Invalid;
3905 const int m = std::atoi(mask.c_str());
3906
3907 in_addr v4{};
3908 in6_addr v6{};
3909 if (::inet_pton(AF_INET, addr.c_str(), &v4) == 1) {
3910 if (m < 0 || m > 32) return BypassKind::Invalid;
3911 return BypassKind::CIDR;
3912 }
3913 if (::inet_pton(AF_INET6, addr.c_str(), &v6) == 1) {
3914 if (m < 0 || m > 128) return BypassKind::Invalid;
3915 return BypassKind::CIDR;
3916 }
3917 return BypassKind::Invalid;
3918 }
3919
3920 // Caso IPv4/IPv6 letterale
3921 {
3922 in_addr v4{};
3923 in6_addr v6{};
3924 if (::inet_pton(AF_INET, s.c_str(), &v4) == 1) return BypassKind::IPv4;
3925 if (::inet_pton(AF_INET6, s.c_str(), &v6) == 1) return BypassKind::IPv6;
3926 }
3927
3928 // Caso dominio DNS: deve avere almeno un punto, solo caratteri DNS validi.
3929 if (s.find('.') == std::string::npos) return BypassKind::Invalid;
3930 for (char c : s) {
3931 const unsigned char uc = static_cast<unsigned char>(c);
3932 if (!(std::isalnum(uc) || c == '.' || c == '-' || c == '_'))
3933 return BypassKind::Invalid;
3934 }
3935 if (s.front() == '.' || s.back() == '.' || s.front() == '-')
3936 return BypassKind::Invalid;
3937
3938 return BypassKind::Domain;
3939}
#define AF_INET
Definition bsc_ebpf.c:56
#define AF_INET6
Definition bsc_ebpf.c:57

References AF_INET, AF_INET6, CIDR, classify_bypass_entry(), Domain, Invalid, IPv4, and IPv6.

Referenced by SettingsPage::build_proxy_bypass_tab(), and classify_bypass_entry().

◆ copy_with_pkexec()

bool copy_with_pkexec ( const std::string & src,
const std::string & dst )

Definition at line 1158 of file SettingsPage.cpp.

1159{
1160 if (!fs::exists(src)) {
1161 std::cerr << _("[copy_with_pkexec] File sorgente non trovato: ") << src << std::endl;
1162 return false;
1163 }
1164
1165 return bg_process::run({"pkexec", "/usr/bin/install", "-D", "-m", "0644", src, dst}).ok();
1166}
#define _(s)
Result run(const std::vector< std::string > &args, bool merge_stderr=false, std::size_t limit=8U *1024U *1024U, const std::map< std::string, std::string > &environment={}, const std::function< bool(const std::string &)> &on_line={})

References _, copy_with_pkexec(), and bg_process::run().

Referenced by copy_with_pkexec().

◆ create_log_popup()

Gtk::Window * create_log_popup ( Gtk::Widget * owner,
const Glib::RefPtr< Gtk::TextBuffer > & buffer )
static

Definition at line 564 of file SettingsPage.cpp.

565{
566 auto* win = new Gtk::Window();
567 win->set_title(_("Installazione navigazione sicura"));
568 win->set_default_size(760, 420);
569 win->set_modal(true);
570 win->set_resizable(true);
571
572 if (owner) {
573 if (auto* root = owner->get_root()) {
574 if (auto* parent = dynamic_cast<Gtk::Window*>(root)) {
575 win->set_transient_for(*parent);
576 }
577 }
578 }
579
580 auto* outer = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::VERTICAL, 12);
581 outer->set_margin_top(12);
582 outer->set_margin_bottom(12);
583 outer->set_margin_start(12);
584 outer->set_margin_end(12);
585
586 auto* title = Gtk::make_managed<Gtk::Label>(_("Log installazione"));
587 title->set_halign(Gtk::Align::START);
588 title->add_css_class("title-4");
589 outer->append(*title);
590
591 auto* text = Gtk::make_managed<Gtk::TextView>();
592 text->set_buffer(buffer);
593 text->set_editable(false);
594 text->set_cursor_visible(false);
595 text->set_monospace(true);
596 text->set_wrap_mode(Gtk::WrapMode::WORD_CHAR);
597 text->set_vexpand(true);
598 text->set_hexpand(true);
599
600 auto* scroll = Gtk::make_managed<Gtk::ScrolledWindow>();
601 scroll->set_policy(Gtk::PolicyType::AUTOMATIC, Gtk::PolicyType::AUTOMATIC);
602 scroll->set_min_content_height(320);
603 scroll->set_child(*text);
604 outer->append(*scroll);
605
606 auto* btnClose = Gtk::make_managed<Gtk::Button>(_("Chiudi"));
607 btnClose->set_halign(Gtk::Align::END);
608 btnClose->signal_clicked().connect([win]() {
609 win->hide();
610 delete win;
611 });
612 outer->append(*btnClose);
613
614 win->set_child(*outer);
615 win->present();
616 return win;
617}

References _, and create_log_popup().

Referenced by SettingsPage::build_secure_payments_tab(), and create_log_popup().

◆ detect_distro()

std::string detect_distro ( )

Definition at line 1216 of file SettingsPage.cpp.

1217{
1218 std::string distro = "auto";
1219 std::string id;
1220
1221
1222 {
1223 const auto lsb = bg_process::run({"lsb_release", "-si"});
1224 std::string result = lsb.ok() ? lsb.output : std::string{};
1225
1226 result.erase(std::remove(result.begin(), result.end(), '\n'), result.end());
1227 result.erase(std::remove(result.begin(), result.end(), '\r'), result.end());
1228
1229 if (!result.empty() && result.find("n/a") == std::string::npos) {
1230 id = result;
1231 } else {
1232 std::cout << _("[detect_distro] lsb_release non fornisce info, fallback su /etc/os-release\n");
1233 }
1234 }
1235
1236
1237 if (id.empty() && std::filesystem::exists("/etc/os-release")) {
1238 std::ifstream file("/etc/os-release");
1239 std::string line;
1240 while (std::getline(file, line)) {
1241 if (line.rfind("ID=", 0) == 0)
1242 id = line.substr(3);
1243 }
1244 if (!id.empty() && id.front() == '"' && id.back() == '"')
1245 id = id.substr(1, id.size() - 2);
1246 }
1247
1248
1249 if (id.empty()) {
1250 if (std::filesystem::exists("/etc/arch-release")) id = "arch";
1251 else if (std::filesystem::exists("/etc/debian_version")) id = "debian";
1252 else if (std::filesystem::exists("/etc/redhat-release")) id = "fedora";
1253 else if (std::filesystem::exists("/etc/gentoo-release")) id = "gentoo";
1254 else if (std::filesystem::exists("/etc/slackware-version")) id = "slackware";
1255 else if (std::filesystem::exists("/usr/local/etc/rc.conf")) id = "bsd";
1256 }
1257
1258 // Normalizza minuscolo
1259 std::transform(id.begin(), id.end(), id.begin(), ::tolower);
1260
1261
1262 if (id.find("debian") != std::string::npos || id.find("ubuntu") != std::string::npos || id.find("mint") != std::string::npos)
1263 distro = "debian";
1264 else if (id.find("fedora") != std::string::npos || id.find("rhel") != std::string::npos ||
1265 id.find("centos") != std::string::npos || id.find("alma") != std::string::npos || id.find("rocky") != std::string::npos)
1266 distro = "fedora";
1267 else if (id.find("arch") != std::string::npos || id.find("manjaro") != std::string::npos || id.find("endeavour") != std::string::npos)
1268 distro = "arch";
1269 else if (id.find("suse") != std::string::npos)
1270 distro = "opensuse";
1271 else if (id.find("gentoo") != std::string::npos)
1272 distro = "gentoo";
1273 else if (id.find("slackware") != std::string::npos)
1274 distro = "slackware";
1275 else if (id.find("bsd") != std::string::npos)
1276 distro = "bsd";
1277
1278 std::cout << _("[detect_distro] Distribuzione rilevata: ") << distro << std::endl;
1279 return distro;
1280}

References _, detect_distro(), bg_process::Result::ok(), and bg_process::run().

Referenced by SettingsPage::build_options_tab(), and detect_distro().

◆ detect_webserver()

std::string detect_webserver ( )
static

Definition at line 1283 of file SettingsPage.cpp.

1283 {
1284 using namespace std;
1285
1286 auto is_active = [](const std::string& svc) -> bool {
1287 return bg_process::run({"/usr/libexec/bastionguard/bastionguard-service",
1288 "--system", "is-active", svc}).ok();
1289 };
1290
1291 auto cmd_exists = [](const std::string& cmd) -> bool {
1292 return bg_process::run({"which", "--", cmd}).ok();
1293 };
1294
1295 if (is_active("apache2") || is_active("httpd") || cmd_exists("apache2") || cmd_exists("httpd")) {
1296 std::cout << _("[detect_webserver] Apache rilevato") << std::endl;
1297 return "apache";
1298 }
1299
1300 if (is_active("nginx") || cmd_exists("nginx")) {
1301 std::cout << _("[detect_webserver] Nginx rilevato") << std::endl;
1302 return "nginx";
1303 }
1304
1305 if (is_active("lshttpd") || is_active("lsws") || cmd_exists("lsws") || cmd_exists("lshttpd")) {
1306 std::cout << _("[detect_webserver] LiteSpeed rilevato") << std::endl;
1307 return "litespeed";
1308 }
1309
1310 {
1311 const auto processes = bg_process::run({"ps", "-eo", "comm"});
1312 const std::string& out = processes.output;
1313 if (out.find("apache2") != std::string::npos || out.find("httpd") != std::string::npos) return "apache";
1314 if (out.find("nginx") != std::string::npos) return "nginx";
1315 if (out.find("lshttpd") != std::string::npos || out.find("lsws") != std::string::npos) return "litespeed";
1316 }
1317
1318 std::cout << _("[detect_webserver] Nessun server rilevato") << std::endl;
1319 return "unknown";
1320}

References _, detect_webserver(), bg_process::Result::output, and bg_process::run().

Referenced by detect_webserver().

◆ elev_cmd()

std::string elev_cmd ( const std::string & inner)
static

Definition at line 1074 of file SettingsPage.cpp.

1074 {
1075 if (std::filesystem::exists("/usr/bin/pkexec")) return std::string("pkexec ") + inner;
1076 return std::string("sudo ") + inner;
1077}

References elev_cmd().

Referenced by elev_cmd().

◆ ensure_mail_json_exists()

void ensure_mail_json_exists ( )
static

Definition at line 197 of file SettingsPage.cpp.

197 {
198 const std::string path = mail_json_path_user();
199
200 try {
201 std::filesystem::create_directories(std::filesystem::path(path).parent_path());
202 } catch (...) {}
203
204 if (std::filesystem::exists(path)) return;
205
206 json j;
207 j["version"] = 2;
208 j["enabled"] = false;
209 j["scan_outgoing"] = true;
210 j["inject_signature"] = false;
211 j["local_smtp_host"] = "127.0.0.1";
212 j["local_smtp_port"] = 2525;
213 j["default_profile_id"] = "default";
214
215 j["profiles"] = json::array({
216 {
217 {"id", "default"},
218 {"label", "Default"},
219 {"match_from", json::array()},
220 {"match_from_domain", json::array()},
221 {"smtp_host", ""},
222 {"smtp_port", 587},
223 {"starttls", true},
224 {"implicit_tls", false},
225 {"username", ""},
226 {"password", ""},
227 {"signature", {
228 {"display_name", ""},
229 {"job_title", ""},
230 {"company", ""},
231 {"phone", ""},
232 {"website", ""},
233 {"logo_path", ""}
234 }}
235 }
236 });
237
238 std::ofstream out(path, std::ios::binary | std::ios::trunc);
239 if (out.good()) out << j.dump(2);
240}
nlohmann::json json
Definition Backend.cpp:2908
static std::string mail_json_path_user()

References ensure_mail_json_exists(), and mail_json_path_user().

Referenced by ensure_mail_json_exists(), load_mail_security_config(), and save_mail_security_config().

◆ ensure_payments_json_exists()

void ensure_payments_json_exists ( )
static

Definition at line 905 of file SettingsPage.cpp.

905 {
906 const std::string path = payments_json_path_user();
907 try {
908 fs::create_directories(fs::path(path).parent_path());
909 } catch (...) {}
910
911 if (fs::exists(path)) return;
912
913 json j;
914 j["version"] = 1;
915 j["updated_at"] = iso_today_yyyy_mm_dd();
916 j["enabled"] = false;
917 j["list"] = json::array({
918 "paypal.com",
919 "stripe.com",
920 "adyen.com",
921 "klarna.com",
922 "checkout.com",
923 "worldpay.com",
924 "braintreepayments.com",
925 "braintreegateway.com",
926 "amazonpay.com",
927 "pay.google.com",
928 "pay.apple.com",
929 "amazon.com"
930 });
931
932 std::ofstream out(path, std::ios::binary | std::ios::trunc);
933 if (out.good()) out << j.dump(2);
934}
static std::string payments_json_path_user()
static std::string iso_today_yyyy_mm_dd()

References ensure_payments_json_exists(), iso_today_yyyy_mm_dd(), and payments_json_path_user().

Referenced by SettingsPage::build_secure_payments_tab(), ensure_payments_json_exists(), load_payments_domains(), save_payments_domains(), and update_payments_enabled_only().

◆ is_clamav_signature_file()

bool is_clamav_signature_file ( const std::filesystem::path & p)
static

Definition at line 540 of file SettingsPage.cpp.

541{
542 if (!p.has_extension()) return false;
543
544 std::string ext = p.extension().string();
545 std::transform(ext.begin(), ext.end(), ext.begin(),
546 [](unsigned char c){ return std::tolower(c); });
547
548 // Estensioni comuni DB/firme ClamAV
549 static const std::set<std::string> exts = {
550 ".ndb", ".hdb", ".hsb", ".ldb", ".sdb", ".fp", ".mdb", ".pdb",
551 ".wdb", ".cbc", ".cdb", ".cat"
552 };
553
554 if (exts.find(ext) == exts.end())
555 return false;
556
557 // scarta file nascosti
558 const auto name = p.filename().string();
559 if (!name.empty() && name[0] == '.') return false;
560
561 return true;
562}

References is_clamav_signature_file().

Referenced by is_clamav_signature_file(), and list_clamav_signatures().

◆ isClamonaccRunning()

bool isClamonaccRunning ( )

Definition at line 1437 of file SettingsPage.cpp.

1437 {
1438 return isServiceActive("clamonacc.service") ||
1439 isServiceActive("clamav-clamonacc.service");
1440 }
bool isServiceActive(const std::string &service, bool user=false)

References isClamonaccRunning(), and anonymous_namespace{SettingsPage.cpp}::isServiceActive().

Referenced by isClamonaccRunning(), and SettingsPage::SettingsPage().

◆ iso_today_yyyy_mm_dd()

std::string iso_today_yyyy_mm_dd ( )
static

Definition at line 865 of file SettingsPage.cpp.

865 {
866 std::time_t t = std::time(nullptr);
867 std::tm tm{};
868 localtime_r(&t, &tm);
869 std::ostringstream oss;
870 oss << std::put_time(&tm, "%Y-%m-%d");
871 return oss.str();
872}

References iso_today_yyyy_mm_dd().

Referenced by ensure_payments_json_exists(), iso_today_yyyy_mm_dd(), save_mail_security_config(), save_payments_domains(), and update_payments_enabled_only().

◆ join_semicolon_list()

std::string join_semicolon_list ( const std::vector< std::string > & items)
static

Definition at line 172 of file SettingsPage.cpp.

172 {
173 std::ostringstream oss;
174 for (size_t i = 0; i < items.size(); ++i) {
175 if (i) oss << "; ";
176 oss << items[i];
177 }
178 return oss.str();
179}

References join_semicolon_list().

Referenced by join_semicolon_list().

◆ list_clamav_signatures()

std::vector< std::filesystem::path > list_clamav_signatures ( const std::filesystem::path & dir)
static

Definition at line 619 of file SettingsPage.cpp.

620{
621 std::vector<std::filesystem::path> out;
622 std::error_code ec;
623
624 if (!std::filesystem::exists(dir, ec) || !std::filesystem::is_directory(dir, ec))
625 return out;
626
627 for (const auto& entry : std::filesystem::directory_iterator(dir, ec))
628 {
629 if (ec) break;
630 if (!entry.is_regular_file(ec)) continue;
631
632 const auto& p = entry.path();
634 out.push_back(p);
635 }
636
637 std::sort(out.begin(), out.end(),
638 [](const auto& a, const auto& b){
639 return a.filename().string() < b.filename().string();
640 });
641
642 return out;
643}
static bool is_clamav_signature_file(const std::filesystem::path &p)

References is_clamav_signature_file(), and list_clamav_signatures().

Referenced by list_clamav_signatures(), and SettingsPage::refresh_clamav_db_list().

◆ load_mail_security_config()

MailSecurityConfig load_mail_security_config ( )
static

Definition at line 339 of file SettingsPage.cpp.

339 {
341
343 const std::string path = mail_json_path_user();
344
345 try {
346 std::ifstream in(path, std::ios::binary);
347 if (!in.good()) return cfg;
348
349 json j;
350 in >> j;
351
352 cfg.version = j.value("version", 2);
353 cfg.enabled = j.value("enabled", false);
354 cfg.scan_outgoing = j.value("scan_outgoing", true);
355 cfg.inject_signature = j.value("inject_signature", false);
356 cfg.local_host = j.value("local_smtp_host", std::string("127.0.0.1"));
357 cfg.local_port = j.value("local_smtp_port", 2525);
358 cfg.local_tls_port = j.value("local_smtp_tls_port", 2465);
359 cfg.local_submission_port = j.value("local_submission_port", 2587);
360 cfg.advertise_starttls = j.value("advertise_starttls", true);
361 cfg.enable_implicit_tls_listener = j.value("enable_implicit_tls_listener", true);
362 cfg.default_profile_id = j.value("default_profile_id", std::string("default"));
363
364 if (j.contains("profiles") && j["profiles"].is_array()) {
365 for (const auto& p : j["profiles"]) {
366 if (!p.is_object()) continue;
367
368 MailRelayProfile prof;
369 prof.id = p.value("id", std::string());
370 prof.label = p.value("label", std::string("Profile"));
371 prof.smtp_host = p.value("smtp_host", std::string());
372 prof.smtp_port = p.value("smtp_port", 587);
373 prof.starttls = p.value("starttls", true);
374 prof.implicit_tls = p.value("implicit_tls", false);
375 prof.username = p.value("username", std::string());
376 prof.password = p.value("password", std::string());
377
378 if (p.contains("match_from") && p["match_from"].is_array()) {
379 for (const auto& v : p["match_from"])
380 if (v.is_string()) prof.match_from.push_back(v.get<std::string>());
381 }
382
383 if (p.contains("match_from_domain") && p["match_from_domain"].is_array()) {
384 for (const auto& v : p["match_from_domain"])
385 if (v.is_string()) prof.match_from_domain.push_back(v.get<std::string>());
386 }
387
388 if (p.contains("signature") && p["signature"].is_object()) {
389 const auto& s = p["signature"];
390 prof.signature.display_name = s.value("display_name", std::string());
391 prof.signature.job_title = s.value("job_title", std::string());
392 prof.signature.company = s.value("company", std::string());
393 prof.signature.phone = s.value("phone", std::string());
394 prof.signature.website = s.value("website", std::string());
395 prof.signature.logo_path = s.value("logo_path", std::string());
396 }
397
398 if (prof.id.empty())
399 prof.id = make_profile_id(prof.label);
400
401 cfg.profiles.push_back(std::move(prof));
402 }
403 }
404
405 if (cfg.profiles.empty()) {
407 p.id = "default";
408 p.label = "Default";
409 cfg.profiles.push_back(std::move(p));
410 cfg.default_profile_id = "default";
411 }
412 } catch (...) {
413 }
414
415 return cfg;
416}
static void ensure_mail_json_exists()
static std::string make_profile_id(const std::string &label)
std::vector< std::string > match_from_domain
MailSignatureConfig signature
std::string username
std::vector< std::string > match_from
std::string smtp_host
std::string password
std::string default_profile_id
std::vector< MailRelayProfile > profiles

References MailSecurityConfig::advertise_starttls, MailSignatureConfig::company, MailSecurityConfig::default_profile_id, MailSignatureConfig::display_name, MailSecurityConfig::enable_implicit_tls_listener, MailSecurityConfig::enabled, ensure_mail_json_exists(), MailRelayProfile::id, MailRelayProfile::implicit_tls, MailSecurityConfig::inject_signature, MailSignatureConfig::job_title, MailRelayProfile::label, MailSecurityConfig::local_host, MailSecurityConfig::local_port, MailSecurityConfig::local_submission_port, MailSecurityConfig::local_tls_port, MailSignatureConfig::logo_path, mail_json_path_user(), make_profile_id(), MailRelayProfile::match_from, MailRelayProfile::match_from_domain, MailRelayProfile::password, MailSignatureConfig::phone, MailSecurityConfig::profiles, MailSecurityConfig::scan_outgoing, MailRelayProfile::signature, MailRelayProfile::smtp_host, MailRelayProfile::smtp_port, MailRelayProfile::starttls, MailRelayProfile::username, MailSecurityConfig::version, and MailSignatureConfig::website.

Referenced by SettingsPage::build_email_security_tab().

◆ load_payments_domains()

std::vector< std::string > load_payments_domains ( )
static

Definition at line 936 of file SettingsPage.cpp.

936 {
938
939 const std::string path = payments_json_path_user();
940 std::vector<std::string> out;
941
942 try {
943 std::ifstream in(path, std::ios::binary);
944 if (!in.good()) return out;
945
946 json j;
947 in >> j;
948
949 if (j.contains("list") && j["list"].is_array()) {
950 for (const auto& v : j["list"]) {
951 if (!v.is_string()) continue;
952 std::string d = normalize_domain_or_url(v.get<std::string>());
953 if (!d.empty()) out.push_back(d);
954 }
955 }
956
957 std::sort(out.begin(), out.end());
958 out.erase(std::unique(out.begin(), out.end()), out.end());
959
960 } catch (...) {
961 }
962
963 return out;
964}
static std::string normalize_domain_or_url(std::string in)
static void ensure_payments_json_exists()

References ensure_payments_json_exists(), load_payments_domains(), normalize_domain_or_url(), and payments_json_path_user().

Referenced by SettingsPage::build_secure_payments_tab(), and load_payments_domains().

◆ load_proxy_bypass_domains()

std::vector< std::string > load_proxy_bypass_domains ( )
static

Definition at line 3832 of file SettingsPage.cpp.

3832 {
3833 const std::string path = Glib::build_filename(
3834 Glib::get_home_dir(), ".config", "BastionGuard", "proxy_bypass.json");
3835 std::vector<std::string> result;
3836 if (!std::filesystem::exists(path)) return result;
3837 try {
3838 std::ifstream f(path);
3839 nlohmann::json j; f >> j;
3840 if (j.contains("list") && j["list"].is_array())
3841 for (const auto& item : j["list"])
3842 if (item.is_string()) {
3843 std::string d = item.get<std::string>();
3844 if (!d.empty()) result.push_back(d);
3845 }
3846 } catch (...) {}
3847 return result;
3848}

References load_proxy_bypass_domains().

Referenced by SettingsPage::build_proxy_bypass_tab(), and load_proxy_bypass_domains().

◆ mail_json_path_user()

std::string mail_json_path_user ( )
static

Definition at line 144 of file SettingsPage.cpp.

144 {
145 return Glib::get_home_dir() + "/.config/BastionGuard/mail.json";
146}

References mail_json_path_user().

Referenced by ensure_mail_json_exists(), load_mail_security_config(), mail_json_path_user(), and save_mail_security_config().

◆ make_profile_id()

std::string make_profile_id ( const std::string & label)
static

Definition at line 181 of file SettingsPage.cpp.

181 {
182 std::string out;
183 for (unsigned char c : label) {
184 if (std::isalnum(c)) out += (char)std::tolower(c);
185 else if (c == ' ' || c == '-' || c == '_') out += '-';
186 }
187
188 while (out.find("--") != std::string::npos)
189 out = std::regex_replace(out, std::regex("--"), "-");
190
191 if (!out.empty() && out.front() == '-') out.erase(out.begin());
192 if (!out.empty() && out.back() == '-') out.pop_back();
193 if (out.empty()) out = "profile";
194 return out;
195}

References make_profile_id().

Referenced by load_mail_security_config(), and make_profile_id().

◆ normalize_domain_or_url()

std::string normalize_domain_or_url ( const std::string & in_raw)
static

Definition at line 874 of file SettingsPage.cpp.

874 {
875 std::string in = in_raw;
876 auto l = in.find_first_not_of(" \t\r\n");
877 auto r = in.find_last_not_of(" \t\r\n");
878 if (l == std::string::npos) return {};
879 in = in.substr(l, r - l + 1);
880 std::string s = in;
881 auto pos = s.find("://");
882 if (pos != std::string::npos) s.erase(0, pos + 3);
883 pos = s.find('/');
884 if (pos != std::string::npos) s.erase(pos);
885
886 pos = s.find('@');
887 if (pos != std::string::npos) s = s.substr(pos + 1);
888
889 pos = s.find(':');
890 if (pos != std::string::npos) s.erase(pos);
891
892 if (s.rfind("www.", 0) == 0) s.erase(0, 4);
893
894 std::transform(s.begin(), s.end(), s.begin(),
895 [](unsigned char c){ return std::tolower(c); });
896
897 static const std::regex re(R"(^[a-z0-9][a-z0-9.-]*[a-z0-9]$)");
898 if (!std::regex_match(s, re)) return {};
899
900 if (s.find('.') == std::string::npos) return {};
901
902 return s;
903}

References normalize_domain_or_url().

Referenced by SettingsPage::build_secure_payments_tab().

◆ normalize_locale()

std::string normalize_locale ( std::string s)
static

Definition at line 2476 of file SettingsPage.cpp.

2476 {
2477 auto p = s.find('.'); if (p != std::string::npos) s = s.substr(0, p);
2478 p = s.find('@'); if (p != std::string::npos) s = s.substr(0, p);
2479 for (auto& c : s) if (c == '-') c = '_';
2480 return s;
2481}

References normalize_locale().

Referenced by SettingsPage::build_options_tab(), and normalize_locale().

◆ payments_json_path_user()

std::string payments_json_path_user ( )
static

Definition at line 645 of file SettingsPage.cpp.

645 {
646 return Glib::get_home_dir() + "/.config/BastionGuard/payments.json";
647}

References payments_json_path_user().

Referenced by ensure_payments_json_exists(), load_payments_domains(), payments_json_path_user(), save_payments_domains(), and update_payments_enabled_only().

◆ read_current_ports()

std::pair< int, int > read_current_ports ( const std::string & )

Definition at line 1323 of file SettingsPage.cpp.

1324{
1325 int http_port = 81;
1326 int https_port = 444;
1327 const std::string portfile = "/etc/BastionGuard/webports.conf";
1328
1329 std::ifstream f(portfile);
1330 if (f.is_open()) {
1331 int p1 = 0, p2 = 0;
1332 f >> p1 >> p2;
1333
1334 if (p1 > 0 && p1 < 65536) http_port = p1;
1335 if (p2 > 0 && p2 < 65536) https_port = p2;
1336
1337 std::cout << _("[settings] Porte lette da ") << portfile
1338 << " → HTTP=" << http_port
1339 << " HTTPS=" << https_port << std::endl;
1340 } else {
1341 std::cerr << _("[settings] ⚠ Impossibile aprire ") << portfile
1342 << _(" — uso valori di default (80/443)\n");
1343 }
1344
1345 return {http_port, https_port};
1346}

References _, and read_current_ports().

Referenced by read_current_ports().

◆ read_webports_conf()

std::pair< int, int > read_webports_conf ( )

Definition at line 1111 of file SettingsPage.cpp.

1112{
1113 constexpr int default_http_port = 81;
1114 constexpr int default_https_port = 444;
1115
1116 auto valid_port = [](int port) {
1117 return port > 0 && port < 65536;
1118 };
1119
1120 std::vector<std::string> paths = {
1121 "/etc/BastionGuard/webports.conf",
1122 "/tmp/BastionGuard_webports.conf"
1123 };
1124
1125 for (const auto& p : paths) {
1126 std::ifstream f(p);
1127 if (!f.is_open())
1128 continue;
1129
1130 std::stringstream buffer;
1131 buffer << f.rdbuf();
1132 const std::string content = buffer.str();
1133
1134 int http_port = default_http_port;
1135 int https_port = default_https_port;
1136 std::istringstream iss(content);
1137
1138 if ((iss >> http_port >> https_port) &&
1139 valid_port(http_port) && valid_port(https_port)) {
1140 std::cout << _("[settings] 📖 Letto webports.conf: ")
1141 << http_port << " " << https_port << std::endl;
1142 return {http_port, https_port};
1143 }
1144
1145 // Evita che un file scritto male venga interpretato come una singola porta HTTP.
1146 // La coppia supportata resta 81/444.
1147 std::cerr << _("[settings] ⚠️ webports.conf malformato, uso default 81/444: ")
1148 << content << std::endl;
1149 return {default_http_port, default_https_port};
1150 }
1151
1152 std::cout << _("[settings] ⚠️ Nessun webports.conf trovato, uso default 81/444\n");
1153 return {default_http_port, default_https_port};
1154}

References _, and read_webports_conf().

Referenced by SettingsPage::build_options_tab(), and read_webports_conf().

◆ restart_service()

bool restart_service ( const std::string & svc)

Definition at line 1168 of file SettingsPage.cpp.

1169{
1170 return bg_process::run({"pkexec", "/usr/libexec/bastionguard/bastionguard-service",
1171 "--system", "restart", svc}).ok();
1172}

References restart_service(), and bg_process::run().

Referenced by restart_service().

◆ run_privhelper_and_capture()

bool run_privhelper_and_capture ( const std::vector< std::string > & args,
std::string & stdout_out,
std::string & stderr_out,
int & exit_status )
static

Definition at line 243 of file SettingsPage.cpp.

247{
248 try {
249 std::vector<std::string> argv;
250 argv.push_back("pkexec");
251 argv.push_back("/usr/bin/bastionguard-emailproxy");
252 argv.insert(argv.end(), args.begin(), args.end());
253
254 auto proc = Gio::Subprocess::create(
255 argv,
256 Gio::Subprocess::Flags::STDOUT_PIPE |
257 Gio::Subprocess::Flags::STDERR_PIPE
258 );
259
260 auto result = proc->communicate_utf8("");
261 stdout_out = result.first;
262 stderr_out = result.second;
263
264 if (proc->get_if_exited())
265 exit_status = proc->get_exit_status();
266 else
267 exit_status = -1;
268
269 return proc->get_if_exited() && exit_status == 0;
270 } catch (const std::exception& e) {
271 stdout_out.clear();
272 stderr_out = e.what();
273 exit_status = -1;
274 return false;
275 }
276}

References run_privhelper_and_capture().

Referenced by run_privhelper_and_capture().

◆ save_mail_security_config()

bool save_mail_security_config ( const MailSecurityConfig & cfg)
static

Definition at line 418 of file SettingsPage.cpp.

418 {
420 const std::string path = mail_json_path_user();
421
422 try {
423 json j;
424 j["version"] = 2;
425 j["updated_at"] = iso_today_yyyy_mm_dd();
426 j["enabled"] = cfg.enabled;
427 j["scan_outgoing"] = cfg.scan_outgoing;
428 j["inject_signature"] = cfg.inject_signature;
429 j["local_smtp_host"] = cfg.local_host;
430 j["local_smtp_port"] = cfg.local_port;
431 j["local_smtp_tls_port"] = cfg.local_tls_port;
432 j["local_submission_port"] = cfg.local_submission_port;
433 j["advertise_starttls"] = cfg.advertise_starttls;
434 j["enable_implicit_tls_listener"] = cfg.enable_implicit_tls_listener;
435 j["default_profile_id"] = cfg.default_profile_id;
436 j["profiles"] = json::array();
437
438 for (const auto& p : cfg.profiles) {
439 json jp;
440 jp["id"] = p.id;
441 jp["label"] = p.label;
442 jp["match_from"] = p.match_from;
443 jp["match_from_domain"] = p.match_from_domain;
444 jp["smtp_host"] = p.smtp_host;
445 jp["smtp_port"] = p.smtp_port;
446 jp["starttls"] = p.starttls;
447 jp["implicit_tls"] = p.implicit_tls;
448 jp["username"] = p.username;
449 jp["password"] = p.password;
450 jp["signature"] = {
451 {"display_name", p.signature.display_name},
452 {"job_title", p.signature.job_title},
453 {"company", p.signature.company},
454 {"phone", p.signature.phone},
455 {"website", p.signature.website},
456 {"logo_path", p.signature.logo_path}
457 };
458 j["profiles"].push_back(std::move(jp));
459 }
460
461 const std::string tmp = path + ".tmp";
462 {
463 std::ofstream out(tmp, std::ios::binary | std::ios::trunc);
464 if (!out.good()) return false;
465 out << j.dump(2);
466 out.flush();
467 if (!out.good()) return false;
468 }
469
470 std::error_code ec;
471 std::filesystem::rename(tmp, path, ec);
472 if (ec) {
473 std::filesystem::remove(path, ec);
474 ec.clear();
475 std::filesystem::rename(tmp, path, ec);
476 if (ec) {
477 std::filesystem::remove(tmp, ec);
478 return false;
479 }
480 }
481
482 return true;
483 } catch (...) {
484 return false;
485 }
486}

References MailSecurityConfig::advertise_starttls, MailSecurityConfig::default_profile_id, MailSecurityConfig::enable_implicit_tls_listener, MailSecurityConfig::enabled, ensure_mail_json_exists(), MailSecurityConfig::inject_signature, iso_today_yyyy_mm_dd(), MailSecurityConfig::local_host, MailSecurityConfig::local_port, MailSecurityConfig::local_submission_port, MailSecurityConfig::local_tls_port, mail_json_path_user(), MailSecurityConfig::profiles, save_mail_security_config(), and MailSecurityConfig::scan_outgoing.

Referenced by SettingsPage::build_email_security_tab(), and save_mail_security_config().

◆ save_payments_domains()

bool save_payments_domains ( const std::vector< std::string > & domains_in,
bool enabled_flag )
static

Definition at line 966 of file SettingsPage.cpp.

966 {
968
969 const std::string path = payments_json_path_user();
970
971 std::vector<std::string> domains;
972 domains.reserve(domains_in.size());
973 for (const auto& s : domains_in) {
974 auto d = normalize_domain_or_url(s);
975 if (!d.empty()) domains.push_back(d);
976 }
977 std::sort(domains.begin(), domains.end());
978 domains.erase(std::unique(domains.begin(), domains.end()), domains.end());
979
980 try {
981 json j;
982
983 {
984 std::ifstream in(path, std::ios::binary);
985 if (in.good()) {
986 try { in >> j; } catch (...) { j = json::object(); }
987 }
988 }
989
990 if (!j.is_object()) j = json::object();
991
992 j["version"] = 1;
993 j["updated_at"] = iso_today_yyyy_mm_dd();
994 j["enabled"] = enabled_flag;
995 j["list"] = json::array();
996 for (const auto& d : domains) j["list"].push_back(d);
997
998 const std::string tmp = path + ".tmp";
999 {
1000 std::ofstream out(tmp, std::ios::binary | std::ios::trunc);
1001 if (!out.good()) return false;
1002 out << j.dump(2);
1003 out.flush();
1004 if (!out.good()) return false;
1005 }
1006
1007 std::error_code ec;
1008 fs::rename(tmp, path, ec);
1009 if (ec) {
1010 fs::remove(path, ec);
1011 ec.clear();
1012 fs::rename(tmp, path, ec);
1013 if (ec) {
1014 fs::remove(tmp, ec);
1015 return false;
1016 }
1017 }
1018
1019 return true;
1020 } catch (...) {
1021 return false;
1022 }
1023}

References ensure_payments_json_exists(), iso_today_yyyy_mm_dd(), normalize_domain_or_url(), payments_json_path_user(), and save_payments_domains().

Referenced by SettingsPage::build_secure_payments_tab(), and save_payments_domains().

◆ save_proxy_bypass_domains()

bool save_proxy_bypass_domains ( const std::vector< std::string > & domains)
static

Definition at line 3850 of file SettingsPage.cpp.

3850 {
3851 const std::string dir = Glib::build_filename(
3852 Glib::get_home_dir(), ".config", "BastionGuard");
3853 const std::string path = Glib::build_filename(dir, "proxy_bypass.json");
3854 try {
3855 std::filesystem::create_directories(dir);
3856 nlohmann::json j;
3857 j["version"] = 1;
3858 j["description"] = "Domini che bypassano completamente il proxy BastionGuard. "
3859 "Tunnel TCP puro trasparente — nessuna intercettazione TLS. "
3860 "Usare per siti che attivano 2FA o CAPTCHA in presenza del proxy.";
3861 j["list"] = nlohmann::json::array();
3862 for (const auto& d : domains) j["list"].push_back(d);
3863 const std::string tmp = path + ".tmp";
3864 std::ofstream out(tmp, std::ios::trunc);
3865 if (!out.is_open()) return false;
3866 out << j.dump(2); out.flush(); out.close();
3867 std::error_code ec;
3868 std::filesystem::rename(tmp, path, ec);
3869 return !ec;
3870 } catch (...) { return false; }
3871}

References save_proxy_bypass_domains().

Referenced by SettingsPage::build_proxy_bypass_tab(), and save_proxy_bypass_domains().

◆ show_service_error_dialog()

void show_service_error_dialog ( const Glib::ustring & msg,
const std::string & service )

Definition at line 4501 of file SettingsPage.cpp.

4502{
4503 auto dlg = Gtk::AlertDialog::create(msg);
4504 dlg->set_detail(Glib::ustring::compose(_("Servizio: %1\n\n"
4505 "Verifica i permessi o prova ad eseguire il comando da terminale."), service));
4506 dlg->show();
4507}

References _, and show_service_error_dialog().

Referenced by show_service_error_dialog().

◆ split_semicolon_list()

std::vector< std::string > split_semicolon_list ( const std::string & input)
static

Definition at line 148 of file SettingsPage.cpp.

148 {
149 std::vector<std::string> out;
150 std::string cur;
151
152 auto push_trimmed = [&](std::string s) {
153 auto l = s.find_first_not_of(" \t\r\n");
154 auto r = s.find_last_not_of(" \t\r\n");
155 if (l == std::string::npos) return;
156 s = s.substr(l, r - l + 1);
157 if (!s.empty()) out.push_back(s);
158 };
159
160 for (char c : input) {
161 if (c == ';') {
162 push_trimmed(cur);
163 cur.clear();
164 } else {
165 cur += c;
166 }
167 }
168 push_trimmed(cur);
169 return out;
170}

References split_semicolon_list().

◆ tb_find_default_profile()

std::string tb_find_default_profile ( )
static

Definition at line 716 of file SettingsPage.cpp.

716 {
717 const std::string base = Glib::get_home_dir() + "/.thunderbird";
718
719 {
720 auto installs = tb_parse_ini_file(base + "/installs.ini");
721 for (const auto& [sec, kv] : installs) {
722 auto it = kv.find("Default");
723 if (it == kv.end()) continue;
724 std::string path = it->second;
725 if (!path.empty() && path.front() != '/')
726 path = base + "/" + path;
727 if (std::filesystem::exists(path + "/prefs.js"))
728 return path;
729 }
730 }
731
732 auto sections = tb_parse_ini_file(base + "/profiles.ini");
733
734 std::string best_default_release;
735 std::string best_default_flag;
736 std::string best_any;
737
738 for (const auto& [sec, kv] : sections) {
739 if (sec.rfind("Profile", 0) != 0) continue;
740 auto it_path = kv.find("Path");
741 if (it_path == kv.end()) continue;
742
743 std::string path = it_path->second;
744 auto it_rel = kv.find("IsRelative");
745 bool rel = (it_rel == kv.end() || it_rel->second != "0");
746 if (rel) path = base + "/" + path;
747
748 if (!std::filesystem::exists(path + "/prefs.js")) continue;
749
750 // Default=1
751 auto it_def = kv.find("Default");
752 if (it_def != kv.end() && it_def->second == "1" && best_default_flag.empty())
753 best_default_flag = path;
754
755 // suffisso .default-release
756 const std::string suffix = ".default-release";
757 if (path.size() >= suffix.size() &&
758 path.compare(path.size() - suffix.size(), suffix.size(), suffix) == 0 &&
759 best_default_release.empty())
760 best_default_release = path;
761
762 if (best_any.empty()) best_any = path;
763 }
764
765 if (!best_default_flag.empty()) return best_default_flag;
766 if (!best_default_release.empty()) return best_default_release;
767 return best_any;
768}
static std::map< std::string, std::map< std::string, std::string > > tb_parse_ini_file(const std::string &path)

References tb_find_default_profile(), and tb_parse_ini_file().

Referenced by tb_find_default_profile(), and tb_import_profiles().

◆ tb_import_profiles()

std::vector< MailRelayProfile > tb_import_profiles ( std::string & err_out)
static

Definition at line 770 of file SettingsPage.cpp.

770 {
771 std::vector<MailRelayProfile> result;
772 err_out.clear();
773
774 const std::string profile_dir = tb_find_default_profile();
775 if (profile_dir.empty()) {
776 err_out = _("Profilo Thunderbird non trovato");
777 return result;
778 }
779
780 const std::string prefs_path = profile_dir + "/prefs.js";
781 std::ifstream in(prefs_path);
782 if (!in.is_open()) {
783 err_out = _("prefs.js non trovato: ") + prefs_path;
784 return result;
785 }
786
787 std::map<std::string, TbSmtpEntry> smtp_map;
788 std::map<std::string, TbIdentityEntry> identity_map;
789
790 std::string line;
791 while (std::getline(in, line)) {
792 std::string key, value;
793 if (!tb_parse_pref_line(line, key, value)) continue;
794
795 if (key.rfind("mail.smtpserver.", 0) == 0) {
796 auto rest = key.substr(16);
797 auto dot = rest.find('.');
798 if (dot == std::string::npos) continue;
799 auto sid = rest.substr(0, dot);
800 auto field = rest.substr(dot + 1);
801 auto& s = smtp_map[sid];
802 s.id = sid;
803 if (field == "hostname") s.hostname = value;
804 else if (field == "port") s.port = std::atoi(value.c_str());
805 else if (field == "username") s.username = value;
806 else if (field == "try_ssl") s.try_ssl = std::atoi(value.c_str());
807 else if (field == "description") s.description = value;
808 }
809 else if (key.rfind("mail.identity.", 0) == 0) {
810 auto rest = key.substr(14);
811 auto dot = rest.find('.');
812 if (dot == std::string::npos) continue;
813 auto iid = rest.substr(0, dot);
814 auto field = rest.substr(dot + 1);
815 auto& id = identity_map[iid];
816 if (field == "useremail") id.email = value;
817 else if (field == "smtpServer") id.smtp_server = value;
818 }
819 }
820
821 std::map<std::string, MailRelayProfile> built;
822
823 for (const auto& [iid, ident] : identity_map) {
824 if (ident.email.empty() || ident.smtp_server.empty()) continue;
825 auto it = smtp_map.find(ident.smtp_server);
826 if (it == smtp_map.end()) continue;
827
828 const auto& s = it->second;
829 auto& p = built[s.id];
830
831 if (p.id.empty()) {
832 p.id = s.id;
833 p.label = s.description.empty() ? s.hostname : s.description;
834 p.smtp_host = s.hostname;
835 p.smtp_port = (s.port > 0 ? s.port : 587);
836 p.username = s.username;
837 p.password = "";
838 p.starttls = (s.try_ssl == 2);
839 p.implicit_tls = (s.try_ssl == 3);
840 }
841
842 std::string email_lc = ident.email;
843 std::transform(email_lc.begin(), email_lc.end(), email_lc.begin(), ::tolower);
844 if (std::find(p.match_from.begin(), p.match_from.end(), email_lc) == p.match_from.end())
845 p.match_from.push_back(email_lc);
846
847 auto at = email_lc.find('@');
848 if (at != std::string::npos) {
849 std::string dom = email_lc.substr(at + 1);
850 if (std::find(p.match_from_domain.begin(), p.match_from_domain.end(), dom)
851 == p.match_from_domain.end())
852 p.match_from_domain.push_back(dom);
853 }
854 }
855
856 for (auto& [id, p] : built)
857 result.push_back(std::move(p));
858
859 if (result.empty())
860 err_out = _("Nessun server SMTP trovato in Thunderbird");
861
862 return result;
863}
static bool tb_parse_pref_line(const std::string &line, std::string &key, std::string &value)
static std::string tb_find_default_profile()

References _, tb_find_default_profile(), tb_import_profiles(), and tb_parse_pref_line().

Referenced by SettingsPage::build_email_security_tab(), and tb_import_profiles().

◆ tb_parse_ini_file()

std::map< std::string, std::map< std::string, std::string > > tb_parse_ini_file ( const std::string & path)
static

Definition at line 691 of file SettingsPage.cpp.

691 {
692 std::map<std::string, std::map<std::string,std::string>> sections;
693 std::ifstream f(path);
694 if (!f.is_open()) return sections;
695
696 std::string line, sec;
697 while (std::getline(f, line)) {
698 // trim
699 auto s = line.find_first_not_of(" \t\r\n");
700 if (s == std::string::npos || line[s] == ';' || line[s] == '#') continue;
701 line = line.substr(s);
702 auto e = line.find_last_not_of(" \t\r\n");
703 if (e != std::string::npos) line = line.substr(0, e + 1);
704
705 if (line.front() == '[' && line.back() == ']') {
706 sec = line.substr(1, line.size() - 2);
707 continue;
708 }
709 auto eq = line.find('=');
710 if (eq == std::string::npos || sec.empty()) continue;
711 sections[sec][line.substr(0, eq)] = line.substr(eq + 1);
712 }
713 return sections;
714}

References tb_parse_ini_file().

Referenced by tb_find_default_profile(), and tb_parse_ini_file().

◆ tb_parse_pref_line()

bool tb_parse_pref_line ( const std::string & line,
std::string & key,
std::string & value )
static

Definition at line 664 of file SettingsPage.cpp.

665 {
666 const std::string prefix = "user_pref(\"";
667 if (line.rfind(prefix, 0) != 0) return false;
668
669 auto ks = prefix.size();
670 auto ke = line.find('"', ks);
671 if (ke == std::string::npos) return false;
672 key = line.substr(ks, ke - ks);
673
674 auto vs = line.find(',', ke);
675 if (vs == std::string::npos) return false;
676 ++vs;
677 while (vs < line.size() && line[vs] == ' ') ++vs;
678
679 auto ve = line.rfind(')');
680 if (ve == std::string::npos || ve <= vs) return false;
681 value = line.substr(vs, ve - vs);
682
683
684 if (value.size() >= 2 && value.front() == '"' && value.back() == '"')
685 value = value.substr(1, value.size() - 2);
686
687 return true;
688}

References tb_parse_pref_line().

Referenced by tb_import_profiles(), and tb_parse_pref_line().

◆ update_payments_enabled_only()

bool update_payments_enabled_only ( bool enabled_flag)
static

Definition at line 1025 of file SettingsPage.cpp.

1025 {
1027
1028 const std::string path = payments_json_path_user();
1029 try {
1030 json j;
1031 {
1032 std::ifstream in(path, std::ios::binary);
1033 if (!in.good()) return false;
1034 in >> j;
1035 }
1036 if (!j.is_object()) j = json::object();
1037
1038 j["version"] = 1;
1039 j["updated_at"] = iso_today_yyyy_mm_dd();
1040 j["enabled"] = enabled_flag;
1041
1042 if (!j.contains("list") || !j["list"].is_array())
1043 j["list"] = json::array();
1044
1045 const std::string tmp = path + ".tmp";
1046 {
1047 std::ofstream out(tmp, std::ios::binary | std::ios::trunc);
1048 if (!out.good()) return false;
1049 out << j.dump(2);
1050 out.flush();
1051 if (!out.good()) return false;
1052 }
1053
1054 std::error_code ec;
1055 fs::rename(tmp, path, ec);
1056 if (ec) {
1057 fs::remove(path, ec);
1058 ec.clear();
1059 fs::rename(tmp, path, ec);
1060 if (ec) {
1061 fs::remove(tmp, ec);
1062 return false;
1063 }
1064 }
1065
1066 return true;
1067 } catch (...) {
1068 return false;
1069 }
1070}

References ensure_payments_json_exists(), iso_today_yyyy_mm_dd(), payments_json_path_user(), and update_payments_enabled_only().

Referenced by SettingsPage::build_secure_payments_tab(), and update_payments_enabled_only().

◆ update_ports_in_file()

bool update_ports_in_file ( const std::string & file,
int http_port,
int https_port )

Definition at line 1174 of file SettingsPage.cpp.

1175{
1176 if (!fs::exists(file)) {
1177 std::cerr << _("[update_ports_in_file] File non trovato: ") << file << std::endl;
1178 return false;
1179 }
1180
1181 std::ifstream fin(file);
1182 if (!fin.is_open()) {
1183 std::cerr << _("[update_ports_in_file] Impossibile aprire il file: ") << file << std::endl;
1184 return false;
1185 }
1186
1187 std::stringstream buffer;
1188 buffer << fin.rdbuf();
1189 fin.close();
1190 std::string content = buffer.str();
1191
1192 std::regex http_regex(R"((Listen\s+)80\b)");
1193 std::regex https_regex(R"((Listen\s+)443\b)");
1194 std::regex star_http(R"((\*|127\.0\.0\.1|\‍[::1\‍])?:80\b)");
1195 std::regex star_https(R"((\*|127\.0\.0\.1|\‍[::1\‍])?:443\b)");
1196
1197 content = std::regex_replace(content, http_regex, "Listen " + std::to_string(http_port));
1198 content = std::regex_replace(content, https_regex, "Listen " + std::to_string(https_port));
1199 content = std::regex_replace(content, star_http, "$1:" + std::to_string(http_port));
1200 content = std::regex_replace(content, star_https, "$1:" + std::to_string(https_port));
1201
1202 std::string tmpfile = "/tmp/BastionGuard-vhost.conf";
1203 std::ofstream fout(tmpfile);
1204 if (!fout.is_open()) {
1205 std::cerr << _("[update_ports_in_file] Impossibile scrivere il file temporaneo") << std::endl;
1206 return false;
1207 }
1208 fout << content;
1209 fout.close();
1210
1211 return bg_process::run({"pkexec", "/usr/bin/install", "-m", "0644", tmpfile, file}).ok();
1212}

References _, bg_process::run(), and update_ports_in_file().

Referenced by update_ports_in_file().

◆ update_webserver_ports()

bool update_webserver_ports ( const std::string & websrv,
int http_port,
int https_port )

Definition at line 1350 of file SettingsPage.cpp.

1351{
1352 (void)websrv;
1353 namespace fs = std::filesystem;
1354
1355 const std::string tmpfile = "/tmp/BastionGuard_webports.conf";
1356 const std::string targetfile = "/etc/BastionGuard/webports.conf";
1357
1358 try {
1359
1360 std::ofstream fout(tmpfile);
1361 if (!fout.is_open()) {
1362 std::cerr << _("[settings] ❌ Impossibile creare file temporaneo: ") << tmpfile << std::endl;
1363 return false;
1364 }
1365
1366 fout << http_port << " " << https_port << "\n";
1367 fout.close();
1368
1369 const int ret = bg_process::run({"pkexec", "/usr/bin/install", "-D", "-m", "0644",
1370 tmpfile, targetfile}).exit_code;
1371
1372 if (ret == 0) {
1373 std::cout << _("[settings] ✅ Porte BastionGuard salvate in ") << targetfile
1374 << " → HTTP interno=" << http_port
1375 << ", HTTPS interno=" << https_port << std::endl;
1376 return true;
1377 } else {
1378 std::cerr << _("[settings] ❌ Errore durante l'installazione via pkexec.\n");
1379 return false;
1380 }
1381 } catch (const std::exception& e) {
1382 std::cerr << _("[settings] ⚠ Eccezione durante update_webserver_ports: ") << e.what() << std::endl;
1383 return false;
1384 }
1385}

References _, bg_process::run(), and update_webserver_ports().

Referenced by update_webserver_ports().

◆ write_mail_config_temp_json()

bool write_mail_config_temp_json ( const MailSecurityConfig & cfg,
std::string & out_path )
static

Definition at line 278 of file SettingsPage.cpp.

278 {
279 try {
280 auto tmpdir = Glib::get_tmp_dir();
281 out_path = Glib::build_filename(tmpdir, "bastionguard-mail-config.json");
282
283 json j;
284 j["version"] = cfg.version;
285 j["enabled"] = cfg.enabled;
286 j["scan_outgoing"] = cfg.scan_outgoing;
287 j["inject_signature"] = cfg.inject_signature;
288 j["local_smtp_host"] = cfg.local_host;
289 j["local_smtp_port"] = cfg.local_port;
290 j["local_smtp_tls_port"] = cfg.local_tls_port;
291 j["advertise_starttls"] = cfg.advertise_starttls;
292 j["enable_implicit_tls_listener"] = cfg.enable_implicit_tls_listener;
293 j["default_profile_id"] = cfg.default_profile_id;
294
295 j["profiles"] = json::array();
296 for (const auto& p : cfg.profiles) {
297 json jp;
298 jp["id"] = p.id;
299 jp["label"] = p.label;
300 jp["match_from"] = p.match_from;
301 jp["match_from_domain"] = p.match_from_domain;
302 jp["smtp_host"] = p.smtp_host;
303 jp["smtp_port"] = p.smtp_port;
304 jp["starttls"] = p.starttls;
305 jp["implicit_tls"] = p.implicit_tls;
306 jp["username"] = p.username;
307 jp["password"] = p.password;
308
309 jp["signature"] = {
310 {"display_name", p.signature.display_name},
311 {"job_title", p.signature.job_title},
312 {"company", p.signature.company},
313 {"phone", p.signature.phone},
314 {"website", p.signature.website},
315 {"logo_path", "/usr/share/BastionGuard/data/logo.png"}
316 };
317
318 j["profiles"].push_back(jp);
319 }
320
321 std::ofstream out(out_path, std::ios::binary | std::ios::trunc);
322 if (!out.good())
323 return false;
324
325 out << j.dump(2);
326 return out.good();
327 } catch (...) {
328 return false;
329 }
330}

References MailSecurityConfig::advertise_starttls, MailSecurityConfig::default_profile_id, MailSecurityConfig::enable_implicit_tls_listener, MailSecurityConfig::enabled, MailSecurityConfig::inject_signature, MailSecurityConfig::local_host, MailSecurityConfig::local_port, MailSecurityConfig::local_tls_port, MailSecurityConfig::profiles, MailSecurityConfig::scan_outgoing, MailSecurityConfig::version, and write_mail_config_temp_json().

Referenced by write_mail_config_temp_json().

◆ write_temp_script_and_elevate()

bool write_temp_script_and_elevate ( const std::string & script_contents,
std::string * out_log = nullptr,
int * exit_code = nullptr )
static

Definition at line 1079 of file SettingsPage.cpp.

1079 {
1080 char tmpl[] = "/tmp/BastionGuard_tmp_XXXXXX";
1081 int fd = mkstemp(tmpl);
1082 if (fd < 0) {
1083 if (out_log) *out_log = _("Impossibile creare file temporaneo");
1084 return false;
1085 }
1086 std::string tmpname = tmpl;
1087 // write
1088 ssize_t written = write(fd, script_contents.c_str(), script_contents.size());
1089 close(fd);
1090 if (written < 0) {
1091 if (out_log) *out_log = _("Errore scrittura temporanea");
1092 std::filesystem::remove(tmpname);
1093 return false;
1094 }
1095 ::chmod(tmpname.c_str(), 0755);
1096
1097 const std::string runner = std::filesystem::exists("/usr/bin/pkexec") ? "pkexec" : "sudo";
1098 const auto result = bg_process::run({runner, tmpname}, true);
1099 std::string out = result.output;
1100 const int rc = result.exit_code;
1101 const bool ok = result.ok();
1102
1103 // pulizia
1104 std::filesystem::remove(tmpname);
1105
1106 if (out_log) *out_log = out;
1107 if (exit_code) *exit_code = rc;
1108 return ok;
1109}

References _, bg_process::Result::output, bg_process::run(), and write_temp_script_and_elevate().

Referenced by SettingsPage::build_options_tab(), and write_temp_script_and_elevate().

Variable Documentation

◆ toggleControlled

std::map<std::string, bool> toggleControlled
static

Definition at line 1391 of file SettingsPage.cpp.

◆ updatingToggle

bool updatingToggle = false
static

Definition at line 1389 of file SettingsPage.cpp.