Replaced references to obfuscate by anonymize

This commit is contained in:
Alejandro Celaya
2020-05-08 15:43:09 +02:00
parent bfdd6e0c50
commit 8f06e4b20f
10 changed files with 26 additions and 46 deletions

View File

@@ -12,7 +12,7 @@ return [
'hostname' => '', 'hostname' => '',
], ],
'validate_url' => false, 'validate_url' => false,
'obfuscate_remote_addr' => true, 'anonymize_remote_addr' => true,
'visits_webhooks' => [], 'visits_webhooks' => [],
'default_short_codes_length' => DEFAULT_SHORT_CODES_LENGTH, 'default_short_codes_length' => DEFAULT_SHORT_CODES_LENGTH,
], ],

View File

@@ -173,7 +173,7 @@ This is the complete list of supported env vars:
* `MERCURE_PUBLIC_HUB_URL`: The public URL of a mercure hub server to which Shlink will sent updates. This URL will also be served to consumers that want to subscribe to those updates. * `MERCURE_PUBLIC_HUB_URL`: The public URL of a mercure hub server to which Shlink will sent updates. This URL will also be served to consumers that want to subscribe to those updates.
* `MERCURE_INTERNAL_HUB_URL`: An internal URL for a mercure hub. Will be used only when publishing updates to mercure, and does not need to be public. If this is not provided but `MERCURE_PUBLIC_HUB_URL` was, the former one will be used to publish updates. * `MERCURE_INTERNAL_HUB_URL`: An internal URL for a mercure hub. Will be used only when publishing updates to mercure, and does not need to be public. If this is not provided but `MERCURE_PUBLIC_HUB_URL` was, the former one will be used to publish updates.
* `MERCURE_JWT_SECRET`: The secret key that was provided to the mercure hub server, in order to be able to generate valid JWTs for publishing/subscribing to that server. * `MERCURE_JWT_SECRET`: The secret key that was provided to the mercure hub server, in order to be able to generate valid JWTs for publishing/subscribing to that server.
* `OBFUSCATE_REMOTE_ADDR`: Tells if IP addresses from visitors should be obfuscated before storing them in the database. Default value is `true`. **Careful!** Setting this to `false` will make your Shlink instance no longer be in compliance with the GDPR and other similar laws. * `ANONYMIZE_REMOTE_ADDR`: Tells if IP addresses from visitors should be obfuscated before storing them in the database. Default value is `true`. **Careful!** Setting this to `false` will make your Shlink instance no longer be in compliance with the GDPR and other similar data protection regulations.
An example using all env vars could look like this: An example using all env vars could look like this:
@@ -205,7 +205,7 @@ docker run \
-e "MERCURE_PUBLIC_HUB_URL=https://example.com" \ -e "MERCURE_PUBLIC_HUB_URL=https://example.com" \
-e "MERCURE_INTERNAL_HUB_URL=http://my-mercure-hub.prod.svc.cluster.local" \ -e "MERCURE_INTERNAL_HUB_URL=http://my-mercure-hub.prod.svc.cluster.local" \
-e MERCURE_JWT_SECRET=super_secret_key \ -e MERCURE_JWT_SECRET=super_secret_key \
-e OBFUSCATE_REMOTE_ADDR=false \ -e ANONYMIZE_REMOTE_ADDR=false \
shlinkio/shlink:stable shlinkio/shlink:stable
``` ```
@@ -251,7 +251,7 @@ The whole configuration should have this format, but it can be split into multip
"mercure_public_hub_url": "https://example.com", "mercure_public_hub_url": "https://example.com",
"mercure_internal_hub_url": "http://my-mercure-hub.prod.svc.cluster.local", "mercure_internal_hub_url": "http://my-mercure-hub.prod.svc.cluster.local",
"mercure_jwt_secret": "super_secret_key", "mercure_jwt_secret": "super_secret_key",
"obfuscate_remote_addr": false "anonymize_remote_addr": false
} }
``` ```

View File

@@ -117,7 +117,7 @@ return [
'hostname' => env('SHORT_DOMAIN_HOST', ''), 'hostname' => env('SHORT_DOMAIN_HOST', ''),
], ],
'validate_url' => (bool) env('VALIDATE_URLS', false), 'validate_url' => (bool) env('VALIDATE_URLS', false),
'obfuscate_remote_addr' => (bool) env('OBFUSCATE_REMOTE_ADDR', true), 'anonymize_remote_addr' => (bool) env('ANONYMIZE_REMOTE_ADDR', true),
'visits_webhooks' => $helper->getVisitsWebhooks(), 'visits_webhooks' => $helper->getVisitsWebhooks(),
'default_short_codes_length' => $helper->getDefaultShortCodesLength(), 'default_short_codes_length' => $helper->getDefaultShortCodesLength(),
], ],

View File

@@ -57,7 +57,7 @@ return [
Service\VisitsTracker::class => [ Service\VisitsTracker::class => [
'em', 'em',
EventDispatcherInterface::class, EventDispatcherInterface::class,
'config.url_shortener.obfuscate_remote_addr', 'config.url_shortener.anonymize_remote_addr',
], ],
Service\ShortUrlService::class => ['em', Service\ShortUrl\ShortUrlResolver::class, Util\UrlValidator::class], Service\ShortUrlService::class => ['em', Service\ShortUrl\ShortUrlResolver::class, Util\UrlValidator::class],
Visit\VisitLocator::class => ['em'], Visit\VisitLocator::class => ['em'],

View File

@@ -37,7 +37,7 @@ class SimplifiedConfigParser
'mercure_public_hub_url' => ['mercure', 'public_hub_url'], 'mercure_public_hub_url' => ['mercure', 'public_hub_url'],
'mercure_internal_hub_url' => ['mercure', 'internal_hub_url'], 'mercure_internal_hub_url' => ['mercure', 'internal_hub_url'],
'mercure_jwt_secret' => ['mercure', 'jwt_secret'], 'mercure_jwt_secret' => ['mercure', 'jwt_secret'],
'obfuscate_remote_addr' => ['url_shortener', 'obfuscate_remote_addr'], 'anonymize_remote_addr' => ['url_shortener', 'anonymize_remote_addr'],
]; ];
private const SIMPLIFIED_CONFIG_SIDE_EFFECTS = [ private const SIMPLIFIED_CONFIG_SIDE_EFFECTS = [
'delete_short_url_threshold' => [ 'delete_short_url_threshold' => [

View File

@@ -21,19 +21,19 @@ class Visit extends AbstractEntity implements JsonSerializable
private ShortUrl $shortUrl; private ShortUrl $shortUrl;
private ?VisitLocation $visitLocation = null; private ?VisitLocation $visitLocation = null;
public function __construct(ShortUrl $shortUrl, Visitor $visitor, bool $obfuscate = true, ?Chronos $date = null) public function __construct(ShortUrl $shortUrl, Visitor $visitor, bool $anonymize = true, ?Chronos $date = null)
{ {
$this->shortUrl = $shortUrl; $this->shortUrl = $shortUrl;
$this->date = $date ?? Chronos::now(); $this->date = $date ?? Chronos::now();
$this->userAgent = $visitor->getUserAgent(); $this->userAgent = $visitor->getUserAgent();
$this->referer = $visitor->getReferer(); $this->referer = $visitor->getReferer();
$this->remoteAddr = $this->processAddress($obfuscate, $visitor->getRemoteAddress()); $this->remoteAddr = $this->processAddress($anonymize, $visitor->getRemoteAddress());
} }
private function processAddress(bool $obfuscate, ?string $address): ?string private function processAddress(bool $anonymize, ?string $address): ?string
{ {
// Localhost addresses do not need to be obfuscated // Localhost addresses do not need to be anonymized
if (! $obfuscate || $address === null || $address === IpAddress::LOCALHOST) { if (! $anonymize || $address === null || $address === IpAddress::LOCALHOST) {
return $address; return $address;
} }

View File

@@ -22,16 +22,16 @@ class VisitsTracker implements VisitsTrackerInterface
{ {
private ORM\EntityManagerInterface $em; private ORM\EntityManagerInterface $em;
private EventDispatcherInterface $eventDispatcher; private EventDispatcherInterface $eventDispatcher;
private bool $obfuscateRemoteAddr; private bool $anonymizeRemoteAddr;
public function __construct( public function __construct(
ORM\EntityManagerInterface $em, ORM\EntityManagerInterface $em,
EventDispatcherInterface $eventDispatcher, EventDispatcherInterface $eventDispatcher,
bool $obfuscateRemoteAddr bool $anonymizeRemoteAddr
) { ) {
$this->em = $em; $this->em = $em;
$this->eventDispatcher = $eventDispatcher; $this->eventDispatcher = $eventDispatcher;
$this->obfuscateRemoteAddr = $obfuscateRemoteAddr; $this->anonymizeRemoteAddr = $anonymizeRemoteAddr;
} }
/** /**
@@ -39,7 +39,7 @@ class VisitsTracker implements VisitsTrackerInterface
*/ */
public function track(ShortUrl $shortUrl, Visitor $visitor): void public function track(ShortUrl $shortUrl, Visitor $visitor): void
{ {
$visit = new Visit($shortUrl, $visitor, $this->obfuscateRemoteAddr); $visit = new Visit($shortUrl, $visitor, $this->anonymizeRemoteAddr);
$this->em->persist($visit); $this->em->persist($visit);
$this->em->flush(); $this->em->flush();

View File

@@ -64,7 +64,7 @@ class SimplifiedConfigParserTest extends TestCase
'mercure_public_hub_url' => 'public_url', 'mercure_public_hub_url' => 'public_url',
'mercure_internal_hub_url' => 'internal_url', 'mercure_internal_hub_url' => 'internal_url',
'mercure_jwt_secret' => 'super_secret_value', 'mercure_jwt_secret' => 'super_secret_value',
'obfuscate_remote_addr' => false, 'anonymize_remote_addr' => false,
]; ];
$expected = [ $expected = [
'app_options' => [ 'app_options' => [
@@ -93,7 +93,7 @@ class SimplifiedConfigParserTest extends TestCase
'https://third-party.io/foo', 'https://third-party.io/foo',
], ],
'default_short_codes_length' => 8, 'default_short_codes_length' => 8,
'obfuscate_remote_addr' => false, 'anonymize_remote_addr' => false,
], ],
'delete_short_urls' => [ 'delete_short_urls' => [

View File

@@ -39,20 +39,20 @@ class VisitTest extends TestCase
* @test * @test
* @dataProvider provideAddresses * @dataProvider provideAddresses
*/ */
public function addressIsObfuscatedWhenRequested(bool $obfuscate, ?string $address, ?string $expectedAddress): void public function addressIsAnonymizedWhenRequested(bool $anonymize, ?string $address, ?string $expectedAddress): void
{ {
$visit = new Visit(new ShortUrl(''), new Visitor('Chrome', 'some site', $address), $obfuscate); $visit = new Visit(new ShortUrl(''), new Visitor('Chrome', 'some site', $address), $anonymize);
$this->assertEquals($expectedAddress, $visit->getRemoteAddr()); $this->assertEquals($expectedAddress, $visit->getRemoteAddr());
} }
public function provideAddresses(): iterable public function provideAddresses(): iterable
{ {
yield 'obfuscated null address' => [true, null, null]; yield 'anonymized null address' => [true, null, null];
yield 'non-obfuscated null address' => [false, null, null]; yield 'non-anonymized null address' => [false, null, null];
yield 'obfuscated localhost' => [true, IpAddress::LOCALHOST, IpAddress::LOCALHOST]; yield 'anonymized localhost' => [true, IpAddress::LOCALHOST, IpAddress::LOCALHOST];
yield 'non-obfuscated localhost' => [false, IpAddress::LOCALHOST, IpAddress::LOCALHOST]; yield 'non-anonymized localhost' => [false, IpAddress::LOCALHOST, IpAddress::LOCALHOST];
yield 'obfuscated regular address' => [true, '1.2.3.4', '1.2.3.0']; yield 'anonymized regular address' => [true, '1.2.3.4', '1.2.3.0'];
yield 'non-obfuscated regular address' => [false, '1.2.3.4', '1.2.3.4']; yield 'non-anonymized regular address' => [false, '1.2.3.4', '1.2.3.4'];
} }
} }

View File

@@ -6,7 +6,6 @@ namespace ShlinkioTest\Shlink\Core\Service;
use Doctrine\ORM\EntityManager; use Doctrine\ORM\EntityManager;
use Laminas\Stdlib\ArrayUtils; use Laminas\Stdlib\ArrayUtils;
use PHPUnit\Framework\Assert;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Prophecy\Argument; use Prophecy\Argument;
use Prophecy\Prophecy\ObjectProphecy; use Prophecy\Prophecy\ObjectProphecy;
@@ -53,25 +52,6 @@ class VisitsTrackerTest extends TestCase
$this->eventDispatcher->dispatch(Argument::type(ShortUrlVisited::class))->shouldHaveBeenCalled(); $this->eventDispatcher->dispatch(Argument::type(ShortUrlVisited::class))->shouldHaveBeenCalled();
} }
/** @test */
public function trackedIpAddressGetsObfuscated(): void
{
$shortCode = '123ABC';
$this->em->persist(Argument::any())->will(function ($args) {
/** @var Visit $visit */
$visit = $args[0];
Assert::assertEquals('4.3.2.0', $visit->getRemoteAddr());
$visit->setId('1');
return $visit;
})->shouldBeCalledOnce();
$this->em->flush()->shouldBeCalledOnce();
$this->visitsTracker->track(new ShortUrl($shortCode), new Visitor('', '', '4.3.2.1'));
$this->eventDispatcher->dispatch(Argument::type(ShortUrlVisited::class))->shouldHaveBeenCalled();
}
/** @test */ /** @test */
public function infoReturnsVisitsForCertainShortCode(): void public function infoReturnsVisitsForCertainShortCode(): void
{ {