def _handle_open_request(self, iq): sid = iq['ibb_open']['sid'] size = iq['ibb_open']['block_size'] or self.block_size log.debug('Received IBB stream request from %s', iq['from']) if not sid: raise XMPPError(etype='modify', condition='bad-request') if not self._accept_stream(iq): raise XMPPError(etype='modify', condition='not-acceptable') if size > self.max_block_size: raise XMPPError('resource-constraint') stream = IBBytestream(self.xmpp, sid, size, iq['to'], iq['from'], self.window_size) stream.stream_started.set() self.api['set_stream'](stream.self_jid, stream.sid, stream.peer_jid, stream) iq.reply() iq.send() self.xmpp.event('ibb_stream_start', stream) self.xmpp.event('stream:%s:%s' % (sid, stream.peer_jid), stream)
def can_unsubscribe(self, iq, fjid, node, sjid, subid=None): if not self.node_exists(node): raise XMPPError(condition='item-not-found', etype='cancel') if subid is None or subid == '': subids = self.get_subids(node, sjid) if len(subids) == 0: raise XMPPError( condition='unexpected-request', etype='cancel', extension='not-subscribed', extension_ns='http://jabber.org/protocol/pubsub#errors') elif len(subids) > 1: raise XMPPError( condition='bad-request', etype='modify', extension='subid-required', extension_ns='http://jabber.org/protocol/pubsub#errors') else: subid = subids.pop() else: if not self.redis.sismember( 'xmpp.jid.subs.{%s}.{%s}' % (sjid, node), subid): raise XMPPError( condition='unexpected-request', etype='cancel', extension='not-subscribed', extension_ns='http://jabber.org/protocol/pubsub#errors') if self.is_admin(fjid) or self.is_affiliation(node, fjid, 'owner'): return True elif fjid.full != jid and fjid.bare != jid: raise XMPPError(condition='forbidden', etype='auth') return True
def _default_get_last_activity(self, jid, node, ifrom, iq): if not isinstance(iq, Iq): reply = self.xmpp.Iq() else: iq.reply() reply = iq if jid not in self._last_activities: raise XMPPError('service-unavailable') bare = JID(jid).bare if bare != self.xmpp.boundjid.bare: if bare in self.xmpp.roster[jid]: sub = self.xmpp.roster[jid][bare]['subscription'] if sub not in ('from', 'both'): raise XMPPError('forbidden') td = datetime.now() - self._last_activities[jid]['seconds'] seconds = td.seconds + td.days * 24 * 3600 status = self._last_activities[jid]['status'] reply['last_activity']['seconds'] = seconds reply['last_activity']['status'] = status return reply
def _handle_streamhost(self, iq): """Handle incoming SOCKS5 session request.""" sid = iq['socks']['sid'] if not sid: raise XMPPError(etype='modify', condition='not-acceptable') streamhosts = iq['socks']['streamhosts'] conn = None used_streamhost = None for streamhost in streamhosts: try: conn = self._connect_proxy(sid, iq['from'], self.xmpp.boundjid, streamhost['host'], streamhost['port']) used_streamhost = streamhost['jid'] break except socket.error: continue else: raise XMPPError(etype='cancel', condition='item-not-found') iq.reply() with self._sessions_lock: self._sessions[sid] = conn iq['socks']['sid'] = sid iq['socks']['streamhost_used']['jid'] = used_streamhost iq.send()
def handle_command(form, session): with self.lock: if self.max_tasks and len(self.tasks) + 1 > self.max_tasks: raise XMPPError( condition='resource-constraint', text='Maximum number of tasks already running.', etype='wait') self.tasks[session['id']] = True if len(self.tasks) == self.max_tasks: self.xmpp.send_presence(ptype='dnd', pstatus='Executing tasks.') command = form['values']['command'] command_started = self._execute(session['id'], command) if not command_started or session['id'] not in self.tasks: with self.lock: if session['id'] in self.tasks: del self.tasks[session['id']] raise XMPPError('internal-server-error', etype='cancel') form = self.xmpp['xep_0004'].makeForm(ftype='form') form.addField(var='cleanup', label='Cleanup', required=True) session['payload'] = form session['next'] = handle_cleanup session['has_next'] = False return session
def handleCreateNode(self, iq): node = iq['pubsub']['create']['node'] or uuid.uuid4().hex config = iq['pubsub']['configure']['form'] or self.default_config if node in self.nodes: raise XMPPError('conflict', etype='cancel') if not self.createNode(node, config, iq['from'].full): raise XMPPError() iq.reply() iq['pubsub']['create']['node'] = node iq.send()
def _get_items(self, jid, node, data, disco, pubsub): try: firstpart = node.split('/', 2)[1] except: raise XMPPError(condition='item-not-found') if firstpart == 'passtimes': pass elif firstpart in self.modalities.keys(): return self.modalities[firstpart].get_items( jid, node, data, disco, pubsub) raise XMPPError(condition='item-not-found')
def handlePublish(self, iq): fjid = iq['from'].bare node = iq['pubsub']['publish']['node'] instant_node = False auto_create = False if not node: if 'instant-nodes' not in self.features: raise XMPPError( etype='modify', condition='not-acceptable', extention='nodeid-required', extention_ns='http://jabber.org/protocol/pubsub#errors') node = uuid.uuid4().hex instant_node = True if instant_node or not self.node_exists(node): if 'auto-create' in self.features: #create config from default config merged with publish-options config = self.xmpp.plugin['xep_0004'].make_form() config['values'] = self.default_config if 'publish_options' in iq['pubsub'].plugins: config.merge(iq['pubsub']['publish_options']) config = self.xmppconfig2thoonkconfig(None, config['values']) self.thoonk.create_feed(node, config) self.set_affilation(node, fjid, 'owner') auto_create = True else: raise XMPPError(condition='item-not-found', etype='cancel') if not self.is_admin(fjid) and not self.is_affiliation( node, fjid, 'owner') and not self.is_affiliation( node, fjid, 'publisher') and not self.is_affiliation( node, fjid, 'publish-only'): raise XMPPError(etype='auth', condition='forbidden') #TODO: if too big, error payload-to-big 7.1.3.4 #TODO: if wrong ns or more than one root element in <item /> error invalid-payload 7.1.3.5 if not auto_create and 'publish_options' in iq['pubsub'].plugins: options = iq['pubsub']['publish_options']['values'] existing_config = self.thoonkconfig2xmppconfig(node) for key in options: if options[key] != existing_config.get(key): raise XMPPError( condition='conflict', etype='cancel', extension='precondition-not-met', extension_ns='http://jabber.org/protocol/pubsub#errors' ) item_id = iq['pubsub']['publish']['item']['id'] if not item_id: item_id = uuid.uuid4().hex self.thoonk.publish(node, iq['pubsub']['publish']['item'], id=item_id)
def test_send_ping_with_monitor(): v = a_vacbot(monitor=True) ping_mock = v.xmpp.send_ping = Mock() request_statuses_mock = v.request_all_statuses = Mock() # First ping should try to fetch statuses v.send_ping() assert_equals(1, request_statuses_mock.call_count) # Nothing blowing up is success # On four failed pings, vacuum state gets set to 'offline' ping_mock.side_effect = XMPPError() v.send_ping() v.send_ping() v.send_ping() assert_equals(None, v.vacuum_status) v.send_ping() assert_equals('offline', v.vacuum_status) # On a successful ping after the offline state, a request for initial statuses is made ping_mock.side_effect = None request_statuses_mock.reset_mock() v.send_ping() assert_equals(1, request_statuses_mock.call_count)
def _handle_roster(self, iq): """Update the roster after receiving a roster stanza. :param iq: The roster stanza. """ if iq['type'] == 'set': if iq['from'].bare and iq['from'].bare != self.boundjid.bare: raise XMPPError(condition='service-unavailable') roster = self.client_roster if iq['roster']['ver']: roster.version = iq['roster']['ver'] items = iq['roster']['items'] valid_subscriptions = ('to', 'from', 'both', 'none', 'remove') for jid, item in items.items(): if item['subscription'] in valid_subscriptions: roster[jid]['name'] = item['name'] roster[jid]['groups'] = item['groups'] roster[jid]['from'] = item['subscription'] in ('from', 'both') roster[jid]['to'] = item['subscription'] in ('to', 'both') roster[jid]['pending_out'] = (item['ask'] == 'subscribe') roster[jid].save(remove=(item['subscription'] == 'remove')) self.event("roster_update", iq) if iq['type'] == 'set': resp = self.Iq(stype='result', sto=iq['from'], sid=iq['id']) resp.enable('roster') resp.send()
def _handle_data(self, stanza): sid = stanza['ibb_data']['sid'] stream = self.streams.get(sid, None) if stream is not None and stanza['from'] != stream.sender: stream._recv_data(stanza) else: raise XMPPError('item-not-found')
def _handle_close(self, iq): sid = iq['ibb_close']['sid'] stream = self.streams.get(sid, None) if stream is not None and iq['from'] != stream.sender: stream._closed(iq) else: raise XMPPError('item-not-found')
def message(msg): raise XMPPError(condition='feature-not-implemented', text="We don't do things that way here.", etype='cancel', extension='foo', extension_ns='foo:error', extension_args={'test': 'true'})
def _handle_data(self, stanza): sid = stanza['ibb_data']['sid'] stream = self.api['get_stream'](stanza['to'], sid, stanza['from']) if stream is not None and stanza['from'] == stream.peer_jid: stream._recv_data(stanza) else: raise XMPPError('item-not-found')
def _handle_roster(self, iq, request=False): """Update the roster after receiving a roster stanza. :param iq: The roster stanza. :param request: Indicates if this stanza is a response to a request for the roster, and not an empty acknowledgement from the server. """ if iq['from'].bare and iq['from'].bare != self.boundjid.bare: raise XMPPError(condition='service-unavailable') if iq['type'] == 'set' or (iq['type'] == 'result' and request): roster = self.client_roster if iq['roster']['ver']: roster.version = iq['roster']['ver'] for jid in iq['roster']['items']: item = iq['roster']['items'][jid] roster[jid]['name'] = item['name'] roster[jid]['groups'] = item['groups'] roster[jid]['from'] = item['subscription'] in ['from', 'both'] roster[jid]['to'] = item['subscription'] in ['to', 'both'] roster[jid]['pending_out'] = (item['ask'] == 'subscribe') roster[jid].save(remove=(item['subscription'] == 'remove')) self.event('roster_received', iq) self.event("roster_update", iq) if iq['type'] == 'set': iq.reply() iq.enable('roster') iq.send()
def _recv_data(self, iq): with self._recv_seq_lock: new_seq = iq['ibb_data']['seq'] if new_seq != (self.recv_seq + 1) % 65535: self.close() raise XMPPError('unexpected-request') self.recv_seq = new_seq data = iq['ibb_data']['data'] if len(data) > self.block_size: self.close() raise XMPPError('not-acceptable') self.recv_queue.put(data) self.xmpp.event('ibb_stream_data', {'stream': self, 'data': data}) iq.reply() iq.send()
def _handle_open_request(self, iq): sid = iq['ibb_open']['sid'] size = iq['ibb_open']['block_size'] if not self._accept_stream(iq): raise XMPPError('not-acceptable') if size > self.max_block_size: raise XMPPError('resource-constraint') stream = IBBytestream(self.xmpp, sid, size, iq['from'], iq['to'], self.window_size) stream.stream_started.set() self.streams[sid] = stream iq.reply() iq.send() self.xmpp.event('ibb_stream_start', stream)
def _handle_close(self, iq): sid = iq['ibb_close']['sid'] stream = self.api['get_stream'](iq['to'], sid, iq['from']) if stream is not None and iq['from'] == stream.peer_jid: stream._closed(iq) self.api['del_stream'](stream.self_jid, stream.sid, stream.peer_jid) else: raise XMPPError('item-not-found')
def _handle_request(self, iq): profile = iq['si']['profile'] sid = iq['si']['id'] if not sid: raise XMPPError(etype='modify', condition='bad-request') if profile not in self._profiles: raise XMPPError( etype='modify', condition='bad-request', extension='bad-profile', extension_ns=SI.namespace) neg = iq['si']['feature_neg']['form']['fields'] options = neg['stream-method']['options'] or [] methods = [] for opt in options: methods.append(opt['value']) for method in methods: if method in self._methods: supported = True break else: raise XMPPError('bad-request', extension='no-valid-streams', extension_ns=SI.namespace) selected_method = None log.debug('Available: %s', methods) for order, method, plugin in self._methods_order: log.debug('Testing: %s', method) if method in methods: selected_method = method break receiver = iq['to'] sender = iq['from'] self.api['add_pending'](receiver, sid, sender, { 'response_id': iq['id'], 'method': selected_method, 'profile': profile }) self.xmpp.event('si_request', iq)
def connect_to_jabber(self, jabber_id, password): self.xmpp = ClientXMPP(jabber_id, password) self.xmpp.reconnect_max_attempts = 1 connected = self.xmpp.connect() if not connected: raise XMPPError("Vyanse kwikonecta") self.xmpp.process() self.xmpp.send_presence() self.xmpp.get_roster() self.xmpp.add_event_handler('message', self.root.handle_xmpp_message)
def _handle_task_command(self, iq, session): def handle_cleanup(form, session): cleanup = form['values'].get('cleanup', None) if cleanup: self._execute(session['id'], cleanup, cleanup=True) with self.lock: if session['id'] in self.tasks: del self.tasks[session['id']] self.xmpp.send_presence(pstatus='Ready for Task') def handle_command(form, session): with self.lock: if self.max_tasks and len(self.tasks) + 1 > self.max_tasks: raise XMPPError( condition='resource-constraint', text='Maximum number of tasks already running.', etype='wait') self.tasks[session['id']] = True if len(self.tasks) == self.max_tasks: self.xmpp.send_presence(ptype='dnd', pstatus='Executing tasks.') command = form['values']['command'] command_started = self._execute(session['id'], command) if not command_started or session['id'] not in self.tasks: with self.lock: if session['id'] in self.tasks: del self.tasks[session['id']] raise XMPPError('internal-server-error', etype='cancel') form = self.xmpp['xep_0004'].makeForm(ftype='form') form.addField(var='cleanup', label='Cleanup', required=True) session['payload'] = form session['next'] = handle_cleanup session['has_next'] = False return session def handle_cancel(iq, session): self._cancel(session['id']) if self.whitelist: if iq['from'].bare not in self.whitelist: raise XMPPError('not-authorized', etype='cancel') form = self.xmpp['xep_0004'].makeForm(ftype='form') form.addField(var='command', label='Command', required=True) session['payload'] = form session['next'] = handle_command session['cancel'] = handle_cancel session['has_next'] = True return session
def _default_handler(self, iq): """ As a safe default, don't actually download files. Register a new handler using self.register_url_handler to screen requests and download files. Arguments: iq -- The Iq stanza containing the OOB transfer request. """ raise XMPPError('service-unavailable')
def get_info(self, jid, node, data): """ Return the stored info data for the requested JID/node combination. The data parameter is not used. """ if (jid, node) not in self.nodes: if not node: return DiscoInfo() else: raise XMPPError(condition='item-not-found') else: return self.nodes[(jid, node)]['info']
def get_items(self, jid, node, ifrom, data): """ Return the stored items data for the requested JID/node combination. The data parameter is not used. """ with self.lock: if not self.node_exists(jid, node): if not node: return DiscoItems() else: raise XMPPError(condition='item-not-found') else: return self.get_node(jid, node)['items']
def patched_handle_get_vcard(self, iq): if iq['type'] == 'result': self.api['set_vcard'](jid=iq['from'], args=iq['vcard_temp']) return elif iq['type'] == 'get': vcard = self.api['get_vcard'](iq['to'].bare) if isinstance(vcard, Iq): vcard.send() else: iq = iq.reply() iq.append(vcard) iq.send() elif iq['type'] == 'set': raise XMPPError('service-unavailable')
def _run_url_handler(self, iq): """ Execute the appropriate handler for a transfer request. Arguments: iq -- The Iq stanza containing the OOB transfer request. """ if iq['to'] in self.url_handlers['jid']: return self.url_handlers['jid'][jid](iq) else: if self.url_handlers['global']: self.url_handlers['global'](iq) else: raise XMPPError('service-unavailable')
def handleSubscribe(self, stanza): node = stanza['pubsub']['subscribe']['node'] jid = stanza['pubsub']['subscribe']['jid'] subid = self.subscribeNode(node, jid, stanza['from']) if not subid: raise XMPPError('not-allowed') #self.xmpp.send(self.xmpp.makeIqError(stanza['id'])) return stanza.reply() stanza.clear() stanza['pubsub']['subscription']['subid'] = subid stanza['pubsub']['subscription']['node'] = node stanza['pubsub']['subscription']['jid'] = str(jid) stanza['pubsub']['subscription']['subscription'] = 'subscribed' stanza.send()
def handleSetState(self, iq): node = self.nodes.get(iq['psstate']['node']) payload = iq['psstate']['payload'] if node is None: raise XMPPError('item-not-found') item = iq['psstate']['item'] if item is not None: result = node.setItemState(item, payload, iq['from']) if result: iq.reply() iq['psstate']['payload'] = payload iq.send() else: iq.reply() iq['error']['condition'] = 'not-allowed' iq.send()
def get_items(self, jid, node, data, disco=None, pubsub=None): latlon = self.validnode_latlon.match(node) print node if latlon is not None: lat = latlon.group(1) lon = latlon.group(2) what = latlon.group(3) x, y = wgs84_rd(lat, lon) x = int(x) y = int(y) if what == 'quays': if disco is not None: return self.nearestuserstop_disco(disco, jid, node, x, y) elif pubsub is not None: return self.nearestuserstop_get_items(pubsub, jid, node, x, y) elif what == 'stopplaces': if disco is not None: return self.neareststopplace_disco(disco, jid, node, x, y) elif pubsub is not None: return self.neareststopplace_get_items(pubsub, jid, node, x, y) else: if disco is not None: return disco.static.get_items(jid, node, data) elif pubsub is not None: print node match = self.validnode.match(node) if match is not None: print 'match=>', match.group(0) if match.group(9) is not None: if match.group(10) is not None: return self.passtimes(pubsub, match.group(3), match.group(6), match.group(9), match.group(12)) else: return self.quay(pubsub, node, match.group(3), match.group(6), match.group(9)) elif match.group(6) is not None and match.group(6) != '': if match.group(10) is not None: return self.passtimes_stopplace(pubsub, match.group(3), match.group(6), match.group(12)) else: return self.stopplace(pubsub, node, match.group(3), match.group(6)) raise XMPPError(condition='item-not-found')
def test_send_ping_no_monitor(): v = a_vacbot() mock = v.xmpp.send_ping = Mock() v.send_ping() # On four failed pings, vacuum state gets set to 'offline' mock.side_effect = XMPPError() v.send_ping() v.send_ping() v.send_ping() assert_equals(None, v.vacuum_status) v.send_ping() assert_equals('offline', v.vacuum_status) # On a successful ping after the offline state, state gets reset to None, indicating that it is unknown mock.side_effect = None v.send_ping() assert_equals(None, v.vacuum_status)