Exports: Added rate limits for UI exports
Some checks failed
test-php / build (8.2) (push) Has been cancelled
test-php / build (8.3) (push) Has been cancelled
test-php / build (8.4) (push) Has been cancelled
analyse-php / build (push) Has been cancelled
lint-php / build (push) Has been cancelled
test-migrations / build (8.1) (push) Has been cancelled
test-migrations / build (8.2) (push) Has been cancelled
test-migrations / build (8.3) (push) Has been cancelled
test-migrations / build (8.4) (push) Has been cancelled
test-php / build (8.1) (push) Has been cancelled

Just as a measure to prevent potential abuse of these potentially
longer-running endpoints.
Adds test to cover for ZIP exports, but applied to all formats.
This commit is contained in:
Dan Brown 2025-01-01 15:42:59 +00:00
parent 7e31725d48
commit 1ff2826678
No known key found for this signature in database
GPG Key ID: 46D9F943C24A2EF9
5 changed files with 32 additions and 0 deletions

View File

@ -85,5 +85,12 @@ class RouteServiceProvider extends ServiceProvider
RateLimiter::for('public', function (Request $request) {
return Limit::perMinute(10)->by($request->ip());
});
RateLimiter::for('exports', function (Request $request) {
$user = user();
$attempts = $user->isGuest() ? 4 : 10;
$key = $user->isGuest() ? $request->ip() : $user->id;
return Limit::perMinute($attempts)->by($key);
});
}
}

View File

@ -16,6 +16,7 @@ class BookExportController extends Controller
protected ExportFormatter $exportFormatter,
) {
$this->middleware('can:content-export');
$this->middleware('throttle:exports');
}
/**

View File

@ -16,6 +16,7 @@ class ChapterExportController extends Controller
protected ExportFormatter $exportFormatter,
) {
$this->middleware('can:content-export');
$this->middleware('throttle:exports');
}
/**

View File

@ -17,6 +17,7 @@ class PageExportController extends Controller
protected ExportFormatter $exportFormatter,
) {
$this->middleware('can:content-export');
$this->middleware('throttle:exports');
}
/**

View File

@ -423,6 +423,28 @@ class ZipExportTest extends TestCase
$this->assertStringContainsString("[Link to chapter]([[bsexport:chapter:{$chapter->id}]])", $pageData['markdown']);
}
public function test_exports_rate_limited_low_for_guest_viewers()
{
$this->setSettings(['app-public' => 'true']);
$page = $this->entities->page();
for ($i = 0; $i < 4; $i++) {
$this->get($page->getUrl("/export/zip"))->assertOk();
}
$this->get($page->getUrl("/export/zip"))->assertStatus(429);
}
public function test_exports_rate_limited_higher_for_logged_in_viewers()
{
$this->asAdmin();
$page = $this->entities->page();
for ($i = 0; $i < 10; $i++) {
$this->get($page->getUrl("/export/zip"))->assertOk();
}
$this->get($page->getUrl("/export/zip"))->assertStatus(429);
}
protected function extractZipResponse(TestResponse $response): ZipResultData
{
$zipData = $response->streamedContent();