From e899668213ee8f7d3566bb5754b488d8633c30c7 Mon Sep 17 00:00:00 2001 From: Marvin W Date: Tue, 10 Sep 2019 20:56:00 +0200 Subject: Add JET support --- xmpp-vala/src/module/xep/0166_jingle.vala | 68 +++++++++++++++++++++++++++---- 1 file changed, 60 insertions(+), 8 deletions(-) (limited to 'xmpp-vala/src/module/xep/0166_jingle.vala') diff --git a/xmpp-vala/src/module/xep/0166_jingle.vala b/xmpp-vala/src/module/xep/0166_jingle.vala index 86396f30..85663929 100644 --- a/xmpp-vala/src/module/xep/0166_jingle.vala +++ b/xmpp-vala/src/module/xep/0166_jingle.vala @@ -43,6 +43,7 @@ public errordomain Error { BAD_REQUEST, INVALID_PARAMETERS, UNSUPPORTED_TRANSPORT, + UNSUPPORTED_SECURITY, NO_SHARED_PROTOCOLS, TRANSPORT_ERROR, } @@ -69,6 +70,7 @@ class ContentNode { public string name; public StanzaNode? description; public StanzaNode? transport; + public StanzaNode? security; } ContentNode get_single_content_node(StanzaNode jingle) throws IqError { @@ -94,6 +96,7 @@ ContentNode get_single_content_node(StanzaNode jingle) throws IqError { string? name = content.get_attribute("name"); StanzaNode? description = get_single_node_anyns(content, "description"); StanzaNode? transport = get_single_node_anyns(content, "transport"); + StanzaNode? security = get_single_node_anyns(content, "security"); if (name == null || creator == null) { throw new IqError.BAD_REQUEST("missing name or creator"); } @@ -102,7 +105,8 @@ ContentNode get_single_content_node(StanzaNode jingle) throws IqError { creator=creator, name=name, description=description, - transport=transport + transport=transport, + security=security }; } @@ -112,6 +116,7 @@ public class Module : XmppStreamModule, Iq.Handler { private HashMap content_types = new HashMap(); private HashMap transports = new HashMap(); + private HashMap security_preconditions = new HashMap(); private XmppStream? current_stream = null; @@ -163,6 +168,16 @@ public class Module : XmppStreamModule, Iq.Handler { } return result; } + public void register_security_precondition(SecurityPrecondition precondition) { + security_preconditions[precondition.security_ns_uri()] = precondition; + } + public SecurityPrecondition? get_security_precondition(string? ns_uri) { + if (ns_uri == null) return null; + if (!security_preconditions.has_key(ns_uri)) { + return null; + } + return security_preconditions[ns_uri]; + } private bool is_jingle_available(XmppStream stream, Jid full_jid) { bool? has_jingle = stream.get_flag(ServiceDiscovery.Flag.IDENTITY).has_entity_feature(full_jid, NS_URI); @@ -173,7 +188,7 @@ public class Module : XmppStreamModule, Iq.Handler { return is_jingle_available(stream, full_jid) && select_transport(stream, type, full_jid, Set.empty()) != null; } - public Session create_session(XmppStream stream, TransportType type, Jid receiver_full_jid, Senders senders, string content_name, StanzaNode description) throws Error { + public Session create_session(XmppStream stream, TransportType type, Jid receiver_full_jid, Senders senders, string content_name, StanzaNode description, string? precondition_name = null, Object? precondation_options = null) throws Error { if (!is_jingle_available(stream, receiver_full_jid)) { throw new Error.NO_SHARED_PROTOCOLS("No Jingle support"); } @@ -181,18 +196,26 @@ public class Module : XmppStreamModule, Iq.Handler { if (transport == null) { throw new Error.NO_SHARED_PROTOCOLS("No suitable transports"); } + SecurityPrecondition? precondition = get_security_precondition(precondition_name); + if (precondition_name != null && precondition == null) { + throw new Error.UNSUPPORTED_SECURITY("No suitable security precondiiton found"); + } Jid? my_jid = stream.get_flag(Bind.Flag.IDENTITY).my_jid; if (my_jid == null) { throw new Error.GENERAL("Couldn't determine own JID"); } TransportParameters transport_params = transport.create_transport_parameters(stream, my_jid, receiver_full_jid); - Session session = new Session.initiate_sent(random_uuid(), type, transport_params, my_jid, receiver_full_jid, content_name, send_terminate_and_remove_session); + SecurityParameters? security_params = precondition != null ? precondition.create_security_parameters(stream, my_jid, receiver_full_jid, precondation_options) : null; + Session session = new Session.initiate_sent(random_uuid(), type, transport_params, security_params, my_jid, receiver_full_jid, content_name, send_terminate_and_remove_session); StanzaNode content = new StanzaNode.build("content", NS_URI) .put_attribute("creator", "initiator") .put_attribute("name", content_name) .put_attribute("senders", senders.to_string()) .put_node(description) .put_node(transport_params.to_transport_stanza_node()); + if (security_params != null) { + content.put_node(security_params.to_security_stanza_node(stream, my_jid, receiver_full_jid)); + } StanzaNode jingle = new StanzaNode.build("jingle", NS_URI) .add_self_xmlns() .put_attribute("action", "session-initiate") @@ -233,8 +256,17 @@ public class Module : XmppStreamModule, Iq.Handler { } ContentParameters content_params = content_type.parse_content_parameters(content.description); + SecurityPrecondition? precondition = content.security != null ? get_security_precondition(content.security.ns_uri) : null; + SecurityParameters? security_params = null; + if (precondition != null) { + debug("Using precondition %s", precondition.security_ns_uri()); + security_params = precondition.parse_security_parameters(stream, my_jid, iq.from, content.security); + } else if (content.security != null) { + throw new IqError.NOT_IMPLEMENTED("unknown security precondition"); + } + TransportType type = content_type.content_type_transport_type(); - Session session = new Session.initiate_received(sid, type, transport_params, my_jid, iq.from, content.name, send_terminate_and_remove_session); + Session session = new Session.initiate_received(sid, type, transport_params, security_params, my_jid, iq.from, content.name, send_terminate_and_remove_session); stream.get_flag(Flag.IDENTITY).add_session(session); stream.get_module(Iq.Module.IDENTITY).send_iq(stream, new Iq.Stanza.result(iq)); @@ -328,7 +360,7 @@ public interface Transport : Object { public abstract bool is_transport_available(XmppStream stream, Jid full_jid); public abstract TransportType transport_type(); public abstract int transport_priority(); - public abstract TransportParameters create_transport_parameters(XmppStream stream, Jid local_full_jid, Jid peer_full_jid); + public abstract TransportParameters create_transport_parameters(XmppStream stream, Jid local_full_jid, Jid peer_full_jid) throws Error; public abstract TransportParameters parse_transport_parameters(XmppStream stream, Jid local_full_jid, Jid peer_full_jid, StanzaNode transport) throws IqError; } @@ -375,6 +407,17 @@ public interface ContentParameters : Object { public abstract void on_session_initiate(XmppStream stream, Session session); } +public interface SecurityPrecondition : Object { + public abstract string security_ns_uri(); + public abstract SecurityParameters? create_security_parameters(XmppStream stream, Jid local_full_jid, Jid peer_full_jid, Object options) throws Jingle.Error; + public abstract SecurityParameters? parse_security_parameters(XmppStream stream, Jid local_full_jid, Jid peer_full_jid, StanzaNode security) throws IqError; +} + +public interface SecurityParameters : Object { + public abstract string security_ns_uri(); + public abstract StanzaNode to_security_stanza_node(XmppStream stream, Jid local_full_jid, Jid peer_full_jid); + public abstract IOStream wrap_stream(IOStream stream); +} public class Session { // INITIATE_SENT -> CONNECTING -> [REPLACING_TRANSPORT -> CONNECTING ->]... ACTIVE -> ENDED @@ -398,6 +441,7 @@ public class Session { public Jid peer_full_jid { get; private set; } public Role content_creator { get; private set; } public string content_name { get; private set; } + public SecurityParameters? security { get; private set; } private Connection connection; public IOStream conn { get { return connection; } } @@ -410,7 +454,7 @@ public class Session { SessionTerminate session_terminate_handler; - public Session.initiate_sent(string sid, TransportType type, TransportParameters transport, Jid local_full_jid, Jid peer_full_jid, string content_name, owned SessionTerminate session_terminate_handler) { + public Session.initiate_sent(string sid, TransportType type, TransportParameters transport, SecurityParameters? security, Jid local_full_jid, Jid peer_full_jid, string content_name, owned SessionTerminate session_terminate_handler) { this.state = State.INITIATE_SENT; this.role = Role.INITIATOR; this.sid = sid; @@ -422,12 +466,13 @@ public class Session { this.tried_transport_methods = new HashSet(); this.tried_transport_methods.add(transport.transport_ns_uri()); this.transport = transport; + this.security = security; this.connection = new Connection(this); this.session_terminate_handler = (owned)session_terminate_handler; this.terminate_on_connection_close = true; } - public Session.initiate_received(string sid, TransportType type, TransportParameters? transport, Jid local_full_jid, Jid peer_full_jid, string content_name, owned SessionTerminate session_terminate_handler) { + public Session.initiate_received(string sid, TransportType type, TransportParameters? transport, SecurityParameters? security, Jid local_full_jid, Jid peer_full_jid, string content_name, owned SessionTerminate session_terminate_handler) { this.state = State.INITIATE_RECEIVED; this.role = Role.RESPONDER; this.sid = sid; @@ -437,6 +482,7 @@ public class Session { this.content_creator = Role.INITIATOR; this.content_name = content_name; this.transport = transport; + this.security = security; this.tried_transport_methods = new HashSet(); if (transport != null) { this.tried_transport_methods.add(transport.transport_ns_uri()); @@ -557,7 +603,12 @@ public class Session { state = State.ACTIVE; transport = null; tried_transport_methods.clear(); - connection.set_inner(conn); + if (security != null) { + connection.set_inner(security.wrap_stream(conn)); + } else { + connection.set_inner(conn); + } + } else { if (role == Role.INITIATOR) { select_new_transport(stream); @@ -913,6 +964,7 @@ public class Connection : IOStream { return true; } public async bool close_read_async(int io_priority = GLib.Priority.DEFAULT, Cancellable? cancellable = null) throws IOError { + debug("Closing Jingle input stream"); yield wait_and_check_for_errors(io_priority, cancellable); if (read_closed) { return true; -- cgit v1.2.3-70-g09d2