diff --git a/poetry.lock b/poetry.lock index b32ac5f..c1268a6 100644 --- a/poetry.lock +++ b/poetry.lock @@ -3629,4 +3629,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = ">=3.8.1,<3.13" -content-hash = "6ed31d5e656cec63bfd4e1402b09b449ea7c3d5edb2ada0ec38e79b4784a38b7" +content-hash = "0ae3318c2969c455c7d29bd34a9b28689a17cda4f10ca8352bcb0c7ebcb0a6ec" diff --git a/pyproject.toml b/pyproject.toml index edabbef..01f5064 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -80,6 +80,7 @@ urllib3 = [ {version = "^2.0.7", python = ">=3.10"} ] pypdns = "^2.2.2" +python-magic = "^0.4.27" [tool.poetry.group.dev.dependencies] mypy = "^1.8.0" diff --git a/website/web/__init__.py b/website/web/__init__.py index 8a68554..7df0401 100644 --- a/website/web/__init__.py +++ b/website/web/__init__.py @@ -15,6 +15,7 @@ import sys import time import filetype # type: ignore[import-untyped] +import magic from datetime import date, datetime, timedelta, timezone from importlib.metadata import version @@ -838,6 +839,7 @@ def mark_as_legitimate(tree_uuid: str) -> Response: def tree_favicons(tree_uuid: str) -> str: favicons = [] favicons_zip = lookyloo.get_potential_favicons(tree_uuid, all_favicons=True, for_datauri=False) + f = magic.Magic(mime=True) with ZipFile(favicons_zip, 'r') as myzip: for name in myzip.namelist(): if not name.endswith('.ico'): @@ -845,11 +847,12 @@ def tree_favicons(tree_uuid: str) -> str: favicon = myzip.read(name) if not favicon: continue + mimetype = f.from_buffer(favicon) favicon_sha512 = hashlib.sha512(favicon).hexdigest() frequency = lookyloo.indexing.favicon_frequency(favicon_sha512) number_captures = lookyloo.indexing.favicon_number_captures(favicon_sha512) b64_favicon = base64.b64encode(favicon).decode() - favicons.append((favicon_sha512, frequency, number_captures, b64_favicon)) + favicons.append((favicon_sha512, frequency, number_captures, mimetype, b64_favicon)) return render_template('tree_favicons.html', tree_uuid=tree_uuid, favicons=favicons) @@ -1243,11 +1246,14 @@ def hhh_detail(hhh: str) -> str: def favicon_detail(favicon_sha512: str) -> str: captures, favicon = lookyloo.get_favicon_investigator(favicon_sha512.strip()) if favicon: + f = magic.Magic(mime=True) + mimetype = f.from_buffer(favicon) b64_favicon = base64.b64encode(favicon).decode() else: b64_favicon = '' + mimetype = '' return render_template('favicon_details.html', favicon_sha512=favicon_sha512, - captures=captures, b64_favicon=b64_favicon) + captures=captures, mimetype=mimetype, b64_favicon=b64_favicon) @app.route('/body_hashes/', methods=['GET']) diff --git a/website/web/sri.txt b/website/web/sri.txt index 3d982a6..aeb478e 100644 --- a/website/web/sri.txt +++ b/website/web/sri.txt @@ -20,7 +20,7 @@ "favicon.ico": "KOmrfwRbOQqhhwSeBkNpMRAxSVMmmLg+2kRMg9iSv7OWjE9spJc7x4MKB4AE/hi0knaV7UBVctAU6XZ7AC72ZA==", "font.png": "RwoQkj9dT9SLUL2F7cAA16Nat9t2hDb58eQlHF9ThUar829p0INUXG+5XuDaFOC8SsmCZK5vw2f+YAQ6mLC1Qw==", "generic.css": "Sh/BcxFMLYYaLdCluVt9efGvJ9CF5d+YJ7lkL2M24PRGu8VZHI9lJiUlFObIocjQgwss3Ve2U5cUAE5WiAdpQQ==", - "generic.js": "UmFl4fHmB/UjMdUuYdFy9BfzQlJTyeImNHCFyBO4SdLxBCwCGxkF3NQvel1PKqW8JTnoPlPpq/n9d+vCfPeegA==", + "generic.js": "h2tLqpn8r1mZ/5FqiBDK6Er6mY5MdRuyir2mS9piT8VUUco2daxdKWSkiEtIsH2Ok+/W+NJb95A1ob5J/6sW4A==", "html.png": "T7pZrb8MMDsA/JV/51hu+TOglTqlxySuEVY0rpDjTuAEyhzk2v+W4kYrj7vX+Tp3n2d2lvVD08PwhCG62Yfbzg==", "ifr.png": "rI5YJypmz1QcULRf9UaOYSqV4tPUSxUdLAycoYzCwywt4Pw4eWzBg9SUr769VyIimoiIyJR+aNuoIA4p5WO2fQ==", "img.png": "bknBlmIfSb9qv9/lSaJ2idn2a8bDyvJ2pATj4oOpehRlCdXlWYOyb2jN3wV1QGHFoqyxNqOv5MfCpI0tbqkicg==", diff --git a/website/web/static/generic.js b/website/web/static/generic.js index 34ba628..e6902c2 100644 --- a/website/web/static/generic.js +++ b/website/web/static/generic.js @@ -24,3 +24,18 @@ function checkAllBoxes(name) { checkboxs[i].checked = !checkboxs[i].checked; } } + +// Parameters: +// contentType: The content type of your file. +// its like application/pdf or application/msword or image/jpeg or +// image/png and so on +// base64Data: Its your actual base64 data +// fileName: Its the file name of the file which will be downloaded. +// Source: https://stackoverflow.com/questions/14011021/how-to-download-a-base64-encoded-image +function downloadBase64File(contentType, base64Data, fileName) { + const linkSource = `data:${contentType};base64,${base64Data}`; + const downloadLink = document.createElement("a"); + downloadLink.href = linkSource; + downloadLink.download = fileName; + downloadLink.click(); +} diff --git a/website/web/templates/favicon_details.html b/website/web/templates/favicon_details.html index bcdd1cd..4622198 100644 --- a/website/web/templates/favicon_details.html +++ b/website/web/templates/favicon_details.html @@ -7,7 +7,7 @@
- +
diff --git a/website/web/templates/tree_favicons.html b/website/web/templates/tree_favicons.html index c734b47..8482aca 100644 --- a/website/web/templates/tree_favicons.html +++ b/website/web/templates/tree_favicons.html @@ -15,13 +15,14 @@ - {% for favicon_sha512, freq, number_captures, b64_favicon in favicons %} + {% for favicon_sha512, freq, number_captures, mimetype, b64_favicon in favicons %}
- + + {{ freq }} {{ number_captures }}