Merge branch 'master' into develop

This commit is contained in:
Lance Stout 2012-09-13 11:00:58 -07:00
commit 67147570e9
14 changed files with 328 additions and 2 deletions

View File

@ -66,6 +66,7 @@ packages = [ 'sleekxmpp',
'sleekxmpp/plugins/xep_0030/stanza',
'sleekxmpp/plugins/xep_0033',
'sleekxmpp/plugins/xep_0047',
'sleekxmpp/plugins/xep_0049',
'sleekxmpp/plugins/xep_0050',
'sleekxmpp/plugins/xep_0054',
'sleekxmpp/plugins/xep_0059',
@ -98,8 +99,10 @@ packages = [ 'sleekxmpp',
'sleekxmpp/plugins/xep_0221',
'sleekxmpp/plugins/xep_0224',
'sleekxmpp/plugins/xep_0231',
'sleekxmpp/plugins/xep_0235',
'sleekxmpp/plugins/xep_0249',
'sleekxmpp/plugins/xep_0258',
'sleekxmpp/plugins/xep_0279',
'sleekxmpp/features',
'sleekxmpp/features/feature_mechanisms',
'sleekxmpp/features/feature_mechanisms/stanza',

View File

@ -24,6 +24,7 @@ __all__ = [
'xep_0033', # Extended Stanza Addresses
'xep_0045', # Multi-User Chat (Client)
'xep_0047', # In-Band Bytestreams
'xep_0049', # Private XML Storage
'xep_0050', # Ad-hoc Commands
'xep_0054', # vcard-temp
'xep_0059', # Result Set Management
@ -61,10 +62,12 @@ __all__ = [
'xep_0223', # Persistent Storage of Private Data via Pubsub
'xep_0224', # Attention
'xep_0231', # Bits of Binary
'xep_0235', # OAuth Over XMPP
'xep_0242', # XMPP Client Compliance 2009
'xep_0249', # Direct MUC Invitations
'xep_0256', # Last Activity in Presence
'xep_0258', # Security Labels in XMPP
'xep_0270', # XMPP Compliance Suites 2010
'xep_0279', # Server IP Check
'xep_0302', # XMPP Compliance Suites 2012
]

View File

@ -0,0 +1,15 @@
"""
SleekXMPP: The Sleek XMPP Library
Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
This file is part of SleekXMPP.
See the file LICENSE for copying permission.
"""
from sleekxmpp.plugins.base import register_plugin
from sleekxmpp.plugins.xep_0049.stanza import PrivateXML
from sleekxmpp.plugins.xep_0049.private_storage import XEP_0049
register_plugin(XEP_0049)

View File

@ -0,0 +1,53 @@
"""
SleekXMPP: The Sleek XMPP Library
Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
This file is part of SleekXMPP.
See the file LICENSE for copying permission.
"""
import logging
from sleekxmpp import Iq
from sleekxmpp.plugins import BasePlugin
from sleekxmpp.xmlstream.handler import Callback
from sleekxmpp.xmlstream.matcher import StanzaPath
from sleekxmpp.xmlstream import register_stanza_plugin
from sleekxmpp.plugins.xep_0049 import stanza, PrivateXML
log = logging.getLogger(__name__)
class XEP_0049(BasePlugin):
name = 'xep_0049'
description = 'XEP-0049: Private XML Storage'
dependencies = set([])
stanza = stanza
def plugin_init(self):
register_stanza_plugin(Iq, PrivateXML)
def register(self, stanza):
register_stanza_plugin(PrivateXML, stanza, iterable=True)
def store(self, data, ifrom=None, block=True, timeout=None, callback=None):
iq = self.xmpp.Iq()
iq['type'] = 'set'
iq['from'] = ifrom
if not isinstance(data, list):
data = [data]
for elem in data:
iq['private'].append(elem)
return iq.send(block=block, timeout=timeout, callback=callback)
def retrieve(self, name, ifrom=None, block=True, timeout=None, callback=None):
iq = self.xmpp.Iq()
iq['type'] = 'get'
iq['from'] = ifrom
iq['private'].enable(name)
return iq.send(block=block, timeout=timeout, callback=callback)

View File

@ -0,0 +1,17 @@
"""
SleekXMPP: The Sleek XMPP Library
Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
This file is part of SleekXMPP.
See the file LICENSE for copying permission.
"""
from sleekxmpp.xmlstream import ET, ElementBase
class PrivateXML(ElementBase):
name = 'query'
namespace = 'jabber:iq:private'
plugin_attrib = 'private'
interfaces = set()

View File

@ -143,6 +143,11 @@ class XEP_0115(BasePlugin):
if str(existing_verstring) == str(pres['caps']['ver']):
return
existing_caps = self.get_caps(verstring=pres['caps']['ver'])
if existing_caps is not None:
self.assign_verstring(pres['from'], pres['caps']['ver'])
return
if pres['caps']['hash'] not in self.hashes:
try:
log.debug("Unknown caps hash: %s", pres['caps']['hash'])

View File

@ -0,0 +1,16 @@
"""
SleekXMPP: The Sleek XMPP Library
Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
This file is part of SleekXMPP.
See the file LICENSE for copying permission.
"""
from sleekxmpp.plugins.base import register_plugin
from sleekxmpp.plugins.xep_0235 import stanza
from sleekxmpp.plugins.xep_0235.stanza import OAuth
from sleekxmpp.plugins.xep_0235.oauth import XEP_0235
register_plugin(XEP_0235)

View File

@ -0,0 +1,32 @@
"""
SleekXMPP: The Sleek XMPP Library
Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
This file is part of SleekXMPP.
See the file LICENSE for copying permission.
"""
import logging
from sleekxmpp import Message
from sleekxmpp.plugins import BasePlugin
from sleekxmpp.xmlstream import register_stanza_plugin
from sleekxmpp.plugins.xep_0235 import stanza, OAuth
class XEP_0235(BasePlugin):
name = 'xep_0235'
description = 'XEP-0235: OAuth Over XMPP'
dependencies = set(['xep_0030'])
stanza = stanza
def plugin_init(self):
register_stanza_plugin(Message, OAuth)
def session_bind(self, jid):
self.xmpp['xep_0030'].add_feature('urn:xmpp:oauth:0')
def plugin_end(self):
self.xmpp['xep_0030'].del_feature(feature='urn:xmpp:oauth:0')

View File

@ -0,0 +1,80 @@
"""
SleekXMPP: The Sleek XMPP Library
Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
This file is part of SleekXMPP.
See the file LICENSE for copying permission.
"""
import hmac
import hashlib
import urllib
import base64
from sleekxmpp.xmlstream import ET, ElementBase, JID
class OAuth(ElementBase):
name = 'oauth'
namespace = 'urn:xmpp:oauth:0'
plugin_attrib = 'oauth'
interfaces = set(['oauth_consumer_key', 'oauth_nonce', 'oauth_signature',
'oauth_signature_method', 'oauth_timestamp',
'oauth_token', 'oauth_version'])
sub_interfaces = interfaces
def generate_signature(self, stanza, sfrom, sto, consumer_secret,
token_secret, method='HMAC-SHA1'):
self['oauth_signature_method'] = method
request = urllib.quote('%s&%s' % (sfrom, sto), '')
parameters = urllib.quote('&'.join([
'oauth_consumer_key=%s' % self['oauth_consumer_key'],
'oauth_nonce=%s' % self['oauth_nonce'],
'oauth_signature_method=%s' % self['oauth_signature_method'],
'oauth_timestamp=%s' % self['oauth_timestamp'],
'oauth_token=%s' % self['oauth_token'],
'oauth_version=%s' % self['oauth_version']
]), '')
sigbase = '%s&%s&%s' % (stanza, request, parameters)
consumer_secret = urllib.quote(consumer_secret, '')
token_secret = urllib.quote(token_secret, '')
key = '%s&%s' % (consumer_secret, token_secret)
if method == 'HMAC-SHA1':
sig = base64.b64encode(hmac.new(key, sigbase, hashlib.sha1).digest())
elif method == 'PLAINTEXT':
sig = key
self['oauth_signature'] = sig
return sig
def verify_signature(self, stanza, sfrom, sto, consumer_secret,
token_secret):
method = self['oauth_signature_method']
request = urllib.quote('%s&%s' % (sfrom, sto), '')
parameters = urllib.quote('&'.join([
'oauth_consumer_key=%s' % self['oauth_consumer_key'],
'oauth_nonce=%s' % self['oauth_nonce'],
'oauth_signature_method=%s' % self['oauth_signature_method'],
'oauth_timestamp=%s' % self['oauth_timestamp'],
'oauth_token=%s' % self['oauth_token'],
'oauth_version=%s' % self['oauth_version']
]), '')
sigbase = '%s&%s&%s' % (stanza, request, parameters)
consumer_secret = urllib.quote(consumer_secret, '')
token_secret = urllib.quote(token_secret, '')
key = '%s&%s' % (consumer_secret, token_secret)
if method == 'HMAC-SHA1':
sig = base64.b64encode(hmac.new(key, sigbase, hashlib.sha1).digest())
elif method == 'PLAINTEXT':
sig = key
return self['oauth_signature'] == sig

View File

@ -0,0 +1,16 @@
"""
SleekXMPP: The Sleek XMPP Library
Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
This file is part of SleekXMPP.
See the file LICENSE for copying permission.
"""
from sleekxmpp.plugins.base import register_plugin
from sleekxmpp.plugins.xep_0279 import stanza
from sleekxmpp.plugins.xep_0279.stanza import IPCheck
from sleekxmpp.plugins.xep_0279.ipcheck import XEP_0279
register_plugin(XEP_0279)

View File

@ -0,0 +1,39 @@
"""
SleekXMPP: The Sleek XMPP Library
Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
This file is part of SleekXMPP.
See the file LICENSE for copying permission.
"""
import logging
from sleekxmpp import Iq
from sleekxmpp.plugins import BasePlugin
from sleekxmpp.xmlstream import register_stanza_plugin
from sleekxmpp.plugins.xep_0279 import stanza, IPCheck
class XEP_0279(BasePlugin):
name = 'xep_0279'
description = 'XEP-0279: Server IP Check'
dependencies = set(['xep_0030'])
stanza = stanza
def plugin_init(self):
register_stanza_plugin(Iq, IPCheck)
def session_bind(self, jid):
self.xmpp['xep_0030'].add_feature('urn:xmpp:sic:0')
def plugin_end(self):
self.xmpp['xep_0030'].del_feature(feature='urn:xmpp:sic:0')
def check_ip(self, ifrom=None, block=True, timeout=None, callback=None):
iq = self.xmpp.Iq()
iq['type'] = 'get'
iq['from'] = ifrom
iq.enable('ip_check')
return iq.send(block=block, timeout=timeout, callback=callback)

View File

@ -0,0 +1,30 @@
"""
SleekXMPP: The Sleek XMPP Library
Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
This file is part of SleekXMPP.
See the file LICENSE for copying permission.
"""
from sleekxmpp.xmlstream import ElementBase
class IPCheck(ElementBase):
name = 'ip'
namespace = 'urn:xmpp:sic:0'
plugin_attrib = 'ip_check'
interfaces = set(['ip_check'])
is_extension = True
def get_ip_check(self):
return self.xml.text
def set_ip_check(self, value):
if value:
self.xml.text = value
else:
self.xml.text = ''
def del_ip_check(self):
self.xml.text = ''

View File

@ -123,6 +123,17 @@ class X_MESSENGER_OAUTH2(Mech):
return self.credentials['access_token']
@sasl_mech(10)
class X_OAUTH2(Mech):
name = 'X-OAUTH2'
required_credentials = set(['username', 'access_token'])
def process(self, challenge=b''):
return b'\x00' + self.credentials['username'] + \
b'\x00' + self.credentials['access_token']
@sasl_mech(3)
class X_GOOGLE_TOKEN(Mech):

View File

@ -147,7 +147,10 @@ def verify(expected, raw_cert):
raise CertificateError(
'Certificate has expired.')
expected_wild = expected[expected.index('.'):]
if '.' in expected:
expected_wild = expected[expected.index('.'):]
else:
expected_wild = expected
expected_srv = '_xmpp-client.%s' % expected
for name in cert_names['XMPPAddr']:
@ -160,7 +163,10 @@ def verify(expected, raw_cert):
if name == expected:
return True
if name.startswith('*'):
name_wild = name[name.index('.'):]
if '.' in name:
name_wild = name[name.index('.'):]
else:
name_wild = name
if expected_wild == name_wild:
return True
for name in cert_names['URI']: