Skip to content
API Documentation
BastionGuard™
xdg-open.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
22#include "xdg-open.hpp"
23#include "SecureBrowser.hpp"
24#include "SettingsStore.hpp"
25#include <fstream>
26#include <iostream>
27#include <nlohmann/json.hpp>
28#include <filesystem>
29#include <regex>
30#include <cstdlib>
31#include <glibmm.h>
32#include <glibmm/i18n.h>
33
34namespace fs = std::filesystem;
35using json = nlohmann::json;
36
37bool BankOpener::open_if_trusted(const std::string& url) {
38 if (url.empty()) {
39 std::cerr << _("[BankOpener] ⚠️ URL vuoto.\n");
40 return false;
41 }
42
43 std::string domain = extract_domain(url);
44 if (domain.empty()) {
45 std::cerr << _("[BankOpener] ❌ Impossibile estrarre dominio da: ") << url << "\n";
46 return false;
47 }
48
49 const bool trusted_bank = is_trusted_domain(domain);
50 const bool trusted_pay = is_payment_domain(domain);
51 if (trusted_bank || trusted_pay) {
52 std::cout << _("[BankOpener] 🧩 Dominio sicuro rilevato: ") << domain
53 << (trusted_bank ? " (bank)" : " (payments)") << "\n";
54 std::cout << _("[BankOpener] 🔐 Avvio sandbox CEF (Blink)...\n");
55 if (!SecureBrowser::open(url, 0, nullptr)) {
56 std::cerr << _("[BankOpener] ❌ Sandbox non avviata.\n");
57 return false;
58 }
59 return true;
60 }
61
62 std::cout << _("[BankOpener] 🌐 Dominio non in lista sicura: ") << domain << "\n";
63 std::cout << _("[BankOpener] → Delego l'apertura sicura al chiamante.\n");
64 return false;
65}
66
67
68std::string BankOpener::extract_domain(const std::string& url) {
69 std::regex re(R"(^(?:https?:\/\/)?(?:www\.)?([^\/:]+))", std::regex::icase);
70 std::smatch match;
71 if (std::regex_search(url, match, re)) {
72 std::string domain = match[1].str();
73 if (domain.rfind("www.", 0) == 0)
74 domain = domain.substr(4);
75 std::transform(domain.begin(), domain.end(), domain.begin(), ::tolower);
76 return domain;
77 }
78 return "";
79}
80
81bool BankOpener::ends_with(const std::string& s, const std::string& suffix) {
82 if (suffix.size() > s.size()) return false;
83 return std::equal(
84 suffix.rbegin(), suffix.rend(),
85 s.rbegin(),
86 [](char a, char b) { return std::tolower(a) == std::tolower(b); }
87 );
88}
89
90bool BankOpener::is_trusted_domain(const std::string& domain) {
91 namespace fs = std::filesystem;
92 std::string path_user = Glib::get_home_dir() + "/.local/share/BastionGuard/banks.json";
93 std::string path_system = "/usr/share/BastionGuard/data/bank/banks.json";
94 std::string path_whitelist = Glib::get_home_dir() + "/.config/BastionGuard/whitelist.json";
95
96 std::vector<std::string> domains;
97
98 auto load_domains = [&](const std::string& path) {
99 if (!fs::exists(path))
100 return;
101
102 std::ifstream f(path);
103 if (!f.is_open()) {
104 std::cerr << _("[BankOpener] ⚠️ Impossibile aprire ") << path << "\n";
105 return;
106 }
107
108 json j;
109 try { f >> j; } catch (...) {
110 std::cerr << _("[BankOpener] ⚠️ Errore parsing JSON in ") << path << "\n";
111 return;
112 }
113
114 if (j.contains("list") && j["list"].is_array()) {
115 for (auto& item : j["list"]) {
116 if (item.is_string())
117 domains.push_back(clean_domain(item.get<std::string>()));
118 else if (item.contains("value"))
119 domains.push_back(clean_domain(item["value"].get<std::string>()));
120 }
121 } else if (j.is_array()) {
122 for (auto& b : j) {
123 if (b.is_object() && b.contains("domains") && b["domains"].is_array() && !b["domains"].empty())
124 domains.push_back(clean_domain(b["domains"][0].get<std::string>()));
125 else if (b.is_string())
126 domains.push_back(clean_domain(b.get<std::string>()));
127 }
128 }
129 };
130
131 load_domains(path_user);
132 load_domains(path_system);
133 load_domains(path_whitelist);
134
135 if (domains.empty()) {
136 std::cerr << _("[BankOpener] ⚠️ Nessun dominio caricato da liste.\n");
137 return false;
138 }
139
140 std::string dnorm = clean_domain(domain);
141
142 for (auto& d : domains) {
143 if (dnorm == d || ends_with(dnorm, "." + d) || ends_with(d, "." + dnorm))
144 return true;
145 }
146
147 return false;
148}
149
150bool BankOpener::is_payment_domain(const std::string& domain) {
151 // Attivo solo se impostazione ON
153 return false;
154
155 namespace fs = std::filesystem;
156
157 std::string path_user = Glib::get_home_dir() + "/.config/BastionGuard/payments.json";
158 std::string path_system = "/usr/share/BastionGuard/data/payments/payments.json";
159
160 static bool initialized = false;
161 static std::vector<std::string> cached;
162
163 if (!initialized) {
164 auto load_domains = [&](const std::string& path) {
165 if (!fs::exists(path))
166 return;
167
168 std::ifstream f(path);
169 if (!f.is_open()) {
170 std::cerr << _("[BankOpener] ⚠️ Impossibile aprire ") << path << "\n";
171 return;
172 }
173
174 json j;
175 try { f >> j; } catch (...) {
176 std::cerr << _("[BankOpener] ⚠️ Errore parsing JSON in ") << path << "\n";
177 return;
178 }
179
180 auto push = [&](const std::string& raw) {
181 auto cd = clean_domain(raw);
182 if (!cd.empty()) cached.push_back(cd);
183 };
184
185 if (j.is_object()) {
186 if (j.contains("list") && j["list"].is_array()) {
187 for (auto& item : j["list"]) {
188 if (item.is_string()) push(item.get<std::string>());
189 else if (item.is_object() && item.contains("value") && item["value"].is_string())
190 push(item["value"].get<std::string>());
191 }
192 } else if (j.contains("domains") && j["domains"].is_array()) {
193 for (auto& item : j["domains"]) if (item.is_string()) push(item.get<std::string>());
194 } else if (j.contains("whitelist") && j["whitelist"].is_array()) {
195 for (auto& item : j["whitelist"]) if (item.is_string()) push(item.get<std::string>());
196 }
197 } else if (j.is_array()) {
198 for (auto& v : j) {
199 if (v.is_string()) push(v.get<std::string>());
200 else if (v.is_object() && v.contains("domains") && v["domains"].is_array() && !v["domains"].empty()) {
201 if (v["domains"][0].is_string()) push(v["domains"][0].get<std::string>());
202 }
203 }
204 }
205 };
206
207 load_domains(path_system);
208 load_domains(path_user);
209
210 std::cerr << _("[BankOpener] ✅ Domini pagamenti caricati: ") << cached.size() << "\n";
211 initialized = true;
212 }
213
214 if (cached.empty())
215 return false;
216
217 std::string dnorm = clean_domain(domain);
218
219 for (auto& d : cached) {
220 if (dnorm == d || ends_with(dnorm, "." + d) || ends_with(d, "." + dnorm))
221 return true;
222 }
223
224 return false;
225}
226
227std::string BankOpener::clean_domain(const std::string& d) {
228 std::string s = d;
229 if (!s.empty() && s[0] == '.')
230 s = s.substr(1);
231 if (s.rfind("www.", 0) == 0)
232 s = s.substr(4);
233 std::transform(s.begin(), s.end(), s.begin(), ::tolower);
234 return s;
235}
nlohmann::json json
Definition Backend.cpp:2908
#define _(s)
static bool is_payment_domain(const std::string &domain)
Definition xdg-open.cpp:150
static bool is_trusted_domain(const std::string &domain)
Definition xdg-open.cpp:90
static bool ends_with(const std::string &value, const std::string &suffix)
Definition xdg-open.cpp:81
static std::string extract_domain(const std::string &url)
Definition xdg-open.cpp:68
static bool open_if_trusted(const std::string &url)
Definition xdg-open.cpp:37
static std::string clean_domain(const std::string &d)
Definition xdg-open.cpp:227
static bool open(const std::string &url, int argc, char **argv)
static bool get_secure_payments_enabled()