Fix some for sign body to montify and not get 401 error|

This commit is contained in:
mahmood
2026-07-27 01:36:02 +03:30
parent 815da9896d
commit 933424ddfc
8 changed files with 381 additions and 36 deletions
@@ -5,6 +5,8 @@ namespace App\Http\Controllers\pay;
use App\Http\Controllers\Controller;
use App\Models\Withdraw;
use App\Services\ConfigService;
use App\Services\Payment\Contracts\SupportsStatusQuery;
use App\Services\Payment\WalletDepositCreditor;
use App\Services\Payment\WalletPaymentManager;
use Illuminate\Http\Request;
use InvalidArgumentException;
@@ -20,6 +22,7 @@ class WalletPaymentController extends Controller
public function __construct(
private WalletPaymentManager $payments,
private ConfigService $config,
private WalletDepositCreditor $creditor,
) {
}
@@ -105,25 +108,17 @@ class WalletPaymentController extends Controller
throw new UnprocessableEntityHttpException('پرداخت آنلاین فعال نیست');
}
// همه پارامترهای برگشت عیناً وارد امضا می‌شوند؛ whitelist کردن باعث
// مغایرت امضا می‌شود اگر پارتنر پارامتر اضافه‌ای بفرستد.
$payload = [];
foreach ([
'status',
'reference_id',
'session_id',
'amount',
'track_number',
'timestamp',
'signature',
] as $key) {
if (!$request->has($key)) {
foreach ($request->all() as $key => $value) {
if (!is_string($key) || $key === '' || is_array($value) || $value === null) {
continue;
}
$value = $request->input($key);
if ($value === null || is_array($value)) {
continue;
if (count($payload) >= 30) {
break;
}
// track_number خالی هم ممکن است در امضا باشد
$payload[$key] = (string) $value;
$payload[$key] = is_bool($value) ? ($value ? 'true' : 'false') : (string) $value;
}
if (($payload['signature'] ?? '') === '' || ($payload['reference_id'] ?? '') === '') {
@@ -136,6 +131,12 @@ class WalletPaymentController extends Controller
$result = $gateway->handleReturnPayload($payload);
if (!($result['ok'] ?? false)) {
// redirect مرورگر قابل اعتماد نیست؛ منبع حقیقت، استعلام مستقیم از درگاه است.
$fallback = $this->statusFallback((string) $payload['reference_id']);
if ($fallback) {
return $fallback;
}
return response()->json([
'ok' => false,
'message' => $result['message'] ?? 'خطا در تأیید پرداخت',
@@ -148,18 +149,77 @@ class WalletPaymentController extends Controller
return response()->json(['ok' => false, 'message' => 'سفارش یافت نشد'], 404);
}
$customerId = (int) auth('customer')->id();
if ((int) $withdraw->customer_id !== $customerId) {
if (!$this->ownsWithdraw($withdraw)) {
return response()->json(['ok' => false, 'message' => 'دسترسی غیرمجاز'], 403);
}
$sts = (int) $withdraw->sts;
$paid = $sts === 2;
$paid = (int) $withdraw->sts === 2;
return $this->paymentStateResponse(
$withdraw,
$paid ? 'success' : ((string) ($payload['status'] ?? '') === 'success' ? 'pending' : 'failed')
);
}
/**
* استعلام وضعیت یک پرداخت از درگاه — برای polling فرانت وقتی نتیجه هنوز قطعی نیست.
*/
public function status(Request $request)
{
$referenceId = trim((string) $request->input('reference_id', ''));
if ($referenceId === '') {
return response()->json(['ok' => false, 'message' => 'شناسه پرداخت ارسال نشده'], 422);
}
$response = $this->statusFallback($referenceId);
if ($response) {
return $response;
}
return response()->json(['ok' => false, 'message' => 'سفارش یافت نشد'], 404);
}
/**
* استعلام مستقیم وضعیت از درگاه با بررسی مالکیت سفارش.
*/
private function statusFallback(string $referenceId): ?\Illuminate\Http\JsonResponse
{
$withdraw = $this->creditor->findByReference($referenceId);
if (!$withdraw || !$this->ownsWithdraw($withdraw)) {
return null;
}
if ((int) $withdraw->sts !== 2) {
$gateway = $this->payments->resolve();
if ($gateway instanceof SupportsStatusQuery) {
$gateway->syncStatusByReference($referenceId);
$withdraw = $withdraw->fresh() ?: $withdraw;
}
}
$sts = (int) $withdraw->sts;
return $this->paymentStateResponse(
$withdraw,
match ($sts) {
2 => 'success',
3 => 'failed',
default => 'pending',
}
);
}
private function ownsWithdraw(Withdraw $withdraw): bool
{
return (int) $withdraw->customer_id === (int) auth('customer')->id();
}
private function paymentStateResponse(Withdraw $withdraw, string $status): \Illuminate\Http\JsonResponse
{
return response()->json([
'ok' => true,
'paid' => $paid,
'status' => $paid ? 'success' : ((string) ($payload['status'] ?? '') === 'success' ? 'pending' : 'failed'),
'paid' => (int) $withdraw->sts === 2,
'status' => $status,
'amount' => (int) $withdraw->cash,
'reference_id' => 'WD-' . $withdraw->id,
'withdraw_id' => $withdraw->id,