Skip to content

Commit 357d9bb

Browse files
authored
Merge pull request #919 from dfir-iris/api_v2_code_uniformization
Api v2 code uniformization
2 parents dad1ccf + 36bfe6d commit 357d9bb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1009
-784
lines changed

e2e/tests/api.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const createCase = async (rest) => {
88
data: {
99
case_name: caseName,
1010
case_description: 'Case description',
11-
case_customer: 1,
11+
case_customer_id: 1,
1212
case_soc_id: ''
1313
}
1414
});

source/app/blueprints/graphql/cases.py

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,14 @@
3535
from app.business.cases import cases_create
3636
from app.business.cases import cases_delete
3737
from app.business.cases import cases_update
38+
from app.business.cases import cases_get_by_identifier
39+
from app.business.errors import BusinessProcessingError
3840
from app.blueprints.graphql.permissions import permissions_check_current_user_has_some_permission
3941
from app.blueprints.graphql.permissions import permissions_check_current_user_has_some_case_access
42+
from app.iris_engine.module_handler.module_handler import call_deprecated_on_preload_modules_hook
43+
from app.schema.marshables import CaseSchema
44+
from app.iris_engine.access_control.iris_user import iris_current_user
45+
from app.datamgmt.manage.manage_access_control_db import user_has_client_access
4046

4147
from app.blueprints.graphql.iocs import IOCConnection
4248

@@ -104,8 +110,13 @@ def mutate(root, info, name, description, client_id, soc_id=None, classification
104110
request['case_soc_id'] = soc_id
105111
if classification_id:
106112
request['classification_id'] = classification_id
107-
case = cases_create(request)
108-
return CaseCreate(case=case)
113+
114+
request_data = call_deprecated_on_preload_modules_hook('case_create', request, None)
115+
schema = CaseSchema()
116+
case = schema.load(request_data)
117+
case_template_id = request_data.pop('case_template_id', None)
118+
result = cases_create(case, case_template_id)
119+
return CaseCreate(case=result)
109120

110121

111122
class CaseDelete(Mutation):
@@ -170,5 +181,22 @@ def mutate(root, info, case_id, name=None, soc_id=None, classification_id=None,
170181
permissions_check_current_user_has_some_permission([Permissions.standard_user])
171182
permissions_check_current_user_has_some_case_access(case_id, [CaseAccessLevel.full_access])
172183

173-
case, _ = cases_update(case_id, request)
184+
case = cases_get_by_identifier(case_id)
185+
186+
# If user tries to update the customer, check if the user has access to the new customer
187+
if request.get('case_customer') and request.get('case_customer') != case.client_id:
188+
if not user_has_client_access(iris_current_user.id, request.get('case_customer')):
189+
raise BusinessProcessingError('Invalid customer ID. Permission denied.')
190+
191+
if 'case_name' in request:
192+
short_case_name = request.get('case_name').replace(f'#{case.case_id} - ', '')
193+
request['case_name'] = f'#{case.case_id} - {short_case_name}'
194+
request['case_customer'] = case.client_id if not request.get('case_customer') else request.get('case_customer')
195+
request['reviewer_id'] = None if request.get('reviewer_id') == '' else request.get('reviewer_id')
196+
197+
add_case_schema = CaseSchema()
198+
updated_case = add_case_schema.load(request, instance=case, partial=True)
199+
protagonists = request.get('protagonists')
200+
tags = request.get('case_tags')
201+
case = cases_update(case, updated_case, protagonists, tags)
174202
return CaseUpdate(case=case)

source/app/blueprints/graphql/iocs.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
from app.business.iocs import iocs_get
3333
from app.business.iocs import iocs_update
3434
from app.business.iocs import iocs_delete
35+
from app.iris_engine.module_handler.module_handler import call_deprecated_on_preload_modules_hook
36+
from app.schema.marshables import IocSchema
3537

3638
from graphene.relay import Connection
3739

@@ -78,7 +80,11 @@ def mutate(root, info, case_id, type_id, tlp_id, value, description=None, tags=N
7880
}
7981
permissions_check_current_user_has_some_case_access(case_id, [CaseAccessLevel.full_access])
8082

81-
ioc, _ = iocs_create(request, case_id)
83+
request_data = call_deprecated_on_preload_modules_hook('ioc_create', request, case_id)
84+
request_data['case_id'] = case_id
85+
add_ioc_schema = IocSchema()
86+
ioc = add_ioc_schema.load(request_data)
87+
ioc = iocs_create(ioc)
8288
return IOCCreate(ioc=ioc)
8389

8490

@@ -124,7 +130,15 @@ def mutate(root, info, ioc_id, type_id=None, tlp_id=None, value=None, descriptio
124130
if modification_history:
125131
request['modification_history'] = modification_history
126132
ioc = iocs_get(ioc_id)
127-
ioc, _ = iocs_update(ioc, request)
133+
134+
request_data = call_deprecated_on_preload_modules_hook('ioc_update', request, ioc.case_id)
135+
136+
# validate before saving
137+
ioc_schema = IocSchema()
138+
request_data['ioc_id'] = ioc.ioc_id
139+
request_data['case_id'] = ioc.case_id
140+
ioc_sc = ioc_schema.load(request_data, instance=ioc, partial=True)
141+
ioc = iocs_update(ioc, ioc_sc)
128142
return IOCCreate(ioc=ioc)
129143

130144

source/app/blueprints/pages/login/login_routes.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@
4848
from app.iris_engine.access_control.iris_user import iris_current_user
4949
from app.iris_engine.utils.tracker import track_activity
5050
from app.datamgmt.manage.manage_groups_db import get_groups_list
51+
from app.business.auth import generate_auth_tokens
52+
from app.schema.marshables import UserSchema
5153

5254
login_blueprint = Blueprint(
5355
'login',
@@ -89,7 +91,13 @@ def _authenticate_ldap(form, username, password, local_fallback=True):
8991
if user is None:
9092
return _render_template_login(form, 'Wrong credentials. Please try again.')
9193

92-
return wrap_login_user(user)
94+
user_data = UserSchema(exclude=['user_password', 'mfa_secrets', 'webauthn_credentials']).dump(user)
95+
96+
# Generate auth tokens for API access
97+
tokens = generate_auth_tokens(user)
98+
user_data.update({'tokens': tokens})
99+
100+
return wrap_login_user(user_data)
93101

94102
except Exception as e:
95103
log.error(e.__str__())

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ def add_case_modal(caseid: int, url_redir: bool):
122122
is_server_administrator=ac_current_user_has_permission(
123123
Permissions.server_administrator))
124124

125-
form.case_customer.choices = [(c['customer_id'], c['customer_name']) for c in client_list]
125+
form.case_customer_id.choices = [(c['customer_id'], c['customer_name']) for c in client_list]
126126

127127
form.classification_id.choices = [(clc['id'], clc['name_expanded']) for clc in get_case_classifications_list()]
128128
form.case_template_id.choices = [(ctp['id'], ctp['display_name']) for ctp in get_case_templates_list()]

source/app/blueprints/pages/manage/templates/modal_add_case.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ <h4>Create a new case</h4>
1616

1717
<div class="mt-4">
1818
<div class="input-group mb-4">
19-
{{ form.case_customer(class="selectpicker form-control") }}
19+
{{ form.case_customer_id(class="selectpicker form-control") }}
2020
</div>
2121
<div class="input-group mb-4">
2222
<div class="input-group-prepend">

source/app/blueprints/rest/case/case_evidences_routes.py

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
from datetime import datetime
2020

21-
import marshmallow
21+
from marshmallow import ValidationError
2222
from flask import Blueprint
2323
from flask import request
2424

@@ -46,6 +46,7 @@
4646
from app.business.evidences import evidences_delete
4747
from app.business.evidences import evidences_update
4848
from app.business.errors import BusinessProcessingError
49+
from app.iris_engine.module_handler.module_handler import call_deprecated_on_preload_modules_hook
4950

5051

5152
case_evidences_rest_blueprint = Blueprint('case_evidences_rest', __name__)
@@ -81,11 +82,16 @@ def case_rfiles_state(caseid):
8182
@ac_requires_case_identifier(CaseAccessLevel.full_access)
8283
@ac_api_requires()
8384
def case_add_rfile(caseid):
85+
evidence_schema = CaseEvidenceSchema()
8486
try:
85-
evidence = evidences_create(caseid, request.get_json())
86-
evidence_schema = CaseEvidenceSchema()
87+
request_data = call_deprecated_on_preload_modules_hook('evidence_create', request.get_json(), caseid)
88+
evidence = evidence_schema.load(request_data)
89+
90+
evidence = evidences_create(caseid, evidence)
8791
return response_success('Evidence added', data=evidence_schema.dump(evidence))
8892

93+
except ValidationError as e:
94+
return response_error('Data error', data=e.messages)
8995
except BusinessProcessingError as e:
9096
return response_error(e.get_message(), data=e.get_data())
9197

@@ -108,18 +114,22 @@ def case_get_evidence(cur_id, caseid):
108114
@ac_requires_case_identifier(CaseAccessLevel.full_access)
109115
@ac_api_requires()
110116
def case_edit_rfile(cur_id, caseid):
117+
evidence_schema = CaseEvidenceSchema()
111118
try:
112119
crf = get_rfile(cur_id)
113120
if not crf:
114121
return response_error('Invalid evidence ID for this case')
115122

116-
evd = evidences_update(crf, request.get_json())
123+
request_data = call_deprecated_on_preload_modules_hook('evidence_update', request.get_json(), crf.case_id)
124+
request_data['id'] = crf.id
125+
evidence = evidence_schema.load(request_data, instance=crf, partial=True)
126+
127+
evd = evidences_update(evidence)
117128

118-
evidence_schema = CaseEvidenceSchema()
119129
return response_success(f'Evidence {evd.filename} updated', data=evidence_schema.dump(evd))
120130

121-
except marshmallow.exceptions.ValidationError as e:
122-
return response_error(msg="Data error", data=e.messages)
131+
except ValidationError as e:
132+
return response_error(msg='Data error', data=e.messages)
123133

124134
except BusinessProcessingError as e:
125135
return response_error(e.get_message(), data=e.get_data())
@@ -184,7 +194,7 @@ def case_comment_evidence_add(cur_id, caseid):
184194
track_activity(f"evidence \"{evidence.filename}\" commented", caseid=caseid)
185195
return response_success("Evidence commented", data=comment_schema.dump(comment))
186196

187-
except marshmallow.exceptions.ValidationError as e:
197+
except ValidationError as e:
188198
return response_error(msg="Data error", data=e.normalized_messages())
189199

190200

source/app/blueprints/rest/case/case_ioc_routes.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import marshmallow
2424
from flask import Blueprint
2525
from flask import request
26+
from marshmallow import ValidationError
2627

2728
from app import db
2829
from app.blueprints.rest.case_comments import case_comment_update
@@ -56,6 +57,7 @@
5657
from app.blueprints.access_controls import ac_api_return_access_denied
5758
from app.blueprints.responses import response_error
5859
from app.blueprints.responses import response_success
60+
from app.iris_engine.module_handler.module_handler import call_deprecated_on_preload_modules_hook
5961

6062
case_ioc_rest_blueprint = Blueprint('case_ioc_rest', __name__)
6163

@@ -104,8 +106,13 @@ def deprecated_case_add_ioc(caseid):
104106
ioc_schema = IocSchema()
105107

106108
try:
107-
ioc, msg = iocs_create(request.get_json(), caseid)
108-
return response_success(msg, data=ioc_schema.dump(ioc))
109+
request_data = call_deprecated_on_preload_modules_hook('ioc_create', request.get_json(), caseid)
110+
request_data['case_id'] = caseid
111+
ioc = ioc_schema.load(request_data)
112+
ioc = iocs_create(ioc)
113+
return response_success('IOC added', data=ioc_schema.dump(ioc))
114+
except ValidationError as e:
115+
return response_error('Data error', e.messages)
109116
except BusinessProcessingError as e:
110117
return response_error(e.get_message(), data=e.get_data())
111118

@@ -240,8 +247,19 @@ def case_update_ioc(cur_id, caseid):
240247

241248
try:
242249
ioc = iocs_get(cur_id)
243-
ioc, msg = iocs_update(ioc, request.get_json())
244-
return response_success(msg, data=ioc_schema.dump(ioc))
250+
251+
request_data = call_deprecated_on_preload_modules_hook('ioc_update', request.get_json(), ioc.case_id)
252+
253+
# validate before saving
254+
request_data['ioc_id'] = ioc.ioc_id
255+
request_data['case_id'] = ioc.case_id
256+
ioc_sc = ioc_schema.load(request_data, instance=ioc, partial=True)
257+
ioc = iocs_update(ioc, ioc_sc)
258+
return response_success(f'Updated ioc "{ioc.ioc_value}"', data=ioc_schema.dump(ioc))
259+
260+
except ValidationError as e:
261+
return response_error('Data error', e.messages)
262+
245263
except BusinessProcessingError as e:
246264
return response_error(e.get_message(), data=e.get_data())
247265

source/app/blueprints/rest/case/case_tasks_routes.py

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
from datetime import datetime
2020

21-
import marshmallow
21+
from marshmallow import ValidationError
2222
from flask import Blueprint
2323
from flask import request
2424

@@ -49,6 +49,7 @@
4949
from app.blueprints.access_controls import ac_api_requires
5050
from app.blueprints.responses import response_error
5151
from app.blueprints.responses import response_success
52+
from app.iris_engine.module_handler.module_handler import call_deprecated_on_preload_modules_hook
5253

5354
case_tasks_rest_blueprint = Blueprint('case_tasks_rest', __name__)
5455

@@ -110,9 +111,22 @@ def case_task_status_update(cur_id: int, caseid: int):
110111
def deprecated_case_add_task(caseid: int):
111112
task_schema = CaseTaskSchema()
112113
try:
113-
msg, task = tasks_create(case_identifier=caseid,
114-
request_json=request.get_json())
115-
return response_success(msg, data=task_schema.dump(task))
114+
request_data = call_deprecated_on_preload_modules_hook('task_create', request.get_json(), caseid)
115+
116+
if 'task_assignee_id' in request_data or 'task_assignees_id' not in request_data:
117+
raise BusinessProcessingError('task_assignee_id is not valid anymore since v1.5.0')
118+
119+
task_assignee_list = request_data['task_assignees_id']
120+
del request_data['task_assignees_id']
121+
122+
task = task_schema.load(request_data)
123+
task.task_case_id = caseid
124+
task = tasks_create(task, task_assignee_list)
125+
return response_success(f'Task "{task.task_title}" added', data=task_schema.dump(task))
126+
127+
except ValidationError as e:
128+
return response_error('Data error', e.messages)
129+
116130
except BusinessProcessingError as e:
117131
return response_error(e.get_message(), data=e.get_data())
118132

@@ -136,18 +150,29 @@ def deprecated_case_task_view(cur_id: int, caseid: int):
136150
@ac_requires_case_identifier(CaseAccessLevel.full_access)
137151
@ac_api_requires()
138152
def deprecated_case_edit_task(cur_id: int, caseid: int):
153+
task_schema = CaseTaskSchema()
139154
try:
140155
task = get_task(task_id=cur_id)
141156
if not task:
142157
return response_error(msg='Invalid task ID for this case')
143158

144-
task = tasks_update(task, request.get_json())
145-
task_schema = CaseTaskSchema()
159+
case_identifier = task.task_case_id
160+
request_data = call_deprecated_on_preload_modules_hook('task_update', request.get_json(), case_identifier)
146161

147-
return response_success(msg='Task updated', data=task_schema.dump(task))
162+
if 'task_assignee_id' in request_data or 'task_assignees_id' not in request_data:
163+
return response_error('task_assignee_id is not valid anymore since v1.5.0')
164+
165+
task_assignee_list = request_data['task_assignees_id']
166+
del request_data['task_assignees_id']
167+
168+
request_data['id'] = task.id
169+
task = task_schema.load(request_data, instance=task)
148170

149-
except marshmallow.exceptions.ValidationError as e:
150-
return response_error(msg='Data error', data=e.messages)
171+
task = tasks_update(task, task_assignee_list)
172+
173+
return response_success(msg='Task updated', data=task_schema.dump(task))
174+
except ValidationError as e:
175+
return response_error('Data error', data=e.messages)
151176

152177

153178
@case_tasks_rest_blueprint.route('/case/tasks/delete/<int:cur_id>', methods=['POST'])
@@ -160,7 +185,7 @@ def deprecated_case_delete_task(cur_id: int, caseid: int):
160185
tasks_delete(task)
161186
return response_success('Task deleted')
162187
except BusinessProcessingError as e:
163-
return response_error(msg=e.get_message(), data=e.get_data())
188+
return response_error(e.get_message(), data=e.get_data())
164189

165190

166191
@case_tasks_rest_blueprint.route('/case/tasks/<int:cur_id>/comments/list', methods=['GET'])
@@ -210,7 +235,7 @@ def case_comment_task_add(cur_id: int, caseid: int):
210235
track_activity(f"task \"{task.task_title}\" commented", caseid=caseid)
211236
return response_success("Task commented", data=comment_schema.dump(comment))
212237

213-
except marshmallow.exceptions.ValidationError as e:
238+
except ValidationError as e:
214239
return response_error(msg="Data error", data=e.normalized_messages())
215240

216241

0 commit comments

Comments
 (0)