new funcionality

This commit is contained in:
2026-07-27 17:20:02 +02:00
parent c2b5291a74
commit c5ce8a7a36
101 changed files with 6889 additions and 176 deletions

View File

@@ -0,0 +1,89 @@
<?php
namespace App\Jobs;
use App\Models\WebhookDelivery;
use App\Support\WebhookEndpoints;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Str;
class SendWebhookJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public int $tries = 3;
/**
* Backoff creciente entre reintentos (segundos) — le da tiempo al
* endpoint del cliente a recuperarse si está caído momentáneamente.
*/
public array $backoff = [10, 60, 300];
public function __construct(public WebhookDelivery $delivery)
{
}
public function handle(): void
{
$endpoint = $this->delivery->endpoint;
// El endpoint pudo haberse borrado o desactivado entre que se
// encoló el job y que se procesó — no tiene sentido reintentar.
if (! $endpoint || ! $endpoint->active) {
return;
}
// Re-chequeo anti-SSRF: la URL ya se validó al crear/editar el
// webhook, pero un dominio público en ese momento puede resolver a
// una IP interna más tarde (DNS rebinding). No reintentamos esto —
// si sigue sin ser seguro en el próximo intento, va a fallar igual.
if (! WebhookEndpoints::isSafeUrl($endpoint->url)) {
$this->delivery->update([
'response_body' => 'Bloqueado: la URL resuelve a una dirección privada/reservada.',
]);
return;
}
$body = json_encode([
'event' => $this->delivery->event,
'data' => $this->delivery->payload,
]);
$signature = hash_hmac('sha256', $body, $endpoint->secret);
$this->delivery->increment('attempts');
try {
$response = Http::timeout(5)
->withHeaders([
'Content-Type' => 'application/json',
'X-Webhook-Event' => $this->delivery->event,
'X-Webhook-Signature' => 'sha256='.$signature,
])
->withBody($body, 'application/json')
->post($endpoint->url);
$this->delivery->update([
'response_status' => $response->status(),
'response_body' => Str::limit($response->body(), 1000),
'delivered_at' => $response->successful() ? now() : null,
]);
if (! $response->successful()) {
throw new \RuntimeException("El endpoint del webhook respondió {$response->status()}.");
}
} catch (\Throwable $e) {
$this->delivery->update([
'response_body' => Str::limit($e->getMessage(), 1000),
]);
throw $e;
}
}
}