Beispiel #1
0
 def test_jid_operators(self):
     a = JID("user@host/res")
     b = JID("user@host/res")
     self.assertTrue(a == b)
     self.assertFalse(a != b)
     self.assertTrue(a is not b)
     self.assertFalse(a is b)
Beispiel #2
0
 def test_bad_jids_raise(self):
     for testjid in self.badjids:
         try:
             with self.assertRaises(ValueError) as cm:
                 jid = JID(testjid)
         except AssertionError:
             raise AssertionError("ValueError not raised for JID '%s'" % testjid)
Beispiel #3
0
    def handle(self, tree):
        """<iq> handler, returns one or more <iq> tags with results and new ones if required"""

        self.from_jid = JID(tree.get("from"))
        self.tree = tree

        responses = []
        # dispatch to the handler for the given request query
        for req in list(tree):
            if tree.get("type") == "get":
                try:
                    data = self.get_handler[req.tag](self, req)
                    if data != None:
                        responses.append(self.create_response(data))
                except KeyError as e:
                    for elem in self.failure(req):
                        iq.append(elem)
                    iq.set("type", "error")
        # return the result
        return responses
Beispiel #4
0
    def test_str(self):
        jids = [
            "host",
            "user@host",
            "host/res",
            "user@host/res"
        ]

        for testjid in jids:
            jid = JID(testjid)
            self.assertEqual(str(jid), testjid)
Beispiel #5
0
    def __init__(self, jid, **kwds):
        super(Contact, self).__init__()

        # required
        if isinstance(jid, basestring):
            self.jid = JID(jid)
        elif isinstance(jid, JID):
            self.jid = jid
            self.jid.validate(raise_error=True)
        else:
            raise AttributeError(
                "Needs valid jid either as string or JID instance")

        # optional
        self.approved = False
        self.ask = None
        self.name = None
        self.subscription = "none"
        self.groups = []

        for k, v in kwds.iteritems():
            setattr(self, k, v)
Beispiel #6
0
    def route_stanza(self, stanza, raw_bytes):
        """Takes care of routing stanzas supplied to their addressed destination"""

        # Stanzas without a sender MUST be ignored..
        if stanza.get('from') is None:
            log.info('ignoring stanza without from attribute for ' +
                     stanza.get('to'))
            log.debug(ET.tostring(stanza))
            return
        stanza_source = JID(stanza.get('from'))
        stanza_destination = stanza.get('to')
        log.debug("received stanza from %s to %s" %
                  (stanza_source, stanza_destination))
        if stanza_destination is None:
            destination = stanza_source.domain
            log.debug("setting to attribute to " + destination)
            stanza_destination = destination

        stanza_destination = JID(stanza_destination)
        try:
            for peer in self.peers[stanza_destination.bare]:
                # Send to peer if the stanza has a bare jid as recipient
                # or if the full jid matches
                if (stanza_destination.resource is None \
                            and stanza_source != peer[0]) \
                            or stanza_destination == peer[0]:
                    log.debug("routing stanza from %s to %s" %
                              (stanza_source, peer[0]))
                    peer[1].send(raw_bytes)
        except KeyError:
            log.debug("Unknown message destination..")
            # Do not send errors if we cant deliver error messages
            if stanza.find('error') is None:
                # import error here on demand to prevent import loop
                from pyfire.stream.stanzas.errors import ServiceUnavailableError
                error_message = ServiceUnavailableError(stanza)
                self.route_stanza(error_message.element,
                                  cPickle.dumps(error_message.element))
Beispiel #7
0
    def authenticate(self, tree):
        """Authenticates user for session"""

        # Currently RFC specifies only SASL as supported way of auth'ing
        handler = SASLAuthHandler()
        if tree.get('xmlns') != handler.namespace:
            raise MalformedRequestError
        handler.process(tree)
        self.connection.parser.reset()
        self.jid = JID("@".join([handler.authenticated_user, self.hostname]))
        self.authenticated = True
        response_element = ET.Element("success")
        response_element.set("xmlns", handler.namespace)
        self.send_element(response_element)
Beispiel #8
0
    def streamhandler(self, attrs):
        """Handles a stream start"""

        if attrs == {}:
            # </stream:stream> received
            self.connection.stop_connection()
        else:
            # check if we are responsible for this stream
            self.hostname = attrs.getValue("to")
            if self.hostname not in config.getlist("listeners", "domains"):
                raise HostUnknownError

            # Stream restart
            stream = ET.Element("stream:stream")
            stream.set("xmlns", attrs.getValue("xmlns"))
            stream.set("from", self.hostname)
            stream.set("id", uuid.uuid4().hex)
            stream.set("xml:lang", "en")
            stream.set("xmlns:stream", "http://etherx.jabber.org/streams")

            # only include version in response if client sent its max supported
            # version (RFC6120 Section 4.7.5)
            try:
                if attrs.getValue("version") != "1.0":
                    raise UnsupportedVersionError
                stream.set("version", "1.0")
            except KeyError:
                pass

            try:
                from_jid = JID(attrs.getValue("from"))
                stream.set("to", unicode(from_jid))
            except ValueError:
                raise InvalidFromError
            except KeyError:
                pass

            start_stream = """<?xml version="1.0"?>""" + ET.tostring(stream)
            # Element has subitems but are added later to the stream,
            # so don't mark it a single element
            self.send_string(start_stream.replace("/>", ">"))

            # Make a list of supported features
            features = ET.Element("stream:features")
            if not self.authenticated:
                self.add_auth_options(features)
            else:
                self.add_server_features(features)

            self.send_element(features)
Beispiel #9
0
    def roster(self):
        """RFC6121 Section 2"""

        session = Session()
        senderjid = JID(self.sender)
        roster = session.query(Roster).filter_by(jid=senderjid.bare).first()
        if roster is None:
            roster = Roster(jid=senderjid.bare)
            session.add(roster)
            session.commit()

        for contact in roster.contacts:
            self.response.append(contact.to_element())
        self.response.set("xmlns", """jabber:iq:roster""")
Beispiel #10
0
    def handle(self, tree):
        """handler for resence requests,
           returns a response that should be sent back"""
        log.debug('loading roster to broadcast presence to subscribers..')
        session = Session()
        response = list()
        senderjid = JID(tree.get("from"))
        roster = session.query(Roster).filter_by(jid=senderjid.bare).first()
        if roster is not None:
            for contact in roster.contacts:
                # only broadcast to contacts having from or both subscription to brodcasting contact..
                if contact.subscription not in ['from', 'both']:
                    continue
                log.debug('broadcasting presence to ' + contact.jid.bare)
                brd_element = copy.deepcopy(tree)
                brd_element.set('to', contact.jid.bare)
                response.append(brd_element)

        # also broadcast presence to bare JID so all resources gets it
        brd_element = copy.deepcopy(tree)
        brd_element.set('to', JID(tree.get('from')).bare)
        response.append(brd_element)

        return response
Beispiel #11
0
    def handle(self, tree):
        """<iq> handler, returns one or more <iq> tags with results and new ones if required"""

        self.from_jid = JID(tree.get("from"))
        self.tree = tree

        responses = []
        # dispatch to the handler for the given request query
        for req in list(tree):
            if tree.get("type") == "get":
                try:
                    data = self.get_handler[req.tag](self, req)
                    if data != None:
                        responses.append(self.create_response(data))
                except KeyError as e:
                    for elem in self.failure(req):
                        iq.append(elem)
                    iq.set("type", "error")
        # return the result
        return responses
Beispiel #12
0
    def __init__(self, jid, **kwds):
        super(Contact, self).__init__()

        # required
        if isinstance(jid, basestring):
            self.jid = JID(jid)
        elif isinstance(jid, JID):
            self.jid = jid
            self.jid.validate(raise_error=True)
        else:
            raise AttributeError("Needs valid jid either as string or JID instance")

        # optional
        self.approved = False
        self.ask = None
        self.name = None
        self.subscription = "none"
        self.groups = []

        for k, v in kwds.iteritems():
            setattr(self, k, v)
Beispiel #13
0
    def handle_forwarder_message(self, msg):
        """Handles incoming command requests from peer"""

        if msg.command == 'REGISTER':
            (password, push_url, jids) = msg.attributes
            log.info('peer is trying to register')
            if password != config.get('ipc', 'password'):
                log.info('Authorization failed')
                return
            log.info('registering new peer at ' + push_url)
            peer = self.ctx.socket(zmq.PUSH)
            peer.connect(push_url)
            if isinstance(jids, JID):
                jids = [
                    jids,
                ]
            for jid in jids:
                log.info('adding routing entry for ' + unicode(jid))
                jid = JID(jid)
                try:
                    # append to bare jids list of existing connections
                    self.peers[jid.bare].append((jid, peer))
                except KeyError:
                    # create new entry
                    self.peers[jid.bare] = [
                        (jid, peer),
                    ]
        elif msg.command == 'UNREGISTER':
            push_url = msg.attributes
            log.info('unregistering peer at ' + push_url)
            for bare_jid in self.peers.keys():
                for peer in self.peers[bare_jid]:
                    if peer[1] == push_url:
                        self.peers.remove(peer)
                        if len(self.peers) == 0:
                            del self.peers[bare_jid]

        else:
            raise InternalServerError()
Beispiel #14
0
 def test_jid_true(self):
     jid = JID("user@host/res")
     self.assertTrue(jid.validate())
Beispiel #15
0
class Iq(object):
    """This Class handles <iq> XMPP frames"""
    def __init__(self):
        super(Iq, self).__init__()
        self.from_jid = None

    def create_response(self, content, iq_id=None):
        """Set up an iq response"""
        # prepare result header
        iq = ET.Element("iq")
        iq.set("id", iq_id or self.tree.get("id"))
        iq.set("type", "result")
        iq.set("from", self.from_jid.domain)
        iq.set("to", self.tree.get("from"))
        iq.append(content)
        return iq

    def handle(self, tree):
        """<iq> handler, returns one or more <iq> tags with results and new ones if required"""

        self.from_jid = JID(tree.get("from"))
        self.tree = tree

        responses = []
        # dispatch to the handler for the given request query
        for req in list(tree):
            if tree.get("type") == "get":
                try:
                    data = self.get_handler[req.tag](self, req)
                    if data != None:
                        responses.append(self.create_response(data))
                except KeyError as e:
                    for elem in self.failure(req):
                        iq.append(elem)
                    iq.set("type", "error")
        # return the result
        return responses

    def bind(self, request):
        """Handles bind requests"""
        bind = ET.Element("bind")
        bind.set("xmlns", "urn:ietf:params:xml:ns:xmpp-bind")
        jid = ET.SubElement(bind, "jid")
        # add resource to JID if provided
        if request.find("resource") != None:
            self.from_jid.resource = request.find("resource").text
            if not self.from_jid.validate():
                self.from_jid.resource = None

        jid.text = unicode(self.from_jid)
        return bind

    def session(self, request):
        """ No-op as suggested in RFC6121 Appendix E.
            Session establishment had been defined in RFC3921 Section 3
            and marked depricated in RFC6121.
        """
        return None

    def query(self, request):
        """Implements the query command"""
        handler = Query()
        return handler.handle(request, self.tree.get("from"))

    def ping(self, request):
        """A No-op for XEP-0199"""

    def vcard(self, request):
        """Returns the users vCard as specified by XEP-0054"""

        # TODO: Stub - Implement real vCard storage
        return ET.Element("vCard")

    def failure(self, requested_service):
        error = ET.Element("error")
        error.set("type", "cancel")
        service = ET.SubElement(error, "service-unavailable")
        service.set("xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas")
        return [requested_service, error]

    get_handler = {
        'bind': bind,
        'session': session,
        'query': query,
        'ping': ping,
        'vCard': vcard
    }
Beispiel #16
0
class Contact(Base):
    """Jabber Contact, aka roster item. It has some really strict attribute
       setting mechanism as it leads to all kinds of fantastic crashes with
       clients which should be avoided in any case.
    """

    __tablename__ = 'contacts'

    id = Column(Integer, primary_key=True)
    approved = Column(Boolean)
    ask = Column(Enum('subscribe'))
    jid = Column(JIDString, nullable=False)
    name = Column(String(255))
    subscription = Column(Enum("none", "from", "to", "remove", "both"))
    groups = relationship(Group, secondary=contacts_groups)
    roster = relationship(Roster, backref=backref('contacts'))
    roster_id = Column(Integer, ForeignKey('rosters.id'), nullable=False)

    def __init__(self, jid, **kwds):
        super(Contact, self).__init__()

        # required
        if isinstance(jid, basestring):
            self.jid = JID(jid)
        elif isinstance(jid, JID):
            self.jid = jid
            self.jid.validate(raise_error=True)
        else:
            raise AttributeError("Needs valid jid either as string or JID instance")

        # optional
        self.approved = False
        self.ask = None
        self.name = None
        self.subscription = "none"
        self.groups = []

        for k, v in kwds.iteritems():
            setattr(self, k, v)

    def to_element(self):
        """Formats contact as `class`:ET.Element object"""

        element = ET.Element("item")
        if self.approved is not None:
            element.set("approved", 'true' if self.approved else 'false')
        if self.ask is not None:
            element.set("ask", self.ask)
        element.set("jid", str(self.jid))
        if self.name is not None:
            element.set("name", self.name)
        if self.subscription is not None:
            element.set("subscription", self.subscription)
        for group in self.groups:
            group_element = ET.SubElement(element, "group")
            group_element.text = group
        return element

    @staticmethod
    def from_element(element):
        """Creates contact instance from `class`:ET.Element"""

        if element.tag != "item":
            raise ValueError("Invalid element with tag %s" % element.tag)

        cont = Contact(element.get('jid'))
        cont.ask = element.get('ask')
        cont.subscription = element.get('subscription')
        approved = element.get('approved')
        if approved == 'true':
            cont.approved = True
        elif approved == 'false':
            cont.approved = False
        else:
            cont.approved = approved
        for group in list(element):
            if group.tag == "group":
                cont.groups.append(group.text)
        return cont
Beispiel #17
0
 def test_bare_jid(self):
     jid = JID("user@host/res")
     self.assertEqual(jid.bare, "user@host")
     jid = JID("host/res")
     self.assertEqual(jid.bare, "host")
Beispiel #18
0
 def test_jid_ip(self):
     JID("[email protected]/res")
     JID("user@fe80::1/res")
Beispiel #19
0
 def test_jid_compare(self):
     jid1 = JID("user1@host/res")
     jid2 = JID("user2@host/res")
     self.assertTrue(jid1 == jid1)
     self.assertFalse(jid1 == jid2)
Beispiel #20
0
 def test_parse_domain_jid(self):
     jid = JID("host")
     self.assertEqual(jid.local, None)
     self.assertEqual(jid.domain, "host")
     self.assertEqual(jid.resource, None)
Beispiel #21
0
 def test_parse_full_jid(self):
     jid = JID("user@host/res")
     self.assertEqual(jid.local, "user")
     self.assertEqual(jid.domain, "host")
     self.assertEqual(jid.resource, "res")
Beispiel #22
0
 def test_bad_jid_inject(self):
     jid = JID('test')
     jid.domain = None
     with self.assertRaises(ValueError) as cm:
         jid.validate(True)
Beispiel #23
0
 def test_bad_jid(self):
     jid = JID('test')
     jid.domain = ''
     with self.assertRaises(ValueError):
         cont = Contact(jid)
Beispiel #24
0
class Iq(object):
    """This Class handles <iq> XMPP frames"""

    def __init__(self):
        super(Iq, self).__init__()
        self.from_jid = None

    def create_response(self, content, iq_id=None):
        """Set up an iq response"""
        # prepare result header
        iq = ET.Element("iq")
        iq.set("id", iq_id or self.tree.get("id"))
        iq.set("type", "result")
        iq.set("from", self.from_jid.domain)
        iq.set("to", self.tree.get("from"))
        iq.append(content)
        return iq

    def handle(self, tree):
        """<iq> handler, returns one or more <iq> tags with results and new ones if required"""

        self.from_jid = JID(tree.get("from"))
        self.tree = tree

        responses = []
        # dispatch to the handler for the given request query
        for req in list(tree):
            if tree.get("type") == "get":
                try:
                    data = self.get_handler[req.tag](self, req)
                    if data != None:
                        responses.append(self.create_response(data))
                except KeyError as e:
                    for elem in self.failure(req):
                        iq.append(elem)
                    iq.set("type", "error")
        # return the result
        return responses

    def bind(self, request):
        """Handles bind requests"""
        bind = ET.Element("bind")
        bind.set("xmlns", "urn:ietf:params:xml:ns:xmpp-bind")
        jid = ET.SubElement(bind, "jid")
        # add resource to JID if provided
        if request.find("resource") != None:
            self.from_jid.resource = request.find("resource").text
            if not self.from_jid.validate():
                self.from_jid.resource = None

        jid.text = unicode(self.from_jid)
        return bind

    def session(self, request):
        """ No-op as suggested in RFC6121 Appendix E.
            Session establishment had been defined in RFC3921 Section 3
            and marked depricated in RFC6121.
        """
        return None

    def query(self, request):
        """Implements the query command"""
        handler = Query()
        return handler.handle(request, self.tree.get("from"))

    def ping(self, request):
        """A No-op for XEP-0199"""

    def vcard(self, request):
        """Returns the users vCard as specified by XEP-0054"""

        # TODO: Stub - Implement real vCard storage
        return ET.Element("vCard")

    def failure(self, requested_service):
        error = ET.Element("error")
        error.set("type", "cancel")
        service = ET.SubElement(error, "service-unavailable")
        service.set("xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas")
        return [requested_service, error]

    get_handler = {
      'bind': bind,
      'session': session,
      'query': query,
      'ping': ping,
      'vCard': vcard
    }
Beispiel #25
0
class Contact(Base):
    """Jabber Contact, aka roster item. It has some really strict attribute
       setting mechanism as it leads to all kinds of fantastic crashes with
       clients which should be avoided in any case.
    """

    __tablename__ = 'contacts'

    id = Column(Integer, primary_key=True)
    approved = Column(Boolean)
    ask = Column(Enum('subscribe'))
    jid = Column(JIDString, nullable=False)
    name = Column(String(255))
    subscription = Column(Enum("none", "from", "to", "remove", "both"))
    groups = relationship(Group, secondary=contacts_groups)
    roster = relationship(Roster, backref=backref('contacts'))
    roster_id = Column(Integer, ForeignKey('rosters.id'), nullable=False)

    def __init__(self, jid, **kwds):
        super(Contact, self).__init__()

        # required
        if isinstance(jid, basestring):
            self.jid = JID(jid)
        elif isinstance(jid, JID):
            self.jid = jid
            self.jid.validate(raise_error=True)
        else:
            raise AttributeError(
                "Needs valid jid either as string or JID instance")

        # optional
        self.approved = False
        self.ask = None
        self.name = None
        self.subscription = "none"
        self.groups = []

        for k, v in kwds.iteritems():
            setattr(self, k, v)

    def to_element(self):
        """Formats contact as `class`:ET.Element object"""

        element = ET.Element("item")
        if self.approved is not None:
            element.set("approved", 'true' if self.approved else 'false')
        if self.ask is not None:
            element.set("ask", self.ask)
        element.set("jid", str(self.jid))
        if self.name is not None:
            element.set("name", self.name)
        if self.subscription is not None:
            element.set("subscription", self.subscription)
        for group in self.groups:
            group_element = ET.SubElement(element, "group")
            group_element.text = group
        return element

    @staticmethod
    def from_element(element):
        """Creates contact instance from `class`:ET.Element"""

        if element.tag != "item":
            raise ValueError("Invalid element with tag %s" % element.tag)

        cont = Contact(element.get('jid'))
        cont.ask = element.get('ask')
        cont.subscription = element.get('subscription')
        approved = element.get('approved')
        if approved == 'true':
            cont.approved = True
        elif approved == 'false':
            cont.approved = False
        else:
            cont.approved = approved
        for group in list(element):
            if group.tag == "group":
                cont.groups.append(group.text)
        return cont
Beispiel #26
0
 def __init__(self, jid):
     self.jid = JID(jid)
Beispiel #27
0
 def test_bad_jids_false(self):
     for testjid in self.badjids:
         jid = JID(testjid, validate_on_init=False)
         self.assertFalse(jid.validate())
Beispiel #28
0
 def test_init_required_attrs(self):
     with self.assertRaises(TypeError) as cm:
         cont = Contact()
     cont = Contact('test')
     cont = Contact(JID('test'))