fix: Support rendering non-icon favicons

pull/887/head
Raphaël Vinot 2024-02-20 19:53:07 +01:00
parent dcbec2efef
commit 104129bbe2
7 changed files with 30 additions and 7 deletions

2
poetry.lock generated
View File

@ -3629,4 +3629,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p
[metadata] [metadata]
lock-version = "2.0" lock-version = "2.0"
python-versions = ">=3.8.1,<3.13" python-versions = ">=3.8.1,<3.13"
content-hash = "6ed31d5e656cec63bfd4e1402b09b449ea7c3d5edb2ada0ec38e79b4784a38b7" content-hash = "0ae3318c2969c455c7d29bd34a9b28689a17cda4f10ca8352bcb0c7ebcb0a6ec"

View File

@ -80,6 +80,7 @@ urllib3 = [
{version = "^2.0.7", python = ">=3.10"} {version = "^2.0.7", python = ">=3.10"}
] ]
pypdns = "^2.2.2" pypdns = "^2.2.2"
python-magic = "^0.4.27"
[tool.poetry.group.dev.dependencies] [tool.poetry.group.dev.dependencies]
mypy = "^1.8.0" mypy = "^1.8.0"

View File

@ -15,6 +15,7 @@ import sys
import time import time
import filetype # type: ignore[import-untyped] import filetype # type: ignore[import-untyped]
import magic
from datetime import date, datetime, timedelta, timezone from datetime import date, datetime, timedelta, timezone
from importlib.metadata import version from importlib.metadata import version
@ -838,6 +839,7 @@ def mark_as_legitimate(tree_uuid: str) -> Response:
def tree_favicons(tree_uuid: str) -> str: def tree_favicons(tree_uuid: str) -> str:
favicons = [] favicons = []
favicons_zip = lookyloo.get_potential_favicons(tree_uuid, all_favicons=True, for_datauri=False) 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: with ZipFile(favicons_zip, 'r') as myzip:
for name in myzip.namelist(): for name in myzip.namelist():
if not name.endswith('.ico'): if not name.endswith('.ico'):
@ -845,11 +847,12 @@ def tree_favicons(tree_uuid: str) -> str:
favicon = myzip.read(name) favicon = myzip.read(name)
if not favicon: if not favicon:
continue continue
mimetype = f.from_buffer(favicon)
favicon_sha512 = hashlib.sha512(favicon).hexdigest() favicon_sha512 = hashlib.sha512(favicon).hexdigest()
frequency = lookyloo.indexing.favicon_frequency(favicon_sha512) frequency = lookyloo.indexing.favicon_frequency(favicon_sha512)
number_captures = lookyloo.indexing.favicon_number_captures(favicon_sha512) number_captures = lookyloo.indexing.favicon_number_captures(favicon_sha512)
b64_favicon = base64.b64encode(favicon).decode() 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) 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: def favicon_detail(favicon_sha512: str) -> str:
captures, favicon = lookyloo.get_favicon_investigator(favicon_sha512.strip()) captures, favicon = lookyloo.get_favicon_investigator(favicon_sha512.strip())
if favicon: if favicon:
f = magic.Magic(mime=True)
mimetype = f.from_buffer(favicon)
b64_favicon = base64.b64encode(favicon).decode() b64_favicon = base64.b64encode(favicon).decode()
else: else:
b64_favicon = '' b64_favicon = ''
mimetype = ''
return render_template('favicon_details.html', favicon_sha512=favicon_sha512, 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/<string:body_hash>', methods=['GET']) @app.route('/body_hashes/<string:body_hash>', methods=['GET'])

View File

@ -20,7 +20,7 @@
"favicon.ico": "KOmrfwRbOQqhhwSeBkNpMRAxSVMmmLg+2kRMg9iSv7OWjE9spJc7x4MKB4AE/hi0knaV7UBVctAU6XZ7AC72ZA==", "favicon.ico": "KOmrfwRbOQqhhwSeBkNpMRAxSVMmmLg+2kRMg9iSv7OWjE9spJc7x4MKB4AE/hi0knaV7UBVctAU6XZ7AC72ZA==",
"font.png": "RwoQkj9dT9SLUL2F7cAA16Nat9t2hDb58eQlHF9ThUar829p0INUXG+5XuDaFOC8SsmCZK5vw2f+YAQ6mLC1Qw==", "font.png": "RwoQkj9dT9SLUL2F7cAA16Nat9t2hDb58eQlHF9ThUar829p0INUXG+5XuDaFOC8SsmCZK5vw2f+YAQ6mLC1Qw==",
"generic.css": "Sh/BcxFMLYYaLdCluVt9efGvJ9CF5d+YJ7lkL2M24PRGu8VZHI9lJiUlFObIocjQgwss3Ve2U5cUAE5WiAdpQQ==", "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==", "html.png": "T7pZrb8MMDsA/JV/51hu+TOglTqlxySuEVY0rpDjTuAEyhzk2v+W4kYrj7vX+Tp3n2d2lvVD08PwhCG62Yfbzg==",
"ifr.png": "rI5YJypmz1QcULRf9UaOYSqV4tPUSxUdLAycoYzCwywt4Pw4eWzBg9SUr769VyIimoiIyJR+aNuoIA4p5WO2fQ==", "ifr.png": "rI5YJypmz1QcULRf9UaOYSqV4tPUSxUdLAycoYzCwywt4Pw4eWzBg9SUr769VyIimoiIyJR+aNuoIA4p5WO2fQ==",
"img.png": "bknBlmIfSb9qv9/lSaJ2idn2a8bDyvJ2pATj4oOpehRlCdXlWYOyb2jN3wV1QGHFoqyxNqOv5MfCpI0tbqkicg==", "img.png": "bknBlmIfSb9qv9/lSaJ2idn2a8bDyvJ2pATj4oOpehRlCdXlWYOyb2jN3wV1QGHFoqyxNqOv5MfCpI0tbqkicg==",

View File

@ -24,3 +24,18 @@ function checkAllBoxes(name) {
checkboxs[i].checked = !checkboxs[i].checked; 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();
}

View File

@ -7,7 +7,7 @@
</script> </script>
<center> <center>
<img src="data:image/ico;base64,{{ b64_favicon }}" style="width:64px;height:64px;"/> <img src="data:{{mimetype}};base64,{{ b64_favicon }}" style="width:64px;height:64px;"/>
</center> </center>
<table id="faviconDetailsTable" class="table table-striped" style="width:100%"> <table id="faviconDetailsTable" class="table table-striped" style="width:100%">
<thead> <thead>

View File

@ -15,13 +15,14 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for favicon_sha512, freq, number_captures, b64_favicon in favicons %} {% for favicon_sha512, freq, number_captures, mimetype, b64_favicon in favicons %}
<tr> <tr>
<td> <td>
<a href="#faviconDetailsModal" data-remote="{{ url_for('favicon_detail', favicon_sha512=favicon_sha512) }}" <a href="#faviconDetailsModal" data-remote="{{ url_for('favicon_detail', favicon_sha512=favicon_sha512) }}"
data-bs-toggle="modal" data-bs-target="#faviconDetailsModal" role="button"> data-bs-toggle="modal" data-bs-target="#faviconDetailsModal" role="button">
<img src="data:image/ico;base64,{{ b64_favicon }}" style="width:32px;height:32px;"/> <img src="data:{{mimetype}};base64,{{ b64_favicon }}" style="width:32px;height:32px;"/>
</a> </a>
<button type="button" class="btn btn-light" onclick="downloadBase64File('{{mimetype}}', '{{b64_favicon}}', 'favicon.ico')">Download favicon</button>
</td> </td>
<td>{{ freq }}</td> <td>{{ freq }}</td>
<td>{{ number_captures }}</td> <td>{{ number_captures }}</td>