Skip to content
API Documentation
BastionGuard™
PhishingCheckCard.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 "PhishingCheckCard.hpp"
22#include <glibmm/i18n.h>
23#include <glibmm/markup.h>
24#include <regex>
25
27 : Gtk::Box(Gtk::Orientation::VERTICAL, 8),
28 btn_analyze_(_("Analyze"))
29{
30 add_css_class("phishing-card");
31 set_margin_top(16);
32 set_margin_bottom(16);
33 set_margin_start(16);
34 set_margin_end(16);
35 set_hexpand(true);
36
37 root_box_.set_hexpand(true);
38 root_box_.set_valign(Gtk::Align::CENTER);
39
40 icon_box_.set_valign(Gtk::Align::START);
41 icon_box_.add_css_class("phishing-card-icon-wrap");
42
43 try {
44 icon_.set_from_icon_name("system-search-symbolic");
45 } catch (...) {
46 }
47
48 icon_.set_pixel_size(28);
49 icon_.add_css_class("phishing-card-icon");
50 icon_box_.append(icon_);
51
52 lbl_title_.set_markup("<b>Check a domain phishing</b>");
53 lbl_title_.set_halign(Gtk::Align::START);
54 lbl_title_.set_xalign(0.0f);
55 lbl_title_.add_css_class("phishing-card-title");
56
57 lbl_description_.set_text(
58 _("When a destination is not present in our blocklists, "
59 "BastionGuard applies heuristic page analysis to detect phishing "
60 "patterns, redirect chains, credential-harvesting forms, "
61 "obfuscated scripts, and brand impersonation signals."));
62 lbl_description_.set_wrap(true);
63 lbl_description_.set_wrap_mode(Pango::WrapMode::WORD_CHAR);
64 lbl_description_.set_halign(Gtk::Align::START);
65 lbl_description_.set_xalign(0.0f);
66 lbl_description_.add_css_class("phishing-card-description");
67
68 entry_url_.set_hexpand(true);
69 entry_url_.set_placeholder_text("https://example.com/login");
70 entry_url_.add_css_class("phishing-card-entry");
71 entry_url_.signal_activate().connect(
72 sigc::mem_fun(*this, &PhishingCheckCard::on_analyze_clicked));
73
74 btn_analyze_.add_css_class("suggested-action");
75 btn_analyze_.add_css_class("phishing-card-button");
76 btn_analyze_.signal_clicked().connect(
77 sigc::mem_fun(*this, &PhishingCheckCard::on_analyze_clicked));
78
79 action_row_.set_hexpand(true);
80 action_row_.append(entry_url_);
82
83 lbl_feedback_.set_halign(Gtk::Align::START);
84 lbl_feedback_.set_xalign(0.0f);
85 lbl_feedback_.set_visible(false);
86 lbl_feedback_.add_css_class("phishing-card-feedback");
87
88 content_box_.set_hexpand(true);
93
94 root_box_.append(icon_box_);
95 root_box_.append(content_box_);
96
97 append(root_box_);
98}
99
100sigc::signal<void(const Glib::ustring&)>& PhishingCheckCard::signal_analyze_requested() {
102}
103
104void PhishingCheckCard::set_title(const Glib::ustring& text) {
105 lbl_title_.set_markup("<b>" + Glib::Markup::escape_text(text) + "</b>");
106}
107
108void PhishingCheckCard::set_description(const Glib::ustring& text) {
109 lbl_description_.set_text(text);
110}
111
112void PhishingCheckCard::set_placeholder(const Glib::ustring& text) {
113 entry_url_.set_placeholder_text(text);
114}
115
116void PhishingCheckCard::set_button_label(const Glib::ustring& text) {
117 btn_analyze_.set_label(text);
118}
119
120void PhishingCheckCard::set_feedback(const Glib::ustring& text, bool is_error) {
121 lbl_feedback_.set_text(text);
122
123 if (is_error)
124 lbl_feedback_.add_css_class("error");
125 else
126 lbl_feedback_.remove_css_class("error");
127
128 lbl_feedback_.set_visible(!text.empty());
129}
130
132 lbl_feedback_.set_text({});
133 lbl_feedback_.remove_css_class("error");
134 lbl_feedback_.set_visible(false);
135}
136
137Glib::ustring PhishingCheckCard::get_url() const {
138 return entry_url_.get_text();
139}
140
141void PhishingCheckCard::set_url(const Glib::ustring& url) {
142 entry_url_.set_text(url);
143}
144
145bool PhishingCheckCard::is_valid_url(const Glib::ustring& url) const {
146 static const std::regex re(
147 R"(^(https?:\/\/)?(([A-Za-z0-9-]+\.)+[A-Za-z]{2,}|localhost)(:\d+)?(\/[^\s]*)?$)",
148 std::regex::icase);
149 return std::regex_match(url.raw(), re);
150}
151
153 const auto url = entry_url_.get_text();
154
155 if (url.empty()) {
156 set_feedback(_("Insert a URL or domain to analyze."), true);
157 return;
158 }
159
160 if (!is_valid_url(url)) {
161 set_feedback(_("The URL/domain format is not valid."), true);
162 return;
163 }
164
165 set_feedback(_("Analysis started..."), false);
167}
#define _(s)
void set_url(const Glib::ustring &url)
void set_button_label(const Glib::ustring &text)
sigc::signal< void(const Glib::ustring &)> signal_analyze_requested_
void set_placeholder(const Glib::ustring &text)
Glib::ustring get_url() const
void set_description(const Glib::ustring &text)
bool is_valid_url(const Glib::ustring &url) const
sigc::signal< void(const Glib::ustring &)> & signal_analyze_requested()
void set_feedback(const Glib::ustring &text, bool is_error=false)
void set_title(const Glib::ustring &text)