From 59c59d049a13c14e009c01206e05b9a10d848e38 Mon Sep 17 00:00:00 2001 From: DariusIII Date: Mon, 8 Jan 2024 18:59:30 +0100 Subject: [PATCH] Update packages and btcpayment support --- app/Http/Controllers/BtcPaymentController.php | 32 +++++- app/Models/Payment.php | 13 +++ composer.lock | 99 ++++++++++--------- ...024_01_06_173518_create_payments_table.php | 38 +++++++ routes/web.php | 35 +------ 5 files changed, 131 insertions(+), 86 deletions(-) create mode 100644 app/Models/Payment.php create mode 100644 database/migrations/2024_01_06_173518_create_payments_table.php diff --git a/app/Http/Controllers/BtcPaymentController.php b/app/Http/Controllers/BtcPaymentController.php index 57127991f..b816a1263 100644 --- a/app/Http/Controllers/BtcPaymentController.php +++ b/app/Http/Controllers/BtcPaymentController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers; +use App\Models\Payment; use App\Models\User; use Blacklight\libraries\Geary; use Illuminate\Http\Request; @@ -87,6 +88,9 @@ class BtcPaymentController extends BasePageController } } + /** + * BtcPay callback. + */ public function btcPayCallback(Request $request): Response { $hashCheck = 'sha256='.hash_hmac('sha256', $request->getContent(), config('nntmux.btcpay_webhook_secret')); @@ -110,9 +114,31 @@ class BtcPaymentController extends BasePageController } $user = User::query()->where('email', '=', $payload['metadata']['buyerEmail'])->first(); if ($user) { - User::updateUserRole($user->id, $matches['role']); - User::updateUserRoleChangeDate($user->id, null, $matches['addYears']); - Log::info('User upgraded to '.$matches['role'].' for BTCPay webhook: '.$payload['metadata']['buyerEmail']); + $checkOrder = Payment::query()->where('invoice_id', '=', $payload['invoiceId'])->where('payment_status', '=', 'Settled')->first(); + if (! empty($checkOrder)) { + Log::error('Duplicate BTCPay webhook: '.$payload['webhookId']); + + return response('Not Found', 404); + } else { + Payment::create([ + 'email' => $payload['metadata']['buyerEmail'], + 'username' => $user->username, + 'item_description' => $payload['metadata']['itemDesc'], + 'order_id' => $payload['metadata']['orderId'], + 'payment_id' => $payload['payment']['id'], + 'payment_status' => $payload['payment']['status'], + 'invoice_amount' => $payload['metadata']['invoice_amount'], + 'payment_method' => $payload['paymentMethod'], + 'payment_value' => $payload['payment']['value'], + 'webhook_id' => $payload['webhookId'], + 'invoice_id' => $payload['invoiceId'], + ]); + User::updateUserRole($user->id, $matches['role']); + User::updateUserRoleChangeDate($user->id, null, $matches['addYears']); + Log::info('User: '.$user->username.' upgraded to '.$matches['role'].' for BTCPay webhook: '.$payload['metadata']['buyerEmail']); + + return response('OK', 200); + } } else { Log::error('User not found for BTCPay webhook: '.$payload['metadata']['buyerEmail']); diff --git a/app/Models/Payment.php b/app/Models/Payment.php new file mode 100644 index 000000000..0e1589c5a --- /dev/null +++ b/app/Models/Payment.php @@ -0,0 +1,13 @@ +id(); + $table->timestamps(); + $table->string('email'); + $table->string('username'); + $table->string('item_description'); + $table->string('order_id'); + $table->string('payment_id'); + $table->string('payment_status'); + $table->string('invoice_amount'); + $table->string('payment_method'); + $table->string('payment_value'); + $table->string('webhook_id'); + $table->string('invoice_id'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('payments'); + } +}; diff --git a/routes/web.php b/routes/web.php index 336f7c02e..2c53e5f44 100644 --- a/routes/web.php +++ b/routes/web.php @@ -376,37 +376,4 @@ Route::post('2faVerify', function () { return redirect()->to(URL()->previous()); })->name('2faVerify')->middleware('2fa'); -Route::post('btcpay/webhook', function (Illuminate\Http\Request $request) { - $hashCheck = 'sha256='.hash_hmac('sha256', $request->getContent(), config('nntmux.btcpay_webhook_secret')); - if ($hashCheck !== $request->header('btcpay-sig')) { - Log::error('BTCPay webhook hash check failed: '.$request->header('btcpay-sig')); - - return response('Not Found', 404); - } - $payload = json_decode($request->getContent(), true); - // We have received a payment for an invoice and user should be upgraded to a paid plan based on order - if ($payload['type'] === 'InvoicePaymentSettled') { - preg_match('/(?P\w+(\s\+\+)?)[\s](?P\d+)/i', $payload['metadata']['itemDesc'], $matches); - if (empty($matches)) { - Log::error('Could not parse BTCPay webhook: '.$payload['metadata']['itemDesc']); - preg_match('/(?P\w+(\s\+\+)?)[\s](?P\d+)/i', $payload['metadata']['itemCode'], $matches); - if (empty($matches)) { - Log::error('Could not parse BTCPay webhook: '.$payload['metadata']['itemDesc']); - - return response('Not Found', 404); - } - } - $user = User::query()->where('email', '=', $payload['metadata']['buyerEmail'])->first(); - if ($user) { - User::updateUserRole($user->id, $matches['role']); - User::updateUserRoleChangeDate($user->id, null, $matches['addYears']); - Log::info('User upgraded to '.$matches['role'].' for BTCPay webhook: '.$payload['metadata']['buyerEmail']); - } else { - Log::error('User not found for BTCPay webhook: '.$payload['metadata']['buyerEmail']); - - return response('Not Found', 404); - } - } - - return response('OK', 200); -}); +Route::post('btcpay/webhook', [BtcPaymentController::class, 'btcPayCallback'])->name('btcpay.webhook');