Harden credit flows and add RevenueCat webhook
This commit is contained in:
69
app/Http/Controllers/RevenueCatWebhookController.php
Normal file
69
app/Http/Controllers/RevenueCatWebhookController.php
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Jobs\ProcessRevenueCatWebhook;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class RevenueCatWebhookController extends Controller
|
||||
{
|
||||
public function handle(Request $request): JsonResponse
|
||||
{
|
||||
$secret = (string) config('services.revenuecat.webhook', '');
|
||||
|
||||
if ($secret === '') {
|
||||
Log::error('RevenueCat webhook secret not configured');
|
||||
return response()->json(['error' => 'Webhook not configured'], 500);
|
||||
}
|
||||
|
||||
$signature = trim((string) $request->header('X-Signature', ''));
|
||||
if ($signature === '') {
|
||||
return response()->json(['error' => 'Signature missing'], 400);
|
||||
}
|
||||
|
||||
$payload = $request->getContent();
|
||||
if (! $this->signatureMatches($payload, $signature, $secret)) {
|
||||
return response()->json(['error' => 'Invalid signature'], 400);
|
||||
}
|
||||
|
||||
$decoded = json_decode($payload, true);
|
||||
if (json_last_error() !== JSON_ERROR_NONE || ! is_array($decoded)) {
|
||||
Log::warning('RevenueCat webhook received invalid JSON', [
|
||||
'error' => json_last_error_msg(),
|
||||
]);
|
||||
return response()->json(['error' => 'Invalid payload'], 400);
|
||||
}
|
||||
|
||||
ProcessRevenueCatWebhook::dispatch(
|
||||
$decoded,
|
||||
(string) $request->header('X-Event-Id', '')
|
||||
);
|
||||
|
||||
return response()->json(['status' => 'accepted'], 202);
|
||||
}
|
||||
|
||||
private function signatureMatches(string $payload, string $providedSignature, string $secret): bool
|
||||
{
|
||||
$normalized = preg_replace('/\s+/', '', $providedSignature);
|
||||
if (! is_string($normalized)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$candidates = [
|
||||
base64_encode(hash_hmac('sha1', $payload, $secret, true)),
|
||||
base64_encode(hash_hmac('sha256', $payload, $secret, true)),
|
||||
hash_hmac('sha1', $payload, $secret),
|
||||
hash_hmac('sha256', $payload, $secret),
|
||||
];
|
||||
|
||||
foreach ($candidates as $expected) {
|
||||
if (hash_equals($expected, $normalized)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user