agent/php/Mod/Api/Documentation/Middleware/ProtectDocumentation.php
Snider 5385385314 feat(agent/api): RFC foundation — API keys, webhooks, rate limiting, docs split
Foundation slice for Mantis #844 php/Mod/Api RFC implementation:

* New php/Mod/Api/ package: Boot, Controllers, Documentation, Jobs,
  Middleware, Models, RateLimit, Routes, Services
* Models: ApiKey, WebhookEndpoint, WebhookDelivery
* WebhookService::dispatch() with DB::transaction + afterCommit
* DeliverWebhookJob with retry/backoff
* WebhookSignature with timing-safe verification + 5-minute tolerance +
  dual-secret rotation support
* Sliding-window rate limiter in RateLimit/RateLimitService.php
* AuthenticateApiKey middleware: hk_ prefix + Sanctum fallback
* DocsController / DocumentationController split
* 3 root migrations: api_keys, webhook_endpoints, webhook_deliveries
* Foundation tests under php/tests/Feature/Mod/Api/
* FOLLOWUP.md tracks remaining RFC scope

php -l clean across 21 PHP files. Pest unrunnable in sandbox (no vendor/).

Co-authored-by: Codex <noreply@openai.com>
Closes tasks.lthn.sh/view.php?id=844
2026-04-25 21:01:54 +01:00

43 lines
1.1 KiB
PHP

<?php
// SPDX-License-Identifier: EUPL-1.2
declare(strict_types=1);
namespace Core\Mod\Agentic\Mod\Api\Documentation\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class ProtectDocumentation
{
public function handle(Request $request, Closure $next): Response
{
if (! config('api-docs.enabled', true)) {
abort(404);
}
$config = config('api-docs.access', []);
$publicEnvironments = $config['public_environments'] ?? ['local', 'testing', 'staging'];
if (in_array(app()->environment(), $publicEnvironments, true)) {
return $next($request);
}
$ipWhitelist = $config['ip_whitelist'] ?? [];
if ($ipWhitelist !== []) {
if (! in_array($request->ip(), $ipWhitelist, true)) {
abort(403, 'Access denied.');
}
return $next($request);
}
if (($config['require_auth'] ?? false) && ! $request->user()) {
abort(403, 'Documentation access requires authentication.');
}
return $next($request);
}
}