feat(payments): implement standard webhooks validation system

Add comprehensive webhook validation and processing system with Polar.sh integration:

  - Create built-in Standard Webhooks package following official specification
  - Implement HMAC-SHA256 signature validation with base64 encoding
  - Add webhook factory for multi-provider support (Polar, Stripe, generic)
  - Replace custom Polar webhook validation with Standard Webhooks implementation
  - Add proper exception handling with custom WebhookVerificationException
  - Support sandbox mode bypass for development environments
  - Update Polar provider to use database-driven configuration
  - Enhance webhook test suite with proper Standard Webhooks format
  - Add PaymentProvider model HasFactory trait for testing
  - Implement timestamp tolerance checking (±5 minutes) for replay protection
  - Support multiple signature versions and proper header validation

  This provides a secure, reusable webhook validation system that can be extended
  to other payment providers while maintaining full compliance with Standard
  Webhooks specification.

  BREAKING CHANGE: Polar webhook validation now uses Standard Webhooks format
  with headers 'webhook-id', 'webhook-timestamp', 'webhook-signature' instead of
  previous Polar-specific headers.
This commit is contained in:
idevakk
2025-12-06 22:49:54 -08:00
parent 15e018eb88
commit 289baa1286
13 changed files with 1955 additions and 66 deletions

View File

@@ -2,10 +2,13 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class PaymentProvider extends Model
{
use HasFactory;
protected $fillable = [
'name',
'display_name',

View File

@@ -3,11 +3,14 @@
namespace App\Models;
use App\Services\Payments\PaymentOrchestrator;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Log;
class Subscription extends Model
{
use HasFactory;
protected $fillable = [
'user_id',
'type',
@@ -49,6 +52,16 @@ class Subscription extends Model
'order_created_at',
'order_paid_at',
'provider_checkout_id',
'resume_reason',
'trial_ended_at',
'trial_converted_to',
'subscription_id_fetched_at',
'polar_dates',
'customer_state_changed_at',
'polar_subscription_data',
'customer_metadata',
'trial_will_end_sent_at',
'pause_reason',
];
protected $casts = [