2020-04-04 14:27:22 +00:00
|
|
|
import arrow
|
|
|
|
|
|
|
|
from app.alias_utils import try_auto_create
|
|
|
|
from app.config import (
|
2020-04-04 15:22:27 +00:00
|
|
|
MAX_ACTIVITY_DURING_MINUTE_PER_ALIAS,
|
|
|
|
MAX_ACTIVITY_DURING_MINUTE_PER_MAILBOX,
|
2020-04-04 14:27:22 +00:00
|
|
|
)
|
2021-10-12 12:36:47 +00:00
|
|
|
from app.db import Session
|
2020-11-16 18:22:19 +00:00
|
|
|
from app.email_utils import is_reply_email
|
2020-04-04 14:27:22 +00:00
|
|
|
from app.log import LOG
|
|
|
|
from app.models import Alias, EmailLog, Contact
|
|
|
|
|
|
|
|
|
2021-06-24 07:47:01 +00:00
|
|
|
def rate_limited_for_alias(alias: Alias) -> bool:
|
2020-04-04 15:22:27 +00:00
|
|
|
min_time = arrow.now().shift(minutes=-1)
|
|
|
|
|
|
|
|
# get the nb of activity on this alias
|
|
|
|
nb_activity = (
|
2021-10-12 12:36:47 +00:00
|
|
|
Session.query(EmailLog)
|
2020-04-04 16:07:05 +00:00
|
|
|
.join(Contact, EmailLog.contact_id == Contact.id)
|
2020-08-27 08:20:48 +00:00
|
|
|
.filter(
|
|
|
|
Contact.alias_id == alias.id,
|
|
|
|
EmailLog.created_at > min_time,
|
|
|
|
)
|
2020-04-04 15:22:27 +00:00
|
|
|
.group_by(EmailLog.id)
|
|
|
|
.count()
|
2020-04-04 14:27:22 +00:00
|
|
|
)
|
|
|
|
|
2020-04-04 15:22:27 +00:00
|
|
|
if nb_activity > MAX_ACTIVITY_DURING_MINUTE_PER_ALIAS:
|
2021-06-23 17:55:41 +00:00
|
|
|
LOG.w(
|
2020-08-27 08:20:48 +00:00
|
|
|
"Too much forward on alias %s. Nb Activity %s",
|
|
|
|
alias,
|
|
|
|
nb_activity,
|
2020-04-04 15:22:27 +00:00
|
|
|
)
|
|
|
|
return True
|
2020-04-04 14:27:22 +00:00
|
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
2021-06-24 07:47:01 +00:00
|
|
|
def rate_limited_for_mailbox(alias: Alias) -> bool:
|
2020-04-04 15:22:27 +00:00
|
|
|
min_time = arrow.now().shift(minutes=-1)
|
|
|
|
|
|
|
|
# get nb of activity on this mailbox
|
|
|
|
nb_activity = (
|
2021-10-12 12:36:47 +00:00
|
|
|
Session.query(EmailLog)
|
2020-04-04 16:07:05 +00:00
|
|
|
.join(Contact, EmailLog.contact_id == Contact.id)
|
|
|
|
.join(Alias, Contact.alias_id == Alias.id)
|
2020-08-27 08:20:48 +00:00
|
|
|
.filter(
|
|
|
|
Alias.mailbox_id == alias.mailbox_id,
|
|
|
|
EmailLog.created_at > min_time,
|
|
|
|
)
|
2020-04-04 15:22:27 +00:00
|
|
|
.group_by(EmailLog.id)
|
|
|
|
.count()
|
2020-04-04 14:27:22 +00:00
|
|
|
)
|
|
|
|
|
2020-04-04 15:22:27 +00:00
|
|
|
if nb_activity > MAX_ACTIVITY_DURING_MINUTE_PER_MAILBOX:
|
2021-06-23 17:55:41 +00:00
|
|
|
LOG.w(
|
2020-04-04 15:22:27 +00:00
|
|
|
"Too much forward on mailbox %s, alias %s. Nb Activity %s",
|
|
|
|
alias.mailbox,
|
|
|
|
alias,
|
|
|
|
nb_activity,
|
|
|
|
)
|
|
|
|
return True
|
2020-04-04 14:27:22 +00:00
|
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
2021-06-24 07:47:01 +00:00
|
|
|
def rate_limited_forward_phase(alias_address: str) -> bool:
|
2020-04-04 14:27:22 +00:00
|
|
|
alias = Alias.get_by(email=alias_address)
|
|
|
|
|
|
|
|
if alias:
|
2021-06-24 07:47:01 +00:00
|
|
|
return rate_limited_for_alias(alias) or rate_limited_for_mailbox(alias)
|
2020-04-04 14:27:22 +00:00
|
|
|
|
|
|
|
else:
|
|
|
|
LOG.d(
|
|
|
|
"alias %s not exist. Try to see if it can be created on the fly",
|
|
|
|
alias_address,
|
|
|
|
)
|
|
|
|
alias = try_auto_create(alias_address)
|
|
|
|
if alias:
|
2021-06-24 07:47:01 +00:00
|
|
|
return rate_limited_for_mailbox(alias)
|
2020-04-04 14:27:22 +00:00
|
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
2021-06-24 07:47:01 +00:00
|
|
|
def rate_limited_reply_phase(reply_email: str) -> bool:
|
2020-04-04 14:27:22 +00:00
|
|
|
contact = Contact.get_by(reply_email=reply_email)
|
|
|
|
if not contact:
|
|
|
|
return False
|
|
|
|
|
|
|
|
alias = contact.alias
|
2021-06-24 07:47:01 +00:00
|
|
|
return rate_limited_for_alias(alias) or rate_limited_for_mailbox(alias)
|
2020-04-04 14:27:22 +00:00
|
|
|
|
|
|
|
|
2021-06-24 07:47:01 +00:00
|
|
|
def rate_limited(mail_from: str, rcpt_tos: [str]) -> bool:
|
2020-04-04 14:27:22 +00:00
|
|
|
for rcpt_to in rcpt_tos:
|
2020-11-16 18:22:19 +00:00
|
|
|
if is_reply_email(rcpt_to):
|
2021-06-24 07:47:01 +00:00
|
|
|
if rate_limited_reply_phase(rcpt_to):
|
2020-04-04 14:27:22 +00:00
|
|
|
return True
|
|
|
|
else:
|
|
|
|
# Forward phase
|
2020-09-14 10:20:16 +00:00
|
|
|
address = rcpt_to # alias@SL
|
2021-06-24 07:47:01 +00:00
|
|
|
if rate_limited_forward_phase(address):
|
2020-04-04 14:27:22 +00:00
|
|
|
return True
|
|
|
|
|
|
|
|
return False
|