chg: [trackers] refactor trackers

pull/594/head
Terrtia 2023-05-11 16:21:43 +02:00
parent 6b60041db2
commit 4473086f89
No known key found for this signature in database
GPG Key ID: 1E1B1F50D84613D0
14 changed files with 871 additions and 875 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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&ltags={{ 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>

View File

@ -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'])
});

View File

@ -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'])
});

View 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>&nbsp;
{% elif meta['type'] == 'set' %}
<i class="fas fa-layer-group"></i>&nbsp;
{% elif meta['type'] == 'regex' %}
<i class="fas fa-compass"></i>&nbsp;
{% elif meta['type'] == 'typosquatting' %}
<i class="fas fa-clone"></i>&nbsp;
{% elif meta['type'] == 'yara' %}
<span class="bg-danger text-white font-weight-bold" style="font-size: 120%">&nbsp;{ </span>&nbsp;
{% 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>

View File

@ -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] }}...

View File

@ -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] }}...