Browse Source

Update Compose Apis, refactor rate limits

Daniel Supernault 4 years ago
parent
commit
42375b3d79

+ 26 - 0
app/Http/Controllers/Api/ApiV1Controller.php

@@ -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();

+ 38 - 0
app/Http/Controllers/ComposeController.php

@@ -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();
 	}
 	}

+ 7 - 0
resources/assets/js/components/ComposeModal.vue

@@ -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;

+ 1 - 1
routes/api.php

@@ -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);

+ 2 - 7
routes/web.php

@@ -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')
-                    ->middleware('throttle:maxComposeMediaUpdatesPerHour,60')
-                    ->middleware('throttle:maxComposeMediaUpdatesPerDay,1440')
-                    ->middleware('throttle:maxComposeMediaUpdatesPerMonth,43800');
+                Route::post('/media/update', 'ComposeController@mediaUpdate');
                 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')
-                    ->middleware('throttle:maxPostsPerHour,60')
-                    ->middleware('throttle:maxPostsPerDay,1440');
+                Route::post('/publish', 'ComposeController@store');
                 Route::post('/publish/text', 'ComposeController@storeText');
                 Route::post('/publish/text', 'ComposeController@storeText');
                 Route::get('/media/processing', 'ComposeController@mediaProcessingCheck');
                 Route::get('/media/processing', 'ComposeController@mediaProcessingCheck');
             });
             });