Add notify_hibp cron job
This commit is contained in:
parent
5aef6cceb2
commit
fb4cb8727c
46
cron.py
46
cron.py
|
@ -7,6 +7,7 @@ from typing import List, Tuple
|
|||
import arrow
|
||||
import requests
|
||||
from sqlalchemy import func, desc, or_
|
||||
from sqlalchemy.orm import joinedload
|
||||
|
||||
from app import s3
|
||||
from app.alias_utils import nb_email_log_for_mailbox
|
||||
|
@ -771,6 +772,47 @@ async def check_hibp():
|
|||
LOG.d("Done checking HIBP API for aliases in breaches")
|
||||
|
||||
|
||||
def notify_hibp():
|
||||
"""
|
||||
Send aggregated email reports for HIBP breaches
|
||||
"""
|
||||
# to get a list of users that have at least a breached alias
|
||||
alias_query = (
|
||||
db.session.query(Alias)
|
||||
.options(joinedload(Alias.hibp_breaches))
|
||||
.filter(Alias.hibp_breaches.any())
|
||||
.distinct(Alias.user_id)
|
||||
.all()
|
||||
)
|
||||
|
||||
user_ids = [alias.user_id for alias in alias_query]
|
||||
|
||||
for user in User.query.filter(User.id.in_(user_ids)):
|
||||
breached_aliases = (
|
||||
db.session.query(Alias)
|
||||
.options(joinedload(Alias.hibp_breaches))
|
||||
.filter(Alias.hibp_breaches.any(), Alias.user_id == user.id)
|
||||
.all()
|
||||
)
|
||||
|
||||
LOG.d(f"Send new breaches found email to user {user}")
|
||||
|
||||
send_email(
|
||||
user.email,
|
||||
f"You were in a data breach",
|
||||
render(
|
||||
"transactional/hibp-new-breaches.txt.jinja2",
|
||||
user=user,
|
||||
breached_aliases=breached_aliases,
|
||||
),
|
||||
render(
|
||||
"transactional/hibp-new-breaches.html",
|
||||
user=user,
|
||||
breached_aliases=breached_aliases,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
LOG.d("Start running cronjob")
|
||||
parser = argparse.ArgumentParser()
|
||||
|
@ -790,6 +832,7 @@ if __name__ == "__main__":
|
|||
"delete_old_monitoring",
|
||||
"check_custom_domain",
|
||||
"check_hibp",
|
||||
"notify_hibp",
|
||||
],
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
@ -827,3 +870,6 @@ if __name__ == "__main__":
|
|||
elif args.job == "check_hibp":
|
||||
LOG.d("Check HIBP")
|
||||
asyncio.run(check_hibp())
|
||||
elif args.job == "notify_hibp":
|
||||
LOG.d("Notify users about HIBP breaches")
|
||||
notify_hibp()
|
||||
|
|
|
@ -58,4 +58,11 @@ jobs:
|
|||
shell: /bin/bash
|
||||
schedule: "0 18 * * *"
|
||||
captureStderr: true
|
||||
concurrencyPolicy: Forbid
|
||||
|
||||
- name: SimpleLogin Notify HIBP breaches
|
||||
command: python /code/cron.py -j notify_hibp
|
||||
shell: /bin/bash
|
||||
schedule: "0 19 * * *"
|
||||
captureStderr: true
|
||||
concurrencyPolicy: Forbid
|
17
server.py
17
server.py
|
@ -102,6 +102,8 @@ from app.models import (
|
|||
Payout,
|
||||
Coupon,
|
||||
SLDomain,
|
||||
Hibp,
|
||||
AliasHibp,
|
||||
)
|
||||
from app.monitor.base import monitor_bp
|
||||
from app.oauth.base import oauth_bp
|
||||
|
@ -421,6 +423,21 @@ def fake_data():
|
|||
|
||||
SLDomain.create(domain="premium.com", premium_only=True, commit=True)
|
||||
|
||||
hibp1 = Hibp.create(
|
||||
name="first breach", description="breach description", commit=True
|
||||
)
|
||||
hibp2 = Hibp.create(
|
||||
name="second breach", description="breach description", commit=True
|
||||
)
|
||||
breached_alias1 = Alias.create(
|
||||
email="john@example.com", user_id=user.id, mailbox_id=m1.id, commit=True
|
||||
)
|
||||
breached_alias2 = Alias.create(
|
||||
email="wick@example.com", user_id=user.id, mailbox_id=m1.id, commit=True
|
||||
)
|
||||
AliasHibp.create(hibp_id=hibp1.id, alias_id=breached_alias1.id)
|
||||
AliasHibp.create(hibp_id=hibp2.id, alias_id=breached_alias2.id)
|
||||
|
||||
|
||||
@login_manager.user_loader
|
||||
def load_user(user_id):
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
{% call text() %}
|
||||
<h1>
|
||||
{{ breached_aliases|count }} of your aliases are found in data breaches.
|
||||
</h1>
|
||||
{% endcall %}
|
||||
|
||||
<ol>
|
||||
{%- for alias in breached_aliases[:10] %}
|
||||
<li>{% call text() %}
|
||||
<b>{{ alias.email }}</b> was found in {{ alias.hibp_breaches|count }} data breaches. <br>
|
||||
|
||||
<ul>
|
||||
{% set breaches = alias.hibp_breaches|sort(attribute='date', reverse=True) %}
|
||||
{%- for breach in breaches[:4] %}
|
||||
<li>
|
||||
<b>{{ breach.name }}</b> {% if breach.date %}({{ breach.date.format('YYYY-MM-DD') }}){% endif %}
|
||||
{{ breach.description }}
|
||||
</li>
|
||||
{%- endfor %}
|
||||
</ul>
|
||||
|
||||
{% if breaches|length > 4 %}
|
||||
And {{ breaches|length - 4 }} more data breaches...
|
||||
{% endif %}
|
||||
|
||||
{% endcall %}</li>
|
||||
{%- endfor %}
|
||||
|
||||
</ol>
|
||||
|
||||
{% if breached_aliases|length > 10 %}
|
||||
{% call text() %}
|
||||
And {{ breached_aliases|length - 10 }} more aliases...
|
||||
{% endcall %}
|
||||
{% endif %}
|
||||
|
||||
{% call text() %}
|
||||
For more information, check <a href='https://haveibeenpwned.com/'>HaveIBeenPwned.com</a>.
|
||||
{% endcall %}
|
||||
|
||||
|
||||
{{ render_text('Best, <br />SimpleLogin Team.') }}
|
||||
{% endblock %}
|
|
@ -0,0 +1,23 @@
|
|||
{{ breached_aliases|count }} of your aliases are found in data breaches.
|
||||
|
||||
{% for alias in breached_aliases[:10] %}
|
||||
{{ loop.index }} ) {{ alias.email }} was found in {{ alias.hibp_breaches|count }} data breaches.
|
||||
|
||||
{%- set breaches = alias.hibp_breaches|sort(attribute='date', reverse=True) %}
|
||||
{% for breach in breaches[:4] %}
|
||||
- {{ breach.name }} {% if breach.date %}({{ breach.date.format('YYYY-MM-DD') }}){% endif %}
|
||||
{%- endfor %}
|
||||
|
||||
{%- if breaches|length > 4 %}
|
||||
And {{ breaches|length - 4 }} more data breaches...
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{%- if breached_aliases|length > 10 %}
|
||||
And {{ breached_aliases|length - 10 }} more aliases...
|
||||
{%- endif %}
|
||||
|
||||
For more information, please check https://haveibeenpwned.com/.
|
||||
|
||||
Best,
|
||||
SimpleLogin Team.
|
Loading…
Reference in New Issue