Нет описания

case_iocs_db.py 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. # IRIS Source Code
  2. # Copyright (C) 2021 - Airbus CyberSecurity (SAS)
  3. # ir@cyberactionlab.net
  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 sqlalchemy import and_
  20. from app import db
  21. from app import app
  22. from app.datamgmt.states import update_ioc_state
  23. from app.datamgmt.conversions import convert_sort_direction
  24. from app.iris_engine.access_control.utils import ac_get_fast_user_cases_access
  25. from app.models.cases import Cases
  26. from app.models.models import Client
  27. from app.models.models import Comments
  28. from app.models.models import Ioc
  29. from app.models.models import IocComments
  30. from app.models.models import IocType
  31. from app.models.models import Tlp
  32. from app.models.authorization import User
  33. from app.models.authorization import UserCaseEffectiveAccess
  34. from app.models.authorization import CaseAccessLevel
  35. from app.models.pagination_parameters import PaginationParameters
  36. def get_iocs(case_identifier) -> list[Ioc]:
  37. return Ioc.query.filter(
  38. Ioc.case_id == case_identifier
  39. ).all()
  40. def get_ioc(ioc_id, caseid=None):
  41. q = Ioc.query.filter(Ioc.ioc_id == ioc_id)
  42. if caseid:
  43. q = q.filter(Ioc.case_id == caseid)
  44. return q.first()
  45. def update_ioc(ioc_type, ioc_tags, ioc_value, ioc_description, ioc_tlp, userid, ioc_id):
  46. ioc = get_ioc(ioc_id)
  47. if ioc:
  48. ioc.ioc_type = ioc_type
  49. ioc.ioc_tags = ioc_tags
  50. ioc.ioc_value = ioc_value
  51. ioc.ioc_description = ioc_description
  52. ioc.ioc_tlp_id = ioc_tlp
  53. ioc.user_id = userid
  54. db.session.commit()
  55. else:
  56. return False
  57. def delete_ioc(ioc: Ioc):
  58. # Delete the relevant records from the AssetComments table
  59. com_ids = IocComments.query.with_entities(
  60. IocComments.comment_id
  61. ).filter(
  62. IocComments.comment_ioc_id == ioc.ioc_id,
  63. ).all()
  64. com_ids = [c.comment_id for c in com_ids]
  65. IocComments.query.filter(IocComments.comment_id.in_(com_ids)).delete()
  66. Comments.query.filter(
  67. Comments.comment_id.in_(com_ids)
  68. ).delete()
  69. db.session.delete(ioc)
  70. update_ioc_state(ioc.case_id)
  71. def get_detailed_iocs(caseid):
  72. detailed_iocs = (Ioc.query.with_entities(
  73. Ioc.ioc_id,
  74. Ioc.ioc_uuid,
  75. Ioc.ioc_value,
  76. Ioc.ioc_type_id,
  77. IocType.type_name.label('ioc_type'),
  78. Ioc.ioc_type_id,
  79. Ioc.ioc_description,
  80. Ioc.ioc_tags,
  81. Ioc.ioc_misp,
  82. Tlp.tlp_name,
  83. Tlp.tlp_bscolor,
  84. Ioc.ioc_tlp_id
  85. ).filter(Ioc.case_id == caseid)
  86. .join(Ioc.ioc_type)
  87. .outerjoin(Ioc.tlp)
  88. .order_by(IocType.type_name).all())
  89. return detailed_iocs
  90. def get_ioc_links(ioc_id):
  91. search_condition = and_(Cases.case_id.in_([]))
  92. user_search_limitations = ac_get_fast_user_cases_access(current_user.id)
  93. if user_search_limitations:
  94. search_condition = and_(Cases.case_id.in_(user_search_limitations))
  95. ioc = Ioc.query.filter(Ioc.ioc_id == ioc_id).first()
  96. # Search related iocs based on value and type
  97. related_iocs = (Ioc.query.with_entities(
  98. Cases.case_id,
  99. Cases.name.label('case_name'),
  100. Client.name.label('client_name')
  101. ).filter(and_(
  102. Ioc.ioc_value == ioc.ioc_value,
  103. Ioc.ioc_type_id == ioc.ioc_type_id,
  104. Ioc.ioc_id != ioc_id,
  105. search_condition)
  106. ).join(Ioc.case)
  107. .join(Cases.client)
  108. .all())
  109. return related_iocs
  110. def add_ioc(ioc: Ioc, user_id, caseid):
  111. ioc.user_id = user_id
  112. ioc.case_id = caseid
  113. db.session.add(ioc)
  114. update_ioc_state(caseid=caseid)
  115. db.session.commit()
  116. def case_iocs_db_exists(ioc: Ioc):
  117. iocs = Ioc.query.filter(Ioc.case_id == ioc.case_id,
  118. Ioc.ioc_value == ioc.ioc_value,
  119. Ioc.ioc_type_id == ioc.ioc_type_id)
  120. return iocs.first() is not None
  121. def get_ioc_types_list():
  122. ioc_types = IocType.query.with_entities(
  123. IocType.type_id,
  124. IocType.type_name,
  125. IocType.type_description,
  126. IocType.type_taxonomy,
  127. IocType.type_validation_regex,
  128. IocType.type_validation_expect,
  129. ).all()
  130. l_types = [row._asdict() for row in ioc_types]
  131. return l_types
  132. def add_ioc_type(name:str, description:str, taxonomy:str):
  133. ioct = IocType(type_name=name,
  134. type_description=description,
  135. type_taxonomy=taxonomy
  136. )
  137. db.session.add(ioct)
  138. db.session.commit()
  139. return ioct
  140. def check_ioc_type_id(type_id: int):
  141. type_id = IocType.query.filter(
  142. IocType.type_id == type_id
  143. ).first()
  144. return type_id
  145. def get_ioc_type_id(type_name: str):
  146. type_id = IocType.query.filter(
  147. IocType.type_name == type_name
  148. ).first()
  149. return type_id if type_id else None
  150. def get_tlps():
  151. return [(tlp.tlp_id, tlp.tlp_name) for tlp in Tlp.query.all()]
  152. def get_tlps_dict():
  153. tlpDict = {}
  154. for tlp in Tlp.query.all():
  155. tlpDict[tlp.tlp_name]=tlp.tlp_id
  156. return tlpDict
  157. def get_case_ioc_comments(ioc_id):
  158. return Comments.query.filter(
  159. IocComments.comment_ioc_id == ioc_id
  160. ).with_entities(
  161. Comments
  162. ).join(
  163. IocComments,
  164. Comments.comment_id == IocComments.comment_id
  165. ).order_by(
  166. Comments.comment_date.asc()
  167. ).all()
  168. def add_comment_to_ioc(ioc_id, comment_id):
  169. ec = IocComments()
  170. ec.comment_ioc_id = ioc_id
  171. ec.comment_id = comment_id
  172. db.session.add(ec)
  173. db.session.commit()
  174. def get_case_iocs_comments_count(iocs_list):
  175. return IocComments.query.filter(
  176. IocComments.comment_ioc_id.in_(iocs_list)
  177. ).with_entities(
  178. IocComments.comment_ioc_id,
  179. IocComments.comment_id
  180. ).group_by(
  181. IocComments.comment_ioc_id,
  182. IocComments.comment_id
  183. ).all()
  184. def get_case_ioc_comment(ioc_id, comment_id):
  185. return (IocComments.query.filter(
  186. IocComments.comment_ioc_id == ioc_id,
  187. IocComments.comment_id == comment_id
  188. ).with_entities(
  189. Comments.comment_id,
  190. Comments.comment_text,
  191. Comments.comment_date,
  192. Comments.comment_update_date,
  193. Comments.comment_uuid,
  194. User.name,
  195. User.user
  196. ).join(IocComments.comment)
  197. .join(Comments.user).first())
  198. def delete_ioc_comment(ioc_id, comment_id):
  199. comment = Comments.query.filter(
  200. Comments.comment_id == comment_id,
  201. Comments.comment_user_id == current_user.id
  202. ).first()
  203. if not comment:
  204. return False, "You are not allowed to delete this comment"
  205. IocComments.query.filter(
  206. IocComments.comment_ioc_id == ioc_id,
  207. IocComments.comment_id == comment_id
  208. ).delete()
  209. db.session.delete(comment)
  210. db.session.commit()
  211. return True, "Comment deleted"
  212. def get_ioc_by_value(ioc_value, caseid=None):
  213. if caseid:
  214. Ioc.query.filter(Ioc.ioc_value == ioc_value, Ioc.case_id == caseid).first()
  215. return Ioc.query.filter(Ioc.ioc_value == ioc_value).first()
  216. def user_list_cases_view(user_id):
  217. res = UserCaseEffectiveAccess.query.with_entities(
  218. UserCaseEffectiveAccess.case_id
  219. ).filter(and_(
  220. UserCaseEffectiveAccess.user_id == user_id,
  221. UserCaseEffectiveAccess.access_level != CaseAccessLevel.deny_all.value
  222. )).all()
  223. return [r.case_id for r in res]
  224. def _build_filter_ioc_query(
  225. caseid: int = None,
  226. ioc_type_id: int = None,
  227. ioc_type: str = None,
  228. ioc_tlp_id: int = None,
  229. ioc_value: str = None,
  230. ioc_description: str = None,
  231. ioc_tags: str = None,
  232. sort_by=None,
  233. sort_dir='asc'):
  234. """
  235. Get a list of iocs from the database, filtered by the given parameters
  236. """
  237. conditions = []
  238. if ioc_type_id is not None:
  239. conditions.append(Ioc.ioc_type_id == ioc_type_id)
  240. if ioc_type is not None:
  241. conditions.append(Ioc.ioc_type == ioc_type)
  242. if ioc_tlp_id is not None:
  243. conditions.append(Ioc.ioc_tlp_id == ioc_tlp_id)
  244. if ioc_value is not None:
  245. conditions.append(Ioc.ioc_value == ioc_value)
  246. if ioc_description is not None:
  247. conditions.append(Ioc.ioc_description == ioc_description)
  248. if ioc_tags is not None:
  249. conditions.append(Ioc.ioc_tags == ioc_tags)
  250. if caseid is not None:
  251. conditions.append(Ioc.case_id == caseid)
  252. query = Ioc.query.filter(*conditions)
  253. if sort_by is not None:
  254. order_func = convert_sort_direction(sort_dir)
  255. if sort_by == 'opened_by':
  256. query = query.join(User, Ioc.user_id == User.id).order_by(order_func(User.name))
  257. elif hasattr(Ioc, sort_by):
  258. query = query.order_by(order_func(getattr(Ioc, sort_by)))
  259. return query
  260. def get_filtered_iocs(
  261. pagination_parameters: PaginationParameters,
  262. caseid: int = None,
  263. ioc_type_id: int = None,
  264. ioc_type: str = None,
  265. ioc_tlp_id: int = None,
  266. ioc_value: str = None,
  267. ioc_description: str = None,
  268. ioc_tags: str = None
  269. ):
  270. query = _build_filter_ioc_query(caseid=caseid, ioc_type_id=ioc_type_id, ioc_type=ioc_type, ioc_tlp_id=ioc_tlp_id, ioc_value=ioc_value,
  271. ioc_description=ioc_description, ioc_tags=ioc_tags,
  272. sort_by=pagination_parameters.get_order_by(), sort_dir=pagination_parameters.get_direction())
  273. try:
  274. filtered_iocs = query.paginate(page=pagination_parameters.get_page(), per_page=pagination_parameters.get_per_page(), error_out=False)
  275. except Exception as e:
  276. app.logger.exception(f"Error getting cases: {str(e)}")
  277. return None
  278. return filtered_iocs