[geary/wip/713247-tls] Refinements.



commit 1bb55d48f2385ef57d18a2999b8c585eab2e7fdb
Author: Jim Nelson <jim yorba org>
Date:   Wed Aug 27 12:28:47 2014 -0700

    Refinements.

 src/client/application/geary-controller.vala  |   41 ++++++++++++++++---------
 src/engine/api/geary-account-information.vala |   27 +++++++++++-----
 src/engine/api/geary-endpoint.vala            |   40 ++++++++++++++++++++----
 src/engine/api/geary-engine.vala              |   21 ++++++++----
 ui/certificate_warning_dialog.glade           |   32 ++++++++++++++-----
 5 files changed, 115 insertions(+), 46 deletions(-)
---
diff --git a/src/client/application/geary-controller.vala b/src/client/application/geary-controller.vala
index 30d205c..cb19076 100644
--- a/src/client/application/geary-controller.vala
+++ b/src/client/application/geary-controller.vala
@@ -111,6 +111,7 @@ public class GearyController : Geary.BaseObject {
     private LoginDialog? login_dialog = null;
     private UpgradeDialog upgrade_dialog;
     private Gee.List<string> pending_mailtos = new Gee.ArrayList<string>();
+    private Geary.Nonblocking.Mutex untrusted_host_prompt_mutex = new Geary.Nonblocking.Mutex();
     
     // List of windows we're waiting to close before Geary closes.
     private Gee.List<ComposerWidget> waiting_to_close = new Gee.ArrayList<ComposerWidget>();
@@ -177,7 +178,7 @@ public class GearyController : Geary.BaseObject {
         
         Geary.Engine.instance.account_available.connect(on_account_available);
         Geary.Engine.instance.account_unavailable.connect(on_account_unavailable);
-        Geary.Engine.instance.tls_warnings_detected.connect(on_tls_warnings_detected);
+        Geary.Engine.instance.untrusted_host.connect(on_untrusted_host);
         
         // Connect to various UI signals.
         main_window.conversation_list_view.conversations_selected.connect(on_conversations_selected);
@@ -500,49 +501,59 @@ public class GearyController : Geary.BaseObject {
         close_account(get_account_instance(account_information));
     }
     
-    private void on_tls_warnings_detected(Geary.AccountInformation account_information,
+    private void on_untrusted_host(Geary.AccountInformation account_information,
         Geary.Endpoint endpoint, Geary.Endpoint.SecurityType security, TlsConnection cx,
         Geary.Service service, TlsCertificateFlags warnings) {
-        prompt_tls_warning_async.begin(account_information, endpoint, security, cx, service, warnings);
+        prompt_untrusted_host_async.begin(account_information, endpoint, security, cx, service, warnings);
     }
     
-    private Geary.Nonblocking.Mutex tls_prompt_mutex = new Geary.Nonblocking.Mutex();
-    
-    private async void prompt_tls_warning_async(Geary.AccountInformation account_information,
+    private async void prompt_untrusted_host_async(Geary.AccountInformation account_information,
         Geary.Endpoint endpoint, Geary.Endpoint.SecurityType security, TlsConnection cx,
         Geary.Service service, TlsCertificateFlags warnings) {
+        int token = Geary.Nonblocking.Mutex.INVALID_TOKEN;
         try {
-            int token = yield tls_prompt_mutex.claim_async();
+            // use a mutex to prevent multiple dialogs popping up at the same time
+            token = yield untrusted_host_prompt_mutex.claim_async();
             
-            // possible while waiting on mutex that this endpoint became trusted
-            if (endpoint.trust_host)
+            // possible while waiting on mutex that this endpoint became trusted or untrusted
+            if (endpoint.trust_untrusted_host != Geary.Trillian.UNKNOWN)
                 return;
             
             CertificateWarningDialog dialog = new CertificateWarningDialog(main_window, endpoint,
                 warnings);
             switch (dialog.run()) {
                 case CertificateWarningDialog.Result.TRUST:
-                    endpoint.trust_host = true;
+                    endpoint.trust_untrusted_host = Geary.Trillian.TRUE;
                 break;
                 
                 case CertificateWarningDialog.Result.ALWAYS_TRUST:
-                    endpoint.trust_host = true;
+                    endpoint.trust_untrusted_host = Geary.Trillian.TRUE;
                     // TODO: Pin certificate
                 break;
                 
                 default:
+                    endpoint.trust_untrusted_host = Geary.Trillian.FALSE;
+                    
                     try {
-                        Geary.Account account = 
Geary.Engine.instance.get_account_instance(account_information);
-                        close_account(account);
+                        if (Geary.Engine.instance.get_accounts().has_key(account_information.email)) {
+                            Geary.Account account = 
Geary.Engine.instance.get_account_instance(account_information);
+                            close_account(account);
+                        }
                     } catch (Error err) {
                         message("Unable to close account due to user trust issues: %s", err.message);
                     }
                 break;
             }
-            
-            tls_prompt_mutex.release(ref token);
         } catch (Error err) {
             warning("Unable to prompt for certificate security warning: %s", err.message);
+        } finally {
+            if (token != Geary.Nonblocking.Mutex.INVALID_TOKEN) {
+                try {
+                    untrusted_host_prompt_mutex.release(ref token);
+                } catch (Error err) {
+                    debug("Unable to release mutex: %s", err.message);
+                }
+            }
         }
     }
     
diff --git a/src/engine/api/geary-account-information.vala b/src/engine/api/geary-account-information.vala
index 50bf1e7..9901f60 100644
--- a/src/engine/api/geary-account-information.vala
+++ b/src/engine/api/geary-account-information.vala
@@ -108,7 +108,16 @@ public class Geary.AccountInformation : BaseObject {
     private Endpoint? imap_endpoint = null;
     private Endpoint? smtp_endpoint = null;
     
-    public signal void tls_warnings_detected(Endpoint endpoint, Endpoint.SecurityType security,
+    /**
+     * Indicates the supplied { link Endpoint} has reported TLS certificate warnings during
+     * connection.
+     *
+     * Since this { link Endpoint} persists for the lifetime of the { link AccountInformation},
+     * marking it as trusted once will survive the application session.  It is up to the caller to
+     * pin the certificate appropriately if the user does not want to receive these warnings in
+     * the future.
+     */
+    public signal void untrusted_host(Endpoint endpoint, Endpoint.SecurityType security,
         TlsConnection cx, Service service, TlsCertificateFlags warnings);
     
     // Used to create temporary AccountInformation objects.  (Note that these cannot be saved.)
@@ -186,10 +195,10 @@ public class Geary.AccountInformation : BaseObject {
     
     ~AccountInformation() {
         if (imap_endpoint != null)
-            imap_endpoint.tls_warnings_detected.disconnect(on_imap_tls_warnings_detected);
+            imap_endpoint.untrusted_host.disconnect(on_imap_untrusted_host);
         
         if (smtp_endpoint != null)
-            smtp_endpoint.tls_warnings_detected.disconnect(on_smtp_tls_warnings_detected);
+            smtp_endpoint.untrusted_host.disconnect(on_smtp_untrusted_host);
     }
     
     // Copies all data from the "from" object into this one.
@@ -485,14 +494,14 @@ public class Geary.AccountInformation : BaseObject {
                 assert_not_reached();
         }
         
-        imap_endpoint.tls_warnings_detected.connect(on_imap_tls_warnings_detected);
+        imap_endpoint.untrusted_host.connect(on_imap_untrusted_host);
         
         return imap_endpoint;
     }
     
-    private void on_imap_tls_warnings_detected(Endpoint endpoint, Endpoint.SecurityType security,
+    private void on_imap_untrusted_host(Endpoint endpoint, Endpoint.SecurityType security,
         TlsConnection cx, TlsCertificateFlags warnings) {
-        tls_warnings_detected(endpoint, security, cx, Service.IMAP, warnings);
+        untrusted_host(endpoint, security, cx, Service.IMAP, warnings);
     }
     
     public Endpoint get_smtp_endpoint() {
@@ -527,14 +536,14 @@ public class Geary.AccountInformation : BaseObject {
                 assert_not_reached();
         }
         
-        smtp_endpoint.tls_warnings_detected.connect(on_smtp_tls_warnings_detected);
+        smtp_endpoint.untrusted_host.connect(on_smtp_untrusted_host);
         
         return smtp_endpoint;
     }
     
-    private void on_smtp_tls_warnings_detected(Endpoint endpoint, Endpoint.SecurityType security,
+    private void on_smtp_untrusted_host(Endpoint endpoint, Endpoint.SecurityType security,
         TlsConnection cx, TlsCertificateFlags warnings) {
-        tls_warnings_detected(endpoint, security, cx, Service.SMTP, warnings);
+        untrusted_host(endpoint, security, cx, Service.SMTP, warnings);
     }
     
     private Geary.FolderPath? build_folder_path(Gee.List<string>? parts) {
diff --git a/src/engine/api/geary-endpoint.vala b/src/engine/api/geary-endpoint.vala
index 876e1fd..1fc8ffa 100644
--- a/src/engine/api/geary-endpoint.vala
+++ b/src/engine/api/geary-endpoint.vala
@@ -42,9 +42,27 @@ public class Geary.Endpoint : BaseObject {
     public Flags flags { get; private set; }
     public uint timeout_sec { get; private set; }
     public TlsCertificateFlags tls_validation_flags { get; set; default = TlsCertificateFlags.VALIDATE_ALL; }
-    public TlsCertificateFlags tls_validation_warnings { get; private set; default = 0; }
     public bool force_ssl3 { get; set; default = false; }
-    public bool trust_host { get; set; default = false; }
+    
+    /**
+     * When set, TLS has reported certificate issues.
+     *
+     * @see trust_untrusted_host
+     * @see untrusted_host
+     */
+    public TlsCertificateFlags tls_validation_warnings { get; private set; default = 0; }
+    
+    /**
+     * When set, indicates the user has acceded to trusting the host even though TLS has reported
+     * certificate issues.
+     *
+     * Initialized to { link Trillian.UNKNOWN}, meaning the user must decide when warnings are
+     * detected.
+     *
+     * @see untrusted_host
+     * @see tls_validation_warnings
+     */
+    public Trillian trust_untrusted_host { get; set; default = Trillian.UNKNOWN; }
     
     public bool is_ssl { get {
         return flags.is_all_set(Flags.SSL);
@@ -56,7 +74,15 @@ public class Geary.Endpoint : BaseObject {
     
     private SocketClient? socket_client = null;
     
-    public signal void tls_warnings_detected(SecurityType security, TlsConnection cx,
+    /**
+     * Fired when TLS certificate warnings are detected and the caller has not marked this
+     * { link Endpoint} as trusted via { link trust_untrusted_host}.
+     *
+     * The connection will be closed when this is fired.  The caller should query the user about
+     * how to deal with the situation.  If user wants to proceed, set { link trust_untrusted_host}
+     * to { link Trillian.TRUE} and retry connection.
+     */
+    public signal void untrusted_host(SecurityType security, TlsConnection cx,
         TlsCertificateFlags tls_warnings);
     
     public Endpoint(string host_specifier, uint16 default_port, Flags flags, uint timeout_sec) {
@@ -118,8 +144,6 @@ public class Geary.Endpoint : BaseObject {
             tls_cx.accept_certificate.connect(on_accept_starttls_certificate);
         else
             tls_cx.accept_certificate.connect(on_accept_ssl_certificate);
-        
-        tls_warnings_detected(SecurityType.SSL, tls_cx, TlsCertificateFlags.UNKNOWN_CA);
     }
     
     private bool on_accept_starttls_certificate(TlsConnection cx, TlsCertificate cert, TlsCertificateFlags 
flags) {
@@ -138,10 +162,12 @@ public class Geary.Endpoint : BaseObject {
         
         tls_validation_warnings = warnings;
         
-        if (trust_host)
+        // if user has marked this untrusted host as trusted already, accept warnings and move on
+        if (trust_untrusted_host == Trillian.TRUE)
             return true;
         
-        tls_warnings_detected(security, cx, warnings);
+        // signal an issue has been detected and return false to deny the connection
+        untrusted_host(security, cx, warnings);
         
         return false;
     }
diff --git a/src/engine/api/geary-engine.vala b/src/engine/api/geary-engine.vala
index 006c692..3fbe839 100644
--- a/src/engine/api/geary-engine.vala
+++ b/src/engine/api/geary-engine.vala
@@ -81,7 +81,14 @@ public class Geary.Engine : BaseObject {
      */
     public signal void account_removed(AccountInformation account);
     
-    public signal void tls_warnings_detected(Geary.AccountInformation account_information,
+    /**
+     * Fired when an { link Endpoint} associated with the { link AccountInformation} reports
+     * TLS certificate warnings during connection.
+     *
+     * This may be fired during normal operation or while validating the AccountInformation, in
+     * which case there is no { link Account} associated with it.
+     */
+    public signal void untrusted_host(Geary.AccountInformation account_information,
         Endpoint endpoint, Endpoint.SecurityType security, TlsConnection cx, Service service,
         TlsCertificateFlags warnings);
     
@@ -243,7 +250,7 @@ public class Geary.Engine : BaseObject {
         if (!options.is_all_set(ValidationOption.CHECK_CONNECTIONS))
             return error_code;
         
-        account.tls_warnings_detected.connect(on_tls_warnings_detected);
+        account.untrusted_host.connect(on_untrusted_host);
         
         // validate IMAP, which requires logging in and establishing an AUTHORIZED cx state
         Geary.Imap.ClientSession? imap_session = new Imap.ClientSession(account.get_imap_endpoint());
@@ -299,7 +306,7 @@ public class Geary.Engine : BaseObject {
             smtp_session = null;
         }
         
-        account.tls_warnings_detected.disconnect(on_tls_warnings_detected);
+        account.untrusted_host.disconnect(on_untrusted_host);
         
         return error_code;
     }
@@ -360,7 +367,7 @@ public class Geary.Engine : BaseObject {
         accounts.set(account.email, account);
 
         if (!already_added) {
-            account.tls_warnings_detected.connect(on_tls_warnings_detected);
+            account.untrusted_host.connect(on_untrusted_host);
             
             if (created)
                 account_added(account);
@@ -383,7 +390,7 @@ public class Geary.Engine : BaseObject {
         }
         
         if (accounts.unset(account.email)) {
-            account.tls_warnings_detected.disconnect(on_tls_warnings_detected);
+            account.untrusted_host.disconnect(on_untrusted_host);
             
             // Removal *MUST* be done in the following order:
             // 1. Send the account-unavailable signal.
@@ -400,9 +407,9 @@ public class Geary.Engine : BaseObject {
         }
     }
     
-    private void on_tls_warnings_detected(AccountInformation account_information, Endpoint endpoint,
+    private void on_untrusted_host(AccountInformation account_information, Endpoint endpoint,
         Endpoint.SecurityType security, TlsConnection cx, Service service, TlsCertificateFlags warnings) {
-        tls_warnings_detected(account_information, endpoint, security, cx, service, warnings);
+        untrusted_host(account_information, endpoint, security, cx, service, warnings);
     }
 }
 
diff --git a/ui/certificate_warning_dialog.glade b/ui/certificate_warning_dialog.glade
index 317b000..29e1bcf 100644
--- a/ui/certificate_warning_dialog.glade
+++ b/ui/certificate_warning_dialog.glade
@@ -4,7 +4,7 @@
   <requires lib="gtk+" version="3.10"/>
   <object class="GtkDialog" id="CertificateWarningDialog">
     <property name="can_focus">False</property>
-    <property name="title" translatable="yes">Certificate Security Warning</property>
+    <property name="title" translatable="yes">Untrusted Connection</property>
     <property name="modal">True</property>
     <property name="destroy_with_parent">True</property>
     <property name="type_hint">dialog</property>
@@ -12,10 +12,10 @@
     <child internal-child="vbox">
       <object class="GtkBox" id="dialog-vbox1">
         <property name="can_focus">False</property>
-        <property name="margin_left">8</property>
-        <property name="margin_right">8</property>
-        <property name="margin_top">8</property>
-        <property name="margin_bottom">8</property>
+        <property name="margin_left">12</property>
+        <property name="margin_right">12</property>
+        <property name="margin_top">12</property>
+        <property name="margin_bottom">12</property>
         <property name="orientation">vertical</property>
         <property name="spacing">2</property>
         <child internal-child="action_area">
@@ -79,7 +79,7 @@
             <property name="visible">True</property>
             <property name="can_focus">False</property>
             <property name="orientation">vertical</property>
-            <property name="spacing">4</property>
+            <property name="spacing">8</property>
             <child>
               <object class="GtkBox" id="box2">
                 <property name="visible">True</property>
@@ -152,12 +152,13 @@
               </packing>
             </child>
             <child>
-              <object class="GtkLabel" id="label2">
+              <object class="GtkLabel" id="dont_trust_label">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
                 <property name="valign">end</property>
                 <property name="xalign">0</property>
-                <property name="label" translatable="yes">Selecting "Don't Trust This Host" will cause Geary 
to exit.</property>
+                <property name="label" translatable="yes">Selecting "Don't Trust This Host" will cause Geary 
to exit if you have no other registered email accounts.</property>
+                <property name="wrap">True</property>
                 <attributes>
                   <attribute name="weight" value="bold"/>
                 </attributes>
@@ -169,6 +170,21 @@
                 <property name="position">3</property>
               </packing>
             </child>
+            <child>
+              <object class="GtkLabel" id="bottom_label">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">Contact your system administrator or email service 
provider if you have any question about these issues.</property>
+                <property name="wrap">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="pack_type">end</property>
+                <property name="position">4</property>
+              </packing>
+            </child>
           </object>
           <packing>
             <property name="expand">True</property>


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