Made a first pass at cleaning up ComponentXMPP.
This commit is contained in:
parent
178608f4c0
commit
a7410f2146
2 changed files with 125 additions and 59 deletions
|
@ -26,6 +26,14 @@ from sleekxmpp.xmlstream.matcher import *
|
|||
from sleekxmpp.xmlstream.handler import *
|
||||
|
||||
|
||||
# Flag indicating if DNS SRV records are available for use.
|
||||
SRV_SUPPORT = True
|
||||
try:
|
||||
import dns.resolver
|
||||
except:
|
||||
SRV_SUPPORT = False
|
||||
|
||||
|
||||
# In order to make sure that Unicode is handled properly
|
||||
# in Python 2.x, reset the default encoding.
|
||||
if sys.version_info < (3, 0):
|
||||
|
|
176
sleekxmpp/componentxmpp.py
Executable file → Normal file
176
sleekxmpp/componentxmpp.py
Executable file → Normal file
|
@ -1,5 +1,3 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
SleekXMPP: The Sleek XMPP Library
|
||||
Copyright (C) 2010 Nathanael C. Fritz
|
||||
|
@ -7,72 +5,132 @@
|
|||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
from . basexmpp import BaseXMPP
|
||||
from xml.etree import cElementTree as ET
|
||||
|
||||
from . xmlstream.xmlstream import XMLStream
|
||||
from . xmlstream.xmlstream import RestartStream
|
||||
from . xmlstream.matcher.xmlmask import MatchXMLMask
|
||||
from . xmlstream.matcher.xpath import MatchXPath
|
||||
from . xmlstream.matcher.many import MatchMany
|
||||
from . xmlstream.handler.callback import Callback
|
||||
from . xmlstream.stanzabase import StanzaBase
|
||||
from . xmlstream import xmlstream as xmlstreammod
|
||||
import time
|
||||
from __future__ import absolute_import
|
||||
|
||||
import logging
|
||||
import base64
|
||||
import sys
|
||||
import random
|
||||
import copy
|
||||
from . import plugins
|
||||
from . import stanza
|
||||
import hashlib
|
||||
srvsupport = True
|
||||
try:
|
||||
import dns.resolver
|
||||
except ImportError:
|
||||
srvsupport = False
|
||||
|
||||
from sleekxmpp import plugins
|
||||
from sleekxmpp import stanza
|
||||
from sleekxmpp.basexmpp import BaseXMPP, SRV_SUPPORT
|
||||
from sleekxmpp.xmlstream import XMLStream, RestartStream
|
||||
from sleekxmpp.xmlstream.matcher import *
|
||||
from sleekxmpp.xmlstream.handler import *
|
||||
from sleekxmpp.xmlstream.stanzabase import StanzaBase, ET
|
||||
|
||||
|
||||
class ComponentXMPP(basexmpp, XMLStream):
|
||||
"""SleekXMPP's client class. Use only for good, not evil."""
|
||||
class ComponentXMPP(BaseXMPP):
|
||||
|
||||
def __init__(self, jid, secret, host, port, plugin_config = {}, plugin_whitelist=[], use_jc_ns=False):
|
||||
if use_jc_ns:
|
||||
default_ns = 'jabber:client'
|
||||
else:
|
||||
default_ns = 'jabber:component:accept'
|
||||
BaseXMPP.__init__(self, default_ns)
|
||||
self.auto_authorize = None
|
||||
self.stream_header = "<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' to='%s'>" % jid
|
||||
self.stream_footer = "</stream:stream>"
|
||||
self.server_host = host
|
||||
self.server_port = port
|
||||
self.set_jid(jid)
|
||||
self.secret = secret
|
||||
self.is_component = True
|
||||
self.registerHandler(Callback('Handshake', MatchXPath('{jabber:component:accept}handshake'), self._handleHandshake))
|
||||
"""
|
||||
SleekXMPP's basic XMPP server component.
|
||||
|
||||
def incoming_filter(self, xmlobj):
|
||||
if xmlobj.tag.startswith('{jabber:client}'):
|
||||
xmlobj.tag = xmlobj.tag.replace('jabber:client', self.default_ns)
|
||||
for sub in xmlobj:
|
||||
self.incoming_filter(sub)
|
||||
return xmlobj
|
||||
Use only for good, not for evil.
|
||||
|
||||
def start_stream_handler(self, xml):
|
||||
sid = xml.get('id', '')
|
||||
handshake = ET.Element('{jabber:component:accept}handshake')
|
||||
if sys.version_info < (3,0):
|
||||
handshake.text = hashlib.sha1("%s%s" % (sid, self.secret)).hexdigest().lower()
|
||||
else:
|
||||
handshake.text = hashlib.sha1(bytes("%s%s" % (sid, self.secret), 'utf-8')).hexdigest().lower()
|
||||
self.sendXML(handshake)
|
||||
Methods:
|
||||
connect -- Overrides XMLStream.connect.
|
||||
incoming_filter -- Overrides XMLStream.incoming_filter.
|
||||
start_stream_handler -- Overrides XMLStream.start_stream_handler.
|
||||
"""
|
||||
|
||||
def _handleHandshake(self, xml):
|
||||
self.event("session_start")
|
||||
def __init__(self, jid, secret, host, port,
|
||||
plugin_config={}, plugin_whitelist=[], use_jc_ns=False):
|
||||
"""
|
||||
Arguments:
|
||||
jid -- The JID of the component.
|
||||
secret -- The secret or password for the component.
|
||||
host -- The server accepting the component.
|
||||
port -- The port used to connect to the server.
|
||||
plugin_config -- A dictionary of plugin configurations.
|
||||
plugin_whitelist -- A list of desired plugins to load
|
||||
when using register_plugins.
|
||||
use_js_ns -- Indicates if the 'jabber:client' namespace
|
||||
should be used instead of the standard
|
||||
'jabber:component:accept' namespace.
|
||||
Defaults to False.
|
||||
"""
|
||||
if use_jc_ns:
|
||||
default_ns = 'jabber:client'
|
||||
else:
|
||||
default_ns = 'jabber:component:accept'
|
||||
BaseXMPP.__init__(self, default_ns)
|
||||
|
||||
def connect(self):
|
||||
logging.debug("Connecting to %s:%s" % (self.server_host, self.server_port))
|
||||
return xmlstreammod.XMLStream.connect(self, self.server_host, self.server_port)
|
||||
self.auto_authorize = None
|
||||
self.stream_header = "<stream:stream %s %s to='%s'>" % (
|
||||
'xmlns="jabber:component:accept"',
|
||||
'xmlns:stream="http://etherx.jabber.org/streams"',
|
||||
jid)
|
||||
self.stream_footer = "</stream:stream>"
|
||||
self.server_host = host
|
||||
self.server_port = port
|
||||
self.set_jid(jid)
|
||||
self.secret = secret
|
||||
self.is_component = True
|
||||
|
||||
self.register_handler(
|
||||
Callback('Handshake',
|
||||
MatchXPath('{jabber:component:accept}handshake'),
|
||||
self._handle_handshake))
|
||||
|
||||
def connect(self):
|
||||
"""
|
||||
Connect to the server.
|
||||
|
||||
Overrides XMLStream.connect.
|
||||
"""
|
||||
logging.debug("Connecting to %s:%s" % (self.server_host,
|
||||
self.server_port))
|
||||
return XMLStream.connect(self, self.server_host,
|
||||
self.server_port)
|
||||
|
||||
def incoming_filter(self, xml):
|
||||
"""
|
||||
Pre-process incoming XML stanzas by converting any 'jabber:client'
|
||||
namespaced elements to the component's default namespace.
|
||||
|
||||
Overrides XMLStream.incoming_filter.
|
||||
|
||||
Arguments:
|
||||
xml -- The XML stanza to pre-process.
|
||||
"""
|
||||
if xml.tag.startswith('{jabber:client}'):
|
||||
xml.tag = xml.tag.replace('jabber:client', self.default_ns)
|
||||
|
||||
# The incoming_filter call is only made on top level stanza
|
||||
# elements. So we manually continue filtering on sub-elements.
|
||||
for sub in xml:
|
||||
self.incoming_filter(sub)
|
||||
|
||||
return xml
|
||||
|
||||
def start_stream_handler(self, xml):
|
||||
"""
|
||||
Once the streams are established, attempt to handshake
|
||||
with the server to be accepted as a component.
|
||||
|
||||
Overrides XMLStream.start_stream_handler.
|
||||
|
||||
Arguments:
|
||||
xml -- The incoming stream's root element.
|
||||
"""
|
||||
# Construct a hash of the stream ID and the component secret.
|
||||
sid = xml.get('id', '')
|
||||
pre_hash = '%s%s' % (sid, self.secret)
|
||||
if sys.version_info >= (3, 0):
|
||||
# Handle Unicode byte encoding in Python 3.
|
||||
pre_hash = bytes(pre_hash, 'utf-8')
|
||||
|
||||
handshake = ET.Element('{jabber:component:accept}handshake')
|
||||
handshake.text = hashlib.sha1(pre_hash).hexdigest().lower()
|
||||
self.send_xml(handshake)
|
||||
|
||||
def _handle_handshake(self, xml):
|
||||
"""
|
||||
The handshake has been accepted.
|
||||
|
||||
Arguments:
|
||||
xml -- The reply handshake stanza.
|
||||
"""
|
||||
self.event("session_start")
|
||||
|
|
Loading…
Reference in a new issue