Fixed: basePath self→static binding, namespace detection, event wiring,
SQLite cache, file cache driver. All Mod Boot classes converted to
$listens pattern for lifecycle event discovery.
Working endpoints:
- /v1/explorer/info — live chain height, difficulty, aliases
- /v1/explorer/stats — formatted chain statistics
- /v1/names/directory — alias directory grouped by type
- /v1/names/available/{name} — name availability check
- /v1/names/lookup/{name} — name details
Co-Authored-By: Charon <charon@lethean.io>
3.2 KiB
3.2 KiB
Bouncer
Early-exit security middleware + whitelist-based action authorisation gate.
What It Does
Two subsystems in one:
- Bouncer (top-level): IP blocklist + SEO redirects, runs before all other middleware
- Gate (subdirectory): Whitelist-based controller action authorisation with training mode
Bouncer (IP Blocking + Redirects)
Key Classes
| Class | Purpose |
|---|---|
Boot |
ServiceProvider registering BlocklistService, RedirectService, and migrations |
BouncerMiddleware |
Early-exit middleware: sets trusted proxies, checks blocklist (O(1) via cached set), handles SEO redirects, then passes through |
BlocklistService |
IP blocking with Redis-cached lookup. Statuses: pending (honeypot, needs review), approved (active block), rejected (reviewed, not blocked). Methods: isBlocked(), block(), unblock(), syncFromHoneypot(), approve(), reject(), getPending(), getStats() |
RedirectService |
Cached SEO redirects from seo_redirects table. Supports exact match and wildcard (path/*). Methods: match(), add(), remove() |
Hidden Ideas
- Blocked IPs get
418 I'm a teapotwithX-Powered-By: Earl Grey - Honeypot monitors paths from
robots.txtdisallow list; critical paths (/admin,/.env,/wp-admin) trigger auto-block - Rate-limited honeypot logging prevents DoS via log flooding
TRUSTED_PROXIESenv var: comma-separated IPs or*(trust all)
Gate (Action Whitelist)
Philosophy: "If it wasn't trained, it doesn't exist."
Key Classes
| Class | Purpose |
|---|---|
Gate\Boot |
ServiceProvider registering middleware, migrations, route macros, and training routes |
ActionGateService |
Resolves action name from route (3-level priority), checks against ActionPermission table, logs to ActionRequest. Methods: check(), allow(), deny(), resolveAction() |
ActionGateMiddleware |
Enforces gate: allowed = pass, denied = 403, training = approval prompt (JSON for API, redirect for web) |
Action (attribute) |
#[Action('product.create', scope: 'product')] on controller methods |
ActionPermission (model) |
Whitelist record: action + guard + role + scope. Methods: isAllowed(), train(), revoke(), allowedFor() |
ActionRequest (model) |
Audit log of all permission checks. Methods: log(), pending(), deniedActionsSummary(), prune() |
RouteActionMacro |
Adds ->action('name'), ->bypassGate(), ->requiresTraining() to Route |
Action Resolution Priority
- Route action:
Route::post(...)->action('product.create') - Controller attribute:
#[Action('product.create')] - Auto-resolved:
ProductController@storebecomesproduct.store
Training Mode
When core.bouncer.training_mode = true, unknown actions prompt for approval instead of blocking. Training routes at /_bouncer/approve and /_bouncer/pending.
Integration
- BouncerMiddleware runs FIRST in the stack (replaces Laravel TrustProxies)
- ActionGateMiddleware appends to
web,admin,api,clientgroups - Config:
core.bouncer.enabled,core.bouncer.training_mode,core.bouncer.guarded_middleware - DB tables:
blocked_ips,seo_redirects,honeypot_hits,core_action_permissions,core_action_requests