From 70d4dad4941cb7dceea627da98f137aa4426e7bb Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Fri, 16 Oct 2026 00:16:20 +0200 Subject: [PATCH] fix(settings): keep manually set instance public IPs on restart Closes #11802 Co-Authored-By: Claude Opus 5.5 --- bootstrap/helpers/shared.php | 55 ++++++++--------- .../views/livewire/settings/index.blade.php | 4 +- tests/Feature/GetPublicIpsTest.php | 60 +++++++++++++++++++ 3 files changed, 90 insertions(+), 29 deletions(-) create mode 100644 tests/Feature/GetPublicIpsTest.php diff --git a/bootstrap/helpers/shared.php b/bootstrap/helpers/shared.php index 6c359212af..136c34589e 100644 --- a/bootstrap/helpers/shared.php +++ b/bootstrap/helpers/shared.php @@ -2677,38 +2677,39 @@ function deduplicateAllowlist(array $entries): array return $result; } -function get_public_ips() +/** + * Detect the instance public IPs with ifconfig.io. Only empty settings are filled, so an address saved in Settings is kept. + */ +function get_public_ips(): void { try { - [$first, $second] = Process::concurrently(function (Pool $pool) { - $pool->path(__DIR__)->command('curl -4s https://ifconfig.io'); - $pool->path(__DIR__)->command('curl -6s https://ifconfig.io'); - }); - $ipv4 = $first->output(); - if ($ipv4) { - $ipv4 = trim($ipv4); - $validate_ipv4 = filter_var($ipv4, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4); - if ($validate_ipv4 == false) { - echo "Invalid ipv4: $ipv4\n"; - - return; - } - InstanceSettings::get()->update(['public_ipv4' => $ipv4]); + $settings = InstanceSettings::get(); + $versions = array_filter( + ['public_ipv4' => 4, 'public_ipv6' => 6], + fn (string $column) => blank($settings->$column), + ARRAY_FILTER_USE_KEY, + ); + if ($versions === []) { + return; } - } catch (Exception $e) { - echo "Error: {$e->getMessage()}\n"; - } - try { - $ipv6 = $second->output(); - if ($ipv6) { - $ipv6 = trim($ipv6); - $validate_ipv6 = filter_var($ipv6, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6); - if ($validate_ipv6 == false) { - echo "Invalid ipv6: $ipv6\n"; - return; + $results = Process::concurrently(function (Pool $pool) use ($versions) { + foreach ($versions as $column => $version) { + $pool->as($column)->path(__DIR__)->command("curl -{$version}s https://ifconfig.io"); } - InstanceSettings::get()->update(['public_ipv6' => $ipv6]); + }); + + foreach ($versions as $column => $version) { + $ip = trim($results[$column]->output()); + if ($ip === '') { + continue; + } + if (filter_var($ip, FILTER_VALIDATE_IP, $version === 4 ? FILTER_FLAG_IPV4 : FILTER_FLAG_IPV6) === false) { + echo "Invalid ipv{$version}: $ip\n"; + + continue; + } + $settings->update([$column => $ip]); } } catch (Throwable $e) { echo "Error: {$e->getMessage()}\n"; diff --git a/resources/views/livewire/settings/index.blade.php b/resources/views/livewire/settings/index.blade.php index 848642b6bb..d888145faa 100644 --- a/resources/views/livewire/settings/index.blade.php +++ b/resources/views/livewire/settings/index.blade.php @@ -51,11 +51,11 @@
diff --git a/tests/Feature/GetPublicIpsTest.php b/tests/Feature/GetPublicIpsTest.php new file mode 100644 index 0000000000..477a9d3ed0 --- /dev/null +++ b/tests/Feature/GetPublicIpsTest.php @@ -0,0 +1,60 @@ + "203.0.113.1\n", + 'curl -6s https://ifconfig.io' => "2001:db8::1\n", + ]); +}); + +it('detects the public IPs when the settings are empty', function () { + InstanceSettings::forceCreate(['id' => 0]); + + get_public_ips(); + + $settings = InstanceSettings::find(0); + expect($settings->public_ipv4)->toBe('203.0.113.1') + ->and($settings->public_ipv6)->toBe('2001:db8::1'); +}); + +it('keeps public IPs that are already set', function () { + InstanceSettings::forceCreate(['id' => 0, 'public_ipv4' => '203.0.113.21', 'public_ipv6' => '2001:db8::21']); + + get_public_ips(); + + $settings = InstanceSettings::find(0); + expect($settings->public_ipv4)->toBe('203.0.113.21') + ->and($settings->public_ipv6)->toBe('2001:db8::21'); + Process::assertNothingRan(); +}); + +it('detects only the address family that is empty', function () { + InstanceSettings::forceCreate(['id' => 0, 'public_ipv4' => '203.0.113.21']); + + get_public_ips(); + + $settings = InstanceSettings::find(0); + expect($settings->public_ipv4)->toBe('203.0.113.21') + ->and($settings->public_ipv6)->toBe('2001:db8::1'); + Process::assertNotRan('curl -4s https://ifconfig.io'); +}); + +it('still detects IPv6 when the IPv4 lookup returns an invalid address', function () { + Process::fake([ + 'curl -4s https://ifconfig.io' => 'not-an-ip', + 'curl -6s https://ifconfig.io' => "2001:db8::1\n", + ]); + InstanceSettings::forceCreate(['id' => 0]); + + get_public_ips(); + + $settings = InstanceSettings::find(0); + expect($settings->public_ipv4)->toBeNull() + ->and($settings->public_ipv6)->toBe('2001:db8::1'); +});