这是indexloc提供的服务,不要输入任何密码
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 2 additions & 22 deletions src/plugins/compare/file_coverage/view/file_coverage.html
Original file line number Diff line number Diff line change
Expand Up @@ -75,35 +75,15 @@

{% elif feature == 'changed_text_files' %}
<tr>
<td data-toggle="tooltip" data-placement="right" title="text files with identical paths but different content">diverging text files</td>
<td data-toggle="tooltip" data-placement="right" title="text files with identical paths but different content">changed text files</td>
<td colspan="{{ uid_list | length }}">
<div class="list-group">
<div role="button" data-toggle="collapse" data-target="#changed_text_files" class="list-group-item list-group-item-primary d-flex justify-content-between align-items-center" aria-expanded="false">
show files<span class="badge badge-pill badge-primary">{{ result['plugins'][plugin][feature] | length }}</span>
</div>
<div id="changed_text_files" class="collapse">
<div class="list-group list-group-flush">
<div class="list-group-item list-group-item-action border-top p-0">
<table class="internal-table table-sm" style="width: 100%;">
{% for path, uid_tuple_list in result['plugins'][plugin][feature].items() | sort %}
{% for (uid_1, uid_2) in uid_tuple_list %}
<tr>
<td style="width: 50%;">
<a href="/analysis/{{ uid_1 }}" target="_blank" rel="noopener noreferrer">{{ path }}</a>
</td>
<td>
<a href="/analysis/{{ uid_2 }}" target="_blank" rel="noopener noreferrer">{{ path }}</a>
</td>
<td style="width: 140px; text-align: right;">
<button class="btn btn-primary" onclick=" window.open('/comparison/text_files/{{ uid_1 }}/{{ uid_2 }}','_blank')">
show file diff
</button>
</td>
</tr>
{% endfor %}
{% endfor %}
</table>
</div>
{{ result['plugins'][plugin][feature] | group_changed_text_files | render_changed_text_files | safe }}
</div>
</div>
</div>
Expand Down
12 changes: 12 additions & 0 deletions src/test/unit/web_interface/test_filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,18 @@ def test_group_dict_list_by_key(list_of_dicts, key, expected_result):
assert flt.group_dict_list_by_key(list_of_dicts, key) == expected_result


@pytest.mark.parametrize(
('input_dict', 'expected_result'),
[
({}, {}),
({'a': 1}, {'a': 1}),
({'/a/b/c': 1, '/a/b/d': 2, '/a/e': 3}, {'a': {'b': {'c': 1, 'd': 2}, 'e': 3}}),
],
)
def test_grp_changed_text_file_data(input_dict, expected_result):
assert flt.group_path_dict_by_dirs(input_dict) == expected_result


@pytest.mark.parametrize(
('function', 'input_data', 'expected_output', 'error_message'),
[
Expand Down
2 changes: 2 additions & 0 deletions src/web_interface/components/jinja_filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ def _setup_filters(self):
'get_searchable_crypto_block': flt.get_searchable_crypto_block,
'get_unique_keys_from_list_of_dicts': flt.get_unique_keys_from_list_of_dicts,
'group_dict_list_by_key': flt.group_dict_list_by_key,
'group_changed_text_files': flt.group_path_dict_by_dirs,
'hex': hex,
'hide_dts_binary_data': flt.hide_dts_binary_data,
'infection_color': flt.infection_color,
Expand Down Expand Up @@ -207,6 +208,7 @@ def _setup_filters(self):
'regex_meta': flt.comment_out_regex_meta_chars,
'remaining_time': elapsed_time,
'render_analysis_tags': flt.render_analysis_tags,
'render_changed_text_files': flt.render_changed_text_files,
'render_general_information': self._render_general_information_table,
'render_query_title': flt.render_query_title,
'render_fw_tags': flt.render_fw_tags,
Expand Down
76 changes: 76 additions & 0 deletions src/web_interface/filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import binascii
import json
import logging
import os
import random
import re
import stat
Expand All @@ -25,6 +26,7 @@
from helperFunctions.data_conversion import make_unicode_string
from helperFunctions.tag import TagColor
from helperFunctions.web_interface import get_alternating_color_list
from web_interface.file_tree.file_tree import get_icon_for_mime, get_mime_for_text_file
from web_interface.security.authentication import user_has_privilege
from web_interface.security.privileges import PRIVILEGES

Expand Down Expand Up @@ -376,6 +378,20 @@ def group_dict_list_by_key(dict_list: list[dict], key: Any) -> dict[str, list[di
return result


def group_path_dict_by_dirs(data: dict[str, list[tuple]]) -> dict:
# groups paths into folders, resulting in a tree structure
result = {}
for path, value in data.items():
current = result
# path is expected to be of structure /dir1/dir2/.../file
*folders, file = path.split('/')
for dir_name in folders:
if dir_name:
current = current.setdefault(dir_name, {})
current[file] = value
return result


def random_collapse_id():
return ''.join(random.choice(ascii_letters) for _ in range(10))

Expand All @@ -397,6 +413,66 @@ def format_duration(duration: float) -> str:
return str(timedelta(seconds=duration))


def render_changed_text_files(changed_text_files: dict) -> str:
elements = []
for key, value in sorted(changed_text_files.items()):
icon = get_icon_for_mime(get_mime_for_text_file(key))
if isinstance(value, list):
# file tuple list (represents a leaf/file in the file tree)
lines = ['<table class="internal-table table-sm" style="width: 100%;">']
for uid_1, uid_2 in value:
lines.extend(
[
'<tr>',
' <td style="width: 50%;">',
f' <img src="{icon}" alt="">',
f' <a href="/analysis/{uid_1}" target="_blank" rel="noopener noreferrer">{key}</a>',
' </td>',
' <td>',
f' <img src="{icon}" alt="">',
f' <a href="/analysis/{uid_2}" target="_blank" rel="noopener noreferrer">{key}</a>',
' </td>',
' <td style="width: 150px; text-align: right;">',
f' <button class="btn btn-primary" onclick=" '
f" window.open('/comparison/text_files/{uid_1}/{uid_2}','_blank')\">",
' show file diff',
' </button>',
' </td>',
'</tr>',
]
)
lines.append('</table>')
element = '\n'.join(lines)
else:
# directory dict (represents an inner node/folder in the file tree)
inner = render_changed_text_files(value)
id_ = f'ctf-{os.urandom(8).hex()}'
count = _count_changed_files(value)
element = (
f'<div class="p-1" data-toggle="collapse" data-target="#{id_}">'
f' ╰ <img src="/static/file_icons/folder.svg"> {key} <i class="fas fa-caret-down"></i>'
f' <span class="badge badge-pill badge-secondary">{count}</span>'
f'</div>\n'
f'<div id="{id_}" class="collapse list-group list-group-flush">\n'
f' {inner}\n'
'</div>\n'
)
elements.append(
f'<div class="list-group-item border-top" style="padding: 0 0 0 25px">\n' f'{element}\n' '</div>'
)
return '\n'.join(elements)


def _count_changed_files(ctf_dict: dict) -> int:
count = 0
for value in ctf_dict.values():
if isinstance(value, dict):
count += _count_changed_files(value)
elif isinstance(value, list):
count += len(value)
return count


def render_query_title(query_title: None | str | dict):
if query_title is None:
return None
Expand Down