diff --git a/bin/lib/objects/Usernames.py b/bin/lib/objects/Usernames.py index c9154b99..bcd808b7 100755 --- a/bin/lib/objects/Usernames.py +++ b/bin/lib/objects/Usernames.py @@ -13,7 +13,7 @@ sys.path.append(os.environ['AIL_BIN']) # Import Project packages ################################## from lib.ConfigLoader import ConfigLoader -from lib.objects.abstract_subtype_object import AbstractSubtypeObject, get_all_id +from lib.objects.abstract_subtype_object import AbstractSubtypeObject, AbstractSubtypeObjects, get_all_id config_loader = ConfigLoader() baseurl = config_loader.get_config_str("Notifications", "ail_domain") @@ -65,7 +65,7 @@ class Username(AbstractSubtypeObject): meta = self._get_meta(options=options) meta['id'] = self.id meta['subtype'] = self.subtype - meta['tags'] = self.get_tags(r_list=True) + meta['tags'] = self.get_tags(r_list=True) # TODO NB Chats return meta def get_misp_object(self): @@ -136,7 +136,20 @@ def search_usernames_by_name(name_to_search, subtype, r_pos=False): return usernames +class Usernames(AbstractSubtypeObjects): + """ + Usernames Objects + """ + def __init__(self): + super().__init__('username', Username) + + def sanitize_id_to_search(self, subtypes, name_to_search): + return name_to_search + + # if __name__ == '__main__': # name_to_search = 'co' -# subtype = 'telegram' -# print(search_usernames_by_name(name_to_search, subtype)) +# subtypes = ['telegram'] +# u = Usernames() +# r = u.search_by_id(name_to_search, subtypes, r_pos=True) +# print(r) diff --git a/bin/lib/objects/abstract_subtype_object.py b/bin/lib/objects/abstract_subtype_object.py index 71d9d267..17be1add 100755 --- a/bin/lib/objects/abstract_subtype_object.py +++ b/bin/lib/objects/abstract_subtype_object.py @@ -7,8 +7,9 @@ Base Class for AIL Objects # Import External packages ################################## import os +import re import sys -from abc import ABC +from abc import ABC, abstractmethod # from flask import url_for @@ -192,6 +193,62 @@ class AbstractSubtypeObject(AbstractObject, ABC): def _delete(self): pass + +class AbstractSubtypeObjects(ABC): + """ + Abstract Subtype Objects + """ + def __init__(self, obj_type, obj_class): + self.type = obj_type + self.obj_class = obj_class + + def get_ids(self): # TODO FORMAT + ids = [] + for subtype in get_object_all_subtypes(self.type): + ids += r_object.zrange(f'{self.type}_all:{subtype}', 0, -1) + return ids + + def get_id_iterators_by_subtype(self, subtype): + return zscan_iter(r_object, f'{self.type}_all:{subtype}') + + def get_metas(self, subtype, obj_ids, options=set()): + dict_obj = {} + for obj_id in obj_ids: + obj = self.obj_class(obj_id, subtype) + dict_obj[obj_id] = obj.get_meta(options=options) + return dict_obj + + @abstractmethod + def sanitize_id_to_search(self, subtypes, id_to_search): + return id_to_search + + # TODO + def search_by_id(self, name_to_search, subtypes=[], r_pos=False, case_sensitive=True): + objs = {} + if case_sensitive: + flags = 0 + else: + flags = re.IGNORECASE + # for subtype in subtypes: + r_name = self.sanitize_id_to_search(subtypes, name_to_search) + if not name_to_search or isinstance(r_name, dict): + return objs + r_name = re.compile(r_name, flags=flags) + for subtype in subtypes: + for obj_id in self.get_id_iterators_by_subtype(subtype): + obj_id = obj_id[0] + res = re.search(r_name, obj_id) + if res: + objs[obj_id] = {} + if r_pos: + objs[obj_id]['hl-start'] = res.start() + objs[obj_id]['hl-end'] = res.end() + return objs + +######################################################################## +######################################################################## +######################################################################## + def get_all_id(obj_type, subtype): return r_object.zrange(f'{obj_type}_all:{subtype}', 0, -1) @@ -246,3 +303,5 @@ def get_subtypes_objs_range_json(obj_type, date_from, date_to): objs_range.append(day_dict) return objs_range + + diff --git a/var/www/blueprints/chats_explorer.py b/var/www/blueprints/chats_explorer.py index 342f67e4..1552ae62 100644 --- a/var/www/blueprints/chats_explorer.py +++ b/var/www/blueprints/chats_explorer.py @@ -49,7 +49,7 @@ def chats_explorer_dashboard(): @login_read_only def chats_explorer_protocols(): protocols = chats_viewer.get_chat_protocols_meta() - return render_template('chats_protocols.html', protocols=protocols) + return render_template('chats_protocols.html', protocols=protocols, username_subtypes=ail_core.get_object_all_subtypes('username')) @chats_explorer.route("chats/explorer/networks", methods=['GET']) @login_required diff --git a/var/www/blueprints/objects_subtypes.py b/var/www/blueprints/objects_subtypes.py index 85944365..70d3b0b3 100644 --- a/var/www/blueprints/objects_subtypes.py +++ b/var/www/blueprints/objects_subtypes.py @@ -23,6 +23,7 @@ from lib import ail_core from lib.objects import abstract_subtype_object from lib.objects import ail_objects from lib.objects import CryptoCurrencies +from lib.objects import Usernames from packages import Date # ============ BLUEPRINT ============ @@ -117,6 +118,43 @@ def objects_dashboard_pgp(): def objects_dashboard_username(): return subtypes_objects_dashboard('username', request) +@objects_subtypes.route("/objects/usernames/search", methods=['GET', 'POST']) +@login_required +@login_read_only +def objects_username_search(): + if request.method == 'POST': + to_search = request.form.get('to_search') + subtype = request.form.get('search_subtype') + page = request.form.get('page', 1) + try: + page = int(page) + except (TypeError, ValueError): + page = 1 + return redirect(url_for('objects_subtypes.objects_username_search', search=to_search, page=page, subtype=subtype)) + else: + to_search = request.args.get('search') + subtype = request.args.get('subtype') # TODO sanityze + page = request.args.get('page', 1) + try: + page = int(page) + except (TypeError, ValueError): + page = 1 + + usernames = Usernames.Usernames() + search_result = usernames.search_by_id(to_search, [subtype], page) + + if search_result: + ids = sorted(search_result.keys()) + dict_page = ail_core.paginate_iterator(ids, nb_obj=500, page=page) + dict_objects = usernames.get_metas(subtype, dict_page['list_elem'], options={'icon', 'sparkline'}) # TODO OPTIONS + else: + dict_objects = {} + dict_page = {} + + return render_template("username/search_usernames_result.html", dict_objects=dict_objects, search_result=search_result, + dict_page=dict_page, subtypes=ail_core.get_object_all_subtypes('username'), + to_search=to_search, subtype=subtype) + @objects_subtypes.route("/objects/user-accounts", methods=['GET']) @login_required @login_read_only diff --git a/var/www/templates/chats_explorer/chats_protocols.html b/var/www/templates/chats_explorer/chats_protocols.html index 6870a220..5cc914e4 100644 --- a/var/www/templates/chats_explorer/chats_protocols.html +++ b/var/www/templates/chats_explorer/chats_protocols.html @@ -70,6 +70,12 @@ +
+
+ {% with subtypes=username_subtypes %} + {% include 'username/block_usernames_search.html' %} + {% endwith %} + diff --git a/var/www/templates/objects/subtypes_objs_dashboard.html b/var/www/templates/objects/subtypes_objs_dashboard.html index 15c30f5a..3113864e 100644 --- a/var/www/templates/objects/subtypes_objs_dashboard.html +++ b/var/www/templates/objects/subtypes_objs_dashboard.html @@ -76,28 +76,35 @@
-
-
-
Search {{obj_type}} by name:
+ {% if obj_type == 'username' %} + {% with subtypes=subtypes %} + {% include 'username/block_usernames_search.html' %} + {% endwith %} + {% else %} -
+
+
+
Search {{obj_type}} by name:
-
- - + - - -
+
+ + - -
-
+ + +
+ + +
+
+ {% endif %} diff --git a/var/www/templates/objects/username/block_usernames_search.html b/var/www/templates/objects/username/block_usernames_search.html new file mode 100644 index 00000000..3efb5d8b --- /dev/null +++ b/var/www/templates/objects/username/block_usernames_search.html @@ -0,0 +1,21 @@ +
+
+
Usernames Search:
+
+
+ + + + +
+
+ + +
+
+
+
\ No newline at end of file diff --git a/var/www/templates/objects/username/search_usernames_result.html b/var/www/templates/objects/username/search_usernames_result.html new file mode 100644 index 00000000..67ed64b6 --- /dev/null +++ b/var/www/templates/objects/username/search_usernames_result.html @@ -0,0 +1,130 @@ + + + + + Usernames Search - AIL + + + + + + + + + + + + + + + + + + + + + {% include 'nav_bar.html' %} + +
+
+ + {% include 'sidebars/sidebar_objects.html' %} + +
+ + {% with page=dict_page['page'], subtypes=subtypes, subtype=subtype %} + {% include 'username/block_usernames_search.html' %} + {% endwith %} + + + + + + + + + + + + + + + {% for obj_id in dict_objects %} + + + + + + + + + {% endfor %} + +
SubtypeIDFirst SeenLast SeenNB SeenSparkline
+ {% with style=dict_objects[obj_id]['icon']['style'], icon=dict_objects[obj_id]['icon']['icon'] , color=dict_objects[obj_id]['icon']['color'] %} + {% include 'objects/obj_svg_block.html' %} + {% endwith %} + {{ dict_objects[obj_id]['subtype'] }} + + + {{ dict_objects[obj_id]['id'][:search_result[obj_id]['hl-start']] }}{{dict_objects[obj_id]['id'][search_result[obj_id]['hl-start']:search_result[obj_id]['hl-end']]}}{{ dict_objects[obj_id]['id'][search_result[obj_id]['hl-end']:] }} + + + {% if dict_objects[obj_id]['first_seen'] %} + {{ dict_objects[obj_id]['first_seen'][0:4] }}-{{ dict_objects[obj_id]['first_seen'][4:6] }}-{{ dict_objects[obj_id]['first_seen'][6:8] }} + {% endif %} + + {% if dict_objects[obj_id]['last_seen'] %} + {{ dict_objects[obj_id]['last_seen'][0:4] }}-{{ dict_objects[obj_id]['last_seen'][4:6] }}-{{ dict_objects[obj_id]['last_seen'][6:8] }} + {% endif %} + {{ dict_objects[obj_id]['nb_seen'] }} +
+ + {% if dict_page %} + {% with page=dict_page['page'], nb_page_max=dict_page['nb_pages'], nb_first_elem=dict_page['nb_first_elem'], nb_last_elem=dict_page['nb_last_elem'], nb_all_elem=dict_page['nb_all_elem'] %} + {% set target_url=url_for('objects_subtypes.objects_username_search') + "?search=" + to_search + "&subtype=" + subtype + "&case_sensitive=" + case_sensitive|string %} + {% include 'pagination.html' %} + {% endwith %} + {% endif %} + +
+
+
+ + + + + + + +