From b29d52fddae832d275e66dbd1b494e06ce11d0da Mon Sep 17 00:00:00 2001 From: fiaxh Date: Wed, 9 Aug 2017 20:44:15 +0200 Subject: [PATCH] SRV records for XMPP over TLS --- libdino/src/entity/conversation.vala | 12 ++-- libdino/src/service/module_manager.vala | 1 + main/src/ui/unified_window.vala | 4 +- .../src/contact_titlebar_entry.vala | 9 ++- xmpp-vala/CMakeLists.txt | 1 + xmpp-vala/src/core/xmpp_stream.vala | 56 +++++++++++++++++-- xmpp-vala/src/module/tls.vala | 2 +- .../src/module/xep/0333_chat_markers.vala | 2 +- .../src/module/xep/0368_srv_records_tls.vala | 53 ++++++++++++++++++ 9 files changed, 124 insertions(+), 16 deletions(-) create mode 100644 xmpp-vala/src/module/xep/0368_srv_records_tls.vala diff --git a/libdino/src/entity/conversation.vala b/libdino/src/entity/conversation.vala index 40bff1c2..fa78c619 100644 --- a/libdino/src/entity/conversation.vala +++ b/libdino/src/entity/conversation.vala @@ -73,17 +73,19 @@ public class Conversation : Object { .value(db.conversation.jid_id, db.get_jid_id(counterpart)) .value(db.conversation.type_, type_) .value(db.conversation.encryption, encryption) - .value(db.conversation.read_up_to, read_up_to.id) - .value(db.conversation.active, active); + .value(db.conversation.active, active) + .value(db.conversation.notification, notify_setting) + .value(db.conversation.send_typing, send_typing) + .value(db.conversation.send_marker, send_marker); + if (read_up_to != null) { + insert.value(db.conversation.read_up_to, read_up_to.id); + } if (counterpart.is_full()) { insert.value(db.conversation.resource, counterpart.resourcepart); } if (last_active != null) { insert.value(db.conversation.last_active, (long) last_active.to_unix()); } - insert.value(db.conversation.notification, notify_setting); - insert.value(db.conversation.send_typing, send_typing); - insert.value(db.conversation.send_marker, send_marker); id = (int) insert.perform(); notify.connect(on_update); } diff --git a/libdino/src/service/module_manager.vala b/libdino/src/service/module_manager.vala index 9f2a05d0..b10765f1 100644 --- a/libdino/src/service/module_manager.vala +++ b/libdino/src/service/module_manager.vala @@ -46,6 +46,7 @@ public class ModuleManager { lock(module_map) { module_map[account] = new ArrayList(); module_map[account].add(new Tls.Module()); + module_map[account].add(new Xep.SrvRecordsTls.Module()); module_map[account].add(new Session.Module()); module_map[account].add(new Roster.Module()); module_map[account].add(new Xep.ServiceDiscovery.Module.with_identity("client", "pc")); diff --git a/main/src/ui/unified_window.vala b/main/src/ui/unified_window.vala index c0bf0487..c0a74731 100644 --- a/main/src/ui/unified_window.vala +++ b/main/src/ui/unified_window.vala @@ -145,7 +145,7 @@ public class NoAccountsPlaceholder : UnifiedWindowPlaceholder { public class NoConversationsPlaceholder : UnifiedWindowPlaceholder { public NoConversationsPlaceholder() { label.label = _("No conversation active"); - primary_button.label = _("Add Chat"); + primary_button.label = _("Start Chat"); secondary_button.label = _("Join Conference"); secondary_button.visible = true; } @@ -158,4 +158,4 @@ public class UnifiedWindowPlaceholder : Box { [GtkChild] public Button secondary_button; } -} \ No newline at end of file +} diff --git a/plugins/http-files/src/contact_titlebar_entry.vala b/plugins/http-files/src/contact_titlebar_entry.vala index a87c7ddf..74966c0e 100644 --- a/plugins/http-files/src/contact_titlebar_entry.vala +++ b/plugins/http-files/src/contact_titlebar_entry.vala @@ -54,9 +54,12 @@ public class ConversationTitlebarWidget : Button, Plugins.ConversationTitlebarWi } public void on_upload_available(Account account) { - if (conversation.account.equals(account)) { - visible = true; - } + Idle.add(() => { + if (conversation != null && conversation.account.equals(account)) { + visible = true; + } + return false; + }); } public new void set_conversation(Conversation conversation) { diff --git a/xmpp-vala/CMakeLists.txt b/xmpp-vala/CMakeLists.txt index 54bd3886..779540cc 100644 --- a/xmpp-vala/CMakeLists.txt +++ b/xmpp-vala/CMakeLists.txt @@ -60,6 +60,7 @@ SOURCES "src/module/xep/0203_delayed_delivery.vala" "src/module/xep/0280_message_carbons.vala" "src/module/xep/0333_chat_markers.vala" + "src/module/xep/0368_srv_records_tls.vala" "src/module/xep/pixbuf_storage.vala" PACKAGES ${ENGINE_PACKAGES} diff --git a/xmpp-vala/src/core/xmpp_stream.vala b/xmpp-vala/src/core/xmpp_stream.vala index 715e7832..eb6ffaa5 100644 --- a/xmpp-vala/src/core/xmpp_stream.vala +++ b/xmpp-vala/src/core/xmpp_stream.vala @@ -21,8 +21,9 @@ public class XmppStream { private StanzaReader? reader; private StanzaWriter? writer; - private ArrayList flags = new ArrayList(); - private ArrayList modules = new ArrayList(); + private Gee.List flags = new ArrayList(); + private Gee.List modules = new ArrayList(); + private Gee.List connection_providers = new ArrayList(); private bool setup_needed = false; private bool negotiation_complete = false; @@ -35,11 +36,24 @@ public class XmppStream { public signal void received_nonza(XmppStream stream, StanzaNode node); public signal void stream_negotiated(XmppStream stream); + public XmppStream() { + register_connection_provider(new StartTlsConnectionProvider()); + } + public void connect(string? remote_name = null) throws IOStreamError { if (remote_name != null) this.remote_name = (!)remote_name; - SocketClient client = new SocketClient(); try { - SocketConnection? stream = client.connect(new NetworkService("xmpp-client", "tcp", this.remote_name)); + int min_priority = -1; + ConnectionProvider? best_provider = null; + foreach (ConnectionProvider connection_provider in connection_providers) { + int? priority = connection_provider.get_priority(remote_name); + if (priority != null && (priority < min_priority || min_priority == -1)) { + min_priority = priority; + best_provider = connection_provider; + } + } + if (best_provider == null) throw new IOStreamError.CONNECT("no suitable connection provider"); + IOStream? stream = best_provider.connect(this); if (stream == null) throw new IOStreamError.CONNECT("client.connect() returned null"); reset_stream((!)stream); } catch (Error e) { @@ -142,6 +156,10 @@ public class XmppStream { return null; } + public void register_connection_provider(ConnectionProvider connection_provider) { + connection_providers.add(connection_provider); + } + private void setup() throws IOStreamError { StanzaNode outs = new StanzaNode.build("stream", "http://etherx.jabber.org/streams") .put_attribute("to", remote_name) @@ -294,4 +312,34 @@ public abstract class XmppStreamNegotiationModule : XmppStreamModule { public abstract bool negotiation_active(XmppStream stream); } +public abstract class ConnectionProvider { + public abstract int? get_priority(string remote_name); + public abstract IOStream? connect(XmppStream stream); + public abstract string get_id(); +} + +public class StartTlsConnectionProvider : ConnectionProvider { + private SrvTarget? srv_target; + + public override int? get_priority(string remote_name) { + GLib.List? xmpp_target = null; + try { + Resolver resolver = Resolver.get_default(); + xmpp_target = resolver.lookup_service("xmpp-client", "tcp", remote_name, null); + } catch (Error e) { + return null; + } + xmpp_target.sort((a, b) => { return a.get_priority() - b.get_priority(); }); + srv_target = xmpp_target.nth(0).data; + return xmpp_target.nth(0).data.get_priority(); + } + + public override IOStream? connect(XmppStream stream) { + SocketClient client = new SocketClient(); + return client.connect_to_host(srv_target.get_hostname(), srv_target.get_port()); + } + + public override string get_id() { return "start_tls"; } +} + } diff --git a/xmpp-vala/src/module/tls.vala b/xmpp-vala/src/module/tls.vala index 8cc7ad16..dd4fd82d 100644 --- a/xmpp-vala/src/module/tls.vala +++ b/xmpp-vala/src/module/tls.vala @@ -81,7 +81,7 @@ namespace Xmpp.Tls { public class Flag : XmppStreamFlag { public static FlagIdentity IDENTITY = new FlagIdentity(NS_URI, "tls"); public TlsCertificate? peer_certificate; - public bool finished = false; + public bool finished { get; set; default=false; } public override string get_ns() { return NS_URI; } public override string get_id() { return IDENTITY.id; } diff --git a/xmpp-vala/src/module/xep/0333_chat_markers.vala b/xmpp-vala/src/module/xep/0333_chat_markers.vala index 11817a22..9c1b9c74 100644 --- a/xmpp-vala/src/module/xep/0333_chat_markers.vala +++ b/xmpp-vala/src/module/xep/0333_chat_markers.vala @@ -45,7 +45,7 @@ public class Module : XmppStreamModule { } public static void require(XmppStream stream) { - if (stream.get_module(IDENTITY) == null) stream.add_module(new ChatMarkers.Module()); + if (stream.get_module(IDENTITY) == null) stream.add_module(new Module()); } public override string get_ns() { return NS_URI; } diff --git a/xmpp-vala/src/module/xep/0368_srv_records_tls.vala b/xmpp-vala/src/module/xep/0368_srv_records_tls.vala new file mode 100644 index 00000000..da70b513 --- /dev/null +++ b/xmpp-vala/src/module/xep/0368_srv_records_tls.vala @@ -0,0 +1,53 @@ +using Gee; + +using Xmpp.Core; + +namespace Xmpp.Xep.SrvRecordsTls { + +public class Module : XmppStreamNegotiationModule { + public static ModuleIdentity IDENTITY = new ModuleIdentity("", "0363_srv_records_for_xmpp_over_tls"); + + public override void attach(XmppStream stream) { + stream.register_connection_provider(new TlsConnectionProvider()); + } + + public override void detach(XmppStream stream) { } + + public static void require(XmppStream stream) { + if (stream.get_module(IDENTITY) == null) stream.add_module(new Module()); + } + + public override bool mandatory_outstanding(XmppStream stream) { return false; } + public override bool negotiation_active(XmppStream stream) { return false; } + public override string get_ns() { return IDENTITY.ns; } + public override string get_id() { return IDENTITY.id; } +} + +public class TlsConnectionProvider : ConnectionProvider { + private SrvTarget? srv_target; + + public override int? get_priority(string remote_name) { + GLib.List? xmpp_target = null; + try { + Resolver resolver = Resolver.get_default(); + xmpp_target = resolver.lookup_service("xmpps-client", "tcp", remote_name, null); + } catch (Error e) { + return null; + } + xmpp_target.sort((a, b) => { return a.get_priority() - b.get_priority(); }); + srv_target = xmpp_target.nth(0).data; + return xmpp_target.nth(0).data.get_priority(); + } + + public override IOStream? connect(XmppStream stream) { + SocketClient client = new SocketClient(); + IOStream? io_stream = client.connect_to_host(srv_target.get_hostname(), srv_target.get_port()); + io_stream = TlsClientConnection.new(io_stream, new NetworkAddress(srv_target.get_hostname(), srv_target.get_port())); + stream.add_flag(new Tls.Flag() { finished=true }); + return io_stream; + } + + public override string get_id() { return "start_tls"; } +} + +}