def __init__(self,
                 app_id,
                 key,
                 secret,
                 ssl=True,
                 host=None,
                 port=None,
                 timeout=5,
                 cluster=None,
                 json_encoder=None,
                 json_decoder=None,
                 backend=None,
                 notification_host=None,
                 notification_ssl=True,
                 **backend_options):
        self._eventflit_client = EventflitClient(app_id, key, secret, ssl,
                                                 host, port, timeout, cluster,
                                                 json_encoder, json_decoder,
                                                 backend, **backend_options)

        self._authentication_client = AuthenticationClient(
            app_id, key, secret, ssl, host, port, timeout, cluster,
            json_encoder, json_decoder, backend, **backend_options)

        self._notification_client = NotificationClient(
            app_id, key, secret, notification_ssl, notification_host, port,
            timeout, cluster, json_encoder, json_decoder, backend,
            **backend_options)
Beispiel #2
0
    def test_authenticate_for_private_channels(self):
        authenticationClient = AuthenticationClient(key=u'foo',
                                                    secret=u'bar',
                                                    host=u'host',
                                                    app_id=u'4',
                                                    ssl=True)

        expected = {
            u'auth':
            u"foo:89955e77e1b40e33df6d515a5ecbba86a01dc816a5b720da18a06fd26f7d92ff"
        }

        self.assertEqual(
            authenticationClient.authenticate(u'private-channel', u'345.23'),
            expected)
Beispiel #3
0
    def test_authenticate_types(self):
        authenticationClient = AuthenticationClient(key=u'foo',
                                                    secret=u'bar',
                                                    host=u'host',
                                                    app_id=u'4',
                                                    ssl=True)

        self.assertRaises(
            TypeError,
            lambda: authenticationClient.authenticate(2423, u'34554'))
        self.assertRaises(
            TypeError,
            lambda: authenticationClient.authenticate(u'plah', 234234))
        self.assertRaises(
            ValueError,
            lambda: authenticationClient.authenticate(u'::', u'345345'))
Beispiel #4
0
    def test_validate_webhook_bad_time(self):
        authenticationClient = AuthenticationClient(key=u'foo',
                                                    secret=u'bar',
                                                    host=u'host',
                                                    app_id=u'4',
                                                    ssl=True)

        body = u'{"time_ms": 1000000}'
        signature = six.text_type(
            hmac.new(authenticationClient.secret.encode('utf8'),
                     body.encode('utf8'), hashlib.sha256).hexdigest())

        with mock.patch('time.time', return_value=1301):
            self.assertEqual(
                authenticationClient.validate_webhook(authenticationClient.key,
                                                      signature, body), None)
Beispiel #5
0
    def test_validate_webhook_bad_signature(self):
        authenticationClient = AuthenticationClient(key=u'foo',
                                                    secret=u'bar',
                                                    host=u'host',
                                                    app_id=u'4',
                                                    ssl=True)

        body = u'some body'
        signature = u'some signature'

        with mock.patch('time.time') as time_mock:
            self.assertEqual(
                authenticationClient.validate_webhook(authenticationClient.key,
                                                      signature, body), None)

        time_mock.assert_not_called()
Beispiel #6
0
    def test_validate_webhook_bad_key(self):
        authenticationClient = AuthenticationClient(key=u'foo',
                                                    secret=u'bar',
                                                    host=u'host',
                                                    app_id=u'4',
                                                    ssl=True)

        body = u'some body'
        signature = six.text_type(
            hmac.new(authenticationClient.secret.encode(u'utf8'),
                     body.encode(u'utf8'), hashlib.sha256).hexdigest())

        with mock.patch('time.time') as time_mock:
            self.assertEqual(
                authenticationClient.validate_webhook(u'badkey', signature,
                                                      body), None)

        time_mock.assert_not_called()
Beispiel #7
0
class TestJson(unittest.TestCase):
    def setUp(self):
        class JSONEncoder(json.JSONEncoder):
            def default(self, o):
                if isinstance(o, Decimal):
                    return str(o)

                return super(JSONEncoder, self).default(o)

        constants = {"NaN": 99999}

        class JSONDecoder(json.JSONDecoder):
            def __init__(self, **kwargs):
                super(JSONDecoder,
                      self).__init__(parse_constant=constants.__getitem__)

        self.authentication_client = AuthenticationClient(
            "4",
            "key",
            "secret",
            host="somehost",
            json_encoder=JSONEncoder,
            json_decoder=JSONDecoder)

    def test_custom_json_decoder(self):
        t = 1000 * time.time()
        body = u'{"nan": NaN, "time_ms": %f}' % t
        signature = sign(self.authentication_client.secret, body)
        data = self.authentication_client.validate_webhook(
            self.authentication_client.key, signature, body)
        self.assertEqual({u"nan": 99999, u"time_ms": t}, data)

    def test_custom_json_encoder(self):
        expected = {
            u'channel_data':
            '{"money": "1.32"}',
            u'auth':
            u'key:7f2ae5922800a20b9615543ce7c8e7d1c97115d108939410825ea690f308a05f'
        }
        data = self.authentication_client.authenticate(
            "presence-c1", "1.1", {"money": Decimal("1.32")})
        self.assertEqual(expected, data)
Beispiel #8
0
    def setUp(self):
        class JSONEncoder(json.JSONEncoder):
            def default(self, o):
                if isinstance(o, Decimal):
                    return str(o)

                return super(JSONEncoder, self).default(o)

        constants = {"NaN": 99999}

        class JSONDecoder(json.JSONDecoder):
            def __init__(self, **kwargs):
                super(JSONDecoder,
                      self).__init__(parse_constant=constants.__getitem__)

        self.authentication_client = AuthenticationClient(
            "4",
            "key",
            "secret",
            host="somehost",
            json_encoder=JSONEncoder,
            json_decoder=JSONDecoder)
Beispiel #9
0
    def test_authenticate_for_presence_channels(self):
        authenticationClient = AuthenticationClient(key=u'foo',
                                                    secret=u'bar',
                                                    host=u'host',
                                                    app_id=u'4',
                                                    ssl=True)

        custom_data = {u'user_id': u'fred', u'user_info': {u'key': u'value'}}

        expected = {
            u'auth':
            u"foo:e80ba6439492c2113022c39297a87a948de14061cc67b5788e045645a68b8ccd",
            u'channel_data':
            u"{\"user_id\":\"fred\",\"user_info\":{\"key\":\"value\"}}"
        }

        with mock.patch('json.dumps',
                        return_value=expected[u'channel_data']) as dumps_mock:
            actual = authenticationClient.authenticate(u'presence-channel',
                                                       u'345.43245',
                                                       custom_data)

        self.assertEqual(actual, expected)
        dumps_mock.assert_called_once_with(custom_data, cls=None)
Beispiel #10
0
    def test_validate_webhook_bad_types(self):
        authenticationClient = AuthenticationClient(key=u'foo',
                                                    secret=u'bar',
                                                    host=u'host',
                                                    app_id=u'4',
                                                    ssl=True)

        authenticationClient.validate_webhook(u'key', u'signature', u'body')

        # These things are meant to be human readable, so enforcing being
        # text is sensible.

        with mock.patch('time.time') as time_mock:
            self.assertRaises(
                TypeError, lambda: authenticationClient.validate_webhook(
                    4, u'signature', u'body'))
            self.assertRaises(
                TypeError, lambda: authenticationClient.validate_webhook(
                    u'key', 4, u'body'))
            self.assertRaises(
                TypeError, lambda: authenticationClient.validate_webhook(
                    u'key', u'signature', 4))

        time_mock.assert_not_called()
class Eventflit(object):
    """Client for the Eventflit HTTP API.

    This client supports various backend adapters to support various http
    libraries available in the python ecosystem.

    :param app_id:  a eventflit application identifier
    :param key:     a eventflit application key
    :param secret:  a eventflit application secret token
    :param ssl:     Whenever to use SSL or plain HTTP
    :param host:    Used for custom host destination
    :param port:    Used for custom port destination
    :param timeout: Request timeout (in seconds)
    :param cluster: Convention for other clusters than the main Eventflit-one.
      Eg: 'eu' will resolve to the api-eu.eventflitapp.com host
    :param backend: an http adapter class (AsyncIOBackend, RequestsBackend,
      SynchronousBackend, TornadoBackend)
    :param backend_options: additional backend
    """
    def __init__(self,
                 app_id,
                 key,
                 secret,
                 ssl=True,
                 host=None,
                 port=None,
                 timeout=5,
                 cluster=None,
                 json_encoder=None,
                 json_decoder=None,
                 backend=None,
                 notification_host=None,
                 notification_ssl=True,
                 **backend_options):
        self._eventflit_client = EventflitClient(app_id, key, secret, ssl,
                                                 host, port, timeout, cluster,
                                                 json_encoder, json_decoder,
                                                 backend, **backend_options)

        self._authentication_client = AuthenticationClient(
            app_id, key, secret, ssl, host, port, timeout, cluster,
            json_encoder, json_decoder, backend, **backend_options)

        self._notification_client = NotificationClient(
            app_id, key, secret, notification_ssl, notification_host, port,
            timeout, cluster, json_encoder, json_decoder, backend,
            **backend_options)

    @classmethod
    def from_url(cls, url, **options):
        """Alternative constructor that extracts the information from a URL.

        :param url: String containing a URL

        Usage::

          >> from eventflit import Eventflit
          >> p =
            Eventflit.from_url("http://*****:*****@eventflit.com/apps/432")
        """
        m = eventflit_url_re.match(ensure_text(url, "url"))
        if not m:
            raise Exception("Unparsable url: %s" % url)

        ssl = m.group(1) == 'https'

        options_ = {
            'key': m.group(2),
            'secret': m.group(3),
            'host': m.group(4),
            'app_id': m.group(5),
            'ssl': ssl
        }

        options_.update(options)

        return cls(**options_)

    @classmethod
    def from_env(cls, env='EVENTFLIT_URL', **options):
        """Alternative constructor that extracts the information from an URL
        stored in an environment variable. The eventflit heroku addon will set
        the EVENTFLIT_URL automatically when installed for example.

        :param env: Name of the environment variable

        Usage::

          >> from eventflit import Eventflit
          >> c = Eventflit.from_env("EVENTFLIT_URL")
        """
        val = os.environ.get(env)
        if not val:
            raise Exception("Environment variable %s not found" % env)

        return cls.from_url(val, **options)

    @doc_string(EventflitClient.trigger.__doc__)
    def trigger(self, channels, event_name, data, socket_id=None):
        return self._eventflit_client.trigger(channels, event_name, data,
                                              socket_id)

    @doc_string(EventflitClient.trigger_batch.__doc__)
    def trigger_batch(self, batch=[], already_encoded=False):
        return self._eventflit_client.trigger_batch(batch, already_encoded)

    @doc_string(EventflitClient.channels_info.__doc__)
    def channels_info(self, prefix_filter=None, attributes=[]):
        return self._eventflit_client.channels_info(prefix_filter, attributes)

    @doc_string(EventflitClient.channel_info.__doc__)
    def channel_info(self, channel, attributes=[]):
        return self._eventflit_client.channel_info(channel, attributes)

    @doc_string(EventflitClient.users_info.__doc__)
    def users_info(self, channel):
        return self._eventflit_client.users_info(channel)

    @doc_string(AuthenticationClient.authenticate.__doc__)
    def authenticate(self, channel, socket_id, custom_data=None):
        return self._authentication_client.authenticate(
            channel, socket_id, custom_data)

    @doc_string(AuthenticationClient.validate_webhook.__doc__)
    def validate_webhook(self, key, signature, body):
        return self._authentication_client.validate_webhook(
            key, signature, body)

    @doc_string(NotificationClient.notify.__doc__)
    def notify(self, interest, notification):
        return self._notification_client.notify(interest, notification)