Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

text preview fix #1315

Merged
merged 1 commit into from
Dec 13, 2024
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
16 changes: 16 additions & 0 deletions src/test/unit/web_interface/test_filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import pytest

import web_interface.filter as flt
from test.common_helper import create_test_file_object

UNSORTABLE_LIST = [[], ()]

Expand Down Expand Up @@ -496,3 +497,18 @@ def test_str_to_hex(input_, expected_result):
)
def test_octal_to_readable(input_, include_type, expected_result):
assert flt.octal_to_readable(input_, include_type=include_type) == expected_result


@pytest.mark.parametrize(
('type_analysis', 'expected_result'),
[
({'file_type': {}}, False),
({'file_type': {'result': {'mime': 'image/png'}}}, True),
({'file_type': {'result': {'mime': 'text/plain'}}}, True),
({'file_type': {'result': {'mime': 'application/octet-stream'}}}, False),
({'file_type': {'result': {'mime': 'application/javascript'}}}, True),
],
)
def test_is_text_file_or_image(type_analysis, expected_result):
fo = create_test_file_object(analyses=type_analysis)
assert flt.is_text_file_or_image(fo) == expected_result
11 changes: 8 additions & 3 deletions src/web_interface/components/ajax_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@
from web_interface.file_tree.file_tree import remove_virtual_path_from_root
from web_interface.file_tree.file_tree_node import FileTreeNode
from web_interface.file_tree.jstree_conversion import convert_to_jstree_node
from web_interface.filter import bytes_to_str_filter, encode_base64_filter
from web_interface.filter import (
bytes_to_str_filter,
encode_base64_filter,
is_image,
is_text_file,
)
from web_interface.security.decorator import roles_accepted
from web_interface.security.privileges import PRIVILEGES

Expand Down Expand Up @@ -89,12 +94,12 @@ def _get_nice_uid_list_html(self, input_data, root_uid):
def ajax_get_binary(self, mime_type, uid):
mime_type = mime_type.replace('_', '/')
binary = self.intercom.get_binary_and_filename(uid)[0]
if 'text/' in mime_type:
if is_text_file(mime_type):
return (
'<pre class="line_numbering" style="white-space: pre-wrap">'
f'{html.escape(bytes_to_str_filter(binary))}</pre>'
)
if 'image/' in mime_type:
if is_image(mime_type):
return (
'<div style="display: block; border: 1px solid; border-color: #dddddd; padding: 5px; '
f'text-align: center"><img src="data:image/{mime_type[6:]} ;base64,{encode_base64_filter(binary)}" '
Expand Down
1 change: 1 addition & 0 deletions src/web_interface/components/jinja_filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ def _setup_filters(self):
'hide_dts_binary_data': flt.hide_dts_binary_data,
'infection_color': flt.infection_color,
'is_list': lambda item: isinstance(item, list),
'is_text_file_or_image': flt.is_text_file_or_image,
'json_dumps': json.dumps,
'link_cve': flt.replace_cve_with_link,
'link_cwe': flt.replace_cwe_with_link,
Expand Down
27 changes: 26 additions & 1 deletion src/web_interface/filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from re import Match
from string import ascii_letters
from time import localtime, strftime, struct_time, time
from typing import Iterable, Union
from typing import TYPE_CHECKING, Iterable, Union

import packaging.version
import semver
Expand All @@ -28,6 +28,9 @@
from web_interface.security.authentication import user_has_privilege
from web_interface.security.privileges import PRIVILEGES

if TYPE_CHECKING:
from objects.file import FileObject


def generic_nice_representation(i): # noqa: PLR0911
if isinstance(i, struct_time):
Expand Down Expand Up @@ -557,3 +560,25 @@ def _file_mode_to_type(mode: int) -> str:

def str_to_hex(string: str) -> str:
return string.encode(errors='replace').hex()


KNOWN_TEXT_MIME_TYPES = { # that don't start with text/
'application/javascript',
'application/json',
'application/pgp-keys',
'firmware/intel-hex',
'message/news',
}


def is_text_file(mime: str) -> bool:
return mime.startswith('text/') or mime in KNOWN_TEXT_MIME_TYPES


def is_image(mime: str) -> bool:
return mime.startswith('image/')


def is_text_file_or_image(fo: FileObject) -> bool:
mime = fo.processed_analysis.get('file_type', {}).get('result', {}).get('mime', '')
return is_image(mime) or is_text_file(mime)
4 changes: 1 addition & 3 deletions src/web_interface/templates/show_analysis.html
Original file line number Diff line number Diff line change
Expand Up @@ -360,10 +360,8 @@ <h5 class="modal-title">Add analysis to file</h5>
<div id="preview-content" class="m-0 mt-2 p-0"></div>
</div>

{%- set is_text_preview = firmware.processed_analysis["file_type"]["result"]['mime'][0:5] == "text/" or firmware.processed_analysis["file_type"]["result"]['mime'][0:6] == "image/" %}

<script>
const isTextOrImage = {{ 'true' if is_text_preview else 'false' }};
const isTextOrImage = {{ 'true' if firmware | is_text_file_or_image else 'false' }};
let mimeType = '{{ firmware.processed_analysis["file_type"]["result"]["mime"].replace("/", "_") }}';
</script>
<script type="text/javascript" src="{{ url_for('static', filename='js/show_analysis_preview.js') }}"></script>
Expand Down
Loading