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()
def test_validate_webhook_success_case(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=1200): self.assertEqual(authenticationClient.validate_webhook(authenticationClient.key, signature, body), {u'time_ms': 1000000})
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()
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()
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)
class Pusher(object): """Client for the Pusher HTTP API. This client supports various backend adapters to support various http libraries available in the python ecosystem. :param app_id: a pusher application identifier :param key: a pusher application key :param secret: a pusher 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 Pusher-one. Eg: 'eu' will resolve to the api-eu.pusherapp.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._pusher_client = PusherClient( 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 pusher import Pusher >> p = Pusher.from_url("http://*****:*****@api.pusher.com/apps/432") """ m = pusher_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='PUSHER_URL', **options): """Alternative constructor that extracts the information from an URL stored in an environment variable. The pusher heroku addon will set the PUSHER_URL automatically when installed for example. :param env: Name of the environment variable Usage:: >> from pusher import Pusher >> c = Pusher.from_env("PUSHER_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(PusherClient.trigger.__doc__) def trigger(self, channels, event_name, data, socket_id=None): return self._pusher_client.trigger( channels, event_name, data, socket_id) @doc_string(PusherClient.trigger_batch.__doc__) def trigger_batch(self, batch=[], already_encoded=False): return self._pusher_client.trigger_batch(batch, already_encoded) @doc_string(PusherClient.channels_info.__doc__) def channels_info(self, prefix_filter=None, attributes=[]): return self._pusher_client.channels_info(prefix_filter, attributes) @doc_string(PusherClient.channel_info.__doc__) def channel_info(self, channel, attributes=[]): return self._pusher_client.channel_info(channel, attributes) @doc_string(PusherClient.users_info.__doc__) def users_info(self, channel): return self._pusher_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)