mirror of https://github.com/CIRCL/AIL-framework
chg: [trackers + retro_hunts] add org level to retro_hunt + update acl to support org + refactor trackers org
parent
b466d4766a
commit
5c903f9f88
|
@ -26,6 +26,7 @@ sys.path.append(os.environ['AIL_BIN'])
|
||||||
from packages import Date
|
from packages import Date
|
||||||
from lib.ail_core import get_objects_tracked, get_object_all_subtypes, get_objects_retro_hunted
|
from lib.ail_core import get_objects_tracked, get_object_all_subtypes, get_objects_retro_hunted
|
||||||
from lib import ail_logger
|
from lib import ail_logger
|
||||||
|
from lib import ail_orgs
|
||||||
from lib import ConfigLoader
|
from lib import ConfigLoader
|
||||||
from lib import item_basic
|
from lib import item_basic
|
||||||
from lib import Tag
|
from lib import Tag
|
||||||
|
@ -177,12 +178,45 @@ class Tracker:
|
||||||
def get_description(self):
|
def get_description(self):
|
||||||
return self._get_field('description')
|
return self._get_field('description')
|
||||||
|
|
||||||
|
## LEVEL ##
|
||||||
|
|
||||||
def get_level(self):
|
def get_level(self):
|
||||||
level = self._get_field('level')
|
level = int(self._get_field('level'))
|
||||||
if not level:
|
if not level:
|
||||||
level = 0
|
level = 0
|
||||||
return int(level)
|
return int(level)
|
||||||
|
|
||||||
|
def set_level(self, level, org_uuid):
|
||||||
|
tracker_type = self.get_type()
|
||||||
|
if level == 0: # user only
|
||||||
|
user_id = self.get_user()
|
||||||
|
r_tracker.sadd(f'user:tracker:{user_id}', self.uuid)
|
||||||
|
r_tracker.sadd(f'user:tracker:{user_id}:{tracker_type}', self.uuid)
|
||||||
|
elif level == 1: # global
|
||||||
|
r_tracker.sadd('global:tracker', self.uuid)
|
||||||
|
r_tracker.sadd(f'global:tracker:{tracker_type}', self.uuid)
|
||||||
|
elif level == 2: # org only
|
||||||
|
r_tracker.sadd(f'org:tracker:{org_uuid}', self.uuid)
|
||||||
|
r_tracker.sadd(f'org:tracker:{org_uuid}:{tracker_type}', self.uuid)
|
||||||
|
self.add_to_org(org_uuid)
|
||||||
|
self._set_field('level', level)
|
||||||
|
|
||||||
|
def reset_level(self, old_level, new_level, new_org_uuid):
|
||||||
|
if old_level == 0:
|
||||||
|
user_id = self.get_user()
|
||||||
|
r_tracker.srem(f'user:tracker:{user_id}', self.uuid)
|
||||||
|
r_tracker.srem(f'user:tracker:{user_id}:{self.get_type()}', self.uuid)
|
||||||
|
elif old_level == 1:
|
||||||
|
r_tracker.srem('global:tracker', self.uuid)
|
||||||
|
r_tracker.srem(f'global:tracker:{self.get_type()}', self.uuid)
|
||||||
|
# Org
|
||||||
|
elif old_level == 2:
|
||||||
|
old_org = self.get_org()
|
||||||
|
r_tracker.srem(f'org:tracker:{old_org}', self.uuid)
|
||||||
|
r_tracker.srem(f'org:tracker:{old_org}:{self.get_type()}', self.uuid)
|
||||||
|
ail_orgs.remove_obj_to_org(old_org, 'tracker', self.uuid)
|
||||||
|
self.set_level(new_level, new_org_uuid)
|
||||||
|
|
||||||
def is_level_user(self):
|
def is_level_user(self):
|
||||||
return self.get_level() == 0
|
return self.get_level() == 0
|
||||||
|
|
||||||
|
@ -192,21 +226,19 @@ class Tracker:
|
||||||
def is_level_global(self):
|
def is_level_global(self):
|
||||||
return self.get_level() == 1
|
return self.get_level() == 1
|
||||||
|
|
||||||
def _set_level(self, level, tracker_type=None, org=None, user=None):
|
## ORG ##
|
||||||
if not tracker_type:
|
|
||||||
tracker_type = self.get_type()
|
def get_creator_org(self):
|
||||||
if level == 0: # user only
|
return self._get_field('creator_org')
|
||||||
if not user:
|
|
||||||
user = self.get_user()
|
def get_org(self):
|
||||||
r_tracker.sadd(f'user:tracker:{user}', self.uuid)
|
return self._get_field('org')
|
||||||
r_tracker.sadd(f'user:tracker:{user}:{tracker_type}', self.uuid)
|
|
||||||
elif level == 1: # global
|
def add_to_org(self, org_uuid):
|
||||||
r_tracker.sadd('global:tracker', self.uuid)
|
self._set_field('org', org_uuid)
|
||||||
r_tracker.sadd(f'global:tracker:{tracker_type}', self.uuid)
|
ail_orgs.add_obj_to_org(org_uuid, 'tracker', self.uuid)
|
||||||
elif level == 2: # org only
|
|
||||||
r_tracker.sadd(f'org:tracker:{org}', self.uuid)
|
## -ORG- ##
|
||||||
r_tracker.sadd(f'org:tracker:{org}:{tracker_type}', self.uuid)
|
|
||||||
self._set_field('level', level)
|
|
||||||
|
|
||||||
def get_filters(self):
|
def get_filters(self):
|
||||||
filters = self._get_field('filters')
|
filters = self._get_field('filters')
|
||||||
|
@ -258,9 +290,6 @@ class Tracker:
|
||||||
def _del_mails(self):
|
def _del_mails(self):
|
||||||
r_tracker.delete(f'tracker:mail:{self.uuid}')
|
r_tracker.delete(f'tracker:mail:{self.uuid}')
|
||||||
|
|
||||||
def get_org(self):
|
|
||||||
return self._get_field('org')
|
|
||||||
|
|
||||||
def get_user(self):
|
def get_user(self):
|
||||||
return self._get_field('user_id')
|
return self._get_field('user_id')
|
||||||
|
|
||||||
|
@ -424,7 +453,7 @@ class Tracker:
|
||||||
self._set_field('tracked', to_track)
|
self._set_field('tracked', to_track)
|
||||||
self._set_field('type', tracker_type)
|
self._set_field('type', tracker_type)
|
||||||
self._set_field('date', datetime.date.today().strftime("%Y%m%d"))
|
self._set_field('date', datetime.date.today().strftime("%Y%m%d"))
|
||||||
self._set_field('org', org)
|
self._set_field('creator_org', org)
|
||||||
self._set_field('user_id', user_id)
|
self._set_field('user_id', user_id)
|
||||||
if description:
|
if description:
|
||||||
self._set_field('description', escape(description))
|
self._set_field('description', escape(description))
|
||||||
|
@ -441,7 +470,7 @@ class Tracker:
|
||||||
|
|
||||||
|
|
||||||
# TRACKER LEVEL
|
# TRACKER LEVEL
|
||||||
self._set_level(level, tracker_type=tracker_type, org=org, user=user_id)
|
self.set_level(level, org)
|
||||||
|
|
||||||
# create tracker tags list
|
# create tracker tags list
|
||||||
if tags:
|
if tags:
|
||||||
|
@ -493,16 +522,7 @@ class Tracker:
|
||||||
|
|
||||||
if tracker_type != old_type:
|
if tracker_type != old_type:
|
||||||
# LEVEL
|
# LEVEL
|
||||||
if old_level == 0:
|
self.reset_level(old_level, level, org)
|
||||||
r_tracker.srem(f'user:tracker:{user_id}:{old_type}', self.uuid)
|
|
||||||
r_tracker.srem(f'user:tracker:{user_id}', self.uuid)
|
|
||||||
elif old_level == 1:
|
|
||||||
r_tracker.srem(f'global:tracker:{old_type}', self.uuid)
|
|
||||||
r_tracker.srem(f'global:tracker', self.uuid)
|
|
||||||
elif old_level == 2:
|
|
||||||
r_tracker.srem(f'org:tracker:{self.get_org()}:{old_type}', self.uuid)
|
|
||||||
r_tracker.srem(f'org:tracker:{self.get_org()}', self.uuid)
|
|
||||||
self._set_level(level, tracker_type=tracker_type, org=org, user=user_id)
|
|
||||||
# Delete OLD YARA Rule File
|
# Delete OLD YARA Rule File
|
||||||
if old_type == 'yara':
|
if old_type == 'yara':
|
||||||
if not is_default_yara_rule(old_to_track):
|
if not is_default_yara_rule(old_to_track):
|
||||||
|
@ -524,17 +544,9 @@ class Tracker:
|
||||||
r_tracker.sadd(f'trackers:all:{tracker_type}', self.uuid)
|
r_tracker.sadd(f'trackers:all:{tracker_type}', self.uuid)
|
||||||
|
|
||||||
# Same Type
|
# Same Type
|
||||||
elif level != old_level:
|
|
||||||
if old_level == 0:
|
# LEVEL
|
||||||
r_tracker.srem(f'user:tracker:{user_id}', self.uuid)
|
self.reset_level(old_level, level, org)
|
||||||
r_tracker.srem(f'user:tracker:{user_id}:{tracker_type}', self.uuid)
|
|
||||||
elif old_level == 1:
|
|
||||||
r_tracker.srem('global:tracker', self.uuid)
|
|
||||||
r_tracker.srem(f'global:tracker:{tracker_type}', self.uuid)
|
|
||||||
elif old_level == 2:
|
|
||||||
r_tracker.srem(f'org:tracker:{self.get_org()}', self.uuid)
|
|
||||||
r_tracker.srem(f'org:tracker:{self.get_org()}:{tracker_type}', self.uuid)
|
|
||||||
self._set_level(level, tracker_type=tracker_type, org=org, user=user_id)
|
|
||||||
|
|
||||||
# To Track Edited
|
# To Track Edited
|
||||||
if to_track != old_to_track:
|
if to_track != old_to_track:
|
||||||
|
@ -581,11 +593,6 @@ class Tracker:
|
||||||
|
|
||||||
tracker_type = self.get_type()
|
tracker_type = self.get_type()
|
||||||
tracked = self.get_tracked()
|
tracked = self.get_tracked()
|
||||||
r_tracker.srem(f'all:tracker:{tracker_type}', tracked)
|
|
||||||
# tracker - uuid map
|
|
||||||
r_tracker.srem(f'all:tracker_uuid:{tracker_type}:{tracked}', self.uuid)
|
|
||||||
r_tracker.srem('trackers:all', self.uuid)
|
|
||||||
r_tracker.srem(f'trackers:all:{tracker_type}', self.uuid)
|
|
||||||
|
|
||||||
if tracker_type == 'typosquatting':
|
if tracker_type == 'typosquatting':
|
||||||
r_tracker.delete(f'tracker:typosquatting:{tracked}')
|
r_tracker.delete(f'tracker:typosquatting:{tracked}')
|
||||||
|
@ -613,11 +620,17 @@ class Tracker:
|
||||||
elif level == 1: # global
|
elif level == 1: # global
|
||||||
r_tracker.srem('global:tracker', self.uuid)
|
r_tracker.srem('global:tracker', self.uuid)
|
||||||
r_tracker.srem(f'global:tracker:{tracker_type}', self.uuid)
|
r_tracker.srem(f'global:tracker:{tracker_type}', self.uuid)
|
||||||
elif level == 2: # TODO ORG check delete permission
|
elif level == 2:
|
||||||
org = self.get_org()
|
org = self.get_org()
|
||||||
r_tracker.srem(f'org:tracker:{org}', self.uuid)
|
r_tracker.srem(f'org:tracker:{org}', self.uuid)
|
||||||
r_tracker.srem(f'org:tracker:{org}:{tracker_type}', self.uuid)
|
r_tracker.srem(f'org:tracker:{org}:{tracker_type}', self.uuid)
|
||||||
|
|
||||||
|
r_tracker.srem(f'all:tracker:{tracker_type}', tracked)
|
||||||
|
# tracker - uuid map
|
||||||
|
r_tracker.srem(f'all:tracker_uuid:{tracker_type}:{tracked}', self.uuid)
|
||||||
|
r_tracker.srem('trackers:all', self.uuid)
|
||||||
|
r_tracker.srem(f'trackers:all:{tracker_type}', self.uuid)
|
||||||
|
ail_orgs.remove_obj_to_org(self.get_org(), 'tracker', self.uuid)
|
||||||
# meta
|
# meta
|
||||||
r_tracker.delete(f'tracker:{self.uuid}')
|
r_tracker.delete(f'tracker:{self.uuid}')
|
||||||
trigger_trackers_refresh(tracker_type)
|
trigger_trackers_refresh(tracker_type)
|
||||||
|
@ -1436,6 +1449,48 @@ class RetroHunt:
|
||||||
def _set_field(self, field, value):
|
def _set_field(self, field, value):
|
||||||
return r_tracker.hset(f'retro_hunt:{self.uuid}', field, value)
|
return r_tracker.hset(f'retro_hunt:{self.uuid}', field, value)
|
||||||
|
|
||||||
|
## LEVEL ##
|
||||||
|
|
||||||
|
def get_level(self):
|
||||||
|
level = int(self._get_field('level'))
|
||||||
|
if not level:
|
||||||
|
level = 0
|
||||||
|
return int(level)
|
||||||
|
|
||||||
|
def set_level(self, level, org_uuid):
|
||||||
|
if level == 1: # global
|
||||||
|
r_tracker.sadd('retro_hunts', self.uuid)
|
||||||
|
elif level == 2: # org only
|
||||||
|
self.add_to_org(org_uuid)
|
||||||
|
self._set_field('level', level)
|
||||||
|
|
||||||
|
def delete_level(self, level=None):
|
||||||
|
if not level:
|
||||||
|
level = self.get_level()
|
||||||
|
if level == 1:
|
||||||
|
r_tracker.srem('retro_hunts', self.uuid)
|
||||||
|
# Org
|
||||||
|
elif level == 2:
|
||||||
|
ail_orgs.remove_obj_to_org(self.get_org(), 'retro_hunt', self.uuid)
|
||||||
|
|
||||||
|
def reset_level(self, old_level, new_level, new_org_uuid):
|
||||||
|
self.delete_level(old_level)
|
||||||
|
self.set_level(new_level, new_org_uuid)
|
||||||
|
|
||||||
|
## ORG ##
|
||||||
|
|
||||||
|
def get_creator_org(self):
|
||||||
|
return self._get_field('creator_org')
|
||||||
|
|
||||||
|
def get_org(self):
|
||||||
|
return self._get_field('org')
|
||||||
|
|
||||||
|
def add_to_org(self, org_uuid):
|
||||||
|
self._set_field('org', org_uuid)
|
||||||
|
ail_orgs.add_obj_to_org(org_uuid, 'retro_hunt', self.uuid)
|
||||||
|
|
||||||
|
## -ORG- ##
|
||||||
|
|
||||||
def get_creator(self):
|
def get_creator(self):
|
||||||
return self._get_field('creator')
|
return self._get_field('creator')
|
||||||
|
|
||||||
|
@ -1515,6 +1570,8 @@ class RetroHunt:
|
||||||
meta['date'] = self.get_date()
|
meta['date'] = self.get_date()
|
||||||
if 'description' in options:
|
if 'description' in options:
|
||||||
meta['description'] = self.get_description()
|
meta['description'] = self.get_description()
|
||||||
|
if 'level' in options:
|
||||||
|
meta['level'] = self.get_level()
|
||||||
if 'mails' in options:
|
if 'mails' in options:
|
||||||
meta['mails'] = self.get_mails()
|
meta['mails'] = self.get_mails()
|
||||||
if 'nb_match' in options:
|
if 'nb_match' in options:
|
||||||
|
@ -1624,7 +1681,7 @@ class RetroHunt:
|
||||||
r_tracker.srem(f'obj:retro_hunts:{obj_type}:{subtype}:{obj_id}', self.uuid)
|
r_tracker.srem(f'obj:retro_hunts:{obj_type}:{subtype}:{obj_id}', self.uuid)
|
||||||
self._decr_nb_match()
|
self._decr_nb_match()
|
||||||
|
|
||||||
def create(self, name, rule, creator, description=None, filters=[], mails=[], tags=[], timeout=30, state='pending'):
|
def create(self, org_uuid, user_id, level, name, rule, description=None, filters=[], mails=[], tags=[], timeout=30, state='pending'):
|
||||||
if self.exists():
|
if self.exists():
|
||||||
raise Exception('Error: Retro Hunt Task already exists')
|
raise Exception('Error: Retro Hunt Task already exists')
|
||||||
|
|
||||||
|
@ -1634,7 +1691,8 @@ class RetroHunt:
|
||||||
|
|
||||||
self._set_field('date', datetime.date.today().strftime("%Y%m%d"))
|
self._set_field('date', datetime.date.today().strftime("%Y%m%d"))
|
||||||
self._set_field('name', escape(name))
|
self._set_field('name', escape(name))
|
||||||
self._set_field('creator', creator)
|
self._set_field('creator_org', org_uuid)
|
||||||
|
self._set_field('creator', user_id)
|
||||||
if description:
|
if description:
|
||||||
self._set_field('description', description)
|
self._set_field('description', description)
|
||||||
if timeout:
|
if timeout:
|
||||||
|
@ -1649,6 +1707,7 @@ class RetroHunt:
|
||||||
if filters:
|
if filters:
|
||||||
self.set_filters(filters)
|
self.set_filters(filters)
|
||||||
|
|
||||||
|
self.set_level(level, org_uuid)
|
||||||
r_tracker.sadd('retro_hunts:all', self.uuid)
|
r_tracker.sadd('retro_hunts:all', self.uuid)
|
||||||
|
|
||||||
# add to pending tasks
|
# add to pending tasks
|
||||||
|
@ -1667,6 +1726,8 @@ class RetroHunt:
|
||||||
if filepath:
|
if filepath:
|
||||||
os.remove(filepath)
|
os.remove(filepath)
|
||||||
|
|
||||||
|
self.delete_level()
|
||||||
|
|
||||||
r_tracker.srem('retro_hunts:pending', self.uuid)
|
r_tracker.srem('retro_hunts:pending', self.uuid)
|
||||||
r_tracker.delete(f'retro_hunts:{self.uuid}')
|
r_tracker.delete(f'retro_hunts:{self.uuid}')
|
||||||
r_tracker.delete(f'retro_hunt:tags:{self.uuid}')
|
r_tracker.delete(f'retro_hunt:tags:{self.uuid}')
|
||||||
|
@ -1683,13 +1744,13 @@ class RetroHunt:
|
||||||
self.clear_cache()
|
self.clear_cache()
|
||||||
return self.uuid
|
return self.uuid
|
||||||
|
|
||||||
def create_retro_hunt(name, rule_type, rule, creator, description=None, filters=[], mails=[], tags=[], timeout=30, state='pending', task_uuid=None):
|
def create_retro_hunt(user_org, user_id, level, name, rule_type, rule, description=None, filters=[], mails=[], tags=[], timeout=30, state='pending', task_uuid=None):
|
||||||
if not task_uuid:
|
if not task_uuid:
|
||||||
task_uuid = str(uuid.uuid4())
|
task_uuid = str(uuid.uuid4())
|
||||||
retro_hunt = RetroHunt(task_uuid)
|
retro_hunt = RetroHunt(task_uuid)
|
||||||
# rule_type: yara_default - yara custom
|
# rule_type: yara_default - yara custom
|
||||||
rule = save_yara_rule(rule_type, rule, tracker_uuid=retro_hunt.uuid)
|
rule = save_yara_rule(rule_type, rule, tracker_uuid=retro_hunt.uuid)
|
||||||
retro_hunt.create(name, rule, creator, description=description, mails=mails, tags=tags,
|
retro_hunt.create(user_org, user_id , level, name, rule, description=description, mails=mails, tags=tags,
|
||||||
timeout=timeout, filters=filters, state=state)
|
timeout=timeout, filters=filters, state=state)
|
||||||
return retro_hunt.uuid
|
return retro_hunt.uuid
|
||||||
|
|
||||||
|
@ -1713,6 +1774,12 @@ def create_retro_hunt(name, rule_type, rule, creator, description=None, filters=
|
||||||
def get_all_retro_hunt_tasks():
|
def get_all_retro_hunt_tasks():
|
||||||
return r_tracker.smembers('retro_hunts:all')
|
return r_tracker.smembers('retro_hunts:all')
|
||||||
|
|
||||||
|
def get_retro_hunts_global():
|
||||||
|
return r_tracker.smembers('retro_hunts')
|
||||||
|
|
||||||
|
def get_retro_hunts_org(org_uuid):
|
||||||
|
return ail_orgs.get_org_objs_by_type(org_uuid, 'retro_hunt')
|
||||||
|
|
||||||
def get_retro_hunt_pending_tasks():
|
def get_retro_hunt_pending_tasks():
|
||||||
return r_tracker.smembers('retro_hunts:pending')
|
return r_tracker.smembers('retro_hunts:pending')
|
||||||
|
|
||||||
|
@ -1736,9 +1803,9 @@ def get_retro_hunt_task_to_start():
|
||||||
|
|
||||||
## Metadata ##
|
## Metadata ##
|
||||||
|
|
||||||
def get_retro_hunt_metas():
|
def get_retro_hunt_metas(trackers_uuid):
|
||||||
tasks = []
|
tasks = []
|
||||||
for task_uuid in get_all_retro_hunt_tasks():
|
for task_uuid in trackers_uuid:
|
||||||
retro_hunt = RetroHunt(task_uuid)
|
retro_hunt = RetroHunt(task_uuid)
|
||||||
tasks.append(retro_hunt.get_meta(options={'date', 'progress', 'nb_match', 'tags'}))
|
tasks.append(retro_hunt.get_meta(options={'date', 'progress', 'nb_match', 'tags'}))
|
||||||
return tasks
|
return tasks
|
||||||
|
@ -1756,7 +1823,26 @@ def delete_obj_retro_hunts(obj_type, subtype, obj_id):
|
||||||
retro_hunt = RetroHunt(retro_uuid)
|
retro_hunt = RetroHunt(retro_uuid)
|
||||||
retro_hunt.remove(obj_type, subtype, obj_id)
|
retro_hunt.remove(obj_type, subtype, obj_id)
|
||||||
|
|
||||||
## API ##
|
#### ACL ####
|
||||||
|
|
||||||
|
def check_retro_hunt_access_acl(retro_hunt, user_org, is_admin=False):
|
||||||
|
if is_admin:
|
||||||
|
return True
|
||||||
|
|
||||||
|
level = retro_hunt.get_level()
|
||||||
|
if level == 1:
|
||||||
|
return True
|
||||||
|
elif level == 2:
|
||||||
|
return ail_orgs.check_access_acl(retro_hunt, user_org, is_admin=is_admin)
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def api_check_retro_hunt_access_acl(retro_hunt, user_org, is_admin=False):
|
||||||
|
if not check_retro_hunt_access_acl(retro_hunt, user_org, is_admin=is_admin):
|
||||||
|
return {"status": "error", "reason": "Access Denied"}, 403
|
||||||
|
|
||||||
|
#### API ####
|
||||||
|
|
||||||
def api_check_retro_hunt_task_uuid(task_uuid):
|
def api_check_retro_hunt_task_uuid(task_uuid):
|
||||||
if not is_valid_uuid_v4(task_uuid):
|
if not is_valid_uuid_v4(task_uuid):
|
||||||
return {"status": "error", "reason": "Invalid uuid"}, 400
|
return {"status": "error", "reason": "Invalid uuid"}, 400
|
||||||
|
@ -1765,22 +1851,28 @@ def api_check_retro_hunt_task_uuid(task_uuid):
|
||||||
return {"status": "error", "reason": "Unknown uuid"}, 404
|
return {"status": "error", "reason": "Unknown uuid"}, 404
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def api_pause_retro_hunt_task(task_uuid):
|
def api_pause_retro_hunt_task(user_org, is_admin, task_uuid):
|
||||||
res = api_check_retro_hunt_task_uuid(task_uuid)
|
res = api_check_retro_hunt_task_uuid(task_uuid)
|
||||||
if res:
|
if res:
|
||||||
return res
|
return res
|
||||||
retro_hunt = RetroHunt(task_uuid)
|
retro_hunt = RetroHunt(task_uuid)
|
||||||
|
res = api_check_retro_hunt_access_acl(retro_hunt, user_org, is_admin=is_admin)
|
||||||
|
if res:
|
||||||
|
return res
|
||||||
task_state = retro_hunt.get_state()
|
task_state = retro_hunt.get_state()
|
||||||
if task_state not in ['pending', 'running']:
|
if task_state not in ['pending', 'running']:
|
||||||
return {"status": "error", "reason": f"Task {task_uuid} not paused, current state: {task_state}"}, 400
|
return {"status": "error", "reason": f"Task {task_uuid} not paused, current state: {task_state}"}, 400
|
||||||
retro_hunt.pause()
|
retro_hunt.pause()
|
||||||
return task_uuid, 200
|
return task_uuid, 200
|
||||||
|
|
||||||
def api_resume_retro_hunt_task(task_uuid):
|
def api_resume_retro_hunt_task(user_org, is_admin, task_uuid):
|
||||||
res = api_check_retro_hunt_task_uuid(task_uuid)
|
res = api_check_retro_hunt_task_uuid(task_uuid)
|
||||||
if res:
|
if res:
|
||||||
return res
|
return res
|
||||||
retro_hunt = RetroHunt(task_uuid)
|
retro_hunt = RetroHunt(task_uuid)
|
||||||
|
res = api_check_retro_hunt_access_acl(retro_hunt, user_org, is_admin=is_admin)
|
||||||
|
if res:
|
||||||
|
return res
|
||||||
if not retro_hunt.is_paused():
|
if not retro_hunt.is_paused():
|
||||||
return {"status": "error",
|
return {"status": "error",
|
||||||
"reason": f"Task {task_uuid} not paused, current state: {retro_hunt.get_state()}"}, 400
|
"reason": f"Task {task_uuid} not paused, current state: {retro_hunt.get_state()}"}, 400
|
||||||
|
@ -1798,7 +1890,7 @@ def api_validate_rule_to_add(rule, rule_type):
|
||||||
return {"status": "error", "reason": "Incorrect type"}, 400
|
return {"status": "error", "reason": "Incorrect type"}, 400
|
||||||
return {"status": "success", "rule": rule, "type": rule_type}, 200
|
return {"status": "success", "rule": rule, "type": rule_type}, 200
|
||||||
|
|
||||||
def api_create_retro_hunt_task(dict_input, creator):
|
def api_create_retro_hunt_task(dict_input, user_org, user_id):
|
||||||
# # TODO: API: check mandatory arg
|
# # TODO: API: check mandatory arg
|
||||||
# # TODO: TIMEOUT
|
# # TODO: TIMEOUT
|
||||||
|
|
||||||
|
@ -1810,6 +1902,15 @@ def api_create_retro_hunt_task(dict_input, creator):
|
||||||
if not task_type:
|
if not task_type:
|
||||||
return {"status": "error", "reason": "type not provided"}, 400
|
return {"status": "error", "reason": "type not provided"}, 400
|
||||||
|
|
||||||
|
# Level
|
||||||
|
level = dict_input.get('level', 1)
|
||||||
|
try:
|
||||||
|
level = int(level)
|
||||||
|
except TypeError:
|
||||||
|
level = 1
|
||||||
|
if level not in range(1, 3):
|
||||||
|
level = 1
|
||||||
|
|
||||||
# # TODO: limit
|
# # TODO: limit
|
||||||
name = dict_input.get('name', '')
|
name = dict_input.get('name', '')
|
||||||
name = escape(name)
|
name = escape(name)
|
||||||
|
@ -1867,15 +1968,18 @@ def api_create_retro_hunt_task(dict_input, creator):
|
||||||
if res:
|
if res:
|
||||||
return res
|
return res
|
||||||
|
|
||||||
task_uuid = create_retro_hunt(name, task_type, rule, creator, description=description,
|
task_uuid = create_retro_hunt(user_org, user_id, level, name, task_type, rule, description=description,
|
||||||
mails=mails, tags=tags, timeout=30, filters=filters)
|
mails=mails, tags=tags, timeout=30, filters=filters)
|
||||||
return {'name': name, 'rule': rule, 'type': task_type, 'uuid': task_uuid}, 200
|
return {'name': name, 'rule': rule, 'type': task_type, 'uuid': task_uuid}, 200
|
||||||
|
|
||||||
def api_delete_retro_hunt_task(task_uuid):
|
def api_delete_retro_hunt_task(user_org, is_admin, task_uuid):
|
||||||
res = api_check_retro_hunt_task_uuid(task_uuid)
|
res = api_check_retro_hunt_task_uuid(task_uuid)
|
||||||
if res:
|
if res:
|
||||||
return res
|
return res
|
||||||
retro_hunt = RetroHunt(task_uuid)
|
retro_hunt = RetroHunt(task_uuid)
|
||||||
|
res = api_check_retro_hunt_access_acl(retro_hunt, user_org, is_admin=is_admin)
|
||||||
|
if res:
|
||||||
|
return res
|
||||||
if retro_hunt.is_running() and retro_hunt.get_state() not in ['completed', 'paused']:
|
if retro_hunt.is_running() and retro_hunt.get_state() not in ['completed', 'paused']:
|
||||||
return {"status": "error", "reason": "You can't delete a running task"}, 400
|
return {"status": "error", "reason": "You can't delete a running task"}, 400
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -27,6 +27,29 @@ r_data = config_loader.get_db_conn("Kvrocks_DB") # TODO MOVE DEFAULT DB
|
||||||
|
|
||||||
config_loader = None
|
config_loader = None
|
||||||
|
|
||||||
|
# #### PART OF ORGANISATION ####
|
||||||
|
# from abc import ABC, abstractmethod
|
||||||
|
#
|
||||||
|
# class AbstractObject(ABC):
|
||||||
|
#
|
||||||
|
# @abstractmethod
|
||||||
|
# def get_org(self):
|
||||||
|
# pass
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# ## LEVEL ##
|
||||||
|
#
|
||||||
|
# @abstractmethod
|
||||||
|
# def get_level(self):
|
||||||
|
# pass
|
||||||
|
#
|
||||||
|
# @abstractmethod
|
||||||
|
# def set_level(self):
|
||||||
|
# pass
|
||||||
|
#
|
||||||
|
# @abstractmethod
|
||||||
|
# def reset_level(self):
|
||||||
|
# pass
|
||||||
|
|
||||||
#### ORGANISATIONS ####
|
#### ORGANISATIONS ####
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ from lib import ail_users
|
||||||
from lib import Investigations
|
from lib import Investigations
|
||||||
from lib.ConfigLoader import ConfigLoader
|
from lib.ConfigLoader import ConfigLoader
|
||||||
from lib import chats_viewer
|
from lib import chats_viewer
|
||||||
|
from lib import Tracker
|
||||||
|
|
||||||
class Updater(AIL_Updater):
|
class Updater(AIL_Updater):
|
||||||
"""default Updater."""
|
"""default Updater."""
|
||||||
|
@ -45,6 +46,13 @@ if __name__ == '__main__':
|
||||||
inv = Investigations.Investigation(inv_uuid)
|
inv = Investigations.Investigation(inv_uuid)
|
||||||
inv.set_level(1, None)
|
inv.set_level(1, None)
|
||||||
|
|
||||||
|
# TODO Trackers
|
||||||
|
|
||||||
|
print('Updating Retro Hunts ...')
|
||||||
|
for retro_hunt_uuid in Tracker.get_all_retro_hunt_tasks(): # TODO Creator ORG
|
||||||
|
retro = Tracker.RetroHunt(retro_hunt_uuid)
|
||||||
|
retro.set_level(1, None)
|
||||||
|
|
||||||
chats_viewer.fix_chats_with_messages()
|
chats_viewer.fix_chats_with_messages()
|
||||||
|
|
||||||
updater = Updater('v5.7')
|
updater = Updater('v5.7')
|
||||||
|
|
|
@ -468,8 +468,10 @@ def tracker_objects():
|
||||||
@login_required
|
@login_required
|
||||||
@login_read_only
|
@login_read_only
|
||||||
def retro_hunt_all_tasks():
|
def retro_hunt_all_tasks():
|
||||||
retro_hunts = Tracker.get_retro_hunt_metas()
|
user_org = current_user.get_org()
|
||||||
return render_template("retro_hunt_tasks.html", retro_hunts=retro_hunts, bootstrap_label=bootstrap_label)
|
retro_hunts_global = Tracker.get_retro_hunt_metas(Tracker.get_retro_hunts_global())
|
||||||
|
retro_hunts_org = Tracker.get_retro_hunt_metas(Tracker.get_retro_hunts_org(user_org))
|
||||||
|
return render_template("retro_hunt_tasks.html", retro_hunts_global=retro_hunts_global, retro_hunts_org=retro_hunts_org, bootstrap_label=bootstrap_label)
|
||||||
|
|
||||||
@hunters.route('/retro_hunt/task/show', methods=['GET'])
|
@hunters.route('/retro_hunt/task/show', methods=['GET'])
|
||||||
@login_required
|
@login_required
|
||||||
|
@ -478,19 +480,19 @@ def retro_hunt_show_task():
|
||||||
task_uuid = request.args.get('uuid', None)
|
task_uuid = request.args.get('uuid', None)
|
||||||
objs = request.args.get('objs', False)
|
objs = request.args.get('objs', False)
|
||||||
|
|
||||||
date_from_item = request.args.get('date_from')
|
# date_from_item = request.args.get('date_from')
|
||||||
date_to_item = request.args.get('date_to')
|
# date_to_item = request.args.get('date_to')
|
||||||
if date_from_item:
|
# if date_from_item:
|
||||||
date_from_item = date_from_item.replace('-', '')
|
# date_from_item = date_from_item.replace('-', '')
|
||||||
if date_to_item:
|
# if date_to_item:
|
||||||
date_to_item = date_to_item.replace('-', '')
|
# date_to_item = date_to_item.replace('-', '')
|
||||||
|
|
||||||
res = Tracker.api_check_retro_hunt_task_uuid(task_uuid)
|
res = Tracker.api_check_retro_hunt_task_uuid(task_uuid)
|
||||||
if res:
|
if res:
|
||||||
return create_json_response(res[0], res[1])
|
return create_json_response(res[0], res[1])
|
||||||
|
|
||||||
retro_hunt = Tracker.RetroHunt(task_uuid)
|
retro_hunt = Tracker.RetroHunt(task_uuid)
|
||||||
dict_task = retro_hunt.get_meta(options={'creator', 'date', 'description', 'progress', 'filters', 'nb_objs', 'tags'})
|
dict_task = retro_hunt.get_meta(options={'creator', 'date', 'description', 'level', 'progress', 'filters', 'nb_objs', 'tags'})
|
||||||
rule_content = Tracker.get_yara_rule_content(dict_task['rule'])
|
rule_content = Tracker.get_yara_rule_content(dict_task['rule'])
|
||||||
dict_task['filters'] = json.dumps(dict_task['filters'], indent=4)
|
dict_task['filters'] = json.dumps(dict_task['filters'], indent=4)
|
||||||
|
|
||||||
|
@ -509,6 +511,7 @@ def retro_hunt_show_task():
|
||||||
@login_analyst
|
@login_analyst
|
||||||
def retro_hunt_add_task():
|
def retro_hunt_add_task():
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
|
level = request.form.get("level", 1)
|
||||||
name = request.form.get("name", '')
|
name = request.form.get("name", '')
|
||||||
description = request.form.get("description", '')
|
description = request.form.get("description", '')
|
||||||
timeout = request.form.get("timeout", 30)
|
timeout = request.form.get("timeout", 30)
|
||||||
|
@ -586,14 +589,15 @@ def retro_hunt_add_task():
|
||||||
rule = yara_default_rule
|
rule = yara_default_rule
|
||||||
rule_type='yara_default'
|
rule_type='yara_default'
|
||||||
|
|
||||||
|
user_org = current_user.get_org()
|
||||||
user_id = current_user.get_user_id()
|
user_id = current_user.get_user_id()
|
||||||
|
|
||||||
input_dict = {"name": name, "description": description, "creator": user_id,
|
input_dict = {"level": level, "name": name, "description": description, "creator": user_id,
|
||||||
"rule": rule, "type": rule_type,
|
"rule": rule, "type": rule_type,
|
||||||
"tags": tags, "filters": filters, "timeout": timeout, # "mails": mails
|
"tags": tags, "filters": filters, "timeout": timeout, # "mails": mails
|
||||||
}
|
}
|
||||||
|
|
||||||
res = Tracker.api_create_retro_hunt_task(input_dict, user_id)
|
res = Tracker.api_create_retro_hunt_task(input_dict, user_org, user_id)
|
||||||
if res[1] == 200:
|
if res[1] == 200:
|
||||||
return redirect(url_for('hunters.retro_hunt_all_tasks'))
|
return redirect(url_for('hunters.retro_hunt_all_tasks'))
|
||||||
else:
|
else:
|
||||||
|
@ -609,8 +613,10 @@ def retro_hunt_add_task():
|
||||||
@login_required
|
@login_required
|
||||||
@login_analyst
|
@login_analyst
|
||||||
def retro_hunt_pause_task():
|
def retro_hunt_pause_task():
|
||||||
|
user_org = current_user.get_org()
|
||||||
|
is_admin = current_user.is_admin()
|
||||||
task_uuid = request.args.get('uuid', None)
|
task_uuid = request.args.get('uuid', None)
|
||||||
res = Tracker.api_pause_retro_hunt_task(task_uuid)
|
res = Tracker.api_pause_retro_hunt_task(user_org, is_admin, task_uuid)
|
||||||
if res[1] != 200:
|
if res[1] != 200:
|
||||||
return create_json_response(res[0], res[1])
|
return create_json_response(res[0], res[1])
|
||||||
return redirect(url_for('hunters.retro_hunt_all_tasks'))
|
return redirect(url_for('hunters.retro_hunt_all_tasks'))
|
||||||
|
@ -619,8 +625,10 @@ def retro_hunt_pause_task():
|
||||||
@login_required
|
@login_required
|
||||||
@login_analyst
|
@login_analyst
|
||||||
def retro_hunt_resume_task():
|
def retro_hunt_resume_task():
|
||||||
|
user_org = current_user.get_org()
|
||||||
|
is_admin = current_user.is_admin()
|
||||||
task_uuid = request.args.get('uuid', None)
|
task_uuid = request.args.get('uuid', None)
|
||||||
res = Tracker.api_resume_retro_hunt_task(task_uuid)
|
res = Tracker.api_resume_retro_hunt_task(user_org, is_admin, task_uuid)
|
||||||
if res[1] != 200:
|
if res[1] != 200:
|
||||||
return create_json_response(res[0], res[1])
|
return create_json_response(res[0], res[1])
|
||||||
return redirect(url_for('hunters.retro_hunt_all_tasks'))
|
return redirect(url_for('hunters.retro_hunt_all_tasks'))
|
||||||
|
@ -629,8 +637,10 @@ def retro_hunt_resume_task():
|
||||||
@login_required
|
@login_required
|
||||||
@login_analyst
|
@login_analyst
|
||||||
def retro_hunt_delete_task():
|
def retro_hunt_delete_task():
|
||||||
|
user_org = current_user.get_org()
|
||||||
|
is_admin = current_user.is_admin()
|
||||||
task_uuid = request.args.get('uuid', None)
|
task_uuid = request.args.get('uuid', None)
|
||||||
res = Tracker.api_delete_retro_hunt_task(task_uuid)
|
res = Tracker.api_delete_retro_hunt_task(user_org, is_admin, task_uuid)
|
||||||
if res[1] != 200:
|
if res[1] != 200:
|
||||||
return create_json_response(res[0], res[1])
|
return create_json_response(res[0], res[1])
|
||||||
return redirect(url_for('hunters.retro_hunt_all_tasks'))
|
return redirect(url_for('hunters.retro_hunt_all_tasks'))
|
||||||
|
|
|
@ -175,6 +175,12 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-xl-3">
|
<div class="col-12 col-xl-3">
|
||||||
|
|
||||||
|
<label class="mt-3" for="level_selector">View Level</label>
|
||||||
|
<select class="custom-select" id="level_selector" name="level">
|
||||||
|
<option value="1" selected><i class="fas fa-users"></i> Global</option>
|
||||||
|
<option value="2"><i class="fas fa-landmark"></i> My Organisation</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,9 @@
|
||||||
Create New Retro Hunt
|
Create New Retro Hunt
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<table id="table_user_trackers" class="table table-striped border-primary">
|
<h5>My Organisation:</h5>
|
||||||
|
|
||||||
|
<table id="table_retro_hunts_org" class="table table-striped border-primary">
|
||||||
<thead class="bg-dark text-white">
|
<thead class="bg-dark text-white">
|
||||||
<tr>
|
<tr>
|
||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
|
@ -46,7 +48,74 @@
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody style="font-size: 15px;">
|
<tbody style="font-size: 15px;">
|
||||||
{% for dict_task in retro_hunts %}
|
{% for dict_task in retro_hunts_org %}
|
||||||
|
<tr class="border-color: blue;">
|
||||||
|
<td>
|
||||||
|
<a href="{{ url_for('hunters.retro_hunt_show_task') }}?uuid={{ dict_task['uuid'] }}">
|
||||||
|
<span>
|
||||||
|
{{ dict_task['name']}}
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
<div>
|
||||||
|
{% for tag in dict_task['tags'] %}
|
||||||
|
<a href="{{ url_for('tags_ui.get_obj_by_tags') }}?object_type=item<ags={{ tag }}">
|
||||||
|
<span class="badge badge-{{ bootstrap_label[loop.index0 % 5] }} pull-left">{{ tag }}</span>
|
||||||
|
</a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>{{ dict_task['date'][0:4]}}/{{ dict_task['date'][4:6]}}/{{ dict_task['date'][6:8]}}</td>
|
||||||
|
<td>
|
||||||
|
<b><h3 class="font-weight-bold text-primary">{{dict_task['nb_match']}}</h3></b>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{%if dict_task['state']=='paused'%}
|
||||||
|
<a href="{{ url_for('hunters.retro_hunt_resume_task') }}?uuid={{dict_task['uuid']}}" class="mx-1">
|
||||||
|
<button class='btn btn-info'><i class="fas fa-play"></i></button>
|
||||||
|
</a>
|
||||||
|
{%endif%}
|
||||||
|
{%if dict_task['state']=='running' or dict_task['state']=='pending'%}
|
||||||
|
<!-- <a href="{{ url_for('hunters.retro_hunt_pause_task') }}?uuid={{dict_task['uuid']}}" class="mx-1">
|
||||||
|
<button class='btn btn-secondary'><i class="fas fa-stop"></i></button>
|
||||||
|
</a> -->
|
||||||
|
<a href="{{ url_for('hunters.retro_hunt_pause_task') }}?uuid={{dict_task['uuid']}}" class="mx-1">
|
||||||
|
<button class='btn btn-info'><i class="fas fa-pause"></i></button>
|
||||||
|
</a>
|
||||||
|
{%endif%}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td class="text-center">
|
||||||
|
<span class="justify-content-end">
|
||||||
|
{%if dict_task['state']=='pending'%}
|
||||||
|
<span class="text-secondary"><i class="fas fa-ellipsis-h fa-3x"></i>pending</span>
|
||||||
|
{%elif dict_task['state']=='completed'%}
|
||||||
|
<span class="text-success"><i class="fas fa-check-square fa-3x"></i> completed</span>
|
||||||
|
{%elif dict_task['state']=='paused'%}
|
||||||
|
<span class="text-secondary"><i class="fas fa-pause fa-3x"></i> paused [{{ dict_task['progress']}}%]</span>
|
||||||
|
{%elif dict_task['state']=='running'%}
|
||||||
|
<span class="text-secondary"><i class="fas fa-sync-alt fa-3x fa-spin"></i>running [{{ dict_task['progress']}}%]</span>
|
||||||
|
{%endif%}
|
||||||
|
<span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h5>Global:</h5>
|
||||||
|
|
||||||
|
<table id="table_retro_hunts_global" class="table table-striped border-primary">
|
||||||
|
<thead class="bg-dark text-white">
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Date</th>
|
||||||
|
<th>Nb Matches</th>
|
||||||
|
<th></th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody style="font-size: 15px;">
|
||||||
|
{% for dict_task in retro_hunts_global %}
|
||||||
<tr class="border-color: blue;">
|
<tr class="border-color: blue;">
|
||||||
<td>
|
<td>
|
||||||
<a href="{{ url_for('hunters.retro_hunt_show_task') }}?uuid={{ dict_task['uuid'] }}">
|
<a href="{{ url_for('hunters.retro_hunt_show_task') }}?uuid={{ dict_task['uuid'] }}">
|
||||||
|
@ -112,7 +181,12 @@ $(document).ready(function(){
|
||||||
$('#nav_title_retro_hunt').removeClass("text-muted");
|
$('#nav_title_retro_hunt').removeClass("text-muted");
|
||||||
$("#nav_retro_hunts").addClass("active");
|
$("#nav_retro_hunts").addClass("active");
|
||||||
|
|
||||||
$('#table_user_trackers').DataTable({
|
$('#table_retro_hunts_org').DataTable({
|
||||||
|
"aLengthMenu": [[5, 10, 15, -1], [5, 10, 15, "All"]],
|
||||||
|
"iDisplayLength": 10,
|
||||||
|
"order": [[ 1, "desc" ],[ 4, "desc" ]]
|
||||||
|
});
|
||||||
|
$('#table_retro_hunts_global').DataTable({
|
||||||
"aLengthMenu": [[5, 10, 15, -1], [5, 10, 15, "All"]],
|
"aLengthMenu": [[5, 10, 15, -1], [5, 10, 15, "All"]],
|
||||||
"iDisplayLength": 10,
|
"iDisplayLength": 10,
|
||||||
"order": [[ 1, "desc" ],[ 4, "desc" ]]
|
"order": [[ 1, "desc" ],[ 4, "desc" ]]
|
||||||
|
|
|
@ -105,6 +105,16 @@
|
||||||
<td class="text-right"><b>Description</b></td>
|
<td class="text-right"><b>Description</b></td>
|
||||||
<td>{{dict_task['description']}}</td>
|
<td>{{dict_task['description']}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="text-right"><b>Level</b></td>
|
||||||
|
<td>
|
||||||
|
{% if dict_task['level'] == 1 %}
|
||||||
|
Global
|
||||||
|
{% elif dict_task['level'] == 2 %}
|
||||||
|
My Organisation
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-right"><b>Tags</b></td>
|
<td class="text-right"><b>Tags</b></td>
|
||||||
<td>
|
<td>
|
||||||
|
|
Loading…
Reference in New Issue