def delete_account(record_id): """ Deletes a single account record, removes all traces of account from other tables """ try: # Delete this account's subscriptions Interactions.delete_specific( DEFAULT_SUBSCRIPTIONS_TABLE, filters={'account_id': record_id}) # Loop and delete any records subscribed to their registrations registrations = Interactions.query(DEFAULT_REGISTRATIONS_TABLE, filters={'account_id': record_id}) for registration in registrations: delete_registration(registration['id']) return make_response( jsonify(Interactions.delete(DEFAULT_ACCOUNTS_TABLE, record_id)), client.OK) except RqlRuntimeError as runtime_err: return make_response(jsonify({'Error': runtime_err.message}), client.INTERNAL_SERVER_ERROR) except RqlDriverError as rql_err: return make_response(jsonify({'Error': rql_err.message}), client.INTERNAL_SERVER_ERROR) except TypeError: return make_response( jsonify({'Error': 'Invalid id parameter'}), client.BAD_REQUEST)
def delete_account(record_id): """ Deletes a single account record, removes all traces of account from other tables """ try: # Delete this account's subscriptions Interactions.delete_specific(DEFAULT_SUBSCRIPTIONS_TABLE, filters={'account_id': record_id}) # Loop and delete any records subscribed to their registrations registrations = Interactions.query(DEFAULT_REGISTRATIONS_TABLE, filters={'account_id': record_id}) for registration in registrations: delete_registration(registration['id']) return make_response( jsonify(Interactions.delete(DEFAULT_ACCOUNTS_TABLE, record_id)), client.OK) except RqlRuntimeError as runtime_err: return make_response(jsonify({'Error': runtime_err.message}), client.INTERNAL_SERVER_ERROR) except RqlDriverError as rql_err: return make_response(jsonify({'Error': rql_err.message}), client.INTERNAL_SERVER_ERROR) except TypeError: return make_response(jsonify({'Error': 'Invalid id parameter'}), client.BAD_REQUEST)
def wrapper(*args, **kwargs): try: api_key = request.headers['api-key'] except KeyError: return make_response( jsonify({'Error': 'Missing API key header value'}), client.UNAUTHORIZED) try: username = request.headers['username'] except KeyError: return make_response( jsonify({'Error': 'Missing username header value'}), client.UNAUTHORIZED) record = Interactions.query(DEFAULT_ACCOUNTS_TABLE, filters={'username': username}) if not record: return make_response( jsonify({'Error': 'Invalid API key or Username'}), client.UNAUTHORIZED) if not check_password_hash(record[0]['api_key'], api_key): return make_response(jsonify({'Error': 'Invalid API key'}), client.UNAUTHORIZED) if verify_admin: if not record[0]['is_admin']: return make_response(jsonify({'Error': 'Not an Admin'}), client.UNAUTHORIZED) return f(*args, **kwargs)
def insert_account(table_name, **kwargs): """ Creates new account records (handles POST traffic) Salts the api_key """ try: # Username cannot already exist record = Interactions.query(table_name, filters={'username': kwargs['username']}) if record: return make_response(jsonify({'Error': 'Username already exists'}), client.CONFLICT) original_api_key = kwargs['api_key'] kwargs['api_key'] = generate_password_hash(kwargs['api_key']) account_data = Interactions.insert(table_name, **kwargs) account_data['api_key'] = original_api_key return make_response(jsonify(account_data), client.CREATED) except RqlRuntimeError as runtime_err: return make_response(jsonify({'Error': runtime_err.message}), client.INTERNAL_SERVER_ERROR) except RqlDriverError as rql_err: return make_response(jsonify({'Error': rql_err.message}), client.INTERNAL_SERVER_ERROR) except TypeError: return make_response(jsonify({'Error': 'Invalid parameter(s)'}), client.BAD_REQUEST)
def insert_account(table_name, **kwargs): """ Creates new account records (handles POST traffic) Salts the api_key """ try: # Username cannot already exist record = Interactions.query( table_name, filters={'username': kwargs['username']}) if record: return make_response( jsonify({'Error': 'Username already exists'}), client.CONFLICT) original_api_key = kwargs['api_key'] kwargs['api_key'] = generate_password_hash(kwargs['api_key']) account_data = Interactions.insert(table_name, **kwargs) account_data['api_key'] = original_api_key return make_response(jsonify(account_data), client.CREATED) except RqlRuntimeError as runtime_err: return make_response(jsonify({'Error': runtime_err.message}), client.INTERNAL_SERVER_ERROR) except RqlDriverError as rql_err: return make_response(jsonify({'Error': rql_err.message}), client.INTERNAL_SERVER_ERROR) except TypeError: return make_response( jsonify({'Error': 'Invalid parameter(s)'}), client.BAD_REQUEST)
def lookup_account_id(username): """ Looks up the user's account id based on username """ try: record = Interactions.query(DEFAULT_ACCOUNTS_TABLE, filters={'username': username}) return record[0]['id'] except RqlRuntimeError as runtime_err: return runtime_err except RqlDriverError as rql_err: return rql_err
def lookup_subscription_id(account_id, subscription_id): """ Looks up subscription based on account_id and pass the record back """ try: return Interactions.query( DEFAULT_SUBSCRIPTIONS_TABLE, filters={'account_id': account_id, 'id': subscription_id}) except RqlRuntimeError as runtime_err: return runtime_err except RqlDriverError as rql_err: return rql_err
def lookup_registration_id(account_id, registration_id): """ Looks up registration based on account_id and pass the record back """ try: return Interactions.query( DEFAULT_REGISTRATIONS_TABLE, filters={'account_id': account_id, 'id': registration_id}) except RqlRuntimeError as runtime_err: return runtime_err except RqlDriverError as rql_err: return rql_err
def lookup_account_id(username): """ Looks up the user's account id based on username """ try: record = Interactions.query( DEFAULT_ACCOUNTS_TABLE, filters={'username': username}) return record[0]['id'] except RqlRuntimeError as runtime_err: return runtime_err except RqlDriverError as rql_err: return rql_err
def lookup_subscription_id(account_id, subscription_id): """ Looks up subscription based on account_id and pass the record back """ try: return Interactions.query(DEFAULT_SUBSCRIPTIONS_TABLE, filters={ 'account_id': account_id, 'id': subscription_id }) except RqlRuntimeError as runtime_err: return runtime_err except RqlDriverError as rql_err: return rql_err
def post(self, registration_id): """ Creates new triggered webhook event """ registration = Interactions.query(DEFAULT_REGISTRATIONS_TABLE, filters={'id': registration_id}) if not registration: return make_response( jsonify({'Error': 'Registration id not found'}), client.NOT_FOUND) # Other users cannot trigger webhooks they didn't create calling_account_id = lookup_account_id(request.headers['username']) if not lookup_registration_id(calling_account_id, registration_id): return make_response( jsonify({ 'Error': 'You don\'t have access ' 'to this registration record or it no ' 'longer exists' }), client.UNAUTHORIZED) # Notify subscribed endpoints (send the webhooks out) subscriptions = Interactions.list_all( DEFAULT_SUBSCRIPTIONS_TABLE, order_by='epoch', filters={'registration_id': registration_id}) if subscriptions: for record in subscriptions: account = Interactions.get(DEFAULT_ACCOUNTS_TABLE, record['account_id']) # Only hit the endpoint if their failed count is low enough if int(account['failed_count']) < MAX_FAILED_COUNT: # This import is required to be here so the flask-restful # piece works properly with Celery from pywebhooks.tasks.webhook_notification import \ notify_subscribed_accounts notify_subscribed_accounts.delay( event=registration[0]['event'], event_data=registration[0]['event_data'], secret_key=account['secret_key'], endpoint=account['endpoint'], account_id=record['account_id']) return insert(DEFAULT_TRIGGERED_TABLE, **{'registration_id': registration_id})
def registration_id_exists(registration_id): """ Looks up registration based on record_id and pass the record back """ try: registration = Interactions.query( DEFAULT_REGISTRATIONS_TABLE, filters={'id': registration_id}) if registration: return True return False except RqlRuntimeError as runtime_err: return runtime_err except RqlDriverError as rql_err: return rql_err
def registration_id_exists(registration_id): """ Looks up registration based on record_id and pass the record back """ try: registration = Interactions.query(DEFAULT_REGISTRATIONS_TABLE, filters={'id': registration_id}) if registration: return True return False except RqlRuntimeError as runtime_err: return runtime_err except RqlDriverError as rql_err: return rql_err
def lookup_registration_id(account_id, registration_id): """ Looks up registration based on account_id and pass the record back """ try: return Interactions.query(DEFAULT_REGISTRATIONS_TABLE, filters={ 'account_id': account_id, 'id': registration_id }) except RqlRuntimeError as runtime_err: return runtime_err except RqlDriverError as rql_err: return rql_err
def post(self, registration_id): """ Creates new triggered webhook event """ registration = Interactions.query( DEFAULT_REGISTRATIONS_TABLE, filters={'id': registration_id}) if not registration: return make_response( jsonify( {'Error': 'Registration id not found'} ), client.NOT_FOUND) # Other users cannot trigger webhooks they didn't create calling_account_id = lookup_account_id(request.headers['username']) if not lookup_registration_id(calling_account_id, registration_id): return make_response( jsonify({'Error': 'You don\'t have access ' 'to this registration record or it no ' 'longer exists'}), client.UNAUTHORIZED) # Notify subscribed endpoints (send the webhooks out) subscriptions = Interactions.list_all( DEFAULT_SUBSCRIPTIONS_TABLE, order_by='epoch', filters={'registration_id': registration_id}) if subscriptions: for record in subscriptions: account = Interactions.get(DEFAULT_ACCOUNTS_TABLE, record['account_id']) # Only hit the endpoint if their failed count is low enough if int(account['failed_count']) < MAX_FAILED_COUNT: # This import is required to be here so the flask-restful # piece works properly with Celery from pywebhooks.tasks.webhook_notification import \ notify_subscribed_accounts notify_subscribed_accounts.delay( event=registration[0]['event'], event_data=registration[0]['event_data'], secret_key=account['secret_key'], endpoint=account['endpoint'], account_id=record['account_id']) return insert(DEFAULT_TRIGGERED_TABLE, **{'registration_id': registration_id})
def wrapper(*args, **kwargs): try: username = request.headers['username'] except KeyError: return make_response( jsonify({'Error': 'Missing the username header value'}), client.BAD_REQUEST) record = Interactions.query(DEFAULT_ACCOUNTS_TABLE, filters={'username': username}) if not record: return make_response(jsonify({'Error': 'Username not found'}), client.NOT_FOUND) return f(*args, **kwargs)
def reset_key(username, key_type): """ Resets either a secret key or api key """ try: # Note: The validate_username_in_header decorator will verify the # username and record. The api_key_restricted_resource will validate # the username as well as a valid API key record = Interactions.query(DEFAULT_ACCOUNTS_TABLE, filters={"username": username}) endpoint = record[0]['endpoint'] if not endpoint: return make_response( jsonify({'Error': 'Endpoint not found'}), client.NOT_FOUND ) new_key = common.generate_key() salted_new_key = generate_password_hash(new_key) if not client_reset_key(endpoint, key_type, new_key): return make_response( jsonify({'Error': 'Failed to contact the endpoint or wrong ' 'HTTP status code returned'}), client.BAD_REQUEST ) if key_type == 'api_key': update = {key_type: salted_new_key} else: update = {key_type: new_key} Interactions.update(DEFAULT_ACCOUNTS_TABLE, filters={"username": username}, updates=update) return make_response(jsonify({'Message': 'New key sent to endpoint'}), client.OK) except RqlRuntimeError as runtime_err: return make_response(jsonify({'Error': runtime_err.message}), client.INTERNAL_SERVER_ERROR) except RqlDriverError as rql_err: return make_response(jsonify({'Error': rql_err.message}), client.INTERNAL_SERVER_ERROR)
def reset_key(username, key_type): """ Resets either a secret key or api key """ try: # Note: The validate_username_in_header decorator will verify the # username and record. The api_key_restricted_resource will validate # the username as well as a valid API key record = Interactions.query(DEFAULT_ACCOUNTS_TABLE, filters={"username": username}) endpoint = record[0]['endpoint'] if not endpoint: return make_response(jsonify({'Error': 'Endpoint not found'}), client.NOT_FOUND) new_key = common.generate_key() salted_new_key = generate_password_hash(new_key) if not client_reset_key(endpoint, key_type, new_key): return make_response( jsonify({ 'Error': 'Failed to contact the endpoint or wrong ' 'HTTP status code returned' }), client.BAD_REQUEST) if key_type == 'api_key': update = {key_type: salted_new_key} else: update = {key_type: new_key} Interactions.update(DEFAULT_ACCOUNTS_TABLE, filters={"username": username}, updates=update) return make_response(jsonify({'Message': 'New key sent to endpoint'}), client.OK) except RqlRuntimeError as runtime_err: return make_response(jsonify({'Error': runtime_err.message}), client.INTERNAL_SERVER_ERROR) except RqlDriverError as rql_err: return make_response(jsonify({'Error': rql_err.message}), client.INTERNAL_SERVER_ERROR)
def wrapper(*args, **kwargs): try: api_key = request.headers['api-key'] except KeyError: return make_response( jsonify( {'Error': 'Missing API key header value'} ), client.UNAUTHORIZED ) try: username = request.headers['username'] except KeyError: return make_response( jsonify( {'Error': 'Missing username header value'} ), client.UNAUTHORIZED ) record = Interactions.query(DEFAULT_ACCOUNTS_TABLE, filters={'username': username}) if not record: return make_response( jsonify({'Error': 'Invalid API key or Username'}), client.UNAUTHORIZED ) if not check_password_hash(record[0]['api_key'], api_key): return make_response( jsonify({'Error': 'Invalid API key'}), client.UNAUTHORIZED) if verify_admin: if not record[0]['is_admin']: return make_response( jsonify({'Error': 'Not an Admin'}), client.UNAUTHORIZED ) return f(*args, **kwargs)