Aucune description

case_evidences_routes.py 9.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. # IRIS Source Code
  2. # Copyright (C) 2024 - DFIR-IRIS
  3. # contact@dfir-iris.org
  4. #
  5. # This program is free software; you can redistribute it and/or
  6. # modify it under the terms of the GNU Lesser General Public
  7. # License as published by the Free Software Foundation; either
  8. # version 3 of the License, or (at your option) any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. # Lesser General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU Lesser General Public License
  16. # along with this program; if not, write to the Free Software Foundation,
  17. # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  18. from datetime import datetime
  19. import marshmallow
  20. from flask import Blueprint
  21. from flask import request
  22. from flask_login import current_user
  23. from app import db
  24. from app.blueprints.rest.case_comments import case_comment_update
  25. from app.datamgmt.case.case_rfiles_db import add_comment_to_evidence
  26. from app.datamgmt.case.case_rfiles_db import add_rfile
  27. from app.datamgmt.case.case_rfiles_db import delete_evidence_comment
  28. from app.datamgmt.case.case_rfiles_db import delete_rfile
  29. from app.datamgmt.case.case_rfiles_db import get_case_evidence_comment
  30. from app.datamgmt.case.case_rfiles_db import get_case_evidence_comments
  31. from app.datamgmt.case.case_rfiles_db import get_rfile
  32. from app.datamgmt.case.case_rfiles_db import get_rfiles
  33. from app.datamgmt.case.case_rfiles_db import update_rfile
  34. from app.datamgmt.states import get_evidences_state
  35. from app.iris_engine.module_handler.module_handler import call_modules_hook
  36. from app.iris_engine.utils.tracker import track_activity
  37. from app.models.authorization import CaseAccessLevel
  38. from app.schema.marshables import CaseEvidenceSchema
  39. from app.schema.marshables import CommentSchema
  40. from app.blueprints.access_controls import ac_requires_case_identifier
  41. from app.blueprints.access_controls import ac_api_requires
  42. from app.blueprints.responses import response_error
  43. from app.blueprints.responses import response_success
  44. case_evidences_rest_blueprint = Blueprint('case_evidences_rest', __name__)
  45. @case_evidences_rest_blueprint.route('/case/evidences/list', methods=['GET'])
  46. @ac_requires_case_identifier(CaseAccessLevel.read_only, CaseAccessLevel.full_access)
  47. @ac_api_requires()
  48. def case_list_rfiles(caseid):
  49. crf = get_rfiles(caseid)
  50. ret = {
  51. "evidences": CaseEvidenceSchema().dump(crf, many=True),
  52. "state": get_evidences_state(caseid=caseid)
  53. }
  54. return response_success("", data=ret)
  55. @case_evidences_rest_blueprint.route('/case/evidences/state', methods=['GET'])
  56. @ac_requires_case_identifier(CaseAccessLevel.read_only, CaseAccessLevel.full_access)
  57. @ac_api_requires()
  58. def case_rfiles_state(caseid):
  59. os = get_evidences_state(caseid=caseid)
  60. if os:
  61. return response_success(data=os)
  62. return response_error('No evidences state for this case.')
  63. @case_evidences_rest_blueprint.route('/case/evidences/add', methods=['POST'])
  64. @ac_requires_case_identifier(CaseAccessLevel.full_access)
  65. @ac_api_requires()
  66. def case_add_rfile(caseid):
  67. try:
  68. # validate before saving
  69. evidence_schema = CaseEvidenceSchema()
  70. request_data = call_modules_hook('on_preload_evidence_create', data=request.get_json(), caseid=caseid)
  71. evidence = evidence_schema.load(request_data)
  72. crf = add_rfile(evidence=evidence,
  73. user_id=current_user.id,
  74. caseid=caseid
  75. )
  76. crf = call_modules_hook('on_postload_evidence_create', data=crf, caseid=caseid)
  77. if crf:
  78. track_activity(f"added evidence \"{crf.filename}\"", caseid=caseid)
  79. return response_success("Evidence added", data=evidence_schema.dump(crf))
  80. return response_error("Unable to create task for internal reasons")
  81. except marshmallow.exceptions.ValidationError as e:
  82. return response_error(msg="Data error", data=e.messages)
  83. @case_evidences_rest_blueprint.route('/case/evidences/<int:cur_id>', methods=['GET'])
  84. @ac_requires_case_identifier(CaseAccessLevel.read_only, CaseAccessLevel.full_access)
  85. @ac_api_requires()
  86. def case_get_evidence(cur_id, caseid):
  87. crf = get_rfile(cur_id, caseid)
  88. if not crf:
  89. return response_error("Invalid evidence ID for this case")
  90. evidence_schema = CaseEvidenceSchema()
  91. return response_success(data=evidence_schema.dump(crf))
  92. @case_evidences_rest_blueprint.route('/case/evidences/update/<int:cur_id>', methods=['POST'])
  93. @ac_requires_case_identifier(CaseAccessLevel.full_access)
  94. @ac_api_requires()
  95. def case_edit_rfile(cur_id, caseid):
  96. try:
  97. # validate before saving
  98. evidence_schema = CaseEvidenceSchema()
  99. request_data = call_modules_hook('on_preload_evidence_update', data=request.get_json(), caseid=caseid)
  100. crf = get_rfile(cur_id, caseid)
  101. if not crf:
  102. return response_error("Invalid evidence ID for this case")
  103. request_data['id'] = cur_id
  104. evidence = evidence_schema.load(request_data, instance=crf)
  105. evd = update_rfile(evidence=evidence,
  106. user_id=current_user.id,
  107. caseid=caseid
  108. )
  109. evd = call_modules_hook('on_postload_evidence_update', data=evd, caseid=caseid)
  110. if evd:
  111. track_activity(f"updated evidence \"{evd.filename}\"", caseid=caseid)
  112. return response_success("Evidence {} updated".format(evd.filename), data=evidence_schema.dump(evd))
  113. return response_error("Unable to update task for internal reasons")
  114. except marshmallow.exceptions.ValidationError as e:
  115. return response_error(msg="Data error", data=e.messages)
  116. @case_evidences_rest_blueprint.route('/case/evidences/delete/<int:cur_id>', methods=['POST'])
  117. @ac_requires_case_identifier(CaseAccessLevel.full_access)
  118. @ac_api_requires()
  119. def case_delete_rfile(cur_id, caseid):
  120. call_modules_hook('on_preload_evidence_delete', data=cur_id, caseid=caseid)
  121. crf = get_rfile(cur_id, caseid)
  122. if not crf:
  123. return response_error("Invalid evidence ID for this case")
  124. delete_rfile(cur_id, caseid=caseid)
  125. call_modules_hook('on_postload_evidence_delete', data=cur_id, caseid=caseid)
  126. track_activity(f"deleted evidence \"{crf.filename}\" from registry", caseid)
  127. return response_success("Evidence deleted")
  128. @case_evidences_rest_blueprint.route('/case/evidences/<int:cur_id>/comments/list', methods=['GET'])
  129. @ac_requires_case_identifier(CaseAccessLevel.read_only, CaseAccessLevel.full_access)
  130. @ac_api_requires()
  131. def case_comment_evidence_list(cur_id, caseid):
  132. evidence_comments = get_case_evidence_comments(cur_id)
  133. if evidence_comments is None:
  134. return response_error('Invalid evidence ID')
  135. return response_success(data=CommentSchema(many=True).dump(evidence_comments))
  136. @case_evidences_rest_blueprint.route('/case/evidences/<int:cur_id>/comments/add', methods=['POST'])
  137. @ac_requires_case_identifier(CaseAccessLevel.full_access)
  138. @ac_api_requires()
  139. def case_comment_evidence_add(cur_id, caseid):
  140. try:
  141. evidence = get_rfile(cur_id, caseid=caseid)
  142. if not evidence:
  143. return response_error('Invalid evidence ID')
  144. comment_schema = CommentSchema()
  145. comment = comment_schema.load(request.get_json())
  146. comment.comment_case_id = caseid
  147. comment.comment_user_id = current_user.id
  148. comment.comment_date = datetime.now()
  149. comment.comment_update_date = datetime.now()
  150. db.session.add(comment)
  151. db.session.commit()
  152. add_comment_to_evidence(evidence.id, comment.comment_id)
  153. db.session.commit()
  154. hook_data = {
  155. "comment": comment_schema.dump(comment),
  156. "evidence": CaseEvidenceSchema().dump(evidence)
  157. }
  158. call_modules_hook('on_postload_evidence_commented', data=hook_data, caseid=caseid)
  159. track_activity(f"evidence \"{evidence.filename}\" commented", caseid=caseid)
  160. return response_success("Evidence commented", data=comment_schema.dump(comment))
  161. except marshmallow.exceptions.ValidationError as e:
  162. return response_error(msg="Data error", data=e.normalized_messages())
  163. @case_evidences_rest_blueprint.route('/case/evidences/<int:cur_id>/comments/<int:com_id>', methods=['GET'])
  164. @ac_requires_case_identifier(CaseAccessLevel.read_only, CaseAccessLevel.full_access)
  165. @ac_api_requires()
  166. def case_comment_evidence_get(cur_id, com_id, caseid):
  167. comment = get_case_evidence_comment(cur_id, com_id)
  168. if not comment:
  169. return response_error("Invalid comment ID")
  170. return response_success(data=comment._asdict())
  171. @case_evidences_rest_blueprint.route('/case/evidences/<int:cur_id>/comments/<int:com_id>/edit', methods=['POST'])
  172. @ac_requires_case_identifier(CaseAccessLevel.full_access)
  173. @ac_api_requires()
  174. def case_comment_evidence_edit(cur_id, com_id, caseid):
  175. return case_comment_update(com_id, 'tasks', caseid)
  176. @case_evidences_rest_blueprint.route('/case/evidences/<int:cur_id>/comments/<int:com_id>/delete', methods=['POST'])
  177. @ac_requires_case_identifier(CaseAccessLevel.full_access)
  178. @ac_api_requires()
  179. def case_comment_evidence_delete(cur_id, com_id, caseid):
  180. success, msg = delete_evidence_comment(cur_id, com_id)
  181. if not success:
  182. return response_error(msg)
  183. call_modules_hook('on_postload_evidence_comment_delete', data=com_id, caseid=caseid)
  184. track_activity(f"comment {com_id} on evidence {cur_id} deleted", caseid=caseid)
  185. return response_success(msg)