From 2e344d7ce18b6c48acc759d4d629fa7ad233bbf8 Mon Sep 17 00:00:00 2001 From: Michael Gratton Date: Tue, 8 Jan 2019 23:44:44 +1100 Subject: [PATCH] Handle untrusted certs when adding a new account Make the cert mamager easily available to acccount editor panes, hook up to untrusted-host when validating the new account and prompt to pin certs as needed. --- .../accounts/accounts-editor-add-pane.vala | 74 ++++++++++++++++--- src/client/accounts/accounts-editor.vala | 6 ++ 2 files changed, 69 insertions(+), 11 deletions(-) diff --git a/src/client/accounts/accounts-editor-add-pane.vala b/src/client/accounts/accounts-editor-add-pane.vala index 3c5468df..5d9f54ae 100644 --- a/src/client/accounts/accounts-editor-add-pane.vala +++ b/src/client/accounts/accounts-editor-add-pane.vala @@ -163,7 +163,7 @@ internal class Accounts.EditorAddPane : Gtk.Grid, EditorPane { this.is_operation_running = true; bool is_valid = false; - string message = ""; + string? message = null; Gtk.Widget? to_focus = null; Geary.AccountInformation account = @@ -178,6 +178,7 @@ internal class Accounts.EditorAddPane : Gtk.Grid, EditorPane { account.incoming = new_imap_service(); account.outgoing = new_smtp_service(); + account.untrusted_host.connect(on_untrusted_host); if (this.provider == Geary.ServiceProvider.OTHER) { bool imap_valid = false; @@ -193,11 +194,17 @@ internal class Accounts.EditorAddPane : Gtk.Grid, EditorPane { to_focus = this.imap_login.value; // Translators: In-app notification label message = _("Check your receiving login and password"); + } catch (GLib.TlsError.BAD_CERTIFICATE err) { + debug("Error validating IMAP certifiate: %s", err.message); + // Nothing to do here, since the untrusted host + // handler will be dealing with it } catch (GLib.IOError.CANCELLED err) { // Nothing to do here, someone just cancelled debug("IMAP validation was cancelled: %s", err.message); } catch (GLib.Error err) { - debug("Error validating IMAP service: %s", err.message); + Geary.ErrorContext context = new Geary.ErrorContext(err); + debug("Error validating IMAP service: %s", + context.format_full_error()); this.imap_tls.show(); to_focus = this.imap_hostname.value; // Translators: In-app notification label @@ -224,11 +231,17 @@ internal class Accounts.EditorAddPane : Gtk.Grid, EditorPane { to_focus = this.smtp_login.value; // Translators: In-app notification label message = _("Check your sending login and password"); + } catch (GLib.TlsError.BAD_CERTIFICATE err) { + debug("Error validating SMTP certifiate: %s", err.message); + // Nothing to do here, since the untrusted host + // handler will be dealing with it } catch (GLib.IOError.CANCELLED err) { // Nothing to do here, someone just cancelled debug("SMTP validation was cancelled: %s", err.message); } catch (GLib.Error err) { - debug("Error validating SMTP service: %s", err.message); + Geary.ErrorContext context = new Geary.ErrorContext(err); + debug("Error validating SMTP service: %s", + context.format_full_error()); this.smtp_tls.show(); to_focus = this.smtp_hostname.value; // Translators: In-app notification label @@ -249,7 +262,9 @@ internal class Accounts.EditorAddPane : Gtk.Grid, EditorPane { // Translators: In-app notification label message = _("Check your email address and password"); } catch (GLib.Error err) { - debug("Error validating provider service: %s", err.message); + Geary.ErrorContext context = new Geary.ErrorContext(err); + debug("Error validating SMTP service: %s", + context.format_full_error()); is_valid = false; // Translators: In-app notification label message = _("Could not connect, check your network"); @@ -269,6 +284,7 @@ internal class Accounts.EditorAddPane : Gtk.Grid, EditorPane { } } + account.untrusted_host.disconnect(on_untrusted_host); this.is_operation_running = false; // Focus and pop up the notification after re-sensitising @@ -277,13 +293,15 @@ internal class Accounts.EditorAddPane : Gtk.Grid, EditorPane { if (to_focus != null) { to_focus.grab_focus(); } - this.editor.add_notification( - new InAppNotification( - // Translators: In-app notification label, the - // string substitution is a more detailed reason. - _("Account not created: %s").printf(message) - ) - ); + if (message != null) { + this.editor.add_notification( + new InAppNotification( + // Translators: In-app notification label, the + // string substitution is a more detailed reason. + _("Account not created: %s").printf(message) + ) + ); + } } } @@ -419,6 +437,40 @@ internal class Accounts.EditorAddPane : Gtk.Grid, EditorPane { check_validation(); } + private void on_untrusted_host(Geary.AccountInformation account, + Geary.ServiceInformation service, + Geary.Endpoint endpoint, + GLib.TlsConnection cx) { + this.editor.certificates.prompt_pin_certificate.begin( + this.editor, account, service, endpoint, true, this.op_cancellable, + (obj, res) => { + try { + this.editor.certificates.prompt_pin_certificate.end(res); + } catch (Application.CertificateManagerError.UNTRUSTED err) { + // All good, just drop back into the editor window. + return; + } catch (Application.CertificateManagerError.STORE_FAILED err) { + // All good, just drop back into the editor + // window. XXX show error info bar rather than a + // notification + this.editor.add_notification( + new InAppNotification( + // Translators: In-app notification label, + // when the app had a problem pinning an + // otherwise untrusted TLS certificate + _("Failed to store certificate") + ) + ); + return; + } catch (Application.CertificateManagerError err) { + debug("Unexptected error pinning cert: %s", err.message); + } + + // Kick off another attempt to validate + this.validate_account.begin(this.op_cancellable); + }); + } + [GtkCallback] private void on_create_button_clicked() { this.validate_account.begin(this.op_cancellable); diff --git a/src/client/accounts/accounts-editor.vala b/src/client/accounts/accounts-editor.vala index 7b6f0a04..1d1a8be6 100644 --- a/src/client/accounts/accounts-editor.vala +++ b/src/client/accounts/accounts-editor.vala @@ -36,6 +36,9 @@ public class Accounts.Editor : Gtk.Dialog { internal Manager accounts { get; private set; } + internal Application.CertificateManager certificates { + get; private set; + } private SimpleActionGroup actions = new SimpleActionGroup(); @@ -55,6 +58,9 @@ public class Accounts.Editor : Gtk.Dialog { this.application = application; this.transient_for = parent; + this.accounts = application.controller.account_manager; + this.certificates = application.controller.certificate_manager; + // Can't set this in Glade 3.22.1 :( this.get_content_area().border_width = 0;