Skip to content
API Documentation
BastionGuard™
first-run-services-window.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
22#include "../DistroUtils.hpp"
23#include "Resource.hpp"
24#include "StyleProvider.hpp"
25
26#include <glib/gi18n.h>
27#include <glibmm/fileutils.h>
28#include <glibmm/datetime.h>
29#include <glibmm/miscutils.h>
30#include <giomm/file.h>
31#include <giomm/subprocess.h>
32
33#include <fstream>
34#include <set>
35#include <algorithm>
36#include <iostream>
37#include <filesystem>
38#include <thread>
39#include <vector>
40#include <nlohmann/json.hpp>
41
42using json = nlohmann::json;
43
44namespace {
45 const std::string FLAG_DIR = Glib::get_user_config_dir() + "/BastionGuard";
46 const std::string FLAG_FILE = FLAG_DIR + "/first-run-services-done";
47
48 const std::string CONFIG_DIR = Glib::get_user_config_dir() + "/BastionGuard";
49 const std::string CONFIG_FILE = CONFIG_DIR + "/config.json";
50
51 const std::set<std::string> SYSTEM_UNITS = {
52 "BastionGuard-phishing-scanner.service",
53 "BastionGuard-phishing-updater.service",
54 "BastionGuard-phishing-updater.timer",
55 "Bastionguard-privhelper.service",
56 "bastionguard-sanesecurity.service",
57 "bastionguard-sanesecurity.timer",
58 "BastionGuard-ransomware-realtime.service",
59 "BastionGuard-usbd.service",
60 };
61
62 static constexpr const char* CA_HELPER =
63 "/usr/share/BastionGuard/data/scripts/install-ca-system.sh";
64
65 static bool is_system_unit(const std::string& unit_name)
66 {
67 return SYSTEM_UNITS.contains(unit_name);
68 }
69
70 static bool run_cmd(const std::vector<std::string>& argv,
71 bool silence_stderr = true,
72 bool capture_stdout = false,
73 std::string* out_stdout = nullptr)
74 {
75 try
76 {
77 Gio::Subprocess::Flags flags = Gio::Subprocess::Flags::NONE;
78
79 if (capture_stdout)
80 flags |= Gio::Subprocess::Flags::STDOUT_PIPE;
81
82 if (silence_stderr)
83 flags |= Gio::Subprocess::Flags::STDERR_SILENCE;
84 else
85 flags |= Gio::Subprocess::Flags::STDERR_PIPE;
86
87 auto proc = Gio::Subprocess::create(argv, flags);
88
89 if (capture_stdout && out_stdout)
90 {
91 auto [stdout_str, stderr_str] = proc->communicate_utf8("");
92 *out_stdout = stdout_str.raw();
93 return proc->get_successful();
94 }
95
96 proc->wait();
97 return proc->get_successful();
98 }
99 catch (...)
100 {
101 return false;
102 }
103 }
104
105 static bool pkexec_servicectl(const std::vector<std::string>& args,
106 bool silence_stderr = false)
107 {
108 std::vector<std::string> argv;
109 argv.reserve(args.size() + 3);
110 argv.push_back("pkexec");
111 argv.push_back("/usr/libexec/bastionguard/bastionguard-service");
112 argv.push_back("--system");
113 argv.insert(argv.end(), args.begin(), args.end());
114 return run_cmd(argv, silence_stderr);
115 }
116
117 static std::string get_user_intercept_ca_path()
118 {
119 return Glib::build_filename(
120 Glib::get_home_dir(),
121 ".local", "share", "BastionGuard", "certs", "intercept-ca.crt.pem");
122 }
123
124 static std::string get_system_fallback_ca_path()
125 {
126 return "/etc/BastionGuard/certs/intercept-ca.crt.pem";
127 }
128
129 static std::string resolve_ca_path()
130 {
131 const auto user_ca = get_user_intercept_ca_path();
132 if (std::filesystem::exists(user_ca))
133 return user_ca;
134
135 const auto system_ca = get_system_fallback_ca_path();
136 if (std::filesystem::exists(system_ca))
137 return system_ca;
138
139 return {};
140 }
141}
142
143static void ensure_config_dir()
144{
145 Glib::RefPtr<Gio::File> dir = Gio::File::create_for_path(CONFIG_DIR);
146
147 if (!dir->query_exists())
148 {
149 try
150 {
151 dir->make_directory_with_parents();
152 }
153 catch (const Glib::Error& ex)
154 {
155 std::cerr << _("Impossibile creare directory config: ") << ex.what() << std::endl;
156 }
157 }
158}
159
160static void ensure_flag_dir()
161{
162 Glib::RefPtr<Gio::File> dir = Gio::File::create_for_path(FLAG_DIR);
163
164 if (!dir->query_exists())
165 {
166 try
167 {
168 dir->make_directory_with_parents();
169 }
170 catch (const Glib::Error& ex)
171 {
172 std::cerr << _("Impossibile creare directory flag: ") << ex.what() << std::endl;
173 }
174 }
175}
176
177static void touch_flag_file()
178{
180
181 try
182 {
183 std::ofstream touch(FLAG_FILE, std::ios::out | std::ios::trunc);
184 touch.close();
185 }
186 catch (const std::exception& ex)
187 {
188 std::cerr << _("Errore durante scrittura flag file: ") << ex.what() << std::endl;
189 }
190}
191
192static void save_config(const std::vector<std::string>& service_names,
193 const std::vector<Gtk::CheckButton*>& check_buttons)
194{
196
197 json config;
198 config["wizard_completed"] = true;
199
200 Glib::DateTime now = Glib::DateTime::create_now_utc();
201 config["installed_at"] = now.format("%FT%TZ");
202
203 json services = json::object();
204 for (size_t i = 0; i < service_names.size(); ++i)
205 {
206 services[service_names[i]] = check_buttons[i]->get_active();
207 }
208 config["services"] = services;
209
210 try
211 {
212 std::ofstream file(CONFIG_FILE, std::ios::out | std::ios::trunc);
213 if (file.is_open())
214 {
215 file << config.dump(2);
216 file.close();
217 }
218 else
219 {
220 std::cerr << _("Errore: impossibile aprire config.json per scrittura") << std::endl;
221 }
222 }
223 catch (const std::exception& ex)
224 {
225 std::cerr << _("Errore durante il salvataggio config: ") << ex.what() << std::endl;
226 }
227}
228
230{
231 set_title("");
232 set_resizable(true);
233 set_default_size(720, 640);
234 set_size_request(680, 580);
235 set_modal(true);
236
238 build_ui();
240}
241
243{
244 if (Glib::file_test(FLAG_FILE, Glib::FileTest::EXISTS))
245 return;
246
247 auto* win = new FirstRunServicesWindow();
248
249 win->signal_hide().connect([win]() {
251 delete win;
252 });
253
254 win->show();
255}
256
258{
259 auto header = Gtk::make_managed<Gtk::HeaderBar>();
260 header->set_show_title_buttons(false);
261 header->set_decoration_layout("");
262 header->get_style_context()->add_class("custom-headerbar");
263
264 auto title_label = Gtk::make_managed<Gtk::Label>(_("BastionGuard - Configurazione iniziale"));
265 title_label->get_style_context()->add_class("header-title");
266 title_label->set_halign(Gtk::Align::CENTER);
267 title_label->set_valign(Gtk::Align::CENTER);
268 header->set_title_widget(*title_label);
269
270 auto header_right = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::HORIZONTAL);
271
272 try {
273 auto pix_min = Gdk::Pixbuf::create_from_file(resource("icon-minimize.png"), 32, 32, true);
274 btn_minimize = Gtk::make_managed<Gtk::Button>();
275 btn_minimize->set_child(*Gtk::make_managed<Gtk::Image>(pix_min));
276 btn_minimize->get_style_context()->add_class("header-button");
277 header_right->append(*btn_minimize);
278 btn_minimize->signal_clicked().connect(sigc::mem_fun(*this, &FirstRunServicesWindow::on_minimize_clicked));
279 } catch (...) {
280 std::cerr << _("⚠ Errore caricamento icona minimize\n");
281 }
282
283 try {
284 auto pix_close = Gdk::Pixbuf::create_from_file(resource("icon-close.png"), 32, 32, true);
285 btn_close = Gtk::make_managed<Gtk::Button>();
286 btn_close->set_child(*Gtk::make_managed<Gtk::Image>(pix_close));
287 btn_close->get_style_context()->add_class("header-button");
288 header_right->append(*btn_close);
289 btn_close->signal_clicked().connect(sigc::mem_fun(*this, &FirstRunServicesWindow::on_close_clicked));
290 } catch (...) {
291 std::cerr << _("⚠ Errore caricamento icona close\n");
292 }
293
294 header->pack_end(*header_right);
295 set_titlebar(*header);
296}
297
299{
300 auto main_box = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::HORIZONTAL, 0);
301 main_box->set_vexpand(false);
302 main_box->set_hexpand(true);
303 set_child(*main_box);
304
305 auto sidebar = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::VERTICAL, 10);
306 sidebar->set_size_request(240, -1);
307 sidebar->set_vexpand(false);
308 sidebar->get_style_context()->add_class("sidebar");
309
310 auto header_sidebar = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::HORIZONTAL, 8);
311 header_sidebar->get_style_context()->add_class("sidebar-header");
312
313 try {
314 auto pixbuf = Gdk::Pixbuf::create_from_file(resource("logo-sidebar.png"), 96, 96, true);
315 auto logo = Gtk::make_managed<Gtk::Image>(pixbuf);
316 header_sidebar->append(*logo);
317 } catch (...) {
318 std::cerr << _("⚠ Impossibile caricare logo-sidebar.png\n");
319 }
320
321 auto lbl = Gtk::make_managed<Gtk::Label>("BastionGuard");
322 lbl->set_halign(Gtk::Align::START);
323 lbl->get_style_context()->add_class("sidebar-title");
324 header_sidebar->append(*lbl);
325
326 sidebar->append(*header_sidebar);
327
328 auto spacer = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::VERTICAL);
329 spacer->set_vexpand(true);
330 sidebar->append(*spacer);
331
332 main_box->append(*sidebar);
333
334 auto content_box = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::VERTICAL, 12);
335 content_box->set_margin(24);
336 content_box->set_hexpand(true);
337 content_box->set_vexpand(false);
338 content_box->get_style_context()->add_class("content");
339 main_box->append(*content_box);
340
341 auto title = Gtk::make_managed<Gtk::Label>(_("Scegli quali servizi di protezione attivare"));
342 title->get_style_context()->add_class("title");
343 content_box->append(*title);
344
345 auto subtitle = Gtk::make_managed<Gtk::Label>(
346 _("I servizi selezionati verranno avviati automaticamente al login.\n"
347 "Potrai modificarli in qualsiasi momento dalle impostazioni."));
348 subtitle->set_wrap();
349 subtitle->add_css_class("alert-info");
350 content_box->append(*subtitle);
351
352 auto grid = Gtk::make_managed<Gtk::Grid>();
353 grid->set_column_spacing(20);
354 grid->set_row_spacing(10);
355 grid->set_margin_top(12);
356 grid->set_margin_bottom(12);
357 grid->set_vexpand(false);
358 grid->set_valign(Gtk::Align::START);
359 content_box->append(*grid);
360
361 std::vector<ServiceInfo> services = {
362 {"BastionGuard-privacyd.service", _("Privacy Guard"), _("Blocco microfono e webcam quando non in uso")},
363 {"BastionGuard-ransomware-alert.service", _("Ransomware Alert"), _("Notifiche su possibili attività ransomware")},
364 {"BastionGuard-ransomware-realtime-alert.service", _("Ransomware Realtime Alert"), _("Avvisi in tempo reale su comportamenti sospetti")},
365 {"BastionGuard-ransomware-scanner.service", _("Ransomware Scanner"), _("Scansione periodica alla ricerca di comportamenti malevoli")},
366 {"BastionGuard-useragent.service", _("User-Agent Randomizer"), _("Modifica user-agent per aumentare anonimato")},
367 {"BastionGuard-pacd.service", _("PAC Daemon"), _("Gestione automatica di proxy PAC sicuri")},
368 {"BastionGuard-phishing-scanner.service", _("Phishing Scanner (System)"), _("Scansione anti-phishing a livello di sistema")},
369 {"BastionGuard-mailproxy.service", _("Mail Proxy"), _("Proxy SMTP locale per protezione email in uscita")},
370 {"BastionGuard-usbd.service", _("USB Protection (System)"), _("Monitoraggio e blocco dispositivi USB sospetti")},
371 {"BastionGuard-ransomware-realtime.service", _("Ransomware Realtime (System)"), _("Monitor realtime ransomware a livello di sistema")},
372 };
373
375 services.push_back({"BastionGuard-cef.service", _("CEF Sandbox Service"), _("Supporto in background per pagamenti sicuri con CEF")});
376 }
377
378 int row = 0;
379 for (const auto& svc : services)
380 {
381 auto check = Gtk::make_managed<Gtk::CheckButton>(svc.label);
382 check->set_active(true);
383
384 auto desc = Gtk::make_managed<Gtk::Label>(svc.description);
385 desc->add_css_class("label");
386 desc->set_wrap();
387 desc->set_halign(Gtk::Align::START);
388 desc->set_margin_start(24);
389 desc->set_max_width_chars(50);
390 desc->set_ellipsize(Pango::EllipsizeMode::END);
391
392 grid->attach(*check, 0, row, 1, 1);
393 grid->attach(*desc, 1, row, 1, 1);
394
395 check_buttons.push_back(check);
396 service_names.push_back(svc.name);
397
398 row++;
399 }
400
401 auto btn_box = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::HORIZONTAL, 12);
402 btn_box->set_halign(Gtk::Align::END);
403 btn_box->set_margin_top(16);
404 btn_box->set_vexpand(false);
405
406 auto btn_minimal = Gtk::make_managed<Gtk::Button>(_("Configurazione minima"));
407 btn_minimal->get_style_context()->add_class("btn-warning");
408 btn_minimal->signal_clicked().connect(sigc::mem_fun(*this, &FirstRunServicesWindow::select_minimal));
409
410 auto btn_all = Gtk::make_managed<Gtk::Button>(_("Attiva tutto"));
411 btn_all->get_style_context()->add_class("btn-primary");
412 btn_all->signal_clicked().connect(sigc::mem_fun(*this, &FirstRunServicesWindow::select_all));
413
414 auto btn_apply = Gtk::make_managed<Gtk::Button>(_("Applica e continua"));
415 btn_apply->get_style_context()->add_class("btn-success");
416 btn_apply->signal_clicked().connect(sigc::mem_fun(*this, &FirstRunServicesWindow::apply_and_close));
417
418 btn_box->append(*btn_minimal);
419 btn_box->append(*btn_all);
420 btn_box->append(*btn_apply);
421
422 content_box->append(*btn_box);
423}
424
426{
427 for (size_t i = 0; i < check_buttons.size(); ++i)
428 {
429 const auto& unit = service_names[i];
430
431 bool enabled = false;
432 if (is_system_unit(unit))
433 enabled = is_system_service_enabled(unit);
434 else
435 enabled = is_user_service_enabled(unit);
436
437 check_buttons[i]->set_active(enabled);
438 }
439}
440
442{
443 for (auto* ch : check_buttons)
444 ch->set_active(true);
445}
446
448{
449 std::set<std::string> minimal = {
450 "BastionGuard-usbd.service",
451 "BastionGuard-privacyd.service",
452 "BastionGuard-ransomware-realtime-alert.service"
453 };
454
455 for (size_t i = 0; i < check_buttons.size(); ++i)
456 {
457 check_buttons[i]->set_active(minimal.contains(service_names[i]));
458 }
459}
460
461
462static void install_ca_system()
463{
465 std::cerr << _("[FirstRun] CA di sistema disabilitata: CEF non disponibile in questa build/distribuzione.\n");
466 return;
467 }
468 const std::string ca_src = resolve_ca_path();
469
470 if (ca_src.empty()) {
471 std::cerr << _("[FirstRun] CA non trovata né nella home utente né in /etc, verrà installata al primo avvio CEF\n");
472 return;
473 }
474
475 if (!std::filesystem::exists(CA_HELPER)) {
476 std::cerr << _("[FirstRun] helper non trovato: ") << CA_HELPER << "\n";
477 return;
478 }
479
480 std::cerr << _("[FirstRun] Installazione CA BastionGuard nel trust store...\n");
481 std::cerr << _("[FirstRun] Uso certificato: ") << ca_src << "\n";
482
483 bool ok = run_cmd({"pkexec", CA_HELPER, ca_src}, false);
484 if (!ok) {
485 std::cerr << _("[FirstRun] ⚠️ pkexec fallito, tentativo sudo...\n");
486 ok = run_cmd({"sudo", "--non-interactive", CA_HELPER, ca_src}, false);
487 }
488
489 if (ok) {
490 std::cerr << _("[FirstRun] ✅ CA installata nel sistema\n");
491 } else {
492 std::cerr << _("[FirstRun] ❌ Installazione CA fallita — verrà ritentata al primo avvio CEF\n");
493 try {
494 std::filesystem::remove(
495 Glib::get_user_data_dir() + "/BastionGuard/ca-installed.stamp");
496 } catch (...) {}
497 }
498}
499
501{
503 return;
504 }
505 const std::string ca_src = resolve_ca_path();
506 if (ca_src.empty()) {
507 std::cerr << _("[FirstRun] CA NSS utente non trovata\n");
508 return;
509 }
510
511 auto nss_add = [&](const std::string& db) {
512 if (!std::filesystem::exists(db))
513 return;
514
515 const std::string prefix =
516 std::filesystem::exists(db + "/cert9.db") ? "sql:" : "dbm:";
517
518 run_cmd({"certutil", "-D", "-d", prefix + db, "-n", "BastionGuard-CA"}, true);
519
520 bool ok = run_cmd({"certutil", "-A",
521 "-d", prefix + db,
522 "-n", "BastionGuard-CA",
523 "-t", "CT,,",
524 "-i", ca_src}, false);
525
526 if (ok)
527 std::cerr << _("[FirstRun] ✅ NSS: ") << db << "\n";
528 };
529
530 const std::string home = Glib::get_home_dir();
531
532
533 for (const auto& db : std::vector<std::string>{
534 home + "/.pki/nssdb",
535 home + "/snap/chromium/current/.pki/nssdb",
536 home + "/.var/app/org.chromium.Chromium/.pki/nssdb",
537 home + "/.var/app/com.google.Chrome/.pki/nssdb",
538 home + "/.var/app/com.brave.Browser/.pki/nssdb",
539 home + "/.var/app/com.microsoft.Edge/.pki/nssdb",
540 home + "/.var/app/com.opera.Opera/.pki/nssdb",
541 home + "/.var/app/com.vivaldi.Vivaldi/.pki/nssdb",
542 home + "/.config/BraveSoftware/Brave-Browser/Default",
543 home + "/.config/microsoft-edge/Default",
544 home + "/.config/opera",
545 home + "/.config/vivaldi/Default",
546 home + "/.config/chromium/Default",
547 home + "/.config/yandex-browser/Default",
548 }) {
549 nss_add(db);
550 }
551
552 auto is_profile = [](const std::string& n) {
553 for (const auto& s : {
554 ".default",
555 ".default-release",
556 ".default-esr",
557 ".dev-edition-default",
558 "-release",
559 "-esr"
560 }) {
561 if (n.size() >= std::string(s).size() &&
562 n.compare(n.size() - std::string(s).size(), std::string(s).size(), s) == 0)
563 return true;
564 }
565 return n.size() > 9 && n[8] == '.';
566 };
567
568 for (const auto& base : std::vector<std::string>{
569 home + "/.mozilla/firefox",
570 home + "/.var/app/org.mozilla.firefox/.mozilla/firefox",
571 home + "/.var/app/org.mozilla.firefoxesr/.mozilla/firefox",
572 home + "/snap/firefox/current/.mozilla/firefox",
573 home + "/.librewolf",
574 home + "/.var/app/io.gitlab.librewolf-community/.librewolf",
575 home + "/.waterfox",
576 home + "/.floorp",
577 home + "/.var/app/one.ablaze.floorp/.floorp",
578 home + "/.zen",
579 home + "/.var/app/io.github.zen_browser.zen/.zen",
580 home + "/.icecat",
581 home + "/.thunderbird",
582 home + "/.var/app/org.mozilla.Thunderbird/.thunderbird",
583 home + "/snap/thunderbird/current/.thunderbird",
584 }) {
585 if (!std::filesystem::exists(base))
586 continue;
587
588 try {
589 for (const auto& e : std::filesystem::directory_iterator(base)) {
590 if (e.is_directory() && is_profile(e.path().filename().string()))
591 nss_add(e.path().string());
592 }
593 } catch (...) {}
594 }
595
596 std::cerr << _("[FirstRun] ✅ NSS profili utente aggiornati\n");
597}
598
600{
601 for (size_t i = 0; i < check_buttons.size(); ++i)
602 {
603 const auto& unit = service_names[i];
604 bool want = check_buttons[i]->get_active();
605
606 bool current = false;
607 if (is_system_unit(unit))
608 current = is_system_service_enabled(unit);
609 else
610 current = is_user_service_enabled(unit);
611
612 if (want == current)
613 continue;
614
615 if (is_system_unit(unit))
616 {
617 if (want) enable_system_service(unit);
618 else disable_system_service(unit);
619 }
620 else
621 {
622 if (want) enable_user_service(unit);
623 else disable_user_service(unit);
624 }
625 }
626
628
630
631 std::thread([]() { install_ca_nss_user(); }).detach();
632
633 hide();
634}
635
637{
638#if GTKMM_CHECK_VERSION(4,10,0)
639 hide();
640#endif
641}
642
647
649{
651 return false;
652}
653
654bool FirstRunServicesWindow::is_user_service_enabled(const std::string& service_name)
655{
656 try
657 {
658 auto proc = Gio::Subprocess::create(
659 {"/usr/libexec/bastionguard/bastionguard-service", "--user", "is-enabled", service_name},
660 Gio::Subprocess::Flags::STDOUT_PIPE |
661 Gio::Subprocess::Flags::STDERR_PIPE
662 );
663
664 auto [stdout_str, stderr_str] = proc->communicate_utf8("");
665
666 if (!proc->get_successful())
667 return false;
668
669 std::string result = stdout_str.raw();
670 result.erase(std::remove(result.begin(), result.end(), '\n'), result.end());
671 result.erase(std::remove(result.begin(), result.end(), '\r'), result.end());
672
673 return result == "enabled";
674 }
675 catch (...)
676 {
677 return false;
678 }
679}
680
681bool FirstRunServicesWindow::enable_user_service(const std::string& service_name)
682{
683 if (!run_cmd({"/usr/libexec/bastionguard/bastionguard-service", "--user", "enable", "--now", service_name}))
684 return false;
685
686 run_cmd({"/usr/libexec/bastionguard/bastionguard-service", "--user", "start", service_name});
687 return true;
688}
689
690bool FirstRunServicesWindow::disable_user_service(const std::string& service_name)
691{
692 run_cmd({"/usr/libexec/bastionguard/bastionguard-service", "--user", "stop", service_name});
693 return run_cmd({"/usr/libexec/bastionguard/bastionguard-service", "--user", "disable", "--now", service_name});
694}
695
697{
698 try
699 {
700 auto proc = Gio::Subprocess::create(
701 {"/usr/libexec/bastionguard/bastionguard-service", "--system", "is-enabled", unit_name},
702 Gio::Subprocess::Flags::STDOUT_PIPE |
703 Gio::Subprocess::Flags::STDERR_PIPE
704 );
705
706 auto [stdout_str, stderr_str] = proc->communicate_utf8("");
707
708 if (!proc->get_successful())
709 return false;
710
711 std::string result = stdout_str.raw();
712 result.erase(std::remove(result.begin(), result.end(), '\n'), result.end());
713 result.erase(std::remove(result.begin(), result.end(), '\r'), result.end());
714
715 return result == "enabled";
716 }
717 catch (...)
718 {
719 return false;
720 }
721}
722
723bool FirstRunServicesWindow::enable_system_service(const std::string& unit_name)
724{
725 if (!pkexec_servicectl({"enable", "--now", unit_name}, false))
726 return false;
727
728 pkexec_servicectl({"start", unit_name}, false);
729 return true;
730}
731
732bool FirstRunServicesWindow::disable_system_service(const std::string& unit_name)
733{
734 pkexec_servicectl({"stop", unit_name}, false);
735 return pkexec_servicectl({"disable", "--now", unit_name}, false);
736}
nlohmann::json json
Definition Backend.cpp:2908
#define _(s)
bool disable_user_service(const std::string &service_name)
bool enable_system_service(const std::string &unit_name)
std::vector< Gtk::CheckButton * > check_buttons
bool is_user_service_enabled(const std::string &service_name)
bool is_system_service_enabled(const std::string &unit_name)
bool disable_system_service(const std::string &unit_name)
bool enable_user_service(const std::string &service_name)
std::vector< std::string > service_names
static void install_ca_system()
static void save_config(const std::vector< std::string > &service_names, const std::vector< Gtk::CheckButton * > &check_buttons)
static void ensure_config_dir()
static void touch_flag_file()
static void install_ca_nss_user()
static void ensure_flag_dir()
static bool run_cmd(const std::vector< std::string > &argv, bool silence_stderr=true, bool capture_stdout=false, std::string *out_stdout=nullptr)
static bool is_system_unit(const std::string &unit_name)
static bool pkexec_servicectl(const std::vector< std::string > &args, bool silence_stderr=false)
std::string resource(const std::string &rel)
Definition Resource.hpp:31