mirror of https://github.com/CIRCL/AIL-framework
				
				
				
			chg: [username] add username search
							parent
							
								
									31e3da5e53
								
							
						
					
					
						commit
						4a6ab3caa1
					
				|  | @ -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) | ||||
|  |  | |||
|  | @ -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 | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -70,6 +70,12 @@ | |||
|                     </div> | ||||
|                 </div> | ||||
| 
 | ||||
|                 <br> | ||||
|                 <br> | ||||
|                 {% with subtypes=username_subtypes %} | ||||
|                     {% include 'username/block_usernames_search.html' %} | ||||
|                 {% endwith %} | ||||
| 
 | ||||
|             </div> | ||||
| 
 | ||||
|         </div> | ||||
|  |  | |||
|  | @ -76,28 +76,35 @@ | |||
| 						<div class="mt-1" id="barchart_type"> | ||||
| 						</div> | ||||
| 
 | ||||
|             <div class="card border-secondary my-2"> | ||||
|           		<div class="card-body text-dark"> | ||||
|           			<h5 class="card-title">Search {{obj_type}} by name:</h5> | ||||
|                         {% if obj_type == 'username' %} | ||||
|                             {% with subtypes=subtypes %} | ||||
|                                 {% include 'username/block_usernames_search.html' %} | ||||
|                             {% endwith %} | ||||
|                         {% else %} | ||||
| 
 | ||||
|                 <form action="{{ url_for('objects_subtypes.objects_subtypes_search') }}" id="search_subtype_onj" method='post'> | ||||
|                             <div class="card border-secondary my-2"> | ||||
|                                 <div class="card-body text-dark"> | ||||
|                                     <h5 class="card-title">Search {{obj_type}} by name:</h5> | ||||
| 
 | ||||
|                   <div class="input-group mb-1"> | ||||
|                     <input type="text" class="form-control" name="type" value="{{obj_type}}" hidden> | ||||
|                   	<select class="custom-select col-2" name="subtype" value="{{subtype}}" required> | ||||
|                       <option value="">{{obj_type}} Type...</option> | ||||
|                       {% for typ in subtypes %} | ||||
|                         <option value="{{typ}}">{{typ}}</option> | ||||
|                       {% endfor %} | ||||
|                     </select> | ||||
|                                 <form action="{{ url_for('objects_subtypes.objects_subtypes_search') }}" id="search_subtype_onj" method='post'> | ||||
| 
 | ||||
|                     <input type="text" class="form-control col-8" name="id" value="" placeholder="{{obj_type}} ID" required> | ||||
|                     <button class="btn btn-primary input-group-addon search-obj col-2"><i class="fas fa-search"></i></button> | ||||
|                   </div> | ||||
|                                   <div class="input-group mb-1"> | ||||
|                                     <input type="text" class="form-control" name="type" value="{{obj_type}}" hidden> | ||||
|                                     <select class="custom-select col-2" name="subtype" value="{{subtype}}" required> | ||||
|                                       <option value="">{{obj_type}} Type...</option> | ||||
|                                       {% for typ in subtypes %} | ||||
|                                         <option value="{{typ}}">{{typ}}</option> | ||||
|                                       {% endfor %} | ||||
|                                     </select> | ||||
| 
 | ||||
|                 </form> | ||||
|               </div> | ||||
|             </div> | ||||
|                                     <input type="text" class="form-control col-8" name="id" value="" placeholder="{{obj_type}} ID" required> | ||||
|                                     <button class="btn btn-primary input-group-addon search-obj col-2"><i class="fas fa-search"></i></button> | ||||
|                                   </div> | ||||
| 
 | ||||
|                                 </form> | ||||
|                               </div> | ||||
|                             </div> | ||||
|                         {% endif %} | ||||
| 
 | ||||
| 					</div> | ||||
| 
 | ||||
|  |  | |||
|  | @ -0,0 +1,21 @@ | |||
| <div class="card border-secondary my-2"> | ||||
|     <div class="card-body text-dark"> | ||||
|         <h5 class="card-title">Usernames Search:</h5> | ||||
|         <form action="{{ url_for('objects_subtypes.objects_username_search') }}" id="search_subtype_onj" method='post'> | ||||
|             <div class="input-group mb-1"> | ||||
|                 <input type="text" name="page" value="{% if page %}{{ page }}{% else %}1{% endif %}" hidden=""> | ||||
|                 <select class="custom-select col-2" name="search_subtype" required> | ||||
|                     {% for s in subtypes %} | ||||
|                         <option value="{{ s }}" {% if s == subtype %}selected{% endif %}>{{ s }}</option> | ||||
|                     {% endfor %} | ||||
|                 </select> | ||||
|                 <input type="text" class="form-control col-8" name="to_search" value="{% if to_search %}{{ to_search }}{% endif %}" placeholder="Username to Search" required> | ||||
|                 <button class="btn btn-primary input-group-addon search-obj col-2"><i class="fas fa-search"></i></button> | ||||
|             </div> | ||||
|             <div class="custom-control custom-switch mt-1"> | ||||
|                 <input class="custom-control-input" type="checkbox" name="case_sensitive" id="case_sensitive" {% if type_to_search %}{% if case_sensitive %}value="True" checked{% else %}value="False"{% endif %}{% else %}value="True" checked{% endif %}> | ||||
|                 <label class="custom-control-label" for="case_sensitive">Case Sensitive</label> | ||||
|             </div> | ||||
|         </form> | ||||
|     </div> | ||||
| </div> | ||||
|  | @ -0,0 +1,130 @@ | |||
| <!DOCTYPE html> | ||||
| <html> | ||||
| 
 | ||||
| <head> | ||||
|   <title>Usernames Search - 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/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/d3.min.js') }}"></script> | ||||
|     <script src="{{ url_for('static', filename='js/d3/sparklines.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 page=dict_page['page'], subtypes=subtypes, subtype=subtype %} | ||||
| 				    {% include 'username/block_usernames_search.html' %} | ||||
|                 {% endwith %} | ||||
| 
 | ||||
| 
 | ||||
| 				<table id="table_objects" class="table table-striped table-bordered"> | ||||
|                     <thead class="bg-dark text-white"> | ||||
|                     <tr> | ||||
|                         <th>Subtype</th> | ||||
|                         <th>ID</th> | ||||
|                         <th>First Seen</th> | ||||
|                         <th>Last Seen</th> | ||||
|                         <th>NB Seen</th> | ||||
|                         <th>Sparkline</th> | ||||
|                     </tr> | ||||
|                     </thead> | ||||
|                     <tbody style="font-size: 15px;"> | ||||
|                     {% for obj_id in dict_objects %} | ||||
|                         <tr> | ||||
|                             <td> | ||||
|                                 {% 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'] }} | ||||
|                             </td> | ||||
|                             <td> | ||||
|                                 <a target="_blank" href="{{ url_for('correlation.show_correlation') }}?type=username&subtype=telegram&id={{ obj_id }}"> | ||||
|                                     <span>{{ dict_objects[obj_id]['id'][:search_result[obj_id]['hl-start']] }}</span><span class="hg-text">{{dict_objects[obj_id]['id'][search_result[obj_id]['hl-start']:search_result[obj_id]['hl-end']]}}</span>{{ dict_objects[obj_id]['id'][search_result[obj_id]['hl-end']:] }} | ||||
|                                 </a> | ||||
|                             </td> | ||||
|                             <td> | ||||
|                                 {% 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 %} | ||||
|                             </td> | ||||
|                             <td> | ||||
|                                 {% 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 %} | ||||
|                             </td> | ||||
|                             <td>{{ dict_objects[obj_id]['nb_seen'] }} | ||||
|                             </td> | ||||
|                             <td id="sparklines_{{ obj_id }}" style="text-align:center;"></td> | ||||
|                         </tr> | ||||
|                     {% endfor %} | ||||
|                     </tbody> | ||||
|                 </table> | ||||
| 
 | ||||
|                 {% 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 %} | ||||
| 
 | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
| 
 | ||||
| <script> | ||||
|     var chart = {}; | ||||
|     $(document).ready(function(){ | ||||
|         $("#page-Decoded").addClass("active"); | ||||
|         $("#nav_username").addClass("active"); | ||||
| 
 | ||||
|         $('#table_objects').DataTable({ | ||||
|             "aLengthMenu": [[5, 10, 15, -1], [5, 10, 15, "All"]], | ||||
|             "iDisplayLength": 10, | ||||
|             "order": [[ 3, "desc" ]] | ||||
|         }); | ||||
|   }); | ||||
| 
 | ||||
| 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> | ||||
| 
 | ||||
| 
 | ||||
| </body> | ||||
| </html> | ||||
		Loading…
	
		Reference in New Issue
	
	 terrtia
						terrtia