Banhammer

repository·2.x·Indexed 18 days ago

https://github.com/mchev/banhammer

A Laravel package for banning Eloquent models, IP addresses, and entire countries. It supports permanent and temporary bans with automatic expiration handling, geolocation-based blocking, and provides middleware for authenticated users, IPs, and country-level restrictions. Includes Artisan commands for managing ban lifecycles and a polymorphic Ban model for flexible record management.

Tokens
6.3K
Snippets
31
Records
35
Agent score
60%

What's inside banhammer

  1. Configuring UUIDs for Bans

    2.x

    If your application uses UUIDs instead of auto-incrementing IDs, follow these steps to configure Banhammer:

    1. Publish migrations and edit the migration file to change $table->id() to $table->uuid('id').
    2. Create a custom Ban model that uses the HasUuids trait:
      namespace App\
      Models;
      
      use Illuminate\Database\Eloquent\Concerns\HasUuids;
      use Mchev\Banhammer\Models\Ban as BanhammerBan;
      
      class Ban extends BanhammerBan
      {
          use HasUuids;
      }
    3. Update the config to point to your new model in config/ban.php:
      'model' => \App\Models\Ban::class,
    // config/ban.php
    'model' => \App\Models\Ban::class,
  2. Make an Eloquent model bannable

    2.x

    To allow an Eloquent model (such as User, Team, or Group) to be banned, add the Mchev\Banhammer\Traits\Bannable trait to the model class.

    use Mchevanhammer\Traits\Bannable;
    
    class User extends Model
    {
        use Bannable;
    }
  3. Automating ban expiration with the Scheduler

    2.x

    Banhammer automatically deletes expired bans using Laravel's scheduler. You must have a cron job running Laravel's scheduler for this to work.

    Configuration: By default, the banhammer:unban command runs every minute. You can customize this in config/ban.php or via environment variables.

    Disable automatic scheduler:

    // config/ban.php
    'scheduler_enabled' => false,

    Or via .env: BANHAMMER_SCHEDULER_ENABLED=false

    Change frequency:

    // config/ban.php
    'scheduler_periodicity' => 'everyFiveMinutes', // options: 'everyMinute', 'everyFiveMinutes', 'hourly', 'daily', etc.

    Or via .env: BANHAMMER_SCHEDULER_PERIODICITY=everyFiveMinutes

    // config/ban.php
    'scheduler_enabled' => true,
    'scheduler_periodicity' => 'everyMinute',
  4. Protecting routes with Ban Middleware

    2.x

    Use Banhammer's built-in middleware to protect your routes from banned users or IPs.

    MiddlewareDescription
    auth.bannedBlocks banned users
    ip.bannedBlocks banned IPs
    logout.bannedLogs out and blocks banned users/IPs

    Usage Examples:

    Single route:

    Route::get('/dashboard', [DashboardController::class, 'index'])
        ->middleware('auth.banned');

    Route group:

    Route::middleware(['auth.banned'])->group(function () {
        Route::get('/profile', [ProfileController::class, 'index']);
        Route::get('/settings', [SettingsController::class, 'index']);
    });

    Global IP protection: To block banned IPs on all routes, add the middleware to your app/Http/Kernel.php:

    protected $middleware = [
        // ...
        \Mchev\Banhammer\Middleware\IPBanned::class,
    ];

    Tip: logout.banned combines the functionality of both auth.banned and ip.banned.

    Route::get('/dashboard', [DashboardController::class, 'index'])->middleware('auth.banned');
  5. Install Banhammer in Laravel

    2.x

    To install Banhammer, require the package via Composer, publish the migrations, and run them to set up the necessary database tables.

    composer require mchev/banhammer
    php artisan vendor:publish --provider="Mchev\Banhammer\BanhammerServiceProvider" --tag="migrations"
    php artisan migrate
  6. Blocking countries

    2.x

    You can block entire countries by configuring the config/ban.php file. This uses middleware to automatically block requests from specified countries.

    1. Enable country blocking in config/ban.php:

      'block_by_country' => true,
    2. Specify blocked countries (using ISO codes):

      'blocked_countries' => ['FR', 'ES', 'US'],

    Note: This feature relies on geolocation services. The free version of ip-api.com has a limit of 45 requests/minute.

    // config/ban.php
    'block_by_country' => true,
    'blocked_countries' => ['FR', 'ES', 'US'],
  7. Handle Banhammer exceptions via custom rendering

    2.x

    When a BanhammerException is thrown, it defaults to a 403 Forbidden HTTP status code. The exception's behavior during rendering is determined by the ban.fallback_url configuration key:

    1. If ban.fallback_url is set: The user is automatically redirected to the configured URL.
    2. If ban.fallback_url is NOT set: The application will abort with a 403 status code and the exception's message.

    Additionally, the exception automatically logs an error message using the format Banhammer Exception: {message} via the Laravel Log facade.

    // Example of how the rendering logic behaves based on config
    // If config('ban.fallback_url') is 'https://example.com/banned'
    // The exception will trigger a redirect to that URL.
  8. Publish Banhammer configuration and migrations

    2.x

    To customize the package behavior or set up the necessary database tables, you can publish the configuration file and migrations using the Artisan command:

    php artisan vendor:publish --tag=config
    php artisan vendor:publish --tag=migrations
    • The configuration will be saved to config/ban.php.
    • The migrations will be saved to your database/migrations directory.
  9. Banning and managing IP addresses

    2.x

    Use the Mchev\Banhammer\IP class to manage IP-based bans.

    Basic Operations:

    use Mchev\Banhammer\IP;
    
    // Ban single IP
    IP::ban("8.8.8.8");
    
    // Ban multiple IPs
    IP::ban(["8.8.8.8", "4.4.4.4"]);
    
    // Ban with expiration
    IP::ban("8.8.8.8", [], now()->addMinutes(10));
    
    // Ban with metadata
    IP::ban("8.8.8.8", [
        'reason' => 'spam',
        'severity' => 'high'
    ]);
    
    // Unban single IP
    IP::unban("8.8.8.8");
    
    // Unban multiple IPs
    IP::unban(["8.8.8.8", "4.4.4.4"]);

    Checking and Listing IPs:

    // Check if IP is banned
    IP::isBanned("8.8.8.8"); // returns bool
    
    // Get all banned IPs
    $ips = IP::banned()->get(); // Collection
    $ips = IP::banned()->pluck('ip')->toArray(); // Array
    use Mchev\Banhammer\IP;
    
    IP::ban("8.8.8.8");
    IP::unban("8.8.8.8");
    IP::isBanned("8.8.8.8");
  10. Using Metadata (Metas) with bans

    2.x

    You can store and query additional data associated with a ban using the metas feature.

    Managing Meta on a Ban instance:

    $ban->setMeta('username', 'Jane');
    $ban->getMeta('username'); // 'Jane'
    $ban->hasMeta('username'); // true
    $ban->forgetMeta('username');

    Filtering by Meta:

    // Find bans with specific meta
    IP::banned()->whereMeta('username', 'Jane')->get();
    $user->bans()->whereMeta('reason', 'spam')->get();
    
    // Using model scopes
    User::whereBansMeta('username', 'Jane')->get();
    $ban->setMeta('reason', 'spam');
    $ban->getMeta('reason');
  11. Banning and unbanning models

    2.x

    Once a model uses the Bannable trait, you can perform the following operations:

    ActionCode
    Ban a user$user->ban()
    Ban with expiration$user->banUntil('2 days')
    Check if banned$user->isBanned()
    Check if not banned$user->isNotBanned()
    Unban$user->unban()

    Advanced Ban Options You can pass an array to ban() to include metadata, specific expiration dates, or the admin responsible for the ban:

    $user->ban([
        'comment' => "You've been evil",
        'ip' => "8.8.8.8",
        'expired_at' => Carbon::now()->addDays(7),
        'created_by_type' => 'App\Models\Admin',
        'created_by_id' => auth()->id(),
        'metas' => [
            'route' => request()->route()->getName(),
            'user_agent' => request()->header('user-agent')
        ]
    ]);

    Note: Without expired_at, the ban is permanent.

    $user->ban();
    $user->banUntil('2 days');
    $user->isBanned();
    $user->isNotBanned();
    $user->unban();
  12. Querying banned and active models

    2.x

    Use the provided query scopes to filter models based on their ban status.

    Scopes:

    • banned(): Returns models that are currently banned.
    • notBanned(): Returns models that are not banned.
    • banned(false): Alternative syntax for notBanned().

    Example:

    // Get banned users
    $bannedUsers = User::banned()->get();
    
    // Get non-banned users
    $activeUsers = User::notBanned()->get();

    Accessing Ban Records: You can access the relationship to the bans directly via the model:

    // All bans for a model
    $bans = $user->bans()->get();
    
    // Only expired bans
    $expired = $user->bans()->expired()->get();
    
    // Active bans
    $active = $user->bans()->notExpired()->get();
    $bannedUsers = User::banned()->get();
    $activeUsers = User::notBanned()->get();
    $bans = $user->bans()->get();