Sin descripción

iocs.py 6.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  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 flask_login import current_user
  19. from marshmallow.exceptions import ValidationError
  20. from app import db
  21. from app.models.models import Ioc
  22. from app.datamgmt.case.case_iocs_db import add_ioc
  23. from app.datamgmt.case.case_iocs_db import case_iocs_db_exists
  24. from app.datamgmt.case.case_iocs_db import check_ioc_type_id
  25. from app.datamgmt.case.case_iocs_db import get_iocs
  26. from app.datamgmt.case.case_iocs_db import delete_ioc
  27. from app.datamgmt.states import update_ioc_state
  28. from app.schema.marshables import IocSchema
  29. from app.iris_engine.module_handler.module_handler import call_modules_hook
  30. from app.iris_engine.utils.tracker import track_activity
  31. from app.business.errors import BusinessProcessingError
  32. from app.business.errors import ObjectNotFoundError
  33. from app.datamgmt.case.case_iocs_db import get_ioc
  34. def _load(request_data):
  35. try:
  36. add_ioc_schema = IocSchema()
  37. return add_ioc_schema.load(request_data)
  38. except ValidationError as e:
  39. raise BusinessProcessingError('Data error', e.messages)
  40. def iocs_get(ioc_identifier) -> Ioc:
  41. ioc = get_ioc(ioc_identifier)
  42. if not ioc:
  43. raise ObjectNotFoundError()
  44. return ioc
  45. def iocs_create(request_json, case_identifier):
  46. # TODO ideally schema validation should be done before, outside the business logic in the REST API
  47. # for that the hook should be called after schema validation
  48. request_data = call_modules_hook('on_preload_ioc_create', data=request_json, caseid=case_identifier)
  49. ioc = _load({**request_data, 'case_id': case_identifier})
  50. if not ioc:
  51. raise BusinessProcessingError('Unable to create IOC for internal reasons')
  52. if not check_ioc_type_id(type_id=ioc.ioc_type_id):
  53. raise BusinessProcessingError('Not a valid IOC type')
  54. if case_iocs_db_exists(ioc):
  55. raise BusinessProcessingError('IOC with same value and type already exists')
  56. add_ioc(ioc, current_user.id, case_identifier)
  57. ioc = call_modules_hook('on_postload_ioc_create', data=ioc, caseid=case_identifier)
  58. if ioc:
  59. track_activity(f'added ioc "{ioc.ioc_value}"', caseid=case_identifier)
  60. msg = 'IOC added'
  61. return ioc, msg
  62. raise BusinessProcessingError('Unable to create IOC for internal reasons')
  63. def iocs_update(ioc: Ioc, request_json: dict) -> (Ioc, str):
  64. """
  65. Identifier: the IOC identifier
  66. Request JSON: the Request
  67. """
  68. try:
  69. # TODO ideally schema validation should be done before, outside the business logic in the REST API
  70. # for that the hook should be called after schema validation
  71. request_data = call_modules_hook('on_preload_ioc_update', data=request_json, caseid=ioc.case_id)
  72. # validate before saving
  73. ioc_schema = IocSchema()
  74. request_data['ioc_id'] = ioc.ioc_id
  75. request_data['case_id'] = ioc.case_id
  76. ioc_sc = ioc_schema.load(request_data, instance=ioc, partial=True)
  77. ioc_sc.user_id = current_user.id
  78. if not check_ioc_type_id(type_id=ioc_sc.ioc_type_id):
  79. raise BusinessProcessingError('Not a valid IOC type')
  80. update_ioc_state(ioc.case_id)
  81. db.session.commit()
  82. ioc_sc = call_modules_hook('on_postload_ioc_update', data=ioc_sc, caseid=ioc.case_id)
  83. if ioc_sc:
  84. track_activity(f'updated ioc "{ioc_sc.ioc_value}"', caseid=ioc.case_id)
  85. return ioc, f'Updated ioc "{ioc_sc.ioc_value}"'
  86. raise BusinessProcessingError('Unable to update ioc for internal reasons')
  87. # TODO most probably the scope of this try catch could be reduced, this exception is probably raised only on load
  88. except ValidationError as e:
  89. raise BusinessProcessingError('Data error', e.messages)
  90. except Exception as e:
  91. raise BusinessProcessingError('Unexpected error server-side', e)
  92. def iocs_delete(ioc: Ioc):
  93. call_modules_hook('on_preload_ioc_delete', data=ioc.ioc_id)
  94. delete_ioc(ioc)
  95. call_modules_hook('on_postload_ioc_delete', data=ioc.ioc_id, caseid=ioc.case_id)
  96. track_activity(f'deleted IOC "{ioc.ioc_value}"', caseid=ioc.case_id)
  97. return f'IOC {ioc.ioc_id} deleted'
  98. def iocs_exports_to_json(case_id):
  99. iocs = get_iocs(case_id)
  100. return IocSchema().dump(iocs, many=True)
  101. def iocs_build_filter_query(ioc_id: int = None,
  102. ioc_uuid: str = None,
  103. ioc_value: str = None,
  104. ioc_type_id: int = None,
  105. ioc_description: str = None,
  106. ioc_tlp_id: int = None,
  107. ioc_tags: str = None,
  108. ioc_misp: str = None,
  109. user_id: float = None):
  110. """
  111. Get a list of iocs from the database, filtered by the given parameters
  112. """
  113. conditions = []
  114. if ioc_id is not None:
  115. conditions.append(Ioc.ioc_id == ioc_id)
  116. if ioc_uuid is not None:
  117. conditions.append(Ioc.ioc_uuid == ioc_uuid)
  118. if ioc_value is not None:
  119. conditions.append(Ioc.ioc_value == ioc_value)
  120. if ioc_type_id is not None:
  121. conditions.append(Ioc.ioc_type_id == ioc_type_id)
  122. if ioc_description is not None:
  123. conditions.append(Ioc.ioc_description == ioc_description)
  124. if ioc_tlp_id is not None:
  125. conditions.append(Ioc.ioc_tlp_id == ioc_tlp_id)
  126. if ioc_tags is not None:
  127. conditions.append(Ioc.ioc_tags == ioc_tags)
  128. if ioc_misp is not None:
  129. conditions.append(Ioc.ioc_misp == ioc_misp)
  130. if user_id is not None:
  131. conditions.append(Ioc.user_id == user_id)
  132. return Ioc.query.filter(*conditions)