Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
MadMikeyB committed Oct 25, 2017
0 parents commit 384bc04
Show file tree
Hide file tree
Showing 9 changed files with 421 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules/
vendor/
composer.lock
.DS_Store
._*
21 changes: 21 additions & 0 deletions LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# The MIT License (MIT)

Copyright (c) Michael Burton

> Permission is hereby granted, free of charge, to any person obtaining a copy
> of this software and associated documentation files (the "Software"), to deal
> in the Software without restriction, including without limitation the rights
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> copies of the Software, and to permit persons to whom the Software is
> furnished to do so, subject to the following conditions:
>
> The above copyright notice and this permission notice shall be included in
> all copies or substantial portions of the Software.
>
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> THE SOFTWARE.
139 changes: 139 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
# Laravel Throttleable

[![Packagist](https://img.shields.io/packagist/v/madmikeyb/throttleable.svg?style=flat-square)](https://packagist.org/packages/madmikeyb/throttleable)
[![Packagist](https://img.shields.io/packagist/l/madmikeyb/throttleable.svg?style=flat-square)]()

Throttle requests to your application based on users IP address.

- Set a threshold on how many requests an IP address can make.
- Throttles expire after a configurable period of time.
- Throttles are unique per IP address.
- Configurable through `config/throttleable.php`

## Installation

Pull in the package using Composer

composer require madmikeyb/throttleable

> **Note**: If you are using Laravel 5.5, the next step for provider are unnecessary. Laravel Throttleable supports Laravel [Package Discovery](https://laravel.com/docs/5.5/packages#package-discovery).
Include the service provider within `app/config/app.php`.

```php
'providers' => [
...
MadMikeyB\Throttleable\Providers\ThrottleableServiceProvider::class,
],
```

You can publish [the migration](https://github.com/madmikeyb/throttleable/blob/master/database/migrations/create_throttles_table.php.stub) with:

```bash
php artisan vendor:publish --provider="MadMikeyB\Throttleable\Providers\ThrottleableServiceProvider" --tag="migrations"
php artisan migrate
```

You can publish the config file with:

```bash
php artisan vendor:publish --provider="MadMikeyB\Throttleable\Providers\ThrottleableServiceProvider" --tag="config"
```

When published, [the `config/throttleable.php` config file](https://github.com/madmikeyb/throttleable/blob/master/config/throttleable.php) contains:

```php
<?php

return [
'attempt_limit' => 10,
'expiry_weeks' => 1
];
```

These are merely the default values and can be overriden on a case-by-case basis if needed.

## Sample Usage

Simply import the Throttle Model in your controller.

```php
<?php
namespace App\Http\Controllers;

use MadMikeyB\Throttleable\Models\Throttle;
```

Then, on whichever method you'd like to throttle, new up a `Throttle` instance. The minimum parameters required by this class is an instance of `Illuminate\Http\Request`.

The `check()` method of `Throttle` returns a boolean, which indicates whether the IP address has been throttled or not.

```php
public function create(Request $request)
{
$throttle = new Throttle($request->instance());

if (!$throttle->check()) {
alert()->error('Sorry, you have made too many requests. Please try again later.');
return back();
}
}
```

**NB. the `alert()` helper is provided by [uxweb/sweet-alert](https://github.com/uxweb/sweet-alert) and is not included in this package.**

## Full Example

```php
<?php
namespace App\Http\Controllers;

use App\Comment;
use MadMikeyB\Throttleable\Models\Throttle;

class CommentsController
{
public function store(Request $request)
{
$throttle = new Throttle($request->instance());

if (!$throttle->check()) {
alert()->error('Sorry, you have made too many requests. Please try again later.');
return back();
}

// save comment here
Comment::create($request->all());
alert()->success('Comment Created!');
return back();
}
}
```

## Overriding Configuration on a case-by-case basis

If you need to allow one method more attempts than is defined in the configuration file, you may override the defaults by passing them as the second and third arguments to `Throttle`.

```php
public function store(Request $request)
{
$attemptLimit = 10000;
$expiryWeeks = 52;

$throttle = new Throttle($request->instance(), $attemptLimit, $expiryWeeks);

if (!$throttle->check()) {
alert()->error('Sorry, you have made too many requests. Please try again later.');
return back();
}

// save comment here
Comment::create($request->all());
alert()->success('Comment Created!');
return back();
}
```

## License

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.
39 changes: 39 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"name": "madmikeyb/throttleable",
"description": "Temporarily disallow IP addresses from taking certain actions within your Laravel Application",
"keywords": [
"madmikeyb",
"laravel",
"throttleable",
"security"
],
"license": "MIT",
"homepage": "https://github.com/madmikeyb/throttleable",
"authors": [
{
"name": "Michael Burton",
"email": "[email protected]",
"homepage": "http://mikeylicio.us",
"role": "Developer"
}
],
"require": {
"php" : ">=7.0",
"illuminate/database": "~5.4.0|~5.5.0",
"illuminate/http": "~5.4.0|~5.5.0",
"nesbot/carbon": "~1.20",
"illuminate/events": "~5.4.0|~5.5.0"
},
"autoload": {
"psr-4": {
"MadMikeyB\\Throttleable\\": "src"
}
},
"extra": {
"laravel": {
"providers": [
"MadMikeyB\\Throttleable\\Providers\\ThrottleableServiceProvider"
]
}
}
}
6 changes: 6 additions & 0 deletions config/throttleable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?php

return [
'attempt_limit' => 10,
'expiry_weeks' => 1
];
34 changes: 34 additions & 0 deletions database/migrations/create_throttles_table.php.stub
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateThrottlesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('throttles', function (Blueprint $table) {
$table->increments('id');
$table->string('ip');
$table->integer('attempts');
$table->timestamp('expires_at')->nullable();
$table->timestamp('created_at')->nullable();
});
}

/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('throttles');
}
}
42 changes: 42 additions & 0 deletions src/Models/Throttle.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

namespace MadMikeyB\Throttleable\Models;

use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Database\Eloquent\Model;
use MadMikeyB\Throttleable\Traits\Throttleable;

class Throttle extends Model
{
use Throttleable;

/** @var \Illuminate\Http\Request */
public $request;

/** @var int Number of attempts allowed before the user is throttled */
public $attemptLimit;

/** @var int Number of weeks before throttle expires */
public $expiryWeeks;

/** @var bool */
public $timestamps = false;

/** @var array */
protected $fillable = ['ip', 'attempts', 'expires_at', 'created_at'];

/** @var array */
protected $dates = ['expires_at', 'created_at'];

/**
* @param \Illuminate\Http\Request $request
*/
public function __construct($request, $attemptLimit = null, $expiryWeeks = null)
{
$this->request = $request;
$this->attemptLimit = $attemptLimit ?? config('throttleable.attempt_limit');
$this->expiryWeeks = $expiryWeeks ?? config('throttleable.expiry_weeks');
}

}
40 changes: 40 additions & 0 deletions src/Providers/ThrottleableServiceProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

namespace MadMikeyB\Throttleable\Providers;

use Illuminate\Support\ServiceProvider;

class ThrottleableServiceProvider extends ServiceProvider
{
/**
* Perform post-registration booting of services.
*
* @return void
*/
public function boot()
{
if (! class_exists(\CreateThrottlesTable::class)) {
$timestamp = date('Y_m_d_His');

$this->publishes([
__DIR__ . '/../../database/migrations/create_throttles_table.php.stub' => database_path("/migrations/{$timestamp}_create_throttles_table.php"),
], 'migrations');
}

$this->publishes([
__DIR__ . '/../../config/throttleable.php' => config_path('throttleable.php'),
], 'config');
}

/**
* Register bindings in the container.
*
* @return void
*/
public function register()
{
$this->mergeConfigFrom(
__DIR__ . '/../../config/throttleable.php', 'throttleable'
);
}
}
Loading

0 comments on commit 384bc04

Please sign in to comment.