chg: [trackers + retro_hunts] add org level to retro_hunt + update acl to support org + refactor trackers org

This commit is contained in:
terrtia 2024-08-28 16:47:44 +02:00
parent b466d4766a
commit 5c903f9f88
No known key found for this signature in database
GPG key ID: 1E1B1F50D84613D0
7 changed files with 312 additions and 77 deletions

View file

@ -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:

View file

@ -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 ####

View file

@ -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')

View file

@ -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'))

View file

@ -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>

View file

@ -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&ltags={{ 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>&nbsp;completed</span>
{%elif dict_task['state']=='paused'%}
<span class="text-secondary"><i class="fas fa-pause fa-3x"></i>&nbsp;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" ]]

View file

@ -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>