Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F117748774
D5865.1775178732.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
8 KB
Referenced Files
None
Subscribers
None
D5865.1775178732.diff
View Options
diff --git a/doc/Policies/RATELIMIT.md b/doc/Policies/RATELIMIT.md
--- a/doc/Policies/RATELIMIT.md
+++ b/doc/Policies/RATELIMIT.md
@@ -10,20 +10,17 @@
1. Mail from soft-deleted or suspended senders is put on HOLD.
2. Whitelisted senders are NOT rate limited (see the Whitelists section below).
-3. Accounts with 100% discount are NOT rate limited.
-4. Accounts with positive balance and any payments are NOT rate limited.
-5. If a sender or all users in an account, in last 60 minutes:
- a) sent at least `RATELIMIT_MAX_MESSAGES` (default: 10) messages or
- b) sent messages to at least `RATELIMIT_MAX_RECIPIENTS` (default: 250) recipients,
- sumbission if DEFER-ed.
+3. If a sender or all users in an account, in last 60 minutes sent messages to
+ at least `RATELIMIT_MAX_RECIPIENTS` (default: 250) recipients, sumbission is DEFER-ed.
+ The limit for new (restricted) accounts is different (`RATELIMIT_MAX_RECIPIENTS_RESTRICTED`).
## Automatic suspending
-A sender (or the whole account) created in last two months gets suspended if the submission rate
-is exceeded too much. Limits are:
+A sender (or the whole account) gets suspended if the submission rate is exceeded too much. Limit
+to number of recipients in last 60 minutes is:
-- count of messages in last 60 minutes: (`RATELIMIT_MAX_MESSAGES * RATELIMIT_SUSPEND_FACTOR`)
-- count of recipients in last 60 minutes: (`RATELIMIT_MAX_RECIPIENTS * RATELIMIT_SUSPEND_FACTOR`)
+- for all accounts: `RATELIMIT_SUSPEND_MAX_RECIPIENTS`
+- for new (restricted) accounts: `RATELIMIT_SUSPEND_MAX_RECIPIENTS_RESTRICTED`
## Whitelists
diff --git a/src/app/Policy/RateLimit.php b/src/app/Policy/RateLimit.php
--- a/src/app/Policy/RateLimit.php
+++ b/src/app/Policy/RateLimit.php
@@ -2,8 +2,8 @@
namespace App\Policy;
+use App\EventLog;
use App\Traits\BelongsToUserTrait;
-use App\Transaction;
use App\User;
use App\UserAlias;
use App\Utils;
@@ -133,94 +133,54 @@
$request->save();
}
- // exempt owners that have 100% discount.
- if ($wallet->discount && $wallet->discount->discount == 100) {
- return new Response(Response::ACTION_DUNNO);
+ // Examine the rates at which the account is sending
+ if ($error = self::checkLimits($user, $owner)) {
+ return new Response(Response::ACTION_DEFER_IF_PERMIT, $error, 403);
}
- // exempt owners that currently maintain a positive balance and made any payments.
- // Because there might be users that pay via external methods (and don't have Payment records)
- // we can't check only the Payments table. Instead we assume that a credit/award transaction
- // is enough to consider the user a "paying user" for purpose of the rate limit.
- if ($wallet->balance > 0) {
- $isPayer = $wallet->transactions()
- ->whereIn('type', [Transaction::WALLET_AWARD, Transaction::WALLET_CREDIT])
- ->where('amount', '>', 0)
- ->exists();
-
- if ($isPayer) {
- return new Response(Response::ACTION_DUNNO);
- }
- }
+ return new Response(Response::ACTION_DUNNO);
+ }
- $max_messages = config('app.ratelimit_max_messages');
+ /**
+ * Check number of recipients limit
+ */
+ private static function checkLimits($user, $owner): ?string
+ {
$max_recipients = config('app.ratelimit_max_recipients');
- $suspend_factor = config('app.ratelimit_suspend_factor');
+ $max_recipients_restricted = config('app.ratelimit_max_recipients_restricted');
+ $suspend_max_recipients = config('app.ratelimit_suspend_max_recipients');
+ $suspend_max_recipients_restricted = config('app.ratelimit_suspend_max_recipients_restricted');
- $ageThreshold = Carbon::now()->subMonthsWithoutOverflow(2);
+ // New users should get a lower limit
+ if ($owner->isRestricted() && $max_recipients_restricted) {
+ $max_recipients = $max_recipients_restricted;
+ }
- // Examine the rates at which the owner (or its users) is sending
- $ownerRates = self::where('owner_id', $owner->id)
- ->where('updated_at', '>=', Carbon::now()->subHour());
+ $recipient_count = self::where('owner_id', $owner->id)
+ ->where('updated_at', '>=', Carbon::now()->subHour())
+ ->sum('recipient_count');
- if (($count = $ownerRates->count()) >= $max_messages) {
- // automatically suspend (recursively) if X times over the original limit and younger than two months
- if ($count >= $max_messages * $suspend_factor && $owner->created_at > $ageThreshold) {
- $owner->suspendAccount();
+ if ($recipient_count >= $max_recipients) {
+ // New users should get a lower limit for suspension
+ if ($owner->isRestricted() && $suspend_max_recipients_restricted) {
+ $suspend_max_recipients = $suspend_max_recipients_restricted;
}
- return new Response(
- Response::ACTION_DEFER_IF_PERMIT,
- "The account is at {$max_messages} messages per hour, cool down.",
- 403
- );
- }
-
- if (($recipientCount = $ownerRates->sum('recipient_count')) >= $max_recipients) {
- // automatically suspend if X times over the original limit and younger than two months
- if ($recipientCount >= $max_recipients * $suspend_factor && $owner->created_at > $ageThreshold) {
+ // automatically suspend if X times over the original limit
+ if ($recipient_count >= $suspend_max_recipients) {
$owner->suspendAccount();
- }
- return new Response(
- Response::ACTION_DEFER_IF_PERMIT,
- "The account is at {$max_recipients} recipients per hour, cool down.",
- 403
- );
- }
+ // TODO: We could include in the message who sent how many messages
+ EventLog::createFor($owner, EventLog::TYPE_SUSPENDED, "Submission rate limit exceeded by {$user->email}");
- // Examine the rates at which the user is sending (if not also the owner)
- if ($user->id != $owner->id) {
- $userRates = self::where('user_id', $user->id)
- ->where('updated_at', '>=', Carbon::now()->subHour());
-
- if (($count = $userRates->count()) >= $max_messages) {
- // automatically suspend if X times over the original limit and younger than two months
- if ($count >= $max_messages * $suspend_factor && $user->created_at > $ageThreshold) {
- $user->suspend();
- }
-
- return new Response(
- Response::ACTION_DEFER_IF_PERMIT,
- "User is at {$max_messages} messages per hour, cool down.",
- 403
- );
+ // TODO: Send a notification email to the account owner?
}
- if (($recipientCount = $userRates->sum('recipient_count')) >= $max_recipients) {
- // automatically suspend if X times over the original limit
- if ($recipientCount >= $max_recipients * $suspend_factor && $user->created_at > $ageThreshold) {
- $user->suspend();
- }
-
- return new Response(
- Response::ACTION_DEFER_IF_PERMIT,
- "The account is at {$max_recipients} recipients per hour, cool down.",
- 403
- );
- }
+ return "The account is at {$max_recipients} recipients per hour, cool down.";
}
- return new Response(Response::ACTION_DUNNO);
+ // TODO: Add another cumulative limit (for 24 hours)?
+
+ return null;
}
}
diff --git a/src/config/app.php b/src/config/app.php
--- a/src/config/app.php
+++ b/src/config/app.php
@@ -275,9 +275,11 @@
'woat_ns2' => env('WOAT_NS2', 'ns02.' . env('APP_DOMAIN')),
'ratelimit_whitelist' => explode(',', env('RATELIMIT_WHITELIST', '')),
- 'ratelimit_max_messages' => (int) env('RATELIMIT_MAX_MESSAGES', 10),
'ratelimit_max_recipients' => (int) env('RATELIMIT_MAX_RECIPIENTS', 100),
- 'ratelimit_suspend_factor' => (float) env('RATELIMIT_SUSPEND_FACTOR', 2.5),
+ 'ratelimit_max_recipients_restricted' => (int) env('RATELIMIT_MAX_RECIPIENTS_RESTRICTED'),
+ 'ratelimit_suspend_max_recipients' => (int) env('RATELIMIT_SUSPEND_MAX_RECIPIENTS', 250),
+ 'ratelimit_suspend_max_recipients_restricted' => (int) env('RATELIMIT_SUSPEND_MAX_RECIPIENTS_RESTRICTED'),
+
'companion_download_link' => env(
'COMPANION_DOWNLOAD_LINK',
"https://mirror.apheleia-it.ch/pub/companion-app-beta.apk"
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Apr 3, 1:12 AM (21 h, 35 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18821853
Default Alt Text
D5865.1775178732.diff (8 KB)
Attached To
Mode
D5865: Rework Rate Limiting
Attached
Detach File
Event Timeline