File tree Expand file tree Collapse file tree 7 files changed +146
-37
lines changed Expand file tree Collapse file tree 7 files changed +146
-37
lines changed Original file line number Diff line number Diff line change @@ -27,6 +27,10 @@ offer secure content and even log in to the application.
2727- [ Lifetime] ( #lifetime )
2828- [ Events] ( #events )
2929- [ Customization] ( #customization )
30+ - [ Rate limiting] ( #rate-limiting )
31+ - [ Testing] ( #testing )
32+ - [ Contributing] ( #contributing )
33+ - [ Security] ( #security )
3034
3135## Installation
3236
@@ -326,8 +330,8 @@ php artisan vendor:publish --provider="MagicLink\MagicLinkServiceProvider" --tag
326330
327331And edit the file ` config/magiclink.php `
328332
329-
330333### Migrations
334+
331335To customize the migration files of this package you need to publish the migration files:
332336
333337``` bash
@@ -336,7 +340,6 @@ php artisan vendor:publish --provider="MagicLink\MagicLinkServiceProvider" --tag
336340
337341You'll find the published files in ` database/migrations/* `
338342
339-
340343### Custom response when magiclink is invalid
341344
342345When the magicLink is invalid by default the http request return a status 403.
@@ -407,6 +410,19 @@ return a `view()`
407410 ],
408411```
409412
413+ ## Rate limiting
414+
415+ You can limit the number of requests per minute for a magic link. To do this, you need to
416+ set the ` MAGICLINK_RATE_LIMIT ` environment variable to the desired value.
417+
418+ By default, the rate limit is 100 attempts per minutes. Use ` none ` to disable the rate limit.
419+
420+ ``` bash
421+ # .env
422+
423+ MAGICLINK_RATE_LIMIT=' none'
424+ ```
425+
410426## Testing
411427
412428Run the tests with:
Original file line number Diff line number Diff line change 11<?php
22
3+
34return [
45
56 'access_code ' => [
7+ /*
8+ |--------------------------------------------------------------------------
9+ | Access Code View
10+ |--------------------------------------------------------------------------
11+ |
12+ | Here you may specify the view to ask for access code.
13+ |
14+ */
615 'view ' => 'magiclink::ask-for-access-code-form ' ,
716 ],
817
3241 'class ' => MagicLink \Responses \Response::class,
3342 ],
3443
35- 'token ' => [
44+ 'middlewares ' => [
45+ 'throttle:magiclink ' ,
46+ MagicLink \Middlewares \MagiclinkMiddleware::class,
47+ 'web ' ,
48+ ],
49+
50+ /*
51+ |--------------------------------------------------------------------------
52+ | Rate Limit
53+ |--------------------------------------------------------------------------
54+ |
55+ | Here you may specify the number of attempts to rate limit per minutes
56+ |
57+ | Default: 100, if you want to disable rate limit, set as 'none'
58+ */
59+ 'rate_limit ' => env ('MAGICLINK_RATE_LIMIT ' , 100 ),
60+
61+ 'token ' => [
3662 /*
3763 |--------------------------------------------------------------------------
3864 | Token size
Original file line number Diff line number Diff line change 11<?php
22
33use Illuminate \Support \Facades \Route ;
4- use MagicLink \Middlewares \MagiclinkMiddleware ;
54
65Route::group (
76 [
8- 'middleware ' => [
9- MagiclinkMiddleware::class,
10- 'web ' ,
11- ],
7+ 'middleware ' => config ('magiclink.middlewares ' ),
128 ],
139 function () {
1410 Route::get (
Original file line number Diff line number Diff line change 22
33namespace MagicLink ;
44
5+ use Illuminate \Cache \RateLimiting \Limit ;
6+ use Illuminate \Support \Facades \RateLimiter ;
57use Illuminate \Support \ServiceProvider ;
68
79class MagicLinkServiceProvider extends ServiceProvider
@@ -15,11 +17,25 @@ public function boot()
1517 {
1618 $ this ->offerPublishing ();
1719
20+ $ this ->registerRateLimit ();
21+
1822 $ this ->loadRouteMagicLink ();
1923
2024 $ this ->loadViewMagicLink ();
2125 }
2226
27+ private function registerRateLimit (): void
28+ {
29+ $ rateLimit = config ('magiclink.rate_limit ' , 100 );
30+
31+ RateLimiter::for (
32+ 'magiclink ' ,
33+ fn () => $ rateLimit === 'none '
34+ ? Limit::none ()
35+ : Limit::perMinute ($ rateLimit )
36+ );
37+ }
38+
2339 private function loadRouteMagicLink (): void
2440 {
2541 $ disableRegisterRoute = config ('magiclink.disable_default_route ' , false );
Original file line number Diff line number Diff line change 1+ <?php
2+
3+ namespace MagicLink \Test \Http ;
4+
5+ use MagicLink \Actions \ResponseAction ;
6+ use MagicLink \MagicLink ;
7+ use MagicLink \Test \TestCase ;
8+
9+ class HttpHeadTest extends TestCase
10+ {
11+ public function test_http_head_request_has_not_effects ()
12+ {
13+ $ magiclink = MagicLink::create (new ResponseAction (function () {
14+ return 'private content ' ;
15+ }));
16+
17+ $ magiclink ->num_visits = 4 ;
18+ $ magiclink ->save ();
19+
20+ $ this ->head ($ magiclink ->url )
21+ ->assertStatus (200 )
22+ ->assertDontSeeText ('private content ' );
23+
24+ $ magiclink ->refresh ();
25+
26+ $ this ->assertEquals (4 , $ magiclink ->num_visits );
27+ }
28+
29+ public function test_http_head_request_without_valid_magiclink ()
30+ {
31+ $ magiclink = MagicLink::create (new ResponseAction (function () {
32+ return 'private content ' ;
33+ }));
34+
35+ $ this ->head ($ magiclink ->url . '-bad ' )
36+ ->assertStatus (404 );
37+ }
38+ }
Original file line number Diff line number Diff line change 11<?php
22
3- namespace MagicLink \Test ;
3+ namespace MagicLink \Test \ Http ;
44
55use MagicLink \Actions \ResponseAction ;
66use MagicLink \MagicLink ;
7+ use MagicLink \Test \TestCase ;
78
89class HttpTest extends TestCase
910{
@@ -25,24 +26,6 @@ public function test_http_get_request()
2526 $ this ->assertEquals (5 , $ magiclink ->num_visits );
2627 }
2728
28- public function test_http_head_request_has_not_effects ()
29- {
30- $ magiclink = MagicLink::create (new ResponseAction (function () {
31- return 'private content ' ;
32- }));
33-
34- $ magiclink ->num_visits = 4 ;
35- $ magiclink ->save ();
36-
37- $ this ->head ($ magiclink ->url )
38- ->assertStatus (200 )
39- ->assertDontSeeText ('private content ' );
40-
41- $ magiclink ->refresh ();
42-
43- $ this ->assertEquals (4 , $ magiclink ->num_visits );
44- }
45-
4629 public function test_http_options_request_has_not_effects ()
4730 {
4831 $ magiclink = MagicLink::create (new ResponseAction (function () {
@@ -73,14 +56,4 @@ public function test_http_urlencode_legacy()
7356 ->assertStatus (200 )
7457 ->assertSeeText ('private content ' );
7558 }
76-
77- public function test_http_head_request_without_valid_magiclink ()
78- {
79- $ magiclink = MagicLink::create (new ResponseAction (function () {
80- return 'private content ' ;
81- }));
82-
83- $ this ->head ($ magiclink ->url . '-bad ' )
84- ->assertStatus (404 );
85- }
8659}
Original file line number Diff line number Diff line change 1+ <?php
2+
3+ namespace MagicLink \Test \Http ;
4+
5+ use MagicLink \Actions \ResponseAction ;
6+ use MagicLink \MagicLink ;
7+ use MagicLink \MagicLinkServiceProvider ;
8+ use MagicLink \Test \TestCase ;
9+
10+ class HttpThrottleTest extends TestCase
11+ {
12+ public function test_http_failed_when_rate_limit_is_exceeded ()
13+ {
14+ config (['magiclink.rate_limit ' => 1 ]);
15+ (new MagicLinkServiceProvider ($ this ->app ))->boot ();
16+
17+ $ magiclink = MagicLink::create (new ResponseAction (function () {
18+ return 'private content ' ;
19+ }));
20+
21+ $ this ->get ($ magiclink ->url )
22+ ->assertStatus (200 );
23+
24+ $ this ->get ($ magiclink ->url )
25+
26+ ->assertStatus (429 );
27+ }
28+ public function test_http_when_rate_limit_is_none ()
29+ {
30+ config (['magiclink.rate_limit ' => 'none ' ]);
31+ (new MagicLinkServiceProvider ($ this ->app ))->boot ();
32+
33+ $ magiclink = MagicLink::create (new ResponseAction (function () {
34+ return 'private content ' ;
35+ }));
36+
37+ $ this ->get ($ magiclink ->url )
38+ ->assertStatus (200 );
39+
40+ $ this ->get ($ magiclink ->url )
41+ ->assertStatus (200 );
42+ }
43+
44+ }
You can’t perform that action at this time.
0 commit comments