# Path: pyxmpp2/sasl/core.py
# class ClientAuthenticator:
#     """Base class for client authenticators.
# 
#     A client authenticator class is a client-side implementation of a SASL
#     mechanism. One `ClientAuthenticator` object may be used for one
#     client authentication process.
#     """
#     __metaclass__ = ABCMeta
#     def __init__(self):
#         """Initialize a `ClientAuthenticator` object."""
#         pass
# 
#     @abstractclassmethod
#     def are_properties_sufficient(cls, properties):
#         """Check if the provided properties are sufficient for
#         this authentication mechanism.
# 
#         If `are_properties_sufficient` returns False for given `properties`
#         mapping, the `start` method of `cls` instance will also fail with
#         such argument.
# 
#         :Parameters:
#             - `properties`: the `authentication properties`_
#         :Types:
#             - `properties`: mapping
# 
#         :Return: if the mechanism can be used with those properties
#         """
#         # pylint: disable=E0213,W0613,R0201
#         return False
# 
#     @abstractmethod
#     def start(self, properties):
#         """Start the authentication process.
# 
#         :Parameters:
#             - `properties`: the `authentication properties`_
#         :Types:
#             - `properties`: mapping
# 
#         :return: the initial response to send to the server or a failuer
#             indicator.
#         :returntype: `Response` or `Failure`
#         """
#         raise NotImplementedError
# 
#     @abstractmethod
#     def challenge(self, challenge):
#         """Process the server's challenge.
# 
#         :Parameters:
#             - `challenge`: the challenge.
#         :Types:
#             - `challenge`: `bytes`
# 
#         :return: the response or a failure indicator.
#         :returntype: `Response` or `Failure`"""
#         raise NotImplementedError
# 
#     @abstractmethod
#     def finish(self, data):
#         """Handle authentication succes information from the server.
# 
#         :Parameters:
#             - `data`: the optional additional data returned with the success.
#         :Types:
#             - `data`: `bytes`
# 
#         :return: success or failure indicator.
#         :returntype: `Success` or `Failure`"""
#         raise NotImplementedError
# 
# class Response(Reply):
#     """The response SASL message (clients's reply the server's
#     challenge)."""
#     # pylint: disable-msg=R0903
#     def __init__(self, data):
#         """Initialize the `Response` object."""
#         Reply.__init__(self, data)
#     def __repr__(self):
#         return "<sasl.Response: {0!r}>".format(self.data)
# 
# class Success(Reply):
#     """The success SASL message (sent by the server on authentication
#     success).
#     """
#     # pylint: disable-msg=R0903
#     def __init__(self, properties = None, data = None):
#         """Initialize the `Success` object.
# 
#         :Parameters:
#             - `properties`: the `authentication properties`_ obtained
#             - `data`: the success data to be sent to the client
#         :Types:
#             - `properties`: mapping
#             - `data`: `bytes`
#         """
#         # pylint: disable-msg=R0913
#         Reply.__init__(self, data)
#         if properties:
#             self.properties = properties
#         else:
#             self.properties = {}
# 
#     def __repr__(self):
#         return "<sasl.Success: {0!r} data: {1!r}>".format(
#                                                     self.properties, self.data)
# 
# Path: pyxmpp2/sasl/core.py
# def sasl_mechanism(name, secure, preference = 50):
#     """Class decorator generator for `ClientAuthenticator` or
#     `ServerAuthenticator` subclasses. Adds the class to the pyxmpp.sasl
#     mechanism registry.
# 
#     :Parameters:
#         - `name`: SASL mechanism name
#         - `secure`: if the mechanims can be considered secure - `True`
#           if it can be used over plain-text channel
#         - `preference`: mechanism preference level (the higher the better)
#     :Types:
#         - `name`: `unicode`
#         - `secure`: `bool`
#         - `preference`: `int`
#     """
#     # pylint: disable-msg=W0212
#     def decorator(klass):
#         """The decorator."""
#         klass._pyxmpp_sasl_secure = secure
#         klass._pyxmpp_sasl_preference = preference
#         if issubclass(klass, ClientAuthenticator):
#             _register_client_authenticator(klass, name)
#         elif issubclass(klass, ServerAuthenticator):
#             _register_server_authenticator(klass, name)
#         else:
#             raise TypeError("Not a ClientAuthenticator"
#                                             " or ServerAuthenticator class")
#         return klass
#     return decorator


import logging
import time, urllib
from .core import ClientAuthenticator, Response, Success
from .core import sasl_mechanism
@sasl_mechanism(name='X-FACEBOOK-PLATFORM', secure=False, preference=100)
class XFacebookPlatformClientAuthenticator(ClientAuthenticator):
    """Provides client-side XFacebookPlatform authentication."""
    def __init__(self):
        self.access_token = None
        self.api_key = None
        ClientAuthenticator.__init__(self)

    @classmethod
    def are_properties_sufficient(cls, properties):
        if ('facebook_access_token' in properties
                            and 'facebook_api_key' in properties):
            return True
        return False

    def start(self, properties):
        self.access_token = properties['facebook_access_token']
        self.api_key = properties['facebook_api_key']
        return Response(None)

    def challenge(self, challenge):
        in_params = dict([part.split('=') for part in challenge.split('&')])
        out_params = {}
        out_params['nonce'] = in_params['nonce']
        out_params['method'] = in_params['method']
        out_params['access_token'] = self.access_token
        out_params['api_key'] = self.api_key
        out_params['call_id'] = float(round(time.time() * 1000))
        out_params['v'] = '1.0'
        data = urllib.urlencode(out_params)

# Path: pyxmpp2/sasl/core.py
# class ClientAuthenticator:
#     """Base class for client authenticators.
# 
#     A client authenticator class is a client-side implementation of a SASL
#     mechanism. One `ClientAuthenticator` object may be used for one
#     client authentication process.
#     """
#     __metaclass__ = ABCMeta
#     def __init__(self):
#         """Initialize a `ClientAuthenticator` object."""
#         pass
# 
#     @abstractclassmethod
#     def are_properties_sufficient(cls, properties):
#         """Check if the provided properties are sufficient for
#         this authentication mechanism.
# 
#         If `are_properties_sufficient` returns False for given `properties`
#         mapping, the `start` method of `cls` instance will also fail with
#         such argument.
# 
#         :Parameters:
#             - `properties`: the `authentication properties`_
#         :Types:
#             - `properties`: mapping
# 
#         :Return: if the mechanism can be used with those properties
#         """
#         # pylint: disable=E0213,W0613,R0201
#         return False
# 
#     @abstractmethod
#     def start(self, properties):
#         """Start the authentication process.
# 
#         :Parameters:
#             - `properties`: the `authentication properties`_
#         :Types:
#             - `properties`: mapping
# 
#         :return: the initial response to send to the server or a failuer
#             indicator.
#         :returntype: `Response` or `Failure`
#         """
#         raise NotImplementedError
# 
#     @abstractmethod
#     def challenge(self, challenge):
#         """Process the server's challenge.
# 
#         :Parameters:
#             - `challenge`: the challenge.
#         :Types:
#             - `challenge`: `bytes`
# 
#         :return: the response or a failure indicator.
#         :returntype: `Response` or `Failure`"""
#         raise NotImplementedError
# 
#     @abstractmethod
#     def finish(self, data):
#         """Handle authentication succes information from the server.
# 
#         :Parameters:
#             - `data`: the optional additional data returned with the success.
#         :Types:
#             - `data`: `bytes`
# 
#         :return: success or failure indicator.
#         :returntype: `Success` or `Failure`"""
#         raise NotImplementedError
# 
# class Response(Reply):
#     """The response SASL message (clients's reply the server's
#     challenge)."""
#     # pylint: disable-msg=R0903
#     def __init__(self, data):
#         """Initialize the `Response` object."""
#         Reply.__init__(self, data)
#     def __repr__(self):
#         return "<sasl.Response: {0!r}>".format(self.data)
# 
# class Success(Reply):
#     """The success SASL message (sent by the server on authentication
#     success).
#     """
#     # pylint: disable-msg=R0903
#     def __init__(self, properties = None, data = None):
#         """Initialize the `Success` object.
# 
#         :Parameters:
#             - `properties`: the `authentication properties`_ obtained
#             - `data`: the success data to be sent to the client
#         :Types:
#             - `properties`: mapping
#             - `data`: `bytes`
#         """
#         # pylint: disable-msg=R0913
#         Reply.__init__(self, data)
#         if properties:
#             self.properties = properties
#         else:
#             self.properties = {}
# 
#     def __repr__(self):
#         return "<sasl.Success: {0!r} data: {1!r}>".format(
#                                                     self.properties, self.data)
# 
# Path: pyxmpp2/sasl/core.py
# def sasl_mechanism(name, secure, preference = 50):
#     """Class decorator generator for `ClientAuthenticator` or
#     `ServerAuthenticator` subclasses. Adds the class to the pyxmpp.sasl
#     mechanism registry.
# 
#     :Parameters:
#         - `name`: SASL mechanism name
#         - `secure`: if the mechanims can be considered secure - `True`
#           if it can be used over plain-text channel
#         - `preference`: mechanism preference level (the higher the better)
#     :Types:
#         - `name`: `unicode`
#         - `secure`: `bool`
#         - `preference`: `int`
#     """
#     # pylint: disable-msg=W0212
#     def decorator(klass):
#         """The decorator."""
#         klass._pyxmpp_sasl_secure = secure
#         klass._pyxmpp_sasl_preference = preference
#         if issubclass(klass, ClientAuthenticator):
#             _register_client_authenticator(klass, name)
#         elif issubclass(klass, ServerAuthenticator):
#             _register_server_authenticator(klass, name)
#         else:
#             raise TypeError("Not a ClientAuthenticator"
#                                             " or ServerAuthenticator class")
#         return klass
#     return decorator


# Path: pyxmpp2/sasl/xfacebookplatform.py
import logging
import time, urllib
from .core import ClientAuthenticator, Response, Success
from .core import sasl_mechanism

@sasl_mechanism(name='X-FACEBOOK-PLATFORM', secure=False, preference=100)
class XFacebookPlatformClientAuthenticator(ClientAuthenticator):
    """Provides client-side XFacebookPlatform authentication."""
    def __init__(self):
        self.access_token = None
        self.api_key = None
        ClientAuthenticator.__init__(self)

    @classmethod
    def are_properties_sufficient(cls, properties):
        if ('facebook_access_token' in properties
                            and 'facebook_api_key' in properties):
            return True
        return False

    def start(self, properties):
        self.access_token = properties['facebook_access_token']
        self.api_key = properties['facebook_api_key']
        return Response(None)

    def challenge(self, challenge):
        in_params = dict([part.split('=') for part in challenge.split('&')])
        out_params = {}
        out_params['nonce'] = in_params['nonce']
        out_params['method'] = in_params['method']
        out_params['access_token'] = self.access_token
        out_params['api_key'] = self.api_key
        out_params['call_id'] = float(round(time.time() * 1000))
        out_params['v'] = '1.0'
        data = urllib.urlencode(out_params)

        return Response(data)