Compare commits
26 Commits
sleek-1.2.
...
sleek-1.3.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
753cb3580e | ||
|
|
60b050b82a | ||
|
|
ad91a8cd5e | ||
|
|
02f79fc94b | ||
|
|
230a73fad2 | ||
|
|
d94dd486fe | ||
|
|
6ecc39b816 | ||
|
|
9c240df9db | ||
|
|
a918bf3a95 | ||
|
|
9434ae267f | ||
|
|
94187d215a | ||
|
|
ef2f5d2978 | ||
|
|
62671e0f56 | ||
|
|
93869f77a0 | ||
|
|
8282d135cc | ||
|
|
9acc78c81d | ||
|
|
3642469630 | ||
|
|
34cd20339c | ||
|
|
7548f44047 | ||
|
|
7cf55ef695 | ||
|
|
543250da13 | ||
|
|
69e55d7316 | ||
|
|
158411e918 | ||
|
|
3f873002c4 | ||
|
|
818f4e5973 | ||
|
|
c8d6e512d2 |
@@ -45,7 +45,7 @@ The latest source code for SleekXMPP may be found on `Github
|
||||
``develop`` branch.
|
||||
|
||||
**Latest Release**
|
||||
- `1.1.11 <http://github.com/fritzy/SleekXMPP/zipball/1.1.11>`_
|
||||
- `1.3.0 <http://github.com/fritzy/SleekXMPP/zipball/1.3.0>`_
|
||||
|
||||
**Develop Releases**
|
||||
- `Latest Develop Version <http://github.com/fritzy/SleekXMPP/zipball/develop>`_
|
||||
|
||||
8
setup.py
8
setup.py
@@ -87,8 +87,8 @@ packages = [ 'sleekxmpp',
|
||||
'sleekxmpp/plugins/xep_0086',
|
||||
'sleekxmpp/plugins/xep_0091',
|
||||
'sleekxmpp/plugins/xep_0092',
|
||||
'sleekxmpp/plugins/xep_0095',
|
||||
'sleekxmpp/plugins/xep_0096',
|
||||
'sleekxmpp/plugins/xep_0095',
|
||||
'sleekxmpp/plugins/xep_0096',
|
||||
'sleekxmpp/plugins/xep_0107',
|
||||
'sleekxmpp/plugins/xep_0108',
|
||||
'sleekxmpp/plugins/xep_0115',
|
||||
@@ -119,6 +119,10 @@ packages = [ 'sleekxmpp',
|
||||
'sleekxmpp/plugins/xep_0308',
|
||||
'sleekxmpp/plugins/xep_0313',
|
||||
'sleekxmpp/plugins/xep_0319',
|
||||
'sleekxmpp/plugins/xep_0323',
|
||||
'sleekxmpp/plugins/xep_0323/stanza',
|
||||
'sleekxmpp/plugins/xep_0325',
|
||||
'sleekxmpp/plugins/xep_0325/stanza',
|
||||
'sleekxmpp/plugins/google',
|
||||
'sleekxmpp/plugins/google/gmail',
|
||||
'sleekxmpp/plugins/google/auth',
|
||||
|
||||
@@ -136,7 +136,7 @@ class ClientXMPP(BaseXMPP):
|
||||
be attempted. If that fails, the server user in the JID
|
||||
will be used.
|
||||
|
||||
:param address -- A tuple containing the server's host and port.
|
||||
:param address: A tuple containing the server's host and port.
|
||||
:param reattempt: If ``True``, repeat attempting to connect if an
|
||||
error occurs. Defaults to ``True``.
|
||||
:param use_tls: Indicates if TLS should be used for the
|
||||
|
||||
@@ -215,6 +215,8 @@ class FeatureMechanisms(BasePlugin):
|
||||
self.attempted_mechs.add(self.mech.name)
|
||||
self.xmpp.disconnect()
|
||||
else:
|
||||
if resp.get_value() == '':
|
||||
resp.del_value()
|
||||
resp.send(now=True)
|
||||
|
||||
def _handle_success(self, stanza):
|
||||
|
||||
@@ -304,7 +304,7 @@ class XEP_0045(BasePlugin):
|
||||
room), whereas affiliations are permanent (they last across groupchat
|
||||
sessions).
|
||||
"""
|
||||
if role not in ('outcast', 'member', 'admin', 'owner', 'none'):
|
||||
if role not in ('moderator', 'participant', 'visitor', 'none'):
|
||||
raise TypeError
|
||||
query = ET.Element('{http://jabber.org/protocol/muc#admin}query')
|
||||
item = ET.Element('item', {'role':role, 'nick':nick})
|
||||
|
||||
@@ -124,10 +124,12 @@ class XEP_0153(BasePlugin):
|
||||
log.debug('Could not retrieve vCard for %s' % jid)
|
||||
|
||||
def _recv_presence(self, pres):
|
||||
if pres['muc']['affiliation']:
|
||||
# Don't process vCard avatars for MUC occupants
|
||||
# since they all share the same bare JID.
|
||||
return
|
||||
try:
|
||||
if pres['muc']['affiliation']:
|
||||
# Don't process vCard avatars for MUC occupants
|
||||
# since they all share the same bare JID.
|
||||
return
|
||||
except: pass
|
||||
|
||||
if not pres.match('presence/vcard_temp_update'):
|
||||
self.api['set_hash'](pres['from'], args=None)
|
||||
|
||||
@@ -118,6 +118,9 @@ class XEP_0184(BasePlugin):
|
||||
if stanza['receipt']:
|
||||
return stanza
|
||||
|
||||
if not stanza['body']:
|
||||
return stanza
|
||||
|
||||
if stanza['to'].resource:
|
||||
if not self.xmpp['xep_0030'].supports(stanza['to'],
|
||||
feature='urn:xmpp:receipts',
|
||||
|
||||
@@ -154,6 +154,7 @@ class XEP_0199(BasePlugin):
|
||||
timeout -- Time in seconds to wait for a response.
|
||||
Defaults to self.timeout.
|
||||
"""
|
||||
own_host = False
|
||||
if not jid:
|
||||
if self.xmpp.is_component:
|
||||
jid = self.xmpp.server
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
from sleekxmpp.stanza.rootstanza import RootStanza
|
||||
from sleekxmpp.xmlstream import StanzaBase, ET
|
||||
from sleekxmpp.xmlstream.handler import Waiter, Callback
|
||||
from sleekxmpp.xmlstream.matcher import MatchIDSender
|
||||
from sleekxmpp.xmlstream.matcher import MatchIDSender, MatcherId
|
||||
from sleekxmpp.exceptions import IqTimeout, IqError
|
||||
|
||||
|
||||
@@ -194,11 +194,14 @@ class Iq(RootStanza):
|
||||
if timeout is None:
|
||||
timeout = self.stream.response_timeout
|
||||
|
||||
criteria = {
|
||||
'id': self['id'],
|
||||
'self': self.stream.boundjid,
|
||||
'peer': self['to']
|
||||
}
|
||||
if self.stream.session_bind_event.is_set():
|
||||
matcher = MatchIDSender({
|
||||
'id': self['id'],
|
||||
'self': self.stream.boundjid,
|
||||
'peer': self['to']
|
||||
})
|
||||
else:
|
||||
matcher = MatcherId(self['id'])
|
||||
|
||||
if callback is not None and self['type'] in ('get', 'set'):
|
||||
handler_name = 'IqCallback_%s' % self['id']
|
||||
@@ -210,19 +213,19 @@ class Iq(RootStanza):
|
||||
self._fire_timeout,
|
||||
repeat=False)
|
||||
handler = Callback(handler_name,
|
||||
MatchIDSender(criteria),
|
||||
matcher,
|
||||
self._handle_result,
|
||||
once=True)
|
||||
else:
|
||||
handler = Callback(handler_name,
|
||||
MatchIDSender(criteria),
|
||||
matcher,
|
||||
callback,
|
||||
once=True)
|
||||
self.stream.register_handler(handler)
|
||||
StanzaBase.send(self, now=now)
|
||||
return handler_name
|
||||
elif block and self['type'] in ('get', 'set'):
|
||||
waitfor = Waiter('IqWait_%s' % self['id'], MatchIDSender(criteria))
|
||||
waitfor = Waiter('IqWait_%s' % self['id'], matcher)
|
||||
self.stream.register_handler(waitfor)
|
||||
StanzaBase.send(self, now=now)
|
||||
result = waitfor.wait(timeout)
|
||||
|
||||
@@ -376,6 +376,7 @@ class SleekTest(unittest.TestCase):
|
||||
if skip:
|
||||
if socket != 'live':
|
||||
# Mark send queue as usable
|
||||
self.xmpp.session_bind_event.set()
|
||||
self.xmpp.session_started_event.set()
|
||||
# Clear startup stanzas
|
||||
self.xmpp.socket.next_sent(timeout=1)
|
||||
|
||||
@@ -287,7 +287,9 @@ class SCRAM(Mech):
|
||||
if nonce[:len(self.cnonce)] != self.cnonce:
|
||||
raise SASLCancelled('Invalid nonce')
|
||||
|
||||
cbind_data = self.credentials['channel_binding']
|
||||
cbind_data = b''
|
||||
if self.use_channel_binding:
|
||||
cbind_data = self.credentials['channel_binding']
|
||||
cbind_input = self.gs2_header + cbind_data
|
||||
channel_binding = b'c=' + b64encode(cbind_input).replace(b'\n', b'')
|
||||
|
||||
@@ -530,6 +532,9 @@ else:
|
||||
result = kerberos.authGSSClientStep(self.gss, b64_challenge)
|
||||
if result != kerberos.AUTH_GSS_CONTINUE:
|
||||
self.step = 1
|
||||
elif not challenge:
|
||||
kerberos.authGSSClientClean(self.gss)
|
||||
return b''
|
||||
elif self.step == 1:
|
||||
username = self.credentials['username']
|
||||
|
||||
@@ -539,7 +544,7 @@ else:
|
||||
|
||||
resp = kerberos.authGSSClientResponse(self.gss)
|
||||
except kerberos.GSSError as e:
|
||||
raise SASLCancelled('Kerberos error: %s' % e.message)
|
||||
raise SASLCancelled('Kerberos error: %s' % e)
|
||||
if not resp:
|
||||
return b''
|
||||
else:
|
||||
|
||||
@@ -9,5 +9,5 @@
|
||||
# We don't want to have to import the entire library
|
||||
# just to get the version info for setup.py
|
||||
|
||||
__version__ = '1.2.0'
|
||||
__version_info__ = (1, 2, 0, '', 0)
|
||||
__version__ = '1.3.0'
|
||||
__version_info__ = (1, 3, 0, '', 0)
|
||||
|
||||
@@ -32,10 +32,10 @@ log = logging.getLogger(__name__)
|
||||
#: cd dnspython
|
||||
#: git checkout python3
|
||||
#: python3 setup.py install
|
||||
USE_DNSPYTHON = False
|
||||
DNSPYTHON_AVAILABLE = False
|
||||
try:
|
||||
import dns.resolver
|
||||
USE_DNSPYTHON = True
|
||||
DNSPYTHON_AVAILABLE = True
|
||||
except ImportError as e:
|
||||
log.debug("Could not find dnspython package. " + \
|
||||
"Not all features will be available")
|
||||
@@ -47,13 +47,13 @@ def default_resolver():
|
||||
:returns: A :class:`dns.resolver.Resolver` object if dnspython
|
||||
is available. Otherwise, ``None``.
|
||||
"""
|
||||
if USE_DNSPYTHON:
|
||||
if DNSPYTHON_AVAILABLE:
|
||||
return dns.resolver.get_default_resolver()
|
||||
return None
|
||||
|
||||
|
||||
def resolve(host, port=None, service=None, proto='tcp',
|
||||
resolver=None, use_ipv6=True):
|
||||
resolver=None, use_ipv6=True, use_dnspython=True):
|
||||
"""Peform DNS resolution for a given hostname.
|
||||
|
||||
Resolution may perform SRV record lookups if a service and protocol
|
||||
@@ -77,6 +77,9 @@ def resolve(host, port=None, service=None, proto='tcp',
|
||||
:param use_ipv6: Optionally control the use of IPv6 in situations
|
||||
where it is either not available, or performance
|
||||
is degraded. Defaults to ``True``.
|
||||
:param use_dnspython: Optionally control if dnspython is used to make
|
||||
the DNS queries instead of the built-in DNS
|
||||
library.
|
||||
|
||||
:type host: string
|
||||
:type port: int
|
||||
@@ -84,14 +87,22 @@ def resolve(host, port=None, service=None, proto='tcp',
|
||||
:type proto: string
|
||||
:type resolver: :class:`dns.resolver.Resolver`
|
||||
:type use_ipv6: bool
|
||||
:type use_dnspython: bool
|
||||
|
||||
:return: An iterable of IP address, port pairs in the order
|
||||
dictated by SRV priorities and weights, if applicable.
|
||||
"""
|
||||
|
||||
if not use_dnspython:
|
||||
if DNSPYTHON_AVAILABLE:
|
||||
log.debug("DNS: Not using dnspython, but dnspython is installed.")
|
||||
else:
|
||||
log.debug("DNS: Not using dnspython.")
|
||||
|
||||
if not use_ipv6:
|
||||
log.debug("DNS: Use of IPv6 has been disabled.")
|
||||
|
||||
if resolver is None and USE_DNSPYTHON:
|
||||
if resolver is None and DNSPYTHON_AVAILABLE and use_dnspython:
|
||||
resolver = dns.resolver.get_default_resolver()
|
||||
|
||||
# An IPv6 literal is allowed to be enclosed in square brackets, but
|
||||
@@ -122,7 +133,9 @@ def resolve(host, port=None, service=None, proto='tcp',
|
||||
if not service:
|
||||
hosts = [(host, port)]
|
||||
else:
|
||||
hosts = get_SRV(host, port, service, proto, resolver=resolver)
|
||||
hosts = get_SRV(host, port, service, proto,
|
||||
resolver=resolver,
|
||||
use_dnspython=use_dnspython)
|
||||
|
||||
for host, port in hosts:
|
||||
results = []
|
||||
@@ -131,16 +144,18 @@ def resolve(host, port=None, service=None, proto='tcp',
|
||||
results.append((host, '::1', port))
|
||||
results.append((host, '127.0.0.1', port))
|
||||
if use_ipv6:
|
||||
for address in get_AAAA(host):
|
||||
for address in get_AAAA(host, resolver=resolver,
|
||||
use_dnspython=use_dnspython):
|
||||
results.append((host, address, port))
|
||||
for address in get_A(host):
|
||||
for address in get_A(host, resolver=resolver,
|
||||
use_dnspython=use_dnspython):
|
||||
results.append((host, address, port))
|
||||
|
||||
for host, address, port in results:
|
||||
yield host, address, port
|
||||
|
||||
|
||||
def get_A(host):
|
||||
def get_A(host, resolver=None, use_dnspython=True):
|
||||
"""Lookup DNS A records for a given host.
|
||||
|
||||
If ``resolver`` is not provided, or is ``None``, then resolution will
|
||||
@@ -148,9 +163,13 @@ def get_A(host):
|
||||
|
||||
:param host: The hostname to resolve for A record IPv4 addresses.
|
||||
:param resolver: Optional DNS resolver object to use for the query.
|
||||
:param use_dnspython: Optionally control if dnspython is used to make
|
||||
the DNS queries instead of the built-in DNS
|
||||
library.
|
||||
|
||||
:type host: string
|
||||
:type resolver: :class:`dns.resolver.Resolver` or ``None``
|
||||
:type use_dnspython: bool
|
||||
|
||||
:return: A list of IPv4 literals.
|
||||
"""
|
||||
@@ -158,15 +177,32 @@ def get_A(host):
|
||||
|
||||
# If not using dnspython, attempt lookup using the OS level
|
||||
# getaddrinfo() method.
|
||||
if resolver is None or not use_dnspython:
|
||||
try:
|
||||
recs = socket.getaddrinfo(host, None, socket.AF_INET,
|
||||
socket.SOCK_STREAM)
|
||||
return [rec[4][0] for rec in recs]
|
||||
except socket.gaierror:
|
||||
log.debug("DNS: Error retreiving A address info for %s." % host)
|
||||
return []
|
||||
|
||||
# Using dnspython:
|
||||
try:
|
||||
recs = socket.getaddrinfo(host, None, socket.AF_INET,
|
||||
socket.SOCK_STREAM)
|
||||
return [rec[4][0] for rec in recs]
|
||||
except socket.gaierror:
|
||||
log.debug("DNS: Error retreiving A address info for %s." % host)
|
||||
recs = resolver.query(host, dns.rdatatype.A)
|
||||
return [rec.to_text() for rec in recs]
|
||||
except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer):
|
||||
log.debug("DNS: No A records for %s" % host)
|
||||
return []
|
||||
except dns.exception.Timeout:
|
||||
log.debug("DNS: A record resolution timed out for %s" % host)
|
||||
return []
|
||||
except dns.exception.DNSException as e:
|
||||
log.debug("DNS: Error querying A records for %s" % host)
|
||||
log.exception(e)
|
||||
return []
|
||||
|
||||
def get_AAAA(host):
|
||||
|
||||
def get_AAAA(host, resolver=None, use_dnspython=True):
|
||||
"""Lookup DNS AAAA records for a given host.
|
||||
|
||||
If ``resolver`` is not provided, or is ``None``, then resolution will
|
||||
@@ -174,9 +210,13 @@ def get_AAAA(host):
|
||||
|
||||
:param host: The hostname to resolve for AAAA record IPv6 addresses.
|
||||
:param resolver: Optional DNS resolver object to use for the query.
|
||||
:param use_dnspython: Optionally control if dnspython is used to make
|
||||
the DNS queries instead of the built-in DNS
|
||||
library.
|
||||
|
||||
:type host: string
|
||||
:type resolver: :class:`dns.resolver.Resolver` or ``None``
|
||||
:type use_dnspython: bool
|
||||
|
||||
:return: A list of IPv6 literals.
|
||||
"""
|
||||
@@ -184,19 +224,36 @@ def get_AAAA(host):
|
||||
|
||||
# If not using dnspython, attempt lookup using the OS level
|
||||
# getaddrinfo() method.
|
||||
if not socket.has_ipv6:
|
||||
log.debug("Unable to query %s for AAAA records: IPv6 is not supported", host)
|
||||
return []
|
||||
if resolver is None or not use_dnspython:
|
||||
if not socket.has_ipv6:
|
||||
log.debug("Unable to query %s for AAAA records: IPv6 is not supported", host)
|
||||
return []
|
||||
try:
|
||||
recs = socket.getaddrinfo(host, None, socket.AF_INET6,
|
||||
socket.SOCK_STREAM)
|
||||
return [rec[4][0] for rec in recs]
|
||||
except (OSError, socket.gaierror):
|
||||
log.debug("DNS: Error retreiving AAAA address " + \
|
||||
"info for %s." % host)
|
||||
return []
|
||||
|
||||
# Using dnspython:
|
||||
try:
|
||||
recs = socket.getaddrinfo(host, None, socket.AF_INET6,
|
||||
socket.SOCK_STREAM)
|
||||
return [rec[4][0] for rec in recs]
|
||||
except (OSError, socket.gaierror):
|
||||
log.debug("DNS: Error retreiving AAAA address " + \
|
||||
"info for %s." % host)
|
||||
recs = resolver.query(host, dns.rdatatype.AAAA)
|
||||
return [rec.to_text() for rec in recs]
|
||||
except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer):
|
||||
log.debug("DNS: No AAAA records for %s" % host)
|
||||
return []
|
||||
except dns.exception.Timeout:
|
||||
log.debug("DNS: AAAA record resolution timed out for %s" % host)
|
||||
return []
|
||||
except dns.exception.DNSException as e:
|
||||
log.debug("DNS: Error querying AAAA records for %s" % host)
|
||||
log.exception(e)
|
||||
return []
|
||||
|
||||
def get_SRV(host, port, service, proto='tcp', resolver=None):
|
||||
|
||||
def get_SRV(host, port, service, proto='tcp', resolver=None, use_dnspython=True):
|
||||
"""Perform SRV record resolution for a given host.
|
||||
|
||||
.. note::
|
||||
@@ -222,7 +279,7 @@ def get_SRV(host, port, service, proto='tcp', resolver=None):
|
||||
:return: A list of hostname, port pairs in the order dictacted
|
||||
by SRV priorities and weights.
|
||||
"""
|
||||
if resolver is None:
|
||||
if resolver is None or not use_dnspython:
|
||||
log.warning("DNS: dnspython not found. Can not use SRV lookup.")
|
||||
return [(host, port)]
|
||||
|
||||
|
||||
@@ -224,6 +224,11 @@ class XMLStream(object):
|
||||
#: If set to ``True``, attempt to use IPv6.
|
||||
self.use_ipv6 = True
|
||||
|
||||
#: If set to ``True``, allow using the ``dnspython`` DNS library
|
||||
#: if available. If set to ``False``, the builtin DNS resolver
|
||||
#: will be used, even if ``dnspython`` is installed.
|
||||
self.use_dnspython = True
|
||||
|
||||
#: Use CDATA for escaping instead of XML entities. Defaults
|
||||
#: to ``False``.
|
||||
self.use_cdata = False
|
||||
@@ -514,11 +519,11 @@ class XMLStream(object):
|
||||
cert_policy = ssl.CERT_REQUIRED
|
||||
|
||||
ssl_args = {
|
||||
'certfile': self.certfile,
|
||||
'keyfile': self.keyfile,
|
||||
'ca_certs': self.ca_certs,
|
||||
'cert_reqs': cert_policy,
|
||||
'do_handshake_on_connect': False,
|
||||
b'certfile': self.certfile,
|
||||
b'keyfile': self.keyfile,
|
||||
b'ca_certs': self.ca_certs,
|
||||
b'cert_reqs': cert_policy,
|
||||
b'do_handshake_on_connect': False,
|
||||
}
|
||||
|
||||
if sys.version_info >= (2, 7):
|
||||
@@ -611,7 +616,7 @@ class XMLStream(object):
|
||||
headers = '\r\n'.join(headers) + '\r\n\r\n'
|
||||
|
||||
try:
|
||||
log.debug("Connecting to proxy: %s:%s", address)
|
||||
log.debug("Connecting to proxy: %s:%s", *address)
|
||||
self.socket.connect(address)
|
||||
self.send_raw(headers, now=True)
|
||||
resp = ''
|
||||
@@ -838,11 +843,11 @@ class XMLStream(object):
|
||||
cert_policy = ssl.CERT_REQUIRED
|
||||
|
||||
ssl_args = {
|
||||
'certfile': self.certfile,
|
||||
'keyfile': self.keyfile,
|
||||
'ca_certs': self.ca_certs,
|
||||
'cert_reqs': cert_policy,
|
||||
'do_handshake_on_connect': False,
|
||||
b'certfile': self.certfile,
|
||||
b'keyfile': self.keyfile,
|
||||
b'ca_certs': self.ca_certs,
|
||||
b'cert_reqs': cert_policy,
|
||||
b'do_handshake_on_connect': False,
|
||||
}
|
||||
|
||||
if sys.version_info >= (2, 7):
|
||||
@@ -1081,7 +1086,8 @@ class XMLStream(object):
|
||||
|
||||
return resolve(domain, port, service=self.dns_service,
|
||||
resolver=resolver,
|
||||
use_ipv6=self.use_ipv6)
|
||||
use_ipv6=self.use_ipv6,
|
||||
use_dnspython=self.use_dnspython)
|
||||
|
||||
def pick_dns_answer(self, domain, port=None):
|
||||
"""Pick a server and port from DNS answers.
|
||||
|
||||
Reference in New Issue
Block a user