diff --git a/.gitignore b/.gitignore index acfff4e0..dc0b045a 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ tlsh Blooms PASTES CRAWLED_SCREENSHOT +IMAGES BASE64 HASHS DATA_ARDB diff --git a/bin/importer/feeders/Default.py b/bin/importer/feeders/Default.py index 4200efa8..ced7ac43 100755 --- a/bin/importer/feeders/Default.py +++ b/bin/importer/feeders/Default.py @@ -62,6 +62,9 @@ class DefaultFeeder: """ return self.json_data.get('data') + def get_obj_type(self): + return self.json_data.get('type', 'item') + ## OVERWRITE ME ## def get_obj(self): """ diff --git a/bin/importer/feeders/abstract_chats_feeder.py b/bin/importer/feeders/abstract_chats_feeder.py index 0b0d3ee0..1a8d097d 100755 --- a/bin/importer/feeders/abstract_chats_feeder.py +++ b/bin/importer/feeders/abstract_chats_feeder.py @@ -20,6 +20,7 @@ sys.path.append(os.environ['AIL_BIN']) from importer.feeders.Default import DefaultFeeder from lib.objects.Chats import Chat from lib.objects import ChatSubChannels +from lib.objects import Images from lib.objects import Messages from lib.objects import UsersAccount from lib.objects.Usernames import Username @@ -70,7 +71,7 @@ class AbstractChatFeeder(DefaultFeeder, ABC): def get_chat_id(self): # TODO RAISE ERROR IF NONE return self.json_data['meta']['chat']['id'] - def get_channel_id(self): + def get_subchannel_id(self): pass def get_subchannels(self): @@ -114,19 +115,29 @@ class AbstractChatFeeder(DefaultFeeder, ABC): timestamp = self.get_message_timestamp() #### Create Object ID #### - chat_id = str(self.json_data['meta']['chat']['id']) - message_id = str(self.json_data['meta']['id']) + chat_id = self.get_chat_id() + message_id = self.get_message_id() # channel id # thread id - obj_id = Messages.create_obj_id(self.get_chat_instance_uuid(), chat_id, message_id, timestamp) - self.obj = Messages.Message(obj_id) + # TODO sanitize obj type + obj_type = self.get_obj_type() + print(obj_type) + + if obj_type == 'image': + self.obj = Images.Image(self.json_data['data-sha256']) + + else: + obj_id = Messages.create_obj_id(self.get_chat_instance_uuid(), chat_id, message_id, timestamp) + self.obj = Messages.Message(obj_id) return self.obj - def process_chat(self, message, date, timestamp, reply_id=None): # TODO threads - meta = self.json_data['meta']['chat'] + def process_chat(self, obj, date, timestamp, reply_id=None): # TODO threads + meta = self.json_data['meta']['chat'] # todo replace me by function chat = Chat(self.get_chat_id(), self.get_chat_instance_uuid()) - chat.add(date) # TODO ### Dynamic subtype ??? + + # date stat + correlation + chat.add(date, obj) if meta.get('name'): chat.set_name(meta['name']) @@ -142,10 +153,12 @@ class AbstractChatFeeder(DefaultFeeder, ABC): chat.update_username_timeline(username.get_global_id(), timestamp) if meta.get('subchannel'): - subchannel = self.process_subchannel(message, date, timestamp, reply_id=reply_id) + subchannel = self.process_subchannel(obj, date, timestamp, reply_id=reply_id) chat.add_children(obj_global_id=subchannel.get_global_id()) else: - chat.add_message(message.get_global_id(), self.get_message_id(), timestamp, reply_id=reply_id) + if obj.type == 'message': + chat.add_message(obj.get_global_id(), self.get_message_id(), timestamp, reply_id=reply_id) + # if meta.get('subchannels'): # TODO Update icon + names @@ -154,9 +167,11 @@ class AbstractChatFeeder(DefaultFeeder, ABC): # def process_subchannels(self): # pass - def process_subchannel(self, message, date, timestamp, reply_id=None): # TODO CREATE DATE + def process_subchannel(self, obj, date, timestamp, reply_id=None): # TODO CREATE DATE meta = self.json_data['meta']['chat']['subchannel'] subchannel = ChatSubChannels.ChatSubChannel(f'{self.get_chat_id()}/{meta["id"]}', self.get_chat_instance_uuid()) + + # TODO correlation with obj = message/image subchannel.add(date) if meta.get('date'): # TODO check if already exists @@ -169,13 +184,17 @@ class AbstractChatFeeder(DefaultFeeder, ABC): if meta.get('info'): subchannel.set_info(meta['info']) - subchannel.add_message(message.get_global_id(), self.get_message_id(), timestamp, reply_id=reply_id) + if obj.type == 'message': + subchannel.add_message(obj.get_global_id(), self.get_message_id(), timestamp, reply_id=reply_id) return subchannel - def process_sender(self, date, timestamp): + def process_sender(self, obj, date, timestamp): meta = self.json_data['meta']['sender'] user_account = UsersAccount.UserAccount(meta['id'], self.get_chat_instance_uuid()) + # date stat + correlation + user_account.add(date, obj) + if meta.get('username'): username = Username(meta['username'], self.get_chat_protocol()) # TODO timeline or/and correlation ???? @@ -214,25 +233,45 @@ class AbstractChatFeeder(DefaultFeeder, ABC): # TODO Translation - # Content - content = self.get_message_content() + print(self.obj.type) - message = Messages.create(self.obj.id, content) # TODO translation + # get object by meta object type + if self.obj.type == 'message': + # Content + obj = Messages.create(self.obj.id, self.get_message_content()) # TODO translation - # CHAT - chat = self.process_chat(message, date, timestamp, reply_id=reply_id) + else: + chat_id = self.get_chat_id() + message_id = self.get_message_id() + message_id = Messages.create_obj_id(self.get_chat_instance_uuid(), chat_id, message_id, timestamp) + message = Messages.Message(message_id) + if message.exists(): + obj = Images.create(self.get_message_content()) + obj.add(date, message) + obj.set_parent(obj_global_id=message.get_global_id()) + else: + obj = None - # SENDER # TODO HANDLE NULL SENDER - user_account = self.process_sender(date, timestamp) + if obj: - # UserAccount---Message - user_account.add(date, obj=message) - # UserAccount---Chat - user_account.add_correlation(chat.type, chat.get_subtype(r_str=True), chat.id) + # CHAT + chat = self.process_chat(obj, date, timestamp, reply_id=reply_id) - # if chat: # TODO Chat---Username correlation ??? - # # Chat---Username - # chat.add_correlation(username.type, username.get_subtype(r_str=True), username.id) + # SENDER # TODO HANDLE NULL SENDER + user_account = self.process_sender(obj, date, timestamp) + + # UserAccount---Chat + user_account.add_correlation(chat.type, chat.get_subtype(r_str=True), chat.id) + + # if chat: # TODO Chat---Username correlation ??? + # # Chat---Username => need to handle members and participants + # chat.add_correlation(username.type, username.get_subtype(r_str=True), username.id) + + + # TODO Sender image -> correlation + # image + # -> subchannel ? + # -> thread id ? diff --git a/bin/lib/ail_core.py b/bin/lib/ail_core.py index e963ba73..77dd0682 100755 --- a/bin/lib/ail_core.py +++ b/bin/lib/ail_core.py @@ -16,8 +16,8 @@ r_serv_db = config_loader.get_db_conn("Kvrocks_DB") r_object = config_loader.get_db_conn("Kvrocks_Objects") config_loader = None -AIL_OBJECTS = sorted({'chat', 'cookie-name', 'cve', 'cryptocurrency', 'decoded', 'domain', 'etag', 'favicon', 'hhhash', 'item', - 'message', 'pgp', 'screenshot', 'title', 'user-account', 'username'}) +AIL_OBJECTS = sorted({'chat', 'cookie-name', 'cve', 'cryptocurrency', 'decoded', 'domain', 'etag', 'favicon', 'hhhash', + 'item', 'image', 'message', 'pgp', 'screenshot', 'title', 'user-account', 'username'}) def get_ail_uuid(): ail_uuid = r_serv_db.get('ail:uuid') diff --git a/bin/lib/correlations_engine.py b/bin/lib/correlations_engine.py index f7b13f61..b0b3108d 100755 --- a/bin/lib/correlations_engine.py +++ b/bin/lib/correlations_engine.py @@ -41,7 +41,7 @@ config_loader = None ################################## CORRELATION_TYPES_BY_OBJ = { - "chat": ["user-account"], # message or direct correlation like cve, bitcoin, ... ??? + "chat": ["image", "user-account"], # message or direct correlation like cve, bitcoin, ... ??? "cookie-name": ["domain"], "cryptocurrency": ["domain", "item", "message"], "cve": ["domain", "item", "message"], @@ -50,8 +50,9 @@ CORRELATION_TYPES_BY_OBJ = { "etag": ["domain"], "favicon": ["domain", "item"], # TODO Decoded "hhhash": ["domain"], + "image": ["chat", "message", "user-account"], "item": ["cve", "cryptocurrency", "decoded", "domain", "favicon", "pgp", "screenshot", "title", "username"], # chat ??? - "message": ["cve", "cryptocurrency", "decoded", "pgp", "user-account"], # chat ?? + "message": ["cve", "cryptocurrency", "decoded", "image", "pgp", "user-account"], # chat ?? "pgp": ["domain", "item", "message"], "screenshot": ["domain", "item"], "title": ["domain", "item"], diff --git a/bin/lib/objects/Images.py b/bin/lib/objects/Images.py new file mode 100755 index 00000000..280ac06c --- /dev/null +++ b/bin/lib/objects/Images.py @@ -0,0 +1,135 @@ +#!/usr/bin/env python3 +# -*-coding:UTF-8 -* + +import base64 +import os +import sys + +from hashlib import sha256 +from io import BytesIO + +from flask import url_for +from pymisp import MISPObject + +sys.path.append(os.environ['AIL_BIN']) +################################## +# Import Project packages +################################## +from lib.ConfigLoader import ConfigLoader +from lib.objects.abstract_daterange_object import AbstractDaterangeObject, AbstractDaterangeObjects + +config_loader = ConfigLoader() +r_serv_metadata = config_loader.get_db_conn("Kvrocks_Objects") +IMAGE_FOLDER = config_loader.get_files_directory('images') +config_loader = None + + +class Image(AbstractDaterangeObject): + """ + AIL Screenshot Object. (strings) + """ + + # ID = SHA256 + def __init__(self, image_id): + super(Image, self).__init__('image', image_id) + + # def get_ail_2_ail_payload(self): + # payload = {'raw': self.get_gzip_content(b64=True), + # 'compress': 'gzip'} + # return payload + + # # WARNING: UNCLEAN DELETE /!\ TEST ONLY /!\ + def delete(self): + # # TODO: + pass + + def exists(self): + return os.path.isfile(self.get_filepath()) + + def get_link(self, flask_context=False): + if flask_context: + url = url_for('correlation.show_correlation', type=self.type, id=self.id) + else: + url = f'{baseurl}/correlation/show?type={self.type}&id={self.id}' + return url + + def get_svg_icon(self): + return {'style': 'far', 'icon': '\uf03e', 'color': '#E1F5DF', 'radius': 5} + + def get_rel_path(self): + rel_path = os.path.join(self.id[0:2], self.id[2:4], self.id[4:6], self.id[6:8], self.id[8:10], self.id[10:12], self.id[12:]) + return rel_path + + def get_filepath(self): + filename = os.path.join(IMAGE_FOLDER, self.get_rel_path()) + return os.path.realpath(filename) + + def get_file_content(self): + filepath = self.get_filepath() + with open(filepath, 'rb') as f: + file_content = BytesIO(f.read()) + return file_content + + def get_content(self, r_type='str'): + return self.get_file_content() + + def get_misp_object(self): + obj_attrs = [] + obj = MISPObject('file') + + obj_attrs.append(obj.add_attribute('sha256', value=self.id)) + obj_attrs.append(obj.add_attribute('attachment', value=self.id, data=self.get_file_content())) + for obj_attr in obj_attrs: + for tag in self.get_tags(): + obj_attr.add_tag(tag) + return obj + + def get_meta(self, options=set()): + meta = self._get_meta(options=options) + meta['id'] = self.id + meta['img'] = self.id + meta['tags'] = self.get_tags(r_list=True) + if 'content' in options: + meta['content'] = self.get_content() + if 'tags_safe' in options: + meta['tags_safe'] = self.is_tags_safe(meta['tags']) + return meta + + def create(self, content): + filepath = self.get_filepath() + dirname = os.path.dirname(filepath) + if not os.path.exists(dirname): + os.makedirs(dirname) + with open(filepath, 'wb') as f: + f.write(content) + +def get_screenshot_dir(): + return IMAGE_FOLDER + + +def create(content, size_limit=5000000, b64=False, force=False): + size = (len(content)*3) / 4 + if size <= size_limit or size_limit < 0 or force: + if b64: + content = base64.standard_b64decode(content.encode()) + image_id = sha256(content).hexdigest() + image = Image(image_id) + if not image.exists(): + image.create(content) + return image + + +class Images(AbstractDaterangeObjects): + """ + CookieName Objects + """ + def __init__(self): + super().__init__('image', Image) + + def sanitize_id_to_search(self, name_to_search): + return name_to_search # TODO + + +# if __name__ == '__main__': +# name_to_search = '29ba' +# print(search_screenshots_by_name(name_to_search)) diff --git a/bin/lib/objects/Messages.py b/bin/lib/objects/Messages.py index 8f3eba6b..e6808bf4 100755 --- a/bin/lib/objects/Messages.py +++ b/bin/lib/objects/Messages.py @@ -88,7 +88,7 @@ class Message(AbstractObject): def get_timestamp(self): dirs = self.id.split('/') - return dirs[-2] + return dirs[1] def get_message_id(self): # TODO optimize message_id = self.get_basename().rsplit('/', 1)[1] @@ -104,6 +104,14 @@ class Message(AbstractObject): # TODO get channel ID # TODO get thread ID + def get_images(self): + images = [] + for child in self.get_childrens(): + obj_type, _, obj_id = child.split(':', 2) + if obj_type == 'image': + images.append(obj_id) + return images + def get_user_account(self, meta=False): user_account = self.get_correlation('user-account') if user_account.get('user-account'): @@ -194,7 +202,7 @@ class Message(AbstractObject): else: timestamp = float(timestamp) timestamp = datetime.fromtimestamp(float(timestamp)) - meta['date'] = timestamp.strftime('%Y%/m/%d') + meta['date'] = timestamp.strftime('%Y/%m/%d') meta['hour'] = timestamp.strftime('%H:%M:%S') meta['full_date'] = timestamp.isoformat(' ') @@ -222,6 +230,8 @@ class Message(AbstractObject): meta['user-account'] = {'id': 'UNKNOWN'} if 'chat' in options: meta['chat'] = self.get_chat_id() + if 'images' in options: + meta['images'] = self.get_images() # meta['encoding'] = None return meta diff --git a/bin/lib/objects/abstract_chat_object.py b/bin/lib/objects/abstract_chat_object.py index d1645913..d266eb5c 100755 --- a/bin/lib/objects/abstract_chat_object.py +++ b/bin/lib/objects/abstract_chat_object.py @@ -128,8 +128,18 @@ class AbstractChatObject(AbstractSubtypeObject, ABC): def get_nb_messages(self): return r_object.zcard(f'messages:{self.type}:{self.subtype}:{self.id}') - def _get_messages(self): # TODO paginate - return r_object.zrange(f'messages:{self.type}:{self.subtype}:{self.id}', 0, -1, withscores=True) + def _get_messages(self, nb=-1, page=1): + if nb < 1: + return r_object.zrange(f'messages:{self.type}:{self.subtype}:{self.id}', 0, -1, withscores=True) + else: + if page > 1: + start = page - 1 + nb + else: + start = 0 + messages = r_object.zrevrange(f'messages:{self.type}:{self.subtype}:{self.id}', start, start+nb-1, withscores=True) + if messages: + messages = reversed(messages) + return messages def get_timestamp_first_message(self): return r_object.zrange(f'messages:{self.type}:{self.subtype}:{self.id}', 0, 0, withscores=True) @@ -169,15 +179,15 @@ class AbstractChatObject(AbstractSubtypeObject, ABC): def get_message_meta(self, message, timestamp=None): # TODO handle file message message = Messages.Message(message[9:]) - meta = message.get_meta(options={'content', 'link', 'parent', 'parent_meta', 'user-account'}, timestamp=timestamp) + meta = message.get_meta(options={'content', 'images', 'link', 'parent', 'parent_meta', 'user-account'}, timestamp=timestamp) return meta - def get_messages(self, start=0, page=1, nb=500, unread=False): # threads ???? + def get_messages(self, start=0, page=1, nb=500, unread=False): # threads ???? # TODO ADD last/first message timestamp + return page # TODO return message meta tags = {} messages = {} curr_date = None - for message in self._get_messages(): + for message in self._get_messages(nb=10, page=3): timestamp = message[1] date_day = datetime.fromtimestamp(timestamp).strftime('%Y/%m/%d') if date_day != curr_date: diff --git a/bin/lib/objects/abstract_daterange_object.py b/bin/lib/objects/abstract_daterange_object.py index f2e86c57..1bf7e5bc 100755 --- a/bin/lib/objects/abstract_daterange_object.py +++ b/bin/lib/objects/abstract_daterange_object.py @@ -71,8 +71,8 @@ class AbstractDaterangeObject(AbstractObject, ABC): else: return last_seen - def get_nb_seen(self): - return self.get_nb_correlation('item') + def get_nb_seen(self): # TODO REPLACE ME -> correlation image + return self.get_nb_correlation('item') + self.get_nb_correlation('message') def get_nb_seen_by_date(self, date): nb = r_object.zscore(f'{self.type}:date:{date}', self.id) @@ -125,7 +125,7 @@ class AbstractDaterangeObject(AbstractObject, ABC): def _add_create(self): r_object.sadd(f'{self.type}:all', self.id) - def _add(self, date, obj): + def _add(self, date, obj): # TODO OBJ=None if not self.exists(): self._add_create() self.set_first_seen(date) @@ -134,13 +134,12 @@ class AbstractDaterangeObject(AbstractObject, ABC): self.update_daterange(date) update_obj_date(date, self.type) + r_object.zincrby(f'{self.type}:date:{date}', 1, self.id) + if obj: # Correlations self.add_correlation(obj.type, obj.get_subtype(r_str=True), obj.get_id()) - # Stats NB by day: # TODO Don't increase on reprocess - r_object.zincrby(f'{self.type}:date:{date}', 1, self.id) - if obj.type == 'item': item_id = obj.get_id() # domain diff --git a/bin/lib/objects/ail_objects.py b/bin/lib/objects/ail_objects.py index 0c29d668..d3bd06f3 100755 --- a/bin/lib/objects/ail_objects.py +++ b/bin/lib/objects/ail_objects.py @@ -23,6 +23,7 @@ from lib.objects import Etags from lib.objects.Favicons import Favicon from lib.objects import HHHashs from lib.objects.Items import Item, get_all_items_objects, get_nb_items_objects +from lib.objects import Images from lib.objects.Messages import Message from lib.objects import Pgps from lib.objects.Screenshots import Screenshot @@ -70,6 +71,8 @@ def get_object(obj_type, subtype, obj_id): return Favicon(obj_id) elif obj_type == 'hhhash': return HHHashs.HHHash(obj_id) + elif obj_type == 'image': + return Images.Image(obj_id) elif obj_type == 'message': return Message(obj_id) elif obj_type == 'screenshot': diff --git a/configs/core.cfg.sample b/configs/core.cfg.sample index 9d7bb390..105fdc74 100644 --- a/configs/core.cfg.sample +++ b/configs/core.cfg.sample @@ -6,6 +6,7 @@ hash = HASHS crawled = crawled har = CRAWLED_SCREENSHOT screenshot = CRAWLED_SCREENSHOT/screenshot +images = IMAGES wordtrending_csv = var/www/static/csv/wordstrendingdata wordsfile = files/wordfile diff --git a/var/www/Flask_server.py b/var/www/Flask_server.py index 97f6dde3..a00f0f7e 100755 --- a/var/www/Flask_server.py +++ b/var/www/Flask_server.py @@ -51,6 +51,7 @@ from blueprints.objects_cookie_name import objects_cookie_name from blueprints.objects_etag import objects_etag from blueprints.objects_hhhash import objects_hhhash from blueprints.chats_explorer import chats_explorer +from blueprints.objects_image import objects_image Flask_dir = os.environ['AIL_FLASK'] @@ -109,6 +110,7 @@ app.register_blueprint(objects_cookie_name, url_prefix=baseUrl) app.register_blueprint(objects_etag, url_prefix=baseUrl) app.register_blueprint(objects_hhhash, url_prefix=baseUrl) app.register_blueprint(chats_explorer, url_prefix=baseUrl) +app.register_blueprint(objects_image, url_prefix=baseUrl) # ========= =========# diff --git a/var/www/blueprints/objects_image.py b/var/www/blueprints/objects_image.py new file mode 100644 index 00000000..8fd320e8 --- /dev/null +++ b/var/www/blueprints/objects_image.py @@ -0,0 +1,90 @@ +#!/usr/bin/env python3 +# -*-coding:UTF-8 -* + +''' + Blueprint Flask: crawler splash endpoints: dashboard, onion crawler ... +''' + +import os +import sys + +from flask import Flask, render_template, jsonify, request, Blueprint, redirect, url_for, Response, abort, send_file, send_from_directory +from flask_login import login_required, current_user + +# Import Role_Manager +from Role_Manager import login_admin, login_analyst, login_read_only, no_cache + +sys.path.append(os.environ['AIL_BIN']) +################################## +# Import Project packages +################################## +from lib.objects import Images +from packages import Date + +# ============ BLUEPRINT ============ +objects_image = Blueprint('objects_image', __name__, template_folder=os.path.join(os.environ['AIL_FLASK'], 'templates/objects/image')) + +# ============ VARIABLES ============ +bootstrap_label = ['primary', 'success', 'danger', 'warning', 'info'] + + +# ============ FUNCTIONS ============ +@objects_image.route('/image/') +@login_required +@login_read_only +@no_cache +def image(filename): + if not filename: + abort(404) + if not 64 <= len(filename) <= 70: + abort(404) + filename = filename.replace('/', '') + image = Images.Image(filename) + return send_from_directory(Images.IMAGE_FOLDER, image.get_rel_path(), as_attachment=True) + + +@objects_image.route("/objects/images", methods=['GET']) +@login_required +@login_read_only +def objects_images(): + date_from = request.args.get('date_from') + date_to = request.args.get('date_to') + show_objects = request.args.get('show_objects') + date = Date.sanitise_date_range(date_from, date_to) + date_from = date['date_from'] + date_to = date['date_to'] + + if show_objects: + dict_objects = Images.Images().api_get_meta_by_daterange(date_from, date_to) + else: + dict_objects = {} + + print(dict_objects) + + return render_template("ImageDaterange.html", date_from=date_from, date_to=date_to, + dict_objects=dict_objects, show_objects=show_objects) + + +@objects_image.route("/objects/images/post", methods=['POST']) +@login_required +@login_read_only +def objects_images_post(): + date_from = request.form.get('date_from') + date_to = request.form.get('date_to') + show_objects = request.form.get('show_objects') + return redirect(url_for('objects_image.objects_images', date_from=date_from, date_to=date_to, show_objects=show_objects)) + + +@objects_image.route("/objects/images/range/json", methods=['GET']) +@login_required +@login_read_only +def objects_images_range_json(): + date_from = request.args.get('date_from') + date_to = request.args.get('date_to') + date = Date.sanitise_date_range(date_from, date_to) + date_from = date['date_from'] + date_to = date['date_to'] + return jsonify(Images.Images().api_get_chart_nb_by_daterange(date_from, date_to)) + +# ============= ROUTES ============== + diff --git a/var/www/templates/chats_explorer/chat_viewer.html b/var/www/templates/chats_explorer/chat_viewer.html index fed8676b..c1a330ae 100644 --- a/var/www/templates/chats_explorer/chat_viewer.html +++ b/var/www/templates/chats_explorer/chat_viewer.html @@ -35,6 +35,10 @@ height: 2px; background: #eee; } + .message_image { + max-width: 50%; + filter: blur(5px); + } @@ -147,6 +151,30 @@ {% if chat['messages'] %} + +
+
+
+
+ +
+
+ +
+
+ +
+
+
+
+
+
@@ -193,6 +221,9 @@ {#
#}
{% endif %} + {% if mess['images'] %} + + {% endif %}
{{ mess['content'] }}
{% for tag in mess['tags'] %} {{ tag }} @@ -245,6 +276,17 @@ function toggle_sidebar(){ $('#core_content').addClass('col-lg-10') } } + + +const blur_slider = $('#blur-slider'); +function blur_images(){ + let blurValue = blur_slider.val(); + blurValue = 15 - blurValue; + let images = document.getElementsByClassName('message_image'); + for(i = 0; i < images.length; i++) { + images[i].style.filter = "blur(" + blurValue + "px)"; + } +} @@ -405,9 +447,6 @@ d3.json("{{ url_for('chats_explorer.chats_explorer_messages_stats_week') }}?uuid tooltip.html(d.date + " " + d.hour + "-" + (d.hour + 1) + "h: " + d.count + " messages") } const mouseleave = function(d) { - console.log(d) - console.log(d.hour) - console.log(d.day) tooltip.style("opacity", 0) d3.select(this) .style("stroke", "none") diff --git a/var/www/templates/correlation/show_correlation.html b/var/www/templates/correlation/show_correlation.html index 11a85cd7..ebcd84e3 100644 --- a/var/www/templates/correlation/show_correlation.html +++ b/var/www/templates/correlation/show_correlation.html @@ -684,7 +684,12 @@ if (d.popover) { if (data["img"]) { if (data["tags_safe"]) { - desc = desc + ""; + if (data["type"] === "screenshot") { + desc = desc + ""; } else { desc = desc + ""; } diff --git a/var/www/templates/objects/image/ImageDaterange.html b/var/www/templates/objects/image/ImageDaterange.html new file mode 100644 index 00000000..e88c9b60 --- /dev/null +++ b/var/www/templates/objects/image/ImageDaterange.html @@ -0,0 +1,602 @@ + + + + + Images - AIL + + + + + + + + + + + + + + + + + + + + + + + + {% include 'nav_bar.html' %} + +
+
+ + {% include 'sidebars/sidebar_objects.html' %} + +
+ +
+
+
+ +{# {% include 'image/block_images_search.html' %}#} + +
+ + +
+ +
+
+
Select a date range :
+
+
+
+ +
+
+
+ +
+
+ + +
+ +
+
+
+ +
+
+
+
+
+
+ + {% if dict_objects %} + {% if date_from|string == date_to|string %} +

{{ date_from }} Images Name:

+ {% else %} +

{{ date_from }} to {{ date_to }} Images Name:

+ {% endif %} + + + + + + + + + + + + {% for obj_id in dict_objects %} + + + + + + + + {% endfor %} + +
First SeenLast SeenTotalLast days
{{ dict_objects[obj_id]['id'] }}{{ dict_objects[obj_id]['first_seen'] }}{{ dict_objects[obj_id]['last_seen'] }}{{ dict_objects[obj_id]['nb_seen'] }}
+ + + {% else %} + {% if show_objects %} + {% if date_from|string == date_to|string %} +

{{ date_from }}, No Image

+ {% else %} +

{{ date_from }} to {{ date_to }}, No Image

+ {% endif %} + {% endif %} + {% endif %} +
+ +
+
+ + + + + + + + + + + + + + + + +