Skip to content

Commit

Permalink
[MRG] Merge pull request #611 from dfir-iris/apiv2_new_dir
Browse files Browse the repository at this point in the history
Apiv2 new dir
  • Loading branch information
whikernel authored Oct 8, 2024
2 parents 7e3d4ae + d04e40b commit 899f55f
Show file tree
Hide file tree
Showing 11 changed files with 254 additions and 222 deletions.
76 changes: 0 additions & 76 deletions source/app/blueprints/login/templates/login.html

This file was deleted.

43 changes: 0 additions & 43 deletions source/app/blueprints/rest/case/case_assets_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,20 +136,6 @@ def deprecated_add_asset(caseid):
return response_error(e.get_message())


@case_assets_rest_blueprint.route('/api/v2/cases/<int:identifier>/assets', methods=['POST'])
@ac_api_requires()
def add_asset(identifier):
if not ac_fast_check_current_user_has_case_access(identifier, [CaseAccessLevel.full_access]):
return ac_api_return_access_denied(caseid=identifier)

asset_schema = CaseAssetsSchema()
try:
_, asset = assets_create(identifier, request.get_json())
return response_api_created(asset_schema.dump(asset))
except BusinessProcessingError as e:
return response_api_error(e.get_message())


@case_assets_rest_blueprint.route('/case/assets/upload', methods=['POST'])
@ac_requires_case_identifier(CaseAccessLevel.full_access)
@ac_api_requires()
Expand Down Expand Up @@ -266,21 +252,6 @@ def deprecated_asset_view(cur_id, caseid):
return response_error(e.get_message())


@case_assets_rest_blueprint.route('/api/v2/assets/<int:identifier>', methods=['GET'])
@ac_api_requires()
def asset_view(identifier):
asset_schema = CaseAssetsSchema()

try:
asset = assets_get(identifier)
if not ac_fast_check_current_user_has_case_access(asset.case_id, [CaseAccessLevel.read_only, CaseAccessLevel.full_access]):
return ac_api_return_access_denied(caseid=asset.case_id)

return response_api_success(asset_schema.dump(asset))
except BusinessProcessingError as e:
return response_api_error(e.get_message())


@case_assets_rest_blueprint.route('/case/assets/update/<int:cur_id>', methods=['POST'])
@ac_requires_case_identifier(CaseAccessLevel.full_access)
@ac_api_requires()
Expand Down Expand Up @@ -339,20 +310,6 @@ def deprecated_asset_delete(cur_id, caseid):
return response_error('Invalid asset ID for this case')


@case_assets_rest_blueprint.route('/api/v2/assets/<int:identifier>', methods=['DELETE'])
@ac_api_requires()
def asset_delete(identifier):
try:
asset = assets_get(identifier)
if not ac_fast_check_current_user_has_case_access(asset.case_id, [CaseAccessLevel.full_access]):
return ac_api_return_access_denied(caseid=asset.case_id)

assets_delete(asset)
return response_api_deleted()
except BusinessProcessingError as e:
return response_api_error(e.get_message())


@case_assets_rest_blueprint.route('/case/assets/<int:cur_id>/comments/list', methods=['GET'])
@ac_requires_case_identifier(CaseAccessLevel.read_only, CaseAccessLevel.full_access)
@ac_api_requires()
Expand Down
99 changes: 1 addition & 98 deletions source/app/blueprints/rest/case/case_ioc_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,57 +93,7 @@ def case_list_ioc(caseid):
return response_success("", data=ret)


@case_ioc_rest_blueprint.route('/api/v2/cases/<int:identifier>/iocs', methods=['GET'])
@ac_api_requires()
def list_ioc(identifier):
if not ac_fast_check_current_user_has_case_access(identifier, [CaseAccessLevel.read_only, CaseAccessLevel.full_access]):
return ac_api_return_access_denied(caseid=identifier)

page = request.args.get('page', 1, type=int)
per_page = request.args.get('per_page', 10, type=int)
order_by = request.args.get('order_by', type=str)
sort_dir = request.args.get('sort_dir', 'asc', type=str)

ioc_type_id = request.args.get('ioc_type_id', None, type=int)
ioc_type = request.args.get('ioc_type', None, type=str)
ioc_tlp_id = request.args.get('ioc_tlp_id', None, type=int)
ioc_value = request.args.get('ioc_value', None, type=str)
ioc_description = request.args.get('ioc_description', None, type=str)
ioc_tags = request.args.get('ioc_tags', None, type=str)

filtered_iocs = get_filtered_iocs(
caseid=identifier,
ioc_type_id=ioc_type_id,
ioc_type=ioc_type,
ioc_tlp_id=ioc_tlp_id,
ioc_value=ioc_value,
ioc_description=ioc_description,
ioc_tags=ioc_tags,
page=page,
per_page=per_page,
sort_by=order_by,
sort_dir=sort_dir
)

if filtered_iocs is None:
return response_api_error('Filtering error')

iocs = IocSchemaForAPIV2().dump(filtered_iocs.items, many=True)

iocs = {
'total': filtered_iocs.total,
# TODO should maybe really uniform all return types of paginated list and replace field iocs by field data
'iocs': iocs,
'last_page': filtered_iocs.pages,
'current_page': filtered_iocs.page,
'next_page': filtered_iocs.next_num if filtered_iocs.has_next else None,
}

return response_api_success(data=iocs)


@case_ioc_rest_blueprint.route('/case/ioc/state', methods=['GET'])
@endpoint_deprecated('GET', '/api/v2/iocs/<int:cur_id>')
@ac_requires_case_identifier(CaseAccessLevel.read_only, CaseAccessLevel.full_access)
@ac_api_requires()
def case_ioc_state(caseid):
Expand All @@ -167,22 +117,6 @@ def deprecated_case_add_ioc(caseid):
return response_error(e.get_message(), data=e.get_data())


@case_ioc_rest_blueprint.route('/api/v2/cases/<int:identifier>/iocs', methods=['POST'])
@ac_api_requires()
def case_add_ioc(identifier):
if not ac_fast_check_current_user_has_case_access(identifier, [CaseAccessLevel.full_access]):
return ac_api_return_access_denied(caseid=identifier)

ioc_schema = IocSchemaForAPIV2()

try:
ioc, _ = iocs_create(request.get_json(), identifier)
return response_api_created(ioc_schema.dump(ioc))
except BusinessProcessingError as e:
log.error(e)
return response_api_error(e.get_message())


@case_ioc_rest_blueprint.route('/case/ioc/upload', methods=['POST'])
@ac_requires_case_identifier(CaseAccessLevel.full_access)
@ac_api_requires()
Expand Down Expand Up @@ -287,24 +221,6 @@ def deprecated_case_delete_ioc(cur_id, caseid):
except BusinessProcessingError as e:
return response_error(e.get_message())


@case_ioc_rest_blueprint.route('/api/v2/iocs/<int:identifier>', methods=['DELETE'])
@ac_api_requires()
def delete_case_ioc(identifier):
try:
ioc = iocs_get(identifier)
if not ac_fast_check_current_user_has_case_access(ioc.case_id, [CaseAccessLevel.full_access]):
return ac_api_return_access_denied(caseid=ioc.case_id)

iocs_delete(ioc)
return response_api_deleted()

except ObjectNotFoundError:
raise BusinessProcessingError('Not a valid IOC for this case')
except BusinessProcessingError as e:
return response_api_error(e.get_message())


@case_ioc_rest_blueprint.route('/case/ioc/<int:cur_id>', methods=['GET'])
@endpoint_deprecated('GET', '/api/v2/iocs/<int:cur_id>')
@ac_requires_case_identifier(CaseAccessLevel.read_only, CaseAccessLevel.full_access)
Expand All @@ -319,21 +235,8 @@ def deprecated_case_view_ioc(cur_id, caseid):
return response_error('Invalid IOC identifier')


@case_ioc_rest_blueprint.route('/api/v2/iocs/<int:identifier>', methods=['GET'])
@ac_api_requires()
def get_case_ioc(identifier):
ioc_schema = IocSchemaForAPIV2()
try:
ioc = iocs_get(identifier)
if not ac_fast_check_current_user_has_case_access(ioc.case_id, [CaseAccessLevel.read_only, CaseAccessLevel.full_access]):
return ac_api_return_access_denied(caseid=ioc.case_id)

return response_api_success(ioc_schema.dump(ioc))
except ObjectNotFoundError:
return response_api_not_found()


@case_ioc_rest_blueprint.route('/case/ioc/update/<int:cur_id>', methods=['POST'])
@endpoint_deprecated('POST', '/api/v2/iocs/<int:cur_id>')
@ac_requires_case_identifier(CaseAccessLevel.full_access)
@ac_api_requires()
def case_update_ioc(cur_id, caseid):
Expand Down
2 changes: 1 addition & 1 deletion source/app/blueprints/rest/endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def inner_wrap(f):
@wraps(f)
def wrap(*args, **kwargs):
result = f(*args, **kwargs)
logger.warning(f'Endpoint deprecated, use {alternative_verb} {alternative_url} instead')
logger.warning(f'Endpoint will be deprecated soon. Use {alternative_verb} {alternative_url} instead')
result.headers['Link'] = f'<{alternative_url}>; rel="alternate"'
result.headers['Deprecation'] = True
return result
Expand Down
1 change: 1 addition & 0 deletions source/app/blueprints/rest/v2/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
api_v2_url_prefix="/api/v2/"
Empty file.
81 changes: 81 additions & 0 deletions source/app/blueprints/rest/v2/case/api_v2_assets_routes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# IRIS Source Code
# Copyright (C) 2024 - DFIR-IRIS
# [email protected]
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 3 of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

from flask import Blueprint
from flask import request

from app.blueprints.access_controls import ac_api_requires
from app.blueprints.rest.endpoints import response_api_created
from app.blueprints.rest.endpoints import response_api_deleted
from app.blueprints.rest.endpoints import response_api_error
from app.blueprints.rest.endpoints import response_api_success
from app.business.assets import assets_create
from app.business.assets import assets_delete
from app.business.assets import assets_get
from app.business.errors import BusinessProcessingError
from app.iris_engine.access_control.utils import ac_fast_check_current_user_has_case_access
from app.models.authorization import CaseAccessLevel
from app.schema.marshables import CaseAssetsSchema
from app.util import ac_api_return_access_denied

api_v2_assets_blueprint = Blueprint('case_assets_rest_v2',
__name__,
url_prefix='/api/v2')


@api_v2_assets_blueprint.route('/cases/<int:identifier>/assets', methods=['POST'])
@ac_api_requires()
def add_asset(identifier):
if not ac_fast_check_current_user_has_case_access(identifier, [CaseAccessLevel.full_access]):
return ac_api_return_access_denied(caseid=identifier)

asset_schema = CaseAssetsSchema()
try:
_, asset = assets_create(identifier, request.get_json())
return response_api_created(asset_schema.dump(asset))
except BusinessProcessingError as e:
return response_api_error(e.get_message())


@api_v2_assets_blueprint.route('/assets/<int:identifier>', methods=['GET'])
@ac_api_requires()
def asset_view(identifier):
asset_schema = CaseAssetsSchema()

try:
asset = assets_get(identifier)
if not ac_fast_check_current_user_has_case_access(asset.case_id, [CaseAccessLevel.read_only, CaseAccessLevel.full_access]):
return ac_api_return_access_denied(caseid=asset.case_id)

return response_api_success(asset_schema.dump(asset))
except BusinessProcessingError as e:
return response_api_error(e.get_message())


@api_v2_assets_blueprint.route('/assets/<int:identifier>', methods=['DELETE'])
@ac_api_requires()
def asset_delete(identifier):
try:
asset = assets_get(identifier)
if not ac_fast_check_current_user_has_case_access(asset.case_id, [CaseAccessLevel.full_access]):
return ac_api_return_access_denied(caseid=asset.case_id)

assets_delete(asset)
return response_api_deleted()
except BusinessProcessingError as e:
return response_api_error(e.get_message())
Loading

0 comments on commit 899f55f

Please sign in to comment.