Skip to content

Commit 36649ba

Browse files
authored
[MRG] Merge pull request #690 from dfir-iris/issue_678_api_v2_cases_put
Issue 678 api v2 cases put
2 parents 0de658a + a367fb0 commit 36649ba

File tree

13 files changed

+140
-50
lines changed

13 files changed

+140
-50
lines changed

source/app/blueprints/graphql/cases.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ def mutate(root, info, name, description, client_id, soc_id=None, classification
103103
request['case_soc_id'] = soc_id
104104
if classification_id:
105105
request['classification_id'] = classification_id
106-
case, _ = cases_create(request)
106+
case = cases_create(request)
107107
return CaseCreate(case=case)
108108

109109

source/app/blueprints/rest/manage/manage_cases_routes.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -249,8 +249,8 @@ def api_add_case():
249249
case_schema = CaseSchema()
250250

251251
try:
252-
case, msg = cases_create(request.get_json())
253-
return response_success(msg, data=case_schema.dump(case))
252+
case = cases_create(request.get_json())
253+
return response_success('Case created', data=case_schema.dump(case))
254254
except BusinessProcessingError as e:
255255
return response_error(e.get_message(), data=e.get_data())
256256

@@ -264,6 +264,7 @@ def api_list_case():
264264

265265

266266
@manage_cases_rest_blueprint.route('/manage/cases/update/<int:cur_id>', methods=['POST'])
267+
@endpoint_deprecated('PUT', '/api/v2/cases/<int:identifier>')
267268
@ac_api_requires(Permissions.standard_user)
268269
def update_case_info(cur_id):
269270
if not ac_fast_check_current_user_has_case_access(cur_id, [CaseAccessLevel.full_access]):

source/app/blueprints/rest/v2/__init__.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@
1010

1111

1212
# Create root /api/v2 blueprint
13-
rest_v2_bp = Blueprint("rest_v2", __name__, url_prefix="/api/v2")
13+
rest_v2_blueprint = Blueprint("rest_v2", __name__, url_prefix="/api/v2")
1414

1515

1616
# Register child blueprints
17-
rest_v2_bp.register_blueprint(cases_blueprint)
18-
rest_v2_bp.register_blueprint(auth_blueprint)
19-
rest_v2_bp.register_blueprint(tasks_blueprint)
20-
rest_v2_bp.register_blueprint(iocs_blueprint)
21-
rest_v2_bp.register_blueprint(assets_blueprint)
22-
rest_v2_bp.register_blueprint(alerts_blueprint)
23-
rest_v2_bp.register_blueprint(dashboard_blueprint)
17+
rest_v2_blueprint.register_blueprint(cases_blueprint)
18+
rest_v2_blueprint.register_blueprint(auth_blueprint)
19+
rest_v2_blueprint.register_blueprint(tasks_blueprint)
20+
rest_v2_blueprint.register_blueprint(iocs_blueprint)
21+
rest_v2_blueprint.register_blueprint(assets_blueprint)
22+
rest_v2_blueprint.register_blueprint(alerts_blueprint)
23+
rest_v2_blueprint.register_blueprint(dashboard_blueprint)

source/app/blueprints/rest/v2/auth/__init__.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,12 @@
2626
from app import db
2727
from app import oidc_client
2828
from app.blueprints.access_controls import is_authentication_ldap
29-
from app.blueprints.access_controls import is_authentication_oidc, \
30-
not_authenticated_redirection_url
29+
from app.blueprints.access_controls import is_authentication_oidc
30+
from app.blueprints.access_controls import not_authenticated_redirection_url
3131
from app.blueprints.rest.endpoints import response_api_error
3232
from app.blueprints.rest.endpoints import response_api_success
3333
from app.business.auth import validate_ldap_login, validate_local_login
3434
from app.iris_engine.utils.tracker import track_activity
35-
from app.models.authorization import User
3635
from app.schema.marshables import UserSchema
3736

3837

source/app/blueprints/rest/v2/cases/__init__.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
from app.business.cases import cases_create
3535
from app.business.cases import cases_delete
3636
from app.datamgmt.case.case_db import get_case
37+
from app.business.cases import cases_update
3738
from app.business.errors import BusinessProcessingError
3839
from app.datamgmt.manage.manage_cases_db import get_filtered_cases
3940
from app.schema.marshables import CaseSchemaForAPIV2
@@ -54,21 +55,21 @@
5455

5556

5657
# Routes
57-
@cases_blueprint.post('', strict_slashes=False)
58+
@cases_blueprint.post('')
5859
@ac_api_requires(Permissions.standard_user)
5960
def create_case():
6061
"""
6162
Handles creating a new case.
6263
"""
6364

6465
try:
65-
case, _ = cases_create(request.get_json())
66+
case = cases_create(request.get_json())
6667
return response_api_created(CaseSchemaForAPIV2().dump(case))
6768
except BusinessProcessingError as e:
6869
return response_api_error(e.get_message(), e.get_data())
6970

7071

71-
@cases_blueprint.get('', strict_slashes=False)
72+
@cases_blueprint.get('')
7273
@ac_api_requires()
7374
def get_cases() -> Response:
7475
"""
@@ -123,7 +124,6 @@ def get_cases() -> Response:
123124

124125
cases = {
125126
'total': filtered_cases.total,
126-
# TODO should maybe really uniform all return types of paginated list and replace field cases by field data
127127
'data': CaseSchemaForAPIV2().dump(filtered_cases.items, many=True),
128128
'last_page': filtered_cases.pages,
129129
'current_page': filtered_cases.page,
@@ -148,6 +148,19 @@ def case_routes_get(identifier):
148148
return response_api_success(CaseSchemaForAPIV2().dump(case))
149149

150150

151+
@cases_blueprint.put('/<int:identifier>')
152+
@ac_api_requires(Permissions.standard_user)
153+
def rest_v2_cases_update(identifier):
154+
if not ac_fast_check_current_user_has_case_access(identifier, [CaseAccessLevel.full_access]):
155+
return ac_api_return_access_denied(caseid=identifier)
156+
157+
try:
158+
case, _ = cases_update(identifier, request.get_json())
159+
return response_api_success(CaseSchemaForAPIV2().dump(case))
160+
except BusinessProcessingError as e:
161+
return response_api_error(e.get_message())
162+
163+
151164
@cases_blueprint.delete('/<int:identifier>')
152165
@ac_api_requires(Permissions.standard_user)
153166
def case_routes_delete(identifier):

source/app/blueprints/rest/v2/cases/assets.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
url_prefix='/<int:case_id>/assets')
3939

4040

41-
@case_assets_blueprint.get('', strict_slashes=False)
41+
@case_assets_blueprint.get('')
4242
@ac_api_requires()
4343
def case_list_assets(case_id):
4444
"""
@@ -65,7 +65,7 @@ def case_list_assets(case_id):
6565
return response_api_error(e.get_message())
6666

6767

68-
@case_assets_blueprint.post('', strict_slashes=False)
68+
@case_assets_blueprint.post('')
6969
@ac_api_requires()
7070
def add_asset(case_id):
7171
"""

source/app/blueprints/rest/v2/cases/iocs.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
url_prefix='/<int:case_id>/iocs')
3838

3939

40-
@case_iocs_blueprint.get('', strict_slashes=False)
40+
@case_iocs_blueprint.get('')
4141
@ac_api_requires()
4242
def get_case_iocs(case_id):
4343
"""
@@ -92,7 +92,7 @@ def get_case_iocs(case_id):
9292
return response_api_success(data=iocs)
9393

9494

95-
@case_iocs_blueprint.post('', strict_slashes=False)
95+
@case_iocs_blueprint.post('')
9696
@ac_api_requires()
9797
def add_ioc_to_case(case_id):
9898
"""

source/app/blueprints/rest/v2/cases/tasks.py

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,81 +19,87 @@
1919
from flask import Blueprint
2020
from flask import request
2121

22-
from app.blueprints.rest.endpoints import response_api_error, response_api_not_found, response_api_deleted
22+
from app.blueprints.rest.endpoints import response_api_error
23+
from app.blueprints.rest.endpoints import response_api_not_found
24+
from app.blueprints.rest.endpoints import response_api_deleted
25+
from app.blueprints.rest.endpoints import response_api_success
2326
from app.blueprints.rest.endpoints import response_api_created
2427
from app.blueprints.access_controls import ac_api_return_access_denied
2528
from app.blueprints.access_controls import ac_api_requires
2629
from app.schema.marshables import CaseTaskSchema
27-
from app.business.errors import BusinessProcessingError, ObjectNotFoundError
28-
from app.business.tasks import tasks_create, tasks_get, tasks_delete
30+
from app.business.errors import BusinessProcessingError
31+
from app.business.errors import ObjectNotFoundError
32+
from app.business.tasks import tasks_create
33+
from app.business.tasks import tasks_get
34+
from app.business.tasks import tasks_delete
2935
from app.models.authorization import CaseAccessLevel
3036
from app.iris_engine.access_control.utils import ac_fast_check_current_user_has_case_access
3137

3238
case_tasks_blueprint = Blueprint('case_tasks',
3339
__name__,
34-
url_prefix='/<int:case_id>/tasks')
40+
url_prefix='/<int:case_identifier>/tasks')
3541

36-
@case_tasks_blueprint.post('', strict_slashes=False)
42+
@case_tasks_blueprint.post('')
3743
@ac_api_requires()
38-
def add_case_task(case_id):
44+
def add_case_task(case_identifier):
3945
"""
4046
Add a task to a case.
4147
4248
Args:
43-
case_id (int): The Case ID for this task
49+
case_identifier (int): The Case ID for this task
4450
"""
45-
if not ac_fast_check_current_user_has_case_access(case_id, [CaseAccessLevel.full_access]):
46-
return ac_api_return_access_denied(caseid=case_id)
51+
if not ac_fast_check_current_user_has_case_access(case_identifier, [CaseAccessLevel.full_access]):
52+
return ac_api_return_access_denied(caseid=case_identifier)
4753

4854
task_schema = CaseTaskSchema()
4955
try:
50-
_, case = tasks_create(case_id, request.get_json())
56+
_, case = tasks_create(case_identifier, request.get_json())
5157
return response_api_created(task_schema.dump(case))
5258
except BusinessProcessingError as e:
5359
return response_api_error(e.get_message())
5460

5561

5662
@case_tasks_blueprint.get('/<int:identifier>')
5763
@ac_api_requires()
58-
def get_case_task(case_id, identifier):
64+
def get_case_task(case_identifier, identifier):
5965
"""
6066
Handles getting a task from a case.
6167
6268
Args:
63-
case_id (int): The case ID
69+
case_identifier (int): The case ID
6470
identifier (int): The task ID
6571
"""
6672

6773
try:
6874
task = tasks_get(identifier)
6975

70-
if task.task_case_id != case_id:
76+
if task.task_case_id != case_identifier:
7177
raise ObjectNotFoundError()
7278

7379
if not ac_fast_check_current_user_has_case_access(task.task_case_id, [CaseAccessLevel.read_only, CaseAccessLevel.full_access]):
7480
return ac_api_return_access_denied(caseid=task.task_case_id)
7581

7682
task_schema = CaseTaskSchema()
77-
return response_api_created(task_schema.dump(task))
83+
return response_api_success(task_schema.dump(task))
7884
except ObjectNotFoundError:
7985
return response_api_not_found()
8086

8187

8288
@case_tasks_blueprint.delete('/<int:identifier>')
8389
@ac_api_requires()
84-
def delete_case_task(case_id, identifier):
90+
def delete_case_task(case_identifier, identifier):
8591
"""
8692
Handle deleting a task from a case
8793
8894
Args:
89-
case_id (int): The case ID
95+
case_identifier (int): The case ID
9096
identifier (int): The task ID
9197
"""
9298

9399
try:
94100
task = tasks_get(identifier)
95101

96-
if task.task_case_id != case_id:
102+
if task.task_case_id != case_identifier:
97103
raise ObjectNotFoundError()
98104

99105
if not ac_fast_check_current_user_has_case_access(task.task_case_id, [CaseAccessLevel.full_access]):
@@ -107,4 +113,4 @@ def delete_case_task(case_id, identifier):
107113
return response_api_error(e.get_message())
108114

109115

110-
# TODO: Add task endpoint endpoint
116+
# TODO: Add task update endpoint

source/app/blueprints/rest/v2/tasks.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from flask import Blueprint
2020

2121
from app.blueprints.rest.endpoints import response_api_not_found
22-
from app.blueprints.rest.endpoints import response_api_created
22+
from app.blueprints.rest.endpoints import response_api_success
2323
from app.blueprints.rest.endpoints import response_api_deleted
2424
from app.blueprints.rest.endpoints import response_api_error
2525
from app.blueprints.access_controls import ac_api_requires
@@ -49,8 +49,7 @@ def get_case_task(identifier):
4949
return ac_api_return_access_denied(caseid=task.task_case_id)
5050

5151
task_schema = CaseTaskSchema()
52-
# TODO should be response_api_success => add a test
53-
return response_api_created(task_schema.dump(task))
52+
return response_api_success(task_schema.dump(task))
5453
except ObjectNotFoundError:
5554
return response_api_not_found()
5655

source/app/business/cases.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,9 @@ def cases_exists(identifier):
7878
return case_db_exists(identifier)
7979

8080

81-
def cases_create(request_json):
81+
def cases_create(request_data):
8282
# TODO remove caseid doesn't seems to be useful for call_modules_hook => remove argument
83-
request_data = call_modules_hook('on_preload_case_create', request_json, None)
83+
request_data = call_modules_hook('on_preload_case_create', request_data, None)
8484

8585
case = _load(request_data)
8686

@@ -115,7 +115,7 @@ def cases_create(request_json):
115115
add_obj_history_entry(case, 'created')
116116
track_activity(f'new case "{case.name}" created', caseid=case.case_id, ctx_less=False)
117117

118-
return case, 'Case created'
118+
return case
119119

120120

121121
def cases_delete(case_identifier):

0 commit comments

Comments
 (0)