From 908480c98aa48a9d1caf09ee00f3cfe0863afec2 Mon Sep 17 00:00:00 2001 From: Byron Jones Date: Fri, 31 Oct 2014 15:20:42 +0800 Subject: Bug 1062739: add the ability for administrators to limit the number of emails sent to a user per minute and hour r=dylan,a=glob --- Bugzilla/Mailer.pm | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) (limited to 'Bugzilla/Mailer.pm') diff --git a/Bugzilla/Mailer.pm b/Bugzilla/Mailer.pm index 4447d4046..389b6f69e 100644 --- a/Bugzilla/Mailer.pm +++ b/Bugzilla/Mailer.pm @@ -41,6 +41,8 @@ sub MessageToMTA { return; } + my $dbh = Bugzilla->dbh; + my $email; if (ref $msg) { $email = $msg; @@ -58,14 +60,50 @@ sub MessageToMTA { # email immediately, in case the transaction is rolled back. Instead we # insert it into the mail_staging table, and bz_commit_transaction calls # send_staged_mail() after the transaction is committed. - if (! $send_now && Bugzilla->dbh->bz_in_transaction()) { + if (! $send_now && $dbh->bz_in_transaction()) { # The e-mail string may contain tainted values. my $string = $email->as_string; trick_taint($string); - Bugzilla->dbh->do("INSERT INTO mail_staging (message) VALUES(?)", undef, $string); + $dbh->do("INSERT INTO mail_staging (message) VALUES(?)", undef, $string); return; } + # Ensure that we are not sending emails too quickly to recipients. + if (Bugzilla->params->{use_mailer_queue} + && (EMAIL_LIMIT_PER_MINUTE || EMAIL_LIMIT_PER_HOUR)) + { + $dbh->do( + "DELETE FROM email_rates WHERE message_ts < " + . $dbh->sql_date_math('LOCALTIMESTAMP(0)', '-', '1', 'HOUR')); + + my $recipient = $email->header('To'); + + if (EMAIL_LIMIT_PER_MINUTE) { + my $minute_rate = $dbh->selectrow_array( + "SELECT COUNT(*) + FROM email_rates + WHERE recipient = ? AND message_ts >= " + . $dbh->sql_date_math('LOCALTIMESTAMP(0)', '-', '1', 'MINUTE'), + undef, + $recipient); + if ($minute_rate >= EMAIL_LIMIT_PER_MINUTE) { + die EMAIL_LIMIT_EXCEPTION; + } + } + if (EMAIL_LIMIT_PER_HOUR) { + my $hour_rate = $dbh->selectrow_array( + "SELECT COUNT(*) + FROM email_rates + WHERE recipient = ? AND message_ts >= " + . $dbh->sql_date_math('LOCALTIMESTAMP(0)', '-', '1', 'HOUR'), + undef, + $recipient); + if ($hour_rate >= EMAIL_LIMIT_PER_HOUR) { + die EMAIL_LIMIT_EXCEPTION; + } + } + } + # We add this header to uniquely identify all email that we # send as coming from this Bugzilla installation. # @@ -181,6 +219,17 @@ sub MessageToMTA { ThrowCodeError('mail_send_error', { msg => $@->message, mail => $email }); } } + + # insert into email_rates + if (Bugzilla->params->{use_mailer_queue} + && (EMAIL_LIMIT_PER_MINUTE || EMAIL_LIMIT_PER_HOUR)) + { + $dbh->do( + "INSERT INTO email_rates(recipient, message_ts) VALUES (?, LOCALTIMESTAMP(0))", + undef, + $email->header('To') + ); + } } # Builds header suitable for use as a threading marker in email notifications -- cgit v1.2.3-24-g4f1b