chg: sunday cleanup

pull/424/head
Raphaël Vinot 2022-05-23 00:15:52 +02:00
parent 549861d3de
commit 1817a3e13b
8 changed files with 133 additions and 119 deletions

View File

@ -3,6 +3,7 @@
import csv import csv
import logging import logging
from collections import defaultdict from collections import defaultdict
from collections.abc import Mapping
from datetime import datetime, timedelta from datetime import datetime, timedelta
from pathlib import Path from pathlib import Path
from typing import Dict, List from typing import Dict, List
@ -21,7 +22,7 @@ class Archiver(AbstractManager):
def __init__(self, loglevel: int=logging.INFO): def __init__(self, loglevel: int=logging.INFO):
super().__init__(loglevel) super().__init__(loglevel)
self.script_name = 'archiver' 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 # make sure archived captures dir exists
self.archived_captures_dir = get_homedir() / 'archived_captures' self.archived_captures_dir = get_homedir() / 'archived_captures'
@ -117,18 +118,18 @@ class Archiver(AbstractManager):
# Initialize archives # Initialize archives
for index in get_captures_dir().glob('**/index'): for index in get_captures_dir().glob('**/index'):
with index.open('r') as _f: 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: if recent_uuids:
self.redis.hmset('lookup_dirs', recent_uuids) # type: ignore self.redis.hset('lookup_dirs', mapping=recent_uuids)
else: else:
index.unlink() index.unlink()
# Initialize archives # Initialize archives
for index in self.archived_captures_dir.glob('**/index'): for index in self.archived_captures_dir.glob('**/index'):
with index.open('r') as _f: 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: if archived_uuids:
self.redis.hmset('lookup_dirs_archived', archived_uuids) # type: ignore self.redis.hset('lookup_dirs_archived', mapping=archived_uuids)
else: else:
index.unlink() index.unlink()

View File

@ -12,7 +12,7 @@ from typing import Dict, List, Optional, Tuple, Union
from urllib.parse import urlsplit from urllib.parse import urlsplit
from defang import refang # type: ignore from defang import refang # type: ignore
from redis import Redis from redis.asyncio import Redis
from playwrightcapture import Capture from playwrightcapture import Capture
from lookyloo.default import AbstractManager, get_config, get_socket_path, safe_create_dir 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.script_name = 'async_capture'
self.only_global_lookups: bool = get_config('generic', 'only_global_lookups') self.only_global_lookups: bool = get_config('generic', 'only_global_lookups')
self.capture_dir: Path = get_captures_dir() 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')) self.fox = FOX(get_config('modules', 'FOX'))
if not self.fox.available: if not self.fox.available:
@ -43,65 +42,65 @@ class AsyncCapture(AbstractManager):
async def process_capture_queue(self) -> None: async def process_capture_queue(self) -> None:
'''Process a query from the capture queue''' '''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]: if not value or not value[0]:
# The queue was consumed by an other process. # The queue was consumed by an other process.
return return
uuid, _score = value[0] uuid, _score = value[0]
queue: Optional[str] = self.redis.get(f'{uuid}_mgmt') queue: Optional[str] = await self.redis.get(f'{uuid}_mgmt')
self.redis.sadd('ongoing', uuid) await self.redis.sadd('ongoing', uuid)
lazy_cleanup = self.redis.pipeline() async with self.redis.pipeline() as lazy_cleanup:
lazy_cleanup.delete(f'{uuid}_mgmt') await lazy_cleanup.delete(f'{uuid}_mgmt')
if queue: if queue:
# queue shouldn't be none, but if it is, just ignore. # queue shouldn't be none, but if it is, just ignore.
lazy_cleanup.zincrby('queues', -1, queue) 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'): if get_config('generic', 'default_public'):
# By default, the captures are on the index, unless the user mark them as un-listed # 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 listing = False if ('listing' in to_capture and to_capture['listing'].lower() in ['false', '0', '']) else True
else: else:
# By default, the captures are not on the index, unless the user mark them as listed # 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 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 # Turn the freetext for the headers into a dict
headers = {} headers = {}
if 'headers' in to_capture: if 'headers' in to_capture:
for header_line in to_capture['headers'].splitlines(): for header_line in to_capture['headers'].splitlines():
if header_line and ':' in header_line: if header_line and ':' in header_line:
splitted = header_line.split(':', 1) splitted = header_line.split(':', 1)
if splitted and len(splitted) == 2: if splitted and len(splitted) == 2:
header, h_value = splitted header, h_value = splitted
if header and h_value: if header and h_value:
headers[header.strip()] = h_value.strip() headers[header.strip()] = h_value.strip()
self.logger.info(f'Capturing {to_capture["url"]} - {uuid}') self.logger.info(f'Capturing {to_capture["url"]} - {uuid}')
self.thirdparty_submit(to_capture) self.thirdparty_submit(to_capture)
success, error_message = await self._capture( success, error_message = await self._capture(
to_capture['url'], to_capture['url'],
perma_uuid=uuid, perma_uuid=uuid,
cookies_pseudofile=to_capture.get('cookies', None), cookies_pseudofile=to_capture.get('cookies', None),
listing=listing, listing=listing,
user_agent=to_capture.get('user_agent', None), user_agent=to_capture.get('user_agent', None),
referer=to_capture.get('referer', None), referer=to_capture.get('referer', None),
headers=headers if headers else None, headers=headers if headers else None,
proxy=to_capture.get('proxy', None), proxy=to_capture.get('proxy', None),
os=to_capture.get('os', None), os=to_capture.get('os', None),
browser=to_capture.get('browser', None), browser=to_capture.get('browser', None),
parent=to_capture.get('parent', None) parent=to_capture.get('parent', None)
) )
if success: if success:
self.logger.info(f'Successfully captured {to_capture["url"]} - {uuid}') self.logger.info(f'Successfully captured {to_capture["url"]} - {uuid}')
else: else:
self.logger.warning(f'Unable to capture {to_capture["url"]} - {uuid}: {error_message}') 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}') await lazy_cleanup.setex(f'error_{uuid}', 36000, f'{error_message} - {to_capture["url"]} - {uuid}')
lazy_cleanup.srem('ongoing', uuid) await lazy_cleanup.srem('ongoing', uuid)
lazy_cleanup.delete(uuid) await lazy_cleanup.delete(uuid)
# make sure to expire the key if nothing was processed for a while (= queues empty) # make sure to expire the key if nothing was processed for a while (= queues empty)
lazy_cleanup.expire('queues', 600) await lazy_cleanup.expire('queues', 600)
lazy_cleanup.execute() await lazy_cleanup.execute()
async def _capture(self, url: str, *, perma_uuid: str, cookies_pseudofile: Optional[Union[BufferedIOBase, str]]=None, async def _capture(self, url: str, *, perma_uuid: str, cookies_pseudofile: Optional[Union[BufferedIOBase, str]]=None,
listing: bool=True, user_agent: Optional[str]=None, listing: bool=True, user_agent: Optional[str]=None,
@ -116,15 +115,14 @@ class AsyncCapture(AbstractManager):
splitted_url = urlsplit(url) splitted_url = urlsplit(url)
if self.only_global_lookups: if self.only_global_lookups:
if splitted_url.netloc: if splitted_url.netloc:
if splitted_url.hostname: if splitted_url.hostname and splitted_url.hostname.split('.')[-1] != 'onion':
if splitted_url.hostname.split('.')[-1] != 'onion': try:
try: ip = socket.gethostbyname(splitted_url.hostname)
ip = socket.gethostbyname(splitted_url.hostname) except socket.gaierror:
except socket.gaierror: self.logger.info('Name or service not known')
self.logger.info('Name or service not known') return False, 'Name or service not known.'
return False, 'Name or service not known.' if not ipaddress.ip_address(ip).is_global:
if not ipaddress.ip_address(ip).is_global: return False, 'Capturing ressources on private IPs is disabled.'
return False, 'Capturing ressources on private IPs is disabled.'
else: else:
return False, 'Unable to find hostname or IP in the query.' 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']: if 'cookies' in entries and entries['cookies']:
with (dirpath / '0.cookies.json').open('w') as _cookies: with (dirpath / '0.cookies.json').open('w') as _cookies:
json.dump(entries['cookies'], _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!' return True, 'All good!'
async def _to_run_forever_async(self): 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() await self.process_capture_queue()
if self.shutdown_requested(): if self.shutdown_requested():
break break
await self.redis.close()
def main(): def main():

View File

@ -294,7 +294,7 @@ class CapturesIndex(Mapping):
p = self.redis.pipeline() p = self.redis.pipeline()
p.hset('lookup_dirs', uuid, str(capture_dir)) 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() p.execute()
return CaptureCache(cache) return CaptureCache(cache)
@ -304,7 +304,7 @@ class CapturesIndex(Mapping):
Updates the nodes of the tree accordingly so the information is available. 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. '''Returns a list of CNAMEs starting from one hostname.
The CNAMEs resolutions are made in `_resolve_dns`. A hostname can have a CNAME entry 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. 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] = [] cnames: List[str] = []
to_search = hostname to_search = hostname
while True: while True:
if known_cnames.get(to_search) is None: if not known_cnames.get(to_search):
break break
# At this point, known_cnames[to_search] must exist and be a str cnames.append(known_cnames[to_search])
cnames.append(known_cnames[to_search]) # type: ignore
to_search = known_cnames[to_search] to_search = known_cnames[to_search]
return cnames return cnames
cnames_path = ct.root_hartree.har.path.parent / 'cnames.json' cnames_path = ct.root_hartree.har.path.parent / 'cnames.json'
ips_path = ct.root_hartree.har.path.parent / 'ips.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(): if cnames_path.exists():
try: try:
with cnames_path.open() as f: with cnames_path.open() as f:
@ -348,15 +347,14 @@ class CapturesIndex(Mapping):
if answer.rdtype == dns.rdatatype.RdataType.CNAME: if answer.rdtype == dns.rdatatype.RdataType.CNAME:
host_cnames[str(answer.name).rstrip('.')] = str(answer[0].target).rstrip('.') host_cnames[str(answer.name).rstrip('.')] = str(answer[0].target).rstrip('.')
else: 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]: 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}) host_ips[str(answer.name).rstrip('.')] = list({str(b) for b in answer})
except Exception: except Exception:
host_cnames[node.name] = None host_cnames[node.name] = ''
host_ips[node.name] = [] host_ips[node.name] = []
cnames = _build_cname_chain(host_cnames, node.name) if (cnames := _build_cname_chain(host_cnames, node.name)):
if cnames:
node.add_feature('cname', cnames) node.add_feature('cname', cnames)
if cnames[-1] in host_ips: if cnames[-1] in host_ips:
node.add_feature('resolved_ips', host_ips[cnames[-1]]) node.add_feature('resolved_ips', host_ips[cnames[-1]])

View File

@ -35,7 +35,7 @@ class Context():
if filename == 'generic': if filename == 'generic':
# 1px images, files with spaces, empty => non-relevant stuff # 1px images, files with spaces, empty => non-relevant stuff
for _, type_content in file_content.items(): 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': elif filename == 'malicious':
# User defined as malicious # User defined as malicious
for h, details in file_content.items(): for h, details in file_content.items():

View File

@ -120,9 +120,9 @@ def load_cookies(cookie_pseudofile: Optional[Union[BufferedIOBase, str]]=None) -
try: try:
for cookie in cookies: for cookie in cookies:
to_add: Dict[str, Union[str, bool]] 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 # 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'], to_add = {'path': cookie['Path raw'],
'name': cookie['Name raw'], 'name': cookie['Name raw'],
'httpOnly': cookie['HTTP only raw'] == 'true', 'httpOnly': cookie['HTTP only raw'] == 'true',

View File

@ -19,7 +19,7 @@ from zipfile import ZipFile
from defang import defang # type: ignore from defang import defang # type: ignore
from har2tree import CrawledTree, HostNode, URLNode 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 pymisp import MISPAttribute, MISPEvent, MISPObject
from redis import ConnectionPool, Redis from redis import ConnectionPool, Redis
from redis.connection import UnixDomainSocketConnection from redis.connection import UnixDomainSocketConnection
@ -387,7 +387,7 @@ class Lookyloo():
if priority < -10: if priority < -10:
# Someone is probably abusing the system with useless URLs, remove them from the index # Someone is probably abusing the system with useless URLs, remove them from the index
query['listing'] = 0 query['listing'] = 0
p.hmset(perma_uuid, query) p.hset(perma_uuid, mapping=query)
p.zadd('to_capture', {perma_uuid: priority}) p.zadd('to_capture', {perma_uuid: priority})
p.zincrby('queues', 1, f'{source}|{authenticated}|{user}') p.zincrby('queues', 1, f'{source}|{authenticated}|{user}')
p.set(f'{perma_uuid}_mgmt', f'{source}|{authenticated}|{user}') p.set(f'{perma_uuid}_mgmt', f'{source}|{authenticated}|{user}')

82
poetry.lock generated
View File

@ -421,7 +421,7 @@ python-versions = ">=3.5"
[[package]] [[package]]
name = "importlib-metadata" name = "importlib-metadata"
version = "4.11.3" version = "4.11.4"
description = "Read metadata from Python packages" description = "Read metadata from Python packages"
category = "main" category = "main"
optional = false optional = false
@ -616,7 +616,7 @@ python-versions = "*"
[[package]] [[package]]
name = "numpy" name = "numpy"
version = "1.22.3" version = "1.22.4"
description = "NumPy is the fundamental package for array computing with Python." description = "NumPy is the fundamental package for array computing with Python."
category = "main" category = "main"
optional = false optional = false
@ -910,7 +910,7 @@ six = ">=1.5"
[[package]] [[package]]
name = "python-magic" name = "python-magic"
version = "0.4.25" version = "0.4.26"
description = "File type identification using libmagic" description = "File type identification using libmagic"
category = "main" category = "main"
optional = true optional = true
@ -1103,6 +1103,14 @@ category = "dev"
optional = false optional = false
python-versions = "*" python-versions = "*"
[[package]]
name = "types-pillow"
version = "9.0.15"
description = "Typing stubs for Pillow"
category = "dev"
optional = false
python-versions = "*"
[[package]] [[package]]
name = "types-pkg-resources" name = "types-pkg-resources"
version = "0.1.3" version = "0.1.3"
@ -1121,7 +1129,7 @@ python-versions = "*"
[[package]] [[package]]
name = "types-redis" name = "types-redis"
version = "4.2.4" version = "4.2.5"
description = "Typing stubs for redis" description = "Typing stubs for redis"
category = "dev" category = "dev"
optional = false optional = false
@ -1140,7 +1148,7 @@ types-urllib3 = "<1.27"
[[package]] [[package]]
name = "types-setuptools" name = "types-setuptools"
version = "57.4.14" version = "57.4.15"
description = "Typing stubs for setuptools" description = "Typing stubs for setuptools"
category = "dev" category = "dev"
optional = false optional = false
@ -1320,7 +1328,7 @@ misp = ["python-magic", "pydeep2"]
[metadata] [metadata]
lock-version = "1.1" lock-version = "1.1"
python-versions = ">=3.8,<3.11" python-versions = ">=3.8,<3.11"
content-hash = "42236f7345b82436083464511c96e002470f4c17d3a731ccfa2ffa1570c63d19" content-hash = "91b738a6001f33ba9ce90ebf654bb341713feff6e5d9bcf0630598492d3d9570"
[metadata.files] [metadata.files]
aiohttp = [ aiohttp = [
@ -1726,8 +1734,8 @@ idna = [
{file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"}, {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"},
] ]
importlib-metadata = [ importlib-metadata = [
{file = "importlib_metadata-4.11.3-py3-none-any.whl", hash = "sha256:1208431ca90a8cca1a6b8af391bb53c1a2db74e5d1cef6ddced95d4b2062edc6"}, {file = "importlib_metadata-4.11.4-py3-none-any.whl", hash = "sha256:c58c8eb8a762858f49e18436ff552e83914778e50e9d2f1660535ffb364552ec"},
{file = "importlib_metadata-4.11.3.tar.gz", hash = "sha256:ea4c597ebf37142f827b8f39299579e31685c31d3a438b59f469406afd0f2539"}, {file = "importlib_metadata-4.11.4.tar.gz", hash = "sha256:5d26852efe48c0a32b0509ffbc583fda1a2266545a78d104a6f4aff3db17d700"},
] ]
importlib-resources = [ importlib-resources = [
{file = "importlib_resources-5.7.1-py3-none-any.whl", hash = "sha256:e447dc01619b1e951286f3929be820029d48c75eb25d265c28b92a16548212b8"}, {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"}, {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"},
] ]
numpy = [ numpy = [
{file = "numpy-1.22.3-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:92bfa69cfbdf7dfc3040978ad09a48091143cffb778ec3b03fa170c494118d75"}, {file = "numpy-1.22.4-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:ba9ead61dfb5d971d77b6c131a9dbee62294a932bf6a356e48c75ae684e635b3"},
{file = "numpy-1.22.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8251ed96f38b47b4295b1ae51631de7ffa8260b5b087808ef09a39a9d66c97ab"}, {file = "numpy-1.22.4-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:1ce7ab2053e36c0a71e7a13a7475bd3b1f54750b4b433adc96313e127b870887"},
{file = "numpy-1.22.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48a3aecd3b997bf452a2dedb11f4e79bc5bfd21a1d4cc760e703c31d57c84b3e"}, {file = "numpy-1.22.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7228ad13744f63575b3a972d7ee4fd61815b2879998e70930d4ccf9ec721dce0"},
{file = "numpy-1.22.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3bae1a2ed00e90b3ba5f7bd0a7c7999b55d609e0c54ceb2b076a25e345fa9f4"}, {file = "numpy-1.22.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:43a8ca7391b626b4c4fe20aefe79fec683279e31e7c79716863b4b25021e0e74"},
{file = "numpy-1.22.3-cp310-cp310-win32.whl", hash = "sha256:f950f8845b480cffe522913d35567e29dd381b0dc7e4ce6a4a9f9156417d2430"}, {file = "numpy-1.22.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a911e317e8c826ea632205e63ed8507e0dc877dcdc49744584dfc363df9ca08c"},
{file = "numpy-1.22.3-cp310-cp310-win_amd64.whl", hash = "sha256:08d9b008d0156c70dc392bb3ab3abb6e7a711383c3247b410b39962263576cd4"}, {file = "numpy-1.22.4-cp310-cp310-win32.whl", hash = "sha256:9ce7df0abeabe7fbd8ccbf343dc0db72f68549856b863ae3dd580255d009648e"},
{file = "numpy-1.22.3-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:201b4d0552831f7250a08d3b38de0d989d6f6e4658b709a02a73c524ccc6ffce"}, {file = "numpy-1.22.4-cp310-cp310-win_amd64.whl", hash = "sha256:3e1ffa4748168e1cc8d3cde93f006fe92b5421396221a02f2274aab6ac83b077"},
{file = "numpy-1.22.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f8c1f39caad2c896bc0018f699882b345b2a63708008be29b1f355ebf6f933fe"}, {file = "numpy-1.22.4-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:59d55e634968b8f77d3fd674a3cf0b96e85147cd6556ec64ade018f27e9479e1"},
{file = "numpy-1.22.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:568dfd16224abddafb1cbcce2ff14f522abe037268514dd7e42c6776a1c3f8e5"}, {file = "numpy-1.22.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c1d937820db6e43bec43e8d016b9b3165dcb42892ea9f106c70fb13d430ffe72"},
{file = "numpy-1.22.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ca688e1b9b95d80250bca34b11a05e389b1420d00e87a0d12dc45f131f704a1"}, {file = "numpy-1.22.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4c5d5eb2ec8da0b4f50c9a843393971f31f1d60be87e0fb0917a49133d257d6"},
{file = "numpy-1.22.3-cp38-cp38-win32.whl", hash = "sha256:e7927a589df200c5e23c57970bafbd0cd322459aa7b1ff73b7c2e84d6e3eae62"}, {file = "numpy-1.22.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64f56fc53a2d18b1924abd15745e30d82a5782b2cab3429aceecc6875bd5add0"},
{file = "numpy-1.22.3-cp38-cp38-win_amd64.whl", hash = "sha256:07a8c89a04997625236c5ecb7afe35a02af3896c8aa01890a849913a2309c676"}, {file = "numpy-1.22.4-cp38-cp38-win32.whl", hash = "sha256:fb7a980c81dd932381f8228a426df8aeb70d59bbcda2af075b627bbc50207cba"},
{file = "numpy-1.22.3-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:2c10a93606e0b4b95c9b04b77dc349b398fdfbda382d2a39ba5a822f669a0123"}, {file = "numpy-1.22.4-cp38-cp38-win_amd64.whl", hash = "sha256:e96d7f3096a36c8754207ab89d4b3282ba7b49ea140e4973591852c77d09eb76"},
{file = "numpy-1.22.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fade0d4f4d292b6f39951b6836d7a3c7ef5b2347f3c420cd9820a1d90d794802"}, {file = "numpy-1.22.4-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:4c6036521f11a731ce0648f10c18ae66d7143865f19f7299943c985cdc95afb5"},
{file = "numpy-1.22.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bfb1bb598e8229c2d5d48db1860bcf4311337864ea3efdbe1171fb0c5da515d"}, {file = "numpy-1.22.4-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:b89bf9b94b3d624e7bb480344e91f68c1c6c75f026ed6755955117de00917a7c"},
{file = "numpy-1.22.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97098b95aa4e418529099c26558eeb8486e66bd1e53a6b606d684d0c3616b168"}, {file = "numpy-1.22.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2d487e06ecbf1dc2f18e7efce82ded4f705f4bd0cd02677ffccfb39e5c284c7e"},
{file = "numpy-1.22.3-cp39-cp39-win32.whl", hash = "sha256:fdf3c08bce27132395d3c3ba1503cac12e17282358cb4bddc25cc46b0aca07aa"}, {file = "numpy-1.22.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3eb268dbd5cfaffd9448113539e44e2dd1c5ca9ce25576f7c04a5453edc26fa"},
{file = "numpy-1.22.3-cp39-cp39-win_amd64.whl", hash = "sha256:639b54cdf6aa4f82fe37ebf70401bbb74b8508fddcf4797f9fe59615b8c5813a"}, {file = "numpy-1.22.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37431a77ceb9307c28382c9773da9f306435135fae6b80b62a11c53cfedd8802"},
{file = "numpy-1.22.3-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c34ea7e9d13a70bf2ab64a2532fe149a9aced424cd05a2c4ba662fd989e3e45f"}, {file = "numpy-1.22.4-cp39-cp39-win32.whl", hash = "sha256:cc7f00008eb7d3f2489fca6f334ec19ca63e31371be28fd5dad955b16ec285bd"},
{file = "numpy-1.22.3.zip", hash = "sha256:dbc7601a3b7472d559dc7b933b18b4b66f9aa7452c120e87dfb33d02008c8a18"}, {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 = [ packaging = [
{file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, {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"}, {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"},
] ]
python-magic = [ python-magic = [
{file = "python-magic-0.4.25.tar.gz", hash = "sha256:21f5f542aa0330f5c8a64442528542f6215c8e18d2466b399b0d9d39356d83fc"}, {file = "python-magic-0.4.26.tar.gz", hash = "sha256:8262c13001f904ad5b724d38b5e5b5f17ec0450ae249def398a62e4e33108a50"},
{file = "python_magic-0.4.25-py2.py3-none-any.whl", hash = "sha256:1a2c81e8f395c744536369790bd75094665e9644110a6623bcc3bbea30f03973"}, {file = "python_magic-0.4.26-py2.py3-none-any.whl", hash = "sha256:b978c4b69a20510d133a7f488910c2f07e7796f1f31703e61c241973f2bbf5fb"},
] ]
pytz = [ pytz = [
{file = "pytz-2022.1-py2.py3-none-any.whl", hash = "sha256:e68985985296d9a66a881eb3193b0906246245294a881e7c8afe623866ac6a5c"}, {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.tar.gz", hash = "sha256:85b3a872683d02aea3a5ac2a8ef590193c344092032f58457287fbf8e06711b1"},
{file = "types_MarkupSafe-1.1.10-py3-none-any.whl", hash = "sha256:ca2bee0f4faafc45250602567ef38d533e877d2ddca13003b319c551ff5b3cc5"}, {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 = [ types-pkg-resources = [
{file = "types-pkg_resources-0.1.3.tar.gz", hash = "sha256:834a9b8d3dbea343562fd99d5d3359a726f6bf9d3733bccd2b4f3096fbab9dae"}, {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"}, {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"}, {file = "types_python_dateutil-2.8.16-py3-none-any.whl", hash = "sha256:0e7286436d049d2732ba2f01552f84c52184b955552359156fc8835c10714f2a"},
] ]
types-redis = [ types-redis = [
{file = "types-redis-4.2.4.tar.gz", hash = "sha256:5574d58d95aa77fbb918eba7c183d0a0231b5e02d66d8aeb701e5310a01feabf"}, {file = "types-redis-4.2.5.tar.gz", hash = "sha256:88f04d99f20c20c3d0129c37601f9e70c01b71f1faef473766cfa3dddbd5e5d5"},
{file = "types_redis-4.2.4-py3-none-any.whl", hash = "sha256:117167b25585acfc246162f025e18885098dcbe764b2c55d964cac90cd1660f3"}, {file = "types_redis-4.2.5-py3-none-any.whl", hash = "sha256:c0123db52d9b1a887cd3c7bc0d9cb03893dc3873969ffc55a99c9a9ad9d32a79"},
] ]
types-requests = [ types-requests = [
{file = "types-requests-2.27.27.tar.gz", hash = "sha256:d618d9809fa32f514cf17cea8460814da671c56366fb1c908accca8bf183112b"}, {file = "types-requests-2.27.27.tar.gz", hash = "sha256:d618d9809fa32f514cf17cea8460814da671c56366fb1c908accca8bf183112b"},
{file = "types_requests-2.27.27-py3-none-any.whl", hash = "sha256:6d8463ffe1f6edcf2e5361740a6140e7a16d427c267d83c7c1d3d1298f4e67c5"}, {file = "types_requests-2.27.27-py3-none-any.whl", hash = "sha256:6d8463ffe1f6edcf2e5361740a6140e7a16d427c267d83c7c1d3d1298f4e67c5"},
] ]
types-setuptools = [ types-setuptools = [
{file = "types-setuptools-57.4.14.tar.gz", hash = "sha256:df02fe1dd244f58cf4e67cfc3d0a97930a2d61a72dd89f21d81c71017cd83f9a"}, {file = "types-setuptools-57.4.15.tar.gz", hash = "sha256:650528ce803586029d7f153f32aed2dbaa6bb2888b233334af80d7ba63ed3c87"},
{file = "types_setuptools-57.4.14-py3-none-any.whl", hash = "sha256:828f7e7e51e157876f47c80518b23ba0c3c36aa8081efd39d5d39f393938aec9"}, {file = "types_setuptools-57.4.15-py3-none-any.whl", hash = "sha256:f8f19876f714a440c4badef1b91b0648604ed443e703d29d44cd36ac93b01a77"},
] ]
types-urllib3 = [ types-urllib3 = [
{file = "types-urllib3-1.26.14.tar.gz", hash = "sha256:2a2578e4b36341ccd240b00fccda9826988ff0589a44ba4a664bbd69ef348d27"}, {file = "types-urllib3-1.26.14.tar.gz", hash = "sha256:2a2578e4b36341ccd240b00fccda9826988ff0589a44ba4a664bbd69ef348d27"},

View File

@ -72,14 +72,15 @@ misp = ['python-magic', 'pydeep2']
[tool.poetry.dev-dependencies] [tool.poetry.dev-dependencies]
mypy = "^0.950" mypy = "^0.950"
ipython = "^8.2.0" ipython = "^8.2.0"
types-redis = "^4.2.4" types-redis = "^4.2.5"
types-requests = "^2.27.27" types-requests = "^2.27.27"
types-Flask = "^1.1.6" types-Flask = "^1.1.6"
types-pkg-resources = "^0.1.3" types-pkg-resources = "^0.1.3"
types-Deprecated = "^1.2.8" types-Deprecated = "^1.2.8"
types-python-dateutil = "^2.8.16" types-python-dateutil = "^2.8.16"
types-beautifulsoup4 = "^4.11.1" types-beautifulsoup4 = "^4.11.1"
types-setuptools = "^57.4.14" types-setuptools = "^57.4.15"
types-Pillow = "^9.0.15"
[build-system] [build-system]
requires = ["poetry_core>=1.0", "setuptools"] requires = ["poetry_core>=1.0", "setuptools"]