Exempt Mini Pay POSTs from Link CSRF checks.
Deploy Ladill Link / deploy (push) Successful in 1m4s

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:
isaacclad
2026-07-13 23:11:59 +00:00
co-authored by Cursor
parent fe268e7bfa
commit 520284d766
2 changed files with 45 additions and 1 deletions
+3 -1
View File
@@ -13,9 +13,11 @@ return Application::configure(basePath: dirname(__DIR__))
health: '/up',
)
->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: [
'*/register',
'*/pay',
]);
$middleware->redirectGuestsTo(fn (Request $request) => route('sso.connect', [
+42
View File
@@ -233,4 +233,46 @@ class LinkRedirectTest extends TestCase
->assertOk()
->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');
});
}
}