Comprehensive account, IP, network, device, strike, restriction, appeal, and moderation enforcement tools for Laravel applications.

Maintainers

Package info

github.com/EloquentWorks/Exile

pkg:composer/eloquent-works/exile

Transparency log

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

dev-main 2026-07-13 04:21 UTC

This package is not auto-updated.

Last update: 2026-07-13 04:28:53 UTC


README

tests

Laravel Exile

Comprehensive moderation enforcement tools for Laravel applications.

Exile supports account, IP, CIDR network, and device bans; temporary and permanent enforcement; warnings and strike escalation; login, posting, read-only, and shadow restrictions; appeals, evidence, moderator tracking, audit history, events, notifications, middleware, and scheduled maintenance.

$user->ban(
    reason: 'Repeated harassment',
    expiresAt: now()->addDays(7),
    moderator: $moderator,
);

$user->strike('Spam', points: 3);

$user->restrict(RestrictionType::Posting, 'Posting cooldown');

Supported Versions

Package Version PHP Laravel / Illuminate
Current ^8.2 ^11.15 || ^12.0 || ^13.0

Composer will automatically resolve compatible Laravel / Illuminate versions based on your project.

Installation

composer require eloquent-works/exile
php artisan exile:install --migrate

Add Bannable to your user model:

<?php

namespace App\Models;

use EloquentWorks\Exile\Traits\Bannable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use Bannable;
}

Features

  • Account-only bans
  • IP-only bans
  • Combined account and IP bans
  • CIDR network bans with IPv4 and IPv6 support
  • Device fingerprint bans without storing raw fingerprints
  • Combined account, device, and IP bans
  • Temporary and permanent enforcement
  • Public reasons and private moderator notes
  • Configurable ban categories
  • Moderator issuance and revocation tracking
  • Warnings with severity and acknowledgement
  • Strike points with automatic escalation
  • Login, posting, read-only, and shadow restrictions
  • Ban appeals with approval, denial, and withdrawal
  • Evidence attachments with configurable storage
  • Automatic audit history
  • Middleware and custom 403 responses
  • Lifecycle events and optional notifications
  • Expiration processing and retention pruning commands
  • Configurable models and table names

Account bans

$ban = $user->ban(
    reason: 'Repeated harassment',
    expiresAt: now()->addDays(7),
    moderator: $moderator,
    category: 'harassment',
    internalNotes: 'Case EX-1042',
    metadata: ['case_number' => 'EX-1042'],
);

$user->isBanned();

IP, network, and device bans

use EloquentWorks\Exile\Facades\Exile;

Exile::banIp('203.0.113.10', reason: 'Automated abuse');

Exile::banNetwork('203.0.113.0/24', reason: 'Abusive network');

Exile::banDevice('browser-fingerprint', reason: 'Ban evasion');

Exile::banAccountAndIp(
    $user,
    request()->ip(),
    reason: 'Ban evasion',
);

Register device activity without storing the raw fingerprint:

$user->registerDeviceFingerprint(
    fingerprint: $request->header('X-Device-Fingerprint'),
    ipAddress: $request->ip(),
    label: 'Chrome on Windows',
);

Warnings and strikes

use EloquentWorks\Exile\Enums\WarningSeverity;

$user->warn(
    reason: 'Please review the community rules.',
    severity: WarningSeverity::High,
);

$user->strike(
    reason: 'Spam',
    points: 3,
    category: 'spam',
);

$user->activeStrikePoints();

Escalation thresholds are configured in config/exile.php. The defaults apply:

  • 3 points: one-day posting restriction
  • 5 points: seven-day read-only restriction
  • 10 points: thirty-day account ban

Restrictions

use EloquentWorks\Exile\Enums\RestrictionType;

$user->restrict(
    RestrictionType::Posting,
    reason: 'Posting cooldown',
    expiresAt: now()->addDay(),
);

$user->restrict(RestrictionType::ReadOnly);
$user->restrict(RestrictionType::Login);
$user->restrict(RestrictionType::Shadow);

$user->isRestricted(RestrictionType::Posting);
$user->isShadowBanned();

Middleware

Protect all access against account, IP, network, and device bans:

Route::middleware('exile')->group(function () {
    Route::get('/dashboard', DashboardController::class);
});

Protect specific actions:

Route::post('/posts', StorePostController::class)
    ->middleware('exile.allowed:posting');

Route::post('/login/complete', CompleteLoginController::class)
    ->middleware('exile.allowed:login');

Mark shadow-banned requests without rejecting them:

Route::post('/comments', StoreCommentController::class)
    ->middleware('exile.shadow');

$shadowed = request()->attributes->get('exile.shadowed', false);

Appeals

use EloquentWorks\Exile\Enums\AppealStatus;
use EloquentWorks\Exile\Facades\Exile;

$appeal = Exile::submitAppeal(
    $ban,
    $user,
    'I believe this enforcement was issued in error.',
);

Exile::resolveAppeal(
    $appeal,
    AppealStatus::Approved,
    $reviewer,
    'Appeal accepted.',
);

Approving an appeal revokes the related ban.

Evidence

Attach an existing stored file:

$evidence = Exile::attachEvidence(
    subject: $ban,
    disk: 'private',
    path: 'moderation/case-1042/report.pdf',
    originalName: 'report.pdf',
    uploadedBy: $moderator,
);

Or store an uploaded file through Exile:

$evidence = Exile::storeEvidence(
    $ban,
    $request->file('evidence'),
    $moderator,
);

Revocation

Exile::revokeBan($ban, $moderator);
Exile::revokeRestriction($restriction, $moderator);
Exile::revokeStrike($strike, $moderator);

Records remain available as moderation history until explicitly pruned.

Commands

php artisan exile:expire
php artisan exile:prune

Pruning is disabled by default. Enable it in configuration or run:

php artisan exile:prune --force --days=365

Notifications

Notifications are disabled by default. Enable them in config/exile.php:

'notifications' => [
    'enabled' => true,
    'channels' => ['mail'],
],

The affected model must support Laravel notifications. Database notifications also require Laravel's notifications table.

Events

  • BanIssued
  • BanRevoked
  • BanExpired
  • RestrictionIssued
  • RestrictionRevoked
  • StrikeIssued
  • WarningIssued
  • AppealSubmitted
  • AppealResolved

Testing

composer test
composer analyse
vendor/bin/pint --test

Documentation

Full docs are available in the docs directory:

Security

Keep EXILE_HASH_KEY private. Exile uses keyed HMAC hashes for IP and device matching. Human-readable IP addresses and CIDR ranges are encrypted at rest using Laravel's encryption system.

Do not use device fingerprints as a sole identity signal. Treat them as one moderation indicator alongside account history, IP context, and human review.

If you discover a security vulnerability, please report it privately instead of opening a public issue.

Credits

Built by Eloquent Works.

License

The MIT License.