chg: [file-names] search file by name + fix search username case sensitive
Some checks are pending
CI / ail_test (3.10) (push) Waiting to run
CI / ail_test (3.7) (push) Waiting to run
CI / ail_test (3.8) (push) Waiting to run
CI / ail_test (3.9) (push) Waiting to run

This commit is contained in:
terrtia 2025-01-29 17:19:13 +01:00
parent 561107f6ac
commit 86021dece2
No known key found for this signature in database
GPG key ID: 1E1B1F50D84613D0
8 changed files with 207 additions and 24 deletions

View file

@ -82,7 +82,7 @@ class AbstractDaterangeObject(AbstractObject, ABC):
return int(nb) return int(nb)
def _get_meta(self, options=[]): def _get_meta(self, options=[]):
meta_dict = self.get_default_meta() meta_dict = self.get_default_meta(options=options)
meta_dict['first_seen'] = self.get_first_seen() meta_dict['first_seen'] = self.get_first_seen()
meta_dict['last_seen'] = self.get_last_seen() meta_dict['last_seen'] = self.get_last_seen()
meta_dict['nb_seen'] = self.get_nb_seen() meta_dict['nb_seen'] = self.get_nb_seen()
@ -311,4 +311,4 @@ class AbstractDaterangeObjects(ABC):
def api_get_meta_by_daterange(self, date_from, date_to): def api_get_meta_by_daterange(self, date_from, date_to):
date = Date.sanitise_date_range(date_from, date_to) date = Date.sanitise_date_range(date_from, date_to)
return self.get_metas(self.get_by_daterange(date['date_from'], date['date_to']), options={'sparkline'}) return self.get_metas(self.get_by_daterange(date['date_from'], date['date_to']), options={'sparkline', 'uuid'})

View file

@ -9,6 +9,7 @@ Base Class for AIL Objects
import os import os
import logging.config import logging.config
import sys import sys
import uuid
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from pymisp import MISPObject from pymisp import MISPObject
@ -71,7 +72,7 @@ class AbstractObject(ABC):
def get_last_full_date(self): def get_last_full_date(self):
return None return None
def get_default_meta(self, tags=False, link=False): def get_default_meta(self, tags=False, link=False, options=set()):
dict_meta = {'id': self.get_id(), dict_meta = {'id': self.get_id(),
'type': self.get_type(), 'type': self.get_type(),
'subtype': self.get_subtype(r_str=True)} 'subtype': self.get_subtype(r_str=True)}
@ -79,6 +80,8 @@ class AbstractObject(ABC):
dict_meta['tags'] = self.get_tags(r_list=True) dict_meta['tags'] = self.get_tags(r_list=True)
if link: if link:
dict_meta['link'] = self.get_link() dict_meta['link'] = self.get_link()
if 'uuid' in options:
dict_meta['uuid'] = str(uuid.uuid5(uuid.NAMESPACE_URL, self.get_id()))
return dict_meta return dict_meta
def _get_field(self, field): def _get_field(self, field):

View file

@ -18,6 +18,7 @@ sys.path.append(os.environ['AIL_BIN'])
################################## ##################################
# Import Project packages # Import Project packages
################################## ##################################
from lib import ail_core
from lib.objects import FilesNames from lib.objects import FilesNames
from packages import Date from packages import Date
@ -42,7 +43,6 @@ def objects_files_names():
if show_objects: if show_objects:
dict_objects = FilesNames.FilesNames().api_get_meta_by_daterange(date_from, date_to) dict_objects = FilesNames.FilesNames().api_get_meta_by_daterange(date_from, date_to)
print(dict_objects)
else: else:
dict_objects = {} dict_objects = {}
@ -69,19 +69,50 @@ def objects_file_name_range_json():
date_to = date['date_to'] date_to = date['date_to']
return jsonify(FilesNames.FilesNames().api_get_chart_nb_by_daterange(date_from, date_to)) return jsonify(FilesNames.FilesNames().api_get_chart_nb_by_daterange(date_from, date_to))
# @objects_file_name.route("/objects/file-nam/search", methods=['POST']) @objects_file_name.route("/objects/file-nam/search", methods=['GET', 'POST'])
# @login_required @login_required
# @login_read_only @login_read_only
# def objects_files_names_search(): def objects_files_names_search():
# to_search = request.form.get('object_id') if request.method == 'POST':
# to_search = request.form.get('to_search')
# # TODO SANITIZE ID case_sensitive = bool(request.form.get('case_sensitive'))
# # TODO Search all if case_sensitive:
# cve = Cves.Cve(to_search) case_sensitive = 1
# if not cve.exists(): else:
# abort(404) case_sensitive = 0
# else: page = request.form.get('page', 1)
# return redirect(cve.get_link(flask_context=True)) try:
page = int(page)
except (TypeError, ValueError):
page = 1
return redirect(url_for('objects_file_name.objects_files_names_search', search=to_search, page=page, case_sensitive=case_sensitive))
else:
to_search = request.args.get('search')
page = request.args.get('page', 1)
case_sensitive = request.args.get('case_sensitive', False)
if case_sensitive and case_sensitive != '0':
case_sensitive = True
else:
case_sensitive = False
try:
page = int(page)
except (TypeError, ValueError):
page = 1
filenames = FilesNames.FilesNames()
search_result = filenames.search_by_id(to_search, page, case_sensitive=case_sensitive)
if search_result:
ids = sorted(search_result.keys())
dict_page = ail_core.paginate_iterator(ids, nb_obj=500, page=page)
dict_objects = filenames.get_metas(dict_page['list_elem'], options={'icon', 'sparkline', 'uuid'})
else:
dict_objects = {}
dict_page = {}
return render_template("file-name/search_file_name_result.html", dict_objects=dict_objects, search_result=search_result,
dict_page=dict_page, case_sensitive=case_sensitive,
to_search=to_search)
# ============= ROUTES ============== # ============= ROUTES ==============

View file

@ -125,15 +125,25 @@ def objects_username_search():
if request.method == 'POST': if request.method == 'POST':
to_search = request.form.get('to_search') to_search = request.form.get('to_search')
subtype = request.form.get('search_subtype') subtype = request.form.get('search_subtype')
case_sensitive = bool(request.form.get('case_sensitive'))
if case_sensitive:
case_sensitive = 1
else:
case_sensitive = 0
page = request.form.get('page', 1) page = request.form.get('page', 1)
try: try:
page = int(page) page = int(page)
except (TypeError, ValueError): except (TypeError, ValueError):
page = 1 page = 1
return redirect(url_for('objects_subtypes.objects_username_search', search=to_search, page=page, subtype=subtype)) return redirect(url_for('objects_subtypes.objects_username_search', search=to_search, page=page, subtype=subtype, case_sensitive=case_sensitive))
else: else:
to_search = request.args.get('search') to_search = request.args.get('search')
subtype = request.args.get('subtype') # TODO sanityze subtype = request.args.get('subtype') # TODO sanityze
case_sensitive = request.args.get('case_sensitive', False)
if case_sensitive and case_sensitive != '0':
case_sensitive = True
else:
case_sensitive = False
page = request.args.get('page', 1) page = request.args.get('page', 1)
try: try:
page = int(page) page = int(page)
@ -141,7 +151,7 @@ def objects_username_search():
page = 1 page = 1
usernames = Usernames.Usernames() usernames = Usernames.Usernames()
search_result = usernames.search_by_id(to_search, [subtype], page) search_result = usernames.search_by_id(to_search, [subtype], page, case_sensitive=case_sensitive)
if search_result: if search_result:
ids = sorted(search_result.keys()) ids = sorted(search_result.keys())
@ -153,7 +163,7 @@ def objects_username_search():
return render_template("username/search_usernames_result.html", dict_objects=dict_objects, search_result=search_result, 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'), dict_page=dict_page, subtypes=ail_core.get_object_all_subtypes('username'),
to_search=to_search, subtype=subtype) to_search=to_search, subtype=subtype, case_sensitive=case_sensitive)
@objects_subtypes.route("/objects/user-accounts", methods=['GET']) @objects_subtypes.route("/objects/user-accounts", methods=['GET'])
@login_required @login_required

View file

@ -75,7 +75,7 @@
<div class="col-xl-10"> <div class="col-xl-10">
<div class="mt-1" id="barchart_type"></div> <div class="mt-1" id="barchart_type"></div>
{# {% include 'file-name/block_file_name_search.html' %}#} {% include 'file-name/block_file_name_search.html' %}
</div> </div>
@ -139,7 +139,7 @@
<td>{{ dict_objects[obj_id]['first_seen'] }}</td> <td>{{ dict_objects[obj_id]['first_seen'] }}</td>
<td>{{ dict_objects[obj_id]['last_seen'] }}</td> <td>{{ dict_objects[obj_id]['last_seen'] }}</td>
<td>{{ dict_objects[obj_id]['nb_seen'] }}</td> <td>{{ dict_objects[obj_id]['nb_seen'] }}</td>
<td id="sparklines_{{ obj_id | replace(".", "_point_") }}" style="text-align:center;"></td> <td id="sparklines_{{ dict_objects[obj_id]['uuid'] }}" style="text-align:center;"></td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
@ -233,7 +233,7 @@ function toggle_sidebar(){
<script> <script>
{% for obj_id in dict_objects %} {% for obj_id in dict_objects %}
sparkline("sparklines_{{ obj_id | replace(".", "_point_") }}", {{ dict_objects[obj_id]['sparkline'] }}, {}); sparkline("sparklines_{{ dict_objects[obj_id]['uuid'] }}", {{ dict_objects[obj_id]['sparkline'] }}, {});
{% endfor %} {% endfor %}
</script> </script>

View file

@ -0,0 +1,16 @@
<div class="card border-secondary my-2">
<div class="card-body text-dark">
<h5 class="card-title">File Names Search:</h5>
<form action="{{ url_for('objects_file_name.objects_files_names_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="">
<input type="text" class="form-control col-8" name="to_search" value="{% if to_search %}{{ to_search }}{% endif %}" placeholder="File Name 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 case_sensitive %}value="True" checked{% else %}value="False"{% endif %}>
<label class="custom-control-label" for="case_sensitive">Case Sensitive</label>
</div>
</form>
</div>
</div>

View file

@ -0,0 +1,123 @@
<!DOCTYPE html>
<html>
<head>
<title>File Names 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'] %}
{% include 'file-name/block_file_name_search.html' %}
{% endwith %}
<table id="table_objects" class="table table-striped table-bordered">
<thead class="bg-dark text-white">
<tr>
<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>
<a target="_blank" href="{{ url_for('correlation.show_correlation') }}?type=file-name&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_{{ dict_objects[obj_id]['uuid'] }}" 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_file_name.objects_files_names_search') + "?search=" + to_search + "&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_{{ dict_objects[obj_id]['uuid'] }}", {{ dict_objects[obj_id]['sparkline'] }}, {});
{% endfor %}
</script>
</body>
</html>

View file

@ -13,7 +13,7 @@
<button class="btn btn-primary input-group-addon search-obj col-2"><i class="fas fa-search"></i></button> <button class="btn btn-primary input-group-addon search-obj col-2"><i class="fas fa-search"></i></button>
</div> </div>
<div class="custom-control custom-switch mt-1"> <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 %}> <input class="custom-control-input" type="checkbox" name="case_sensitive" id="case_sensitive" {% if case_sensitive %}value="True" checked{% endif %}>
<label class="custom-control-label" for="case_sensitive">Case Sensitive</label> <label class="custom-control-label" for="case_sensitive">Case Sensitive</label>
</div> </div>
</form> </form>