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'))
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)
def test_authenticate_for_private_encrypted_channels(self): # The authentication client receives the decoded bytes of the key # not the base64 representation master_key=u'OHRXNUZRTG5pUTFzQlFGd3J3N3Q2VFZFc0paZDEweVk=' authenticationClient = AuthenticationClient( key=u'foo', secret=u'bar', host=u'host', app_id=u'4', encryption_master_key_base64=master_key, ssl=True) expected = { u'auth': u'foo:fff0503dfe4929f5162efe4d1dacbce524b0d8e7e1331117a8651c0e74d369e3', u'shared_secret': b'VmIsNZtCSteh8kazd2toc+ofhohBtUouQRSDtRvuyVI=' } self.assertEqual(authenticationClient.authenticate(u'private-encrypted-channel', u'345.23'), expected)
def test_authenticate_for_private_encrypted_channels(self): encryp_master_key = u'8tW5FQLniQ1sBQFwrw7t6TVEsJZd10yY' authenticationClient = AuthenticationClient( key=u'foo', secret=u'bar', host=u'host', app_id=u'4', encryption_master_key=encryp_master_key, ssl=True) expected = { u'auth': u'foo:fff0503dfe4929f5162efe4d1dacbce524b0d8e7e1331117a8651c0e74d369e3', u'shared_secret': b'VmIsNZtCSteh8kazd2toc+ofhohBtUouQRSDtRvuyVI=' } self.assertEqual( authenticationClient.authenticate(u'private-encrypted-channel', u'345.23'), expected)
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)
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)
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)