Skip to content

Commit a2e845e

Browse files
authored
Merge pull request #925 from dfir-iris/api_v2_delete_comments
Api v2 delete comments
2 parents 357d9bb + d5ea695 commit a2e845e

File tree

30 files changed

+480
-42
lines changed

30 files changed

+480
-42
lines changed

.github/workflows/ci.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,11 +183,16 @@ jobs:
183183
source venv/bin/activate
184184
pip install -r requirements.txt
185185
PYTHONUNBUFFERED=true python -m unittest --verbose
186+
- name: Check the absence of errors/stack traces in logs
187+
run: |
188+
! docker compose logs app | grep Traceback -A100
186189
- name: Stop development server
190+
if: ${{ always() }}
187191
run: |
188192
docker compose logs app > ${{ runner.temp }}/iriswebapp_app.log
189193
docker compose down
190194
- name: Upload artifact
195+
if: ${{ always() }}
191196
uses: actions/upload-artifact@v4
192197
with:
193198
name: Test API iriswebapp_app logs

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@
4242
from app.business.auth import validate_ldap_login
4343
from app.business.users import retrieve_user_by_username
4444
from app.business.auth import wrap_login_user
45-
from app.datamgmt.manage.manage_users_db import create_user, update_user_groups
45+
from app.datamgmt.manage.manage_users_db import create_user
46+
from app.datamgmt.manage.manage_users_db import update_user_groups
4647
from app.datamgmt.manage.manage_users_db import get_user
4748
from app.forms import LoginForm, MFASetupForm
4849
from app.iris_engine.access_control.iris_user import iris_current_user

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -408,11 +408,11 @@ def case_comment_asset_edit(cur_id, com_id, caseid):
408408
@ac_requires_case_identifier(CaseAccessLevel.full_access)
409409
@ac_api_requires()
410410
def case_comment_asset_delete(cur_id, com_id, caseid):
411-
success, msg = delete_asset_comment(cur_id, com_id, caseid)
411+
success, msg = delete_asset_comment(cur_id, com_id)
412412
if not success:
413413
return response_error(msg)
414414

415415
call_modules_hook('on_postload_asset_comment_delete', data=com_id, caseid=caseid)
416416

417-
track_activity(f"comment {com_id} on asset {cur_id} deleted", caseid=caseid)
417+
track_activity(f'comment {com_id} on asset {cur_id} deleted', caseid=caseid)
418418
return response_success(msg)

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
from app.schema.marshables import UserSchema
4646
from app.schema.marshables import BasicUserSchema
4747
from app.schema.marshables import UserFullSchema
48+
from app.business.groups import groups_exist
4849

4950
from app.blueprints.access_controls import ac_api_requires
5051
from app.blueprints.access_controls import ac_api_return_access_denied
@@ -171,8 +172,12 @@ def manage_user_group_(cur_id):
171172
if not user:
172173
return response_error("Invalid user ID")
173174

174-
update_user_groups(user_id=cur_id,
175-
groups=request.json.get('groups_membership'))
175+
groups = request.json.get('groups_membership')
176+
for group_identifier in groups:
177+
if not groups_exist(group_identifier):
178+
return response_error(f'No group with identifier {group_identifier}')
179+
180+
update_user_groups(cur_id, groups)
176181

177182
track_activity(f"groups membership of user {cur_id} updated", ctx_less=True)
178183

source/app/blueprints/rest/v2/alerts_routes/comments.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,14 @@
2626
from app.blueprints.rest.endpoints import response_api_success
2727
from app.blueprints.rest.endpoints import response_api_not_found
2828
from app.blueprints.rest.endpoints import response_api_created
29+
from app.blueprints.rest.endpoints import response_api_deleted
2930
from app.blueprints.rest.endpoints import response_api_error
3031
from app.blueprints.rest.parsing import parse_pagination_parameters
32+
from app.blueprints.access_controls import ac_api_return_access_denied
3133
from app.schema.marshables import CommentSchema
3234
from app.business.comments import comments_get_filtered_by_alert
3335
from app.business.comments import comments_create_for_alert
36+
from app.business.comments import comments_delete_for_alert
3437
from app.business.comments import comments_get_for_alert
3538
from app.business.alerts import alerts_get
3639
from app.iris_engine.access_control.iris_user import iris_current_user
@@ -72,6 +75,18 @@ def read(self, alert_identifier, identifier):
7275
except ObjectNotFoundError:
7376
return response_api_not_found()
7477

78+
def delete(self, alert_identifier, identifier):
79+
try:
80+
alert = alerts_get(iris_current_user, alert_identifier)
81+
comment = comments_get_for_alert(alert, identifier)
82+
if comment.comment_user_id != iris_current_user.id:
83+
return ac_api_return_access_denied()
84+
85+
comments_delete_for_alert(comment)
86+
return response_api_deleted()
87+
except ObjectNotFoundError:
88+
return response_api_not_found()
89+
7590

7691
alerts_comments_blueprint = Blueprint('alerts_comments', __name__, url_prefix='/<int:alert_identifier>/comments')
7792
comments_operations = CommentsOperations()
@@ -93,3 +108,9 @@ def create_alerts_comment(alert_identifier):
93108
@ac_api_requires(Permissions.alerts_read)
94109
def get_alerts_comment(alert_identifier, identifier):
95110
return comments_operations.read(alert_identifier, identifier)
111+
112+
113+
@alerts_comments_blueprint.delete('/<int:identifier>')
114+
@ac_api_requires(Permissions.alerts_write)
115+
def delete_alerts_comment(alert_identifier, identifier):
116+
return comments_operations.delete(alert_identifier, identifier)

source/app/blueprints/rest/v2/assets_routes/comments.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,13 @@
2626
from app.blueprints.rest.endpoints import response_api_created
2727
from app.blueprints.rest.endpoints import response_api_error
2828
from app.blueprints.rest.endpoints import response_api_success
29+
from app.blueprints.rest.endpoints import response_api_deleted
30+
from app.blueprints.access_controls import ac_api_return_access_denied
2931
from app.blueprints.rest.parsing import parse_pagination_parameters
3032
from app.business.comments import comments_get_filtered_by_asset
3133
from app.business.comments import comments_create_for_asset
3234
from app.business.comments import comments_get_for_asset
35+
from app.business.comments import comments_delete_for_asset
3336
from app.business.assets import assets_get
3437
from app.business.errors import ObjectNotFoundError
3538
from app.schema.marshables import CommentSchema
@@ -85,6 +88,18 @@ def read(self, asset_identifier, identifier):
8588
except ObjectNotFoundError:
8689
return response_api_not_found()
8790

91+
def delete(self, asset_identifier, identifier):
92+
try:
93+
asset = self._get_asset(asset_identifier, [CaseAccessLevel.full_access])
94+
comment = comments_get_for_asset(asset, identifier)
95+
if comment.comment_user_id != iris_current_user.id:
96+
return ac_api_return_access_denied()
97+
98+
comments_delete_for_asset(asset, comment)
99+
return response_api_deleted()
100+
except ObjectNotFoundError:
101+
return response_api_not_found()
102+
88103

89104
assets_comments_blueprint = Blueprint('assets_comments', __name__, url_prefix='/<int:asset_identifier>/comments')
90105
comments_operations = CommentsOperations()
@@ -106,3 +121,9 @@ def create_assets_comment(asset_identifier):
106121
@ac_api_requires()
107122
def get_assets_comment(asset_identifier, identifier):
108123
return comments_operations.read(asset_identifier, identifier)
124+
125+
126+
@assets_comments_blueprint.delete('/<int:identifier>')
127+
@ac_api_requires()
128+
def delete_alerts_comment(asset_identifier, identifier):
129+
return comments_operations.delete(asset_identifier, identifier)

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

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ def _get_asset_in_case(identifier, case_identifier):
5656
raise ObjectNotFoundError
5757
return asset
5858

59-
def list(self, case_identifier):
59+
def search(self, case_identifier):
6060
if not ac_fast_check_current_user_has_case_access(case_identifier,
6161
[CaseAccessLevel.read_only, CaseAccessLevel.full_access]):
6262
return ac_api_return_access_denied(caseid=case_identifier)
@@ -97,7 +97,7 @@ def create(self, case_identifier):
9797
except BusinessProcessingError as e:
9898
return response_api_error(e.get_message(), data=e.get_data())
9999

100-
def get(self, case_identifier, identifier):
100+
def read(self, case_identifier, identifier):
101101
try:
102102
asset = self._get_asset_in_case(identifier, case_identifier)
103103

@@ -140,7 +140,6 @@ def delete(self, case_identifier, identifier):
140140
try:
141141
asset = self._get_asset_in_case(identifier, case_identifier)
142142

143-
# perform authz check
144143
if not ac_fast_check_current_user_has_case_access(asset.case_id, [CaseAccessLevel.full_access]):
145144
return ac_api_return_access_denied(caseid=asset.case_id)
146145

@@ -161,7 +160,7 @@ def delete(self, case_identifier, identifier):
161160
@case_assets_blueprint.get('')
162161
@ac_api_requires()
163162
def case_list_assets(case_identifier):
164-
return assets_operations.list(case_identifier)
163+
return assets_operations.search(case_identifier)
165164

166165

167166
@case_assets_blueprint.post('')
@@ -173,7 +172,7 @@ def add_asset(case_identifier):
173172
@case_assets_blueprint.get('/<int:identifier>')
174173
@ac_api_requires()
175174
def get_asset(case_identifier, identifier):
176-
return assets_operations.get(case_identifier, identifier)
175+
return assets_operations.read(case_identifier, identifier)
177176

178177

179178
@case_assets_blueprint.put('/<int:identifier>')

source/app/blueprints/rest/v2/events_routes/comments.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,19 @@
2121
from marshmallow import ValidationError
2222

2323
from app.blueprints.access_controls import ac_api_requires
24+
from app.blueprints.access_controls import ac_api_return_access_denied
2425
from app.blueprints.rest.endpoints import response_api_paginated
2526
from app.blueprints.rest.endpoints import response_api_not_found
2627
from app.blueprints.rest.endpoints import response_api_created
2728
from app.blueprints.rest.endpoints import response_api_error
2829
from app.blueprints.rest.endpoints import response_api_success
30+
from app.blueprints.rest.endpoints import response_api_deleted
2931
from app.blueprints.rest.parsing import parse_pagination_parameters
3032
from app.iris_engine.access_control.iris_user import iris_current_user
3133
from app.business.comments import comments_get_filtered_by_event
3234
from app.business.comments import comments_create_for_event
3335
from app.business.comments import comments_get_for_event
36+
from app.business.comments import comments_delete_for_event
3437
from app.business.events import events_get
3538
from app.business.errors import ObjectNotFoundError
3639
from app.models.cases import CasesEvent
@@ -86,6 +89,18 @@ def read(self, event_identifier, identifier):
8689
except ObjectNotFoundError:
8790
return response_api_not_found()
8891

92+
def delete(self, event_identifier, identifier):
93+
try:
94+
event = self._get_event(event_identifier, [CaseAccessLevel.full_access])
95+
comment = comments_get_for_event(event, identifier)
96+
if comment.comment_user_id != iris_current_user.id:
97+
return ac_api_return_access_denied()
98+
99+
comments_delete_for_event(event, comment)
100+
return response_api_deleted()
101+
except ObjectNotFoundError:
102+
return response_api_not_found()
103+
89104

90105
events_comments_blueprint = Blueprint('events_comments', __name__, url_prefix='/<int:event_identifier>/comments')
91106
comments_operations = CommentsOperations()
@@ -107,3 +122,9 @@ def create_event_comment(event_identifier):
107122
@ac_api_requires()
108123
def get_event_comment(event_identifier, identifier):
109124
return comments_operations.read(event_identifier, identifier)
125+
126+
127+
@events_comments_blueprint.delete('/<int:identifier>')
128+
@ac_api_requires()
129+
def delete_task_comment(event_identifier, identifier):
130+
return comments_operations.delete(event_identifier, identifier)

source/app/blueprints/rest/v2/evidences_routes/comments.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,19 @@
2121
from marshmallow import ValidationError
2222

2323
from app.blueprints.access_controls import ac_api_requires
24+
from app.blueprints.access_controls import ac_api_return_access_denied
2425
from app.blueprints.rest.endpoints import response_api_paginated
2526
from app.blueprints.rest.endpoints import response_api_not_found
2627
from app.blueprints.rest.endpoints import response_api_created
2728
from app.blueprints.rest.endpoints import response_api_error
2829
from app.blueprints.rest.endpoints import response_api_success
30+
from app.blueprints.rest.endpoints import response_api_deleted
2931
from app.iris_engine.access_control.iris_user import iris_current_user
3032
from app.blueprints.rest.parsing import parse_pagination_parameters
3133
from app.business.comments import comments_get_filtered_by_evidence
3234
from app.business.comments import comments_create_for_evidence
3335
from app.business.comments import comments_get_for_evidence
36+
from app.business.comments import comments_delete_for_evidence
3437
from app.models.models import CaseReceivedFile
3538
from app.business.evidences import evidences_get
3639
from app.business.errors import ObjectNotFoundError
@@ -87,6 +90,18 @@ def read(self, event_identifier, identifier):
8790
except ObjectNotFoundError:
8891
return response_api_not_found()
8992

93+
def delete(self, evidence_identifier, identifier):
94+
try:
95+
evidence = self._get_evidence(evidence_identifier, [CaseAccessLevel.full_access])
96+
comment = comments_get_for_evidence(evidence, identifier)
97+
if comment.comment_user_id != iris_current_user.id:
98+
return ac_api_return_access_denied()
99+
100+
comments_delete_for_evidence(evidence, comment)
101+
return response_api_deleted()
102+
except ObjectNotFoundError:
103+
return response_api_not_found()
104+
90105

91106
evidences_comments_blueprint = Blueprint('evidences_comments', __name__, url_prefix='/<int:evidence_identifier>/comments')
92107
comments_operations = CommentsOperations()
@@ -108,3 +123,9 @@ def create_evidence_comment(evidence_identifier):
108123
@ac_api_requires()
109124
def get_evidence_comment(evidence_identifier, identifier):
110125
return comments_operations.read(evidence_identifier, identifier)
126+
127+
128+
@evidences_comments_blueprint.delete('/<int:identifier>')
129+
@ac_api_requires()
130+
def delete_evidence_comment(evidence_identifier, identifier):
131+
return comments_operations.delete(evidence_identifier, identifier)

source/app/blueprints/rest/v2/iocs_routes/comments.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,18 @@
2222

2323
from app.iris_engine.access_control.iris_user import iris_current_user
2424
from app.blueprints.access_controls import ac_api_requires
25+
from app.blueprints.access_controls import ac_api_return_access_denied
2526
from app.blueprints.rest.endpoints import response_api_paginated
2627
from app.blueprints.rest.endpoints import response_api_not_found
2728
from app.blueprints.rest.endpoints import response_api_created
2829
from app.blueprints.rest.endpoints import response_api_error
2930
from app.blueprints.rest.endpoints import response_api_success
31+
from app.blueprints.rest.endpoints import response_api_deleted
3032
from app.blueprints.rest.parsing import parse_pagination_parameters
3133
from app.business.comments import comments_get_filtered_by_ioc
3234
from app.business.comments import comments_create_for_ioc
3335
from app.business.comments import comments_get_for_ioc
36+
from app.business.comments import comments_delete_for_ioc
3437
from app.business.iocs import iocs_get
3538
from app.business.errors import ObjectNotFoundError
3639
from app.schema.marshables import CommentSchema
@@ -85,6 +88,18 @@ def read(self, ioc_identifier, identifier):
8588
except ObjectNotFoundError:
8689
return response_api_not_found()
8790

91+
def delete(self, ioc_identifier, identifier):
92+
try:
93+
ioc = self._get_ioc(ioc_identifier, [CaseAccessLevel.full_access])
94+
comment = comments_get_for_ioc(ioc, identifier)
95+
if comment.comment_user_id != iris_current_user.id:
96+
return ac_api_return_access_denied()
97+
98+
comments_delete_for_ioc(ioc, comment)
99+
return response_api_deleted()
100+
except ObjectNotFoundError:
101+
return response_api_not_found()
102+
88103

89104
iocs_comments_blueprint = Blueprint('iocs_comments', __name__, url_prefix='/<int:ioc_identifier>/comments')
90105
comments_operations = CommentsOperations()
@@ -106,3 +121,9 @@ def create_iocs_comment(ioc_identifier):
106121
@ac_api_requires()
107122
def get_ioc_comment(ioc_identifier, identifier):
108123
return comments_operations.read(ioc_identifier, identifier)
124+
125+
126+
@iocs_comments_blueprint.delete('/<int:identifier>')
127+
@ac_api_requires()
128+
def delete_ioc_comment(ioc_identifier, identifier):
129+
return comments_operations.delete(ioc_identifier, identifier)

0 commit comments

Comments
 (0)