82 lines
2.5 KiB
PHP
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.',
|
|
]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|