[geary/wip/20-cert-pinning: 33/36] Handle untrusted certs when adding a editing account server details



commit 817903555e12f5189aecc7fb0109c087c7c77645
Author: Michael Gratton <mike vee net>
Date:   Wed Jan 9 13:00:54 2019 +1100

    Handle untrusted certs when adding a editing account server details
    
    Move common code for prompting for cert errors to the account editor,
    use that when validating an account from the server pane.

 meson_options.txt                                  |  4 +-
 src/client/accounts/accounts-editor-add-pane.vala  | 29 ++++--------
 .../accounts/accounts-editor-servers-pane.vala     | 52 +++++++++++++++++++---
 src/client/accounts/accounts-editor.vala           | 35 +++++++++++++++
 4 files changed, 92 insertions(+), 28 deletions(-)
---
diff --git a/meson_options.txt b/meson_options.txt
index 234e979d..5fe1f799 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -1,6 +1,6 @@
-option('valadoc', type: 'boolean', value: false, description: 'Whether to build the documentaton (requires 
valadoc).')
+option('valadoc', type: 'boolean', value: true, description: 'Whether to build the documentaton (requires 
valadoc).')
 option('contractor', type: 'boolean', value: false, description: 'Whether to install the contractor file 
(Elementary OS-specific).')
 option('poodle', type: 'boolean', value: true, description: 'Whether to apply the POODLE SSLv3 fix.')
-option('ref_tracking', type: 'boolean', value: false, description: 'Whether to use explicit reference 
tracking.')
+option('ref_tracking', type: 'boolean', value: true, description: 'Whether to use explicit reference 
tracking.')
 option('iso_639_xml', type: 'string', value: '', description: 'Full path to the ISO 639 XML file.')
 option('iso_3166_xml', type: 'string', value: '', description: 'Full path to the ISO 3166 XML file.')
diff --git a/src/client/accounts/accounts-editor-add-pane.vala 
b/src/client/accounts/accounts-editor-add-pane.vala
index 5d9f54ae..75789bd1 100644
--- a/src/client/accounts/accounts-editor-add-pane.vala
+++ b/src/client/accounts/accounts-editor-add-pane.vala
@@ -232,7 +232,6 @@ internal class Accounts.EditorAddPane : Gtk.Grid, EditorPane {
                     // 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) {
@@ -261,6 +260,10 @@ internal class Accounts.EditorAddPane : Gtk.Grid, EditorPane {
                 to_focus = this.email.value;
                 // Translators: In-app notification label
                 message = _("Check your email address and password");
+            } catch (GLib.TlsError.BAD_CERTIFICATE err) {
+                // Nothing to do here, since the untrusted host
+                // handler will be dealing with it
+                debug("Error validating SMTP certifiate: %s", err.message);
             } catch (GLib.Error err) {
                 Geary.ErrorContext context = new Geary.ErrorContext(err);
                 debug("Error validating SMTP service: %s",
@@ -441,29 +444,15 @@ internal class Accounts.EditorAddPane : Gtk.Grid, EditorPane {
                                    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,
+        this.editor.prompt_pin_certificate.begin(
+            account, service, endpoint, 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) {
+                    this.editor.prompt_pin_certificate.end(res);
+                } catch (Application.CertificateManagerError 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")
-                        )
-                    );
+                    // window.
                     return;
-                } catch (Application.CertificateManagerError err) {
-                    debug("Unexptected error pinning cert: %s", err.message);
                 }
 
                 // Kick off another attempt to validate
diff --git a/src/client/accounts/accounts-editor-servers-pane.vala 
b/src/client/accounts/accounts-editor-servers-pane.vala
index 38a4b3c0..db6f2af9 100644
--- a/src/client/accounts/accounts-editor-servers-pane.vala
+++ b/src/client/accounts/accounts-editor-servers-pane.vala
@@ -281,22 +281,34 @@ internal class Accounts.EditorServersPane :
     }
 
     private async bool validate(GLib.Cancellable? cancellable) {
+        // Use a copy here so we can handle any prompting needed
+        // (auth, certs) directly, rather than through the main window
+        Geary.AccountInformation local_account =
+            new Geary.AccountInformation.copy(this.account);
+        local_account.untrusted_host.connect(on_untrusted_host);
+
         string? message = null;
         bool imap_valid = false;
         try {
             yield this.engine.validate_imap(
-                this.account, this.incoming_mutable, cancellable
+                local_account, this.incoming_mutable, cancellable
             );
             imap_valid = true;
         } catch (Geary.ImapError.UNAUTHENTICATED err) {
             debug("Error authenticating IMAP service: %s", err.message);
             // Translators: In-app notification label
             message = _("Check your receiving login and password");
+        } catch (GLib.TlsError.BAD_CERTIFICATE err) {
+            // Nothing to do here, since the untrusted host
+            // handler will be dealing with it
+            debug("Error validating IMAP certifiate: %s", err.message);
         } 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());
             // Translators: In-app notification label
             message = _("Check your receiving server details");
         }
@@ -306,7 +318,7 @@ internal class Accounts.EditorServersPane :
             debug("Validating SMTP...");
             try {
                 yield this.engine.validate_smtp(
-                    this.account,
+                    local_account,
                     this.outgoing_mutable,
                     this.incoming_mutable.credentials,
                     cancellable
@@ -320,16 +332,24 @@ internal class Accounts.EditorServersPane :
                 this.outgoing_auth.value.source = Geary.Credentials.Requirement.CUSTOM;
                 // Translators: In-app notification label
                 message = _("Check your sending login and password");
+            } catch (GLib.TlsError.BAD_CERTIFICATE err) {
+                // Nothing to do here, since the untrusted host
+                // handler will be dealing with it
+                debug("Error validating SMTP certifiate: %s", err.message);
             } 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);
-                    // Translators: In-app notification label
-                    message = _("Check your sending server details");
+                Geary.ErrorContext context = new Geary.ErrorContext(err);
+                debug("Error validating SMTP service: %s",
+                      context.format_full_error());
+                // Translators: In-app notification label
+                message = _("Check your sending server details");
             }
         }
 
+        local_account.untrusted_host.disconnect(on_untrusted_host);
+
         bool is_valid = imap_valid && smtp_valid;
         debug("Validation complete, is valid: %s", is_valid.to_string());
 
@@ -413,6 +433,26 @@ internal class Accounts.EditorServersPane :
         }
     }
 
+    private void on_untrusted_host(Geary.AccountInformation account,
+                                   Geary.ServiceInformation service,
+                                   Geary.Endpoint endpoint,
+                                   GLib.TlsConnection cx) {
+        this.editor.prompt_pin_certificate.begin(
+            account, service, endpoint, null,
+            (obj, res) => {
+                try {
+                    this.editor.prompt_pin_certificate.end(res);
+                } catch (Application.CertificateManagerError err) {
+                    // All good, just drop back into the editor
+                    // window.
+                    return;
+                }
+
+                // Kick off another attempt to save
+                this.save.begin(null);
+            });
+    }
+
     [GtkCallback]
     private void on_cancel_button_clicked() {
         if (this.is_operation_running) {
diff --git a/src/client/accounts/accounts-editor.vala b/src/client/accounts/accounts-editor.vala
index 1d1a8be6..24f3297f 100644
--- a/src/client/accounts/accounts-editor.vala
+++ b/src/client/accounts/accounts-editor.vala
@@ -175,6 +175,41 @@ public class Accounts.Editor : Gtk.Dialog {
         notification.show();
     }
 
+    /**
+     * Prompts for pinning a certificate using the certificate manager.
+     *
+     * This provides a thing wrapper around {@link
+     * CertificateManager.prompt_pin_certificate} that uses the
+     * account editor as the dialog parent.
+     */
+    internal async void prompt_pin_certificate(Geary.AccountInformation account,
+                                               Geary.ServiceInformation service,
+                                               Geary.Endpoint endpoint,
+                                               GLib.Cancellable? cancellable)
+        throws Application.CertificateManagerError {
+        try {
+            yield this.certificates.prompt_pin_certificate(
+                this, account, service, endpoint, true, cancellable
+            );
+        } catch (Application.CertificateManagerError.UNTRUSTED err) {
+            throw err;
+        } catch (Application.CertificateManagerError.STORE_FAILED err) {
+            // XXX show error info bar rather than a notification?
+            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")
+                )
+            );
+            throw err;
+        } catch (Application.CertificateManagerError err) {
+            debug("Unexpected error pinning cert: %s", err.message);
+            throw err;
+        }
+    }
+
     /** Removes an account from the editor. */
     internal void remove_account(Geary.AccountInformation account) {
         this.editor_panes.set_visible_child(this.editor_list_pane);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]