Fix ladl.link CORS for Mini payment assets and pay URL.
Deploy Ladill Mini / deploy (push) Successful in 44s
Deploy Ladill Mini / deploy (push) Successful in 44s
Allow cross-origin module loads of Mini build assets and use a same-origin pay path when HTML is proxied through ladl.link so fetch and Vite JS work.
This commit is contained in:
@@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Public Mini payment pages are HTML-proxied through ladl.link while Vite assets
|
||||||
|
* and Mini pay endpoints live on mini.ladill.com. Browsers require CORS for those
|
||||||
|
* cross-origin module scripts and JSON pay posts.
|
||||||
|
*/
|
||||||
|
return [
|
||||||
|
|
||||||
|
'paths' => [
|
||||||
|
'q/*',
|
||||||
|
'build/*',
|
||||||
|
'images/*',
|
||||||
|
'sanctum/csrf-cookie',
|
||||||
|
],
|
||||||
|
|
||||||
|
'allowed_methods' => ['*'],
|
||||||
|
|
||||||
|
'allowed_origins' => array_values(array_filter([
|
||||||
|
'https://ladl.link',
|
||||||
|
'https://www.ladl.link',
|
||||||
|
'https://mini.ladill.com',
|
||||||
|
env('APP_URL') ? rtrim((string) env('APP_URL'), '/') : null,
|
||||||
|
])),
|
||||||
|
|
||||||
|
'allowed_origins_patterns' => [
|
||||||
|
// Public short-link host and optional subdomains.
|
||||||
|
'#^https://([a-z0-9-]+\.)?ladl\.link$#i',
|
||||||
|
// Platform family (custom / satellite hosts that may proxy Mini HTML).
|
||||||
|
'#^https://([a-z0-9-]+\.)?ladill\.com$#i',
|
||||||
|
],
|
||||||
|
|
||||||
|
'allowed_headers' => ['*'],
|
||||||
|
|
||||||
|
'exposed_headers' => [],
|
||||||
|
|
||||||
|
'max_age' => 60 * 60,
|
||||||
|
|
||||||
|
'supports_credentials' => false,
|
||||||
|
|
||||||
|
];
|
||||||
@@ -2,9 +2,13 @@
|
|||||||
$content = $qrCode->content();
|
$content = $qrCode->content();
|
||||||
$businessName = $content['business_name'] ?? $qrCode->label;
|
$businessName = $content['business_name'] ?? $qrCode->label;
|
||||||
$currency = $content['currency'] ?? 'GHS';
|
$currency = $content['currency'] ?? 'GHS';
|
||||||
// Same-origin pay endpoint — ladl.link publicPath is cross-origin from
|
// Public scans stay on ladl.link/{code} (HTML proxied to Mini). Prefer a
|
||||||
// mini.ladill.com and has no CORS headers, so fetch() never reaches showSheet.
|
// same-origin pay path so fetch() does not cross to mini.ladill.com.
|
||||||
$payUrl = url('/q/'.$qrCode->short_code.'/pay');
|
// Direct visits on mini.ladill.com keep the local /q/{code}/pay route.
|
||||||
|
$isProxiedPublicScan = request()->headers->get('X-Ladill-Internal') === '1';
|
||||||
|
$payUrl = $isProxiedPublicScan
|
||||||
|
? '/'.$qrCode->short_code.'/pay'
|
||||||
|
: url('/q/'.$qrCode->short_code.'/pay');
|
||||||
$csrf = csrf_token();
|
$csrf = csrf_token();
|
||||||
@endphp
|
@endphp
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
|
|||||||
@@ -46,8 +46,9 @@ class MiniPaymentCheckoutTest extends TestCase
|
|||||||
->assertSee('data-ladill-pay-sheet', false)
|
->assertSee('data-ladill-pay-sheet', false)
|
||||||
->assertSee('data-ladill-pay-panel', false)
|
->assertSee('data-ladill-pay-panel', false)
|
||||||
->assertSee('resumeTransaction', false)
|
->assertSee('resumeTransaction', false)
|
||||||
->assertSee('/q/'.$qr->short_code.'/pay', false)
|
// Proxied ladl.link scans use same-origin /{code}/pay (not mini absolute /q/...).
|
||||||
->assertDontSee('https://ladl.link/'.$qr->short_code.'/pay', false)
|
->assertSee('/'.$qr->short_code.'/pay', false)
|
||||||
|
->assertDontSee('https://mini.ladill.com/q/'.$qr->short_code.'/pay', false)
|
||||||
->assertDontSee('MTN MoMo number', false)
|
->assertDontSee('MTN MoMo number', false)
|
||||||
->assertDontSee('Pay with MTN MoMo', false)
|
->assertDontSee('Pay with MTN MoMo', false)
|
||||||
->assertDontSee('Continue to Paystack', false)
|
->assertDontSee('Continue to Paystack', false)
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Feature;
|
||||||
|
|
||||||
|
use App\Models\QrCode;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
class MiniPaymentCorsTest extends TestCase
|
||||||
|
{
|
||||||
|
use RefreshDatabase;
|
||||||
|
|
||||||
|
public function test_proxied_payment_landing_uses_same_origin_pay_path(): void
|
||||||
|
{
|
||||||
|
$user = User::create([
|
||||||
|
'public_id' => (string) Str::uuid(),
|
||||||
|
'name' => 'Vendor',
|
||||||
|
'email' => 'vendor-cors@example.com',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$qr = QrCode::query()->create([
|
||||||
|
'user_id' => $user->id,
|
||||||
|
'short_code' => 'paycors01',
|
||||||
|
'type' => QrCode::TYPE_PAYMENT,
|
||||||
|
'label' => 'Till',
|
||||||
|
'payload' => [
|
||||||
|
'content' => [
|
||||||
|
'business_name' => 'Accra Kiosk',
|
||||||
|
'currency' => 'GHS',
|
||||||
|
],
|
||||||
|
'style' => [],
|
||||||
|
],
|
||||||
|
'is_active' => true,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$html = $this->withHeader(\App\Support\LadillLink::INTERNAL_HEADER, '1')
|
||||||
|
->get('/q/'.$qr->short_code)
|
||||||
|
->assertOk()
|
||||||
|
->getContent();
|
||||||
|
|
||||||
|
$this->assertStringContainsString('paycors01/pay', $html);
|
||||||
|
$this->assertStringNotContainsString('https://mini.ladill.com/q/paycors01/pay', $html);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_payment_landing_redirects_non_internal_to_public_host(): void
|
||||||
|
{
|
||||||
|
$user = User::create([
|
||||||
|
'public_id' => (string) Str::uuid(),
|
||||||
|
'name' => 'Vendor',
|
||||||
|
'email' => 'vendor-mode@example.com',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$qr = QrCode::query()->create([
|
||||||
|
'user_id' => $user->id,
|
||||||
|
'short_code' => 'paymode1',
|
||||||
|
'type' => QrCode::TYPE_PAYMENT,
|
||||||
|
'label' => 'Till',
|
||||||
|
'payload' => [
|
||||||
|
'content' => [
|
||||||
|
'business_name' => 'Accra Kiosk',
|
||||||
|
'currency' => 'GHS',
|
||||||
|
],
|
||||||
|
'style' => [],
|
||||||
|
],
|
||||||
|
'is_active' => true,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Direct hit (no internal header) is redirected to ladl.link by legacy middleware.
|
||||||
|
$this->get('/q/'.$qr->short_code)->assertRedirect();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user