From 0bb63828ae1b036ffe9735dab75643e018a2f11c Mon Sep 17 00:00:00 2001 From: Sara Kalupa Date: Thu, 27 Jun 2024 11:50:12 -0500 Subject: [PATCH 1/3] Removing WeasyPrint --- poetry.lock | 240 +---------------- pyproject.toml | 1 - src/python/strelka/scanners/scan_email.py | 271 +++++--------------- src/python/strelka/tests/test_scan_email.py | 87 +------ 4 files changed, 69 insertions(+), 530 deletions(-) diff --git a/poetry.lock b/poetry.lock index 3473d769..fc5febdf 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. [[package]] name = "aplib" @@ -592,25 +592,6 @@ ssh = ["bcrypt (>=3.1.5)"] test = ["certifi", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] test-randomorder = ["pytest-randomly"] -[[package]] -name = "cssselect2" -version = "0.7.0" -description = "CSS selectors for Python ElementTree" -optional = false -python-versions = ">=3.7" -files = [ - {file = "cssselect2-0.7.0-py3-none-any.whl", hash = "sha256:fd23a65bfd444595913f02fc71f6b286c29261e354c41d722ca7a261a49b5969"}, - {file = "cssselect2-0.7.0.tar.gz", hash = "sha256:1ccd984dab89fc68955043aca4e1b03e0cf29cad9880f6e28e3ba7a74b14aa5a"}, -] - -[package.dependencies] -tinycss2 = "*" -webencodings = "*" - -[package.extras] -doc = ["sphinx", "sphinx_rtd_theme"] -test = ["flake8", "isort", "pytest"] - [[package]] name = "decorator" version = "5.1.1" @@ -834,76 +815,6 @@ docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1 testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] typing = ["typing-extensions (>=4.8)"] -[[package]] -name = "fonttools" -version = "4.50.0" -description = "Tools to manipulate font files" -optional = false -python-versions = ">=3.8" -files = [ - {file = "fonttools-4.50.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:effd303fb422f8ce06543a36ca69148471144c534cc25f30e5be752bc4f46736"}, - {file = "fonttools-4.50.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7913992ab836f621d06aabac118fc258b9947a775a607e1a737eb3a91c360335"}, - {file = "fonttools-4.50.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e0a1c5bd2f63da4043b63888534b52c5a1fd7ae187c8ffc64cbb7ae475b9dab"}, - {file = "fonttools-4.50.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d40fc98540fa5360e7ecf2c56ddf3c6e7dd04929543618fd7b5cc76e66390562"}, - {file = "fonttools-4.50.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9fff65fbb7afe137bac3113827855e0204482727bddd00a806034ab0d3951d0d"}, - {file = "fonttools-4.50.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b1aeae3dd2ee719074a9372c89ad94f7c581903306d76befdaca2a559f802472"}, - {file = "fonttools-4.50.0-cp310-cp310-win32.whl", hash = "sha256:e9623afa319405da33b43c85cceb0585a6f5d3a1d7c604daf4f7e1dd55c03d1f"}, - {file = "fonttools-4.50.0-cp310-cp310-win_amd64.whl", hash = "sha256:778c5f43e7e654ef7fe0605e80894930bc3a7772e2f496238e57218610140f54"}, - {file = "fonttools-4.50.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3dfb102e7f63b78c832e4539969167ffcc0375b013080e6472350965a5fe8048"}, - {file = "fonttools-4.50.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9e58fe34cb379ba3d01d5d319d67dd3ce7ca9a47ad044ea2b22635cd2d1247fc"}, - {file = "fonttools-4.50.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c673ab40d15a442a4e6eb09bf007c1dda47c84ac1e2eecbdf359adacb799c24"}, - {file = "fonttools-4.50.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b3ac35cdcd1a4c90c23a5200212c1bb74fa05833cc7c14291d7043a52ca2aaa"}, - {file = "fonttools-4.50.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8844e7a2c5f7ecf977e82eb6b3014f025c8b454e046d941ece05b768be5847ae"}, - {file = "fonttools-4.50.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f849bd3c5c2249b49c98eca5aaebb920d2bfd92b3c69e84ca9bddf133e9f83f0"}, - {file = "fonttools-4.50.0-cp311-cp311-win32.whl", hash = "sha256:39293ff231b36b035575e81c14626dfc14407a20de5262f9596c2cbb199c3625"}, - {file = "fonttools-4.50.0-cp311-cp311-win_amd64.whl", hash = "sha256:c33d5023523b44d3481624f840c8646656a1def7630ca562f222eb3ead16c438"}, - {file = "fonttools-4.50.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b4a886a6dbe60100ba1cd24de962f8cd18139bd32808da80de1fa9f9f27bf1dc"}, - {file = "fonttools-4.50.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b2ca1837bfbe5eafa11313dbc7edada79052709a1fffa10cea691210af4aa1fa"}, - {file = "fonttools-4.50.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0493dd97ac8977e48ffc1476b932b37c847cbb87fd68673dee5182004906828"}, - {file = "fonttools-4.50.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77844e2f1b0889120b6c222fc49b2b75c3d88b930615e98893b899b9352a27ea"}, - {file = "fonttools-4.50.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3566bfb8c55ed9100afe1ba6f0f12265cd63a1387b9661eb6031a1578a28bad1"}, - {file = "fonttools-4.50.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:35e10ddbc129cf61775d58a14f2d44121178d89874d32cae1eac722e687d9019"}, - {file = "fonttools-4.50.0-cp312-cp312-win32.whl", hash = "sha256:cc8140baf9fa8f9b903f2b393a6c413a220fa990264b215bf48484f3d0bf8710"}, - {file = "fonttools-4.50.0-cp312-cp312-win_amd64.whl", hash = "sha256:0ccc85fd96373ab73c59833b824d7a73846670a0cb1f3afbaee2b2c426a8f931"}, - {file = "fonttools-4.50.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e270a406219af37581d96c810172001ec536e29e5593aa40d4c01cca3e145aa6"}, - {file = "fonttools-4.50.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ac2463de667233372e9e1c7e9de3d914b708437ef52a3199fdbf5a60184f190c"}, - {file = "fonttools-4.50.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47abd6669195abe87c22750dbcd366dc3a0648f1b7c93c2baa97429c4dc1506e"}, - {file = "fonttools-4.50.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:074841375e2e3d559aecc86e1224caf78e8b8417bb391e7d2506412538f21adc"}, - {file = "fonttools-4.50.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0743fd2191ad7ab43d78cd747215b12033ddee24fa1e088605a3efe80d6984de"}, - {file = "fonttools-4.50.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3d7080cce7be5ed65bee3496f09f79a82865a514863197ff4d4d177389e981b0"}, - {file = "fonttools-4.50.0-cp38-cp38-win32.whl", hash = "sha256:a467ba4e2eadc1d5cc1a11d355abb945f680473fbe30d15617e104c81f483045"}, - {file = "fonttools-4.50.0-cp38-cp38-win_amd64.whl", hash = "sha256:f77e048f805e00870659d6318fd89ef28ca4ee16a22b4c5e1905b735495fc422"}, - {file = "fonttools-4.50.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b6245eafd553c4e9a0708e93be51392bd2288c773523892fbd616d33fd2fda59"}, - {file = "fonttools-4.50.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a4062cc7e8de26f1603323ef3ae2171c9d29c8a9f5e067d555a2813cd5c7a7e0"}, - {file = "fonttools-4.50.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34692850dfd64ba06af61e5791a441f664cb7d21e7b544e8f385718430e8f8e4"}, - {file = "fonttools-4.50.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:678dd95f26a67e02c50dcb5bf250f95231d455642afbc65a3b0bcdacd4e4dd38"}, - {file = "fonttools-4.50.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4f2ce7b0b295fe64ac0a85aef46a0f2614995774bd7bc643b85679c0283287f9"}, - {file = "fonttools-4.50.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d346f4dc2221bfb7ab652d1e37d327578434ce559baf7113b0f55768437fe6a0"}, - {file = "fonttools-4.50.0-cp39-cp39-win32.whl", hash = "sha256:a51eeaf52ba3afd70bf489be20e52fdfafe6c03d652b02477c6ce23c995222f4"}, - {file = "fonttools-4.50.0-cp39-cp39-win_amd64.whl", hash = "sha256:8639be40d583e5d9da67795aa3eeeda0488fb577a1d42ae11a5036f18fb16d93"}, - {file = "fonttools-4.50.0-py3-none-any.whl", hash = "sha256:48fa36da06247aa8282766cfd63efff1bb24e55f020f29a335939ed3844d20d3"}, - {file = "fonttools-4.50.0.tar.gz", hash = "sha256:fa5cf61058c7dbb104c2ac4e782bf1b2016a8cf2f69de6e4dd6a865d2c969bb5"}, -] - -[package.dependencies] -brotli = {version = ">=1.0.1", optional = true, markers = "platform_python_implementation == \"CPython\" and extra == \"woff\""} -brotlicffi = {version = ">=0.8.0", optional = true, markers = "platform_python_implementation != \"CPython\" and extra == \"woff\""} -zopfli = {version = ">=0.1.4", optional = true, markers = "extra == \"woff\""} - -[package.extras] -all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "pycairo", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.1.0)", "xattr", "zopfli (>=0.1.4)"] -graphite = ["lz4 (>=1.7.4.2)"] -interpolatable = ["munkres", "pycairo", "scipy"] -lxml = ["lxml (>=4.0)"] -pathops = ["skia-pathops (>=0.5.0)"] -plot = ["matplotlib"] -repacker = ["uharfbuzz (>=0.23.0)"] -symfont = ["sympy"] -type1 = ["xattr"] -ufo = ["fs (>=2.2.0,<3)"] -unicode = ["unicodedata2 (>=15.1.0)"] -woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"] - [[package]] name = "formulas" version = "1.2.6" @@ -2316,21 +2227,6 @@ files = [ {file = "pycryptodomex-3.20.0.tar.gz", hash = "sha256:7a710b79baddd65b806402e14766c721aee8fb83381769c27920f26476276c1e"}, ] -[[package]] -name = "pydyf" -version = "0.9.0" -description = "A low-level PDF generator." -optional = false -python-versions = ">=3.7" -files = [ - {file = "pydyf-0.9.0-py3-none-any.whl", hash = "sha256:f0e447d9f69ca20cfa3ab3d17e274e26cc877bb6e36b4a83d196616a089db0dd"}, - {file = "pydyf-0.9.0.tar.gz", hash = "sha256:d5b244e8fc24119ce7bd5d51ea2d6773c0ff88aa81597db556bc440c6b880610"}, -] - -[package.extras] -doc = ["sphinx", "sphinx_rtd_theme"] -test = ["flake8", "isort", "pillow", "pytest"] - [[package]] name = "pyelftools" version = "0.29" @@ -2416,21 +2312,6 @@ files = [ {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, ] -[[package]] -name = "pyphen" -version = "0.14.0" -description = "Pure Python module to hyphenate text" -optional = false -python-versions = ">=3.7" -files = [ - {file = "pyphen-0.14.0-py3-none-any.whl", hash = "sha256:414c9355958ca3c6a3ff233f65678c245b8ecb56418fb291e2b93499d61cd510"}, - {file = "pyphen-0.14.0.tar.gz", hash = "sha256:596c8b3be1c1a70411ba5f6517d9ccfe3083c758ae2b94a45f2707346d8e66fa"}, -] - -[package.extras] -doc = ["sphinx", "sphinx_rtd_theme"] -test = ["flake8", "isort", "pytest"] - [[package]] name = "pyppmd" version = "1.0.0" @@ -2701,7 +2582,6 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -3364,24 +3244,6 @@ all = ["tornado (>=4.0)", "twisted"] tornado = ["tornado (>=4.0)"] twisted = ["twisted"] -[[package]] -name = "tinycss2" -version = "1.2.1" -description = "A tiny CSS parser" -optional = false -python-versions = ">=3.7" -files = [ - {file = "tinycss2-1.2.1-py3-none-any.whl", hash = "sha256:2b80a96d41e7c3914b8cda8bc7f705a4d9c49275616e886103dd839dfc847847"}, - {file = "tinycss2-1.2.1.tar.gz", hash = "sha256:8cff3a8f066c2ec677c06dbc7b45619804a6938478d9d73c284b29d14ecb0627"}, -] - -[package.dependencies] -webencodings = ">=0.4" - -[package.extras] -doc = ["sphinx", "sphinx_rtd_theme"] -test = ["flake8", "isort", "pytest"] - [[package]] name = "tldextract" version = "3.4.0" @@ -3483,31 +3345,6 @@ decorator = ">=3.4.0" [package.extras] test = ["flake8 (>=2.4.0)", "isort (>=4.2.2)", "pytest (>=2.2.3)"] -[[package]] -name = "weasyprint" -version = "60.2" -description = "The Awesome Document Factory" -optional = false -python-versions = ">=3.7" -files = [ - {file = "weasyprint-60.2-py3-none-any.whl", hash = "sha256:3e98eedcc1c5a14cb310c293c6d59a479f59a13f0d705ff07106482827fa5705"}, - {file = "weasyprint-60.2.tar.gz", hash = "sha256:0c0cdd617a78699262b80026e67fa1692e3802cfa966395436eeaf6f787dd126"}, -] - -[package.dependencies] -cffi = ">=0.6" -cssselect2 = ">=0.1" -fonttools = {version = ">=4.0.0", extras = ["woff"]} -html5lib = ">=1.1" -Pillow = ">=9.1.0" -pydyf = ">=0.8.0" -Pyphen = ">=0.9.1" -tinycss2 = ">=1.0.0" - -[package.extras] -doc = ["sphinx", "sphinx_rtd_theme"] -test = ["flake8", "isort", "pytest"] - [[package]] name = "webencodings" version = "0.5.1" @@ -3697,80 +3534,7 @@ files = [ docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] -[[package]] -name = "zopfli" -version = "0.2.3" -description = "Zopfli module for python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "zopfli-0.2.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:52438999888715a378fc6fe1477ab7813e9e9b58a27a38d2ad7be0e396b1ab2e"}, - {file = "zopfli-0.2.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6020a3533c6c7be09db9e59c2a8f3f894bf5d8e95cc01890d82114c923317c57"}, - {file = "zopfli-0.2.3-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:72349c78da402e6784bd9c5f4aff5cc7017bd969016ec07b656722f7f29fc975"}, - {file = "zopfli-0.2.3-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:711d4fde9cb99e1a9158978e9d1624a37cdd170ff057f6340059514fcf38e808"}, - {file = "zopfli-0.2.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ae890df6e5f1e8fa0697cafd848826decce0ac53e54e5a018fd97775e3a354c0"}, - {file = "zopfli-0.2.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:40b830244e6458ef982b4a5ebb0f228986d481408bae557a95eeece2c5ede4e6"}, - {file = "zopfli-0.2.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7bc89b71d1c4677f708cc162f40a4560f78f5f4c6aa6d884b423df7d38e8ba0b"}, - {file = "zopfli-0.2.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f07997453e7777e19ef0a2445cc1b90e1bb90c623dd77554325932dea6350fee"}, - {file = "zopfli-0.2.3-cp310-cp310-win32.whl", hash = "sha256:978395a4ce5cc46db29a36cdb80549b564dc7706237abaca5aac328dd5842f65"}, - {file = "zopfli-0.2.3-cp310-cp310-win_amd64.whl", hash = "sha256:61a2fcc624e8b038d4fca84ba927dc3f31df53a7284692d46aa44d16fb3f47b2"}, - {file = "zopfli-0.2.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:97d2f993142fed4f9c11c1766eb53409efe7298c755cf4599c171bfedcbaddae"}, - {file = "zopfli-0.2.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:92ca61eaa1df774908c173683e23c512189bf791a7ebb49fac61324658cff490"}, - {file = "zopfli-0.2.3-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:975d45745cf6c3e3b61127e0140dcf145fa515f2021f669bd82768937b7bb1fb"}, - {file = "zopfli-0.2.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0a8e556916088fadb098ddb6eed034d5c2df3b8fba7f2488e87e8c224002eca"}, - {file = "zopfli-0.2.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61abe5f11400f9c6b22be578091e28dfb9f1a61efaaeaa2da66138b03ee93072"}, - {file = "zopfli-0.2.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b30a922b9d73f22da2b589b35e594dcc6d144eb38ad890c542f2b92902ba9892"}, - {file = "zopfli-0.2.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:08d105a49576a9e629f53a710f0009c4bf0a1d8a3239a74e41d0944f26e28a61"}, - {file = "zopfli-0.2.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ad2a98890045d13b0cdc93c1637990c211dc877493469afc61a097a00a70cf22"}, - {file = "zopfli-0.2.3-cp311-cp311-win32.whl", hash = "sha256:27f2b58050f84fa059db7a6ec17d98b388c18f9783551e5f97605f790f25e155"}, - {file = "zopfli-0.2.3-cp311-cp311-win_amd64.whl", hash = "sha256:ff86a2cd6b9864027861a129d6d73231b6d463f0d364ca0fdca4492390357cba"}, - {file = "zopfli-0.2.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:2073b07c3ec4fcbc895bb02565a90f9f31373233979f6be398e82eacbd1105f3"}, - {file = "zopfli-0.2.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:1f25f1bb6440ed90a1d458772fa6ce53632f5fb61e435b12ae6b9b39af98d758"}, - {file = "zopfli-0.2.3-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:39d8a73bee07cf7f2c73e08508bf788bfdf28a527da353b5d3e2a0ee4aaf770c"}, - {file = "zopfli-0.2.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d40373db61883f6fc8b7040c9196a16f737e3063632afd15e8b3f25e871a30e8"}, - {file = "zopfli-0.2.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31c467a300ba46f55aa0ea958ea388e350eefd039cf15764bf4cd737d5eeb8a6"}, - {file = "zopfli-0.2.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c3c61787a90439cf68f751b2a1ab789b0805876c0cd9b58398adc212d1eeace5"}, - {file = "zopfli-0.2.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3e4675ca4c7b1215b8a53cec1831cbdb6914f91ea2f183817a06fc7b38e27642"}, - {file = "zopfli-0.2.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f48de4818c10c539fdd01276512043ae4ae738e0301e9cace1dd38f4bcffad6a"}, - {file = "zopfli-0.2.3-cp312-cp312-win32.whl", hash = "sha256:7769f6ca73f37dff92159127bd25b0cc7d81d3feb819d355dc7ac01ad05c673d"}, - {file = "zopfli-0.2.3-cp312-cp312-win_amd64.whl", hash = "sha256:1c5fd29730024f5fb0e2623e3853ca422bd3cf57042389c8e0e771dc47f88084"}, - {file = "zopfli-0.2.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c6555293e42e7a9154940bb18613de2abce21a855780baff8a6c372e395c59b3"}, - {file = "zopfli-0.2.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:40665bf0bacc8b82652a1af4016648dd69f896afa59fc481c1d19a222aa746ea"}, - {file = "zopfli-0.2.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7599ce108386d91a402969cba4f17247e33a594b21cbd662e008414ccb0b4cf7"}, - {file = "zopfli-0.2.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dc59299eda2aaf57f0ee5c4b42ada0b80e3dc4c09c5bdda8ee9ae5cf93fafa9e"}, - {file = "zopfli-0.2.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7ddcbc258bb5c07ebb7f6ee64c46d4e35c39c6abba2b3dfa72c0ea4daf9e65fc"}, - {file = "zopfli-0.2.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:eef08c02295bb99c7fdca380c52e5454fa1c08025fb0bea2c7ae6c0e1e9c034b"}, - {file = "zopfli-0.2.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:7ebb4e1b0f102d431830151041777c55700d12afd1e5adb5bcbce72037c1a10e"}, - {file = "zopfli-0.2.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:9dcf7af42c11b3cf5d3fbf665799e10f54f66caea2020fe304602df83b9a1a69"}, - {file = "zopfli-0.2.3-cp38-cp38-win32.whl", hash = "sha256:0fbb6e7fc0da56835167e3c83a45b28e99ba14b671ecb8e51100ad03dfffc3d0"}, - {file = "zopfli-0.2.3-cp38-cp38-win_amd64.whl", hash = "sha256:ca9a6df3d11c2f8f0356c141523c4914a2850dd39fc213d968c0272db635eea9"}, - {file = "zopfli-0.2.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2770cf6b88e9985c79b90fd6d4c15d8dab0caa37c1c3b17773e61ce857eab586"}, - {file = "zopfli-0.2.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5e52aaab3a93470cf0ff2bb2135a8628dda7b70f675c46f35b6a1b30e8e482f4"}, - {file = "zopfli-0.2.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:082f030b2b7d6d4597ac517816e499c63b92130aa8f4f74a3788ebaa5770f974"}, - {file = "zopfli-0.2.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0574372283befa5af98fb31407e1fe6822f2f9c437ef69e7fa260e49022d8a65"}, - {file = "zopfli-0.2.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:8293062567917201609b28b865289d5ddee55030c779fa9264caae4cc2e00fb3"}, - {file = "zopfli-0.2.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e4068d4d35b2e63898d22e1b7777d986b8f5d61fe83a77973730ce9cff1b4ba1"}, - {file = "zopfli-0.2.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:2da6f30632cefda8ebe032fdcb69cf062f5a6435af9d32de82ccef320e0261f5"}, - {file = "zopfli-0.2.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e5f62ca9a947f09f531c721e2a3f2e0094523436b8eb5df18d71245c1924f89a"}, - {file = "zopfli-0.2.3-cp39-cp39-win32.whl", hash = "sha256:7463b42a2cee33f0a018bf8f1304da2379d6cb8111aa4e04d8f8590d0f1099e1"}, - {file = "zopfli-0.2.3-cp39-cp39-win_amd64.whl", hash = "sha256:22b1cfc398a87754730f7e268693c8eb480cb688fd645648fda85614a8b1c08c"}, - {file = "zopfli-0.2.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:09ad5f8d7e0fe1975ca6d9fd5ad61c74233ae277982d3bc8814b599bbeb92f44"}, - {file = "zopfli-0.2.3-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78022777139ac973286219e9e085d9496fb6c935502d93a52bd1bed01dfc2002"}, - {file = "zopfli-0.2.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13d151d5c83980f384439c87a5511853890182c05d93444f3cb05e5ceed37d82"}, - {file = "zopfli-0.2.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c1afe5ba0d957e462afbd3da116ac1a2a6d23e8a94436a95b692c5c324694a16"}, - {file = "zopfli-0.2.3-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:81d61eba5a8e221b297a1dd27f1dae2785a14a5524cc1e144da53705cf90d5c4"}, - {file = "zopfli-0.2.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:f69b161b4d49e256ab285c6c6ee1cf217fda864a9b175d24fa0a0b8c2de9ff13"}, - {file = "zopfli-0.2.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:57f93802e5ddb20647747ee4039a2e18a26e91bac4c41d3d75a2b2c97f270549"}, - {file = "zopfli-0.2.3-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6225bbc33c4f803cdc1e71e3028af96dd0e1ed3cf061780d1bf05648df616a05"}, - {file = "zopfli-0.2.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:deffa15253a43a597e8ebf82ca1908bd70b3bf899da163b017d49ddd5e12732a"}, - {file = "zopfli-0.2.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:84321886cf3e80e086e0f6f7b765975343aafa61165315bb8db514d0bec2d887"}, - {file = "zopfli-0.2.3.zip", hash = "sha256:dbc9841bedd736041eb5e6982cd92da93bee145745f5422f3795f6f258cdc6ef"}, -] - -[package.extras] -test = ["pytest"] - [metadata] lock-version = "2.0" python-versions = ">=3.10,<=3.12" -content-hash = "60939a94351aded4151f3418c1936118fde6211c66494ccd9dec4211b21438a2" +content-hash = "f3daf46d95f2a36f2f74f3b0236149098663620232dd9ecde9fb5f7637ddf36b" diff --git a/pyproject.toml b/pyproject.toml index 6341b8fe..fbd952dd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -75,7 +75,6 @@ ssdeep = "3.4" tldextract = "3.4.0" tnefparse = "1.4.0" validators = "0.20.0" -weasyprint = "60.2" xlrd2 = "1.3.4" xlrd = "2.0.1" xmltodict = "0.13.0" diff --git a/src/python/strelka/scanners/scan_email.py b/src/python/strelka/scanners/scan_email.py index 7f5e8152..bc621270 100644 --- a/src/python/strelka/scanners/scan_email.py +++ b/src/python/strelka/scanners/scan_email.py @@ -6,70 +6,90 @@ import logging import os import tempfile +from typing import List import eml_parser import fitz # PyMuPDF import pytz from PIL import Image -from weasyprint import HTML from strelka import strelka -# Configure logging to suppress warnings for WeasyPrint and informational messages for fontTools -weasyprint_logger = logging.getLogger("weasyprint") -weasyprint_logger.setLevel(logging.ERROR) - +# Configure logging to suppress warnings for fontTools fonttools_logger = logging.getLogger("fontTools.subset") fonttools_logger.setLevel(logging.WARNING) class ScanEmail(strelka.Scanner): """ - Scanner that collects metadata, extracts files from email messages, and generates thumbnails. + Extracts and analyzes metadata, attachments, and generates thumbnails from email messages. + + This scanner processes email files to extract and analyze metadata and attachments. + It supports both plain text and HTML emails, including inline images. + + Scanner Type: Collection + + Attributes: + None + + ## Detection Use Cases + !!! info "Detection Use Cases" + - **Document Extraction** + - Extracts and analyzes documents, including attachments, from email messages for content review. + - **Email Header Analysis** + - Analyzes email headers for potential indicators of malicious activity, such as suspicious sender addresses + or subject lines. + + ## Known Limitations + !!! warning "Known Limitations" + - **Email Encoding and Complex Structures** + - Limited support for certain email encodings or complex email structures. + - **Limited Output** + - Content is limited to a set amount of characters to prevent excessive output. + + ## To Do + !!! question "To Do" + - **Improve Error Handling**: + - Enhance error handling for edge cases and complex email structures. + - **Enhance Support for Additional Email Encodings and Content Types**: + - Expand support for various email encodings and content types to improve scanning accuracy. + + ## References + !!! quote "References" + - [Python Email Parsing Documentation](https://docs.python.org/3/library/email.html) + - [PyMuPDF (fitz) Documentation](https://pymupdf.readthedocs.io/en/latest/) + + ## Contributors + !!! example "Contributors" + - [Josh Liburdi](https://github.com/jshlbrd) + - [Paul Hutelmyer](https://github.com/phutelmyer) + - [Ryan O'Horo](https://github.com/ryanohoro) - This scanner processes email files to extract metadata, attachments, and generates - thumbnail images of the email content for a visual overview. It handles both plain text and HTML emails, - including inline images. """ - def scan(self, data, file, options, expire_at): + def scan( + self, + data: bytes, + file: strelka.File, + options: dict, + expire_at: int, + ) -> None: """ - Processes the email, extracts metadata and attachments, and optionally generates a thumbnail. + Processes the email, extracts metadata, and attachments. Args: - data: The raw email data. - file: File details. - options: Scanner options including thumbnail creation and size. - expire_at: Expiry time of the scan. + data (bytes): The raw email data. + file (strelka.File): File details. + options (dict): Scanner options. + expire_at (int): Expiry time of the scan. + + Processes the email to extract metadata and attachments. """ + # Initialize data structures for storing scan results attachments = [] self.event["total"] = {"attachments": 0, "extracted": 0} - # Thumbnail creation based on user option - create_thumbnail = options.get("create_thumbnail", False) - thumbnail_header = options.get("thumbnail_header", False) - thumbnail_size = options.get("thumbnail_size", (500, 500)) - - # Attempt to create a thumbnail from the email - if create_thumbnail: - try: - image = self.create_email_thumbnail(data, thumbnail_header) - if image: - image.thumbnail(thumbnail_size, Image.Resampling.BILINEAR) - buffered = io.BytesIO() - image.save(buffered, format="WEBP", quality=30, optimize=True) - base64_image = base64.b64encode(buffered.getvalue()).decode("utf-8") - self.event["base64_thumbnail"] = base64_image - else: - self.flags.append( - f"{self.__class__.__name__}: image_thumbnail_error: Could not generate thumbnail. No HTML found." - ) - except Exception as e: - self.flags.append( - f"{self.__class__.__name__}: image_thumbnail_error: {str(e)[:50]}" - ) - # Parse email contents try: # Open and parse email byte string @@ -182,170 +202,8 @@ def scan(self, data, file, options, expire_at): f"{self.__class__.__name__}: email_parse_error: {str(e)[:50]}" ) - def create_email_thumbnail(self, data, show_header): - """ - Generates a thumbnail image from the content of an email message. - - This function processes the email to extract images and text, combines them into - a single image, and returns that image. - - Args: - show_header: Whether to show the header details in the output. - data: Raw email data. - - Returns: - A PIL Image object representing the combined thumbnail image of the email. - None if no images could be created. - """ - # Supported image types for extraction from the email - image_types = [ - "image/gif", - "image/jpeg", - "image/png", - "image/jpg", - "image/bmp", - "image/ico", - "image/svg", - "image/web", - ] - - # Dictionary to map content IDs to images - images_dict = {} - - # Create a temporary directory to store generated images - with tempfile.TemporaryDirectory() as temp_dir: - # Parse the email data - msg = email.message_from_bytes(data) - - # List to store paths of generated images - images_list = [] - - # Extract and format header details from the email - if show_header: - header_fields = ["Date", "From", "To", "Subject", "Message-Id"] - header_values = { - field: self.decode_and_format_header(msg, field) - for field in header_fields - } - - # Generate an HTML table from the header values - headers_html = '\n' - for field, value in header_values.items(): - headers_html += f' \n' - headers_html += "
{field}:{value}
\n

\n" - - # Convert HTML header details to an image - header_image_path = self.html_to_image(headers_html, temp_dir) - if header_image_path: - images_list.append(header_image_path) - - # Process the MIME parts to extract images - for part in msg.walk(): - if part.is_multipart(): - continue - - mime_type = part.get_content_type() - if mime_type in image_types: - # Extract image data and create a base64 encoded version - content_id = part.get("Content-ID", "").strip("<>") - image_data = part.get_payload(decode=True) - img_data_base64 = base64.b64encode(image_data).decode("utf-8") - images_dict[content_id] = img_data_base64 - - # Process HTML body parts and replace CID references with base64 data - for part in msg.walk(): - if part.get_content_type() == "text/html": - payload = part.get_payload(decode=True).decode("utf-8") - for cid, img_data in images_dict.items(): - payload = payload.replace( - f"cid:{cid}", f"data:image/jpeg;base64,{img_data}" - ) - - # Convert the modified HTML body to an image - body_image_path = self.html_to_image(payload, temp_dir) - if body_image_path: - images_list.append(body_image_path) - - # Combine all extracted images into a single image - if images_list: - images = [Image.open(path) for path in images_list] - return self.append_images(images) - - return None - @staticmethod - def html_to_image(html_content, temp_dir): - """ - Converts HTML content to an image. - - This method uses WeasyPrint to convert the HTML content to a PDF and then - uses PyMuPDF (fitz) to render the PDF as an image. The rendered image is saved as a PNG file. - - Args: - html_content: HTML content to be converted into an image. - temp_dir: Temporary directory to store intermediate files. - - Returns: - The file path to the generated image, or None if the process fails. - """ - # Generate a unique filename for the PDF - pdf_filename = hashlib.md5(html_content.encode()).hexdigest() + ".pdf" - pdf_path = os.path.join(temp_dir, pdf_filename) - - # Convert HTML to a PDF using WeasyPrint - try: - HTML(string=html_content).write_pdf(pdf_path) - - # Open the PDF with fitz and render the first page as an image - with fitz.open(pdf_path) as doc: - if doc.page_count > 0: - page = doc.load_page(0) # first page - pix = page.get_pixmap() - image_path = os.path.join( - temp_dir, pdf_filename.replace(".pdf", ".png") - ) - pix.save(image_path) - return image_path - else: - return None - except Exception: - return None - - @staticmethod - def append_images(images): - """ - Combines multiple image objects into a single image. - - This function stacks the provided images vertically to create one continuous image. - It's particularly useful for creating a visual summary of an email's content. - - Args: - images: A list of PIL Image objects to be combined. - - Returns: - A single PIL Image object that combines all the input images. - """ - # Define the background color for the combined image - bg_color = (255, 255, 255) - - # Calculate the total width (max width among images) and total height (sum of heights of all images) - widths, heights = zip(*(img.size for img in images)) - total_width = max(widths) - total_height = sum(heights) - - # Create a new image with the calculated dimensions - combined_image = Image.new("RGB", (total_width, total_height), color=bg_color) - - # Paste each image onto the combined image, one below the other - y_offset = 0 - for img in images: - combined_image.paste(img, (0, y_offset)) - y_offset += img.height - - return combined_image - - @staticmethod - def decode_and_format_header(msg, header_name): + def decode_and_format_header(msg: email.message.Message, header_name: str) -> str: """ Decodes and safely formats a specific header field from an email message. @@ -353,12 +211,13 @@ def decode_and_format_header(msg, header_name): into a human-readable format, and also ensures that the text is safe for HTML display. Args: - msg: Parsed email message object. - header_name: The name of the header field to decode. + msg (email.message.Message): Parsed email message object. + header_name (str): The name of the header field to decode. Returns: - A string representing the decoded and header field values. + A string representing the decoded and formatted header field values. Returns a placeholder string if the header field is missing or cannot be decoded. + """ try: # Decode the specified header field @@ -371,4 +230,4 @@ def decode_and_format_header(msg, header_name): field_value = "<Unknown>" # Replace angle brackets for HTML safety - return field_value.replace("<", "<").replace(">", ">") + return field_value.replace("<", "<").replace(">", ">") \ No newline at end of file diff --git a/src/python/strelka/tests/test_scan_email.py b/src/python/strelka/tests/test_scan_email.py index 1dc145b3..91b7bd8b 100644 --- a/src/python/strelka/tests/test_scan_email.py +++ b/src/python/strelka/tests/test_scan_email.py @@ -82,87 +82,6 @@ def test_scan_email(mocker): TestCase().assertDictEqual(test_scan_event, scanner_event) -def test_scan_email_with_thumbnail(mocker): - """ - Pass: Sample event matches output of scanner. - Failure: Unable to load file or sample event fails to match. - """ - - test_scan_event = { - "elapsed": mock.ANY, - "flags": [], - "total": {"attachments": 2, "extracted": 2}, - "body": "Lorem Ipsum\n\n[cid:image001.jpg@01D914BA.2B9507C0]\n\n\nLorem ipsum dolor sit amet, consectetur adipisci...tristique mi, quis finibus justo augue non ligula. Quisque facilisis dui in orci aliquet fermentum.\n", - "domains": unordered( - [ - "schemas.microsoft.com", - "www.w3.org", - "div.msonormal", - "span.msohyperlink", - "span.msohyperlinkfollowed", - "span.emailstyle17", - "1.0in", - "div.wordsection1", - ] - ), - "attachments": { - "filenames": ["image001.jpg", "test.doc"], - "hashes": unordered( - [ - "ee97b5bb7816b8ad3c3b4024a5d7ff06", - "33a13c0806ec35806889a93a5f259c7a", - ] - ), - "totalsize": 72819, - }, - "subject": "Lorem Ipsum", - "to": unordered(["baz.quk@example.com"]), - "from": "foo.bar@example.com", - "date_utc": "2022-12-21T02:29:49.000Z", - "message_id": "DS7PR03MB5640AD212589DFB7CE58D90CFBEB9@DS7PR03MB5640.namprd03.prod.outlook.com", - "received_domain": unordered( - [ - "ch2pr03mb5366.namprd03.prod.outlook.com", - "mx0b-0020ab02.pphosted.com", - "pps.filterd", - "mx.example.com", - "ds7pr03mb5640.namprd03.prod.outlook.com", - "mx0a-0020ab02.pphosted.com", - ] - ), - "received_ip": unordered( - [ - "022.12.20.18", - "fe80::bd8e:df17:2c2f:2490", - "8.17.1.19", - "2603:10b6:5:2c0::11", - "205.220.177.243", - "2603:10b6:610:96::16", - "127.0.0.1", - "2002:a05:6500:11d0:b0:17b:2a20:6c32", - ] - ), - "base64_thumbnail": "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", - } - - scanner_event = run_test_scan( - mocker=mocker, - scan_class=ScanUnderTest, - fixture_path=Path(__file__).parent / "fixtures/test.eml", - options={ - "create_thumbnail": True, - }, - ) - - TestCase.maxDiff = None - TestCase().assertDictEqual(test_scan_event, scanner_event) - - def test_scan_email_incomplete(mocker): """ Pass: Sample event matches output of scanner. @@ -171,9 +90,7 @@ def test_scan_email_incomplete(mocker): test_scan_event = { "elapsed": mock.ANY, - "flags": [ - "ScanEmail: image_thumbnail_error: Could not generate thumbnail. No HTML found." - ], + "flags": [], "total": {"attachments": 0, "extracted": 0}, "body": "Hi Placeholder,\n\nCan I have access?\n\nThanks,\nJohn\n\n\nFrom: Placeholder Smith " " shared a file or folder located in Acme Share with you. Delete visitor " @@ -198,4 +115,4 @@ def test_scan_email_incomplete(mocker): ) TestCase.maxDiff = None - TestCase().assertDictEqual(test_scan_event, scanner_event) + TestCase().assertDictEqual(test_scan_event, scanner_event) \ No newline at end of file From d5e947d145b26fd18361c5fb8ccf1e9e3882e201 Mon Sep 17 00:00:00 2001 From: Sara Kalupa Date: Thu, 27 Jun 2024 11:58:01 -0500 Subject: [PATCH 2/3] Update for formatting --- src/python/strelka/scanners/scan_email.py | 2 +- src/python/strelka/tests/test_scan_email.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/python/strelka/scanners/scan_email.py b/src/python/strelka/scanners/scan_email.py index bc621270..2f4bd7d4 100644 --- a/src/python/strelka/scanners/scan_email.py +++ b/src/python/strelka/scanners/scan_email.py @@ -230,4 +230,4 @@ def decode_and_format_header(msg: email.message.Message, header_name: str) -> st field_value = "<Unknown>" # Replace angle brackets for HTML safety - return field_value.replace("<", "<").replace(">", ">") \ No newline at end of file + return field_value.replace("<", "<").replace(">", ">") diff --git a/src/python/strelka/tests/test_scan_email.py b/src/python/strelka/tests/test_scan_email.py index 91b7bd8b..cd000f2d 100644 --- a/src/python/strelka/tests/test_scan_email.py +++ b/src/python/strelka/tests/test_scan_email.py @@ -115,4 +115,4 @@ def test_scan_email_incomplete(mocker): ) TestCase.maxDiff = None - TestCase().assertDictEqual(test_scan_event, scanner_event) \ No newline at end of file + TestCase().assertDictEqual(test_scan_event, scanner_event) From 598946087823a76934b4b01829950b85660e2b63 Mon Sep 17 00:00:00 2001 From: Sara Kalupa Date: Thu, 27 Jun 2024 12:00:10 -0500 Subject: [PATCH 3/3] Removing unused imports --- src/python/strelka/scanners/scan_email.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/python/strelka/scanners/scan_email.py b/src/python/strelka/scanners/scan_email.py index 2f4bd7d4..c9817396 100644 --- a/src/python/strelka/scanners/scan_email.py +++ b/src/python/strelka/scanners/scan_email.py @@ -1,17 +1,10 @@ import base64 import email import email.header -import hashlib -import io import logging -import os -import tempfile -from typing import List import eml_parser -import fitz # PyMuPDF import pytz -from PIL import Image from strelka import strelka