mirror of https://github.com/CIRCL/AIL-framework
				
				
				
			chg: [qrcode] extract qrcode content from images and screenshots + qrcode object + correlation
							parent
							
								
									a199148ca7
								
							
						
					
					
						commit
						9f45202658
					
				|  | @ -280,6 +280,8 @@ function launching_scripts { | |||
|     sleep 0.1 | ||||
|     screen -S "Script_AIL" -X screen -t "OcrExtractor" bash -c "cd ${AIL_BIN}/modules; ${ENV_PY} ./OcrExtractor.py; read x" | ||||
|     sleep 0.1 | ||||
|     screen -S "Script_AIL" -X screen -t "QrCodeReader" bash -c "cd ${AIL_BIN}/modules; ${ENV_PY} ./QrCodeReader.py; read x" | ||||
|     sleep 0.1 | ||||
| 
 | ||||
|     ################################## | ||||
|     #       TRACKERS MODULES         # | ||||
|  |  | |||
|  | @ -359,6 +359,7 @@ class Crawler(AbstractModule): | |||
|                             # Create Correlations | ||||
|                             screenshot.add_correlation('item', '', item_id) | ||||
|                             screenshot.add_correlation('domain', '', self.domain.id) | ||||
|                         self.add_message_to_queue(obj=screenshot, queue='Images') | ||||
|             # HAR | ||||
|             if self.har: | ||||
|                 if 'har' in entries and entries.get('har'): | ||||
|  |  | |||
|  | @ -17,15 +17,15 @@ r_object = config_loader.get_db_conn("Kvrocks_Objects") | |||
| config_loader = None | ||||
| 
 | ||||
| AIL_OBJECTS = sorted({'chat', 'chat-subchannel', 'chat-thread', 'cookie-name', 'cve', 'cryptocurrency', 'decoded', | ||||
|                       'domain', 'etag', 'favicon', 'file-name', 'hhhash', | ||||
|                       'item', 'image', 'message', 'ocr', 'pgp', 'screenshot', 'title', 'user-account', 'username'}) | ||||
|                       'domain', 'etag', 'favicon', 'file-name', 'hhhash','item', 'image', 'message', 'ocr', 'pgp', | ||||
|                       'qrcode', 'screenshot', 'title', 'user-account', 'username'}) | ||||
| 
 | ||||
| AIL_OBJECTS_WITH_SUBTYPES = {'chat', 'chat-subchannel', 'cryptocurrency', 'pgp', 'username', 'user-account'} | ||||
| 
 | ||||
| # TODO by object TYPE ???? | ||||
| AIL_OBJECTS_CORRELATIONS_DEFAULT = sorted({'chat', 'chat-subchannel', 'chat-thread', 'cve', 'cryptocurrency', 'decoded', | ||||
|                                            'domain', 'favicon', 'file-name', | ||||
|                                            'item', 'image', 'message', 'ocr', 'pgp', 'screenshot', 'title', 'user-account', 'username'}) | ||||
|                                            'domain', 'favicon', 'file-name', 'item', 'image', 'message', 'ocr', 'pgp', | ||||
|                                            'qrcode', 'screenshot', 'title', 'user-account', 'username'}) | ||||
| 
 | ||||
| def get_ail_uuid(): | ||||
|     ail_uuid = r_serv_db.get('ail:uuid') | ||||
|  | @ -86,10 +86,10 @@ def get_default_correlation_objects(): | |||
|     return AIL_OBJECTS_CORRELATIONS_DEFAULT | ||||
| 
 | ||||
| def get_obj_queued(): | ||||
|     return ['item', 'image', 'message', 'ocr'] | ||||
|     return ['item', 'image', 'message', 'ocr', 'qrcode'] | ||||
| 
 | ||||
| def get_objects_tracked(): | ||||
|     return ['decoded', 'item', 'pgp', 'message', 'ocr', 'title'] | ||||
|     return ['decoded', 'item', 'pgp', 'message', 'ocr', 'qrcode', 'title'] | ||||
| 
 | ||||
| def get_objects_retro_hunted(): | ||||
|     return ['decoded', 'item', 'message'] | ||||
|  |  | |||
|  | @ -43,22 +43,23 @@ config_loader = None | |||
| CORRELATION_TYPES_BY_OBJ = { | ||||
|     "chat": ["chat-subchannel", "chat-thread", "image", "message", "ocr", "user-account"],  # message or direct correlation like cve, bitcoin, ... ??? | ||||
|     "chat-subchannel": ["chat", "chat-thread", "image", "message", "ocr", "user-account"], | ||||
|     "chat-thread": ["chat", "chat-subchannel", "image", "message", "ocr", "user-account"], # TODO user account | ||||
|     "chat-thread": ["chat", "chat-subchannel", "image", "message", "ocr", "user-account"], | ||||
|     "cookie-name": ["domain"], | ||||
|     "cryptocurrency": ["domain", "item", "message", "ocr"], | ||||
|     "cve": ["domain", "item", "message", "ocr"], | ||||
|     "decoded": ["domain", "item", "message", "ocr"], | ||||
|     "cryptocurrency": ["domain", "item", "message", "ocr", "qrcode"], | ||||
|     "cve": ["domain", "item", "message", "ocr", "qrcode"], | ||||
|     "decoded": ["domain", "item", "message", "ocr", "qrcode"], | ||||
|     "domain": ["cve", "cookie-name", "cryptocurrency", "decoded", "etag", "favicon", "hhhash", "item", "pgp", "title", "screenshot", "username"], | ||||
|     "etag": ["domain"], | ||||
|     "favicon": ["domain", "item"],  # TODO Decoded | ||||
|     "file-name": ["chat", "message"], | ||||
|     "hhhash": ["domain"], | ||||
|     "image": ["chat", "chat-subchannel", "chat-thread", "message", "ocr", "user-account"],  # TODO subchannel + threads ???? | ||||
|     "image": ["chat", "chat-subchannel", "chat-thread", "message", "ocr", "qrcode", "user-account"],  # TODO subchannel + threads ???? | ||||
|     "item": ["cve", "cryptocurrency", "decoded", "domain", "favicon", "pgp", "screenshot", "title", "username"],  # chat ??? | ||||
|     "message": ["chat", "chat-subchannel", "chat-thread", "cve", "cryptocurrency", "decoded", "file-name", "image", "ocr", "pgp", "user-account"], | ||||
|     "ocr": ["chat", "chat-subchannel", "chat-thread", "cve", "cryptocurrency", "decoded", "image", "message", "pgp", "user-account"], | ||||
|     "pgp": ["domain", "item", "message", "ocr"], | ||||
|     "screenshot": ["domain", "item"], | ||||
|     "qrcode": ["chat", "cve", "cryptocurrency", "decoded", "domain", "image", "message", "screenshot"],     # "chat-subchannel", "chat-thread" ????? | ||||
|     "screenshot": ["domain", "item", "qrcode"], | ||||
|     "title": ["domain", "item"], | ||||
|     "user-account": ["chat", "chat-subchannel", "chat-thread", "image", "message", "ocr", "username"], | ||||
|     "username": ["domain", "item", "message", "user-account"], | ||||
|  | @ -67,7 +68,9 @@ CORRELATION_TYPES_BY_OBJ = { | |||
| def get_obj_correl_types(obj_type): | ||||
|     return CORRELATION_TYPES_BY_OBJ.get(obj_type) | ||||
| 
 | ||||
| def sanityze_obj_correl_types(obj_type, correl_types): | ||||
| def sanityze_obj_correl_types(obj_type, correl_types, sanityze=True): | ||||
|     if not sanityze: | ||||
|         return correl_types | ||||
|     obj_correl_types = get_obj_correl_types(obj_type) | ||||
|     if correl_types: | ||||
|         correl_types = set(correl_types).intersection(obj_correl_types) | ||||
|  | @ -99,11 +102,11 @@ def get_correlation_by_correl_type(obj_type, subtype, obj_id, correl_type, unpac | |||
|     else: | ||||
|         return correl | ||||
| 
 | ||||
| def get_correlations(obj_type, subtype, obj_id, filter_types=[], unpack=False): | ||||
| def get_correlations(obj_type, subtype, obj_id, filter_types=[], unpack=False, sanityze=True): | ||||
|     if subtype is None: | ||||
|         subtype = '' | ||||
|     obj_correlations = {} | ||||
|     filter_types = sanityze_obj_correl_types(obj_type, filter_types) | ||||
|     filter_types = sanityze_obj_correl_types(obj_type, filter_types, sanityze=sanityze) | ||||
|     for correl_type in filter_types: | ||||
|         obj_correlations[correl_type] = get_correlation_by_correl_type(obj_type, subtype, obj_id, correl_type, | ||||
|                                                                        unpack=unpack) | ||||
|  |  | |||
|  | @ -0,0 +1,163 @@ | |||
| #!/usr/bin/env python3 | ||||
| # -*-coding:UTF-8 -* | ||||
| 
 | ||||
| import os | ||||
| import sys | ||||
| 
 | ||||
| from hashlib import sha256 | ||||
| from pymisp import MISPObject | ||||
| 
 | ||||
| sys.path.append(os.environ['AIL_BIN']) | ||||
| ################################## | ||||
| # Import Project packages | ||||
| ################################## | ||||
| from lib.objects.abstract_daterange_object import AbstractDaterangeObject, AbstractDaterangeObjects | ||||
| from lib.ConfigLoader import ConfigLoader | ||||
| from packages import Date | ||||
| # from lib.data_retention_engine import update_obj_date, get_obj_date_first | ||||
| 
 | ||||
| from flask import url_for | ||||
| 
 | ||||
| config_loader = ConfigLoader() | ||||
| r_object = config_loader.get_db_conn("Kvrocks_Objects") | ||||
| r_cache = config_loader.get_redis_conn("Redis_Cache") | ||||
| baseurl = config_loader.get_config_str("Notifications", "ail_domain") | ||||
| IMAGE_FOLDER = config_loader.get_files_directory('images') | ||||
| config_loader = None | ||||
| 
 | ||||
| # SET x1,y1:x2,y2:x3,y3:x4,y4:extracted_text | ||||
| 
 | ||||
| class Qrcode(AbstractDaterangeObject): | ||||
|     """ | ||||
|     AIL Message Object. (strings) | ||||
|     """ | ||||
| 
 | ||||
|     def __init__(self, id): | ||||
|         super(Qrcode, self).__init__('qrcode', id) | ||||
| 
 | ||||
|     def get_content(self, r_type='str'): | ||||
|         """ | ||||
|         Returns content | ||||
|         """ | ||||
|         global_id = self.get_global_id() | ||||
|         content = r_cache.get(f'content:{global_id}') | ||||
|         if not content: | ||||
|             content = self._get_field('content') | ||||
|             # Set Cache | ||||
|             if content: | ||||
|                 global_id = self.get_global_id() | ||||
|                 r_cache.set(f'content:{global_id}', content) | ||||
|                 r_cache.expire(f'content:{global_id}', 300) | ||||
|         if r_type == 'str': | ||||
|             return content | ||||
|         elif r_type == 'bytes': | ||||
|             if content: | ||||
|                 return content.encode() | ||||
| 
 | ||||
|     def get_date(self):  # TODO | ||||
|         return Date.get_today_date_str() | ||||
| 
 | ||||
|     def get_nb_seen(self): | ||||
|         return self.get_nb_correlation('image') + self.get_nb_correlation('screenshot') | ||||
| 
 | ||||
|     def get_source(self):  # TODO | ||||
|         """ | ||||
|         Returns source/feeder name | ||||
|         """ | ||||
|         return 'qrcode' | ||||
| 
 | ||||
|     def get_basename(self):  # TODO | ||||
|         return 'qrcode' | ||||
| 
 | ||||
|     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):  # TODO | ||||
|         return {'style': 'fas', 'icon': '\uf029', 'color': 'yellow', 'radius': 5} | ||||
| 
 | ||||
|     def get_misp_object(self):  # TODO | ||||
|         pass | ||||
|     #     obj = MISPObject('instant-message', standalone=True) | ||||
|     #     obj_date = self.get_date() | ||||
|     #     if obj_date: | ||||
|     #         obj.first_seen = obj_date | ||||
|     #     else: | ||||
|     #         self.logger.warning( | ||||
|     #             f'Export error, None seen {self.type}:{self.subtype}:{self.id}, first={obj_date}') | ||||
|     # | ||||
|     #     # obj_attrs = [obj.add_attribute('first-seen', value=obj_date), | ||||
|     #     #              obj.add_attribute('raw-data', value=self.id, data=self.get_raw_content()), | ||||
|     #     #              obj.add_attribute('sensor', value=get_ail_uuid())] | ||||
|     #     obj_attrs = [] | ||||
|     #     for obj_attr in obj_attrs: | ||||
|     #         for tag in self.get_tags(): | ||||
|     #             obj_attr.add_tag(tag) | ||||
|     #     return obj | ||||
| 
 | ||||
|     # options: set of optional meta fields | ||||
|     def get_meta(self, options=None): | ||||
|         """ | ||||
|         :type options: set | ||||
|         """ | ||||
|         if options is None: | ||||
|             options = set() | ||||
|         meta = self._get_meta(options=options) | ||||
|         meta['tags'] = self.get_tags() | ||||
|         meta['content'] = self.get_content() | ||||
| 
 | ||||
|         # optional meta fields | ||||
|         if 'investigations' in options: | ||||
|             meta['investigations'] = self.get_investigations() | ||||
|         if 'link' in options: | ||||
|             meta['link'] = self.get_link(flask_context=True) | ||||
|         if 'icon' in options: | ||||
|             meta['svg_icon'] = self.get_svg_icon() | ||||
|         return meta | ||||
| 
 | ||||
|     def create(self, content, im_obj, tags=[]): | ||||
|         self._set_field('content', content) | ||||
|         if im_obj.type == 'screenshot': | ||||
|             for date in im_obj.get_dates(): | ||||
|                 self._add(date, None) | ||||
|         else: | ||||
|             self._copy_from(im_obj.type, im_obj.get_id()) | ||||
| 
 | ||||
|         for tag in tags: | ||||
|             self.add_tag(tag) | ||||
|         return self.id | ||||
| 
 | ||||
|     # # WARNING: UNCLEAN DELETE /!\ TEST ONLY /!\ | ||||
|     def delete(self): | ||||
|         r_object.delete(f'qrcode:{self.id}') | ||||
| 
 | ||||
| 
 | ||||
| def create(content, im_obj, tags=[]): | ||||
|     if content: | ||||
|         obj_id = sha256(content.encode()).hexdigest() | ||||
|         obj = Qrcode(obj_id) | ||||
|         if not obj.exists(): | ||||
|             obj.create(content, im_obj, tags=tags) | ||||
|         return obj | ||||
| 
 | ||||
| class Qrcodes(AbstractDaterangeObjects): | ||||
|     """ | ||||
|         Qrcodes Objects | ||||
|     """ | ||||
|     def __init__(self): | ||||
|         super().__init__('qrcode', Qrcode) | ||||
| 
 | ||||
|     def sanitize_id_to_search(self, name_to_search): | ||||
|         return name_to_search  # TODO | ||||
| 
 | ||||
| 
 | ||||
| #### API #### | ||||
| def api_get_qrcode(obj_id): | ||||
|     obj = Qrcode(obj_id) | ||||
|     if not obj.exists(): | ||||
|         return {"status": "error", "reason": "Unknown qrcode"}, 404 | ||||
|     meta = obj.get_meta({'content', 'icon', 'link'}) | ||||
|     return meta, 200 | ||||
|  | @ -47,6 +47,22 @@ class Screenshot(AbstractObject): | |||
|     def exists(self): | ||||
|         return os.path.isfile(self.get_filepath()) | ||||
| 
 | ||||
|     def get_last_seen(self): | ||||
|         dates = self.get_dates() | ||||
|         date = 0 | ||||
|         for d in dates: | ||||
|             if int(d) > int(date): | ||||
|                 date = d | ||||
|         return date | ||||
| 
 | ||||
|     def get_dates(self): | ||||
|         dates = [] | ||||
|         for i_id in self.get_correlation('item').get('item'): | ||||
|             if i_id.startswith(':crawled'): | ||||
|                 i_id = i_id.split('/', 4) | ||||
|                 dates.append(f'{i_id[1]}{i_id[2]}{i_id[3]}') | ||||
|         return dates | ||||
| 
 | ||||
|     def get_link(self, flask_context=False): | ||||
|         if flask_context: | ||||
|             url = url_for('correlation.show_correlation', type=self.type, id=self.id) | ||||
|  | @ -116,6 +132,14 @@ def get_all_screenshots(): | |||
|             screenshots.append(screenshot_id) | ||||
|     return screenshots | ||||
| 
 | ||||
| def get_screenshots_obj_iterator(filters=[]): | ||||
|     screenshot_dir = os.path.join(os.environ['AIL_HOME'], SCREENSHOT_FOLDER) | ||||
|     for root, dirs, files in os.walk(screenshot_dir): | ||||
|         for file in files: | ||||
|             screenshot_path = f'{root}{file}' | ||||
|             screenshot_id = screenshot_path.replace(SCREENSHOT_FOLDER, '').replace('/', '')[:-4] | ||||
|             yield Screenshot(screenshot_id) | ||||
| 
 | ||||
| # FIXME STR SIZE LIMIT | ||||
| def create_screenshot(content, size_limit=5000000, b64=True, force=False): | ||||
|     size = (len(content)*3) / 4 | ||||
|  | @ -155,5 +179,6 @@ def search_screenshots_by_name(name_to_search, r_pos=False): | |||
| 
 | ||||
| 
 | ||||
| # if __name__ == '__main__': | ||||
| #     name_to_search = '29ba' | ||||
| #     print(search_screenshots_by_name(name_to_search)) | ||||
| #     obj_id = '' | ||||
| #     obj = Screenshot(obj_id) | ||||
| #     obj.get_last_seen() | ||||
|  |  | |||
|  | @ -132,7 +132,7 @@ class AbstractDaterangeObject(AbstractObject, ABC): | |||
|         last_seen = r_object.hget(f'meta:{obj_type}:{obj_id}', 'last_seen') | ||||
|         if first_seen and last_seen: | ||||
|             for date in Date.get_daterange(first_seen, last_seen): | ||||
|                 nb = r_object.zscore(f'{obj_type}:date:{date}', self.id) | ||||
|                 nb = r_object.zscore(f'{obj_type}:date:{date}', obj_id) | ||||
|                 if nb: | ||||
|                     r_object.zincrby(f'{self.type}:date:{date}', nb, self.id) | ||||
|             update_obj_date(first_seen, self.type) | ||||
|  |  | |||
|  | @ -235,7 +235,7 @@ class AbstractObject(ABC): | |||
|         """ | ||||
|         Get object correlation | ||||
|         """ | ||||
|         return get_correlations(self.type, self.subtype, self.id, filter_types=[obj_type]) | ||||
|         return get_correlations(self.type, self.subtype, self.id, filter_types=[obj_type], sanityze=False) | ||||
| 
 | ||||
|     def get_first_correlation(self, obj_type): | ||||
|         correlation = self.get_correlation(obj_type) | ||||
|  |  | |||
|  | @ -36,7 +36,8 @@ from lib.objects import Images | |||
| from lib.objects import Messages | ||||
| from lib.objects import Ocrs | ||||
| from lib.objects import Pgps | ||||
| from lib.objects.Screenshots import Screenshot | ||||
| from lib.objects import QrCodes | ||||
| from lib.objects import Screenshots | ||||
| from lib.objects import Titles | ||||
| from lib.objects import UsersAccount | ||||
| from lib.objects import Usernames | ||||
|  | @ -98,8 +99,10 @@ def get_object(obj_type, subtype, obj_id): | |||
|             return Messages.Message(obj_id) | ||||
|         elif obj_type == 'ocr': | ||||
|             return Ocrs.Ocr(obj_id) | ||||
|         elif obj_type == 'qrcode': | ||||
|             return QrCodes.Qrcode(obj_id) | ||||
|         elif obj_type == 'screenshot': | ||||
|             return Screenshot(obj_id) | ||||
|             return Screenshots.Screenshot(obj_id) | ||||
|         elif obj_type == 'title': | ||||
|             return Titles.Title(obj_id) | ||||
|         else: | ||||
|  | @ -330,6 +333,8 @@ def obj_iterator(obj_type, filters): | |||
|         return get_all_decodeds_objects(filters=filters) | ||||
|     elif obj_type == 'image': | ||||
|         return Images.get_all_images_objects(filters=filters) | ||||
|     elif obj_type == 'screenshot': | ||||
|         return Screenshots.get_screenshots_obj_iterator(filters=filters) | ||||
|     elif obj_type == 'item': | ||||
|         return get_all_items_objects(filters=filters) | ||||
|     elif obj_type == 'pgp': | ||||
|  | @ -616,4 +621,4 @@ def get_chat_relationships_mentions_cord_graph(obj_type, subtype, obj_id): | |||
|     # print(r) | ||||
| 
 | ||||
|     # res = get_obj_correlations_objs('username', 'telegram', 'corona', lvl=100) | ||||
|     # print(res) | ||||
|     # print(res) | ||||
|  |  | |||
|  | @ -89,7 +89,7 @@ class Categ(AbstractModule): | |||
|         # Search for pattern categories in obj content | ||||
|         for categ, pattern in self.categ_words: | ||||
| 
 | ||||
|             if obj.type == 'message' or obj.type == 'ocr': | ||||
|             if obj.type == 'message' or obj.type == 'ocr' or obj.type == 'qrcode': | ||||
|                 self.add_message_to_queue(message='0', queue=categ) | ||||
|             else: | ||||
| 
 | ||||
|  |  | |||
|  | @ -133,6 +133,7 @@ class Global(AbstractModule): | |||
|             self.add_message_to_queue(obj=self.obj, queue='Item') | ||||
|         elif self.obj.type == 'image': | ||||
|             self.add_message_to_queue(obj=self.obj, queue='Image', message=message) | ||||
|             self.add_message_to_queue(obj=self.obj, queue='Images', message=message) | ||||
|         else: | ||||
|             self.logger.critical(f"Empty obj: {self.obj} {message} not processed") | ||||
| 
 | ||||
|  |  | |||
|  | @ -135,10 +135,10 @@ class Mail(AbstractModule): | |||
|     # # TODO: sanitize mails | ||||
|     def compute(self, message): | ||||
|         score = message | ||||
|         item = self.get_obj() | ||||
|         obj = self.get_obj() | ||||
|         item_date = item.get_date() | ||||
| 
 | ||||
|         mails = self.regex_findall(self.email_regex, item.id, item.get_content()) | ||||
|         mails = self.regex_findall(self.email_regex, obj.id, obj.get_content()) | ||||
|         mxdomains_email = {} | ||||
|         for mail in mails: | ||||
|             mxdomain = mail.rsplit('@', 1)[1].lower() | ||||
|  |  | |||
|  | @ -0,0 +1,108 @@ | |||
| #!/usr/bin/env python3 | ||||
| # -*-coding:UTF-8 -* | ||||
| """ | ||||
| The OcrExtractor Module | ||||
| ====================== | ||||
| 
 | ||||
| """ | ||||
| 
 | ||||
| ################################## | ||||
| # Import External packages | ||||
| ################################## | ||||
| import cv2 | ||||
| import os | ||||
| import sys | ||||
| 
 | ||||
| sys.path.append(os.environ['AIL_BIN']) | ||||
| ################################## | ||||
| # Import Project packages | ||||
| ################################## | ||||
| from modules.abstract_module import AbstractModule | ||||
| from lib.ConfigLoader import ConfigLoader | ||||
| from lib.objects import QrCodes | ||||
| 
 | ||||
| 
 | ||||
| class QrCodeReader(AbstractModule): | ||||
|     """ | ||||
|     QrCodeReader for AIL framework | ||||
|     """ | ||||
| 
 | ||||
|     def __init__(self): | ||||
|         super(QrCodeReader, self).__init__() | ||||
| 
 | ||||
|         # Waiting time in seconds between to message processed | ||||
|         self.pending_seconds = 1 | ||||
| 
 | ||||
|         config_loader = ConfigLoader() | ||||
|         self.r_cache = config_loader.get_redis_conn("Redis_Cache") | ||||
| 
 | ||||
|         # Send module state to logs | ||||
|         self.logger.info(f'Module {self.module_name} initialized') | ||||
| 
 | ||||
|     def is_cached(self): | ||||
|         return self.r_cache.exists(f'qrcode:no:{self.obj.type}:{self.obj.id}') | ||||
| 
 | ||||
|     def add_to_cache(self): | ||||
|         self.r_cache.setex(f'qrcode:no:{self.obj.type}:{self.obj.id}', 86400, 0) | ||||
| 
 | ||||
|     def extract_qrcode(self, path): | ||||
|         detector = cv2.QRCodeDetector()  # TODO Move me in init ??? | ||||
|         image = cv2.imread(path) | ||||
| 
 | ||||
|         # multiple extraction | ||||
|         try: | ||||
|             qr_found, contents, qarray, _ = detector.detectAndDecodeMulti(image) | ||||
|             if qr_found: | ||||
|                 return contents | ||||
|             else: | ||||
|                 # simple extraction | ||||
|                 content, box, _ = detector.detectAndDecode(image) | ||||
|                 if content: | ||||
|                     return [content] | ||||
|                 else: | ||||
|                     return [] | ||||
|         except cv2.error as e: | ||||
|             self.logger.error(f'{e}, {self.obj.get_global_id()}') | ||||
| 
 | ||||
|     def compute(self, message): | ||||
|         obj = self.get_obj() | ||||
| 
 | ||||
|         if self.is_cached(): | ||||
|             return None | ||||
| 
 | ||||
|         if obj.type == 'image': | ||||
|             if self.obj.is_gif(): | ||||
|                 self.logger.warning(f'Ignoring GIF: {self.obj.id}') | ||||
|                 return None | ||||
| 
 | ||||
|         # image - screenshot | ||||
|         path = self.obj.get_filepath() | ||||
|         contents = self.extract_qrcode(path) | ||||
|         if not contents: | ||||
|             # print('no qr code detected') | ||||
|             self.add_to_cache() | ||||
|             return None | ||||
| 
 | ||||
|         for content in contents: | ||||
|             print(content) | ||||
|             qr_code = QrCodes.create(content, self.obj)  # copy screenshot + image daterange | ||||
|             qr_code.add(qr_code.get_date(), self.obj) | ||||
| 
 | ||||
|             for obj_type in ['chat', 'domain', 'message']:  # TODO ITEM ??? | ||||
|                 for c_id in self.obj.get_correlation(obj_type).get(obj_type, []): | ||||
|                     o_subtype, o_id = c_id.split(':', 1) | ||||
|                     qr_code.add_correlation(obj_type, o_subtype, o_id) | ||||
| 
 | ||||
|             tag = 'infoleak:automatic-detection="qrcode"' | ||||
|             self.add_message_to_queue(obj=self.obj, message=tag, queue='Tags') | ||||
| 
 | ||||
|             # TODO only if new ??? | ||||
|             self.add_message_to_queue(obj=qr_code, queue='Item') | ||||
| 
 | ||||
| 
 | ||||
| if __name__ == '__main__': | ||||
|     module = QrCodeReader() | ||||
|     module.run() | ||||
|     # from lib.objects.Images import Image | ||||
|     # module.obj = Image('8a690f4d09509dbfe52a6fb139db500b16b3d5f07e22617944752c4d4885737c') | ||||
|     # module.compute(None) | ||||
|  | @ -1,7 +1,7 @@ | |||
| ######## IMPORTERS ######## | ||||
| 
 | ||||
| [Crawler] | ||||
| publish = Importers,Tags | ||||
| publish = Importers,Tags,Images | ||||
| 
 | ||||
| [ZMQModuleImporter] | ||||
| publish = Importers | ||||
|  | @ -29,7 +29,7 @@ publish = Importers,Tags | |||
| 
 | ||||
| [Global] | ||||
| subscribe = SaveObj | ||||
| publish = Item,Image | ||||
| publish = Item,Image,Images | ||||
| 
 | ||||
| ######## ITEM + MESSAGE ######## | ||||
| 
 | ||||
|  | @ -156,7 +156,7 @@ publish = Tags | |||
| #[Sync_module] | ||||
| #publish = Sync | ||||
| 
 | ||||
| ######## IMAGE ######## | ||||
| ######## IMAGE ######## image | ||||
| 
 | ||||
| [Exif] | ||||
| subscribe = Image | ||||
|  | @ -166,6 +166,12 @@ publish = Tags | |||
| subscribe = Image | ||||
| publish = Item | ||||
| 
 | ||||
| ######## IMAGES ######## images + screenshots | ||||
| 
 | ||||
| [QrCodeReader] | ||||
| subscribe = Images | ||||
| publish = Item,Tags | ||||
| 
 | ||||
| ######## CORE ######## | ||||
| 
 | ||||
| [Tags] | ||||
|  |  | |||
|  | @ -31,10 +31,12 @@ from lib.objects import ail_objects | |||
| 
 | ||||
| from modules.Languages import Languages | ||||
| from modules.OcrExtractor import OcrExtractor | ||||
| from modules.QrCodeReader import QrCodeReader | ||||
| 
 | ||||
| MODULES = { | ||||
|     'Languages': Languages, | ||||
|     'OcrExtractor': OcrExtractor | ||||
|     'OcrExtractor': OcrExtractor, | ||||
|     'QrCodeReader': QrCodeReader | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
|  | @ -68,7 +70,7 @@ if __name__ == "__main__": | |||
|     obj_type = args.type | ||||
|     if not is_object_type(obj_type): | ||||
|         raise Exception(f'Invalid Object Type: {obj_type}') | ||||
|     if obj_type not in ['image', 'item', 'message']: | ||||
|     if obj_type not in ['image', 'item', 'message', 'screenshot']: | ||||
|         raise Exception(f'Currently not supported Object Type: {obj_type}') | ||||
| 
 | ||||
|     modulename = args.module | ||||
|  |  | |||
|  | @ -57,6 +57,7 @@ from blueprints.objects_hhhash import objects_hhhash | |||
| from blueprints.chats_explorer import chats_explorer | ||||
| from blueprints.objects_image import objects_image | ||||
| from blueprints.objects_ocr import objects_ocr | ||||
| from blueprints.objects_qrcode import objects_qrcode | ||||
| from blueprints.objects_favicon import objects_favicon | ||||
| from blueprints.api_rest import api_rest | ||||
| 
 | ||||
|  | @ -140,6 +141,7 @@ app.register_blueprint(objects_hhhash, url_prefix=baseUrl) | |||
| app.register_blueprint(chats_explorer, url_prefix=baseUrl) | ||||
| app.register_blueprint(objects_image, url_prefix=baseUrl) | ||||
| app.register_blueprint(objects_ocr, url_prefix=baseUrl) | ||||
| app.register_blueprint(objects_qrcode, url_prefix=baseUrl) | ||||
| app.register_blueprint(objects_favicon, url_prefix=baseUrl) | ||||
| app.register_blueprint(api_rest, url_prefix=baseUrl) | ||||
| 
 | ||||
|  |  | |||
|  | @ -0,0 +1,101 @@ | |||
| #!/usr/bin/env python3 | ||||
| # -*-coding:UTF-8 -* | ||||
| 
 | ||||
| ''' | ||||
|     Blueprint Flask: crawler splash endpoints: dashboard, onion crawler ... | ||||
| ''' | ||||
| 
 | ||||
| import json | ||||
| import os | ||||
| import sys | ||||
| 
 | ||||
| from io import BytesIO | ||||
| 
 | ||||
| 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 | ||||
| 
 | ||||
| # Import Role_Manager | ||||
| from Role_Manager import login_admin, login_read_only, no_cache | ||||
| 
 | ||||
| sys.path.append(os.environ['AIL_BIN']) | ||||
| ################################## | ||||
| # Import Project packages | ||||
| ################################## | ||||
| from lib import Language | ||||
| from lib import Tag | ||||
| from lib.objects import QrCodes | ||||
| 
 | ||||
| from packages import Date | ||||
| 
 | ||||
| # ============ BLUEPRINT ============ | ||||
| objects_qrcode = Blueprint('objects_qrcode', __name__, template_folder=os.path.join(os.environ['AIL_FLASK'], 'templates/objects/qrcode')) | ||||
| 
 | ||||
| # ============ VARIABLES ============ | ||||
| bootstrap_label = ['primary', 'success', 'danger', 'warning', 'info'] | ||||
| 
 | ||||
| def create_json_response(data, status_code): | ||||
|     return Response(json.dumps(data, indent=2, sort_keys=True), mimetype='application/json'), status_code | ||||
| 
 | ||||
| # ============ FUNCTIONS ============ | ||||
| 
 | ||||
| @objects_qrcode.route("/objects/qrcodes", methods=['GET']) | ||||
| @login_required | ||||
| @login_read_only | ||||
| def objects_qrcodes(): | ||||
|     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 = QrCodes.Qrcodes().api_get_meta_by_daterange(date_from, date_to) | ||||
|     else: | ||||
|         dict_objects = {} | ||||
| 
 | ||||
|     return render_template("QrcodeDaterange.html", date_from=date_from, date_to=date_to, | ||||
|                            dict_objects=dict_objects, show_objects=show_objects) | ||||
| 
 | ||||
| 
 | ||||
| @objects_qrcode.route("/objects/qrcodes/post", methods=['POST']) | ||||
| @login_required | ||||
| @login_read_only | ||||
| def objects_qrcodes_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_qrcode.objects_qrcodes', date_from=date_from, date_to=date_to, show_objects=show_objects)) | ||||
| 
 | ||||
| 
 | ||||
| @objects_qrcode.route("/objects/qrcodes/range/json", methods=['GET']) | ||||
| @login_required | ||||
| @login_read_only | ||||
| def objects_qrcodes_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(QrCodes.Qrcodes().api_get_chart_nb_by_daterange(date_from, date_to)) | ||||
| 
 | ||||
| 
 | ||||
| @objects_qrcode.route("/objects/qrcodes", methods=['GET']) | ||||
| @login_required | ||||
| @login_read_only | ||||
| def object_qrcode(): | ||||
|     obj_id = request.args.get('id') | ||||
|     meta = QrCodes.api_get_qrcode(obj_id) | ||||
|     if meta[1] != 200: | ||||
|         return create_json_response(meta[0], meta[1]) | ||||
|     else: | ||||
|         meta = meta[0] | ||||
|         languages = Language.get_translation_languages() | ||||
|         return render_template("ShowQrcode.html", meta=meta, | ||||
|                                bootstrap_label=bootstrap_label, | ||||
|                                ail_tags=Tag.get_modal_add_tags(meta['id'], meta['type'], meta['subtype']), | ||||
|                                translation_languages=languages, translation_target=target) | ||||
| 
 | ||||
| 
 | ||||
| # ============= ROUTES ============== | ||||
| 
 | ||||
|  | @ -299,7 +299,6 @@ def tags_search_messages(): | |||
| def tags_search_images(): | ||||
|     object_type = 'image' | ||||
|     dict_tagged = {"object_type": object_type, "object_name": object_type.title() + "s"} | ||||
|     dict_tagged['date'] = Date.sanitise_date_range('', '', separator='-') | ||||
|     return render_template("tags/search_obj_by_tags.html", bootstrap_label=bootstrap_label, dict_tagged=dict_tagged) | ||||
| 
 | ||||
| @tags_ui.route('/tag/search/ocr') | ||||
|  | @ -308,7 +307,6 @@ def tags_search_images(): | |||
| def tags_search_ocrs(): | ||||
|     object_type = 'ocr' | ||||
|     dict_tagged = {"object_type": object_type, "object_name": object_type.title() + "s"} | ||||
|     dict_tagged['date'] = Date.sanitise_date_range('', '', separator='-') | ||||
|     return render_template("tags/search_obj_by_tags.html", bootstrap_label=bootstrap_label, dict_tagged=dict_tagged) | ||||
| 
 | ||||
| @tags_ui.route('/tag/search/domain') | ||||
|  |  | |||
|  | @ -132,6 +132,8 @@ | |||
| 						{% include 'chats_explorer/card_image.html' %} | ||||
|                     {% elif dict_object["object_type"] == "ocr" %} | ||||
| 						{% include 'objects/ocr/card_ocr.html' %} | ||||
|                     {% elif dict_object["object_type"] == "qrcode" %} | ||||
| 						{% include 'objects/qrcode/card_qrcode.html' %} | ||||
| 					{% elif dict_object["object_type"] == "item" %} | ||||
| 						{% include 'correlation/metadata_card_item.html' %} | ||||
|                     {% elif dict_object["object_type"] == "favicon" %} | ||||
|  | @ -319,6 +321,10 @@ | |||
|                                                 <input class="form-check-input" type="checkbox" value="True" id="ocr_Check" name="ocr_Check" {%if "ocr" in dict_object["filter"]%}checked{%endif%}> | ||||
|                                                 <label class="form-check-label" for="ocr_Check">OCR</label> | ||||
|                                             </div> | ||||
|                                             <div class="form-check"> | ||||
|                                                 <input class="form-check-input" type="checkbox" value="True" id="qrcode_Check" name="qrcode_Check" {%if "qrcode" in dict_object["filter"]%}checked{%endif%}> | ||||
|                                                 <label class="form-check-label" for="qrcode_Check">Qrcode</label> | ||||
|                                             </div> | ||||
| 
 | ||||
|                                             <hr> | ||||
|                                             <div class="form-check"> | ||||
|  |  | |||
|  | @ -140,9 +140,13 @@ | |||
|                                                         <input class="custom-control-input" type="checkbox" name="message_obj" id="message_obj" {% if not dict_tracker['filters'] or 'message' in dict_tracker['filters'] %}checked=""{% endif %}> | ||||
|                                                         <label class="custom-control-label" for="message_obj"><i class="fas fa-comment-dots"></i> Message <i class="fas fa-info-circle text-info" data-toggle="tooltip" data-placement="right" title="Messages from Chats"></i></label> | ||||
|                                                     </div> | ||||
|                                                     <div class="custom-control custom-switch mt-1"> | ||||
|                                                         <input class="custom-control-input" type="checkbox" name="qrcode_obj" id="qrcode_obj" {% if not dict_tracker['filters'] or 'qrcode' in dict_tracker['filters'] %}checked=""{% endif %}> | ||||
|                                                         <label class="custom-control-label" for="qrcode_obj"><i class="fas fa-qrcode"></i> Qrcode <i class="fas fa-info-circle text-info" data-toggle="tooltip" data-placement="right" title="Qcodes Extracted from Images ans Screenshots"></i></label> | ||||
|                                                     </div> | ||||
|                                                     <div class="custom-control custom-switch mt-1"> | ||||
|                                                         <input class="custom-control-input" type="checkbox" name="ocr_obj" id="ocr_obj" {% if not dict_tracker['filters'] or 'ocr' in dict_tracker['filters'] %}checked=""{% endif %}> | ||||
|                                                         <label class="custom-control-label" for="ocr_obj"><i class="fas fa-comment-dots"></i> OCR <i class="fas fa-expand text-info" data-toggle="tooltip" data-placement="right" title="Text extracted from Images"></i></label> | ||||
|                                                         <label class="custom-control-label" for="ocr_obj"><i class="fas fa-expand"></i> OCR <i class="fas fa-info-circle text-info" data-toggle="tooltip" data-placement="right" title="Text extracted from Images"></i></label> | ||||
|                                                     </div> | ||||
| 
 | ||||
| {#                                                    <div class="custom-control custom-switch mt-1">#} | ||||
|  |  | |||
|  | @ -0,0 +1,167 @@ | |||
| <link href="{{ url_for('static', filename='css/tags.css') }}" rel="stylesheet" type="text/css" /> | ||||
| <script src="{{ url_for('static', filename='js/tags.js') }}"></script> | ||||
| 
 | ||||
| {% with modal_add_tags=ail_tags %} | ||||
| 	{% include 'modals/add_tags.html' %} | ||||
| {% endwith %} | ||||
| 
 | ||||
| {% include 'modals/edit_tag.html' %} | ||||
| 
 | ||||
| <style> | ||||
|     .object_image { | ||||
|         filter: blur(5px); | ||||
|     } | ||||
| </style> | ||||
| 
 | ||||
| <div class="card my-1"> | ||||
| 	<div class="card-header"> | ||||
| 		<h4 class="text-secondary">{{ meta["id"] }} :</h4> | ||||
| 		<ul class="list-group mb-2"> | ||||
|             <li class="list-group-item py-0"> | ||||
|                 <table class="table"> | ||||
|                     <tbody style="font-size: 15px;"> | ||||
|                     <tr> | ||||
|                         <td> | ||||
|                             <svg height="26" width="26"> | ||||
|                                 <g class="nodes"> | ||||
|                                     <circle cx="13" cy="13" r="13" fill="orange"></circle> | ||||
|                                     <text x="13" y="13" text-anchor="middle" dominant-baseline="central" class="{{ meta["svg_icon"]["style"] }}" font-size="16px">{{ meta["svg_icon"]["icon"] }}</text> | ||||
|                                 </g> | ||||
|                             </svg> | ||||
|                             {{ meta['type'] }} | ||||
|                         </td> | ||||
|                         <td><b>First Seen:</b> {% if meta['first_seen'] %}{{ meta['first_seen'][0:4] }}-{{ meta['first_seen'][4:6] }}-{{ meta['first_seen'][6:8] }}{% endif %}</td> | ||||
|                         <td><b>Last Seen:</b> {% if meta['last_seen'] %}{{ meta['last_seen'][0:4] }}-{{ meta['last_seen'][4:6] }}-{{ meta['last_seen'][6:8] }}{% endif %}</td> | ||||
|                     </tr> | ||||
|                     </tbody> | ||||
|                 </table> | ||||
|             </li> | ||||
| 			<li class="list-group-item py-0"> | ||||
| 				<div id="accordion_image" class="my-3"> | ||||
|                     <div class="card"> | ||||
|                         <div class="card-header py-1" id="headingImage"> | ||||
|                             <button class="btn w-100 collapsed rotate" data-toggle="collapse" data-target="#collapseImage" aria-expanded="false" aria-controls="collapseImage"> | ||||
|                                 <span class="row text-left"> | ||||
|                                     <div class="col-11"> | ||||
|                                         <span class="mt-2"> | ||||
|                                             <i class="far fa-image"></i> Show Image   | ||||
|                                         </span> | ||||
|                                     </div> | ||||
|                                     <div class="col-1 text-primary"> | ||||
|                                         <i class="fas fa-chevron-circle-down"></i> | ||||
|                                     </div> | ||||
|                                 </span> | ||||
|                             </button> | ||||
|                         </div> | ||||
|                         <div id="collapseImage" class="collapse show" aria-labelledby="headingImage" data-parent="#accordion_image"> | ||||
|                             <div class="card-body text-center"> | ||||
|                                 {% include 'objects/image/block_blur_img_slider.html' %} | ||||
| 
 | ||||
| 								<img class="object_image mb-1" usemap="#image-map" src="{{ url_for('objects_ocr.ocr_image', filename=meta['id'])}}"> | ||||
|                                 <map name="image-map"> | ||||
|                                     {% for c in meta['map'] %} | ||||
|                                         <area shape="poly" coords="{{ c[0] }}" title="{{ c[1] }}"> | ||||
|                                     {% endfor %} | ||||
|                                 </map> | ||||
|                             </div> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </div> | ||||
| 			</li> | ||||
|             <li class="list-group-item py-0"> | ||||
|                 <pre class="my-0" style="white-space: pre-wrap;">{{ meta['content'] }}</pre> | ||||
|                 {% if meta['translation'] %} | ||||
|                     <hr class="m-1"> | ||||
|                     <pre class="my-0 text-secondary" style="white-space: pre-wrap;">{{ meta['translation'] }}</pre> | ||||
|                {% endif %} | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|                 {% if not is_correlation %} | ||||
|                     <div class="my-1"> | ||||
| 
 | ||||
|                         {% set mess_id_escape= meta['id'] | replace("/", "_") %} | ||||
|                         <span class="btn btn-outline-dark p-0 px-1" type="button" data-toggle="collapse" data-target="#collapseTrans{{ mess_id_escape }}" aria-expanded="false" aria-controls="collapseTrans{{ mess_id_escape }}"> | ||||
|                             <i class="fas fa-language"></i> {% if meta['language'] %}{{ meta['language'] }}{% endif %} | ||||
|                         </span> | ||||
|                         <div class="collapse" id="collapseTrans{{ mess_id_escape }}"> | ||||
|                             <div class="card card-body"> | ||||
|                                 <form method="post" action="{{ url_for('languages_ui.translate_object') }}"> | ||||
|                                     <input type="text" id="type" name="type" value="{{meta['type']}}" hidden> | ||||
|                                     <input type="text" id="id" name="id" value="{{meta['id']}}" hidden> | ||||
|                                     <span class="badge badge-primary">Source:</span> | ||||
|                                     <span class=""> | ||||
|                                         <select id="language_target" name="language_target" class="form-select" aria-label="Message Language" onchange="$('#translation').val('');"> | ||||
|                                                 <option selected value="{{ meta['language'] }}">{{ meta['language'] }}</option> | ||||
|                                             {% for language in translation_languages %} | ||||
|                                                 <option value="{{ language }}">{{ translation_languages[language] }}</option> | ||||
|                                             {% endfor %} | ||||
|                                         </select> | ||||
|                                     </span> | ||||
|                                     {% if translation_target %} | ||||
|                                         <input type="text" id="target" name="target" value="{{translation_target}}" hidden> | ||||
|                                             <span class="badge badge-primary">Target:</span><span>{{translation_target}}</span> | ||||
|                                         <textarea class="form-control" id="translation" name="translation">{{ meta['translation'] }}</textarea> | ||||
|                                         <button class="btn btn-dark" type="submit"> | ||||
|                                             <i class="fas fa-pen-alt"> Update Language or Translation</i> | ||||
|                                         </button> | ||||
|                                     {% else %} | ||||
|                                         <button class="btn btn-dark" type="submit"> | ||||
|                                             <i class="fas fa-pen-alt"> Update Language</i> | ||||
|                                         </button> | ||||
|                                     {% endif %} | ||||
|                                 </form> | ||||
|                                 <div> | ||||
|                                     <a class="btn btn-primary" href="{{ url_for('languages_ui.detect_object_language')}}?type={{ meta['type'] }}&id={{ meta['id'] }}"> | ||||
|                                         <i class="fas fa-redo"></i> Detect Language | ||||
|                                     </a> | ||||
|                                 </div> | ||||
|                             </div> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 {% endif %} | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|             </li> | ||||
| 
 | ||||
| 			<li class="list-group-item py-0"> | ||||
| 				<div class="my-2"> | ||||
| 					Tags: | ||||
| 					{% for tag in meta['tags'] %} | ||||
|                         <button class="btn btn-{{ bootstrap_label[loop.index0 % 5] }}" | ||||
|                                 data-toggle="modal" data-target="#edit_tags_modal" | ||||
| 						        data-tagid="{{ tag }}" data-objtype="{{ meta['type'] }}" data-objsubtype="" data-objid="{{ meta["id"] }}"> | ||||
|                                 {{ tag }} | ||||
| 						</button> | ||||
| 					{%  endfor %} | ||||
| 					<button type="button" class="btn btn-light" data-toggle="modal" data-target="#add_tags_modal"> | ||||
|                         <i class="far fa-plus-square"></i> | ||||
|                     </button> | ||||
| 				</div> | ||||
| 			</li> | ||||
| 		</ul> | ||||
| 
 | ||||
| 		{% with obj_type='ocr', obj_id=meta['id'], obj_subtype='' %} | ||||
| 			{% include 'modals/investigations_register_obj.html' %} | ||||
| 		{% endwith %} | ||||
| 		<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#investigations_register_obj_modal"> | ||||
| 			<i class="fas fa-microscope"></i> Investigations | ||||
| 		</button> | ||||
| 
 | ||||
|         <span class="mb-2 float-right"> | ||||
|             {% if is_correlation %} | ||||
|                 <a href="{{ url_for('objects_ocr.object_ocr')}}?subtype={{ meta['subtype'] }}&id={{ meta['id'] }}"> | ||||
|                     <button class="btn btn-info"><i class="fas fa-expand"></i> Show Object</button> | ||||
|                 </a> | ||||
|             {% else %} | ||||
|                 <a href="{{ url_for('correlation.show_correlation')}}?type={{ meta['type'] }}&subtype={{ meta['subtype'] }}&id={{ meta['id'] }}"> | ||||
|                     <button class="btn btn-info"><i class="far fa-eye"></i> Correlations   | ||||
|                     </button> | ||||
|                 </a> | ||||
|             {% endif %} | ||||
|         </span> | ||||
| 
 | ||||
| 	</div> | ||||
| </div> | ||||
|  | @ -0,0 +1,607 @@ | |||
| <!DOCTYPE html> | ||||
| <html> | ||||
| 
 | ||||
| <head> | ||||
|   <title>Qrcodes - 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/dataTables.bootstrap.min.css') }}" rel="stylesheet"> | ||||
| 	<link href="{{ url_for('static', filename='css/daterangepicker.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 src="{{ url_for('static', filename='js/moment.min.js') }}"></script> | ||||
| 	<script src="{{ url_for('static', filename='js/jquery.daterangepicker.min.js') }}"></script> | ||||
| 	<script src="{{ url_for('static', filename='js/d3.min.js') }}"></script> | ||||
|     <script src="{{ url_for('static', filename='js/d3/sparklines.js')}}"></script> | ||||
| 
 | ||||
| 	<style> | ||||
| 		.input-group .form-control { | ||||
| 			position: unset; | ||||
| 		} | ||||
| 		.line { | ||||
|   		fill: none; | ||||
|   		stroke: #000; | ||||
|   		stroke-width: 2.0px; | ||||
| 		} | ||||
| 		.bar { | ||||
|       fill: steelblue; | ||||
|     } | ||||
|     .bar:hover{ | ||||
|       fill: brown; | ||||
| 			cursor: pointer; | ||||
|     } | ||||
| 		.bar_stack:hover{ | ||||
| 			cursor: pointer; | ||||
|     } | ||||
| 		.pie_path:hover{ | ||||
| 			cursor: pointer; | ||||
| 		} | ||||
| 		.svgText { | ||||
|   		pointer-events: none; | ||||
| 		} | ||||
| 		div.tooltip { | ||||
| 			position: absolute; | ||||
| 			text-align: center; | ||||
| 			padding: 2px; | ||||
| 			font: 12px sans-serif; | ||||
| 			background: #ebf4fb; | ||||
| 			border: 2px solid #b7ddf2; | ||||
| 			border-radius: 8px; | ||||
| 			pointer-events: none; | ||||
| 			color: #000000; | ||||
| 		} | ||||
| 	</style> | ||||
| </head> | ||||
| <body> | ||||
| 
 | ||||
| 	{% include 'nav_bar.html' %} | ||||
| 
 | ||||
| 	<div class="container-fluid"> | ||||
| 		<div class="row"> | ||||
| 
 | ||||
| 			{% include 'sidebars/sidebar_objects.html' %} | ||||
| 
 | ||||
| 			<div class="col-12 col-lg-10" id="core_content"> | ||||
| 
 | ||||
| 				<div class="row"> | ||||
| 					<div class="col-xl-10"> | ||||
| 						<div class="mt-1" id="barchart_type"></div> | ||||
| 
 | ||||
| {#                        {% include 'image/block_images_search.html' %}#} | ||||
| 
 | ||||
|                     </div> | ||||
| 
 | ||||
| 
 | ||||
| 					<div class="col-xl-2"> | ||||
| 
 | ||||
| 						<div class="card mb-3 mt-2" style="background-color:#d9edf7;"> | ||||
| 						  <div class="card-body text-center py-2"> | ||||
| 						    <h6 class="card-title" style="color:#286090;">Select a date range :</h6> | ||||
| 								<form action="{{ url_for('objects_qrcode.objects_qrcodes_post') }}" id="hash_selector_form" method='post'> | ||||
| 									<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" value="{{ date_from }}" name="date_from" autocomplete="off"> | ||||
| 									</div> | ||||
| 									<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" value="{{ date_to }}" name="date_to" autocomplete="off"> | ||||
| 									</div> | ||||
| 									<div class="form-check my-1"> | ||||
| 										<input class="form-check-input" type="checkbox" id="checkbox-input-show" name="show_objects" value="True" {% if show_objects %}checked{% endif %}> | ||||
| 										<label class="form-check-label" for="checkbox-input-show"> | ||||
| 											<span style="color:#286090; font-size: 14px;"> | ||||
| 												Show Qrcodes <i class="fas fa-key"></i> | ||||
| 											</span> | ||||
| 										</label> | ||||
| 									</div> | ||||
| 									<button class="btn btn-primary" style="text-align:center;"> | ||||
| 										<i class="fas fa-copy"></i> Search | ||||
| 									</button> | ||||
| 								</form> | ||||
| 						  </div> | ||||
| 						</div> | ||||
| 
 | ||||
| 						<div id="pie_chart_encoded"> | ||||
| 						</div> | ||||
| 						<div id="pie_chart_top5_types"> | ||||
| 						</div> | ||||
| 					</div> | ||||
| 				</div> | ||||
| 
 | ||||
| 				{% if dict_objects %} | ||||
|                     {% if date_from|string == date_to|string %} | ||||
|                         <h3> {{ date_from }} Qrcodes Name: </h3> | ||||
|                     {% else %} | ||||
|                         <h3> {{ date_from }} to {{ date_to }} Qrcodes Name: </h3> | ||||
|                     {% endif %} | ||||
|                     <table id="tableb64" class="table table-striped table-bordered"> | ||||
|                         <thead class="bg-dark text-white"> | ||||
|                         <tr> | ||||
|                             <th></th> | ||||
|                             <th>First Seen</th> | ||||
|                             <th>Last Seen</th> | ||||
|                             <th>Total</th> | ||||
|                             <th>Last days</th> | ||||
|                         </tr> | ||||
|                         </thead> | ||||
| 						<tbody style="font-size: 15px;"> | ||||
|                         {% for obj_id in dict_objects %} | ||||
|                             <tr> | ||||
|                                 <td style="word-break: break-all;"> | ||||
|                                     <a target="_blank" href="{{ url_for('correlation.show_correlation') }}?type=qrcode&id={{ obj_id }}">{{ dict_objects[obj_id]['id'] }}</a> | ||||
|                                     {% if dict_objects[obj_id]['content'] %} | ||||
|                                         <div><small>{{ dict_objects[obj_id]['content'] }}</small></div> | ||||
|                                     {% endif %} | ||||
|                                 </td> | ||||
|                                 <td>{{ dict_objects[obj_id]['first_seen'] }}</td> | ||||
|                                 <td>{{ dict_objects[obj_id]['last_seen'] }}</td> | ||||
|                                 <td>{{ dict_objects[obj_id]['nb_seen'] }}</td> | ||||
|                                 <td id="sparklines_{{ obj_id }}" style="text-align:center;"></td> | ||||
|                             </tr> | ||||
|                         {% endfor %} | ||||
|                         </tbody> | ||||
|                     </table> | ||||
| 
 | ||||
| 
 | ||||
|                 {% else %} | ||||
|                     {% if show_objects %} | ||||
|                         {% if date_from|string == date_to|string %} | ||||
| 							<h3> {{ date_from }}, No Qrcode</h3> | ||||
|                         {% else %} | ||||
| 							<h3> {{ date_from }} to {{ date_to }}, No Qrcode</h3> | ||||
|                         {% endif %} | ||||
|                     {% endif %} | ||||
|                 {% endif %} | ||||
|             </div> | ||||
| 
 | ||||
|         </div> | ||||
|     </div> | ||||
| 
 | ||||
| <script> | ||||
|     var chart = {}; | ||||
|     $(document).ready(function(){ | ||||
|         $("#page-Decoded").addClass("active"); | ||||
|         $("#nav_qrcode").addClass("active"); | ||||
| 
 | ||||
|         $('#date-range-from').dateRangePicker({ | ||||
|             separator : ' to ', | ||||
|             getValue: function() | ||||
|             { | ||||
|                 if ($('#date-range-from-input').val() && $('#date-range-to').val() ) | ||||
|                     return $('#date-range-from-input').val() + ' to ' + $('#date-range-to').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').val() ) | ||||
|                     return $('#date-range-from-input').val() + ' to ' + $('#date-range-to').val(); | ||||
|                 else | ||||
|                     return ''; | ||||
|             }, | ||||
|             setValue: function(s,s1,s2) | ||||
|             { | ||||
|                 $('#date-range-from-input').val(s1); | ||||
|                 $('#date-range-to-input').val(s2); | ||||
|             }, | ||||
|         }); | ||||
| 
 | ||||
|         $('#date-range-from').data('dateRangePicker').setDateRange('{{date_from}}','{{date_to}}'); | ||||
|         $('#date-range-to').data('dateRangePicker').setDateRange('{{date_from}}','{{date_to}}'); | ||||
| 
 | ||||
|         $('#tableb64').DataTable({ | ||||
|             "aLengthMenu": [[5, 10, 15, -1], [5, 10, 15, "All"]], | ||||
|             "iDisplayLength": 10, | ||||
|             "order": [[ 3, "desc" ]] | ||||
|         }); | ||||
| 
 | ||||
| 
 | ||||
|         chart.stackBarChart = barchart_type_stack("{{ url_for('objects_qrcode.objects_qrcodes_range_json') }}?date_from={{date_from}}&date_to={{date_to}}", 'id'); | ||||
| 
 | ||||
| 
 | ||||
|         chart.onResize(); | ||||
|         $(window).on("resize", function() { | ||||
|             chart.onResize(); | ||||
|         }); | ||||
|   }); | ||||
| 
 | ||||
| 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') | ||||
| 	} | ||||
| } | ||||
| </script> | ||||
| 
 | ||||
| <script> | ||||
| 	{% for obj_id in dict_objects %} | ||||
|     sparkline("sparklines_{{ obj_id }}", {{ dict_objects[obj_id]['sparkline'] }}, {}); | ||||
| 	{% endfor %} | ||||
| </script> | ||||
| 
 | ||||
| <script> | ||||
| var margin = {top: 20, right: 100, bottom: 55, left: 45}, | ||||
| 				width  = 1000 - margin.left - margin.right, | ||||
| 				height = 500  - margin.top  - margin.bottom; | ||||
| var x = d3.scaleBand().rangeRound([0, width]).padding(0.1); | ||||
| 
 | ||||
| var y = d3.scaleLinear().rangeRound([height, 0]); | ||||
| 
 | ||||
| var xAxis = d3.axisBottom(x); | ||||
| 
 | ||||
| var yAxis = d3.axisLeft(y); | ||||
| 
 | ||||
| var color = d3.scaleOrdinal(d3.schemeSet3); | ||||
| 
 | ||||
| var svg = d3.select("#barchart_type").append("svg") | ||||
| 				.attr("id", "thesvg") | ||||
| 				.attr("viewBox", "0 0 1000 500") | ||||
| 				.attr("width",  width  + margin.left + margin.right) | ||||
| 				.attr("height", height + margin.top  + margin.bottom) | ||||
| 			.append("g") | ||||
| 				.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); | ||||
| 
 | ||||
| function barchart_type_stack(url, id) { | ||||
| 
 | ||||
|   d3.json(url) | ||||
|     .then(function(data){ | ||||
| 
 | ||||
| 			var labelVar = 'date';  //A | ||||
| 		  var varNames = d3.keys(data[0]) | ||||
| 		      .filter(function (key) { return key !== labelVar;}); //B | ||||
| 
 | ||||
| 		  data.forEach(function (d) { //D | ||||
| 		    var y0 = 0; | ||||
| 		    d.mapping = varNames.map(function (name) { | ||||
| 		      return { | ||||
| 		        name: name, | ||||
| 		        label: d[labelVar], | ||||
| 		        y0: y0, | ||||
| 		        y1: y0 += +d[name] | ||||
| 		      }; | ||||
| 		    }); | ||||
| 		    d.total = d.mapping[d.mapping.length - 1].y1; | ||||
| 		  }); | ||||
| 
 | ||||
| 		  x.domain(data.map(function (d) { return (d.date); })); //E | ||||
| 		  y.domain([0, d3.max(data, function (d) { return d.total; })]); | ||||
| 
 | ||||
| 			svg.append("g") | ||||
|         .attr("class", "x axis") | ||||
|         .attr("transform", "translate(0," + height + ")") | ||||
|         .call(xAxis) | ||||
| 				.selectAll("text") | ||||
| 					.attr("class", "bar") | ||||
| 					{% if  date_from|string == date_to|string and type is none %} | ||||
| 						.on("click", function (d) { window.location.href = "{{ url_for('objects_qrcode.objects_qrcodes') }}?date_from={{date_from}}&date_to={{date_to}}&type_id="+d }) | ||||
| 						.attr("transform", "rotate(-18)" ) | ||||
| 					{% elif  date_from|string == date_to|string and type is not none %} | ||||
| 						.on("click", function (d) { window.location.href = "{{ url_for('objects_qrcode.objects_qrcodes') }}?date_from="+d+'&date_to='+d }) | ||||
| 						.attr("transform", "rotate(-18)" ) | ||||
| 					{% else %} | ||||
| 						.on("click", function (d) { window.location.href = "{{ url_for('objects_qrcode.objects_qrcodes') }}?date_from="+d+'&date_to='+d }) | ||||
| 						.attr("transform", "rotate(-40)" ) | ||||
| 					{% endif %} | ||||
| 					.style("text-anchor", "end"); | ||||
| 
 | ||||
|     	svg.append("g") | ||||
|         .attr("class", "y axis") | ||||
|         .call(yAxis) | ||||
|       	.append("text") | ||||
|         	.attr("transform", "rotate(-90)") | ||||
|         	.attr("y", 6) | ||||
|         	.attr("dy", ".71em") | ||||
|         	.style("text-anchor", "end"); | ||||
| 
 | ||||
| 			var selection = svg.selectAll(".series") | ||||
| 		    .data(data) | ||||
| 		    .enter().append("g") | ||||
| 		      .attr("class", "series") | ||||
| 		      .attr("transform", function (d) { return "translate(" + x((d.date)) + ",0)"; }); | ||||
| 
 | ||||
| 			selection.selectAll("rect") | ||||
| 	      .data(function (d) { return d.mapping; }) | ||||
| 	    .enter().append("rect") | ||||
| 				.attr("class", "bar_stack") | ||||
| 	      .attr("width", x.bandwidth()) | ||||
| 	      .attr("y", function (d) { return y(d.y1); }) | ||||
| 	      .attr("height", function (d) { return y(d.y0) - y(d.y1); }) | ||||
| 	      .style("fill", function (d) { return color(d.name); }) | ||||
| 	      .style("stroke", "grey") | ||||
| 	      .on("mouseover", function (d) { showPopover.call(this, d); }) | ||||
| 				.on("mouseout", function (d) { removePopovers(); }) | ||||
| 				{% if  date_from|string == date_to|string and type is none %} | ||||
| 					.on("click", function(d){ window.location.href = "{{ url_for('objects_qrcode.objects_qrcodes') }}" +'?date_from={{date_from}}&date_to={{date_to}}&type_id='+d.label+'&encoding='+d.name; }); | ||||
| 				{% elif  date_from|string == date_to|string and type is not none %} | ||||
| 					.on("click", function(d){ window.location.href = "{{ url_for('objects_qrcode.objects_qrcodes') }}" +'?type_id={{type_id}}&date_from='+d.label+'&date_to='+d.label+'&encoding='+d.name; }); | ||||
| 				{% else %} | ||||
| 					.on("click", function(d){ window.location.href = "{{ url_for('objects_qrcode.objects_qrcodes') }}" +'?type_id='+ d.name +'&date_from='+d.label+'&date_to='+d.label; }); | ||||
| 				{% endif %} | ||||
| 
 | ||||
| 				data.forEach(function(d) { | ||||
| 					if(d.total !== 0){ | ||||
| 						svg.append("text") | ||||
| 								.attr("class", "bar") | ||||
| 								.attr("dy", "-.35em") | ||||
| 								.attr('x', x(d.date) + x.bandwidth()/2) | ||||
| 								.attr('y', y(d.total)) | ||||
| 								{% if  date_from|string == date_to|string and type is none %} | ||||
| 									.on("click", function () {window.location.href = "{{ url_for('objects_qrcode.objects_qrcodes') }}"+'?date_from={{date_from}}&date_to={{date_to}}&type_id='+d.date }) | ||||
| 								{% elif  date_from|string == date_to|string and type is not none %} | ||||
| 									.on("click", function () {window.location.href = "{{ url_for('objects_qrcode.objects_qrcodes') }}?type_id={{type_id}}&date_from="+d.date+'&date_to='+d.date }) | ||||
| 								{% else %} | ||||
| 									.on("click", function () {window.location.href = "{{ url_for('objects_qrcode.objects_qrcodes') }}"+'?date_from='+d.date+'&date_to='+d.date }) | ||||
| 								{% endif %} | ||||
| 								.style("text-anchor", "middle") | ||||
| 								.text(d.total); | ||||
| 					} | ||||
| 				}); | ||||
| 
 | ||||
| 			drawLegend(varNames); | ||||
|     }); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| function drawLegend (varNames) { | ||||
|     var legend = svg.selectAll(".legend") | ||||
|         .data(varNames.slice().reverse()) | ||||
|       .enter().append("g") | ||||
|         .attr("class", "legend") | ||||
|         .attr("transform", function (d, i) { return "translate(0," + i * 20 + ")"; }); | ||||
| 
 | ||||
|     legend.append("rect") | ||||
|         .attr("x", 943) | ||||
|         .attr("width", 10) | ||||
|         .attr("height", 10) | ||||
|         .style("fill", color) | ||||
|         .style("stroke", "grey"); | ||||
| 
 | ||||
|     legend.append("text") | ||||
| 				.attr("class", "svgText") | ||||
|         .attr("x", 941) | ||||
|         .attr("y", 6) | ||||
|         .attr("dy", ".35em") | ||||
|         .style("text-anchor", "end") | ||||
|         .text(function (d) { return d; }); | ||||
| } | ||||
| 
 | ||||
| function removePopovers () { | ||||
|     $('.popover').each(function() { | ||||
|       $(this).remove(); | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
| function showPopover (d) { | ||||
|   $(this).popover({ | ||||
|     title: "<b><span id='tooltip-id-name-bar'></span></b>", | ||||
|     placement: 'top', | ||||
|     container: 'body', | ||||
|     trigger: 'manual', | ||||
|     html : true, | ||||
|     content: function() { | ||||
|       return "<span id='tooltip-id-label'></span>" + | ||||
|             "<br/>num: <span id='tooltip-id-value-bar'></span>"; } | ||||
|   }); | ||||
|   $(this).popover('show'); | ||||
|   $("#tooltip-id-name-bar").text(d.name); | ||||
|   $("#tooltip-id-label").text(d.label); | ||||
|   $("#tooltip-id-value-bar").text(d3.format(",")(d.value ? d.value: d.y1 - d.y0)); | ||||
| } | ||||
| 
 | ||||
| chart.onResize = function () { | ||||
|     var aspect = 1000 / 500, chart = $("#thesvg"); | ||||
|     var targetWidth = chart.parent().width(); | ||||
|     chart.attr("width", targetWidth); | ||||
|     chart.attr("height", targetWidth / aspect); | ||||
|   } | ||||
| 
 | ||||
| window.chart = chart; | ||||
| 
 | ||||
| </script> | ||||
| 
 | ||||
| <script> | ||||
| function draw_pie_chart(id, url_json, pie_on_click_url) { | ||||
| 
 | ||||
| 		var width_pie = 200; | ||||
| 		var height_pie = 200; | ||||
| 		var padding_pie = 10; | ||||
| 		var opacity_pie = .8; | ||||
| 
 | ||||
| 		var radius_pie = Math.min(width_pie - padding_pie, height_pie - padding_pie) / 2; | ||||
| 		//var color_pie = d3.scaleOrdinal(d3.schemeCategory10); | ||||
| 		var color_pie = d3.scaleOrdinal(d3.schemeSet3); | ||||
| 
 | ||||
| 		var div_pie = d3.select("body").append("div") | ||||
| 				.attr("class", "tooltip") | ||||
| 				.style("opacity", 0); | ||||
| 
 | ||||
| 		var svg_pie = d3.select("#"+id) | ||||
| 				.append('svg') | ||||
| 				.attr("width", '100%') | ||||
| 				.attr("height", '100%') | ||||
| 				.attr('viewBox','0 0 '+Math.min(width_pie,height_pie) +' '+Math.min(width_pie,height_pie) ) | ||||
| 				.attr('preserveAspectRatio','xMinYMin') | ||||
| 
 | ||||
| 
 | ||||
| 		var g_pie = svg_pie.append('g') | ||||
| 				.attr('transform', 'translate(' + (width_pie/2) + ',' + (height_pie/2) + ')'); | ||||
| 
 | ||||
| 		var arc_pie = d3.arc() | ||||
| 				.innerRadius(0) | ||||
| 				.outerRadius(radius_pie); | ||||
| 
 | ||||
| 		d3.json(url_json) | ||||
| 			.then(function(data){ | ||||
| 
 | ||||
| 			var pie_pie = d3.pie() | ||||
| 					.value(function(d) { return d.value; }) | ||||
| 					.sort(null); | ||||
| 
 | ||||
| 			var path_pie = g_pie.selectAll('path') | ||||
| 				  .data(pie_pie(data)) | ||||
| 				  .enter() | ||||
| 				  .append("g") | ||||
| 				  .append('path') | ||||
| 				  .attr('d', arc_pie) | ||||
| 				  .attr('fill', (d,i) => color_pie(i)) | ||||
| 					.attr('class', 'pie_path') | ||||
| 					.on("mouseover", mouseovered_pie) | ||||
| 					.on("mouseout", mouseouted_pie) | ||||
| 					.on("click", function (d) {window.location.href = pie_on_click_url+d.data.name }) | ||||
| 				  .style('opacity', opacity_pie) | ||||
| 				  .style('stroke', 'white'); | ||||
| 			}); | ||||
| 
 | ||||
| 
 | ||||
| 		function mouseovered_pie(d) { | ||||
|       //remove old content | ||||
|       $("#tooltip-id-name").remove(); | ||||
|       $("#tooltip-id-value").remove(); | ||||
| 
 | ||||
| 			// tooltip | ||||
| 			var content; | ||||
| 
 | ||||
| 			content = "<b><span id='tooltip-id-name'></span></b><br/>"+ | ||||
| 								"<br/>"+ | ||||
| 								"<i>Decoded</i>: <span id='tooltip-id-value'></span><br/>" | ||||
| 
 | ||||
| 			div_pie.transition() | ||||
| 				.duration(200) | ||||
| 				.style("opacity", .9); | ||||
| 			div_pie.html(content) | ||||
| 				.style("left", (d3.event.pageX) + "px") | ||||
| 				.style("top", (d3.event.pageY - 28) + "px"); | ||||
| 
 | ||||
|       $("#tooltip-id-name").text(d.data.name); | ||||
|       $("#tooltip-id-value").text(d.data.value); | ||||
| 		} | ||||
| 
 | ||||
| 		function mouseouted_pie() { | ||||
| 			div_pie.transition() | ||||
| 				.duration(500) | ||||
| 				.style("opacity", 0); | ||||
| 		} | ||||
| } | ||||
| 
 | ||||
| </script> | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| <script> | ||||
| function barchart_type(url, id) { | ||||
| 
 | ||||
| 
 | ||||
|   var margin = {top: 20, right: 20, bottom: 70, left: 40}; | ||||
| 
 | ||||
|   var width = 960 - margin.left - margin.right; | ||||
|   var height = 500 - margin.top - margin.bottom; | ||||
| 
 | ||||
|   var x = d3.scaleBand().rangeRound([0, width]).padding(0.1); | ||||
|   var y = d3.scaleLinear().rangeRound([height, 0]); | ||||
| 
 | ||||
|   var xAxis = d3.axisBottom(x) | ||||
|     //.tickFormat(d3.time.format("%Y-%m")); | ||||
| 
 | ||||
|   var yAxis = d3.axisLeft(y) | ||||
|     .ticks(10); | ||||
| 
 | ||||
| /*var svg = d3.select(id).append("svg") | ||||
|       .attr("width", width + margin.left + margin.right) | ||||
|       .attr("height", height + margin.top + margin.bottom) | ||||
| 			.attr("id", "thesvg") | ||||
|       .append("g") | ||||
|         .attr("transform", | ||||
|           "translate(" + margin.left + "," + margin.top + ")");*/ | ||||
| 
 | ||||
| 
 | ||||
|   d3.json(url) | ||||
|     .then(function(data){ | ||||
| 
 | ||||
|         data.forEach(function(d) { | ||||
|           d.value = +d.value; | ||||
|         }); | ||||
| 
 | ||||
| 				x.domain(data.map(function(d) { return d.date; })); | ||||
|         y.domain([0, d3.max(data, function(d) { return d.value; })]); | ||||
| 
 | ||||
|         var label = svg.append("g") | ||||
|             .attr("class", "x axis") | ||||
|             .attr("transform", "translate(0," + height + ")") | ||||
|             .call(xAxis) | ||||
|           .selectAll("text") | ||||
|             .style("text-anchor", "end") | ||||
|             .attr("dx", "-.8em") | ||||
|             .attr("dy", "-.55em") | ||||
| 						{% if  daily_type_chart %} | ||||
| 						.attr("transform", "rotate(-20)" ); | ||||
| 						{% else %} | ||||
| 						.attr("transform", "rotate(-70)" ) | ||||
| 						.attr("class", "bar") | ||||
| 						{% endif %} | ||||
| 
 | ||||
|         svg.append("g") | ||||
|             .attr("class", "y axis") | ||||
|             .call(yAxis) | ||||
|           .append("text") | ||||
|             .attr("transform", "rotate(-90)") | ||||
|             .attr("y", 6) | ||||
|             .attr("dy", ".71em") | ||||
|             .style("text-anchor", "end") | ||||
|             .text("Value ($)"); | ||||
| 
 | ||||
|         var bar = svg.selectAll("bar") | ||||
|             .data(data) | ||||
|           .enter().append("rect") | ||||
|             .attr("class", "bar") | ||||
|             //.style("fill", "steelblue") | ||||
| 						.attr("x", function(d) { return x(d.date); }) | ||||
|             .attr("width", x.bandwidth()) | ||||
|             .attr("y", function(d) { return y(d.value); }) | ||||
|             .attr("height", function(d) { return height - y(d.value); }) | ||||
| 
 | ||||
| 
 | ||||
|         data.forEach(function(d) { | ||||
|           if(d.value != 0){ | ||||
|             svg.append("text") | ||||
|                 .attr("class", "bar") | ||||
|                 .attr("dy", "-.35em") | ||||
|                 //.text(function(d) { return d.value; }); | ||||
|                 .text(d.value) | ||||
| 								.style("text-anchor", "middle") | ||||
| 								.attr('x', x(d.date) + x.bandwidth()/2) | ||||
|                 .attr('y', y(d.value)); | ||||
|           } | ||||
|         }); | ||||
| 
 | ||||
|     }); | ||||
| 
 | ||||
| } | ||||
| </script> | ||||
| 
 | ||||
| 
 | ||||
| </body> | ||||
| 
 | ||||
| </html> | ||||
|  | @ -0,0 +1,68 @@ | |||
| <!DOCTYPE html> | ||||
| <html> | ||||
| 
 | ||||
| <head> | ||||
|   <title>Qrcode - 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/dataTables.bootstrap.min.css') }}" rel="stylesheet"> | ||||
|     <link href="{{ url_for('static', filename='css/tags.css') }}" rel="stylesheet" type="text/css" /> | ||||
|     <link href="{{ url_for('static', filename='css/ail-project.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 src="{{ url_for('static', filename='js/tags.js') }}"></script> | ||||
| 
 | ||||
| </head> | ||||
| <body> | ||||
| 
 | ||||
| 	{% include 'nav_bar.html' %} | ||||
| 
 | ||||
| 	<div class="container-fluid"> | ||||
| 		<div class="row"> | ||||
| 
 | ||||
| 			{% include 'sidebars/sidebar_objects.html' %} | ||||
| 
 | ||||
| 			<div class="col-12 col-lg-10" id="core_content"> | ||||
| 
 | ||||
|                 {% with meta=meta, is_correlation=False %} | ||||
|                     {% include 'objects/qrcode/card_qrcode.html' %} | ||||
|                 {% endwith %} | ||||
| 
 | ||||
|             </div> | ||||
| 
 | ||||
|         </div> | ||||
|     </div> | ||||
| 
 | ||||
| <script> | ||||
|     var chart = {}; | ||||
|     $(document).ready(function(){ | ||||
|         $("#page-Decoded").addClass("active"); | ||||
|         $("#nav_chat").addClass("active"); | ||||
|   }); | ||||
| 
 | ||||
| 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') | ||||
| 	} | ||||
| } | ||||
| </script> | ||||
| 
 | ||||
| </body> | ||||
| 
 | ||||
| </html> | ||||
|  | @ -36,38 +36,6 @@ | |||
|                     </tbody> | ||||
|                 </table> | ||||
|             </li> | ||||
| 			<li class="list-group-item py-0"> | ||||
| 				<div id="accordion_image" class="my-3"> | ||||
|                     <div class="card"> | ||||
|                         <div class="card-header py-1" id="headingImage"> | ||||
|                             <button class="btn w-100 collapsed rotate" data-toggle="collapse" data-target="#collapseImage" aria-expanded="false" aria-controls="collapseImage"> | ||||
|                                 <span class="row text-left"> | ||||
|                                     <div class="col-11"> | ||||
|                                         <span class="mt-2"> | ||||
|                                             <i class="far fa-image"></i> Show Image   | ||||
|                                         </span> | ||||
|                                     </div> | ||||
|                                     <div class="col-1 text-primary"> | ||||
|                                         <i class="fas fa-chevron-circle-down"></i> | ||||
|                                     </div> | ||||
|                                 </span> | ||||
|                             </button> | ||||
|                         </div> | ||||
| {#                        <div id="collapseImage" class="collapse show" aria-labelledby="headingImage" data-parent="#accordion_image">#} | ||||
| {#                            <div class="card-body text-center">#} | ||||
| {#                                {% include 'objects/image/block_blur_img_slider.html' %}#} | ||||
| {##} | ||||
| {#								<img class="object_image mb-1" usemap="#image-map" src="{{ url_for('objects_ocr.ocr_image', filename=meta['id'])}}">#} | ||||
| {#                                <map name="image-map">#} | ||||
| {#                                    {% for c in meta['map'] %}#} | ||||
| {#                                        <area shape="poly" coords="{{ c[0] }}" title="{{ c[1] }}">#} | ||||
| {#                                    {% endfor %}#} | ||||
| {#                                </map>#} | ||||
| {#                            </div>#} | ||||
| {#                        </div>#} | ||||
|                     </div> | ||||
|                 </div> | ||||
| 			</li> | ||||
|             <li class="list-group-item py-0"> | ||||
| 
 | ||||
| 
 | ||||
|  | @ -88,6 +88,12 @@ | |||
|                       <span>OCR</span> | ||||
|                   </a> | ||||
|               </li> | ||||
|               <li class="nav-item"> | ||||
|                   <a class="nav-link" href="{{url_for('objects_qrcode.objects_qrcodes')}}" id="nav_qrcode"> | ||||
|                       <i class="fas fa-qrcode"></i> | ||||
|                       <span>Qrcode</span> | ||||
|                   </a> | ||||
|               </li> | ||||
|               <li class="nav-item"> | ||||
|                   <a class="nav-link" href="{{url_for('objects_title.objects_titles')}}" id="nav_title"> | ||||
|                       <i class="fas fa-heading"></i> | ||||
|  |  | |||
|  | @ -228,10 +228,12 @@ | |||
|           {% endwith %} | ||||
| 
 | ||||
|         {% else %} | ||||
|             <h2> | ||||
|                 {% if dict_tagged['date']['date_from'] %}{{ dict_tagged['date']['date_from'][0:4] }}-{{ dict_tagged['date']['date_from'][4:6] }}-{{ dict_tagged['date']['date_from'][6:8] }} {% endif %} | ||||
|                 - {{ dict_tagged['date']['date_to'][0:4] }}-{{ dict_tagged['date']['date_to'][4:6] }}-{{ dict_tagged['date']['date_to'][6:8] }} No Result | ||||
|             </h2> | ||||
|             {% if 'date' in dict_tagged and 'current_tags' in dict_tagged %} | ||||
|                 <h2> | ||||
|                     {% if dict_tagged['date']['date_from'] %}{{ dict_tagged['date']['date_from'][0:4] }}-{{ dict_tagged['date']['date_from'][4:6] }}-{{ dict_tagged['date']['date_from'][6:8] }} {% endif %} | ||||
|                     - {{ dict_tagged['date']['date_to'][0:4] }}-{{ dict_tagged['date']['date_to'][4:6] }}-{{ dict_tagged['date']['date_to'][6:8] }} No Result | ||||
|                 </h2> | ||||
|             {% endif %} | ||||
|             {% for tag in dict_tagged['current_tags'] %} | ||||
|                 <span class="badge badge-secondary my-1">{{ tag }}"</span> | ||||
|             {% endfor %} | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 terrtia
						terrtia