mirror of
https://github.com/ail-project/ail-framework.git
synced 2024-11-29 17:27:17 +00:00
chg: [trackers] refactor trackers
This commit is contained in:
parent
6b60041db2
commit
4473086f89
14 changed files with 871 additions and 875 deletions
|
@ -710,6 +710,13 @@ def delete_object_tag(tag, obj_type, id, subtype=''):
|
|||
r_tags.srem(f'tag:{obj_type}:{subtype}:{id}', tag)
|
||||
update_tag_global_by_obj_type(tag, obj_type, subtype=subtype)
|
||||
|
||||
def delete_object_tags(obj_type, subtype, obj_id):
|
||||
if not subtype:
|
||||
subtype = ''
|
||||
for tag in get_object_tags(obj_type, obj_id, subtype=subtype):
|
||||
delete_object_tag(tag, obj_type, obj_id, subtype=subtype)
|
||||
|
||||
|
||||
################################################################################################################
|
||||
|
||||
# TODO: REWRITE OLD
|
||||
|
@ -960,7 +967,10 @@ def is_galaxy_tag(tag, namespace=None):
|
|||
return False
|
||||
|
||||
def is_custom_tag(tag):
|
||||
return r_tags.sismember('tags:custom', tag)
|
||||
try:
|
||||
return r_tags.sismember('tags:custom', tag)
|
||||
except:
|
||||
return False
|
||||
|
||||
# # TODO:
|
||||
# def is_valid_tag(tag):
|
||||
|
@ -1018,6 +1028,20 @@ def sort_tags_taxonomies_galaxies(tags):
|
|||
galaxies_tags.append(tag)
|
||||
return taxonomies_tags, galaxies_tags
|
||||
|
||||
def sort_tags_taxonomies_galaxies_customs(tags):
|
||||
taxonomies_tags = []
|
||||
galaxies_tags = []
|
||||
customs_tags = []
|
||||
for tag in tags:
|
||||
if is_taxonomie_tag(tag):
|
||||
taxonomies_tags.append(tag)
|
||||
elif is_custom_tag(tag):
|
||||
print()
|
||||
customs_tags.append(tag)
|
||||
else:
|
||||
galaxies_tags.append(tag)
|
||||
return taxonomies_tags, galaxies_tags, customs_tags
|
||||
|
||||
##-- Taxonomies - Galaxies --##
|
||||
|
||||
def is_tag_in_all_tag(tag):
|
||||
|
@ -1089,8 +1113,9 @@ def get_modal_add_tags(object_id, object_type='item', object_subtype=''):
|
|||
|
||||
######## NEW VERSION ########
|
||||
def create_custom_tag(tag):
|
||||
r_tags.sadd('tags:custom', tag)
|
||||
r_tags.sadd('tags:custom:enabled_tags', tag)
|
||||
if not is_taxonomie_tag(tag) and not is_galaxy_tag(tag):
|
||||
r_tags.sadd('tags:custom', tag)
|
||||
r_tags.sadd('tags:custom:enabled_tags', tag)
|
||||
|
||||
# # TODO: ADD color
|
||||
def get_tag_metadata(tag, r_int=False):
|
||||
|
|
|
@ -97,23 +97,26 @@ class Tracker:
|
|||
def exists(self):
|
||||
return r_tracker.exists(f'tracker:{self.uuid}')
|
||||
|
||||
def _get_field(self, field):
|
||||
return r_tracker.hget(f'tracker:{self.uuid}', field)
|
||||
|
||||
def _set_field(self, field, value):
|
||||
r_tracker.hset(f'tracker:{self.uuid}', field, value)
|
||||
|
||||
def get_date(self):
|
||||
return r_tracker.hget(f'tracker:{self.uuid}', 'date')
|
||||
return self._get_field('date')
|
||||
|
||||
def get_last_change(self, r_str=False):
|
||||
last_change = r_tracker.hget(f'tracker:{self.uuid}', 'last_change')
|
||||
last_change = self._get_field('last_change')
|
||||
if r_str and last_change:
|
||||
last_change = datetime.datetime.fromtimestamp(float(last_change)).strftime('%Y-%m-%d %H:%M:%S')
|
||||
return last_change
|
||||
|
||||
def get_first_seen(self):
|
||||
return r_tracker.hget(f'tracker:{self.uuid}', 'first_seen')
|
||||
return self._get_field('first_seen')
|
||||
|
||||
def get_last_seen(self):
|
||||
return r_tracker.hget(f'tracker:{self.uuid}', 'last_seen')
|
||||
return self._get_field('last_seen')
|
||||
|
||||
def _set_first_seen(self, date):
|
||||
self._set_field('first_seen', date)
|
||||
|
@ -166,10 +169,10 @@ class Tracker:
|
|||
r_tracker.hdel(f'tracker:{self.uuid}', 'last_seen')
|
||||
|
||||
def get_description(self):
|
||||
return r_tracker.hget(f'tracker:{self.uuid}', 'description')
|
||||
return self._get_field('description')
|
||||
|
||||
def get_level(self):
|
||||
level = r_tracker.hget(f'tracker:{self.uuid}', 'level')
|
||||
level = self._get_field('level')
|
||||
if not level:
|
||||
level = 0
|
||||
return int(level)
|
||||
|
@ -194,7 +197,7 @@ class Tracker:
|
|||
self._set_field('level', level)
|
||||
|
||||
def get_filters(self):
|
||||
filters = r_tracker.hget(f'tracker:{self.uuid}', 'filters')
|
||||
filters = self._get_field('filters')
|
||||
if not filters:
|
||||
return {}
|
||||
else:
|
||||
|
@ -205,20 +208,22 @@ class Tracker:
|
|||
self._set_field('filters', json.dumps(filters))
|
||||
|
||||
def get_tracked(self):
|
||||
return r_tracker.hget(f'tracker:{self.uuid}', 'tracked')
|
||||
return self._get_field('tracked')
|
||||
|
||||
def get_type(self):
|
||||
return r_tracker.hget(f'tracker:{self.uuid}', 'type')
|
||||
return self._get_field('type')
|
||||
|
||||
def get_tags(self):
|
||||
return r_tracker.smembers(f'tracker:tags:{self.uuid}')
|
||||
|
||||
def _set_tags(self, tags):
|
||||
for tag in tags:
|
||||
tag = escape(tag)
|
||||
r_tracker.sadd(f'tracker:tags:{self.uuid}', tag)
|
||||
Tag.create_custom_tag(tag) # TODO CUSTOM TAGS
|
||||
|
||||
def _del_tags(self):
|
||||
return r_tracker.delete(f'tracker:tags:{self.uuid}')
|
||||
|
||||
def mail_export(self):
|
||||
return r_tracker.exists(f'tracker:mail:{self.uuid}')
|
||||
|
||||
|
@ -229,8 +234,11 @@ class Tracker:
|
|||
for mail in mails:
|
||||
r_tracker.sadd(f'tracker:mail:{self.uuid}', escape(mail))
|
||||
|
||||
def _del_mails(self):
|
||||
r_tracker.delete(f'tracker:mail:{self.uuid}')
|
||||
|
||||
def get_user(self):
|
||||
return r_tracker.hget(f'tracker:{self.uuid}', 'user_id')
|
||||
return self._get_field('user_id')
|
||||
|
||||
def webhook_export(self):
|
||||
return r_tracker.hexists(f'tracker:mail:{self.uuid}', 'webhook')
|
||||
|
@ -267,6 +275,8 @@ class Tracker:
|
|||
meta['level'] = self.get_level()
|
||||
if 'description' in options:
|
||||
meta['description'] = self.get_description()
|
||||
if 'nb_objs' in options:
|
||||
meta['nb_objs'] = self.get_nb_objs()
|
||||
if 'tags' in options:
|
||||
meta['tags'] = self.get_tags()
|
||||
if 'filters' in options:
|
||||
|
@ -289,39 +299,28 @@ class Tracker:
|
|||
r_tracker.lpush('trackers:dashboard', mess)
|
||||
r_tracker.ltrim(f'trackers:dashboard', 0, 9)
|
||||
|
||||
# - TODO Data Retention TO Implement - #
|
||||
# Or Daily/Monthly Global DB Cleanup:
|
||||
# Iterate on each tracker:
|
||||
# Iterate on each Obj:
|
||||
# Iterate on each date:
|
||||
# Delete from tracker range if date limit exceeded
|
||||
# - TODO
|
||||
def add(self, obj_type, subtype, obj_id, date=None):
|
||||
if not subtype:
|
||||
subtype = ''
|
||||
if not date:
|
||||
date = Date.get_today_date_str()
|
||||
|
||||
new_obj_date = r_tracker.sadd(f'tracker:objs:{self.uuid}:{date}', f'{obj_type}:{subtype}:{obj_id}')
|
||||
new_obj = r_tracker.sadd(f'obj:trackers:{obj_type}:{subtype}:{obj_id}', self.uuid)
|
||||
# MATCHES
|
||||
if new_obj:
|
||||
r_tracker.zincrby(f'tracker:match:{self.uuid}', 1, 'total')
|
||||
r_tracker.zincrby(f'tracker:match:{self.uuid}', 1, obj_type)
|
||||
|
||||
# Only save date for daterange objects - Needed for the DB Cleaner
|
||||
if obj_type != 'item': # not obj_date:
|
||||
r_tracker.sadd(f'obj:tracker:{obj_type}:{subtype}:{obj_id}:{self.uuid}', date)
|
||||
r_tracker.sadd(f'tracker:objs:{self.uuid}:{obj_type}', f'{subtype}:{obj_id}')
|
||||
|
||||
if new_obj_date:
|
||||
self.update_daterange(date)
|
||||
|
||||
self._add_to_dashboard(obj_type, subtype, obj_id)
|
||||
def get_nb_objs_by_type(self, obj_type):
|
||||
return r_tracker.scard(f'tracker:objs:{self.uuid}:{obj_type}')
|
||||
|
||||
def get_objs_by_type(self, obj_type):
|
||||
return r_tracker.smembers(f'tracker:objs:{self.uuid}:{obj_type}')
|
||||
|
||||
def get_nb_objs(self):
|
||||
objs = {}
|
||||
for obj_type in get_objects_tracked():
|
||||
nb = self.get_nb_objs_by_type(obj_type)
|
||||
if nb:
|
||||
objs[obj_type] = nb
|
||||
return objs
|
||||
|
||||
def get_objs(self):
|
||||
objs = []
|
||||
for obj_type in get_objects_tracked():
|
||||
for obj in self.get_objs_by_type(obj_type):
|
||||
subtype, obj_id = obj.split(':', 1)
|
||||
objs.append((obj_type, subtype, obj_id))
|
||||
return objs
|
||||
|
||||
def get_nb_objs_by_date(self, date):
|
||||
return r_tracker.scard(f'tracker:objs:{self.uuid}:{date}')
|
||||
|
||||
|
@ -335,10 +334,32 @@ class Tracker:
|
|||
return objs
|
||||
|
||||
def get_obj_dates(self, obj_type, subtype, obj_id):
|
||||
if obj_type == 'item':
|
||||
return [item_basic.get_item_date(obj_id)]
|
||||
else:
|
||||
return r_tracker.smembers(f'obj:tracker:{obj_type}:{subtype}:{obj_id}:{self.uuid}')
|
||||
return r_tracker.smembers(f'obj:tracker:{obj_type}:{subtype}:{obj_id}:{self.uuid}')
|
||||
|
||||
# - TODO Data Retention TO Implement - #
|
||||
# Or Daily/Monthly Global DB Cleanup:
|
||||
# Iterate on each tracker:
|
||||
# Iterate on each Obj:
|
||||
# Iterate on each date:
|
||||
# Delete from tracker range if date limit exceeded
|
||||
# - TODO
|
||||
def add(self, obj_type, subtype, obj_id, date=None):
|
||||
if not subtype:
|
||||
subtype = ''
|
||||
if not date:
|
||||
date = Date.get_today_date_str()
|
||||
|
||||
new_obj_date = r_tracker.sadd(f'tracker:objs:{self.uuid}:{date}', f'{obj_type}:{subtype}:{obj_id}')
|
||||
r_tracker.sadd(f'obj:trackers:{obj_type}:{subtype}:{obj_id}', self.uuid)
|
||||
|
||||
# Only save object match date - Needed for the DB Cleaner
|
||||
r_tracker.sadd(f'obj:tracker:{obj_type}:{subtype}:{obj_id}:{self.uuid}', date)
|
||||
r_tracker.sadd(f'tracker:objs:{self.uuid}:{obj_type}', f'{subtype}:{obj_id}')
|
||||
|
||||
if new_obj_date:
|
||||
self.update_daterange(date)
|
||||
|
||||
self._add_to_dashboard(obj_type, subtype, obj_id)
|
||||
|
||||
def remove(self, obj_type, subtype, obj_id):
|
||||
if not subtype:
|
||||
|
@ -350,9 +371,6 @@ class Tracker:
|
|||
|
||||
r_tracker.srem(f'obj:trackers:{obj_type}:{subtype}:{obj_id}', self.uuid)
|
||||
r_tracker.srem(f'tracker:objs:{self.uuid}', f'{obj_type}:{subtype}:{obj_id}')
|
||||
# MATCHES
|
||||
r_tracker.zincrby(f'tracker:match:{self.uuid}', -1, 'total')
|
||||
r_tracker.zincrby(f'tracker:match:{self.uuid}', -1, obj_type)
|
||||
self.update_daterange()
|
||||
|
||||
# TODO escape custom tags
|
||||
|
@ -483,19 +501,28 @@ class Tracker:
|
|||
# Tags
|
||||
nb_old_tags = r_tracker.scard(f'tracker:tags:{self.uuid}')
|
||||
if nb_old_tags > 0 or tags:
|
||||
r_tracker.delete(f'tracker:tags:{self.uuid}')
|
||||
self._del_tags()
|
||||
self._set_tags(tags)
|
||||
|
||||
# Mails
|
||||
nb_old_mails = r_tracker.scard(f'tracker:mail:{self.uuid}')
|
||||
if nb_old_mails > 0 or mails:
|
||||
r_tracker.delete(f'tracker:mail:{self.uuid}')
|
||||
self._del_mails()
|
||||
self._set_mails(mails)
|
||||
|
||||
nb_old_sources = r_tracker.scard(f'tracker:sources:{self.uuid}') # TODO FILTERS
|
||||
if nb_old_sources > 0 or sources:
|
||||
r_tracker.delete(f'tracker:sources:{self.uuid}')
|
||||
self._set_sources(sources)
|
||||
# Filters
|
||||
if not filters:
|
||||
filters = {}
|
||||
for obj_type in get_objects_tracked():
|
||||
filters[obj_type] = {}
|
||||
else:
|
||||
self.set_filters(filters)
|
||||
for obj_type in filters:
|
||||
r_tracker.sadd(f'trackers:objs:{tracker_type}:{obj_type}', to_track)
|
||||
r_tracker.sadd(f'trackers:uuid:{tracker_type}:{to_track}', f'{self.uuid}:{obj_type}')
|
||||
if tracker_type != old_type:
|
||||
r_tracker.srem(f'trackers:objs:{old_type}:{obj_type}', old_to_track)
|
||||
r_tracker.srem(f'trackers:uuid:{old_type}:{old_to_track}', f'{self.uuid}:{obj_type}')
|
||||
|
||||
# Refresh Trackers
|
||||
trigger_trackers_refresh(tracker_type)
|
||||
|
@ -506,7 +533,37 @@ class Tracker:
|
|||
return self.uuid
|
||||
|
||||
def delete(self):
|
||||
pass
|
||||
for obj in self.get_objs():
|
||||
self.remove(obj[0], obj[1], obj[2])
|
||||
|
||||
tracker_type = self.get_type()
|
||||
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':
|
||||
r_tracker.delete(f'tracker:typosquatting:{tracked}')
|
||||
elif tracker_type == 'yara':
|
||||
if not is_default_yara_rule(tracked):
|
||||
filepath = get_yara_rule_file_by_tracker_name(tracked)
|
||||
if filepath:
|
||||
os.remove(filepath)
|
||||
|
||||
# Filters
|
||||
filters = self.get_filters()
|
||||
if not filters:
|
||||
filters = get_objects_tracked()
|
||||
for obj_type in filters:
|
||||
r_tracker.srem(f'trackers:objs:{tracker_type}:{obj_type}', tracked)
|
||||
r_tracker.srem(f'trackers:uuid:{tracker_type}:{tracked}', f'{self.uuid}:{obj_type}')
|
||||
|
||||
self._del_mails()
|
||||
self._del_tags()
|
||||
# meta
|
||||
r_tracker.delete(f'tracker:{self.uuid}')
|
||||
|
||||
|
||||
def create_tracker(tracker_type, to_track, user_id, level, description=None, filters={}, tags=[], mails=[], webhook=None, tracker_uuid=None):
|
||||
|
@ -612,12 +669,14 @@ def get_trackers_dashboard():
|
|||
tracker_uuid, timestamp, obj_type, subtype, obj_id = raw.split(':', 4)
|
||||
tracker = Tracker(tracker_uuid)
|
||||
meta = tracker.get_meta(options={'tags'})
|
||||
if not meta.get('type'):
|
||||
meta['type'] = 'Tracker DELETED'
|
||||
timestamp = datetime.datetime.fromtimestamp(float(timestamp)).strftime('%Y-%m-%d %H:%M:%S')
|
||||
meta['timestamp'] = timestamp
|
||||
trackers.append(meta)
|
||||
return trackers
|
||||
|
||||
def get_user_dashboard(user_id): # TODO SORT + REMOVE OLDER ROWS
|
||||
def get_user_dashboard(user_id): # TODO SORT + REMOVE OLDER ROWS (trim)
|
||||
trackers = []
|
||||
for raw in r_tracker.lrange(f'trackers:user:{user_id}', 0, -1):
|
||||
tracker_uuid, timestamp, obj_type, subtype, obj_id = raw.split(':', 4)
|
||||
|
@ -822,8 +881,8 @@ def api_add_tracker(dict_input, user_id):
|
|||
description = escape(description)
|
||||
webhook = dict_input.get('webhook', '')
|
||||
webhook = escape(webhook)
|
||||
res = api_validate_tracker_to_add(to_track , tracker_type, nb_words=nb_words)
|
||||
if res[1]!=200:
|
||||
res = api_validate_tracker_to_add(to_track, tracker_type, nb_words=nb_words)
|
||||
if res[1] != 200:
|
||||
return res
|
||||
to_track = res[0]['tracked']
|
||||
tracker_type = res[0]['type']
|
||||
|
@ -878,23 +937,81 @@ def api_add_tracker(dict_input, user_id):
|
|||
|
||||
return {'tracked': to_track, 'type': tracker_type, 'uuid': tracker_uuid}, 200
|
||||
|
||||
# TODO
|
||||
def api_edit_tracker(dict_input, user_id):
|
||||
pass
|
||||
# tracker_uuid = dict_input.get('uuid', None)
|
||||
# # check edit ACL
|
||||
# if tracker_uuid:
|
||||
# res = api_is_allowed_to_edit_tracker(tracker_uuid, user_id)
|
||||
# if res[1] != 200:
|
||||
# return res
|
||||
# else:
|
||||
# # check if tracker already tracked in global
|
||||
# if level==1:
|
||||
# if is_tracked_in_global_level(to_track, tracker_type) and not tracker_uuid:
|
||||
# return {"status": "error", "reason": "Tracker already exist"}, 409
|
||||
# else:
|
||||
# if is_tracked_in_user_level(to_track, tracker_type, user_id) and not tracker_uuid:
|
||||
# return {"status": "error", "reason": "Tracker already exist"}, 409
|
||||
tracker_uuid = dict_input.get('uuid')
|
||||
res = api_check_tracker_acl(tracker_uuid, user_id)
|
||||
if res:
|
||||
return res
|
||||
|
||||
tracker = Tracker(tracker_uuid)
|
||||
|
||||
to_track = dict_input.get('tracked', None)
|
||||
if not to_track:
|
||||
return {"status": "error", "reason": "Tracker not provided"}, 400
|
||||
tracker_type = dict_input.get('type', None)
|
||||
if not tracker_type:
|
||||
return {"status": "error", "reason": "Tracker type not provided"}, 400
|
||||
nb_words = dict_input.get('nb_words', 1)
|
||||
description = dict_input.get('description', '')
|
||||
description = escape(description)
|
||||
webhook = dict_input.get('webhook', '')
|
||||
webhook = escape(webhook)
|
||||
res = api_validate_tracker_to_add(to_track, tracker_type, nb_words=nb_words)
|
||||
if res[1] != 200:
|
||||
return res
|
||||
to_track = res[0]['tracked']
|
||||
tracker_type = res[0]['type']
|
||||
|
||||
tags = dict_input.get('tags', [])
|
||||
mails = dict_input.get('mails', [])
|
||||
res = verify_mail_list(mails)
|
||||
if res:
|
||||
return res
|
||||
|
||||
# Filters # TODO MOVE ME
|
||||
filters = dict_input.get('filters', {})
|
||||
if filters:
|
||||
if filters.keys() == {'decoded', 'item', 'pgp'} and set(filters['pgp'].get('subtypes', [])) == {'mail', 'name'}:
|
||||
if not filters['decoded'] and not filters['item']:
|
||||
filters = {}
|
||||
for obj_type in filters:
|
||||
if obj_type not in get_objects_tracked():
|
||||
return {"status": "error", "reason": "Invalid Tracker Object type"}, 400
|
||||
|
||||
if obj_type == 'pgp':
|
||||
if set(filters['pgp'].get('subtypes', [])) == {'mail', 'name'}:
|
||||
filters['pgp'].pop('subtypes')
|
||||
|
||||
for filter_name in filters[obj_type]:
|
||||
if filter_name not in {'mimetypes', 'sources', 'subtypes'}:
|
||||
return {"status": "error", "reason": "Invalid Filter"}, 400
|
||||
elif filter_name == 'mimetypes': # TODO
|
||||
pass
|
||||
elif filter_name == 'sources':
|
||||
if obj_type == 'item':
|
||||
res = item_basic.verify_sources_list(filters['item']['sources'])
|
||||
if res:
|
||||
return res
|
||||
else:
|
||||
return {"status": "error", "reason": "Invalid Filter sources"}, 400
|
||||
elif filter_name == 'subtypes':
|
||||
obj_subtypes = set(get_object_all_subtypes(obj_type))
|
||||
for subtype in filters[obj_type]['subtypes']:
|
||||
if subtype not in obj_subtypes:
|
||||
return {"status": "error", "reason": "Invalid Tracker Object subtype"}, 400
|
||||
|
||||
level = dict_input.get('level', 1)
|
||||
try:
|
||||
level = int(level)
|
||||
except TypeError:
|
||||
level = 1
|
||||
if level not in range(0, 1):
|
||||
level = 1
|
||||
|
||||
tracker.edit(tracker_type, to_track, level, description=description, filters=filters,
|
||||
tags=tags, mails=mails, webhook=webhook)
|
||||
return {'tracked': to_track, 'type': tracker_type, 'uuid': tracker_uuid}, 200
|
||||
|
||||
|
||||
def api_delete_tracker(data, user_id):
|
||||
tracker_uuid = data.get('uuid')
|
||||
|
@ -1073,7 +1190,7 @@ def save_yara_rule(yara_rule_type, yara_rule, tracker_uuid=None):
|
|||
filename = os.path.join('custom-rules', tracker_uuid + '.yar')
|
||||
with open(os.path.join(get_yara_rules_dir(), filename), 'w') as f:
|
||||
f.write(str(yara_rule))
|
||||
if yara_rule_type == 'yara_default':
|
||||
elif yara_rule_type == 'yara_default':
|
||||
filename = os.path.join('ail-yara-rules', 'rules', yara_rule)
|
||||
return filename
|
||||
|
||||
|
@ -1316,7 +1433,9 @@ class RetroHunt:
|
|||
def get_nb_objs(self):
|
||||
objs = {}
|
||||
for obj_type in get_objects_retro_hunted():
|
||||
objs[obj_type] = self.get_nb_objs_by_type(obj_type)
|
||||
nb = self.get_nb_objs_by_type(obj_type)
|
||||
if nb:
|
||||
objs[obj_type] = nb
|
||||
return objs
|
||||
|
||||
def get_objs(self):
|
||||
|
@ -1363,12 +1482,6 @@ class RetroHunt:
|
|||
for mail in mails:
|
||||
r_tracker.sadd(f'retro_hunt:mails:{self.uuid}', escape(mail))
|
||||
|
||||
# TODO Delete filters - SAVE DEFAULT OBJECTS ???
|
||||
# Filters
|
||||
# if not filters:
|
||||
# filters = {}
|
||||
# for obj_type in get_objects_tracked():
|
||||
# filters[obj_type] = {}
|
||||
if filters:
|
||||
self.set_filters(filters)
|
||||
|
||||
|
@ -1379,11 +1492,17 @@ class RetroHunt:
|
|||
state = 'pending'
|
||||
self._set_state(state)
|
||||
|
||||
# TODO Delete Rule custom
|
||||
def delete(self):
|
||||
if self.is_running():
|
||||
if self.is_running() and self.get_state() != 'completed':
|
||||
return None
|
||||
|
||||
# Delete custom rule
|
||||
rule = self.get_rule()
|
||||
if not is_default_yara_rule(rule):
|
||||
filepath = get_yara_rule_file_by_tracker_name(rule)
|
||||
if filepath:
|
||||
os.remove(filepath)
|
||||
|
||||
r_tracker.srem('retro_hunts:pending', self.uuid)
|
||||
r_tracker.delete(f'retro_hunts:{self.uuid}')
|
||||
r_tracker.delete(f'retro_hunt:tags:{self.uuid}')
|
||||
|
@ -1580,7 +1699,7 @@ def api_delete_retro_hunt_task(task_uuid):
|
|||
if res:
|
||||
return res
|
||||
retro_hunt = RetroHunt(task_uuid)
|
||||
if retro_hunt.is_running():
|
||||
if retro_hunt.is_running() and retro_hunt.get_state() != 'completed':
|
||||
return {"status": "error", "reason": "You can't delete a running task"}, 400
|
||||
else:
|
||||
return retro_hunt.delete(), 200
|
||||
|
|
|
@ -83,12 +83,7 @@ class Tracker_Regex(AbstractModule):
|
|||
print(f'new tracked regex found: {tracker_name} in {obj_id}')
|
||||
self.redis_logger.warning(f'new tracked regex found: {tracker_name} in {obj_id}')
|
||||
|
||||
if obj.get_type() == 'item':
|
||||
date = obj.get_date()
|
||||
else:
|
||||
date = None
|
||||
|
||||
tracker.add(obj.get_type(), obj.get_subtype(r_str=True), obj_id, date=date)
|
||||
tracker.add(obj.get_type(), obj.get_subtype(r_str=True), obj_id)
|
||||
|
||||
for tag in tracker.get_tags():
|
||||
if obj.get_type() == 'item':
|
||||
|
|
|
@ -124,14 +124,10 @@ class Tracker_Term(AbstractModule):
|
|||
if ail_objects.is_filtered(obj, filters):
|
||||
continue
|
||||
|
||||
print(f'new tracked term found: {tracker_name} in {obj_id}')
|
||||
print(f'new tracked term {tracker_uuid} found: {tracker_name} in {obj_id}')
|
||||
self.redis_logger.warning(f'new tracked term found: {tracker_name} in {obj_id}')
|
||||
|
||||
if obj.get_type() == 'item':
|
||||
date = obj.get_date()
|
||||
else:
|
||||
date = None
|
||||
tracker.add(obj.get_type(), obj.get_subtype(), obj_id, date=date)
|
||||
tracker.add(obj.get_type(), obj.get_subtype(), obj_id)
|
||||
|
||||
# Tags
|
||||
for tag in tracker.get_tags():
|
||||
|
|
|
@ -78,12 +78,7 @@ class Tracker_Typo_Squatting(AbstractModule):
|
|||
print(f'new tracked typosquatting found: {tracked} in {obj_id}')
|
||||
self.redis_logger.warning(f'tracker typosquatting: {tracked} in {obj_id}')
|
||||
|
||||
if obj.get_type() == 'item':
|
||||
date = obj.get_date()
|
||||
else:
|
||||
date = None
|
||||
|
||||
tracker.add(obj.get_type(), obj.get_subtype(r_str=True), obj_id, date=date)
|
||||
tracker.add(obj.get_type(), obj.get_subtype(r_str=True), obj_id)
|
||||
|
||||
# Tags
|
||||
for tag in tracker.get_tags():
|
||||
|
|
|
@ -84,12 +84,7 @@ class Tracker_Yara(AbstractModule):
|
|||
if ail_objects.is_filtered(self.obj, filters):
|
||||
continue
|
||||
|
||||
if self.obj.get_type() == 'item':
|
||||
date = self.obj.get_date()
|
||||
else:
|
||||
date = None
|
||||
|
||||
tracker.add(self.obj.get_type(), self.obj.get_subtype(r_str=True), obj_id, date=date)
|
||||
tracker.add(self.obj.get_type(), self.obj.get_subtype(r_str=True), obj_id)
|
||||
|
||||
# Tags
|
||||
for tag in tracker.get_tags():
|
||||
|
|
|
@ -9,7 +9,7 @@ import os
|
|||
import sys
|
||||
import json
|
||||
|
||||
from flask import render_template, jsonify, request, Blueprint, redirect, url_for, Response, escape
|
||||
from flask import render_template, jsonify, request, Blueprint, redirect, url_for, Response, escape, abort
|
||||
from flask_login import login_required, current_user, login_user, logout_user
|
||||
|
||||
sys.path.append('modules')
|
||||
|
@ -27,6 +27,7 @@ from lib.objects import ail_objects
|
|||
from lib import item_basic
|
||||
from lib import Tracker
|
||||
from lib import Tag
|
||||
from packages import Date
|
||||
|
||||
|
||||
bootstrap_label = Flask_config.bootstrap_label
|
||||
|
@ -47,6 +48,14 @@ def create_json_response(data, status_code):
|
|||
|
||||
# ============= ROUTES ==============
|
||||
|
||||
@hunters.route("/yara/rule/default/content", methods=['GET'])
|
||||
@login_required
|
||||
@login_read_only
|
||||
def get_default_yara_rule_content():
|
||||
default_yara_rule = request.args.get('rule')
|
||||
res = Tracker.api_get_default_rule_content(default_yara_rule)
|
||||
return Response(json.dumps(res[0], indent=2, sort_keys=True), mimetype='application/json'), res[1]
|
||||
|
||||
##################
|
||||
# TRACKERS #
|
||||
##################
|
||||
|
@ -120,98 +129,160 @@ def tracked_menu_typosquatting():
|
|||
return render_template("trackersManagement.html", user_trackers=user_trackers, global_trackers=global_trackers,
|
||||
bootstrap_label=bootstrap_label, tracker_type=tracker_type)
|
||||
|
||||
|
||||
@hunters.route("/tracker/show")
|
||||
@login_required
|
||||
@login_read_only
|
||||
def show_tracker():
|
||||
user_id = current_user.get_id()
|
||||
tracker_uuid = request.args.get('uuid', None)
|
||||
res = Tracker.api_is_allowed_to_edit_tracker(tracker_uuid, user_id)
|
||||
if res[1] != 200: # invalid access
|
||||
return Response(json.dumps(res[0], indent=2, sort_keys=True), mimetype='application/json'), res[1]
|
||||
|
||||
date_from = request.args.get('date_from')
|
||||
date_to = request.args.get('date_to')
|
||||
|
||||
if date_from:
|
||||
date_from = date_from.replace('-', '')
|
||||
if date_to:
|
||||
date_to = date_to.replace('-', '')
|
||||
|
||||
tracker = Tracker.Tracker(tracker_uuid)
|
||||
meta = tracker.get_meta(options={'description', 'level', 'mails', 'filters', 'sparkline', 'tags',
|
||||
'user', 'webhook', 'nb_objs'})
|
||||
|
||||
if meta['type'] == 'yara':
|
||||
yara_rule_content = Tracker.get_yara_rule_content(meta['tracked'])
|
||||
else:
|
||||
yara_rule_content = None
|
||||
|
||||
if meta['type'] == 'typosquatting':
|
||||
typo_squatting = Tracker.get_tracked_typosquatting_domains(meta['tracked'])
|
||||
sorted(typo_squatting)
|
||||
else:
|
||||
typo_squatting = set()
|
||||
|
||||
if date_from:
|
||||
date_from, date_to = Date.sanitise_daterange(meta['first_seen'], meta['last_seen'])
|
||||
objs = tracker.get_objs_by_daterange(date_from, date_to)
|
||||
meta['objs'] = ail_objects.get_objects_meta(objs, flask_context=True)
|
||||
else:
|
||||
date_from = ''
|
||||
date_to = ''
|
||||
meta['objs'] = []
|
||||
|
||||
meta['date_from'] = date_from
|
||||
meta['date_to'] = date_to
|
||||
meta['item_sources'] = sorted(meta['filters'].get('item', {}).get('sources', []))
|
||||
if meta['filters']:
|
||||
meta['filters'] = json.dumps(meta['filters'], indent=4)
|
||||
|
||||
return render_template("tracker_show.html", meta=meta,
|
||||
rule_content=yara_rule_content,
|
||||
typo_squatting=typo_squatting,
|
||||
bootstrap_label=bootstrap_label)
|
||||
|
||||
def parse_add_edit_request(request_form):
|
||||
to_track = request_form.get("tracker")
|
||||
tracker_uuid = request_form.get("tracker_uuid")
|
||||
tracker_type = request_form.get("tracker_type")
|
||||
nb_words = request_form.get("nb_word", 1)
|
||||
description = request.form.get("description", '')
|
||||
webhook = request_form.get("webhook", '')
|
||||
level = request_form.get("level", 0)
|
||||
mails = request_form.get("mails", [])
|
||||
|
||||
# TAGS
|
||||
tags = request_form.get("tags", [])
|
||||
taxonomies_tags = request_form.get('taxonomies_tags')
|
||||
if taxonomies_tags:
|
||||
try:
|
||||
taxonomies_tags = json.loads(taxonomies_tags)
|
||||
except:
|
||||
taxonomies_tags = []
|
||||
else:
|
||||
taxonomies_tags = []
|
||||
galaxies_tags = request_form.get('galaxies_tags')
|
||||
if galaxies_tags:
|
||||
try:
|
||||
galaxies_tags = json.loads(galaxies_tags)
|
||||
except:
|
||||
galaxies_tags = []
|
||||
else:
|
||||
galaxies_tags = []
|
||||
# custom tags
|
||||
if tags:
|
||||
tags = tags.split()
|
||||
else:
|
||||
tags = []
|
||||
escaped = []
|
||||
for tag in tags:
|
||||
escaped.append(tag)
|
||||
tags = escaped + taxonomies_tags + galaxies_tags
|
||||
|
||||
# YARA #
|
||||
if tracker_type == 'yara':
|
||||
yara_default_rule = request_form.get("yara_default_rule")
|
||||
yara_custom_rule = request_form.get("yara_custom_rule")
|
||||
if yara_custom_rule:
|
||||
to_track = yara_custom_rule
|
||||
tracker_type = 'yara_custom'
|
||||
else:
|
||||
to_track = yara_default_rule
|
||||
tracker_type = 'yara_default'
|
||||
|
||||
if level == 'on':
|
||||
level = 1
|
||||
else:
|
||||
level = 0
|
||||
if mails:
|
||||
mails = mails.split()
|
||||
else:
|
||||
mails = []
|
||||
|
||||
# FILTERS
|
||||
filters = {}
|
||||
for obj_type in Tracker.get_objects_tracked():
|
||||
new_filter = request_form.get(f'{obj_type}_obj')
|
||||
if new_filter == 'on':
|
||||
filters[obj_type] = {}
|
||||
# Mimetypes
|
||||
mimetypes = request_form.get(f'mimetypes_{obj_type}', [])
|
||||
if mimetypes:
|
||||
mimetypes = json.loads(mimetypes)
|
||||
filters[obj_type]['mimetypes'] = mimetypes
|
||||
# Sources
|
||||
sources = request_form.get(f'sources_{obj_type}', [])
|
||||
if sources:
|
||||
sources = json.loads(sources)
|
||||
filters[obj_type]['sources'] = sources
|
||||
# Subtypes
|
||||
for obj_subtype in ail_core.get_object_all_subtypes(obj_type):
|
||||
subtype = request_form.get(f'filter_{obj_type}_{obj_subtype}')
|
||||
if subtype == 'on':
|
||||
if 'subtypes' not in filters[obj_type]:
|
||||
filters[obj_type]['subtypes'] = []
|
||||
filters[obj_type]['subtypes'].append(obj_subtype)
|
||||
|
||||
input_dict = {"tracked": to_track, "type": tracker_type,
|
||||
"tags": tags, "mails": mails, "filters": filters,
|
||||
"level": level, "description": description, "webhook": webhook}
|
||||
if tracker_uuid:
|
||||
input_dict['uuid'] = tracker_uuid
|
||||
if tracker_type == 'set':
|
||||
try:
|
||||
input_dict['nb_words'] = int(nb_words)
|
||||
except (ValueError, TypeError):
|
||||
input_dict['nb_words'] = 1
|
||||
return input_dict
|
||||
|
||||
@hunters.route("/tracker/add", methods=['GET', 'POST'])
|
||||
@login_required
|
||||
@login_analyst
|
||||
def add_tracked_menu():
|
||||
if request.method == 'POST':
|
||||
to_track = request.form.get("tracker")
|
||||
tracker_uuid = request.form.get("tracker_uuid")
|
||||
tracker_type = request.form.get("tracker_type")
|
||||
nb_words = request.form.get("nb_word", 1)
|
||||
description = request.form.get("description", '')
|
||||
webhook = request.form.get("webhook", '')
|
||||
level = request.form.get("level", 0)
|
||||
mails = request.form.get("mails", [])
|
||||
|
||||
# TAGS
|
||||
tags = request.form.get("tags", [])
|
||||
taxonomies_tags = request.form.get('taxonomies_tags')
|
||||
if taxonomies_tags:
|
||||
try:
|
||||
taxonomies_tags = json.loads(taxonomies_tags)
|
||||
except:
|
||||
taxonomies_tags = []
|
||||
else:
|
||||
taxonomies_tags = []
|
||||
galaxies_tags = request.form.get('galaxies_tags')
|
||||
if galaxies_tags:
|
||||
try:
|
||||
galaxies_tags = json.loads(galaxies_tags)
|
||||
except:
|
||||
galaxies_tags = []
|
||||
else:
|
||||
galaxies_tags = []
|
||||
# custom tags
|
||||
if tags:
|
||||
tags = tags.split()
|
||||
else:
|
||||
tags = []
|
||||
tags = tags + taxonomies_tags + galaxies_tags
|
||||
|
||||
# YARA #
|
||||
if tracker_type == 'yara':
|
||||
yara_default_rule = request.form.get("yara_default_rule")
|
||||
yara_custom_rule = request.form.get("yara_custom_rule")
|
||||
if yara_custom_rule:
|
||||
to_track = yara_custom_rule
|
||||
tracker_type = 'yara_custom'
|
||||
else:
|
||||
to_track = yara_default_rule
|
||||
tracker_type = 'yara_default'
|
||||
|
||||
if level == 'on':
|
||||
level = 1
|
||||
else:
|
||||
level = 0
|
||||
if mails:
|
||||
mails = mails.split()
|
||||
else:
|
||||
tags = []
|
||||
|
||||
# FILTERS
|
||||
filters = {}
|
||||
for obj_type in Tracker.get_objects_tracked():
|
||||
new_filter = request.form.get(f'{obj_type}_obj')
|
||||
if new_filter == 'on':
|
||||
filters[obj_type] = {}
|
||||
# Mimetypes
|
||||
mimetypes = request.form.get(f'mimetypes_{obj_type}', [])
|
||||
if mimetypes:
|
||||
mimetypes = json.loads(mimetypes)
|
||||
filters[obj_type]['mimetypes'] = mimetypes
|
||||
# Sources
|
||||
sources = request.form.get(f'sources_{obj_type}', [])
|
||||
if sources:
|
||||
sources = json.loads(sources)
|
||||
filters[obj_type]['sources'] = sources
|
||||
# Subtypes
|
||||
for obj_subtype in ail_core.get_object_all_subtypes(obj_type):
|
||||
subtype = request.form.get(f'filter_{obj_type}_{obj_subtype}')
|
||||
if subtype == 'on':
|
||||
if 'subtypes' not in filters[obj_type]:
|
||||
filters[obj_type]['subtypes'] = []
|
||||
filters[obj_type]['subtypes'].append(obj_subtype)
|
||||
|
||||
input_dict = {"tracked": to_track, "type": tracker_type,
|
||||
"tags": tags, "mails": mails, "filters": filters,
|
||||
"level": level, "description": description, "webhook": webhook}
|
||||
if tracker_type == 'set':
|
||||
try:
|
||||
input_dict['nb_words'] = int(nb_words)
|
||||
except TypeError:
|
||||
input_dict['nb_words'] = 1
|
||||
|
||||
input_dict = parse_add_edit_request(request.form)
|
||||
user_id = current_user.get_id()
|
||||
res = Tracker.api_add_tracker(input_dict, user_id)
|
||||
if res[1] == 200:
|
||||
|
@ -220,9 +291,42 @@ def add_tracked_menu():
|
|||
return create_json_response(res[0], res[1])
|
||||
else:
|
||||
return render_template("tracker_add.html",
|
||||
all_sources=item_basic.get_all_items_sources(r_list=True),
|
||||
tags_selector_data=Tag.get_tags_selector_data(),
|
||||
all_yara_files=Tracker.get_all_default_yara_files())
|
||||
all_sources=item_basic.get_all_items_sources(r_list=True),
|
||||
tags_selector_data=Tag.get_tags_selector_data(),
|
||||
all_yara_files=Tracker.get_all_default_yara_files())
|
||||
|
||||
@hunters.route("/tracker/edit", methods=['GET', 'POST'])
|
||||
@login_required
|
||||
@login_analyst
|
||||
def tracker_edit():
|
||||
if request.method == 'POST':
|
||||
input_dict = parse_add_edit_request(request.form)
|
||||
user_id = current_user.get_id()
|
||||
res = Tracker.api_edit_tracker(input_dict, user_id)
|
||||
if res[1] == 200:
|
||||
return redirect(url_for('hunters.show_tracker', uuid=res[0].get('uuid')))
|
||||
else:
|
||||
user_id = current_user.get_id()
|
||||
tracker_uuid = request.args.get('uuid', None)
|
||||
res = Tracker.api_is_allowed_to_edit_tracker(tracker_uuid, user_id)
|
||||
if res[1] != 200: # invalid access
|
||||
return Response(json.dumps(res[0], indent=2, sort_keys=True), mimetype='application/json'), res[1]
|
||||
|
||||
tracker = Tracker.Tracker(tracker_uuid)
|
||||
dict_tracker = tracker.get_meta(options={'description', 'level', 'mails', 'filters', 'tags', 'webhook'})
|
||||
if dict_tracker['type'] == 'yara':
|
||||
if not Tracker.is_default_yara_rule(dict_tracker['tracked']):
|
||||
dict_tracker['content'] = Tracker.get_yara_rule_content(dict_tracker['tracked'])
|
||||
taxonomies_tags, galaxies_tags, custom_tags = Tag.sort_tags_taxonomies_galaxies_customs(dict_tracker['tags'])
|
||||
tags_selector_data = Tag.get_tags_selector_data()
|
||||
tags_selector_data['taxonomies_tags'] = taxonomies_tags
|
||||
tags_selector_data['galaxies_tags'] = galaxies_tags
|
||||
dict_tracker['tags'] = custom_tags
|
||||
return render_template("tracker_add.html",
|
||||
dict_tracker=dict_tracker,
|
||||
all_sources=item_basic.get_all_items_sources(r_list=True),
|
||||
tags_selector_data=tags_selector_data,
|
||||
all_yara_files=Tracker.get_all_default_yara_files())
|
||||
|
||||
@hunters.route('/tracker/delete', methods=['GET'])
|
||||
@login_required
|
||||
|
@ -234,7 +338,31 @@ def tracker_delete():
|
|||
if res[1] != 200:
|
||||
return create_json_response(res[0], res[1])
|
||||
else:
|
||||
return redirect(url_for('hunter.tracked_menu'))
|
||||
return redirect(url_for('hunters.trackers_dashboard'))
|
||||
|
||||
|
||||
@hunters.route("/tracker/graph/json", methods=['GET'])
|
||||
@login_required
|
||||
@login_read_only
|
||||
def get_json_tracker_graph():
|
||||
user_id = current_user.get_id()
|
||||
tracker_uuid = request.args.get('uuid')
|
||||
res = Tracker.api_check_tracker_acl(tracker_uuid, user_id)
|
||||
if res:
|
||||
return create_json_response(res[0], res[1])
|
||||
|
||||
date_from = request.args.get('date_from')
|
||||
date_to = request.args.get('date_to')
|
||||
|
||||
if date_from:
|
||||
date_from = date_from.replace('-', '')
|
||||
if date_to:
|
||||
date_to = date_to.replace('-', '')
|
||||
if date_from and date_to:
|
||||
res = Tracker.get_trackers_graph_by_day([tracker_uuid], date_from=date_from, date_to=date_to)
|
||||
else:
|
||||
res = Tracker.get_trackers_graph_by_day([tracker_uuid])
|
||||
return jsonify(res)
|
||||
|
||||
|
||||
####################
|
||||
|
|
|
@ -1,219 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*-coding:UTF-8 -*
|
||||
|
||||
'''
|
||||
Flask functions and routes for tracked items
|
||||
'''
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import flask
|
||||
from flask import Flask, render_template, jsonify, request, Blueprint, url_for, redirect, Response, escape
|
||||
|
||||
from Role_Manager import login_admin, login_analyst, login_read_only
|
||||
from flask_login import login_required, current_user
|
||||
|
||||
sys.path.append(os.environ['AIL_BIN'])
|
||||
##################################
|
||||
# Import Project packages
|
||||
##################################
|
||||
from lib.objects import ail_objects
|
||||
from lib import item_basic
|
||||
from lib import Tracker
|
||||
from lib import Tag
|
||||
from packages import Date
|
||||
|
||||
|
||||
# ============ VARIABLES ============
|
||||
import Flask_config
|
||||
|
||||
app = Flask_config.app
|
||||
baseUrl = Flask_config.baseUrl
|
||||
bootstrap_label = Flask_config.bootstrap_label
|
||||
|
||||
hunter = Blueprint('hunter', __name__, template_folder='templates')
|
||||
|
||||
# ============ FUNCTIONS ============
|
||||
|
||||
def create_json_response(data, status_code):
|
||||
return Response(json.dumps(data, indent=2, sort_keys=True), mimetype='application/json'), status_code
|
||||
|
||||
# ============ ROUTES ============
|
||||
|
||||
@hunter.route("/tracker/edit", methods=['GET', 'POST'])
|
||||
@login_required
|
||||
@login_analyst
|
||||
def edit_tracked_menu():
|
||||
user_id = current_user.get_id()
|
||||
tracker_uuid = request.args.get('uuid', None)
|
||||
|
||||
res = Tracker.api_is_allowed_to_edit_tracker(tracker_uuid, user_id) # check if is author or admin
|
||||
if res[1] != 200: # invalid access
|
||||
return Response(json.dumps(res[0], indent=2, sort_keys=True), mimetype='application/json'), res[1]
|
||||
|
||||
tracker = Tracker.Tracker(tracker_uuid)
|
||||
dict_tracker = tracker.get_meta(options={'description', 'level', 'mails', 'sources', 'tags', 'user', 'webhook'})
|
||||
dict_tracker['tags'] = ' '.join(dict_tracker['tags'])
|
||||
dict_tracker['mails'] = ' '.join(dict_tracker['mails'])
|
||||
|
||||
if dict_tracker['type'] == 'set':
|
||||
dict_tracker['tracker'], dict_tracker['nb_words'] = dict_tracker['tracker'].split(';')
|
||||
dict_tracker['tracker'] = dict_tracker['tracker'].replace(',', ' ')
|
||||
elif dict_tracker['type'] == 'yara': #is_valid_default_yara_rule
|
||||
if Tracker.is_default_yara_rule(dict_tracker['tracker']):
|
||||
dict_tracker['yara_file'] = dict_tracker['tracker'].split('/')
|
||||
dict_tracker['yara_file'] = dict_tracker['yara_file'][-2] + '/' + dict_tracker['yara_file'][-1]
|
||||
dict_tracker['content'] = None
|
||||
else:
|
||||
dict_tracker['yara_file'] = None
|
||||
dict_tracker['content'] = Tracker.get_yara_rule_content(dict_tracker['tracker'])
|
||||
|
||||
return render_template("edit_tracker.html", dict_tracker=dict_tracker,
|
||||
all_sources=item_basic.get_all_items_sources(r_list=True),
|
||||
all_yara_files=Tracker.get_all_default_yara_files())
|
||||
|
||||
## TO EDIT
|
||||
# word
|
||||
# set of word + nb words
|
||||
# regex
|
||||
# yara custom
|
||||
# yara default ???? => allow edit ?
|
||||
|
||||
#### EDIT SHow Trackers ??????????????????????????????????????????????????
|
||||
|
||||
@hunter.route("/tracker/show_tracker")
|
||||
@login_required
|
||||
@login_read_only
|
||||
def show_tracker():
|
||||
user_id = current_user.get_id()
|
||||
tracker_uuid = request.args.get('uuid', None)
|
||||
res = Tracker.api_is_allowed_to_edit_tracker(tracker_uuid, user_id)
|
||||
if res[1] != 200: # invalid access
|
||||
return Response(json.dumps(res[0], indent=2, sort_keys=True), mimetype='application/json'), res[1]
|
||||
|
||||
date_from = request.args.get('date_from')
|
||||
date_to = request.args.get('date_to')
|
||||
|
||||
if date_from:
|
||||
date_from = date_from.replace('-', '')
|
||||
if date_to:
|
||||
date_to = date_to.replace('-', '')
|
||||
|
||||
tracker = Tracker.Tracker(tracker_uuid)
|
||||
meta = tracker.get_meta(options={'description', 'level', 'mails', 'filters', 'sparkline', 'tags',
|
||||
'user', 'webhook'})
|
||||
|
||||
if meta['type'] == 'yara':
|
||||
yara_rule_content = Tracker.get_yara_rule_content(meta['tracked'])
|
||||
else:
|
||||
yara_rule_content = None
|
||||
|
||||
if meta['type'] == 'typosquatting':
|
||||
typo_squatting = Tracker.get_tracked_typosquatting_domains(meta['tracked'])
|
||||
sorted(typo_squatting)
|
||||
else:
|
||||
typo_squatting = set()
|
||||
|
||||
if date_from:
|
||||
date_from, date_to = Date.sanitise_daterange(meta['first_seen'], meta['last_seen'])
|
||||
objs = tracker.get_objs_by_daterange(date_from, date_to)
|
||||
meta['objs'] = ail_objects.get_objects_meta(objs, flask_context=True)
|
||||
else:
|
||||
date_from = ''
|
||||
date_to = ''
|
||||
meta['objs'] = []
|
||||
|
||||
meta['date_from'] = date_from
|
||||
meta['date_to'] = date_to
|
||||
print(meta['filters'])
|
||||
meta['item_sources'] = sorted(meta['filters'].get('item', {}).get('sources', []))
|
||||
# meta['filters'] = json.dumps(meta['filters'], indent=4)
|
||||
|
||||
return render_template("showTracker.html", tracker_metadata=meta,
|
||||
yara_rule_content=yara_rule_content,
|
||||
typo_squatting=typo_squatting,
|
||||
bootstrap_label=bootstrap_label)
|
||||
|
||||
@hunter.route("/tracker/update_tracker_description", methods=['POST'])
|
||||
@login_required
|
||||
@login_analyst
|
||||
def update_tracker_description():
|
||||
user_id = current_user.get_id()
|
||||
term_uuid = request.form.get('uuid')
|
||||
res = Tracker.api_is_allowed_to_edit_tracker(term_uuid, user_id)
|
||||
if res[1] != 200: # invalid access
|
||||
return Response(json.dumps(res[0], indent=2, sort_keys=True), mimetype='application/json'), res[1]
|
||||
description = escape( str(request.form.get('description', '')) )
|
||||
Term.replace_tracker_description(term_uuid, description)
|
||||
return redirect(url_for('hunter.show_tracker', uuid=term_uuid))
|
||||
|
||||
@hunter.route("/tracker/update_tracker_tags", methods=['POST'])
|
||||
@login_required
|
||||
@login_analyst
|
||||
def update_tracker_tags():
|
||||
user_id = current_user.get_id()
|
||||
term_uuid = request.form.get('uuid')
|
||||
res = Tracker.api_is_allowed_to_edit_tracker(term_uuid, user_id)
|
||||
if res[1] != 200: # invalid access
|
||||
return Response(json.dumps(res[0], indent=2, sort_keys=True), mimetype='application/json'), res[1]
|
||||
tags = request.form.get('tags')
|
||||
if tags:
|
||||
tags = tags.split()
|
||||
else:
|
||||
tags = []
|
||||
Term.replace_tracked_term_tags(term_uuid, tags)
|
||||
return redirect(url_for('hunter.show_tracker', uuid=term_uuid))
|
||||
|
||||
@hunter.route("/tracker/update_tracker_mails", methods=['POST'])
|
||||
@login_required
|
||||
@login_analyst
|
||||
def update_tracker_mails():
|
||||
user_id = current_user.get_id()
|
||||
term_uuid = request.form.get('uuid')
|
||||
res = Tracker.api_is_allowed_to_edit_tracker(term_uuid, user_id)
|
||||
if res[1] != 200: # invalid access
|
||||
return Response(json.dumps(res[0], indent=2, sort_keys=True), mimetype='application/json'), res[1]
|
||||
mails = request.form.get('mails')
|
||||
if mails:
|
||||
mails = mails.split()
|
||||
else:
|
||||
mails = []
|
||||
res = Term.replace_tracked_term_mails(term_uuid, mails)
|
||||
if res: # invalid mail
|
||||
return Response(json.dumps(res[0], indent=2, sort_keys=True), mimetype='application/json'), res[1]
|
||||
return redirect(url_for('hunter.show_tracker', uuid=term_uuid))
|
||||
|
||||
@hunter.route("/tracker/get_json_tracker_stats", methods=['GET'])
|
||||
@login_required
|
||||
@login_read_only
|
||||
def get_json_tracker_stats():
|
||||
user_id = current_user.get_id()
|
||||
tracker_uuid = request.args.get('uuid')
|
||||
res = Tracker.api_check_tracker_acl(tracker_uuid, user_id)
|
||||
if res:
|
||||
return create_json_response(res[0], res[1])
|
||||
|
||||
date_from = request.args.get('date_from')
|
||||
date_to = request.args.get('date_to')
|
||||
|
||||
if date_from:
|
||||
date_from = date_from.replace('-', '')
|
||||
if date_to:
|
||||
date_to = date_to.replace('-', '')
|
||||
if date_from and date_to:
|
||||
res = Tracker.get_trackers_graph_by_day([tracker_uuid], date_from=date_from, date_to=date_to)
|
||||
else:
|
||||
res = Tracker.get_trackers_graph_by_day([tracker_uuid])
|
||||
return jsonify(res)
|
||||
|
||||
@hunter.route("/tracker/yara/default_rule/content", methods=['GET'])
|
||||
@login_required
|
||||
@login_read_only
|
||||
def get_default_yara_rule_content():
|
||||
default_yara_rule = request.args.get('rule_name')
|
||||
res = Tracker.api_get_default_rule_content(default_yara_rule)
|
||||
return Response(json.dumps(res[0], indent=2, sort_keys=True), mimetype='application/json'), res[1]
|
||||
|
||||
|
||||
# ========= REGISTRATION =========
|
||||
app.register_blueprint(hunter, url_prefix=baseUrl)
|
|
@ -1,440 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
|
||||
<title>AIL Framework - AIL</title>
|
||||
<link rel="icon" href="{{ url_for('static', filename='image/ail-icon.png') }}">
|
||||
|
||||
<!-- Core CSS -->
|
||||
<link href="{{ url_for('static', filename='css/bootstrap4.min.css') }}" rel="stylesheet">
|
||||
<link href="{{ url_for('static', filename='css/font-awesome.min.css') }}" rel="stylesheet">
|
||||
<link href="{{ url_for('static', filename='css/daterangepicker.min.css') }}" rel="stylesheet">
|
||||
<link href="{{ url_for('static', filename='css/dataTables.bootstrap.min.css') }}" rel="stylesheet">
|
||||
|
||||
<!-- JS -->
|
||||
<script src="{{ url_for('static', filename='js/jquery.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/popper.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/bootstrap4.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/jquery.dataTables.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/dataTables.bootstrap.min.js') }}"></script>
|
||||
<script language="javascript" src="{{ url_for('static', filename='js/d3.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/d3/sparklines.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/d3/graphlinesgroup.js') }}"></script>
|
||||
<script language="javascript" src="{{ url_for('static', filename='js/moment.min.js') }}"></script>
|
||||
<script language="javascript" src="{{ url_for('static', filename='js/jquery.daterangepicker.min.js') }}"></script>
|
||||
|
||||
<style>
|
||||
.btn-link {
|
||||
color: #17a2b8
|
||||
}
|
||||
|
||||
.btn-link:hover {
|
||||
color: blue;
|
||||
}
|
||||
|
||||
.mouse_pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
{% include 'nav_bar.html' %}
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
|
||||
{% include 'hunter/menu_sidebar.html' %}
|
||||
|
||||
<div class="col-12 col-lg-10" id="core_content">
|
||||
|
||||
<div class="card my-3">
|
||||
<div class="card-header" style="background-color:#d9edf7;font-size: 15px">
|
||||
<h4 class="text-secondary">
|
||||
{% if tracker_metadata['description'] %}
|
||||
{{ tracker_metadata['description'] }}
|
||||
{% endif %}
|
||||
<span class="btn-interaction btn-link h6 mouse_pointer" title="Edit Tracker description"
|
||||
onclick="edit_description();"><i class="fas fa-pencil-alt"></i></span>
|
||||
</h4>
|
||||
<div class="text-info">
|
||||
{{ tracker_metadata['uuid'] }}
|
||||
</div>
|
||||
<ul class="list-group mb-2">
|
||||
<li class="list-group-item py-0">
|
||||
<div class="row">
|
||||
<div class="col-md-10">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Type</th>
|
||||
<th>Tracker</th>
|
||||
<th>Created</th>
|
||||
<th>Access Level</th>
|
||||
<th>Created by</th>
|
||||
<th>First seen</th>
|
||||
<th>Last seen</th>
|
||||
{% if tracker_metadata['webhook'] %}
|
||||
<th>Webhook</th>
|
||||
{% endif %}
|
||||
<th>Tags <span class="btn-link btn-interaction mouse_pointer"
|
||||
title="Edit Tags List" onclick="edit_tags();"><i
|
||||
class="fas fa-pencil-alt" style="color:Red;"></i></span></th>
|
||||
<th>Email <span class="btn-link btn-interaction mouse_pointer"
|
||||
title="Edit Email List" onclick="edit_mails();"><i
|
||||
class="fas fa-pencil-alt" style="color:Red;"></i></span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{{ tracker_metadata['type'] }}</td>
|
||||
{% if tracker_metadata['type'] == 'typosquatting' %}
|
||||
<td>
|
||||
<a class="btn btn-primary" data-toggle="collapse" href="#collapseTypo" role="button" aria-expanded="false" aria-controls="collapseTypo">
|
||||
{{ tracker_metadata['tracked'].split(",")[0] }}
|
||||
</a>
|
||||
<div class="collapse" id="collapseTypo">
|
||||
<div class="card card-body">
|
||||
{% if typo_squatting %}
|
||||
{% for typo in typo_squatting %}
|
||||
{{typo}}
|
||||
<br/>
|
||||
{% endfor %}
|
||||
{%endif%}
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
{% else %}
|
||||
<td>{{ tracker_metadata['tracked'] }}</td>
|
||||
{% endif %}
|
||||
<td>{{ tracker_metadata['date'][0:4] }}/{{ tracker_metadata['date'][4:6] }}/{{ tracker_metadata['date'][6:8] }}</td>
|
||||
<td>
|
||||
{% if tracker_metadata['level'] == 0 %}
|
||||
Private
|
||||
{% else %}
|
||||
Global
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ tracker_metadata['user'] }}</td>
|
||||
<td>
|
||||
{% if tracker_metadata['first_seen'] %}
|
||||
{{ tracker_metadata['first_seen'][0:4] }}/{{ tracker_metadata['first_seen'][4:6] }}/{{ tracker_metadata['first_seen'][6:8] }}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if tracker_metadata['last_seen'] %}
|
||||
{{ tracker_metadata['last_seen'][0:4] }}/{{ tracker_metadata['last_seen'][4:6] }}/{{ tracker_metadata['last_seen'][6:8] }}
|
||||
{% endif %}
|
||||
</td>
|
||||
{% if tracker_metadata['webhook'] %}
|
||||
<td>
|
||||
Turned ON
|
||||
</td>
|
||||
{% endif %}
|
||||
<td>
|
||||
{% for tag in tracker_metadata['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] }}">{{ tag }}</span>
|
||||
</a>
|
||||
{% endfor %}
|
||||
|
||||
</td>
|
||||
<td>
|
||||
{% for mail in tracker_metadata['mails'] %}
|
||||
{{ mail }}<br>
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="col-md-1">
|
||||
<div id="sparkline"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h6>Filters:</h6>
|
||||
{% if tracker_metadata['filters'] %}
|
||||
<pre>{{ tracker_metadata['filters'] }}</pre>
|
||||
{% else %}
|
||||
<span class="badge badge-secondary">No Filters</span><br>
|
||||
{% endif %}
|
||||
|
||||
{# <h6>Sources:</h6>#}
|
||||
{# {% if tracker_metadata['sources'] %}#}
|
||||
{# {% for sources in tracker_metadata['sources'] %}#}
|
||||
{# <span class="badge badge-secondary">{{ sources }}</span><br>#}
|
||||
{# {% endfor %}#}
|
||||
{# {% else %}#}
|
||||
{# <span class="badge badge-secondary">All Sources</span><br>#}
|
||||
{# {% endif %}#}
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div id="div_edit_description">
|
||||
<form action="{{ url_for('hunter.update_tracker_description') }}" method='post'>
|
||||
<input name="uuid" type="text" value="{{ tracker_metadata['uuid'] }}" hidden>
|
||||
<div>Update this tracker description:</div>
|
||||
<div class="input-group mb-2 mr-sm-2">
|
||||
<div class="input-group-prepend">
|
||||
<div class="input-group-text"><i class="fas fa-pencil-alt"></i></div>
|
||||
</div>
|
||||
<input id="description" name="description" class="form-control"
|
||||
placeholder="Tracker Description" type="text"
|
||||
value="
|
||||
{% if tracker_metadata['description'] %}{{ tracker_metadata['description'] }}{% endif %}">
|
||||
</div>
|
||||
|
||||
<button class="btn btn-info">
|
||||
<i class="fas fa-pencil-alt"></i> Edit Description
|
||||
</button>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="div_edit_tags">
|
||||
<form action="{{ url_for('hunter.update_tracker_tags') }}" method='post'>
|
||||
<input name="uuid" type="text" value="{{ tracker_metadata['uuid'] }}" hidden>
|
||||
<div>All Tags added for this tracker, space separated:</div>
|
||||
<div class="input-group mb-2 mr-sm-2">
|
||||
<div class="input-group-prepend">
|
||||
<div class="input-group-text"><i class="fas fa-tag"></i></div>
|
||||
</div>
|
||||
<input id="tags" name="tags" class="form-control"
|
||||
placeholder="Tags (optional, space separated)" type="text"
|
||||
value="{% for tag in tracker_metadata['tags'] %}{{ tag }} {% endfor %}">
|
||||
</div>
|
||||
|
||||
<button class="btn btn-info">
|
||||
<i class="fas fa-pencil-alt"></i> Edit Tags
|
||||
</button>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="div_edit_mails">
|
||||
<form action="{{ url_for('hunter.update_tracker_mails') }}" method='post'>
|
||||
<input name="uuid" type="text" value="{{ tracker_metadata['uuid'] }}" hidden>
|
||||
<div>All E-Mails to Notify for this tracker, space separated:</div>
|
||||
<div class="input-group mb-2 mr-sm-2">
|
||||
<div class="input-group-prepend">
|
||||
<div class="input-group-text"><i class="fas fa-at"></i></div>
|
||||
</div>
|
||||
<input id="mails" name="mails" class="form-control"
|
||||
placeholder="E-Mails Notification (optional, space separated)" type="text"
|
||||
value="{% for mail in tracker_metadata['mails'] %}{{ mail }} {% endfor %}">
|
||||
</div>
|
||||
|
||||
<button class="btn btn-info">
|
||||
<i class="fas fa-pencil-alt"></i> Edit Email Notification
|
||||
</button>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-row-reverse">
|
||||
<a href="{{ url_for('hunters.tracker_delete') }}?uuid={{ tracker_metadata['uuid'] }}"
|
||||
style="font-size: 15px">
|
||||
<button class='btn btn-danger'><i class="fas fa-trash-alt"></i></button>
|
||||
</a>
|
||||
<a href="{{ url_for('hunter.edit_tracked_menu') }}?uuid={{ tracker_metadata['uuid'] }}"
|
||||
class="mx-2" style="font-size: 15px">
|
||||
<button class='btn btn-info'>Edit Tracker <i class="fas fa-pencil-alt"></i></button>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{% if yara_rule_content %}
|
||||
<p class="my-0"></br></br>
|
||||
<pre class="border bg-light">{{ yara_rule_content }}</pre></p>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="graphline" class="text-center"></div>
|
||||
|
||||
<div class="card mb-5 mt-1">
|
||||
<div class="card-body">
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-6">
|
||||
<div class="input-group" id="date-range-from">
|
||||
<div class="input-group-prepend"><span class="input-group-text"><i
|
||||
class="far fa-calendar-alt" aria-hidden="true"></i></span></div>
|
||||
<input class="form-control" id="date-range-from-input" placeholder="yyyy-mm-dd"
|
||||
name="date_from" autocomplete="off"
|
||||
{% if tracker_metadata['date_from'] %}value="{{ tracker_metadata['date_from'][0:4] }}-{{ tracker_metadata['date_from'][4:6] }}-{{ tracker_metadata['date_from'][6:8] }}"
|
||||
{% elif tracker_metadata['first_seen'] %}value="{{ tracker_metadata['first_seen'][0:4] }}-{{ tracker_metadata['first_seen'][4:6] }}-{{ tracker_metadata['first_seen'][6:8] }}"
|
||||
{% endif %}>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="input-group" id="date-range-to">
|
||||
<div class="input-group-prepend"><span class="input-group-text"><i
|
||||
class="far fa-calendar-alt" aria-hidden="true"></i></span></div>
|
||||
<input class="form-control" id="date-range-to-input" placeholder="yyyy-mm-dd"
|
||||
name="date_to" autocomplete="off"
|
||||
{% if tracker_metadata['date_to'] %}value="{{ tracker_metadata['date_to'][0:4] }}-{{ tracker_metadata['date_to'][4:6] }}-{{ tracker_metadata['date_to'][6:8] }}"
|
||||
{% elif tracker_metadata['last_seen'] %}value="{{ tracker_metadata['last_seen'][0:4] }}-{{ tracker_metadata['last_seen'][4:6] }}-{{ tracker_metadata['last_seen'][6:8] }}"
|
||||
{% endif %}>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-info" type="button" id="button-search-tags" onclick="getItems();">
|
||||
<i class="fas fa-search"></i> Search Tracked Items
|
||||
</button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if tracker_metadata['objs'] %}
|
||||
<div class="mt-4">
|
||||
<table id="myTable_" class="table table-striped border-primary">
|
||||
<thead class="bg-dark text-white">
|
||||
<tr>
|
||||
<th>Type</th>
|
||||
<th></th>
|
||||
<th>Id</th>
|
||||
<th>Tags</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody style="font-size: 15px;">
|
||||
{% for object in tracker_metadata['objs'] %}
|
||||
<tr class="border-color: blue;">
|
||||
<td>
|
||||
{% with style=object['icon']['style'], icon=object['icon']['icon'] , color=object['icon']['color'] %}
|
||||
{% include 'objects/obj_svg_block.html' %}
|
||||
{% endwith %}
|
||||
{{ object['type']}}
|
||||
</td>
|
||||
<td>
|
||||
{% if object['subtype'] %}
|
||||
{{ object['subtype']}}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ object['link'] }}">
|
||||
{{ object['id']}}
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
{% for tag in object['tags'] %}
|
||||
<span class="badge badge-{{ bootstrap_label[loop.index0 % 5] }} pull-left">{{ tag }}</span>
|
||||
{% endfor %}
|
||||
</td>
|
||||
<td class="text-right">
|
||||
{# <a href="{{ url_for('investigations_b.unregister_investigation') }}?uuid={{ tracker_metadata['uuid']}}&type={{ object['type'] }}&subtype={{ object['subtype']}}&id={{ object['id']}}">#}
|
||||
{# <button type="button" class="btn btn-danger"><i class="fas fa-trash-alt"></i></button>#}
|
||||
{# </a>#}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
$('#div_edit_mails').hide();
|
||||
$('#div_edit_tags').hide();
|
||||
$('#div_edit_description').hide();
|
||||
$("#page-Tracker").addClass("active");
|
||||
|
||||
$('#date-range-from').dateRangePicker({
|
||||
separator: ' to ',
|
||||
getValue: function () {
|
||||
if ($('#date-range-from-input').val() && $('#date-range-to-input').val())
|
||||
return $('#date-range-from-input').val() + ' to ' + $('#date-range-to-input').val();
|
||||
else
|
||||
return '';
|
||||
},
|
||||
setValue: function (s, s1, s2) {
|
||||
$('#date-range-from-input').val(s1);
|
||||
$('#date-range-to-input').val(s2);
|
||||
}
|
||||
});
|
||||
$('#date-range-to').dateRangePicker({
|
||||
separator: ' to ',
|
||||
getValue: function () {
|
||||
if ($('#date-range-from-input').val() && $('#date-range-to-input').val())
|
||||
return $('#date-range-from-input').val() + ' to ' + $('#date-range-to-input').val();
|
||||
else
|
||||
return '';
|
||||
},
|
||||
setValue: function (s, s1, s2) {
|
||||
$('#date-range-from-input').val(s1);
|
||||
$('#date-range-to-input').val(s2);
|
||||
}
|
||||
});
|
||||
|
||||
$('#myTable_').DataTable({
|
||||
"aLengthMenu": [[5, 10, 15, -1], [5, 10, 15, "All"]],
|
||||
"iDisplayLength": 10,
|
||||
"order": [[0, "asc"]]
|
||||
});
|
||||
|
||||
sparkline("sparkline", {{ tracker_metadata['sparkline'] }}, {});
|
||||
let div_width = $("#graphline").width();
|
||||
$.getJSON("{{ url_for('hunter.get_json_tracker_stats') }}?uuid={{ tracker_metadata['uuid'] }}{%if tracker_metadata['date_from']%}&date_from={{ tracker_metadata['date_from'] }}{%endif%}{%if tracker_metadata['date_to']%}&date_to={{ tracker_metadata['date_to'] }}{%endif%}",
|
||||
function (data) {
|
||||
multilines_group("graphline", data, {"width": div_width});
|
||||
}
|
||||
);
|
||||
|
||||
});
|
||||
|
||||
function toggle_sidebar() {
|
||||
if ($('#nav_menu').is(':visible')) {
|
||||
$('#nav_menu').hide();
|
||||
$('#side_menu').removeClass('border-right')
|
||||
$('#side_menu').removeClass('col-lg-2')
|
||||
$('#core_content').removeClass('col-lg-10')
|
||||
} else {
|
||||
$('#nav_menu').show();
|
||||
$('#side_menu').addClass('border-right')
|
||||
$('#side_menu').addClass('col-lg-2')
|
||||
$('#core_content').addClass('col-lg-10')
|
||||
}
|
||||
}
|
||||
|
||||
function edit_tags() {
|
||||
$('#div_edit_mails').hide();
|
||||
$('#div_edit_description').hide();
|
||||
$('#div_edit_tags').show();
|
||||
}
|
||||
|
||||
function edit_mails() {
|
||||
$('#div_edit_tags').hide();
|
||||
$('#div_edit_description').hide();
|
||||
$('#div_edit_mails').show();
|
||||
}
|
||||
|
||||
function edit_description() {
|
||||
$('#div_edit_tags').hide();
|
||||
$('#div_edit_mails').hide();
|
||||
$('#div_edit_description').show();
|
||||
}
|
||||
|
||||
function getItems() {
|
||||
var date_from = $('#date-range-from-input').val();
|
||||
var date_to = $('#date-range-to-input').val();
|
||||
window.location.replace("{{ url_for('hunter.show_tracker') }}?uuid={{ tracker_metadata['uuid'] }}&date_from=" + date_from + "&date_to=" + date_to);
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -307,7 +307,7 @@ function get_default_rule_content(selector){
|
|||
if (yara_name === "Select a default rule") {
|
||||
jQuery("#default_yara_rule_content").text("")
|
||||
} else {
|
||||
$.getJSON("{{ url_for('hunter.get_default_yara_rule_content') }}?rule_name=" + yara_name,
|
||||
$.getJSON("{{ url_for('hunters.get_default_yara_rule_content') }}?rule=" + yara_name,
|
||||
function(data) {
|
||||
jQuery("#default_yara_rule_content").text(data['content'])
|
||||
});
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
</div>
|
||||
<div class="card-body">
|
||||
|
||||
<form action="{{ url_for('hunters.add_tracked_menu') }}" method='post'>
|
||||
<form action="{%if dict_tracker%}{{ url_for('hunters.tracker_edit') }}{%else%}{{ url_for('hunters.add_tracked_menu') }}{%endif%}" method='post'>
|
||||
{%if dict_tracker%}
|
||||
<input id="tracker_uuid" name="tracker_uuid" class="form-control" type="text" value="{{dict_tracker['uuid']}}" hidden>
|
||||
{%endif%}
|
||||
|
@ -46,7 +46,7 @@
|
|||
<div class="input-group-prepend">
|
||||
<div class="input-group-text bg-secondary text-white"><i class="fas fa-at"></i></div>
|
||||
</div>
|
||||
<input id="mails" name="mails" class="form-control" placeholder="E-Mails Notification (optional, space separated)" type="text" {%if dict_tracker%}{%if dict_tracker['mails']%}value="{{dict_tracker['mails']}}"{%endif%}{%endif%}>
|
||||
<input id="mails" name="mails" class="form-control" placeholder="E-Mails Notification (optional, space separated)" type="text" {%if dict_tracker%}{%if dict_tracker['mails']%}value="{%for mail in dict_tracker['mails'] %}{{mail}} {%endfor%}"{%endif%}{%endif%}>
|
||||
</div>
|
||||
<div class="input-group mb-2 mr-sm-2">
|
||||
<div class="input-group-prepend">
|
||||
|
@ -191,7 +191,7 @@
|
|||
<div class="input-group-prepend">
|
||||
<div class="input-group-text bg-danger text-white"><i class="fas fa-tag"></i></div>
|
||||
</div>
|
||||
<input id="tags" name="tags" class="form-control" placeholder="Custom Tags (optional, space separated)" type="text" {%if dict_tracker%}{%if dict_tracker['tags']%}value="{{dict_tracker['tags']}}"{%endif%}{%endif%}>
|
||||
<input id="tags" name="tags" class="form-control" placeholder="Custom Tags (optional, space separated)" type="text" {%if dict_tracker%}{%if dict_tracker['tags']%}value="{%for tag in dict_tracker['tags']%}{{tag}} {%endfor%}"{%endif%}{%endif%}>
|
||||
</div>
|
||||
{% include 'tags/block_tags_selector.html' %}
|
||||
</div>
|
||||
|
@ -224,7 +224,7 @@
|
|||
|
||||
<div class="row" id="simple_input">
|
||||
<div class="col-12 col-lg-10">
|
||||
<input id="tracker" name="tracker" class="form-control" placeholder="Terms to track (space separated)" type="text" {%if dict_tracker%}{%if dict_tracker['tracker']!='yara'%}value="{{dict_tracker['tracker']}}"{%endif%}{%endif%}>
|
||||
<input id="tracker" name="tracker" class="form-control" placeholder="Terms to track (space separated)" type="text" {%if dict_tracker%}{%if dict_tracker['type'] != 'yara' and dict_tracker['type'] != 'typosquatting'%}value="{{dict_tracker['tracked']}}"{%endif%}{%endif%}>
|
||||
</div>
|
||||
<div class="col-12 col-lg-2">
|
||||
<input type="number" id="nb_word" name="nb_word" name="quantity" min="1" placeholder="Nb of keywords" {%if dict_tracker%}{%if dict_tracker['nb_words']%}value="{{dict_tracker['nb_words']}}"{%endif%}{%endif%}>
|
||||
|
@ -291,7 +291,7 @@ $(document).ready(function(){
|
|||
|
||||
sources_item = $('#sources_item').tagSuggest({
|
||||
data: {{all_sources|safe}},
|
||||
{%if dict_tracker%}{%if dict_tracker['item_sources']%}value: {{dict_tracker['item_sources']|safe}},{%endif%}{%endif%}
|
||||
{%if dict_tracker%}{%if dict_tracker['filters']%}{%if dict_tracker['filters']['item']%}{%if dict_tracker['filters']['item']['sources']%}value: {{dict_tracker['filters']['item']['sources']|safe}},{%endif%}{%endif%}{%endif%}{%endif%}
|
||||
sortOrder: 'name',
|
||||
maxDropHeight: 200,
|
||||
name: 'sources_item',
|
||||
|
@ -335,9 +335,10 @@ $(document).ready(function(){
|
|||
|
||||
{%if dict_tracker%}
|
||||
$('#tracker_type').val('{{dict_tracker['type']}}').change();
|
||||
|
||||
{%if dict_tracker['type']=='yara' and dict_tracker['yara_file']%}
|
||||
$('#yara_default_rule').val('{{dict_tracker['yara_file']}}').change();
|
||||
{%if dict_tracker['type']=='yara'%}
|
||||
{% if dict_tracker['tracked'][0:21] == 'ail-yara-rules/rules/' %}
|
||||
$('#yara_default_rule').val('{{dict_tracker['tracked'][21:]}}').change();
|
||||
{%endif%}
|
||||
{%endif%}
|
||||
{%endif%}
|
||||
|
||||
|
@ -386,7 +387,7 @@ function get_default_rule_content(selector){
|
|||
if (yara_name === "Select a default rule") {
|
||||
jQuery("#default_yara_rule_content").text("")
|
||||
} else {
|
||||
$.getJSON("{{ url_for('hunter.get_default_yara_rule_content') }}?rule_name=" + yara_name,
|
||||
$.getJSON("{{ url_for('hunters.get_default_yara_rule_content') }}?rule=" + yara_name,
|
||||
function(data) {
|
||||
jQuery("#default_yara_rule_content").text(data['content'])
|
||||
});
|
||||
|
|
401
var/www/templates/hunter/tracker_show.html
Normal file
401
var/www/templates/hunter/tracker_show.html
Normal file
|
@ -0,0 +1,401 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
|
||||
<title>AIL Framework - AIL</title>
|
||||
<link rel="icon" href="{{ url_for('static', filename='image/ail-icon.png') }}">
|
||||
|
||||
<!-- Core CSS -->
|
||||
<link href="{{ url_for('static', filename='css/bootstrap4.min.css') }}" rel="stylesheet">
|
||||
<link href="{{ url_for('static', filename='css/font-awesome.min.css') }}" rel="stylesheet">
|
||||
<link href="{{ url_for('static', filename='css/daterangepicker.min.css') }}" rel="stylesheet">
|
||||
<link href="{{ url_for('static', filename='css/dataTables.bootstrap.min.css') }}" rel="stylesheet">
|
||||
|
||||
<!-- JS -->
|
||||
<script src="{{ url_for('static', filename='js/jquery.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/popper.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/bootstrap4.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/jquery.dataTables.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/dataTables.bootstrap.min.js') }}"></script>
|
||||
<script language="javascript" src="{{ url_for('static', filename='js/d3.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/d3/sparklines.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/d3/graphlinesgroup.js') }}"></script>
|
||||
<script language="javascript" src="{{ url_for('static', filename='js/moment.min.js') }}"></script>
|
||||
<script language="javascript" src="{{ url_for('static', filename='js/jquery.daterangepicker.min.js') }}"></script>
|
||||
|
||||
<style>
|
||||
.btn-link {
|
||||
color: #17a2b8
|
||||
}
|
||||
|
||||
.btn-link:hover {
|
||||
color: blue;
|
||||
}
|
||||
|
||||
.mouse_pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
{% include 'nav_bar.html' %}
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
{% include 'hunter/menu_sidebar.html' %}
|
||||
<div class="col-12 col-lg-10" id="core_content">
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-4">
|
||||
<div class="card my-2">
|
||||
<div class="card-header bg-dark text-white">
|
||||
<span class="badge badge-light lex-row-reverse float-right">
|
||||
<span id="sparkline"></span>
|
||||
</span>
|
||||
<h4 class="card-title">
|
||||
{% if meta['description'] %}
|
||||
{{ meta['description'] }}
|
||||
{% else %}
|
||||
{{ meta['uuid'] }}
|
||||
{% endif %}
|
||||
</h4>
|
||||
</div>
|
||||
<div class="card-body bg-light pt-2">
|
||||
<table class="table table-borderless">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="text-right"><b>Type</b></td>
|
||||
<td>
|
||||
{% if meta['type'] == 'word' %}
|
||||
<i class="fas fa-font"></i>
|
||||
{% elif meta['type'] == 'set' %}
|
||||
<i class="fas fa-layer-group"></i>
|
||||
{% elif meta['type'] == 'regex' %}
|
||||
<i class="fas fa-compass"></i>
|
||||
{% elif meta['type'] == 'typosquatting' %}
|
||||
<i class="fas fa-clone"></i>
|
||||
{% elif meta['type'] == 'yara' %}
|
||||
<span class="bg-danger text-white font-weight-bold" style="font-size: 120%"> { </span>
|
||||
{% endif %}
|
||||
{{ meta['type'] }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-right"><b>Tracked</b></td>
|
||||
<td>
|
||||
{% if meta['type'] == 'typosquatting' %}
|
||||
<a class="btn btn-primary" data-toggle="collapse" href="#collapseTypo" role="button" aria-expanded="false" aria-controls="collapseTypo">
|
||||
{{ meta['tracked'] }}
|
||||
</a>
|
||||
<div class="collapse" id="collapseTypo">
|
||||
<div class="card card-body">
|
||||
{% if typo_squatting %}
|
||||
{% for typo in typo_squatting %}
|
||||
{{typo}}
|
||||
<br/>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
{{ meta['tracked'] }}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-right"><b>Date</b></td>
|
||||
<td>
|
||||
{{meta['date'][0:4]}}/{{meta['date'][4:6]}}/{{meta['date'][6:8]}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-right"><b>Level</b></td>
|
||||
<td>
|
||||
{% if meta['level'] == 0 %}
|
||||
Private
|
||||
{% else %}
|
||||
Global
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-right"><b>Creator</b></td>
|
||||
<td>{{meta['user']}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-right"><b>First Seen</b></td>
|
||||
<td>
|
||||
{% if meta['first_seen'] %}
|
||||
{{ meta['first_seen'][0:4] }} / {{ meta['first_seen'][4:6] }} / {{ meta['first_seen'][6:8] }}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-right"><b>Last Seen</b></td>
|
||||
<td>
|
||||
{% if meta['last_seen'] %}
|
||||
{{ meta['last_seen'][0:4] }} / {{ meta['last_seen'][4:6] }} / {{ meta['last_seen'][6:8] }}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-right"><b>Tags</b></td>
|
||||
<td>
|
||||
{%for tag in meta['tags']%}
|
||||
<span class="badge badge-{{ bootstrap_label[loop.index0 % 5] }}">{{ tag }}</span>
|
||||
{%endfor%}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-right"><b>Mails</b></td>
|
||||
<td>
|
||||
{% for mail in meta['mails'] %}
|
||||
<div>{{ mail }}</div>
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-right"><b>Webhook</b></td>
|
||||
<td>{{meta['webhook']}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-right"><b>Filters</b></td>
|
||||
<td>
|
||||
<div class="">
|
||||
{% if meta['filters'] %}
|
||||
<pre>{{ meta['filters'] }}</pre>
|
||||
{% else %}
|
||||
<span class="badge badge-secondary">No Filters</span><br>
|
||||
{% endif %}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-right"><b>Objects Match</b></td>
|
||||
<td>
|
||||
{%for obj_type in meta['nb_objs']%}
|
||||
<h4><span class="badge badge-{{ bootstrap_label[loop.index0 % 5] }}">
|
||||
{{ obj_type }}
|
||||
<span class="badge badge-light">{{ meta['nb_objs'][obj_type] }}</span>
|
||||
</span></h4>
|
||||
{%endfor%}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="d-flex flex-row-reverse">
|
||||
<a href="{{ url_for('hunters.tracker_delete') }}?uuid={{ meta['uuid'] }}" style="font-size: 15px">
|
||||
<button class='btn btn-danger'><i class="fas fa-trash-alt"></i></button>
|
||||
</a>
|
||||
<a href="{{ url_for('hunters.tracker_edit') }}?uuid={{ meta['uuid'] }}" class="mx-2" style="font-size: 15px">
|
||||
<button class='btn btn-info'>Edit Tracker <i class="fas fa-pencil-alt"></i></button>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-8 mt-1">
|
||||
|
||||
{% if rule_content %}
|
||||
<h5 class="mb-0">Yara Rule:</h5>
|
||||
<p class="my-0">
|
||||
<pre class="border bg-light">{{ rule_content }}</pre>
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
<div class="card mb-5 mt-1">
|
||||
<div class="card-body">
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-6">
|
||||
<div class="input-group" id="date-range-from">
|
||||
<div class="input-group-prepend"><span class="input-group-text"><i
|
||||
class="far fa-calendar-alt" aria-hidden="true"></i></span></div>
|
||||
<input class="form-control" id="date-range-from-input" placeholder="yyyy-mm-dd"
|
||||
name="date_from" autocomplete="off"
|
||||
{% if meta['date_from'] %}value="{{ meta['date_from'][0:4] }}-{{ meta['date_from'][4:6] }}-{{ meta['date_from'][6:8] }}"
|
||||
{% elif meta['first_seen'] %}value="{{ meta['first_seen'][0:4] }}-{{ meta['first_seen'][4:6] }}-{{ meta['first_seen'][6:8] }}"
|
||||
{% endif %}>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="input-group" id="date-range-to">
|
||||
<div class="input-group-prepend"><span class="input-group-text"><i
|
||||
class="far fa-calendar-alt" aria-hidden="true"></i></span></div>
|
||||
<input class="form-control" id="date-range-to-input" placeholder="yyyy-mm-dd"
|
||||
name="date_to" autocomplete="off"
|
||||
{% if meta['date_to'] %}value="{{ meta['date_to'][0:4] }}-{{ meta['date_to'][4:6] }}-{{ meta['date_to'][6:8] }}"
|
||||
{% elif meta['last_seen'] %}value="{{ meta['last_seen'][0:4] }}-{{ meta['last_seen'][4:6] }}-{{ meta['last_seen'][6:8] }}"
|
||||
{% endif %}>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-info" type="button" id="button-search-tags" onclick="getItems();">
|
||||
<i class="fas fa-search"></i> Tracked Objects
|
||||
</button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if meta['objs'] %}
|
||||
<hr>
|
||||
<div class="mt-4">
|
||||
<table id="myTable_" class="table table-striped border-primary">
|
||||
<thead class="bg-dark text-white">
|
||||
<tr>
|
||||
<th>Type</th>
|
||||
<th></th>
|
||||
<th>Id</th>
|
||||
<th>Tags</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody style="font-size: 15px;">
|
||||
{% for object in meta['objs'] %}
|
||||
<tr class="border-color: blue;">
|
||||
<td>
|
||||
{% with style=object['icon']['style'], icon=object['icon']['icon'] , color=object['icon']['color'] %}
|
||||
{% include 'objects/obj_svg_block.html' %}
|
||||
{% endwith %}
|
||||
{{ object['type']}}
|
||||
</td>
|
||||
<td>
|
||||
{% if object['subtype'] %}
|
||||
{{ object['subtype']}}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ object['link'] }}">
|
||||
{{ object['id']}}
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
{% for tag in object['tags'] %}
|
||||
<span class="badge badge-{{ bootstrap_label[loop.index0 % 5] }} pull-left">{{ tag }}</span>
|
||||
{% endfor %}
|
||||
</td>
|
||||
<td class="text-right">
|
||||
{# <a href="{{ url_for('investigations_b.unregister_investigation') }}?uuid={{ meta['uuid']}}&type={{ object['type'] }}&subtype={{ object['subtype']}}&id={{ object['id']}}">#}
|
||||
{# <button type="button" class="btn btn-danger"><i class="fas fa-trash-alt"></i></button>#}
|
||||
{# </a>#}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<hr>
|
||||
{% endif %}
|
||||
|
||||
<div id="graphline" class="text-center mb-4"></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
$('#div_edit_mails').hide();
|
||||
$('#div_edit_tags').hide();
|
||||
$('#div_edit_description').hide();
|
||||
$("#page-Tracker").addClass("active");
|
||||
|
||||
$('#date-range-from').dateRangePicker({
|
||||
separator: ' to ',
|
||||
getValue: function () {
|
||||
if ($('#date-range-from-input').val() && $('#date-range-to-input').val())
|
||||
return $('#date-range-from-input').val() + ' to ' + $('#date-range-to-input').val();
|
||||
else
|
||||
return '';
|
||||
},
|
||||
setValue: function (s, s1, s2) {
|
||||
$('#date-range-from-input').val(s1);
|
||||
$('#date-range-to-input').val(s2);
|
||||
}
|
||||
});
|
||||
$('#date-range-to').dateRangePicker({
|
||||
separator: ' to ',
|
||||
getValue: function () {
|
||||
if ($('#date-range-from-input').val() && $('#date-range-to-input').val())
|
||||
return $('#date-range-from-input').val() + ' to ' + $('#date-range-to-input').val();
|
||||
else
|
||||
return '';
|
||||
},
|
||||
setValue: function (s, s1, s2) {
|
||||
$('#date-range-from-input').val(s1);
|
||||
$('#date-range-to-input').val(s2);
|
||||
}
|
||||
});
|
||||
|
||||
$('#myTable_').DataTable({
|
||||
"aLengthMenu": [[5, 10, 15, -1], [5, 10, 15, "All"]],
|
||||
"iDisplayLength": 10,
|
||||
"order": [[0, "asc"]]
|
||||
});
|
||||
|
||||
sparkline("sparkline", {{ meta['sparkline'] }}, {});
|
||||
let div_width = $("#graphline").width();
|
||||
$.getJSON("{{ url_for('hunters.get_json_tracker_graph') }}?uuid={{ meta['uuid'] }}{%if meta['date_from']%}&date_from={{ meta['date_from'] }}{%endif%}{%if meta['date_to']%}&date_to={{ meta['date_to'] }}{%endif%}",
|
||||
function (data) {
|
||||
multilines_group("graphline", data, {"width": div_width});
|
||||
}
|
||||
);
|
||||
|
||||
});
|
||||
|
||||
function toggle_sidebar() {
|
||||
if ($('#nav_menu').is(':visible')) {
|
||||
$('#nav_menu').hide();
|
||||
$('#side_menu').removeClass('border-right')
|
||||
$('#side_menu').removeClass('col-lg-2')
|
||||
$('#core_content').removeClass('col-lg-10')
|
||||
} else {
|
||||
$('#nav_menu').show();
|
||||
$('#side_menu').addClass('border-right')
|
||||
$('#side_menu').addClass('col-lg-2')
|
||||
$('#core_content').addClass('col-lg-10')
|
||||
}
|
||||
}
|
||||
|
||||
function edit_tags() {
|
||||
$('#div_edit_mails').hide();
|
||||
$('#div_edit_description').hide();
|
||||
$('#div_edit_tags').show();
|
||||
}
|
||||
|
||||
function edit_mails() {
|
||||
$('#div_edit_tags').hide();
|
||||
$('#div_edit_description').hide();
|
||||
$('#div_edit_mails').show();
|
||||
}
|
||||
|
||||
function edit_description() {
|
||||
$('#div_edit_tags').hide();
|
||||
$('#div_edit_mails').hide();
|
||||
$('#div_edit_description').show();
|
||||
}
|
||||
|
||||
function getItems() {
|
||||
var date_from = $('#date-range-from-input').val();
|
||||
var date_to = $('#date-range-to-input').val();
|
||||
window.location.replace("{{ url_for('hunters.show_tracker') }}?uuid={{ meta['uuid'] }}&date_from=" + date_from + "&date_to=" + date_to);
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -70,7 +70,7 @@
|
|||
<td>{{ dict_uuid['type'] }}</td>
|
||||
<td>
|
||||
<span>
|
||||
<a target="_blank" href="{{ url_for('hunter.show_tracker') }}?uuid={{ dict_uuid['uuid'] }}">
|
||||
<a target="_blank" href="{{ url_for('hunters.show_tracker') }}?uuid={{ dict_uuid['uuid'] }}">
|
||||
{% if dict_uuid['tracked'] %}
|
||||
{% if dict_uuid['tracked']|length > 256 %}
|
||||
{{ dict_uuid['tracked'][0:256] }}...
|
||||
|
@ -135,7 +135,7 @@
|
|||
<td>{{ dict_uuid['type'] }}</td>
|
||||
<td>
|
||||
<span>
|
||||
<a target="_blank" href="{{ url_for('hunter.show_tracker') }}?uuid={{ dict_uuid['uuid'] }}">
|
||||
<a target="_blank" href="{{ url_for('hunters.show_tracker') }}?uuid={{ dict_uuid['uuid'] }}">
|
||||
{% if dict_uuid['tracked'] %}
|
||||
{% if dict_uuid['tracked']|length > 256 %}
|
||||
{{ dict_uuid['tracked'][0:256] }}...
|
||||
|
|
|
@ -100,7 +100,7 @@
|
|||
<td>{{ meta['type'] }}</td>
|
||||
<td>
|
||||
<span>
|
||||
<a target="_blank" href="{{ url_for('hunter.show_tracker') }}?uuid={{ meta['uuid'] }}">
|
||||
<a target="_blank" href="{{ url_for('hunters.show_tracker') }}?uuid={{ meta['uuid'] }}">
|
||||
{% if meta['tracked'] %}
|
||||
{% if meta['tracked']|length > 256 %}
|
||||
{{ meta['tracked'][0:256] }}...
|
||||
|
|
Loading…
Reference in a new issue