Skip to content

Commit 1ff2826

Browse files
committed
Exports: Added rate limits for UI exports
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.
1 parent 7e31725 commit 1ff2826

File tree

5 files changed

+32
-0
lines changed

5 files changed

+32
-0
lines changed

app/App/Providers/RouteServiceProvider.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,5 +85,12 @@ protected function configureRateLimiting(): void
8585
RateLimiter::for('public', function (Request $request) {
8686
return Limit::perMinute(10)->by($request->ip());
8787
});
88+
89+
RateLimiter::for('exports', function (Request $request) {
90+
$user = user();
91+
$attempts = $user->isGuest() ? 4 : 10;
92+
$key = $user->isGuest() ? $request->ip() : $user->id;
93+
return Limit::perMinute($attempts)->by($key);
94+
});
8895
}
8996
}

app/Exports/Controllers/BookExportController.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ public function __construct(
1616
protected ExportFormatter $exportFormatter,
1717
) {
1818
$this->middleware('can:content-export');
19+
$this->middleware('throttle:exports');
1920
}
2021

2122
/**

app/Exports/Controllers/ChapterExportController.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ public function __construct(
1616
protected ExportFormatter $exportFormatter,
1717
) {
1818
$this->middleware('can:content-export');
19+
$this->middleware('throttle:exports');
1920
}
2021

2122
/**

app/Exports/Controllers/PageExportController.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public function __construct(
1717
protected ExportFormatter $exportFormatter,
1818
) {
1919
$this->middleware('can:content-export');
20+
$this->middleware('throttle:exports');
2021
}
2122

2223
/**

tests/Exports/ZipExportTest.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,28 @@ public function test_links_in_markdown_are_parsed()
423423
$this->assertStringContainsString("[Link to chapter]([[bsexport:chapter:{$chapter->id}]])", $pageData['markdown']);
424424
}
425425

426+
public function test_exports_rate_limited_low_for_guest_viewers()
427+
{
428+
$this->setSettings(['app-public' => 'true']);
429+
430+
$page = $this->entities->page();
431+
for ($i = 0; $i < 4; $i++) {
432+
$this->get($page->getUrl("/export/zip"))->assertOk();
433+
}
434+
$this->get($page->getUrl("/export/zip"))->assertStatus(429);
435+
}
436+
437+
public function test_exports_rate_limited_higher_for_logged_in_viewers()
438+
{
439+
$this->asAdmin();
440+
441+
$page = $this->entities->page();
442+
for ($i = 0; $i < 10; $i++) {
443+
$this->get($page->getUrl("/export/zip"))->assertOk();
444+
}
445+
$this->get($page->getUrl("/export/zip"))->assertStatus(429);
446+
}
447+
426448
protected function extractZipResponse(TestResponse $response): ZipResultData
427449
{
428450
$zipData = $response->streamedContent();

0 commit comments

Comments
 (0)