diff --git a/CHANGELOG.md b/CHANGELOG.md index 500c0734..7af4ea0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com), and this ### Fixed * [#1024](https://github.com/shlinkio/shlink/issues/1024) Fixed migration that is incorrectly skipped due to the wrong condition being used to check it. +* [#1031](https://github.com/shlinkio/shlink/issues/1031) Fixed shortening of twitter URLs with URL validation enabled. ## [2.6.0] - 2021-02-13 diff --git a/module/Core/src/Util/UrlValidator.php b/module/Core/src/Util/UrlValidator.php index 62c2bea5..23de39ef 100644 --- a/module/Core/src/Util/UrlValidator.php +++ b/module/Core/src/Util/UrlValidator.php @@ -20,6 +20,8 @@ use const Shlinkio\Shlink\Core\TITLE_TAG_VALUE; class UrlValidator implements UrlValidatorInterface, RequestMethodInterface { private const MAX_REDIRECTS = 15; + private const CHROME_USER_AGENT = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) ' + . 'Chrome/51.0.2704.103 Safari/537.36'; private ClientInterface $httpClient; private UrlShortenerOptions $options; @@ -67,6 +69,8 @@ class UrlValidator implements UrlValidatorInterface, RequestMethodInterface return $this->httpClient->request(self::METHOD_GET, $url, [ RequestOptions::ALLOW_REDIRECTS => ['max' => self::MAX_REDIRECTS], RequestOptions::IDN_CONVERSION => true, + // Making the request with a browser's user agent makes the validation closer to a real user + RequestOptions::HEADERS => ['User-Agent' => self::CHROME_USER_AGENT], ]); } catch (GuzzleException $e) { if ($throwOnError) { diff --git a/module/Core/test/Util/UrlValidatorTest.php b/module/Core/test/Util/UrlValidatorTest.php index 9ef8e94e..25710172 100644 --- a/module/Core/test/Util/UrlValidatorTest.php +++ b/module/Core/test/Util/UrlValidatorTest.php @@ -10,6 +10,7 @@ use GuzzleHttp\Exception\ClientException; use GuzzleHttp\RequestOptions; use Laminas\Diactoros\Response; use Laminas\Diactoros\Stream; +use PHPUnit\Framework\Assert; use PHPUnit\Framework\TestCase; use Prophecy\Argument; use Prophecy\PhpUnit\ProphecyTrait; @@ -52,10 +53,16 @@ class UrlValidatorTest extends TestCase $request = $this->httpClient->request( RequestMethodInterface::METHOD_GET, $expectedUrl, - [ - RequestOptions::ALLOW_REDIRECTS => ['max' => 15], - RequestOptions::IDN_CONVERSION => true, - ], + Argument::that(function (array $options) { + Assert::assertArrayHasKey(RequestOptions::ALLOW_REDIRECTS, $options); + Assert::assertEquals(['max' => 15], $options[RequestOptions::ALLOW_REDIRECTS]); + Assert::assertArrayHasKey(RequestOptions::IDN_CONVERSION, $options); + Assert::assertTrue($options[RequestOptions::IDN_CONVERSION]); + Assert::assertArrayHasKey(RequestOptions::HEADERS, $options); + Assert::assertArrayHasKey('User-Agent', $options[RequestOptions::HEADERS]); + + return true; + }), )->willReturn(new Response()); $this->urlValidator->validateUrl($expectedUrl, null); diff --git a/module/Rest/test-api/Action/CreateShortUrlTest.php b/module/Rest/test-api/Action/CreateShortUrlTest.php index 868ad142..e9768a69 100644 --- a/module/Rest/test-api/Action/CreateShortUrlTest.php +++ b/module/Rest/test-api/Action/CreateShortUrlTest.php @@ -297,6 +297,24 @@ class CreateShortUrlTest extends ApiTestCase yield 'example domain' => ['example.com']; } + /** + * @test + * @dataProvider provideTwitterUrls + */ + public function urlsWithBothProtectionCanBeShortenedWithUrlValidationEnabled(string $longUrl): void + { + [$statusCode] = $this->createShortUrl(['longUrl' => $longUrl, 'validateUrl' => true]); + self::assertEquals(self::STATUS_OK, $statusCode); + } + + public function provideTwitterUrls(): iterable + { + yield ['https://twitter.com/shlinkio']; + yield ['https://mobile.twitter.com/shlinkio']; + yield ['https://twitter.com/shlinkio/status/1360637738421268481']; + yield ['https://mobile.twitter.com/shlinkio/status/1360637738421268481']; + } + /** * @return array { * @var int $statusCode