Skip to content

Commit baf8977

Browse files
committed
Correctly handle IP addresses containing RFC 4007 scoping
1 parent c7bf843 commit baf8977

File tree

5 files changed

+100
-6
lines changed

5 files changed

+100
-6
lines changed

src/Entity/LogSystem/SecurityEventLogEntry.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@
4444
use App\Entity\Base\AbstractDBElement;
4545
use App\Entity\UserSystem\User;
4646
use App\Events\SecurityEvents;
47+
use App\Helpers\IPAnonymizer;
4748
use Doctrine\ORM\Mapping as ORM;
4849
use InvalidArgumentException;
49-
use Symfony\Component\HttpFoundation\IpUtils;
5050

5151
/**
5252
* This log entry is created when something security related to a user happens.
@@ -134,7 +134,7 @@ public function getIPAddress(): string
134134
public function setIPAddress(string $ip, bool $anonymize = true): self
135135
{
136136
if ($anonymize) {
137-
$ip = IpUtils::anonymize($ip);
137+
$ip = IPAnonymizer::anonymize($ip);
138138
}
139139
$this->extra['i'] = $ip;
140140

src/Entity/LogSystem/UserLoginLogEntry.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@
2222

2323
namespace App\Entity\LogSystem;
2424

25+
use App\Helpers\IPAnonymizer;
2526
use Doctrine\ORM\Mapping as ORM;
26-
use Symfony\Component\HttpFoundation\IpUtils;
27+
2728

2829
/**
2930
* This log entry is created when a user logs in.
@@ -59,7 +60,7 @@ public function getIPAddress(): string
5960
public function setIPAddress(string $ip, bool $anonymize = true): self
6061
{
6162
if ($anonymize) {
62-
$ip = IpUtils::anonymize($ip);
63+
$ip = IPAnonymizer::anonymize($ip);
6364
}
6465

6566
$this->extra['i'] = $ip;

src/Entity/LogSystem/UserLogoutLogEntry.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@
2222

2323
namespace App\Entity\LogSystem;
2424

25+
use App\Helpers\IPAnonymizer;
2526
use Doctrine\ORM\Mapping as ORM;
26-
use Symfony\Component\HttpFoundation\IpUtils;
2727

2828
#[ORM\Entity]
2929
class UserLogoutLogEntry extends AbstractLogEntry
@@ -56,7 +56,7 @@ public function getIPAddress(): string
5656
public function setIPAddress(string $ip, bool $anonymize = true): self
5757
{
5858
if ($anonymize) {
59-
$ip = IpUtils::anonymize($ip);
59+
$ip = IPAnonymizer::anonymize($ip);
6060
}
6161

6262
$this->extra['i'] = $ip;

src/Helpers/IPAnonymizer.php

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
/*
3+
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
4+
*
5+
* Copyright (C) 2019 - 2024 Jan Böhmer (https://github.com/jbtronics)
6+
*
7+
* This program is free software: you can redistribute it and/or modify
8+
* it under the terms of the GNU Affero General Public License as published
9+
* by the Free Software Foundation, either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU Affero General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU Affero General Public License
18+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
19+
*/
20+
21+
declare(strict_types=1);
22+
23+
24+
namespace App\Helpers;
25+
26+
use Symfony\Component\HttpFoundation\IpUtils;
27+
28+
/**
29+
* Utils to assist with IP anonymization.
30+
* The IPUtils::anonymize has a certain edgecase with local-link addresses, which is handled here.
31+
* See: https://github.com/Part-DB/Part-DB-server/issues/782
32+
*/
33+
final class IPAnonymizer
34+
{
35+
public static function anonymize(string $ip): string
36+
{
37+
/**
38+
* If the IP contains a % symbol, then it is a local-link address with scoping according to RFC 4007
39+
* In that case, we only care about the part before the % symbol, as the following functions, can only work with
40+
* the IP address itself. As the scope can leak information (containing interface name), we do not want to
41+
* include it in our anonymized IP data.
42+
*/
43+
if (str_contains($ip, '%')) {
44+
$ip = substr($ip, 0, strpos($ip, '%'));
45+
}
46+
47+
return IpUtils::anonymize($ip);
48+
}
49+
}

tests/Helpers/IPAnonymizerTest.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
/*
3+
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
4+
*
5+
* Copyright (C) 2019 - 2024 Jan Böhmer (https://github.com/jbtronics)
6+
*
7+
* This program is free software: you can redistribute it and/or modify
8+
* it under the terms of the GNU Affero General Public License as published
9+
* by the Free Software Foundation, either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU Affero General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU Affero General Public License
18+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
19+
*/
20+
21+
namespace App\Tests\Helpers;
22+
23+
use App\Helpers\IPAnonymizer;
24+
use PHPUnit\Framework\TestCase;
25+
26+
class IPAnonymizerTest extends TestCase
27+
{
28+
29+
public function anonymizeDataProvider(): \Generator
30+
{
31+
yield ['127.0.0.0', '127.0.0.23'];
32+
yield ['2001:0db8:85a3::', '2001:0db8:85a3:0000:0000:8a2e:0370:7334'];
33+
//RFC 4007 format
34+
yield ['fe80::', 'fe80::1fc4:15d8:78db:2319%enp4s0'];
35+
}
36+
37+
/**
38+
* @dataProvider anonymizeDataProvider
39+
*/
40+
public function testAnonymize(string $expected, string $input): void
41+
{
42+
$this->assertSame($expected, IPAnonymizer::anonymize($input));
43+
}
44+
}

0 commit comments

Comments
 (0)