Update Compose Apis, refactor rate limits

This commit is contained in:
Daniel Supernault 2021-03-01 20:58:35 -07:00
parent f3a2b354db
commit 42375b3d79
No known key found for this signature in database
GPG key ID: 0DEF1C662C9033F7
5 changed files with 74 additions and 8 deletions

View file

@ -1043,6 +1043,15 @@ class ApiV1Controller extends Controller
return []; return [];
} }
$limitKey = 'compose:rate-limit:media-upload:' . $user->id;
$limitTtl = now()->addMinutes(15);
$limitReached = Cache::remember($limitKey, $limitTtl, function() use($user) {
$dailyLimit = Media::whereUserId($user->id)->where('created_at', '>', now()->subDays(1))->count();
return $dailyLimit >= 250;
});
abort_if($limitReached == true, 429);
$profile = $user->profile; $profile = $user->profile;
if(config('pixelfed.enforce_account_limit') == true) { if(config('pixelfed.enforce_account_limit') == true) {
@ -1097,6 +1106,7 @@ class ApiV1Controller extends Controller
break; break;
} }
Cache::forget($limitKey);
$resource = new Fractal\Resource\Item($media, new MediaTransformer()); $resource = new Fractal\Resource\Item($media, new MediaTransformer());
$res = $this->fractal->createData($resource)->toArray(); $res = $this->fractal->createData($resource)->toArray();
$res['preview_url'] = $media->url(). '?cb=1&_v=' . time(); $res['preview_url'] = $media->url(). '?cb=1&_v=' . time();
@ -1753,6 +1763,20 @@ class ApiV1Controller extends Controller
$in_reply_to_id = $request->input('in_reply_to_id'); $in_reply_to_id = $request->input('in_reply_to_id');
$user = $request->user(); $user = $request->user();
$limitKey = 'compose:rate-limit:store:' . $user->id;
$limitTtl = now()->addMinutes(15);
$limitReached = Cache::remember($limitKey, $limitTtl, function() use($user) {
$dailyLimit = Status::whereProfileId($user->profile_id)
->whereNull('in_reply_to_id')
->whereNull('reblog_of_id')
->where('created_at', '>', now()->subDays(1))
->count();
return $dailyLimit >= 100;
});
abort_if($limitReached == true, 429);
$visibility = $profile->is_private ? 'private' : ( $visibility = $profile->is_private ? 'private' : (
$profile->unlisted == true && $profile->unlisted == true &&
$request->input('visibility', 'public') == 'public' ? $request->input('visibility', 'public') == 'public' ?
@ -1826,6 +1850,8 @@ class ApiV1Controller extends Controller
Cache::forget('_api:statuses:recent_9:'.$user->profile_id); Cache::forget('_api:statuses:recent_9:'.$user->profile_id);
Cache::forget('profile:status_count:'.$user->profile_id); Cache::forget('profile:status_count:'.$user->profile_id);
Cache::forget($user->storageUsedKey()); Cache::forget($user->storageUsedKey());
Cache::forget('profile:embed:' . $status->profile_id);
Cache::forget($limitKey);
$resource = new Fractal\Resource\Item($status, new StatusTransformer()); $resource = new Fractal\Resource\Item($status, new StatusTransformer());
$res = $this->fractal->createData($resource)->toArray(); $res = $this->fractal->createData($resource)->toArray();

View file

@ -81,6 +81,16 @@ class ComposeController extends Controller
$user = Auth::user(); $user = Auth::user();
$profile = $user->profile; $profile = $user->profile;
$limitKey = 'compose:rate-limit:media-upload:' . $user->id;
$limitTtl = now()->addMinutes(15);
$limitReached = Cache::remember($limitKey, $limitTtl, function() use($user) {
$dailyLimit = Media::whereUserId($user->id)->where('created_at', '>', now()->subDays(1))->count();
return $dailyLimit >= 250;
});
abort_if($limitReached == true, 429);
if(config('pixelfed.enforce_account_limit') == true) { if(config('pixelfed.enforce_account_limit') == true) {
$size = Cache::remember($user->storageUsedKey(), now()->addDays(3), function() use($user) { $size = Cache::remember($user->storageUsedKey(), now()->addDays(3), function() use($user) {
return Media::whereUserId($user->id)->sum('size') / 1000; return Media::whereUserId($user->id)->sum('size') / 1000;
@ -138,6 +148,7 @@ class ComposeController extends Controller
break; break;
} }
Cache::forget($limitKey);
$resource = new Fractal\Resource\Item($media, new MediaTransformer()); $resource = new Fractal\Resource\Item($media, new MediaTransformer());
$res = $this->fractal->createData($resource)->toArray(); $res = $this->fractal->createData($resource)->toArray();
$res['preview_url'] = $preview_url; $res['preview_url'] = $preview_url;
@ -160,6 +171,16 @@ class ComposeController extends Controller
$user = Auth::user(); $user = Auth::user();
$limitKey = 'compose:rate-limit:media-updates:' . $user->id;
$limitTtl = now()->addMinutes(15);
$limitReached = Cache::remember($limitKey, $limitTtl, function() use($user) {
$dailyLimit = Media::whereUserId($user->id)->where('created_at', '>', now()->subDays(1))->count();
return $dailyLimit >= 500;
});
abort_if($limitReached == true, 429);
$photo = $request->file('file'); $photo = $request->file('file');
$id = $request->input('id'); $id = $request->input('id');
@ -179,6 +200,7 @@ class ComposeController extends Controller
'url' => $media->url() . '?v=' . time() 'url' => $media->url() . '?v=' . time()
]; ];
ImageOptimize::dispatch($media); ImageOptimize::dispatch($media);
Cache::forget($limitKey);
return $res; return $res;
} }
@ -402,6 +424,21 @@ class ComposeController extends Controller
$user = Auth::user(); $user = Auth::user();
$profile = $user->profile; $profile = $user->profile;
$limitKey = 'compose:rate-limit:store:' . $user->id;
$limitTtl = now()->addMinutes(15);
$limitReached = Cache::remember($limitKey, $limitTtl, function() use($user) {
$dailyLimit = Status::whereProfileId($user->profile_id)
->whereNull('in_reply_to_id')
->whereNull('reblog_of_id')
->where('created_at', '>', now()->subDays(1))
->count();
return $dailyLimit >= 100;
});
abort_if($limitReached == true, 429);
$visibility = $request->input('visibility'); $visibility = $request->input('visibility');
$medias = $request->input('media'); $medias = $request->input('media');
$attachments = []; $attachments = [];
@ -495,6 +532,7 @@ class ComposeController extends Controller
Cache::forget('status:transformer:media:attachments:'.$status->id); Cache::forget('status:transformer:media:attachments:'.$status->id);
Cache::forget($user->storageUsedKey()); Cache::forget($user->storageUsedKey());
Cache::forget('profile:embed:' . $status->profile_id); Cache::forget('profile:embed:' . $status->profile_id);
Cache::forget($limitKey);
return $status->url(); return $status->url();
} }

View file

@ -818,6 +818,13 @@ export default {
self.page = 2; self.page = 2;
break; break;
case 429:
self.uploading = false;
io.value = null;
swal('Limit Reached', 'You can upload up to 250 photos or videos per day and you\'ve reached that limit. Please try again later.', 'error');
self.page = 2;
break;
default: default:
self.uploading = false; self.uploading = false;
io.value = null; io.value = null;

View file

@ -68,7 +68,7 @@ Route::group(['prefix' => 'api'], function() use($middleware) {
Route::post('statuses/{id}/unbookmark', 'Api\ApiV1Controller@unbookmarkStatus')->middleware($middleware); Route::post('statuses/{id}/unbookmark', 'Api\ApiV1Controller@unbookmarkStatus')->middleware($middleware);
Route::delete('statuses/{id}', 'Api\ApiV1Controller@statusDelete')->middleware($middleware); Route::delete('statuses/{id}', 'Api\ApiV1Controller@statusDelete')->middleware($middleware);
Route::get('statuses/{id}', 'Api\ApiV1Controller@statusById')->middleware($middleware); Route::get('statuses/{id}', 'Api\ApiV1Controller@statusById')->middleware($middleware);
Route::post('statuses', 'Api\ApiV1Controller@statusCreate')->middleware($middleware)->middleware('throttle:maxPostsPerHour,60')->middleware('throttle:maxPostsPerDay,1440'); Route::post('statuses', 'Api\ApiV1Controller@statusCreate')->middleware($middleware);
Route::get('timelines/home', 'Api\ApiV1Controller@timelineHome')->middleware($middleware); Route::get('timelines/home', 'Api\ApiV1Controller@timelineHome')->middleware($middleware);

View file

@ -106,19 +106,14 @@ Route::domain(config('pixelfed.domain.app'))->middleware(['validemail', 'twofact
Route::group(['prefix' => 'compose'], function() { Route::group(['prefix' => 'compose'], function() {
Route::group(['prefix' => 'v0'], function() { Route::group(['prefix' => 'v0'], function() {
Route::post('/media/upload', 'ComposeController@mediaUpload'); Route::post('/media/upload', 'ComposeController@mediaUpload');
Route::post('/media/update', 'ComposeController@mediaUpdate') Route::post('/media/update', 'ComposeController@mediaUpdate');
->middleware('throttle:maxComposeMediaUpdatesPerHour,60')
->middleware('throttle:maxComposeMediaUpdatesPerDay,1440')
->middleware('throttle:maxComposeMediaUpdatesPerMonth,43800');
Route::delete('/media/delete', 'ComposeController@mediaDelete'); Route::delete('/media/delete', 'ComposeController@mediaDelete');
Route::get('/search/tag', 'ComposeController@searchTag'); Route::get('/search/tag', 'ComposeController@searchTag');
Route::get('/search/location', 'ComposeController@searchLocation'); Route::get('/search/location', 'ComposeController@searchLocation');
Route::get('/search/mention', 'ComposeController@searchMentionAutocomplete'); Route::get('/search/mention', 'ComposeController@searchMentionAutocomplete');
Route::get('/search/hashtag', 'ComposeController@searchHashtagAutocomplete'); Route::get('/search/hashtag', 'ComposeController@searchHashtagAutocomplete');
Route::post('/publish', 'ComposeController@store') Route::post('/publish', 'ComposeController@store');
->middleware('throttle:maxPostsPerHour,60')
->middleware('throttle:maxPostsPerDay,1440');
Route::post('/publish/text', 'ComposeController@storeText'); Route::post('/publish/text', 'ComposeController@storeText');
Route::get('/media/processing', 'ComposeController@mediaProcessingCheck'); Route::get('/media/processing', 'ComposeController@mediaProcessingCheck');
}); });