Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
def add_filters_to_sql(self, sql, filters):
wheres = []
params = {}
for (f_key, f_value) in filters:
comparator = f_key.split('__')[1]
column = f_key.split('__')[0]
if comparator == 'exact':
wheres.append(f"[{column}] = :filter_value_{column}")
params[f'filter_value_{column}'] = f_value
elif comparator == 'contains':
wheres.append(f"[{column}] LIKE :filter_value_{column}")
params[f'filter_value_{column}'] = f'%{f_value}%'
else:
app.logger.warning(f'Dropped unknown comparator in {f_key}')
if wheres:
sql += ' WHERE '
sql += ' AND '.join(wheres)
return sql, params
): # Check endpoint claims
current_app.query_run_logger.error(
"CLAIM_TYPE_NOT_ALLOWED_BY_TOKEN", **log_dict
)
return (
jsonify(
{
"status": "Error",
"msg": f"'{claim_type}' access denied for '{query_kind}' query",
}
),
401,
)
# Check aggregation claims
elif aggregation_unit not in aggregation_claims:
current_app.query_run_logger.error(
"SPATIAL_AGGREGATION_LEVEL_NOT_ALLOWED_BY_TOKEN", **log_dict
)
return (
jsonify(
{
"status": "Error",
"msg": f"'{claim_type}' access denied for '{aggregation_unit}' "
f"aggregated result of '{query_kind}' query",
}
),
401,
)
else:
pass
current_app.query_run_logger.info("Authorised", **log_dict)
return await func(*args, **kwargs)
msg = reply["msg"]
except KeyError:
msg = "Internal server error"
return {"status": "Error", "msg": msg}, 500
try:
query_state = reply["payload"]["query_state"]
if query_state == "completed":
results_streamer = stream_with_context(stream_result_as_json)(
reply["payload"]["sql"],
result_name="features",
additional_elements={"type": "FeatureCollection"},
)
mimetype = "application/geo+json"
current_app.flowapi_logger.debug(
f"Returning {aggregation_unit} geography data.",
request_id=request.request_id,
)
return (
results_streamer,
200,
{
"Transfer-Encoding": "chunked",
"Content-Disposition": f"attachment;filename={aggregation_unit}.geojson",
"Content-type": mimetype,
},
)
# TODO: Reinstate correct status codes for geographies
#
# elif query_state == "error":
# return {"status": "Error", "msg": reply["msg"]}, 403
async def expired_token_callback(expired_token: Dict[str, Any]) -> Response:
"""
Log that an access attempt was made with an expired token and return
the result from the default callback.
Returns
-------
Response
"""
current_app.access_logger.error(
"EXPIRED_TOKEN",
route=request.path,
request_id=request.request_id,
identity=expired_token["identity"],
expired_token=expired_token,
src_ip=request.headers.get("Remote-Addr"),
json_payload=await request.json,
)
return default_expired_token_callback(expired_token)
title="FlowAPI",
version=__version__,
openapi_version="3.0.1",
info=dict(
description="FlowKit Analytical API",
license=dict(name="MPLv2", url="https://www.mozilla.org/en-US/MPL/2.0/"),
contact=dict(email="flowkit@flowminder.org"),
),
)
spec.components._schemas = flowmachine_query_schemas
spec.components.security_scheme(
"token", dict(type="http", scheme="bearer", bearerFormat="JWT")
)
# Loop over all the registered views and try to parse a yaml
# openapi spec from their docstrings
for rule in current_app.url_map.iter_rules():
try:
func = current_app.view_functions[rule.rule]
operations = yaml_utils.load_operations_from_docstring(func.__doc__)
if len(operations) > 0:
for method, op in operations.items():
op["operationId"] = f"{rule.rule}.{method}"
spec.path(
path=rule[
0
].rule, # In theory, could have multiple rules that match but will only be a single one here
operations=operations,
)
except Exception as e:
pass # Don't include in API
async def revoked_token_callback() -> Response:
"""
Log that an access attempt was made with a revoked token and return
the result from the default callback.
Returns
-------
Response
"""
current_app.access_logger.error(
"REVOKED_TOKEN",
route=request.path,
request_id=request.request_id,
user=str(get_jwt_identity()),
src_ip=request.headers.get("Remote-Addr"),
json_payload=await request.json,
)
return default_revoked_token_callback()
----------
sql_query : str
SQL query to stream output of
result_name : str
Name of the JSON item containing the rows of the result
additional_elements : dict
Additional JSON elements to include along with the query result
Yields
------
bytes
Encoded lines of JSON
"""
logger = current_app.flowapi_logger
db_conn_pool = current_app.db_conn_pool
prefix = "{"
if additional_elements:
for key, value in additional_elements.items():
prefix += f'"{key}":{json.dumps(value)}, '
prefix += f'"{result_name}":['
yield prefix.encode()
prepend = ""
logger.debug("Starting generator.", request_id=request.request_id)
async with db_conn_pool.acquire() as connection:
# Configure asyncpg to encode/decode JSON values
await connection.set_type_codec(
"json", encoder=json.dumps, decoder=json.loads, schema="pg_catalog"
)
logger.debug("Connected.", request_id=request.request_id)
async with connection.transaction():
logger.debug("Got transaction.", request_id=request.request_id)
def get_db_info(urlhash, storage=None):
# app.config not thread safe, sometimes we need to pass storage directly
storage = storage or app.config['DB_ROOT_DIR']
dbpath = f"{storage}/{urlhash}.db"
return {
'dsn': f"sqlite:///{dbpath}",
'db_name': urlhash,
'table_name': urlhash,
'db_path': dbpath,
}
'404':
description: Unknown ID
'500':
description: Server error.
summary: Get the status of a query
"""
await current_user.can_poll_by_query_id(query_id=query_id)
request.socket.send_json(
{
"request_id": request.request_id,
"action": "poll_query",
"params": {"query_id": query_id},
}
)
reply = await request.socket.recv_json()
current_app.flowapi_logger.debug(
f"Received reply {reply}", request_id=request.request_id
)
if reply["status"] == "error":
return {"status": "error", "msg": reply[""]}, 500
else:
assert reply["status"] == "success"
query_state = reply["payload"]["query_state"]
if query_state == "completed":
return (
{"status": query_state},
303,
{"Location": url_for(f"query.get_query_result", query_id=query_id)},
)
elif query_state in ("executing", "queued"):
return (
def user_loader_callback(identity):
"""
Call back for loading user from JWT.
Parameters
----------
identity : str
Username
Returns
-------
UserObject
User with claims pulled from the decoded jwt token
"""
current_app.access_logger.info(
"Attempting to load user",
request_id=request.request_id,
route=request.path,
user=get_jwt_identity(),
src_ip=request.headers.get("Remote-Addr"),
)
claims = decompress_claims(get_jwt_claims())
log_dict = dict(
request_id=request.request_id,
route=request.path,
user=get_jwt_identity(),
src_ip=request.headers.get("Remote-Addr"),
claims=claims,
)