Some checks failed
Deployment Verification / deploy-and-test (push) Failing after 29s
399 lines
11 KiB
Python
399 lines
11 KiB
Python
#!/usr/bin/env python3
|
|
#
|
|
# IRIS Source Code
|
|
# Copyright (C) 2021 - Airbus CyberSecurity (SAS)
|
|
# ir@cyberactionlab.net
|
|
#
|
|
# 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.
|
|
|
|
import datetime
|
|
|
|
from flask_login import current_user
|
|
from sqlalchemy import and_
|
|
from sqlalchemy import func
|
|
|
|
from app import db, app
|
|
from app.datamgmt.states import update_assets_state
|
|
from app.models import AnalysisStatus, CaseStatus
|
|
from app.models import AssetComments
|
|
from app.models import AssetsType
|
|
from app.models import CaseAssets
|
|
from app.models import CaseEventsAssets
|
|
from app.models import Cases
|
|
from app.models import Comments
|
|
from app.models import CompromiseStatus
|
|
from app.models import Ioc
|
|
from app.models import IocAssetLink
|
|
from app.models import IocLink
|
|
from app.models import IocType
|
|
from app.models.authorization import User
|
|
|
|
|
|
log = app.logger
|
|
|
|
def create_asset(asset, caseid, user_id):
|
|
|
|
asset.date_added = datetime.datetime.utcnow()
|
|
asset.date_update = datetime.datetime.utcnow()
|
|
asset.case_id = caseid
|
|
asset.user_id = user_id
|
|
|
|
db.session.add(asset)
|
|
update_assets_state(caseid=caseid, userid=user_id)
|
|
|
|
db.session.commit()
|
|
|
|
return asset
|
|
|
|
|
|
def get_assets(caseid):
|
|
assets = CaseAssets.query.with_entities(
|
|
CaseAssets.asset_id,
|
|
CaseAssets.asset_uuid,
|
|
CaseAssets.asset_name,
|
|
AssetsType.asset_name.label('asset_type'),
|
|
AssetsType.asset_icon_compromised,
|
|
AssetsType.asset_icon_not_compromised,
|
|
CaseAssets.asset_description,
|
|
CaseAssets.asset_domain,
|
|
CaseAssets.asset_compromise_status_id,
|
|
CaseAssets.asset_ip,
|
|
CaseAssets.asset_type_id,
|
|
AnalysisStatus.name.label('analysis_status'),
|
|
CaseAssets.analysis_status_id,
|
|
CaseAssets.asset_tags
|
|
).filter(
|
|
CaseAssets.case_id == caseid,
|
|
).join(
|
|
CaseAssets.asset_type, CaseAssets.analysis_status
|
|
).all()
|
|
|
|
return assets
|
|
|
|
|
|
def get_assets_name(caseid):
|
|
assets_names = CaseAssets.query.with_entities(
|
|
CaseAssets.asset_name
|
|
).filter(
|
|
CaseAssets.case_id == caseid
|
|
).all()
|
|
|
|
return assets_names
|
|
|
|
|
|
def get_asset(asset_id, caseid):
|
|
asset = CaseAssets.query.filter(
|
|
CaseAssets.asset_id == asset_id,
|
|
CaseAssets.case_id == caseid
|
|
).first()
|
|
|
|
return asset
|
|
|
|
|
|
def update_asset(asset_name, asset_description, asset_ip, asset_info, asset_domain,
|
|
asset_compromise_status_id, asset_type, asset_id, caseid, analysis_status, asset_tags):
|
|
asset = get_asset(asset_id, caseid)
|
|
asset.asset_name = asset_name
|
|
asset.asset_description = asset_description
|
|
asset.asset_ip = asset_ip
|
|
asset.asset_info = asset_info
|
|
asset.asset_domain = asset_domain
|
|
asset.asset_compromise_status_id = asset_compromise_status_id
|
|
asset.asset_type_id = asset_type
|
|
asset.analysis_status_id = analysis_status
|
|
asset.asset_tags = asset_tags
|
|
|
|
update_assets_state(caseid=caseid)
|
|
|
|
db.session.commit()
|
|
|
|
|
|
def delete_asset(asset_id, caseid):
|
|
case_asset = get_asset(asset_id, caseid)
|
|
if case_asset is None:
|
|
return
|
|
|
|
if case_asset.case_id and case_asset.alerts is not None:
|
|
|
|
CaseEventsAssets.query.filter(
|
|
case_asset.asset_id == CaseEventsAssets.asset_id
|
|
).delete()
|
|
|
|
case_asset.case_id = None
|
|
db.session.commit()
|
|
return
|
|
|
|
with db.session.begin_nested():
|
|
delete_ioc_asset_link(asset_id)
|
|
|
|
# Delete the relevant records from the CaseEventsAssets table
|
|
CaseEventsAssets.query.filter(
|
|
CaseEventsAssets.case_id == caseid,
|
|
CaseEventsAssets.asset_id == asset_id
|
|
).delete()
|
|
|
|
# Delete the relevant records from the AssetComments table
|
|
com_ids = AssetComments.query.with_entities(
|
|
AssetComments.comment_id
|
|
).filter(
|
|
AssetComments.comment_asset_id == asset_id,
|
|
).all()
|
|
|
|
com_ids = [c.comment_id for c in com_ids]
|
|
AssetComments.query.filter(AssetComments.comment_id.in_(com_ids)).delete()
|
|
|
|
Comments.query.filter(
|
|
Comments.comment_id.in_(com_ids)
|
|
).delete()
|
|
|
|
# Directly delete the relevant records from the CaseAssets table
|
|
CaseAssets.query.filter(
|
|
CaseAssets.asset_id == asset_id,
|
|
CaseAssets.case_id == caseid
|
|
).delete()
|
|
|
|
update_assets_state(caseid=caseid)
|
|
|
|
|
|
def get_assets_types():
|
|
assets_types = [(c.asset_id, c.asset_name) for c
|
|
in AssetsType.query.with_entities(AssetsType.asset_name,
|
|
AssetsType.asset_id).order_by(AssetsType.asset_name)
|
|
]
|
|
|
|
return assets_types
|
|
|
|
|
|
def get_unspecified_analysis_status_id():
|
|
"""
|
|
Get the id of the 'Unspecified' analysis status
|
|
"""
|
|
analysis_status = AnalysisStatus.query.filter(
|
|
AnalysisStatus.name == 'Unspecified'
|
|
).first()
|
|
|
|
return analysis_status.id if analysis_status else None
|
|
|
|
|
|
def get_analysis_status_list():
|
|
analysis_status = [(c.id, c.name) for c in AnalysisStatus.query.with_entities(
|
|
AnalysisStatus.id,
|
|
AnalysisStatus.name
|
|
)]
|
|
|
|
return analysis_status
|
|
|
|
|
|
def get_compromise_status_list():
|
|
return [(e.value, e.name.replace('_', ' ').capitalize()) for e in CompromiseStatus]
|
|
|
|
|
|
def get_compromise_status_dict():
|
|
return [{'value': e.value, 'name': e.name.replace('_', ' ').capitalize()} for e in CompromiseStatus]
|
|
|
|
|
|
def get_case_outcome_status_dict():
|
|
return [{'value': e.value, 'name': e.name.replace('_', ' ').capitalize()} for e in CaseStatus]
|
|
|
|
|
|
def get_asset_type_id(asset_type_name):
|
|
assets_type_id = AssetsType.query.with_entities(
|
|
AssetsType.asset_id
|
|
).filter(
|
|
func.lower(AssetsType.asset_name) == asset_type_name
|
|
).first()
|
|
|
|
return assets_type_id
|
|
|
|
|
|
def get_assets_ioc_links(caseid):
|
|
|
|
ioc_links_req = IocAssetLink.query.with_entities(
|
|
Ioc.ioc_id,
|
|
Ioc.ioc_value,
|
|
IocAssetLink.asset_id
|
|
).filter(
|
|
Ioc.ioc_id == IocAssetLink.ioc_id,
|
|
IocLink.case_id == caseid,
|
|
IocLink.ioc_id == Ioc.ioc_id
|
|
).all()
|
|
|
|
return ioc_links_req
|
|
|
|
def get_similar_assets(asset_name, asset_type_id, caseid, customer_id, cases_limitation):
|
|
|
|
linked_assets = CaseAssets.query.with_entities(
|
|
Cases.name.label('case_name'),
|
|
Cases.open_date.label('case_open_date'),
|
|
CaseAssets.asset_description,
|
|
CaseAssets.asset_compromise_status_id,
|
|
CaseAssets.asset_id,
|
|
CaseAssets.case_id
|
|
).filter(
|
|
Cases.client_id == customer_id,
|
|
CaseAssets.case_id != caseid
|
|
).filter(
|
|
CaseAssets.asset_name == asset_name,
|
|
CaseAssets.asset_type_id == asset_type_id,
|
|
Cases.case_id.in_(cases_limitation)
|
|
).join(CaseAssets.case).all()
|
|
|
|
return (lasset._asdict() for lasset in linked_assets)
|
|
|
|
|
|
def delete_ioc_asset_link(asset_id):
|
|
IocAssetLink.query.filter(
|
|
IocAssetLink.asset_id == asset_id
|
|
).delete()
|
|
|
|
|
|
def get_linked_iocs_from_asset(asset_id):
|
|
iocs = IocAssetLink.query.with_entities(
|
|
Ioc.ioc_id,
|
|
Ioc.ioc_value
|
|
).filter(
|
|
IocAssetLink.asset_id == asset_id,
|
|
Ioc.ioc_id == IocAssetLink.ioc_id
|
|
).all()
|
|
|
|
return iocs
|
|
|
|
|
|
def set_ioc_links(ioc_list, asset_id):
|
|
if ioc_list is None:
|
|
return False, "Empty IOC list"
|
|
|
|
# Reset IOC list
|
|
delete_ioc_asset_link(asset_id)
|
|
|
|
for ioc in ioc_list:
|
|
ial = IocAssetLink()
|
|
ial.asset_id = asset_id
|
|
ial.ioc_id = ioc
|
|
|
|
db.session.add(ial)
|
|
|
|
try:
|
|
db.session.commit()
|
|
except Exception as e:
|
|
db.session.rollback()
|
|
log.exception(e)
|
|
return True, e.__str__()
|
|
|
|
return False, ""
|
|
|
|
|
|
def get_linked_iocs_id_from_asset(asset_id):
|
|
iocs = IocAssetLink.query.with_entities(
|
|
IocAssetLink.ioc_id
|
|
).filter(
|
|
IocAssetLink.asset_id == asset_id
|
|
).all()
|
|
|
|
return iocs
|
|
|
|
|
|
def get_linked_iocs_finfo_from_asset(asset_id):
|
|
iocs = IocAssetLink.query.with_entities(
|
|
Ioc.ioc_id,
|
|
Ioc.ioc_value,
|
|
Ioc.ioc_tags,
|
|
Ioc.ioc_type_id,
|
|
IocType.type_name,
|
|
Ioc.ioc_description,
|
|
Ioc.ioc_tlp_id
|
|
).filter(and_(
|
|
IocAssetLink.asset_id == asset_id,
|
|
IocAssetLink.ioc_id == Ioc.ioc_id
|
|
)).join(Ioc.ioc_type).all()
|
|
|
|
return iocs
|
|
|
|
|
|
def get_case_asset_comments(asset_id):
|
|
return Comments.query.filter(
|
|
AssetComments.comment_asset_id == asset_id
|
|
).with_entities(
|
|
Comments
|
|
).join(AssetComments,
|
|
Comments.comment_id == AssetComments.comment_id
|
|
).order_by(
|
|
Comments.comment_date.asc()
|
|
).all()
|
|
|
|
|
|
def add_comment_to_asset(asset_id, comment_id):
|
|
ec = AssetComments()
|
|
ec.comment_asset_id = asset_id
|
|
ec.comment_id = comment_id
|
|
|
|
db.session.add(ec)
|
|
db.session.commit()
|
|
|
|
|
|
def get_case_assets_comments_count(asset_id):
|
|
return AssetComments.query.filter(
|
|
AssetComments.comment_asset_id.in_(asset_id)
|
|
).with_entities(
|
|
AssetComments.comment_asset_id,
|
|
AssetComments.comment_id
|
|
).group_by(
|
|
AssetComments.comment_asset_id,
|
|
AssetComments.comment_id
|
|
).all()
|
|
|
|
|
|
def get_case_asset_comment(asset_id, comment_id):
|
|
return AssetComments.query.filter(
|
|
AssetComments.comment_asset_id == asset_id,
|
|
AssetComments.comment_id == comment_id
|
|
).with_entities(
|
|
Comments.comment_id,
|
|
Comments.comment_text,
|
|
Comments.comment_date,
|
|
Comments.comment_update_date,
|
|
Comments.comment_uuid,
|
|
User.name,
|
|
User.user
|
|
).join(
|
|
AssetComments.comment,
|
|
Comments.user
|
|
).first()
|
|
|
|
|
|
def delete_asset_comment(asset_id, comment_id, case_id):
|
|
comment = Comments.query.filter(
|
|
Comments.comment_id == comment_id,
|
|
Comments.comment_user_id == current_user.id
|
|
).first()
|
|
if not comment:
|
|
return False, "You are not allowed to delete this comment"
|
|
|
|
AssetComments.query.filter(
|
|
AssetComments.comment_asset_id == asset_id,
|
|
AssetComments.comment_id == comment_id
|
|
).delete()
|
|
|
|
db.session.delete(comment)
|
|
db.session.commit()
|
|
|
|
return True, "Comment deleted"
|
|
|
|
def get_asset_by_name(asset_name, caseid):
|
|
asset = CaseAssets.query.filter(
|
|
CaseAssets.asset_name == asset_name,
|
|
CaseAssets.case_id == caseid
|
|
).first()
|
|
return asset |