Files
filament-short-url/config/filament-short-url.php

502 lines
19 KiB
PHP

<?php
use App\Models\User;
use Bjanczak\FilamentShortUrl\Models\ShortUrl;
use Bjanczak\FilamentShortUrl\Models\ShortUrlVisit;
return [
/*
|--------------------------------------------------------------------------
| Route Prefix
|--------------------------------------------------------------------------
| The URL prefix for short URL redirects. Short URLs will be accessible at:
| /{prefix}/{key} e.g. /s/abc123
*/
'route_prefix' => env('SHORT_URL_PREFIX', 's'),
/*
|--------------------------------------------------------------------------
| Site Name Override
|--------------------------------------------------------------------------
| The brand or site name displayed on the password prompt, redirect warnings,
| and pixel loading screens. Falls back to config('app.name') if empty.
|
*/
'site_name' => env('SHORT_URL_SITE_NAME'),
/*
|--------------------------------------------------------------------------
| Default Redirect Status Code
|--------------------------------------------------------------------------
| Use 302 for better tracking accuracy. 301 redirects are cached by browsers,
| which means subsequent visits won't trigger the tracking logic.
*/
'redirect_status_code' => 302,
/*
|--------------------------------------------------------------------------
| Key Generation
|--------------------------------------------------------------------------
| Length of auto-generated URL keys (base62: a-z, A-Z, 0-9).
| 6 chars = 56 billion possible keys.
*/
'key_length' => 6,
/*
|--------------------------------------------------------------------------
| Lock URL Key
|--------------------------------------------------------------------------
| Globally disable changing the short key after a link is created.
|
*/
'lock_url_key' => env('SHORT_URL_LOCK_KEY', false),
/*
|--------------------------------------------------------------------------
| Disable Default Domain
|--------------------------------------------------------------------------
| Disable the default app domain for short links.
|
*/
'disable_default_domain' => env('SHORT_URL_DISABLE_DEFAULT_DOMAIN', false),
/*
|--------------------------------------------------------------------------
| Custom Domains
|--------------------------------------------------------------------------
| enforce_dns_on_activate: when true, activating a domain (or changing its
| hostname while active) requires a passing DNS check against app.url.
*/
'custom_domains' => [
'enforce_dns_on_activate' => env('SHORT_URL_CUSTOM_DOMAIN_ENFORCE_DNS', true),
],
/*
|--------------------------------------------------------------------------
| Geo-IP Settings
|--------------------------------------------------------------------------
| Country detection from visitor IP addresses.
| Uses ip-api.com (free, no key required, 45 req/min).
| Results are cached per IP for cache_ttl seconds.
*/
'geo_ip' => [
'enabled' => env('SHORT_URL_GEO_IP', true),
'cache_ttl' => 86400, // 24 hours
'driver' => env('SHORT_URL_GEO_IP_DRIVER', 'headers'), // 'headers', 'maxmind', 'ip-api'
'timeout' => 3, // seconds to wait for geo-ip response
'maxmind' => [
'database_path' => env('SHORT_URL_MAXMIND_DB', storage_path('geoip/GeoLite2-Country.mmdb')),
],
'stats_cache_ttl' => env('SHORT_URL_STATS_CACHE_TTL', 300), // 5 minutes caching for stats page calculations
],
/*
|--------------------------------------------------------------------------
| Default Tracking Configuration
|--------------------------------------------------------------------------
| These are the default tracking settings for newly created short URLs.
| Each can be overridden per-URL in the Filament admin panel.
*/
'tracking' => [
'enabled' => true,
'anonymize_ips' => env('SHORT_URL_ANONYMIZE_IPS', false),
'fields' => [
'ip_address' => true,
'browser' => true,
'browser_version' => true,
'operating_system' => true,
'operating_system_version' => true,
'referer_url' => true,
'device_type' => true,
'browser_language' => true,
],
],
/*
|--------------------------------------------------------------------------
| Google Analytics 4 — Measurement Protocol
|--------------------------------------------------------------------------
| When a GA Tracking ID is set on a short URL, server-side events are sent
| to GA4 via the Measurement Protocol API.
| Get your API Secret from: GA4 → Admin → Data Streams → Measurement Protocol API secrets
*/
'ga4' => [
'api_secret' => env('GA4_API_SECRET'),
'firebase_app_id' => env('FIREBASE_APP_ID'),
],
/*
|--------------------------------------------------------------------------
| Queue Connection
|--------------------------------------------------------------------------
| Visit tracking is dispatched to a queue for ultra-fast redirects.
| Default is `sync` (no background worker required). Switch to `database` or
| `redis` in Settings or via SHORT_URL_QUEUE when you run a queue worker.
*/
'queue_connection' => env('SHORT_URL_QUEUE', 'sync'),
/*
|--------------------------------------------------------------------------
| Queue Name
|--------------------------------------------------------------------------
| The queue name to which visit tracking and counter jobs are dispatched.
|
*/
'queue_name' => env('SHORT_URL_QUEUE_NAME', 'default'),
/*
|--------------------------------------------------------------------------
| Redis (Settings override when Queue Connection = redis)
|--------------------------------------------------------------------------
| Defaults from .env; overridden at runtime from Settings → General when
| queue_connection is redis. Used for queue driver, visit counters, stats,
| and live feed — independent of CACHE_STORE.
*/
'redis' => [
'host' => env('REDIS_HOST', '127.0.0.1'),
'port' => (int) env('REDIS_PORT', 6379),
'password' => env('REDIS_PASSWORD'),
'database' => (int) env('REDIS_DB', 0),
'prefix' => env('REDIS_PREFIX', ''),
],
/*
|--------------------------------------------------------------------------
| Redirect Cache TTL
|--------------------------------------------------------------------------
| Short URL records are cached so redirects never hit the database on hot
| paths. Cache is automatically invalidated when a URL is saved or deleted.
| Set to 0 to disable caching (useful for testing). Default: 3600 (1 hour).
*/
'cache_ttl' => (int) env('SHORT_URL_CACHE_TTL', 3600),
/*
|--------------------------------------------------------------------------
| Models
|--------------------------------------------------------------------------
| Override these to use your own custom model classes.
*/
'models' => [
'short_url' => ShortUrl::class,
'short_url_visit' => ShortUrlVisit::class,
],
/*
|--------------------------------------------------------------------------
| Default QR Code Options
|--------------------------------------------------------------------------
| Default design settings for newly generated QR codes.
*/
'qr_defaults' => [
'dot_style' => 'square',
'foreground_color' => '#000000',
'background_color' => '#ffffff',
'gradient_enabled' => false,
'gradient_from' => '#4f46e5',
'gradient_to' => '#06b6d4',
'gradient_type' => 'linear',
],
/*
|--------------------------------------------------------------------------
| Counter Buffering (Write-back Caching)
|--------------------------------------------------------------------------
| For high-traffic applications, direct database writes on every visit
| can cause locks. Enable this to buffer total/unique visit counts in
| cache, then sync them to the database periodically via a scheduled task.
*/
'counter_buffering' => [
'enabled' => (bool) env('SHORT_URL_COUNTER_BUFFERING', false),
'cache_key_prefix' => 'filament-short-url:buffer:',
],
/*
|--------------------------------------------------------------------------
| Trust CDN/Proxy Headers
|--------------------------------------------------------------------------
| If your application sits behind a CDN (like Cloudflare, AWS CloudFront)
| or a reverse proxy, set this to true to parse real visitor IP addresses
| and country codes from proxy headers. Only enable this if you are
| actually behind a proxy to prevent client IP spoofing!
|
*/
'trust_cdn_headers' => (bool) env('SHORT_URL_TRUST_CDN_HEADERS', false),
/*
|--------------------------------------------------------------------------
| Developer REST API
|--------------------------------------------------------------------------
| Enable programmatic access to short URLs via /api/short-url/* endpoints.
| API keys are managed in the Filament settings panel.
|
*/
'api_enabled' => env('SHORT_URL_API_ENABLED', false),
/*
|--------------------------------------------------------------------------
| VPN & Proxy Detection
|--------------------------------------------------------------------------
| Detect VPN, proxy, and Tor connections on incoming visits.
|
*/
'vpn_detection' => [
'enabled' => env('SHORT_URL_VPN_DETECTION', false),
'driver' => env('SHORT_URL_VPN_DRIVER', 'ip-api'),
'vpnapi_key' => env('SHORT_URL_VPNAPI_KEY'),
'block_action' => env('SHORT_URL_VPN_BLOCK_ACTION', 'flag_only'),
'cache_ttl' => 86400,
'timeout' => 2,
],
/*
|--------------------------------------------------------------------------
| Google Safe Browsing
|--------------------------------------------------------------------------
| Block phishing and malware URLs at creation time.
|
*/
'safe_browsing' => [
'enabled' => env('SHORT_URL_SAFE_BROWSING', false),
'api_key' => env('SHORT_URL_SAFE_BROWSING_KEY'),
'check_on_redirect' => env('SHORT_URL_SAFE_BROWSING_ON_REDIRECT', true),
'redirect_cache_ttl' => (int) env('SHORT_URL_SAFE_BROWSING_REDIRECT_CACHE_TTL', 3600),
],
/*
|--------------------------------------------------------------------------
| Click Deduplication
|--------------------------------------------------------------------------
| Ignore repeated clicks from the same IP within the configured window.
|
*/
'click_deduplication' => [
'enabled' => env('SHORT_URL_CLICK_DEDUP', false),
'hours' => (int) env('SHORT_URL_CLICK_DEDUP_HOURS', 1),
],
/*
|--------------------------------------------------------------------------
| Data Pruning & Aggregation
|--------------------------------------------------------------------------
| To keep the database clean and fast, raw visit logs can be aggregated
| into daily statistics and pruned after a retention period.
|
*/
'pruning' => [
'enabled' => env('SHORT_URL_PRUNING_ENABLED', true),
'retention_days' => env('SHORT_URL_PRUNING_DAYS', 90),
],
/*
|--------------------------------------------------------------------------
| Rate Limiting
|--------------------------------------------------------------------------
| Protect redirect routes from bot abuse and brute force by enabling
| rate limiting.
|
*/
'rate_limiting' => [
'enabled' => env('SHORT_URL_RATE_LIMITING', false),
'max_attempts' => env('SHORT_URL_RATE_LIMIT_MAX', 60),
'decay_seconds' => env('SHORT_URL_RATE_LIMIT_DECAY', 60),
],
/*
|--------------------------------------------------------------------------
| Enable Fallback Route
|--------------------------------------------------------------------------
| Register a fallback route to catch redirects for custom domains.
| Set to false if you wish to define custom domain routing manually.
*/
'enable_fallback_route' => env('SHORT_URL_ENABLE_FALLBACK', true),
/*
|--------------------------------------------------------------------------
| Redirect Route Middleware
|--------------------------------------------------------------------------
| Middleware applied to the main short URL redirect route (/s/{key}).
| Intentionally excludes the "web" group (sessions/cookies) for a lean
| hot path. Password routes always load "web" separately (/s-auth/{key}).
| Add "web" here only if your app requires session on every redirect.
|
*/
'middleware' => [
'throttle:120,1',
],
/*
|--------------------------------------------------------------------------
| Link ownership scoping
|--------------------------------------------------------------------------
| When true, authenticated Filament users only see links they created
| (short_urls.user_id). Disable for shared admin panels.
|
*/
'scope_links_to_user' => env('SHORT_URL_SCOPE_TO_USER', true),
/*
|--------------------------------------------------------------------------
| Max visits pessimistic locking
|--------------------------------------------------------------------------
| When remaining slots are above this threshold, use a lock-free UPDATE path.
| Near the cap, a row lock is used to stay exact under concurrent traffic.
*/
'max_visits_pessimistic_remaining' => (int) env('SHORT_URL_MAX_VISITS_PESSIMISTIC_REMAINING', 5),
/*
|--------------------------------------------------------------------------
| Live feed (SSE)
|--------------------------------------------------------------------------
*/
'live_feed' => [
'sse_interval_seconds' => (int) env('SHORT_URL_LIVE_FEED_SSE_INTERVAL', 3),
'sse_max_duration_seconds' => (int) env('SHORT_URL_LIVE_FEED_SSE_MAX_DURATION', 120),
// When the cache store is Redis, SSE blocks on pub/sub instead of sleep-polling.
'use_redis_push' => env('SHORT_URL_LIVE_FEED_REDIS_PUSH', true),
],
/*
|--------------------------------------------------------------------------
| Webhook signing
|--------------------------------------------------------------------------
| Require a signing secret before dispatching global webhooks.
|
*/
'webhook_signing_required' => env('SHORT_URL_WEBHOOK_SIGNING_REQUIRED', true),
/*
|--------------------------------------------------------------------------
| Deep Linking v2.1
|--------------------------------------------------------------------------
| Universal Links (iOS) and App Links (Android) configuration.
|
*/
'deep_linking' => [
'enabled' => env('SHORT_URL_DEEP_LINKING_ENABLED', false),
],
/*
|--------------------------------------------------------------------------
| User Integration Settings
|--------------------------------------------------------------------------
| Configure how the package interacts with the User model for showing avatars
| and user details (name, email) in the Filament admin panel.
|
*/
'user' => [
'model' => User::class,
'name_column' => 'name',
'email_column' => 'email',
'avatar_column' => 'avatar_url', // can be attribute/method on model or null to auto-detect HasAvatar
],
/*
|--------------------------------------------------------------------------
| Bot Detection
|--------------------------------------------------------------------------
| Patterns used to identify crawlers and link-preview bots. Specific tokens
| avoid false positives from real browsers (e.g. Chrome never matches "googlebot").
|
*/
'bot_detection' => [
'user_agent_contains' => [
'facebookexternalhit',
'meta-externalagent',
'meta-externalfetcher',
'meta-externalads',
'meta-webindexer',
'Googlebot',
'Google-InspectionTool',
'GoogleOther',
'Storebot-Google',
'bingbot',
'BingPreview',
'DuckDuckBot',
'Slurp',
'Baiduspider',
'YandexBot',
'Applebot',
'Applebot-Extended',
'Twitterbot',
'LinkedInBot',
'linkedinbot',
'Slackbot',
'Slack-ImgProxy',
'Discordbot',
'TelegramBot',
'WhatsApp',
'Pinterestbot',
'Embedly',
'Iframely',
'SkypeUriPreview',
'facebookcatalog',
'MetaInspector',
'vkShare',
'Tumblr',
'redditbot',
'Snap URL Preview',
'Snapchat',
'ChatGPT-User',
'Claude-Web',
'anthropic-ai',
'PerplexityBot',
'Bytespider',
'GPTBot',
'OAI-SearchBot',
'HeadlessChrome',
'Go-http-client',
'python-requests',
'axios/',
'GuzzleHttp',
'PostmanRuntime',
'Insomnia',
'Scrapy',
'FeedBurner',
'W3C_Validator',
'Validator.nu',
'PocketParser',
'BitlyBot',
'rogerbot',
'SemrushBot',
'AhrefsBot',
'MJ12bot',
'DotBot',
'PetalBot',
'Sogou',
'ia_archiver',
'archive.org_bot',
'Wayback',
'UptimeRobot',
'StatusCake',
'Pingdom',
'GTmetrix',
'Bluesky',
'thirdLandingPageFeInfra',
'ShortLinkTranslate',
],
'user_agent_regex' => [
'/bot[\s\/;\)]/i',
'/crawler[\s\/;\)]/i',
'/spider[\s\/;\)]/i',
'/\bscraper\b/i',
'/\bslurp\b/i',
'/\bpreview\b/i',
'/^curl\//i',
'/^wget\//i',
'/\bPHP\/[\d.]+/i',
],
'referer_contains' => [
'url.emailprotection.link',
'urlsand.com',
'statics.teams.cdn.office.net',
'security-za.m.mimecastprotect.com',
'deref-mail.com',
'deref-gmx.com',
],
'verify_google_bot_ip' => env('SHORT_URL_VERIFY_GOOGLEBOT_IP', false),
'debug_secret' => env('SHORT_URL_BOT_DEBUG_SECRET'),
],
];