From 1817a3e13b8897b731144b8fc0af5113a4328734 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Mon, 23 May 2022 00:15:52 +0200 Subject: [PATCH] chg: sunday cleanup --- bin/archiver.py | 11 ++-- bin/async_capture.py | 126 +++++++++++++++++++-------------------- lookyloo/capturecache.py | 18 +++--- lookyloo/context.py | 2 +- lookyloo/helpers.py | 4 +- lookyloo/lookyloo.py | 4 +- poetry.lock | 82 ++++++++++++++----------- pyproject.toml | 5 +- 8 files changed, 133 insertions(+), 119 deletions(-) diff --git a/bin/archiver.py b/bin/archiver.py index 999c4c9..f80dcbe 100755 --- a/bin/archiver.py +++ b/bin/archiver.py @@ -3,6 +3,7 @@ import csv import logging from collections import defaultdict +from collections.abc import Mapping from datetime import datetime, timedelta from pathlib import Path from typing import Dict, List @@ -21,7 +22,7 @@ class Archiver(AbstractManager): def __init__(self, loglevel: int=logging.INFO): super().__init__(loglevel) self.script_name = 'archiver' - self.redis = Redis(unix_socket_path=get_socket_path('cache')) + self.redis = Redis(unix_socket_path=get_socket_path('cache'), decode_responses=True) # make sure archived captures dir exists self.archived_captures_dir = get_homedir() / 'archived_captures' @@ -117,18 +118,18 @@ class Archiver(AbstractManager): # Initialize archives for index in get_captures_dir().glob('**/index'): with index.open('r') as _f: - recent_uuids: Dict[str, str] = {uuid: str(index.parent / dirname) for uuid, dirname in csv.reader(_f) if (index.parent / dirname).exists()} + recent_uuids: Mapping = {uuid: str(index.parent / dirname) for uuid, dirname in csv.reader(_f) if (index.parent / dirname).exists()} if recent_uuids: - self.redis.hmset('lookup_dirs', recent_uuids) # type: ignore + self.redis.hset('lookup_dirs', mapping=recent_uuids) else: index.unlink() # Initialize archives for index in self.archived_captures_dir.glob('**/index'): with index.open('r') as _f: - archived_uuids: Dict[str, str] = {uuid: str(index.parent / dirname) for uuid, dirname in csv.reader(_f) if (index.parent / dirname).exists()} + archived_uuids: Mapping = {uuid: str(index.parent / dirname) for uuid, dirname in csv.reader(_f) if (index.parent / dirname).exists()} if archived_uuids: - self.redis.hmset('lookup_dirs_archived', archived_uuids) # type: ignore + self.redis.hset('lookup_dirs_archived', mapping=archived_uuids) else: index.unlink() diff --git a/bin/async_capture.py b/bin/async_capture.py index 084986e..bfe67be 100755 --- a/bin/async_capture.py +++ b/bin/async_capture.py @@ -12,7 +12,7 @@ from typing import Dict, List, Optional, Tuple, Union from urllib.parse import urlsplit from defang import refang # type: ignore -from redis import Redis +from redis.asyncio import Redis from playwrightcapture import Capture from lookyloo.default import AbstractManager, get_config, get_socket_path, safe_create_dir @@ -31,7 +31,6 @@ class AsyncCapture(AbstractManager): self.script_name = 'async_capture' self.only_global_lookups: bool = get_config('generic', 'only_global_lookups') self.capture_dir: Path = get_captures_dir() - self.redis = Redis(unix_socket_path=get_socket_path('cache'), decode_responses=True) self.fox = FOX(get_config('modules', 'FOX')) if not self.fox.available: @@ -43,65 +42,65 @@ class AsyncCapture(AbstractManager): async def process_capture_queue(self) -> None: '''Process a query from the capture queue''' - value: Optional[List[Tuple[str, int]]] = self.redis.zpopmax('to_capture') # type: ignore + value: List[Tuple[str, float]] = await self.redis.zpopmax('to_capture') if not value or not value[0]: # The queue was consumed by an other process. return uuid, _score = value[0] - queue: Optional[str] = self.redis.get(f'{uuid}_mgmt') - self.redis.sadd('ongoing', uuid) + queue: Optional[str] = await self.redis.get(f'{uuid}_mgmt') + await self.redis.sadd('ongoing', uuid) - lazy_cleanup = self.redis.pipeline() - lazy_cleanup.delete(f'{uuid}_mgmt') - if queue: - # queue shouldn't be none, but if it is, just ignore. - lazy_cleanup.zincrby('queues', -1, queue) + async with self.redis.pipeline() as lazy_cleanup: + await lazy_cleanup.delete(f'{uuid}_mgmt') + if queue: + # queue shouldn't be none, but if it is, just ignore. + await lazy_cleanup.zincrby('queues', -1, queue) - to_capture: Dict[str, str] = self.redis.hgetall(uuid) + to_capture: Dict[str, str] = await self.redis.hgetall(uuid) - if get_config('generic', 'default_public'): - # By default, the captures are on the index, unless the user mark them as un-listed - listing = False if ('listing' in to_capture and to_capture['listing'].lower() in ['false', '0', '']) else True - else: - # By default, the captures are not on the index, unless the user mark them as listed - listing = True if ('listing' in to_capture and to_capture['listing'].lower() in ['true', '1']) else False + if get_config('generic', 'default_public'): + # By default, the captures are on the index, unless the user mark them as un-listed + listing = False if ('listing' in to_capture and to_capture['listing'].lower() in ['false', '0', '']) else True + else: + # By default, the captures are not on the index, unless the user mark them as listed + listing = True if ('listing' in to_capture and to_capture['listing'].lower() in ['true', '1']) else False - # Turn the freetext for the headers into a dict - headers = {} - if 'headers' in to_capture: - for header_line in to_capture['headers'].splitlines(): - if header_line and ':' in header_line: - splitted = header_line.split(':', 1) - if splitted and len(splitted) == 2: - header, h_value = splitted - if header and h_value: - headers[header.strip()] = h_value.strip() + # Turn the freetext for the headers into a dict + headers = {} + if 'headers' in to_capture: + for header_line in to_capture['headers'].splitlines(): + if header_line and ':' in header_line: + splitted = header_line.split(':', 1) + if splitted and len(splitted) == 2: + header, h_value = splitted + if header and h_value: + headers[header.strip()] = h_value.strip() - self.logger.info(f'Capturing {to_capture["url"]} - {uuid}') - self.thirdparty_submit(to_capture) - success, error_message = await self._capture( - to_capture['url'], - perma_uuid=uuid, - cookies_pseudofile=to_capture.get('cookies', None), - listing=listing, - user_agent=to_capture.get('user_agent', None), - referer=to_capture.get('referer', None), - headers=headers if headers else None, - proxy=to_capture.get('proxy', None), - os=to_capture.get('os', None), - browser=to_capture.get('browser', None), - parent=to_capture.get('parent', None) - ) - if success: - self.logger.info(f'Successfully captured {to_capture["url"]} - {uuid}') - else: - self.logger.warning(f'Unable to capture {to_capture["url"]} - {uuid}: {error_message}') - lazy_cleanup.setex(f'error_{uuid}', 36000, f'{error_message} - {to_capture["url"]} - {uuid}') - lazy_cleanup.srem('ongoing', uuid) - lazy_cleanup.delete(uuid) - # make sure to expire the key if nothing was processed for a while (= queues empty) - lazy_cleanup.expire('queues', 600) - lazy_cleanup.execute() + self.logger.info(f'Capturing {to_capture["url"]} - {uuid}') + self.thirdparty_submit(to_capture) + success, error_message = await self._capture( + to_capture['url'], + perma_uuid=uuid, + cookies_pseudofile=to_capture.get('cookies', None), + listing=listing, + user_agent=to_capture.get('user_agent', None), + referer=to_capture.get('referer', None), + headers=headers if headers else None, + proxy=to_capture.get('proxy', None), + os=to_capture.get('os', None), + browser=to_capture.get('browser', None), + parent=to_capture.get('parent', None) + ) + if success: + self.logger.info(f'Successfully captured {to_capture["url"]} - {uuid}') + else: + self.logger.warning(f'Unable to capture {to_capture["url"]} - {uuid}: {error_message}') + await lazy_cleanup.setex(f'error_{uuid}', 36000, f'{error_message} - {to_capture["url"]} - {uuid}') + await lazy_cleanup.srem('ongoing', uuid) + await lazy_cleanup.delete(uuid) + # make sure to expire the key if nothing was processed for a while (= queues empty) + await lazy_cleanup.expire('queues', 600) + await lazy_cleanup.execute() async def _capture(self, url: str, *, perma_uuid: str, cookies_pseudofile: Optional[Union[BufferedIOBase, str]]=None, listing: bool=True, user_agent: Optional[str]=None, @@ -116,15 +115,14 @@ class AsyncCapture(AbstractManager): splitted_url = urlsplit(url) if self.only_global_lookups: if splitted_url.netloc: - if splitted_url.hostname: - if splitted_url.hostname.split('.')[-1] != 'onion': - try: - ip = socket.gethostbyname(splitted_url.hostname) - except socket.gaierror: - self.logger.info('Name or service not known') - return False, 'Name or service not known.' - if not ipaddress.ip_address(ip).is_global: - return False, 'Capturing ressources on private IPs is disabled.' + if splitted_url.hostname and splitted_url.hostname.split('.')[-1] != 'onion': + try: + ip = socket.gethostbyname(splitted_url.hostname) + except socket.gaierror: + self.logger.info('Name or service not known') + return False, 'Name or service not known.' + if not ipaddress.ip_address(ip).is_global: + return False, 'Capturing ressources on private IPs is disabled.' else: return False, 'Unable to find hostname or IP in the query.' @@ -208,14 +206,16 @@ class AsyncCapture(AbstractManager): if 'cookies' in entries and entries['cookies']: with (dirpath / '0.cookies.json').open('w') as _cookies: json.dump(entries['cookies'], _cookies) - self.redis.hset('lookup_dirs', perma_uuid, str(dirpath)) + await self.redis.hset('lookup_dirs', perma_uuid, str(dirpath)) return True, 'All good!' async def _to_run_forever_async(self): - while self.redis.exists('to_capture'): + self.redis: Redis = Redis(unix_socket_path=get_socket_path('cache'), decode_responses=True) + while await self.redis.exists('to_capture'): await self.process_capture_queue() if self.shutdown_requested(): break + await self.redis.close() def main(): diff --git a/lookyloo/capturecache.py b/lookyloo/capturecache.py index bb777ce..f930816 100644 --- a/lookyloo/capturecache.py +++ b/lookyloo/capturecache.py @@ -294,7 +294,7 @@ class CapturesIndex(Mapping): p = self.redis.pipeline() p.hset('lookup_dirs', uuid, str(capture_dir)) - p.hmset(str(capture_dir), cache) # type: ignore + p.hset(str(capture_dir), mapping=cache) # type: ignore p.execute() return CaptureCache(cache) @@ -304,7 +304,7 @@ class CapturesIndex(Mapping): Updates the nodes of the tree accordingly so the information is available. ''' - def _build_cname_chain(known_cnames: Dict[str, Optional[str]], hostname) -> List[str]: + def _build_cname_chain(known_cnames: Dict[str, str], hostname) -> List[str]: '''Returns a list of CNAMEs starting from one hostname. The CNAMEs resolutions are made in `_resolve_dns`. A hostname can have a CNAME entry and the CNAME entry can have an other CNAME entry, and so on multiple times. @@ -312,16 +312,15 @@ class CapturesIndex(Mapping): cnames: List[str] = [] to_search = hostname while True: - if known_cnames.get(to_search) is None: + if not known_cnames.get(to_search): break - # At this point, known_cnames[to_search] must exist and be a str - cnames.append(known_cnames[to_search]) # type: ignore + cnames.append(known_cnames[to_search]) to_search = known_cnames[to_search] return cnames cnames_path = ct.root_hartree.har.path.parent / 'cnames.json' ips_path = ct.root_hartree.har.path.parent / 'ips.json' - host_cnames: Dict[str, Optional[str]] = {} + host_cnames: Dict[str, str] = {} if cnames_path.exists(): try: with cnames_path.open() as f: @@ -348,15 +347,14 @@ class CapturesIndex(Mapping): if answer.rdtype == dns.rdatatype.RdataType.CNAME: host_cnames[str(answer.name).rstrip('.')] = str(answer[0].target).rstrip('.') else: - host_cnames[str(answer.name).rstrip('.')] = None + host_cnames[str(answer.name).rstrip('.')] = '' if answer.rdtype in [dns.rdatatype.RdataType.A, dns.rdatatype.RdataType.AAAA]: host_ips[str(answer.name).rstrip('.')] = list({str(b) for b in answer}) except Exception: - host_cnames[node.name] = None + host_cnames[node.name] = '' host_ips[node.name] = [] - cnames = _build_cname_chain(host_cnames, node.name) - if cnames: + if (cnames := _build_cname_chain(host_cnames, node.name)): node.add_feature('cname', cnames) if cnames[-1] in host_ips: node.add_feature('resolved_ips', host_ips[cnames[-1]]) diff --git a/lookyloo/context.py b/lookyloo/context.py index 025d80c..49676bb 100644 --- a/lookyloo/context.py +++ b/lookyloo/context.py @@ -35,7 +35,7 @@ class Context(): if filename == 'generic': # 1px images, files with spaces, empty => non-relevant stuff for _, type_content in file_content.items(): - p.hmset('known_content', {h: type_content['description'] for h in type_content['entries']}) + p.hset('known_content', mapping={h: type_content['description'] for h in type_content['entries']}) elif filename == 'malicious': # User defined as malicious for h, details in file_content.items(): diff --git a/lookyloo/helpers.py b/lookyloo/helpers.py index 87026ea..fbae98c 100644 --- a/lookyloo/helpers.py +++ b/lookyloo/helpers.py @@ -120,9 +120,9 @@ def load_cookies(cookie_pseudofile: Optional[Union[BufferedIOBase, str]]=None) - try: for cookie in cookies: to_add: Dict[str, Union[str, bool]] - if 'Host raw' in cookie: + if 'Host raw' in cookie and isinstance(cookie['Host raw'], str): # Cookie export format for Cookie Quick Manager - u = urlparse(cookie['Host raw']).netloc.split(':', 1)[0] # type: ignore + u = urlparse(cookie['Host raw']).netloc.split(':', 1)[0] to_add = {'path': cookie['Path raw'], 'name': cookie['Name raw'], 'httpOnly': cookie['HTTP only raw'] == 'true', diff --git a/lookyloo/lookyloo.py b/lookyloo/lookyloo.py index ed04da0..88eceea 100644 --- a/lookyloo/lookyloo.py +++ b/lookyloo/lookyloo.py @@ -19,7 +19,7 @@ from zipfile import ZipFile from defang import defang # type: ignore from har2tree import CrawledTree, HostNode, URLNode -from PIL import Image, UnidentifiedImageError # type: ignore +from PIL import Image, UnidentifiedImageError from pymisp import MISPAttribute, MISPEvent, MISPObject from redis import ConnectionPool, Redis from redis.connection import UnixDomainSocketConnection @@ -387,7 +387,7 @@ class Lookyloo(): if priority < -10: # Someone is probably abusing the system with useless URLs, remove them from the index query['listing'] = 0 - p.hmset(perma_uuid, query) + p.hset(perma_uuid, mapping=query) p.zadd('to_capture', {perma_uuid: priority}) p.zincrby('queues', 1, f'{source}|{authenticated}|{user}') p.set(f'{perma_uuid}_mgmt', f'{source}|{authenticated}|{user}') diff --git a/poetry.lock b/poetry.lock index ed76ff3..47ac69e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -421,7 +421,7 @@ python-versions = ">=3.5" [[package]] name = "importlib-metadata" -version = "4.11.3" +version = "4.11.4" description = "Read metadata from Python packages" category = "main" optional = false @@ -616,7 +616,7 @@ python-versions = "*" [[package]] name = "numpy" -version = "1.22.3" +version = "1.22.4" description = "NumPy is the fundamental package for array computing with Python." category = "main" optional = false @@ -910,7 +910,7 @@ six = ">=1.5" [[package]] name = "python-magic" -version = "0.4.25" +version = "0.4.26" description = "File type identification using libmagic" category = "main" optional = true @@ -1103,6 +1103,14 @@ category = "dev" optional = false python-versions = "*" +[[package]] +name = "types-pillow" +version = "9.0.15" +description = "Typing stubs for Pillow" +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "types-pkg-resources" version = "0.1.3" @@ -1121,7 +1129,7 @@ python-versions = "*" [[package]] name = "types-redis" -version = "4.2.4" +version = "4.2.5" description = "Typing stubs for redis" category = "dev" optional = false @@ -1140,7 +1148,7 @@ types-urllib3 = "<1.27" [[package]] name = "types-setuptools" -version = "57.4.14" +version = "57.4.15" description = "Typing stubs for setuptools" category = "dev" optional = false @@ -1320,7 +1328,7 @@ misp = ["python-magic", "pydeep2"] [metadata] lock-version = "1.1" python-versions = ">=3.8,<3.11" -content-hash = "42236f7345b82436083464511c96e002470f4c17d3a731ccfa2ffa1570c63d19" +content-hash = "91b738a6001f33ba9ce90ebf654bb341713feff6e5d9bcf0630598492d3d9570" [metadata.files] aiohttp = [ @@ -1726,8 +1734,8 @@ idna = [ {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"}, ] importlib-metadata = [ - {file = "importlib_metadata-4.11.3-py3-none-any.whl", hash = "sha256:1208431ca90a8cca1a6b8af391bb53c1a2db74e5d1cef6ddced95d4b2062edc6"}, - {file = "importlib_metadata-4.11.3.tar.gz", hash = "sha256:ea4c597ebf37142f827b8f39299579e31685c31d3a438b59f469406afd0f2539"}, + {file = "importlib_metadata-4.11.4-py3-none-any.whl", hash = "sha256:c58c8eb8a762858f49e18436ff552e83914778e50e9d2f1660535ffb364552ec"}, + {file = "importlib_metadata-4.11.4.tar.gz", hash = "sha256:5d26852efe48c0a32b0509ffbc583fda1a2266545a78d104a6f4aff3db17d700"}, ] importlib-resources = [ {file = "importlib_resources-5.7.1-py3-none-any.whl", hash = "sha256:e447dc01619b1e951286f3929be820029d48c75eb25d265c28b92a16548212b8"}, @@ -1979,26 +1987,28 @@ mypy-extensions = [ {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, ] numpy = [ - {file = "numpy-1.22.3-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:92bfa69cfbdf7dfc3040978ad09a48091143cffb778ec3b03fa170c494118d75"}, - {file = "numpy-1.22.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8251ed96f38b47b4295b1ae51631de7ffa8260b5b087808ef09a39a9d66c97ab"}, - {file = "numpy-1.22.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48a3aecd3b997bf452a2dedb11f4e79bc5bfd21a1d4cc760e703c31d57c84b3e"}, - {file = "numpy-1.22.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3bae1a2ed00e90b3ba5f7bd0a7c7999b55d609e0c54ceb2b076a25e345fa9f4"}, - {file = "numpy-1.22.3-cp310-cp310-win32.whl", hash = "sha256:f950f8845b480cffe522913d35567e29dd381b0dc7e4ce6a4a9f9156417d2430"}, - {file = "numpy-1.22.3-cp310-cp310-win_amd64.whl", hash = "sha256:08d9b008d0156c70dc392bb3ab3abb6e7a711383c3247b410b39962263576cd4"}, - {file = "numpy-1.22.3-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:201b4d0552831f7250a08d3b38de0d989d6f6e4658b709a02a73c524ccc6ffce"}, - {file = "numpy-1.22.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f8c1f39caad2c896bc0018f699882b345b2a63708008be29b1f355ebf6f933fe"}, - {file = "numpy-1.22.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:568dfd16224abddafb1cbcce2ff14f522abe037268514dd7e42c6776a1c3f8e5"}, - {file = "numpy-1.22.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ca688e1b9b95d80250bca34b11a05e389b1420d00e87a0d12dc45f131f704a1"}, - {file = "numpy-1.22.3-cp38-cp38-win32.whl", hash = "sha256:e7927a589df200c5e23c57970bafbd0cd322459aa7b1ff73b7c2e84d6e3eae62"}, - {file = "numpy-1.22.3-cp38-cp38-win_amd64.whl", hash = "sha256:07a8c89a04997625236c5ecb7afe35a02af3896c8aa01890a849913a2309c676"}, - {file = "numpy-1.22.3-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:2c10a93606e0b4b95c9b04b77dc349b398fdfbda382d2a39ba5a822f669a0123"}, - {file = "numpy-1.22.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fade0d4f4d292b6f39951b6836d7a3c7ef5b2347f3c420cd9820a1d90d794802"}, - {file = "numpy-1.22.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bfb1bb598e8229c2d5d48db1860bcf4311337864ea3efdbe1171fb0c5da515d"}, - {file = "numpy-1.22.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97098b95aa4e418529099c26558eeb8486e66bd1e53a6b606d684d0c3616b168"}, - {file = "numpy-1.22.3-cp39-cp39-win32.whl", hash = "sha256:fdf3c08bce27132395d3c3ba1503cac12e17282358cb4bddc25cc46b0aca07aa"}, - {file = "numpy-1.22.3-cp39-cp39-win_amd64.whl", hash = "sha256:639b54cdf6aa4f82fe37ebf70401bbb74b8508fddcf4797f9fe59615b8c5813a"}, - {file = "numpy-1.22.3-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c34ea7e9d13a70bf2ab64a2532fe149a9aced424cd05a2c4ba662fd989e3e45f"}, - {file = "numpy-1.22.3.zip", hash = "sha256:dbc7601a3b7472d559dc7b933b18b4b66f9aa7452c120e87dfb33d02008c8a18"}, + {file = "numpy-1.22.4-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:ba9ead61dfb5d971d77b6c131a9dbee62294a932bf6a356e48c75ae684e635b3"}, + {file = "numpy-1.22.4-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:1ce7ab2053e36c0a71e7a13a7475bd3b1f54750b4b433adc96313e127b870887"}, + {file = "numpy-1.22.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7228ad13744f63575b3a972d7ee4fd61815b2879998e70930d4ccf9ec721dce0"}, + {file = "numpy-1.22.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:43a8ca7391b626b4c4fe20aefe79fec683279e31e7c79716863b4b25021e0e74"}, + {file = "numpy-1.22.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a911e317e8c826ea632205e63ed8507e0dc877dcdc49744584dfc363df9ca08c"}, + {file = "numpy-1.22.4-cp310-cp310-win32.whl", hash = "sha256:9ce7df0abeabe7fbd8ccbf343dc0db72f68549856b863ae3dd580255d009648e"}, + {file = "numpy-1.22.4-cp310-cp310-win_amd64.whl", hash = "sha256:3e1ffa4748168e1cc8d3cde93f006fe92b5421396221a02f2274aab6ac83b077"}, + {file = "numpy-1.22.4-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:59d55e634968b8f77d3fd674a3cf0b96e85147cd6556ec64ade018f27e9479e1"}, + {file = "numpy-1.22.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c1d937820db6e43bec43e8d016b9b3165dcb42892ea9f106c70fb13d430ffe72"}, + {file = "numpy-1.22.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4c5d5eb2ec8da0b4f50c9a843393971f31f1d60be87e0fb0917a49133d257d6"}, + {file = "numpy-1.22.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64f56fc53a2d18b1924abd15745e30d82a5782b2cab3429aceecc6875bd5add0"}, + {file = "numpy-1.22.4-cp38-cp38-win32.whl", hash = "sha256:fb7a980c81dd932381f8228a426df8aeb70d59bbcda2af075b627bbc50207cba"}, + {file = "numpy-1.22.4-cp38-cp38-win_amd64.whl", hash = "sha256:e96d7f3096a36c8754207ab89d4b3282ba7b49ea140e4973591852c77d09eb76"}, + {file = "numpy-1.22.4-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:4c6036521f11a731ce0648f10c18ae66d7143865f19f7299943c985cdc95afb5"}, + {file = "numpy-1.22.4-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:b89bf9b94b3d624e7bb480344e91f68c1c6c75f026ed6755955117de00917a7c"}, + {file = "numpy-1.22.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2d487e06ecbf1dc2f18e7efce82ded4f705f4bd0cd02677ffccfb39e5c284c7e"}, + {file = "numpy-1.22.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3eb268dbd5cfaffd9448113539e44e2dd1c5ca9ce25576f7c04a5453edc26fa"}, + {file = "numpy-1.22.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37431a77ceb9307c28382c9773da9f306435135fae6b80b62a11c53cfedd8802"}, + {file = "numpy-1.22.4-cp39-cp39-win32.whl", hash = "sha256:cc7f00008eb7d3f2489fca6f334ec19ca63e31371be28fd5dad955b16ec285bd"}, + {file = "numpy-1.22.4-cp39-cp39-win_amd64.whl", hash = "sha256:f0725df166cf4785c0bc4cbfb320203182b1ecd30fee6e541c8752a92df6aa32"}, + {file = "numpy-1.22.4-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0791fbd1e43bf74b3502133207e378901272f3c156c4df4954cad833b1380207"}, + {file = "numpy-1.22.4.zip", hash = "sha256:425b390e4619f58d8526b3dcf656dde069133ae5c240229821f01b5f44ea07af"}, ] packaging = [ {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, @@ -2170,8 +2180,8 @@ python-dateutil = [ {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, ] python-magic = [ - {file = "python-magic-0.4.25.tar.gz", hash = "sha256:21f5f542aa0330f5c8a64442528542f6215c8e18d2466b399b0d9d39356d83fc"}, - {file = "python_magic-0.4.25-py2.py3-none-any.whl", hash = "sha256:1a2c81e8f395c744536369790bd75094665e9644110a6623bcc3bbea30f03973"}, + {file = "python-magic-0.4.26.tar.gz", hash = "sha256:8262c13001f904ad5b724d38b5e5b5f17ec0450ae249def398a62e4e33108a50"}, + {file = "python_magic-0.4.26-py2.py3-none-any.whl", hash = "sha256:b978c4b69a20510d133a7f488910c2f07e7796f1f31703e61c241973f2bbf5fb"}, ] pytz = [ {file = "pytz-2022.1-py2.py3-none-any.whl", hash = "sha256:e68985985296d9a66a881eb3193b0906246245294a881e7c8afe623866ac6a5c"}, @@ -2313,6 +2323,10 @@ types-markupsafe = [ {file = "types-MarkupSafe-1.1.10.tar.gz", hash = "sha256:85b3a872683d02aea3a5ac2a8ef590193c344092032f58457287fbf8e06711b1"}, {file = "types_MarkupSafe-1.1.10-py3-none-any.whl", hash = "sha256:ca2bee0f4faafc45250602567ef38d533e877d2ddca13003b319c551ff5b3cc5"}, ] +types-pillow = [ + {file = "types-Pillow-9.0.15.tar.gz", hash = "sha256:d2e385fe5c192e75970f18accce69f5c2a9f186f3feb578a9b91cd6fdf64211d"}, + {file = "types_Pillow-9.0.15-py3-none-any.whl", hash = "sha256:c9646595dfafdf8b63d4b1443292ead17ee0fc7b18a143e497b68e0ea2dc1eb6"}, +] types-pkg-resources = [ {file = "types-pkg_resources-0.1.3.tar.gz", hash = "sha256:834a9b8d3dbea343562fd99d5d3359a726f6bf9d3733bccd2b4f3096fbab9dae"}, {file = "types_pkg_resources-0.1.3-py2.py3-none-any.whl", hash = "sha256:0cb9972cee992249f93fff1a491bf2dc3ce674e5a1926e27d4f0866f7d9b6d9c"}, @@ -2322,16 +2336,16 @@ types-python-dateutil = [ {file = "types_python_dateutil-2.8.16-py3-none-any.whl", hash = "sha256:0e7286436d049d2732ba2f01552f84c52184b955552359156fc8835c10714f2a"}, ] types-redis = [ - {file = "types-redis-4.2.4.tar.gz", hash = "sha256:5574d58d95aa77fbb918eba7c183d0a0231b5e02d66d8aeb701e5310a01feabf"}, - {file = "types_redis-4.2.4-py3-none-any.whl", hash = "sha256:117167b25585acfc246162f025e18885098dcbe764b2c55d964cac90cd1660f3"}, + {file = "types-redis-4.2.5.tar.gz", hash = "sha256:88f04d99f20c20c3d0129c37601f9e70c01b71f1faef473766cfa3dddbd5e5d5"}, + {file = "types_redis-4.2.5-py3-none-any.whl", hash = "sha256:c0123db52d9b1a887cd3c7bc0d9cb03893dc3873969ffc55a99c9a9ad9d32a79"}, ] types-requests = [ {file = "types-requests-2.27.27.tar.gz", hash = "sha256:d618d9809fa32f514cf17cea8460814da671c56366fb1c908accca8bf183112b"}, {file = "types_requests-2.27.27-py3-none-any.whl", hash = "sha256:6d8463ffe1f6edcf2e5361740a6140e7a16d427c267d83c7c1d3d1298f4e67c5"}, ] types-setuptools = [ - {file = "types-setuptools-57.4.14.tar.gz", hash = "sha256:df02fe1dd244f58cf4e67cfc3d0a97930a2d61a72dd89f21d81c71017cd83f9a"}, - {file = "types_setuptools-57.4.14-py3-none-any.whl", hash = "sha256:828f7e7e51e157876f47c80518b23ba0c3c36aa8081efd39d5d39f393938aec9"}, + {file = "types-setuptools-57.4.15.tar.gz", hash = "sha256:650528ce803586029d7f153f32aed2dbaa6bb2888b233334af80d7ba63ed3c87"}, + {file = "types_setuptools-57.4.15-py3-none-any.whl", hash = "sha256:f8f19876f714a440c4badef1b91b0648604ed443e703d29d44cd36ac93b01a77"}, ] types-urllib3 = [ {file = "types-urllib3-1.26.14.tar.gz", hash = "sha256:2a2578e4b36341ccd240b00fccda9826988ff0589a44ba4a664bbd69ef348d27"}, diff --git a/pyproject.toml b/pyproject.toml index 839208b..a7960d3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -72,14 +72,15 @@ misp = ['python-magic', 'pydeep2'] [tool.poetry.dev-dependencies] mypy = "^0.950" ipython = "^8.2.0" -types-redis = "^4.2.4" +types-redis = "^4.2.5" types-requests = "^2.27.27" types-Flask = "^1.1.6" types-pkg-resources = "^0.1.3" types-Deprecated = "^1.2.8" types-python-dateutil = "^2.8.16" types-beautifulsoup4 = "^4.11.1" -types-setuptools = "^57.4.14" +types-setuptools = "^57.4.15" +types-Pillow = "^9.0.15" [build-system] requires = ["poetry_core>=1.0", "setuptools"]