Files
WebHookInspector/app/Actions/ConfigureWebhookEndpointAction.php
2026-08-04 17:09:39 +02:00

82 lines
2.5 KiB
PHP

<?php
namespace App\Actions;
use App\Models\User;
use App\Models\WebhookEndpoint;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;
class ConfigureWebhookEndpointAction
{
/**
* @param array<string, string|array<int, string>> $headers
*/
public function handle(
?User $user,
WebhookEndpoint $endpoint,
int $status,
array $headers,
string $body,
): WebhookEndpoint {
Gate::forUser($user)->authorize('update', $endpoint);
$maxResponseBodyBytes = (int) config('webhooks.max_response_body_bytes', 1024 * 1024);
if (strlen($body) > $maxResponseBodyBytes) {
throw ValidationException::withMessages([
'response_body' => "The response body may not exceed {$maxResponseBodyBytes} bytes.",
]);
}
Validator::make([
'status' => $status,
'body' => $body,
], [
'status' => ['integer', 'between:100,599'],
'body' => ['string'],
])->validate();
$this->validateHeaders($headers);
$endpoint->forceFill([
'response_status' => $status,
'response_headers' => $headers,
'response_body' => $body,
])->save();
return $endpoint->refresh();
}
/**
* @param array<string, string|array<int, string>> $headers
*/
private function validateHeaders(array $headers): void
{
if (count($headers) > 50) {
throw ValidationException::withMessages([
'response_headers' => 'A maximum of 50 response headers is allowed.',
]);
}
foreach ($headers as $name => $value) {
if (! is_string($name) || preg_match("/^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/", $name) !== 1) {
throw ValidationException::withMessages([
'response_headers' => 'Every response header name must be a valid HTTP header name.',
]);
}
$values = is_array($value) ? $value : [$value];
foreach ($values as $headerValue) {
if (! is_string($headerValue) || preg_match('/[\r\n]/', $headerValue) === 1 || strlen($headerValue) > 8192) {
throw ValidationException::withMessages([
'response_headers' => 'Response headers must not contain line breaks and may not exceed 8 KiB.',
]);
}
}
}
}
}