fix: Trigger autoreport once the tree is built

main
Raphaël Vinot 2024-11-21 15:51:22 +01:00
parent 673c6a0270
commit 0718c6cb39
6 changed files with 40 additions and 27 deletions

View File

@ -98,20 +98,10 @@ class AsyncCapture(AbstractManager):
last_redirected_url=entries.get('last_redirected_url'),
cookies=entries.get('cookies'),
capture_settings=to_capture,
potential_favicons=entries.get('potential_favicons')
potential_favicons=entries.get('potential_favicons'),
auto_report=to_capture.auto_report,
)
if to_capture.auto_report:
send_report = True
settings = {}
if isinstance(to_capture.auto_report, dict):
settings = to_capture.auto_report
if send_report:
self.lookyloo.send_mail(uuid, email=settings.get('email', ''),
comment=settings.get('comment'),
recipient_mail=settings.get("recipient_mail"))
lazy_cleanup = self.lookyloo.redis.pipeline()
if queue and self.lookyloo.redis.zscore('queues', queue):
lazy_cleanup.zincrby('queues', -1, queue)

View File

@ -2,6 +2,7 @@
from __future__ import annotations
import json
import logging
import logging.config
import shutil
@ -34,6 +35,24 @@ class BackgroundBuildCaptures(AbstractManager):
# Redis connector so we don't use the one from Lookyloo
self.redis = Redis(unix_socket_path=get_socket_path('cache'), decode_responses=True)
def __auto_report(self, path: Path) -> None:
with (path / 'uuid').open() as f:
capture_uuid = f.read()
self.logger.info(f'Triggering autoreport for {capture_uuid}...')
settings = {}
with (path / 'auto_report').open() as f:
if ar := f.read():
# could be an empty file.
settings = json.loads(ar)
try:
self.lookyloo.send_mail(capture_uuid, email=settings.get('email', ''),
comment=settings.get('comment'))
(path / 'auto_report').unlink()
except Exception as e:
self.logger.warning(f'Unable to send auto report for {capture_uuid}: {e}')
else:
self.logger.info(f'Auto report for {capture_uuid} sent.')
def _to_run_forever(self) -> None:
self._build_missing_pickles()
# Don't need the cache in this class.
@ -59,6 +78,9 @@ class BackgroundBuildCaptures(AbstractManager):
if ((path / 'tree.pickle.gz').exists() or (path / 'tree.pickle').exists()):
# We already have a pickle file
self.logger.debug(f'{path} has a pickle.')
if (path / 'auto_report').exists():
# the pickle was built somewhere else, trigger report.
self.__auto_report(path)
continue
if not list(path.rglob('*.har.gz')) and not list(path.rglob('*.har')):
# No HAR file
@ -102,6 +124,8 @@ class BackgroundBuildCaptures(AbstractManager):
self.logger.info(f'Pickle for {uuid} built.')
got_new_captures = True
max_captures -= 1
if (path / 'auto_report').exists():
self.__auto_report(path)
except MissingUUID:
self.logger.warning(f'Unable to find {uuid}. That should not happen.')
except NoValidHarFile as e:

View File

@ -408,7 +408,7 @@ class CaptureSettings(LacuscoreCaptureSettings):
'''The capture settings that can be passed to Lookyloo'''
listing: bool = get_config('generic', 'default_public')
not_queued: bool = False
auto_report: bool | dict[str, str] | None = None # {'email': , 'comment': , 'recipient_mail':}
auto_report: bool | dict[str, str] | None = None # {'email': , 'comment':}
dnt: str | None = None
browser_name: str | None = None
os: str | None = None

View File

@ -884,12 +884,11 @@ class Lookyloo():
# unable to run the query, probably an invalid key
pass
if len(modules) == 0:
return "Capture does not seem to be malicious"
return "URL captured doesn't appear in malicious databases."
return f"Malicious capture according to {len(modules)} module(s): {', '.join(modules)}"
def send_mail(self, capture_uuid: str, /, email: str='', comment: str | None=None,
recipient_mail: str | None = None) -> bool | dict[str, Any]:
def send_mail(self, capture_uuid: str, /, email: str | None=None, comment: str | None=None) -> bool | dict[str, Any]:
'''Send an email notification regarding a specific capture'''
if not get_config('generic', 'enable_mail_notification'):
return {"error": "Unable to send mail: mail notification disabled"}
@ -938,7 +937,7 @@ class Lookyloo():
msg['From'] = email_config['from']
if email:
msg['Reply-To'] = email
msg['To'] = email_config['to'] if not recipient_mail else recipient_mail
msg['To'] = email_config['to']
msg['Subject'] = email_config['subject']
body = get_email_template()
body = body.format(
@ -1519,7 +1518,8 @@ class Lookyloo():
last_redirected_url: str | None=None,
cookies: list[Cookie] | list[dict[str, str]] | None=None,
capture_settings: CaptureSettings | None=None,
potential_favicons: set[bytes] | None=None
potential_favicons: set[bytes] | None=None,
auto_report: bool | dict[str, str] | None = None
) -> None:
now = datetime.now()
@ -1595,5 +1595,13 @@ class Lookyloo():
with (dirpath / f'{f_id}.potential_favicons.ico').open('wb') as _fw:
_fw.write(favicon)
if auto_report:
# autoreport needs to be triggered once the tree is build
if isinstance(auto_report, bool):
(dirpath / 'auto_report').touch()
else:
with (dirpath / 'auto_report').open('w') as _ar:
json.dump(auto_report, _ar)
self.redis.hset('lookup_dirs', uuid, str(dirpath))
self.redis.zadd('recent_captures', {uuid: now.timestamp()})

View File

@ -1659,7 +1659,6 @@ def capture_web() -> str | Response | WerkzeugResponse:
capture_query['auto_report'] = {
'email': request.form.get('email', ""),
'comment': request.form.get('comment', ""),
'recipient_mail': request.form.get('recipient-mail', "")
}
if request.form.get('url'):

View File

@ -454,14 +454,6 @@
name="email" placeholder="myself@example.com">
</div>
</div>
<div class="row mb-3">
<label class="col-sm-3 col-form-label" for="recipient-mail">
Email of the recipient (optional): </label>
<div class="col-sm-9">
<input class="form-control" type="text" id="recipient-mail"
name="recipient-mail" placeholder="to-someone@example.com">
</div>
</div>
<div class="row mb-3">
<label class="col-sm-3 col-form-label" for="comment">Comment (optional): </label>
<div class="col-sm-9">