aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorfiaxh <git@mx.ax.lt>2018-01-04 21:13:44 +0100
committerfiaxh <git@mx.ax.lt>2018-01-04 21:17:56 +0100
commita8cc94c188c085e8788e072017ef21d7b7812a55 (patch)
treef537499e6106144a0b6dd756d25d4d6252f146fe
parent6b58b348fa42c3206f56c4b897a255d81f0ea7a9 (diff)
downloaddino-a8cc94c188c085e8788e072017ef21d7b7812a55.tar.gz
dino-a8cc94c188c085e8788e072017ef21d7b7812a55.zip
Show error on invalid TLS certificate
-rw-r--r--libdino/src/service/connection_manager.vala36
-rw-r--r--main/data/contact_details_dialog.ui1
-rw-r--r--main/data/manage_accounts/dialog.ui3
-rw-r--r--main/src/ui/manage_accounts/dialog.vala13
-rw-r--r--xmpp-vala/src/core/stanza_reader.vala8
-rw-r--r--xmpp-vala/src/core/stanza_writer.vala2
-rw-r--r--xmpp-vala/src/core/xmpp_stream.vala43
-rw-r--r--xmpp-vala/src/module/tls.vala4
8 files changed, 66 insertions, 44 deletions
diff --git a/libdino/src/service/connection_manager.vala b/libdino/src/service/connection_manager.vala
index 5fcd66a2..bd22191f 100644
--- a/libdino/src/service/connection_manager.vala
+++ b/libdino/src/service/connection_manager.vala
@@ -32,12 +32,20 @@ public class ConnectionManager {
public enum Source {
CONNECTION,
SASL,
+ TLS,
STREAM_ERROR
}
+ public enum Reconnect {
+ NOW,
+ LATER,
+ NEVER
+ }
+
public Source source;
public string? identifier;
- public StreamError.Flag? flag;
+ public Reconnect reconnect_recomendation { get; set; default=Reconnect.NOW; }
+ public bool resource_rejected = false;
public ConnectionError(Source source, string? identifier) {
this.source = source;
@@ -79,7 +87,8 @@ public class ConnectionManager {
}
Timeout.add_seconds(60, () => {
foreach (Account account in connection_todo) {
- if (connections[account].last_activity.compare(new DateTime.now_utc().add_minutes(-1)) < 0) {
+ if (connections[account].last_activity != null &&
+ connections[account].last_activity.compare(new DateTime.now_utc().add_minutes(-1)) < 0) {
check_reconnect(account);
}
}
@@ -164,7 +173,7 @@ public class ConnectionManager {
change_connection_state(account, ConnectionState.CONNECTED);
});
stream.get_module(PlainSasl.Module.IDENTITY).received_auth_failure.connect((stream, node) => {
- set_connection_error(account, ConnectionError.Source.SASL, null);
+ set_connection_error(account, new ConnectionError(ConnectionError.Source.SASL, null));
change_connection_state(account, ConnectionState.DISCONNECTED);
});
stream.received_node.connect(() => {
@@ -186,9 +195,13 @@ public class ConnectionManager {
connections.unset(account);
return;
}
+ if (e is Core.IOStreamError.TLS) {
+ set_connection_error(account, new ConnectionError(ConnectionError.Source.TLS, e.message) { reconnect_recomendation=ConnectionError.Reconnect.NEVER});
+ return;
+ }
StreamError.Flag? flag = stream.get_flag(StreamError.Flag.IDENTITY);
if (flag != null) {
- set_connection_error(account, ConnectionError.Source.STREAM_ERROR, flag.error_type);
+ set_connection_error(account, new ConnectionError(ConnectionError.Source.STREAM_ERROR, flag.error_type) { resource_rejected=flag.resource_rejected });
}
interpret_connection_error(account);
}
@@ -199,17 +212,17 @@ public class ConnectionManager {
int wait_sec = 5;
if (error == null) {
wait_sec = 3;
- } else if (error.source == ConnectionError.Source.STREAM_ERROR && error.flag != null) {
- if (error.flag.resource_rejected) {
+ } else if (error.source == ConnectionError.Source.STREAM_ERROR) {
+ if (error.resource_rejected) {
connect_(account, account.resourcepart + "-" + random_uuid());
return;
}
- switch (error.flag.reconnection_recomendation) {
- case StreamError.Flag.Reconnect.NOW:
+ switch (error.reconnect_recomendation) {
+ case ConnectionError.Reconnect.NOW:
wait_sec = 5; break;
- case StreamError.Flag.Reconnect.LATER:
+ case ConnectionError.Reconnect.LATER:
wait_sec = 60; break;
- case StreamError.Flag.Reconnect.NEVER:
+ case ConnectionError.Reconnect.NEVER:
return;
}
} else if (error.source == ConnectionError.Source.SASL) {
@@ -291,8 +304,7 @@ public class ConnectionManager {
}
}
- private void set_connection_error(Account account, ConnectionError.Source source, string? id) {
- ConnectionError error = new ConnectionError(source, id);
+ private void set_connection_error(Account account, ConnectionError error) {
connection_errors[account] = error;
connection_error(account, error);
}
diff --git a/main/data/contact_details_dialog.ui b/main/data/contact_details_dialog.ui
index 8fa62398..8ce7306d 100644
--- a/main/data/contact_details_dialog.ui
+++ b/main/data/contact_details_dialog.ui
@@ -77,6 +77,7 @@
<child>
<object class="GtkLabel" id="jid_label">
<property name="xalign">0</property>
+ <property name="yalign">0</property>
<property name="selectable">True</property>
<property name="expand">True</property>
<property name="visible">True</property>
diff --git a/main/data/manage_accounts/dialog.ui b/main/data/manage_accounts/dialog.ui
index 9235f613..2dc2762b 100644
--- a/main/data/manage_accounts/dialog.ui
+++ b/main/data/manage_accounts/dialog.ui
@@ -88,6 +88,7 @@
<child>
<object class="GtkBox">
<property name="visible">True</property>
+ <property name="halign">end</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
@@ -121,6 +122,7 @@
<child>
<object class="GtkLabel" id="jid_label">
<property name="xalign">0</property>
+ <property name="yalign">1</property>
<property name="visible">True</property>
<attributes>
<attribute name="weight" value="PANGO_WEIGHT_BOLD"/>
@@ -136,6 +138,7 @@
<child>
<object class="GtkLabel" id="state_label">
<property name="xalign">0</property>
+ <property name="yalign">0</property>
<property name="visible">True</property>
<style>
<class name="dim-label"/>
diff --git a/main/src/ui/manage_accounts/dialog.vala b/main/src/ui/manage_accounts/dialog.vala
index dd2383a2..b157a936 100644
--- a/main/src/ui/manage_accounts/dialog.vala
+++ b/main/src/ui/manage_accounts/dialog.vala
@@ -171,7 +171,7 @@ public class Dialog : Gtk.Dialog {
}
}
- private bool on_active_switch_state_changed(bool state) {
+ private bool change_account_state(bool state) {
selected_account.enabled = state;
if (state) {
if (selected_account.enabled) account_disabled(selected_account);
@@ -189,7 +189,7 @@ public class Dialog : Gtk.Dialog {
}
private void populate_grid_data(Account account) {
- active_switch.state_set.disconnect(on_active_switch_state_changed);
+ active_switch.state_set.disconnect(change_account_state);
Util.image_set_from_scaled_pixbuf(image, (new AvatarGenerator(50, 50, image.scale_factor)).draw_account(stream_interactor, account));
active_switch.set_active(account.enabled);
@@ -201,7 +201,7 @@ public class Dialog : Gtk.Dialog {
update_status_label(account);
- active_switch.state_set.connect(on_active_switch_state_changed);
+ active_switch.state_set.connect(change_account_state);
foreach(Plugins.AccountSettingsWidget widget in plugin_widgets) {
widget.set_account(account);
@@ -216,8 +216,11 @@ public class Dialog : Gtk.Dialog {
state_label.get_style_context().add_class("is_error");
if (error.source == ConnectionManager.ConnectionError.Source.SASL ||
- (error.flag != null && error.flag.reconnection_recomendation == Xmpp.StreamError.Flag.Reconnect.NEVER)) {
+ error.source == ConnectionManager.ConnectionError.Source.TLS ||
+ error.reconnect_recomendation == ConnectionManager.ConnectionError.Reconnect.NEVER) {
+ active_switch.state_set.disconnect(change_account_state);
active_switch.active = false;
+ active_switch.state_set.connect(change_account_state);
}
} else {
@@ -238,6 +241,8 @@ public class Dialog : Gtk.Dialog {
switch (error.source) {
case ConnectionManager.ConnectionError.Source.SASL:
return _("Wrong password");
+ case ConnectionManager.ConnectionError.Source.TLS:
+ return _("Invalid TLS certificate");
}
if (error.identifier != null) {
return _("Error") + ": " + error.identifier;
diff --git a/xmpp-vala/src/core/stanza_reader.vala b/xmpp-vala/src/core/stanza_reader.vala
index 4b4d98ab..6a7520ba 100644
--- a/xmpp-vala/src/core/stanza_reader.vala
+++ b/xmpp-vala/src/core/stanza_reader.vala
@@ -7,12 +7,12 @@ public const string XML_URI = "http://www.w3.org/XML/1998/namespace";
public const string JABBER_URI = "jabber:client";
public errordomain XmlError {
- XML_ERROR,
NS_DICT_ERROR,
UNSUPPORTED,
EOF,
BAD_XML,
- IO_ERROR
+ IO,
+ TLS
}
public class StanzaReader {
@@ -52,8 +52,10 @@ public class StanzaReader {
buffer_fill = (int) yield ((!)input).read_async(buffer, GLib.Priority.DEFAULT, cancellable);
if (buffer_fill == 0) throw new XmlError.EOF("End of input stream reached.");
buffer_pos = 0;
+ } catch (TlsError e) {
+ throw new XmlError.TLS("TlsError: %s".printf(e.message));
} catch (GLib.IOError e) {
- throw new XmlError.IO_ERROR("IOError in GLib: %s".printf(e.message));
+ throw new XmlError.IO("GLib.IOError: %s".printf(e.message));
}
}
diff --git a/xmpp-vala/src/core/stanza_writer.vala b/xmpp-vala/src/core/stanza_writer.vala
index 270d898d..62c870de 100644
--- a/xmpp-vala/src/core/stanza_writer.vala
+++ b/xmpp-vala/src/core/stanza_writer.vala
@@ -30,7 +30,7 @@ public class StanzaWriter {
sfw.sfun();
}
} catch (GLib.Error e) {
- throw new XmlError.IO_ERROR(@"IOError in GLib: $(e.message)");
+ throw new XmlError.IO(@"IOError in GLib: $(e.message)");
} finally {
running = false;
}
diff --git a/xmpp-vala/src/core/xmpp_stream.vala b/xmpp-vala/src/core/xmpp_stream.vala
index ea186a72..6d4b9c64 100644
--- a/xmpp-vala/src/core/xmpp_stream.vala
+++ b/xmpp-vala/src/core/xmpp_stream.vala
@@ -6,8 +6,8 @@ public errordomain IOStreamError {
READ,
WRITE,
CONNECT,
- DISCONNECT
-
+ DISCONNECT,
+ TLS
}
public class XmppStream {
@@ -58,10 +58,13 @@ public class XmppStream {
IOStream? stream = null;
if (best_provider != null) {
stream = yield best_provider.connect(this);
- } else {
+ }
+ if (stream != null) {
stream = yield (new SocketClient()).connect_async(new NetworkService("xmpp-client", "tcp", this.remote_name));
}
- if (stream == null) throw new IOStreamError.CONNECT("client.connect() returned null");
+ if (stream == null) {
+ throw new IOStreamError.CONNECT("client.connect() returned null");
+ }
reset_stream((!)stream);
} catch (Error e) {
stderr.printf("CONNECTION LOST?\n");
@@ -154,7 +157,10 @@ public class XmppStream {
}
public void detach_modules() {
- foreach (XmppStreamModule module in modules) module.detach(this);
+ foreach (XmppStreamModule module in modules) {
+ if (!(module is XmppStreamNegotiationModule) && !negotiation_complete) continue;
+ module.detach(this);
+ }
}
public T? get_module<T>(ModuleIdentity<T>? identity) {
@@ -238,23 +244,18 @@ public class XmppStream {
}
private bool negotiation_modules_done() throws IOStreamError {
- if (!setup_needed) {
- bool mandatory_outstanding = false;
- foreach (XmppStreamModule module in modules) {
- if (module is XmppStreamNegotiationModule) {
- XmppStreamNegotiationModule negotiation_module = (XmppStreamNegotiationModule) module;
- if (negotiation_module.mandatory_outstanding(this)) mandatory_outstanding = true;
- }
- }
- if (!is_negotiation_active()) {
- if (mandatory_outstanding) {
- throw new IOStreamError.CONNECT("mandatory-to-negotiate feature not negotiated");
- } else {
- return true;
+ if (setup_needed) return false;
+ if (is_negotiation_active()) return false;
+
+ foreach (XmppStreamModule module in modules) {
+ if (module is XmppStreamNegotiationModule) {
+ XmppStreamNegotiationModule negotiation_module = (XmppStreamNegotiationModule) module;
+ if (negotiation_module.mandatory_outstanding(this)) {
+ throw new IOStreamError.CONNECT("mandatory-to-negotiate feature not negotiated: " + negotiation_module.get_id());
}
}
}
- return false;
+ return true;
}
private void attach_non_negotation_modules() {
@@ -281,7 +282,9 @@ public class XmppStream {
StanzaNode node = yield ((!)reader).read_root_node();
log.node("IN ROOT", node);
return node;
- } catch (XmlError e) {
+ } catch (XmlError.TLS e) {
+ throw new IOStreamError.TLS(e.message);
+ } catch (Error e) {
throw new IOStreamError.READ(e.message);
}
}
diff --git a/xmpp-vala/src/module/tls.vala b/xmpp-vala/src/module/tls.vala
index dcd7ab40..5defc72c 100644
--- a/xmpp-vala/src/module/tls.vala
+++ b/xmpp-vala/src/module/tls.vala
@@ -27,10 +27,6 @@ namespace Xmpp.Tls {
var io_stream = stream.get_stream();
if (io_stream == null) return;
var conn = TlsClientConnection.new(io_stream, identity);
- // TODO: Add certificate error handling, that is, allow the
- // program to handle certificate errors. The certificate
- // *is checked* by TlsClientConnection, and connection is
- // not allowed to continue in case that there is an error.
stream.reset_stream(conn);
var flag = stream.get_flag(Flag.IDENTITY);