| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173 |
- # IRIS Source Code
- # Copyright (C) 2024 - DFIR-IRIS
- # contact@dfir-iris.org
- #
- # This program is free software; you can redistribute it and/or
- # modify it under the terms of the GNU Lesser General Public
- # License as published by the Free Software Foundation; either
- # version 3 of the License, or (at your option) any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- # Lesser General Public License for more details.
- #
- # You should have received a copy of the GNU Lesser General Public License
- # along with this program; if not, write to the Free Software Foundation,
- # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- from flask_login import current_user
- from marshmallow.exceptions import ValidationError
- from flask_sqlalchemy.pagination import Pagination
- from app import db
- from app.business.errors import BusinessProcessingError
- from app.business.errors import ObjectNotFoundError
- from app.business.cases import cases_exists
- from app.datamgmt.case.case_db import get_case_client_id
- from app.datamgmt.manage.manage_users_db import get_user_cases_fast
- from app.datamgmt.states import get_assets_state
- from app.datamgmt.states import update_assets_state
- from app.models.models import CaseAssets
- from app.models.pagination_parameters import PaginationParameters
- from app.datamgmt.case.case_assets_db import get_asset
- from app.datamgmt.case.case_assets_db import get_assets
- from app.datamgmt.case.case_assets_db import filter_assets
- from app.datamgmt.case.case_assets_db import get_assets_ioc_links
- from app.datamgmt.case.case_assets_db import get_similar_assets
- from app.datamgmt.case.case_assets_db import case_assets_db_exists
- from app.datamgmt.case.case_assets_db import create_asset
- from app.datamgmt.case.case_assets_db import set_ioc_links
- from app.datamgmt.case.case_assets_db import get_linked_iocs_finfo_from_asset
- from app.datamgmt.case.case_assets_db import delete_asset
- from app.iris_engine.module_handler.module_handler import call_modules_hook
- from app.iris_engine.utils.tracker import track_activity
- from app.schema.marshables import CaseAssetsSchema
- def _load(request_data, **kwargs):
- try:
- add_assets_schema = CaseAssetsSchema()
- return add_assets_schema.load(request_data, **kwargs)
- except ValidationError as e:
- raise BusinessProcessingError('Data error', data=e.messages)
- def assets_create(case_identifier, request_json):
- request_data = call_modules_hook('on_preload_asset_create', data=request_json, caseid=case_identifier)
- asset = _load(request_data)
- asset.case_id = case_identifier
- if case_assets_db_exists(asset):
- raise BusinessProcessingError('Asset with same value and type already exists')
- asset = create_asset(asset=asset, caseid=case_identifier, user_id=current_user.id)
- # TODO should the custom attributes be set?
- if request_data.get('ioc_links'):
- errors, _ = set_ioc_links(request_data.get('ioc_links'), asset.asset_id)
- if errors:
- raise BusinessProcessingError('Encountered errors while linking IOC. Asset has still been created.')
- asset = call_modules_hook('on_postload_asset_create', data=asset, caseid=case_identifier)
- if asset:
- track_activity(f'added asset "{asset.asset_name}"', caseid=case_identifier)
- return 'Asset added', asset
- raise BusinessProcessingError('Unable to create asset for internal reasons')
- def assets_delete(asset: CaseAssets):
- call_modules_hook('on_preload_asset_delete', data=asset.asset_id)
- # Deletes an asset and the potential links with the IoCs from the database
- delete_asset(asset)
- call_modules_hook('on_postload_asset_delete', data=asset.asset_id, caseid=asset.case_id)
- track_activity(f'removed asset ID {asset.asset_name}', caseid=asset.case_id)
- def assets_get(identifier) -> CaseAssets:
- asset = get_asset(identifier)
- if not asset:
- raise ObjectNotFoundError()
- return asset
- def assets_get_detailed(identifier):
- asset = assets_get(identifier)
- # TODO this is a code smell: shouldn't have schemas in the business layer + the CaseAssetsSchema is instantiated twice
- case_assets_schema = CaseAssetsSchema()
- data = case_assets_schema.dump(asset)
- asset_iocs = get_linked_iocs_finfo_from_asset(identifier)
- data['linked_ioc'] = [row._asdict() for row in asset_iocs]
- return data
- def get_assets_case(case_identifier):
- assets = get_assets(case_identifier)
- customer_id = get_case_client_id(case_identifier)
- ret = {'assets': []}
- ioc_links_req = get_assets_ioc_links(case_identifier)
- cache_ioc_link = {}
- for ioc in ioc_links_req:
- if ioc.asset_id not in cache_ioc_link:
- cache_ioc_link[ioc.asset_id] = [ioc._asdict()]
- else:
- cache_ioc_link[ioc.asset_id].append(ioc._asdict())
- cases_access = get_user_cases_fast(current_user.id)
- for asset in assets:
- asset = asset._asdict()
- if len(assets) < 300:
- # Find similar assets from other cases with the same customer
- asset['link'] = list(get_similar_assets(
- asset['asset_name'], asset['asset_type_id'], case_identifier, customer_id, cases_access))
- else:
- asset['link'] = []
- asset['ioc_links'] = cache_ioc_link.get(asset['asset_id'])
- ret['assets'].append(asset)
- ret['state'] = get_assets_state(case_identifier)
- return ret
- def assets_filter(case_identifier, pagination_parameters: PaginationParameters) -> Pagination:
- if not cases_exists(case_identifier):
- raise ObjectNotFoundError()
- return filter_assets(case_identifier, pagination_parameters)
- def assets_update(asset: CaseAssets, request_json):
- caseid = asset.case_id
- request_data = call_modules_hook('on_preload_asset_update', data=request_json, caseid=caseid)
- request_data['asset_id'] = asset.asset_id
- asset_schema = _load(request_data, instance=asset)
- if case_assets_db_exists(asset_schema):
- raise BusinessProcessingError('Data error', data='Asset with same value and type already exists')
- update_assets_state(caseid=caseid)
- db.session.commit()
- if hasattr(asset_schema, 'ioc_links'):
- errors, _ = set_ioc_links(asset_schema.ioc_links, asset.asset_id)
- if errors:
- raise BusinessProcessingError('Encountered errors while linking IOC. Asset has still been updated.')
- asset_schema = call_modules_hook('on_postload_asset_update', data=asset_schema, caseid=caseid)
- if asset_schema:
- track_activity(f'updated asset "{asset_schema.asset_name}"', caseid=caseid)
- return asset_schema
- raise BusinessProcessingError('Unable to update asset for internal reasons')
|