def onMessage(self, message): try: msgType = message.getAttribute('type') group, nick = resolveGroup(message.getAttribute('to')) gr = self.groupset.get(group) frm = message.getAttribute('from') if frm in XMPPChannel.jids and group in XMPPChannel.jids[frm].groups: ch = XMPPChannel.jids[frm] senderNick = ch.groups[group].nick if not nick and msgType == 'groupchat': # It may be None if it is a chat state notification like 'composing'. if message.body is not None: gr.broadcast({ 'cmd': 'say', 'user': senderNick, 'message': unicode(message.body) }) elif nick and msgType != 'groupchat': # TODO private messaging is handled here pass else: # See Example 48 raise error.StanzaError('bad-request', type='modify') else: raise error.StanzaError('not-acceptable', type='cancel') except error.StanzaError as ex: reply = ex.toResponse(message) self.send(reply)
def onSubscribe(self, stanza): """Handle subscription requests.""" if stanza.consumed: return stanza.consumed = True if self.parent.logTraffic: log.debug("subscription request: %s" % (stanza.toXml(), )) else: log.debug("subscription request to %s from %s" % (stanza['to'], self.xmlstream.otherEntity)) # extract jid the user wants to subscribe to jid_to = jid.JID(stanza['to']).userhostJID() jid_from = self.xmlstream.otherEntity # are we subscribing to a user we have blocked? if self.parent.router.is_presence_allowed(jid_to, jid_from) == -1: log.debug("subscribing to blocked user, bouncing error") e = error.StanzaError('not-acceptable', 'cancel') errstanza = e.toResponse(stanza) errstanza.error.addElement( (xmlstream2.NS_IQ_BLOCKING_ERRORS, 'blocked')) self.send(errstanza) else: if not self.parent.router.subscribe( self.parent.router.translateJID(jid_from), self.parent.router.translateJID(jid_to), stanza.getAttribute('id')): e = error.StanzaError('item-not-found') self.send(e.toResponse(stanza))
def _error(failure): log.debug("error: %s" % (failure, )) if isinstance(failure.value, RuntimeError): e = error.StanzaError('bad-request', 'modify', failure.getErrorMessage()) else: e = error.StanzaError('service-unavailable', 'cancel', failure.getErrorMessage()) iq = xmlstream.toResponse(stanza, 'error') iq.addChild(e.getElement()) manager.send(iq, True)
def _error(failure, stanza): log.debug("error: %s" % (failure, )) if isinstance(failure.value, oursql.IntegrityError): # duplicate key of userid: throttling e = error.StanzaError('service-unavailable', 'wait', 'Too many attempts.') else: e = error.StanzaError('service-unavailable', 'cancel', failure.getErrorMessage()) iq = xmlstream.toResponse(stanza, 'error') iq.addChild(e.getElement()) manager.send(iq, True)
def onIqFallback(self, iq): if iq.handled: return if iq['type'] in ('result', 'error'): return iq.handled = True if iq.getAttribute('type') in ('get', 'set'): exc = error.StanzaError('service-unavailable') else: exc = error.StanzaError('bad-request') self.xmlstream.send(exc.toResponse(iq))
def test_getElementConditionNamespace(self): """ Test that the error condition element has the correct namespace. """ e = error.StanzaError('feature-not-implemented') element = e.getElement() self.assertEquals(NS_XMPP_STANZAS, getattr(element, 'feature-not-implemented').uri)
def eb(failure): if not isinstance(failure, error.StanzaError): log.msg(failure) exc = error.StanzaError('internal-server-error') else: exc = failure.value self.xmlstream.send(exc.toResponse(iq))
def route(self, stanza): """ Route a stanza. @param stanza: The stanza to be routed. @type stanza: L{domish.Element}. """ destination = JID(stanza['to']) if destination.host in self.routes: log.msg("Routing to %s: %r" % (destination.full(), stanza.toXml())) self.routes[destination.host].send(stanza) elif None in self.routes: log.msg("Routing to %s (default route): %r" % (destination.full(), stanza.toXml())) self.routes[None].send(stanza) else: log.msg("No route to %s: %r" % (destination.full(), stanza.toXml())) if stanza.getAttribute('type') not in ('result', 'error'): # No route, send back error exc = error.StanzaError('remote-server-timeout', type='wait') exc.code = '504' response = exc.toResponse(stanza) self.route(response)
def handle(self, stanza): # enforce sender stanza['from'] = self.resolveJID(self.xmlstream.otherEntity).full() to = stanza.getAttribute('to') if to is not None: try: to = jid.JID(to) except: # invalid destination, consume stanza and return error stanza.consumed = True log.debug("invalid address: %s" % (to, )) e = error.StanzaError('jid-malformed', 'modify') self.send(e.toResponse(stanza)) return # stanza is for us if to.host == self.network: # sending to full JID, forward to router if to.user is not None and to.resource is not None: self.forward(stanza) # stanza is not intended to component either elif to.host != util.component_jid(self.servername, util.COMPONENT_C2S): self.forward(stanza)
def test_typeRemoteServerTimeout(self): """ Remote Server Timeout should yield type wait, code 504. """ e = error.StanzaError('remote-server-timeout') self.assertEqual('wait', e.type) self.assertEqual('504', e.code)
def _continue(code, stanza, phone): status = self.send_sms(phone, code) if status: # send response with sms sender number iq = xmlstream.toResponse(stanza, 'result') query = iq.addElement((xmlstream2.NS_IQ_REGISTER, 'query')) query.addElement((None, 'instructions'), content=self.ack_instructions) form = query.addElement(('jabber:x:data', 'x')) form['type'] = 'form' hidden = form.addElement((None, 'field')) hidden['type'] = 'hidden' hidden['var'] = 'FORM_TYPE' hidden.addElement((None, 'value'), content=xmlstream2.NS_IQ_REGISTER) phone = form.addElement((None, 'field')) phone['type'] = 'text-single' phone['label'] = 'SMS sender' phone['var'] = 'from' phone.addElement((None, 'value'), content=self.config['from']) else: # send error iq = xmlstream.toResponse(stanza, 'error') e = error.StanzaError('not-acceptable', 'modify', 'Unable to send SMS.') iq.addChild(e.getElement()) return manager.send(iq, True)
def error(self, stanza, condition='service-unavailable', errtype='cancel', text=None): if not stanza.consumed: log.debug("error %s" % (stanza.toXml(), )) stanza.consumed = True util.resetNamespace(stanza, self.namespace) e = error.StanzaError(condition, errtype, text) self.send(e.toResponse(stanza), True)
def test_typeRemoteServerTimeout(self): """ Remote Server Timeout should yield type wait, code 504. """ e = error.StanzaError("remote-server-timeout") self.assertEqual("wait", e.type) self.assertEqual("504", e.code)
def test_getElementTextNamespace(self): """ Test that the error text element has the correct namespace. """ e = error.StanzaError('feature-not-implemented', text='text') element = e.getElement() self.assertEqual(NS_XMPP_STANZAS, element.text.uri)
def onVCardGet(self, stanza): log.debug("%s requested vCard for %s" % (stanza['from'], stanza['to'])) jid_from = jid.JID(stanza['from']) jid_to = jid.JID(stanza['to']) try: # are we requesting vCard for a user we have blocked? if self.parent.is_presence_allowed(jid_to, jid_from) == -1: log.debug("requesting vCard for a blocked user, bouncing error") e = error.StanzaError('not-acceptable', 'cancel') errstanza = e.toResponse(stanza) errstanza.error.addElement((xmlstream2.NS_IQ_BLOCKING_ERRORS, 'blocked')) self.send(errstanza) else: fpr = self.parent.is_presence_allowed(jid_from, jid_to) log.debug("is_presence_allowed: %d" % (fpr, )) if fpr != 1: raise Exception() fpr = self.parent.keyring.get_fingerprint(jid_to.user) keydata = self.parent.keyring.get_key(jid_to.user, fpr) iq = xmlstream.toResponse(stanza, 'result') # add vcard vcard = iq.addElement((xmlstream2.NS_XMPP_VCARD4, 'vcard')) vcard_key = vcard.addElement((None, 'key')) vcard_data = vcard_key.addElement((None, 'uri')) vcard_data.addContent(xmlstream2.DATA_PGP_PREFIX + base64.b64encode(keydata)) self.send(iq) except: self.parent.error(stanza)
def onProbe(self, stanza): """Handle presence probes.""" if stanza.consumed: return log.debug("probe request: %s" % (stanza.toXml(), )) stanza.consumed = True to = jid.JID(stanza['to']) sender = jid.JID(stanza['from']) # are we probing a user we have blocked? if self.parent.is_presence_allowed(to, sender) == -1: log.debug("probing blocked user, bouncing error") e = error.StanzaError('not-acceptable', 'cancel') errstanza = e.toResponse(stanza) errstanza.error.addElement((xmlstream2.NS_IQ_BLOCKING_ERRORS, 'blocked')) self.send(errstanza) elif self.parent.is_presence_allowed(sender, to) == 1: gid = stanza.getAttribute('id') if not self.send_user_presence(gid, sender, to): response = xmlstream.toResponse(stanza, 'error') # TODO include error cause? self.send(response)
def _continue(userid): pkey = base64.b64decode( var_pkey.value.__str__().encode('utf-8')) signed_pkey = manager.link_public_key(pkey, userid) if signed_pkey: iq = xmlstream.toResponse(stanza, 'result') query = iq.addElement((xmlstream2.NS_IQ_REGISTER, 'query')) form = query.addElement(('jabber:x:data', 'x')) form['type'] = 'form' hidden = form.addElement((None, 'field')) hidden['type'] = 'hidden' hidden['var'] = 'FORM_TYPE' hidden.addElement( (None, 'value'), content='http://kontalk.org/protocol/register#code') signed = form.addElement((None, 'field')) signed['type'] = 'text-single' signed['label'] = 'Signed public key' signed['var'] = 'publickey' signed.addElement((None, 'value'), content=base64.b64encode(signed_pkey)) return manager.send(iq, True) else: e = error.StanzaError('bad-request', 'modify', 'Invalid public key.') iq = xmlstream.toResponse(stanza, 'error') iq.addChild(e.getElement()) manager.send(iq, True)
def onAuthGet(iq): """ Called when the initializer sent a query for authentication methods. The server responds that the client is not authorized to authenticate. """ response = error.StanzaError('not-authorized').toResponse(iq) self.pipe.source.send(response)
def _onJingleRequest(self, iq): request = JingleIq.fromElement(iq) method_name = 'on'+''.join(item.capitalize() for item in request.jingle.action.lower().split('-')) handler = getattr(self, method_name, None) if callable(handler): handler(request) else: raise error.StanzaError('bad-request')
def test_getElementType(self): """ Test getting an element for a stanza error with a given type. """ e = error.StanzaError('feature-not-implemented', 'auth') element = e.getElement() self.assertEqual(element.uri, None) self.assertEqual(element['type'], 'auth') self.assertEqual(element['code'], '501')
def test_getElementPlain(self): """ Test getting an element for a plain stanza error. """ e = error.StanzaError("feature-not-implemented") element = e.getElement() self.assertEqual(element.uri, None) self.assertEqual(element["type"], "cancel") self.assertEqual(element["code"], "501")
def test_getElementType(self): """ Test getting an element for a stanza error with a given type. """ e = error.StanzaError("feature-not-implemented", "auth") element = e.getElement() self.assertEqual(element.uri, None) self.assertEqual(element["type"], "auth") self.assertEqual(element["code"], "501")
def test_getElementPlain(self): """ Test getting an element for a plain stanza error. """ e = error.StanzaError('feature-not-implemented') element = e.getElement() self.assertEqual(element.uri, None) self.assertEqual(element['type'], 'cancel') self.assertEqual(element['code'], '501')
def onAuthSet(iq): """ Called when the initializer sent the authentication request. The server checks the credentials and responds with a not-authorized stanza error. """ response = error.StanzaError('not-authorized').toResponse(iq) self.pipe.source.send(response)
def getDiscoInfo(self, req, target, ni): group, nick = resolveGroup(target) if group in self.groupset and not ni: gr = self.groupset.get(group) if nick: if XMPPChannel.isMember(req.full(), gr): # TODO raise error.StanzaError('service-unavailable') else: raise error.StanzaError('bad-request') else: di = [disco.DiscoIdentity(u'conference', u'text', name=gr.name)] for f in gr.getDiscoFeatures(): di.append(f) return di else: # TODO raise error.StanzaError('not-implemented')
def testFailRequestFields(self): """ Test failure of request for fields. """ d = self.init.initialize() iq = self.output[0] response = error.StanzaError('not-authorized').toResponse(iq) self.xmlstream.dataReceived(response.toXml()) self.assertFailure(d, error.StanzaError) return d
def toResponse(info): if request.nodeIdentifier and not info: raise error.StanzaError('item-not-found') else: response = DiscoInfo() response.nodeIdentifier = request.nodeIdentifier for item in info: response.append(item) return response.toElement()
def testToResponse(self): stanza = domish.Element(('jabber:client', 'message')) stanza['type'] = 'get' stanza['to'] = '*****@*****.**' stanza['from'] = '[email protected]/resource' e = error.StanzaError('service-unavailable') response = e.toResponse(stanza) self.assertEqual(response['from'], '*****@*****.**') self.assertEqual(response['to'], '[email protected]/resource') self.assertEqual(response['type'], 'error') self.assertEqual(response.error.children[0].name, 'service-unavailable') self.assertEqual(response.error['type'], 'cancel')
def toResponse(results): info = [] for i in results: info.extend(i[1]) if nodeIdentifier and not info: raise error.StanzaError('item-not-found') else: response = domish.Element((NS_INFO, 'query')) for item in info: response.addChild(item) return response
def availableReceived(self, presence): try: group, nick = resolveGroup(presence.recipient) gr = self.groupset.get(group) if gr is None: raise error.StanzaError('not-allowed', type='cancel') ch = XMPPChannel.getChannel(presence.sender, self.parent, self.groupset) if gr.name in ch.groups: # We are already in the group, it just status changed to # 'Away' or something like this. # TODO broadcast status... return else: try: gr.join(ch, nick) except PresenceException as ex: raise error.StanzaError(ex.tag, type=ex.stanzaType) except error.StanzaError as ex: reply = ex.toResponse(presence.toElement()) self.send(reply)