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)
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)
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 test_str(self): jids = [ "host", "user@host", "host/res", "user@host/res" ] for testjid in jids: jid = JID(testjid) self.assertEqual(str(jid), testjid)
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 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))
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)
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)
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""")
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
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 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()
def test_jid_true(self): jid = JID("user@host/res") self.assertTrue(jid.validate())
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 }
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
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")
def test_jid_ip(self): JID("[email protected]/res") JID("user@fe80::1/res")
def test_jid_compare(self): jid1 = JID("user1@host/res") jid2 = JID("user2@host/res") self.assertTrue(jid1 == jid1) self.assertFalse(jid1 == jid2)
def test_parse_domain_jid(self): jid = JID("host") self.assertEqual(jid.local, None) self.assertEqual(jid.domain, "host") self.assertEqual(jid.resource, None)
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")
def test_bad_jid_inject(self): jid = JID('test') jid.domain = None with self.assertRaises(ValueError) as cm: jid.validate(True)
def test_bad_jid(self): jid = JID('test') jid.domain = '' with self.assertRaises(ValueError): cont = Contact(jid)
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
def __init__(self, jid): self.jid = JID(jid)
def test_bad_jids_false(self): for testjid in self.badjids: jid = JID(testjid, validate_on_init=False) self.assertFalse(jid.validate())
def test_init_required_attrs(self): with self.assertRaises(TypeError) as cm: cont = Contact() cont = Contact('test') cont = Contact(JID('test'))