1. Overview
The PhishingCheckCard module implements a reusable GTKmm (GTK4) input card used to start phishing analysis inside BastionGuard. It provides a compact, card-style interface composed of an icon, title, descriptive text, URL/domain input field, action button, and inline feedback label.
The component is designed as a self-contained UI element for phishing checks: it validates user input locally, emits a typed signal when analysis should begin, and exposes helper methods for runtime customization of title, description, placeholder text, button label, URL content, and feedback state.
The module integrates with:
- GTKmm / GTK4 – box layout, labels, entry field, button, icon widget, alignment, and style classes
- glibmm i18n – translated labels and validation messages through
_() - glibmm markup – safe title rendering through
Glib::Markup::escape_text() - sigc++ signals – outward notification via
signal_analyze_requested() - std::regex – lightweight validation for domain/URL format checks
2. Construction and Layout
2.1 Base Widget Structure
PhishingCheckCard derives from Gtk::Box and is initialized as a vertical container with spacing 8:
PhishingCheckCard::PhishingCheckCard()
: Gtk::Box(Gtk::Orientation::VERTICAL, 8),
btn_analyze_(_("Analyze"))
The root widget applies the CSS class:
phishing-card
It is configured with internal margins on all sides and horizontal expansion enabled.
2.2 Internal Layout Hierarchy
The visual layout is split into two main horizontal regions inside root_box_:
- Icon area – contained in
icon_box_ - Content area – contained in
content_box_
The content area stacks the following widgets vertically:
lbl_title_– bold card titlelbl_description_– wrapped descriptive explanationaction_row_– row containing the URL entry and analyze buttonlbl_feedback_– inline feedback/status message
The complete assembled structure is appended to the outer widget through append(root_box_).
3. Visual Elements and Default Content
3.1 Icon Section
The card displays a search-themed symbolic icon inside icon_box_. The implementation attempts to load:
system-search-symbolic
The icon is set to pixel size 28 and styled with:
phishing-card-icon-wrap– wrapper stylingphishing-card-icon– icon-specific styling
Icon initialization is wrapped in a try/catch block so missing icon theme resources do not cause widget construction failure.
3.2 Title and Description
The default title is rendered using Pango markup:
<b>Check a domain phishing</b>
The title is left-aligned and styled with:
phishing-card-title
The default description explains BastionGuard’s heuristic phishing analysis approach, including detection of:
- Phishing patterns
- Redirect chains
- Credential-harvesting forms
- Obfuscated scripts
- Brand impersonation signals
The description is wrapped with Pango::WrapMode::WORD_CHAR and styled through:
phishing-card-description
3.3 Action Row
The input/action row contains:
entry_url_– a single-line URL/domain input fieldbtn_analyze_– the action button used to trigger analysis
The entry field is configured with:
- Horizontal expansion enabled
- Default placeholder:
https://example.com/login
- CSS class:
phishing-card-entry
The analyze button is initialized with the localized label Analyze and styled with:
suggested-actionphishing-card-button
3.4 Feedback Label
The feedback label is used for inline validation and runtime status messages. It is initially hidden and styled through:
phishing-card-feedback
When error feedback is requested, the additional CSS class error is applied dynamically.
4. Signals and User Interaction
4.1 Analyze Signal Exposure
The component exposes an outward signal through:
sigc::signal<void(const Glib::ustring&)>&
PhishingCheckCard::signal_analyze_requested()
This signal is emitted only after local validation succeeds, allowing parent containers such as PhishingPage to react to clean input without duplicating basic UI validation logic.
4.2 Button and Enter-Key Trigger
The card supports two equivalent user triggers for starting analysis:
- Clicking the analyze button
- Pressing Enter inside the URL entry field
Both actions are connected to the same handler:
PhishingCheckCard::on_analyze_clicked()
This keeps keyboard and pointer interaction behavior fully aligned.
5. Public Runtime Customization API
The widget exposes a small customization API so the card can be reused with different wording or pre-filled values.
set_title(text)– updates the title using bold markup with escaped textset_description(text)– replaces the descriptive paragraphset_placeholder(text)– changes the URL entry placeholderset_button_label(text)– changes the action button labelget_url()– returns the current entry contentset_url(url)– preloads the input field with a URL/domainset_feedback(text, is_error)– displays inline feedback and optionally marks it as error stateclear_feedback()– clears feedback text, removes error styling, and hides the label
The title setter is explicitly safe for user-provided text because it uses Glib::Markup::escape_text() before embedding content into a <b>...</b> markup wrapper.
6. Validation Logic
6.1 Empty Input Handling
When the user triggers analysis, the handler first reads the current entry value:
const auto url = entry_url_.get_text();
If the input is empty, the card does not emit the analysis signal. Instead, it shows the inline error message:
Insert a URL or domain to analyze.
6.2 URL/Domain Format Validation
Format validation is implemented by is_valid_url(), which applies a regular expression to the raw text.
The current regex accepts:
- Optional
http://orhttps://prefix - Domain names with one or more dotted labels
localhost- Optional port
- Optional path
At a high level, accepted examples include values such as:
example.comhttps://example.comhttps://example.com/loginlocalhost:8080/test
If validation fails, the card displays the error message:
The URL/domain format is not valid.
6.3 Successful Validation Path
If the input is non-empty and matches the accepted format, the card sets non-error feedback:
Analysis started...
and emits the outward analysis request signal with the raw user input.
7. Feedback State Management
Inline feedback behavior is centralized in set_feedback(text, is_error).
The method performs three coordinated actions:
- Sets the feedback label text
- Adds or removes the
errorCSS class depending on theis_errorflag - Shows or hides the label depending on whether the text is empty
This makes the feedback widget usable both for validation errors and for neutral progress messages such as analysis start confirmation.
The companion method clear_feedback() fully resets the label to a hidden, non-error state.
8. Styling and UX Considerations
- Card-oriented composition: the widget isolates phishing input workflow into a reusable, stylable component
- Keyboard accessibility: the entry field supports Enter-to-analyze in addition to button click
- Immediate validation feedback: empty and malformed input are rejected locally before any external action is triggered
- Safe title rendering: title customization escapes markup before applying bold formatting
- Graceful icon handling: missing symbolic icons do not break widget initialization
- Visual error separation: the feedback label distinguishes normal and error states through a dedicated CSS class
- Loose coupling: the widget emits an analysis signal rather than embedding network or parsing logic directly