def validate_webhook(self, key, signature, body): """Used to validate incoming webhook messages. When used it guarantees that the sender is Pusher and not someone else impersonating it. :param key: key used to sign the body :param signature: signature that was given with the body :param body: content that needs to be verified """ key = ensure_text(key, "key") signature = ensure_text(signature, "signature") body = ensure_text(body, "body") if key != self.key: return None if not verify(self.secret, body, signature): return None try: body_data = json.loads(body, cls=self._json_decoder) except ValueError: return None time_ms = body_data.get('time_ms') if not time_ms: return None if abs(time.time()*1000 - time_ms) > 300000: return None return body_data
def __init__(self, app_id, key, secret, ssl=True, host=None, port=None, timeout=5, cluster=None, json_encoder=None, json_decoder=None, backend=RequestsBackend, **backend_options): self._app_id = ensure_text(app_id, "app_id") if not app_id_re.match(self._app_id): raise ValueError("Invalid app id") self._key = ensure_text(key, "key") self._secret = ensure_text(secret, "secret") if not isinstance(ssl, bool): raise TypeError("SSL should be a boolean") self._ssl = ssl if host: self._host = ensure_text(host, "host") elif cluster: self._host = six.text_type("api-%s.pusher.com") % ensure_text(cluster, "cluster") else: self._host = six.text_type("api.pusherapp.com") if port and not isinstance(port, six.integer_types): raise TypeError("port should be an integer") self._port = port or (443 if ssl else 80) if not isinstance(timeout, six.integer_types): raise TypeError("timeout should be an integer") self._timeout = timeout self._json_encoder = json_encoder self._json_decoder = json_decoder self.http = backend(self, **backend_options)
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, **backend_options): if backend is None: from .requests import RequestsBackend backend = RequestsBackend self._app_id = ensure_text(app_id, "app_id") if not app_id_re.match(self._app_id): raise ValueError("Invalid app id") self._key = ensure_text(key, "key") self._secret = ensure_text(secret, "secret") if not isinstance(ssl, bool): raise TypeError("SSL should be a boolean") self._ssl = ssl if port and not isinstance(port, six.integer_types): raise TypeError("port should be an integer") self._port = port or (443 if ssl else 80) if not isinstance(timeout, six.integer_types): raise TypeError("timeout should be an integer") self._timeout = timeout self._json_encoder = json_encoder self._json_decoder = json_decoder self.http = backend(self, **backend_options)
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, **backend_options): super(PusherClient, self).__init__(app_id, key, secret, ssl, host, port, timeout, cluster, json_encoder, json_decoder, backend, **backend_options) if host: self._host = ensure_text(host, "host") elif cluster: self._host = (six.text_type("api-%s.pusher.com") % ensure_text(cluster, "cluster")) else: self._host = six.text_type("api.pusherapp.com")
def __init__(self, app_id, key, secret, ssl=True, host=None, port=None, timeout=5, cluster=None, encryption_master_key=None, json_encoder=None, json_decoder=None, backend=None, max_num_channels=None, max_len_event_name=None, max_len_data=None, **backend_options): super(PusherClient, self).__init__(app_id, key, secret, ssl, host, port, timeout, cluster, encryption_master_key, json_encoder, json_decoder, backend, **backend_options) self.max_num_channels = max_num_channels if max_num_channels is not None else 100 self.max_len_event_name = max_len_event_name if max_len_event_name is not None else 200 self.max_len_data = max_len_data if max_len_data is not None else 10240 if host: self._host = ensure_text(host, "host") elif cluster: self._host = (six.text_type("api-%s.pusher.com") % ensure_text(cluster, "cluster")) else: self._host = six.text_type("api.pusherapp.com")
def __init__(self, app_id, key, secret, ssl=True, host=None, port=None, timeout=5, cluster=None, encryption_master_key=None, encryption_master_key_base64=None, json_encoder=None, json_decoder=None, backend=None, **backend_options): if backend is None: from .requests import RequestsBackend backend = RequestsBackend self._app_id = ensure_text(app_id, "app_id") if not app_id_re.match(self._app_id): raise ValueError("Invalid app id") self._key = ensure_text(key, "key") self._secret = ensure_text(secret, "secret") if not isinstance(ssl, bool): raise TypeError("SSL should be a boolean") self._ssl = ssl if host: self._host = ensure_text(host, "host") elif cluster: self._host = (six.text_type("api-%s.pusher.com") % ensure_text(cluster, "cluster")) else: self._host = six.text_type("api.pusherapp.com") if port and not isinstance(port, six.integer_types): raise TypeError("port should be an integer") self._port = port or (443 if ssl else 80) if not isinstance(timeout, six.integer_types): raise TypeError("timeout should be an integer") self._timeout = timeout self._json_encoder = json_encoder self._json_decoder = json_decoder self._encryption_master_key = parse_master_key( encryption_master_key, encryption_master_key_base64) self.http = backend(self, **backend_options)
def __init__(self, app_id, key, secret, ssl=True, host=None, port=None, timeout=5, cluster=None, encryption_master_key=None, json_encoder=None, json_decoder=None, backend=None, **backend_options): if backend is None: from .requests import RequestsBackend backend = RequestsBackend self._app_id = ensure_text(app_id, "app_id") if not app_id_re.match(self._app_id): raise ValueError("Invalid app id") self._key = ensure_text(key, "key") self._secret = ensure_text(secret, "secret") if not isinstance(ssl, bool): raise TypeError("SSL should be a boolean") self._ssl = ssl if port and not isinstance(port, six.integer_types): raise TypeError("port should be an integer") self._port = port or (443 if ssl else 80) if not isinstance(timeout, six.integer_types): raise TypeError("timeout should be an integer") self._timeout = timeout self._json_encoder = json_encoder self._json_decoder = json_decoder if encryption_master_key is not None: encryption_master_key = ensure_binary(encryption_master_key, "encryption_master_key") self._encryption_master_key = encryption_master_key self.http = backend(self, **backend_options)
def trigger_batch(self, batch=[], already_encoded=False): """Trigger multiple events with a single HTTP call. http://pusher.com/docs/rest_api#method-post-batch-events """ if not already_encoded: for event in batch: validate_channel(event['channel']) event_name = ensure_text(event['name'], "event_name") if len(event['name']) > 200: raise ValueError("event_name too long") event['data'] = data_to_string(event['data'], self._json_encoder) if len(event['data']) > 10240: raise ValueError("Too much data") if is_encrypted_channel(event['channel']): event['data'] = json.dumps(encrypt(event['channel'], event['data'], self._encryption_master_key), ensure_ascii=False) params = { 'batch': batch} return Request( self, POST, "/apps/%s/batch_events" % self.app_id, params)
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_)
def trigger_batch(self, batch=[], already_encoded=False): """Trigger multiple events with a single HTTP call. http://pusher.com/docs/rest_api#method-post-batch-events """ if not already_encoded: for event in batch: validate_channel(event['channel']) event_name = ensure_text(event['name'], "event_name") if len(event['name']) > 200: raise ValueError("event_name too long") event['data'] = data_to_string(event['data'], self._json_encoder) if len(event['data']) > 10240: raise ValueError("Too much data") if is_encrypted_channel(event['channel']): event['data'] = json.dumps(encrypt( event['channel'], event['data'], self._encryption_master_key), ensure_ascii=False) params = {'batch': batch} return Request(self, POST, "/apps/%s/batch_events" % self.app_id, params)
def trigger(self, channels, event_name, data, socket_id=None): """Trigger an event on one or more channels, see: http://pusher.com/docs/rest_api#method-post-event """ if isinstance(channels, six.string_types): channels = [channels] if isinstance(channels, dict) or not isinstance( channels, (collections.Sized, collections.Iterable)): raise TypeError("Expected a single or a list of channels") if len(channels) > 10: raise ValueError("Too many channels") channels = list(map(validate_channel, channels)) event_name = ensure_text(event_name, "event_name") if len(event_name) > 200: raise ValueError("event_name too long") data = data_to_string(data, self._json_encoder) if len(data) > 10240: raise ValueError("Too much data") params = {'name': event_name, 'channels': channels, 'data': data} if socket_id: params['socket_id'] = validate_socket_id(socket_id) return Request(self, POST, "/apps/%s/events" % self.app_id, params)
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, **backend_options): super(AuthenticationClient, self).__init__( app_id, key, secret, ssl, host, port, timeout, cluster, json_encoder, json_decoder, backend, **backend_options) if host: self._host = ensure_text(host, "host") elif cluster: self._host = ( six.text_type("api-%s.pusher.com") % ensure_text(cluster, "cluster")) else: self._host = six.text_type("api.pusherapp.com")
def channels_info(self, prefix_filter=None, attributes=[]): ''' Get information on multiple channels, see: http://pusher.com/docs/rest_api#method-get-channels ''' params = {} if attributes: params['info'] = join_attributes(attributes) if prefix_filter: params['filter_by_prefix'] = ensure_text(prefix_filter, "prefix_filter") return Request(self, GET, six.text_type("/apps/%s/channels") % self.app_id, params)
def trigger(self, channels, event_name, data, socket_id=None): ''' Trigger an event on one or more channels, see: http://pusher.com/docs/rest_api#method-post-event ''' if isinstance(channels, six.string_types): channels = [channels] if isinstance(channels, dict) or not isinstance(channels, (collections.Sized, collections.Iterable)): raise TypeError("Expected a single or a list of channels") if len(channels) > 10: raise ValueError("Too many channels") channels = list(map(validate_channel, channels)) event_name = ensure_text(event_name, "event_name") if len(event_name) > 200: raise ValueError("event_name too long") if isinstance(data, six.string_types): data = ensure_text(data, "data") else: data = json.dumps(data, cls=self._json_encoder) if len(data) > 10240: raise ValueError("Too much data") params = { 'name': event_name, 'channels': channels, 'data': data } if socket_id: params['socket_id'] = validate_socket_id(socket_id) return Request(self, POST, "/apps/%s/events" % self.app_id, params)
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, **backend_options): super(NotificationClient, self).__init__( app_id, key, secret, ssl, host, port, timeout, cluster, json_encoder, json_decoder, backend, **backend_options) if host: self._host = ensure_text(host, "host") else: self._host = DEFAULT_HOST
def __init__( self, app_id, key, secret, ssl=True, host=None, port=None, timeout=30, cluster=None, encryption_master_key=None, json_encoder=None, json_decoder=None, backend=None, **backend_options): super(NotificationClient, self).__init__( app_id, key, secret, ssl, host, port, timeout, cluster, encryption_master_key, json_encoder, json_decoder, backend, **backend_options) if host: self._host = ensure_text(host, "host") else: self._host = DEFAULT_HOST
def channels_info(self, prefix_filter=None, attributes=[]): """Get information on multiple channels, see: http://pusher.com/docs/rest_api#method-get-channels """ params = {} if attributes: params['info'] = join_attributes(attributes) if prefix_filter: params['filter_by_prefix'] = ensure_text( prefix_filter, "prefix_filter") return Request( self, GET, six.text_type("/apps/%s/channels") % self.app_id, params)
def trigger(self, channels, event_name, data, socket_id=None): """Trigger an event on one or more channels, see: http://pusher.com/docs/rest_api#method-post-event """ if isinstance(channels, six.string_types): channels = [channels] if isinstance(channels, dict) or not isinstance( channels, (collections.Sized, collections.Iterable)): raise TypeError("Expected a single or a list of channels") if len(channels) > self.max_num_channels: raise ValueError("Too many channels") event_name = ensure_text(event_name, "event_name") if len(event_name) > self.max_len_event_name: raise ValueError("event_name too long") data = data_to_string(data, self._json_encoder) if len(data) > self.max_len_data: raise ValueError("Too much data") channels = list(map(validate_channel, channels)) if len(channels) > 1: for chan in channels: if is_encrypted_channel(chan): raise ValueError( "You cannot trigger to multiple channels when using encrypted channels" ) if is_encrypted_channel(channels[0]): data = json.dumps(encrypt(channels[0], data, self._encryption_master_key), ensure_ascii=False) params = {'name': event_name, 'channels': channels, 'data': data} if socket_id: params['socket_id'] = validate_socket_id(socket_id) return Request(self, POST, "/apps/%s/events" % self.app_id, params)
def trigger(self, channels, event_name, data, socket_id=None): """Trigger an event on one or more channels, see: http://pusher.com/docs/rest_api#method-post-event """ if isinstance(channels, six.string_types): channels = [channels] if isinstance(channels, dict) or not isinstance( channels, (collections.Sized, collections.Iterable)): raise TypeError("Expected a single or a list of channels") if len(channels) > 100: raise ValueError("Too many channels") event_name = ensure_text(event_name, "event_name") if len(event_name) > 200: raise ValueError("event_name too long") data = data_to_string(data, self._json_encoder) if len(data) > 10240: raise ValueError("Too much data") channels = list(map(validate_channel, channels)) if len(channels) > 1: for chan in channels: if is_encrypted_channel(chan): raise ValueError("You cannot trigger to multiple channels when using encrypted channels") if is_encrypted_channel(channels[0]): data = json.dumps(encrypt(channels[0], data, self._encryption_master_key), ensure_ascii=False) params = { 'name': event_name, 'channels': channels, 'data': data} if socket_id: params['socket_id'] = validate_socket_id(socket_id) return Request(self, POST, "/apps/%s/events" % self.app_id, params)
def _data_to_string(self, data): if isinstance(data, six.string_types): return ensure_text(data, "data") else: return json.dumps(data, cls=self._json_encoder)