Пример #1
0
def rpc_database_view_rows(handler, session, table_name, page=0, query_filter=None):
	"""
	Retrieve the rows from the specified table where the search
	criteria matches.

	:param str table_name: The name of the database table to query.
	:param int page: The page number to retrieve results for.
	:param dict query_filter: A dictionary mapping optional search criteria for matching the query.
	:return: A dictionary with columns and rows keys.
	:rtype: dict
	"""
	metatable = database_tables.get(table_name)
	if not metatable:
		raise errors.KingPhisherAPIError("failed to get table object for: {0}".format(table_name))
	query_filter = query_filter or {}
	for column in query_filter.keys():
		if column not in metatable.column_names:
			raise errors.KingPhisherAPIError("column {0} is invalid for table {1}".format(column, table_name))

	offset = page * VIEW_ROW_COUNT
	# it's critical that the columns are in the order that the client is expecting
	rows = []
	query = session.query(metatable.model)
	query = query.filter_by(**query_filter)
	total_rows = query.count()
	for row in query[offset:]:
		if len(rows) == VIEW_ROW_COUNT:
			break
		if row.session_has_permissions('r', handler.rpc_session):
			rows.append([getattr(row, c) for c in metatable.column_names])
	if not len(rows):
		return None
	return {'columns': metatable.column_names, 'rows': rows, 'total_rows': total_rows, 'page_size': VIEW_ROW_COUNT}
Пример #2
0
def rpc_database_set_row_value(handler, session, table_name, row_id, keys,
                               values):
    """
	Set values for a row in the specified table with an id of *row_id*.

	:param str table_name: The name of the database table to set the values of the specified row.
	:param tuple keys: The column names of *values*.
	:param tuple values: The values to be updated in the row.
	"""
    if not isinstance(keys, (list, tuple)):
        keys = (keys, )
    if not isinstance(values, (list, tuple)):
        values = (values, )
    if len(keys) != len(values):
        raise errors.KingPhisherAPIError(
            'the number of keys does not match the number of values')
    table = database_table_objects.get(table_name)
    if not table:
        raise errors.KingPhisherAPIError(
            "failed to get table object for: {0}".format(table_name))
    for key, value in zip(keys, values):
        if key not in database_tables[table_name]:
            raise errors.KingPhisherAPIError(
                "column {0} is invalid for table {1}".format(key, table_name))
    row = db_manager.get_row_by_id(session, table, row_id)
    if not row:
        raise errors.KingPhisherAPIError(
            "failed to get row id: {0} from table: {1}".format(
                row_id, table_name))
    row.assert_session_has_permissions('u', handler.rpc_session)
    for key, value in zip(keys, values):
        setattr(row, key, value)
    row.assert_session_has_permissions('u', handler.rpc_session)
    session.commit()
Пример #3
0
def rpc_database_insert_row(handler, session, table_name, keys, values):
    """
	Insert a new row into the specified table.

	:param str table_name: The name of the database table to insert a new row into.
	:param list keys: The column names of *values*.
	:param list values: The values to be inserted in the row.
	:return: The id of the new row that has been added.
	"""
    if not isinstance(keys, (list, tuple)):
        keys = (keys, )
    if not isinstance(values, (list, tuple)):
        values = (values, )
    if len(keys) != len(values):
        raise errors.KingPhisherAPIError(
            'the number of keys does not match the number of values')
    table = database_table_objects.get(table_name)
    if not table:
        raise errors.KingPhisherAPIError(
            "failed to get table object for: {0}".format(table_name))
    for key in keys:
        if key not in database_tables[table_name]:
            raise errors.KingPhisherAPIError(
                "column {0} is invalid for table {1}".format(key, table_name))

    row = table()
    for key, value in zip(keys, values):
        setattr(row, key, value)
    row.assert_session_has_permissions('c', handler.rpc_session)
    session.add(row)
    session.commit()
    return row.id
Пример #4
0
def rpc_database_insert_row_multi(handler,
                                  session,
                                  table_name,
                                  keys,
                                  rows,
                                  deconflict_ids=False):
    """
	Insert multiple new rows into the specified table. If *deconflict_ids* is
	true, new id values will be assigned as necessary to merge the data into
	the database. This function will fail if constraints for the table are
	not met.

	:param str table_name: The name of the database table to insert data into.
	:param list keys: The column names of the values in *rows*.
	:param list rows: A list of rows, each row is a list of values ordered and identified by *keys* to be inserted.
	:return: List of ids of the newly inserted rows.
	:rtype: list
	"""
    inserted_rows = collections.deque()
    if not isinstance(keys, list):
        keys = list(keys)
    if not isinstance(rows, list):
        rows = list(rows)

    table = database_table_objects.get(table_name)
    if not table:
        raise errors.KingPhisherAPIError(
            'failed to get table object for: {0}'.format(table_name))
    for key in keys:
        if key not in database_tables[table_name]:
            raise errors.KingPhisherAPIError(
                'column {0} is invalid for table {1}'.format(keys, table_name))

    for row in rows:
        if len(row) != len(keys):
            raise errors.KingPhisherAPIError(
                'row is not the same length as the number of values defined')
        row = dict(zip(keys, row))
        if 'id' in row and db_manager.get_row_by_id(session, table,
                                                    row['id']) is not None:
            if deconflict_ids:
                row['id'] = None
            else:
                raise errors.KingPhisherAPIError(
                    'row id conflicts with an existing value')

        table_row = table(**row)
        table_row.assert_session_has_permissions('c', handler.rpc_session)
        session.add(table_row)
        inserted_rows.append(table_row)
    session.commit()
    return [row.id for row in inserted_rows]
Пример #5
0
def rpc_events_unsubscribe(handler, event_id, event_types=None, attributes=None):
	"""
	Unsubscribe from an event published by the server that the client
	previously subscribed to.

	:param str event_id: The identifier of the event to subscribe to.
	:param list event_types: A list of sub-types for the corresponding event.
	:param list attributes: A list of attributes of the event object to be sent to the client.
	"""
	if not isinstance(event_id, str):
		raise errors.KingPhisherAPIError('a valid event id must be specified')
	event_socket = handler.rpc_session.event_socket
	if event_socket is None:
		raise errors.KingPhisherAPIError('the event socket is not open for this session')
	return event_socket.unsubscribe(event_id, event_types=event_types, attributes=attributes)
Пример #6
0
def rpc_database_delete_rows_by_id(handler, session, table_name, row_ids):
    """
	Delete multiple rows from a table with the specified values in the id
	column. If a row id specified in *row_ids* does not exist, then it will
	be skipped and no error will be thrown.

	:param str table_name: The name of the database table to delete rows from.
	:param list row_ids: The row ids to delete.
	:return: The row ids that were deleted.
	:rtype: list
	"""
    table = database_table_objects.get(table_name)
    if not table:
        raise errors.KingPhisherAPIError(
            "failed to get table object for: {0}".format(table_name))
    deleted_rows = []
    for row_id in row_ids:
        row = db_manager.get_row_by_id(session, table, row_id)
        if not row:
            continue
        if not row.session_has_permissions('d', handler.rpc_session):
            continue
        session.delete(row)
        deleted_rows.append(row_id)
    session.commit()
    return deleted_rows
Пример #7
0
def rpc_events_is_subscribed(handler, event_id, event_type):
	"""
	Check if the client is currently subscribed to the specified server event.

	:param str event_id: The identifier of the event to subscribe to.
	:param str event_type: A sub-type for the corresponding event.
	:return: Whether or not the client is subscribed to the event.
	:rtype: bool
	"""
	if not isinstance(event_id, str):
		raise errors.KingPhisherAPIError('a valid event id must be specified')
	if not isinstance(event_type, str):
		raise errors.KingPhisherAPIError('a valid event type must be specified')
	event_socket = handler.rpc_session.event_socket
	if event_socket is None:
		raise errors.KingPhisherAPIError('the event socket is not open for this session')
	return event_socket.is_subscribed(event_id, event_type)
Пример #8
0
def rest_api_geoip_lookup(handler, params):
    ip = handler.get_query('ip')
    if not ip:
        logger.error(
            'the required \'ip\' parameter is missing for geoip/lookup')
        raise errors.KingPhisherAPIError(
            'the required \'ip\' parameter is missing for geoip/lookup')
    return geoip.lookup(ip)
Пример #9
0
def rpc_database_count_rows(handler, session, table_name, query_filter=None):
	"""
	Get a count of the rows in the specified table where the search
	criteria matches.

	:param str table_name: The name of the database table to query.
	:param dict query_filter: A dictionary mapping optional search criteria for matching the query.
	:return: The number of matching rows.
	:rtype: int
	"""
	metatable = database_tables.get(table_name)
	if not metatable:
		raise errors.KingPhisherAPIError("failed to get table object for: {0}".format(table_name))
	query_filter = query_filter or {}
	for column in query_filter.keys():
		if column not in metatable.column_names:
			raise errors.KingPhisherAPIError("column {0} is invalid for table {1}".format(column, table_name))
	query = session.query(metatable.model)
	query = query.filter_by(**query_filter)
	return query.count()
Пример #10
0
def rpc_events_subscribe(handler, event_id, event_types=None, attributes=None):
	"""
	Subscribe the client to the specified event published by the server.
	When the event is published the specified *attributes* of it and it's
	corresponding id and type information will be sent to the client.

	:param str event_id: The identifier of the event to subscribe to.
	:param list event_types: A list of sub-types for the corresponding event.
	:param list attributes: A list of attributes of the event object to be sent to the client.
	"""
	if not isinstance(event_id, str):
		raise errors.KingPhisherAPIError('a valid event id must be specified')
	event_socket = handler.rpc_session.event_socket
	if event_socket is None:
		raise errors.KingPhisherAPIError('the event socket is not open for this session')
	if not event_id.startswith('db-'):
		# db-<table name> events are the only ones that are valid right now
		raise errors.KingPhisherAPIError('invalid event_id: ' + event_id)
	table_name = event_id[3:]
	table_name = table_name.replace('-', '_')
	metatable = database_tables.get(table_name)
	if metatable is None:
		raise errors.KingPhisherAPIError("invalid table object: {0}".format(table_name))
	for event_type in event_types:
		if event_type not in ('deleted', 'inserted', 'updated'):
			raise errors.KingPhisherAPIError("event type {0} is invalid for db-* events".format(event_type))
	for column in attributes:
		if column not in metatable.column_names:
			raise errors.KingPhisherAPIError("column {0} is invalid for table {1}".format(column, table_name))
	return event_socket.subscribe(event_id, event_types=event_types, attributes=attributes)
Пример #11
0
def rpc_database_delete_row_by_id(handler, session, table_name, row_id):
	"""
	Delete the row from the table with the specified value in the id column.
	If the row does not exist, no error is raised.

	:param str table_name: The name of the database table to delete a row from.
	:param row_id: The id value.
	"""
	metatable = database_tables.get(table_name)
	if not metatable:
		raise errors.KingPhisherAPIError("failed to get table object for: {0}".format(table_name))
	row = db_manager.get_row_by_id(session, metatable.model, row_id)
	if row is None:
		logger = logging.getLogger('KingPhisher.Server.API.RPC')
		logger.debug("received delete request for non existing row with id {0} from table {1}".format(row_id, table_name))
		return
	row.assert_session_has_permissions('d', handler.rpc_session)
	session.delete(row)
	session.commit()
Пример #12
0
def rpc_database_get_row_by_id(handler, session, table_name, row_id):
	"""
	Retrieve a row from a given table with the specified value in the
	id column.

	:param str table_name: The name of the database table to retrieve a row from.
	:param row_id: The id value.
	:return: The specified row data.
	:rtype: dict
	"""
	table = database_table_objects.get(table_name)
	if not table:
		raise errors.KingPhisherAPIError("failed to get table object for: {0}".format(table_name))
	columns = database_tables[table_name]
	row = db_manager.get_row_by_id(session, table, row_id)
	if row:
		row.assert_session_has_permissions('r', handler.rpc_session)
		row = dict(zip(columns, (getattr(row, c) for c in columns)))
	return row
Пример #13
0
def rpc_database_get_row_by_id(handler, session, table_name, row_id):
	"""
	Retrieve a row from a given table with the specified value in the
	id column.

	:param str table_name: The name of the database table to retrieve a row from.
	:param row_id: The id value.
	:return: The specified row data.
	:rtype: dict
	"""
	metatable = handler.server.tables_api.get(table_name)
	if not metatable:
		raise errors.KingPhisherAPIError("failed to get table object for: {0}".format(table_name))
	row = db_manager.get_row_by_id(session, metatable.model, row_id)
	if row:
		row.assert_session_has_permissions('r', handler.rpc_session)
		row = dict(zip(metatable.column_names, (getattr(row, c) for c in metatable.column_names)))
	elif metatable.model.is_private:
		raise errors.KingPhisherPermissionError()
	return row
Пример #14
0
def rpc_version(handler):
	"""
	Get the version information of the server. This returns a
	dictionary with keys of version, version_info and rpc_api_version.
	These values are provided for the client to determine
	compatibility.

	:return: A dictionary with version information.
	:rtype: dict
	"""
	if not ipaddress.ip_address(handler.client_address[0]).is_loopback:
		message = "an rpc request to /version was received from non-loopback IP address: {0}".format(handler.client_address[0])
		rpc_logger.error(message)
		raise errors.KingPhisherAPIError(message)

	vinfo = {
		'rpc_api_version': version.rpc_api_version,
		'version': version.version,
		'version_info': version.version_info._asdict()
	}
	return vinfo