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
52 lines
1.2 KiB
PHP
52 lines
1.2 KiB
PHP
<?php
|
|
|
|
// SPDX-License-Identifier: EUPL-1.2
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Core\Mod\Agentic\Mod\Api\Services;
|
|
|
|
use Illuminate\Support\Str;
|
|
|
|
class WebhookSignature
|
|
{
|
|
public const DEFAULT_TOLERANCE = 300;
|
|
|
|
public function generateSecret(): string
|
|
{
|
|
return Str::random(64);
|
|
}
|
|
|
|
public function sign(string $payload, string $secret, int $timestamp): string
|
|
{
|
|
return hash_hmac('sha256', $timestamp.'.'.$payload, $secret);
|
|
}
|
|
|
|
public function verify(
|
|
string $payload,
|
|
string $signature,
|
|
string $secret,
|
|
int $timestamp,
|
|
int $tolerance = self::DEFAULT_TOLERANCE
|
|
): bool {
|
|
if (! $this->isTimestampValid($timestamp, $tolerance)) {
|
|
return false;
|
|
}
|
|
|
|
return hash_equals($this->sign($payload, $secret, $timestamp), $signature);
|
|
}
|
|
|
|
public function verifySignatureOnly(
|
|
string $payload,
|
|
string $signature,
|
|
string $secret,
|
|
int $timestamp
|
|
): bool {
|
|
return hash_equals($this->sign($payload, $secret, $timestamp), $signature);
|
|
}
|
|
|
|
public function isTimestampValid(int $timestamp, int $tolerance = self::DEFAULT_TOLERANCE): bool
|
|
{
|
|
return abs(time() - $timestamp) <= $tolerance;
|
|
}
|
|
}
|