Proxied ladl.link/{slug}/pay requests carry CSRF tokens from Mini HTML, which cannot bind to Link's session — the same 419 failure mode as event registration.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+3
-1
@@ -13,9 +13,11 @@ return Application::configure(basePath: dirname(__DIR__))
|
|||||||
health: '/up',
|
health: '/up',
|
||||||
)
|
)
|
||||||
->withMiddleware(function (Middleware $middleware): void {
|
->withMiddleware(function (Middleware $middleware): void {
|
||||||
// Public event registration POSTs land on ladl.link first; CSRF tokens from Events HTML do not match here.
|
// Public QR action POSTs land on ladl.link first; CSRF tokens from satellite HTML (Events/Mini)
|
||||||
|
// do not match Link's session — same failure mode as Laravel 419 Page Expired.
|
||||||
$middleware->validateCsrfTokens(except: [
|
$middleware->validateCsrfTokens(except: [
|
||||||
'*/register',
|
'*/register',
|
||||||
|
'*/pay',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$middleware->redirectGuestsTo(fn (Request $request) => route('sso.connect', [
|
$middleware->redirectGuestsTo(fn (Request $request) => route('sso.connect', [
|
||||||
|
|||||||
@@ -233,4 +233,46 @@ class LinkRedirectTest extends TestCase
|
|||||||
->assertOk()
|
->assertOk()
|
||||||
->assertJsonPath('badge_code', 'BADGE123');
|
->assertJsonPath('badge_code', 'BADGE123');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function test_mini_pay_post_does_not_require_link_app_csrf_token(): void
|
||||||
|
{
|
||||||
|
$user = $this->user();
|
||||||
|
ShortLink::create([
|
||||||
|
'user_id' => $user->id,
|
||||||
|
'slug' => 'shop-pay',
|
||||||
|
'source_app' => 'mini',
|
||||||
|
'source_kind' => 'qr',
|
||||||
|
'is_managed_here' => false,
|
||||||
|
'destination_url' => 'https://ladl.link/shop-pay',
|
||||||
|
'is_active' => true,
|
||||||
|
]);
|
||||||
|
|
||||||
|
Http::fake([
|
||||||
|
'https://ladill.com/q/shop-pay/pay' => Http::response(json_encode([
|
||||||
|
'checkout_url' => 'https://ladill.com/pay/momo/REF123',
|
||||||
|
'provider' => 'mtn_momo',
|
||||||
|
]), 200, ['Content-Type' => 'application/json']),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->postJson('https://ladl.link/shop-pay/pay', [
|
||||||
|
'amount' => 12.5,
|
||||||
|
'customer_phone' => '0241234567',
|
||||||
|
])
|
||||||
|
->assertOk()
|
||||||
|
->assertJsonPath('provider', 'mtn_momo')
|
||||||
|
->assertJsonPath('checkout_url', 'https://ladill.com/pay/momo/REF123');
|
||||||
|
|
||||||
|
Http::assertSent(function ($request) {
|
||||||
|
if ($request->url() !== 'https://ladill.com/q/shop-pay/pay') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$payload = json_decode($request->body(), true);
|
||||||
|
|
||||||
|
return is_array($payload)
|
||||||
|
&& (float) ($payload['amount'] ?? 0) === 12.5
|
||||||
|
&& ($payload['customer_phone'] ?? '') === '0241234567'
|
||||||
|
&& $request->hasHeader('X-Ladill-Internal', '1');
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user