diff --git a/data/cz.vesp.roster.gschema.xml b/data/cz.vesp.roster.gschema.xml index f91a8b2..406510b 100644 --- a/data/cz.vesp.roster.gschema.xml +++ b/data/cz.vesp.roster.gschema.xml @@ -1,5 +1,15 @@ + + true + Force TLS verification + When enabled, TLS certificates will be verified. Disable to test endpoints with self-signed or invalid certificates. + + + 30 + Request timeout + Timeout for HTTP requests in seconds + diff --git a/src/http_client.py b/src/http_client.py index 736ca12..287f10c 100644 --- a/src/http_client.py +++ b/src/http_client.py @@ -19,7 +19,7 @@ import gi gi.require_version('Soup', '3.0') -from gi.repository import Soup, GLib +from gi.repository import Soup, GLib, Gio import time from typing import Optional, Callable, Any @@ -32,7 +32,36 @@ class HttpClient: def __init__(self): """Initialize HTTP client with reusable session.""" self.session = Soup.Session.new() - self.session.set_timeout(30) # 30 second timeout + + # Load settings + self.settings = Gio.Settings.new('cz.vesp.roster') + + # Initialize TLS verification flag + self.force_tls_verification = True + + # Apply initial settings + self._apply_settings() + + # Listen for settings changes + self.settings.connect('changed::force-tls-verification', self._on_settings_changed) + self.settings.connect('changed::request-timeout', self._on_settings_changed) + + def _apply_settings(self): + """Apply settings to the HTTP session.""" + # Store TLS verification preference (will be applied per-message) + self.force_tls_verification = self.settings.get_boolean('force-tls-verification') + + # Apply timeout setting + timeout = self.settings.get_int('request-timeout') + self.session.set_timeout(timeout) + + def _on_settings_changed(self, settings, key): + """Handle settings changes.""" + self._apply_settings() + + def _accept_all_certificates(self, msg, tls_certificate, tls_errors): + """Accept all TLS certificates when verification is disabled.""" + return True # Accept certificate regardless of errors def execute_request_async(self, request: HttpRequest, callback: Callable, user_data: Any = None): """ @@ -59,6 +88,11 @@ class HttpClient: callback(None, f"Invalid URL: {e}", user_data) return + # Handle TLS certificate verification + if not self.force_tls_verification: + # Connect signal to accept all certificates when verification is disabled + msg.connect('accept-certificate', self._accept_all_certificates) + # Add headers headers = msg.get_request_headers() for key, value in request.headers.items(): diff --git a/src/main.py b/src/main.py index 351d6b7..98e4a04 100644 --- a/src/main.py +++ b/src/main.py @@ -25,6 +25,7 @@ gi.require_version('Adw', '1') from gi.repository import Gtk, Gio, Adw from .window import RosterWindow +from .preferences_dialog import PreferencesDialog class RosterApplication(Adw.Application): @@ -67,7 +68,9 @@ class RosterApplication(Adw.Application): def on_preferences_action(self, widget, _): """Callback for the app.preferences action.""" - print('app.preferences action activated') + preferences = PreferencesDialog() + preferences.set_transient_for(self.props.active_window) + preferences.present() def on_shortcuts_action(self, widget, _): """Callback for the app.shortcuts action.""" diff --git a/src/meson.build b/src/meson.build index 3925436..0de6bb2 100644 --- a/src/meson.build +++ b/src/meson.build @@ -37,6 +37,7 @@ roster_sources = [ 'tab_manager.py', 'constants.py', 'icon_picker_dialog.py', + 'preferences_dialog.py', ] install_data(roster_sources, install_dir: moduledir) diff --git a/src/preferences-dialog.ui b/src/preferences-dialog.ui new file mode 100644 index 0000000..9c175be --- /dev/null +++ b/src/preferences-dialog.ui @@ -0,0 +1,49 @@ + + + + + + + diff --git a/src/preferences_dialog.py b/src/preferences_dialog.py new file mode 100644 index 0000000..6f97848 --- /dev/null +++ b/src/preferences_dialog.py @@ -0,0 +1,49 @@ +# preferences_dialog.py +# +# Copyright 2025 Pavel Baksy +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# SPDX-License-Identifier: GPL-3.0-or-later + +from gi.repository import Adw, Gtk, Gio + + +@Gtk.Template(resource_path='/cz/vesp/roster/preferences-dialog.ui') +class PreferencesDialog(Adw.PreferencesWindow): + __gtype_name__ = 'PreferencesDialog' + + tls_verification_row = Gtk.Template.Child() + timeout_row = Gtk.Template.Child() + + def __init__(self, **kwargs): + super().__init__(**kwargs) + + # Get settings + self.settings = Gio.Settings.new('cz.vesp.roster') + + # Bind settings to UI + self.settings.bind( + 'force-tls-verification', + self.tls_verification_row, + 'active', + Gio.SettingsBindFlags.DEFAULT + ) + + self.settings.bind( + 'request-timeout', + self.timeout_row, + 'value', + Gio.SettingsBindFlags.DEFAULT + ) diff --git a/src/roster.gresource.xml b/src/roster.gresource.xml index 561d1ca..b782723 100644 --- a/src/roster.gresource.xml +++ b/src/roster.gresource.xml @@ -3,6 +3,7 @@ main-window.ui shortcuts-dialog.ui + preferences-dialog.ui icon-picker-dialog.ui widgets/header-row.ui widgets/history-item.ui