fix(core): harden settlement and wallet integration

This commit is contained in:
wchino
2026-07-22 01:40:37 +08:00
parent 150c3e7ebd
commit 35f6e46958
54 changed files with 2564 additions and 359 deletions

View File

@@ -1,19 +1,21 @@
<?php
use App\Models\AdminSite;
use App\Models\AuditLog;
use App\Models\AdminUser;
use App\Models\Player;
use App\Services\Integration\PartnerSiteConfig;
use App\Services\Integration\PartnerSiteConfigResolver;
use App\Models\AuditLog;
use App\Models\AdminSite;
use App\Models\AdminUser;
use Illuminate\Support\Facades\DB;
use Database\Seeders\CurrencySeeder;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Http;
use App\Services\Integration\PartnerSiteConfig;
use Illuminate\Foundation\Testing\RefreshDatabase;
use App\Services\Integration\PartnerSiteConfigResolver;
uses(RefreshDatabase::class);
beforeEach(function (): void {
fakeWalletApiDns();
$this->artisan('lottery:admin-auth-sync')->assertExitCode(0);
});
@@ -221,7 +223,81 @@ test('connectivity test probes partner balance api', function (): void {
$response->assertOk()
->assertJsonPath('data.probe.success', true)
->assertJsonPath('data.probe.main_balance_minor', 12345);
->assertJsonPath('data.probe.main_balance_minor', 12345)
->assertJsonMissingPath('data.probe.response_preview');
});
test('connectivity test rejects hostname resolving to a private address before sending', function (): void {
fakeWalletApiDns([
'wallet.private.test' => ['93.184.216.34', '10.0.0.8'],
], []);
Http::preventStrayRequests();
$token = integrationAdminToken();
$create = $this->withHeader('Authorization', 'Bearer '.$token)
->postJson('/api/v1/admin/integration-sites', [
'code' => 'private-probe-site',
'name' => 'Private Probe',
'wallet_api_url' => 'https://wallet.private.test',
'admin_account' => [
'username' => 'private_probe_admin',
'nickname' => 'Private Probe Admin',
'password' => 'secret-strong',
],
]);
$this->withHeader('Authorization', 'Bearer '.$token)
->postJson('/api/v1/admin/integration-sites/'.(int) $create->json('data.id').'/connectivity-test', [
'site_player_id' => '10001',
'currency_code' => 'NPR',
])
->assertOk()
->assertJsonPath('data.probe.success', false)
->assertJsonPath('data.probe.http_status', null)
->assertJsonPath('data.probe.message', 'wallet_api_url 无效(拒绝以防 SSRF')
->assertJsonMissingPath('data.probe.response_preview');
Http::assertSentCount(0);
});
test('connectivity test does not follow redirects or expose response preview', function (): void {
fakeWalletApiDns([
'wallet.redirect.test' => ['93.184.216.34'],
], []);
Http::fake([
'https://wallet.redirect.test/*' => Http::response(
['secret' => 'must-not-be-returned'],
302,
['Location' => 'https://169.254.169.254/latest/meta-data'],
),
'https://169.254.169.254/*' => Http::response(['role' => 'internal'], 200),
]);
$token = integrationAdminToken();
$create = $this->withHeader('Authorization', 'Bearer '.$token)
->postJson('/api/v1/admin/integration-sites', [
'code' => 'redirect-probe-site',
'name' => 'Redirect Probe',
'wallet_api_url' => 'https://wallet.redirect.test',
'admin_account' => [
'username' => 'redirect_probe_admin',
'nickname' => 'Redirect Probe Admin',
'password' => 'secret-strong',
],
]);
$this->withHeader('Authorization', 'Bearer '.$token)
->postJson('/api/v1/admin/integration-sites/'.(int) $create->json('data.id').'/connectivity-test', [
'site_player_id' => '10001',
'currency_code' => 'NPR',
])
->assertOk()
->assertJsonPath('data.probe.success', false)
->assertJsonPath('data.probe.http_status', 302)
->assertJsonMissingPath('data.probe.response_preview')
->assertJsonMissing(['must-not-be-returned']);
Http::assertSentCount(1);
});
test('export parameter sheet excludes plaintext secrets', function (): void {
@@ -329,7 +405,7 @@ test('site scoped admin only sees bound integration sites', function (): void {
});
test('player list is filtered by admin site binding', function (): void {
$this->seed(\Database\Seeders\CurrencySeeder::class);
$this->seed(CurrencySeeder::class);
Player::query()->create([
'site_code' => 'site-a',