From ac523c65e0131224ad6e77cd300dd1260c75a12d Mon Sep 17 00:00:00 2001 From: Levin Date: Wed, 20 Nov 2024 19:18:44 +0100 Subject: [PATCH] Extract Domain formatter + add more formats to accept --- .../Backend/Social/MastodonController.php | 19 +------- .../Frontend/Social/MastodonController.php | 3 +- .../MastodonDomainExtractionService.php | 48 +++++++++++++++++++ .../Feature/Social/MastodonControllerTest.php | 25 ---------- .../MastodonDomainExtractionServiceTest.php | 40 ++++++++++++++++ 5 files changed, 92 insertions(+), 43 deletions(-) create mode 100644 app/Services/MastodonDomainExtractionService.php create mode 100644 tests/Unit/Services/MastodonDomainExtractionServiceTest.php diff --git a/app/Http/Controllers/Backend/Social/MastodonController.php b/app/Http/Controllers/Backend/Social/MastodonController.php index ca3dd8c5a..a33f503cb 100644 --- a/app/Http/Controllers/Backend/Social/MastodonController.php +++ b/app/Http/Controllers/Backend/Social/MastodonController.php @@ -10,6 +10,7 @@ use App\Models\Status; use App\Models\User; use App\Notifications\MastodonNotSent; +use App\Services\MastodonDomainExtractionService; use Error; use Exception; use GuzzleHttp\Exception\GuzzleException; @@ -54,7 +55,7 @@ public static function getUserFromSocialite(SocialiteUser $socialiteUser, Mastod * @throws InvalidMastodonException */ public static function getMastodonServer(string $domain): ?MastodonServer { - $domain = self::formatDomain($domain); + $domain = (new MastodonDomainExtractionService())->formatDomain($domain); $mastodonServer = MastodonServer::where('domain', $domain)->first(); @@ -67,22 +68,6 @@ public static function getMastodonServer(string $domain): ?MastodonServer { return $mastodonServer ?? self::createMastodonServer($domain); } - public static function formatDomain(string $domain): string { - $domain = strtolower($domain); - - // remove leading usernames - if (str_contains($domain, '@')) { - $domain = last(explode('@', $domain)); - } - - // Force HTTPS - $domain = str_replace('http://', 'https://', $domain); - if (!str_starts_with($domain, 'https://')) { - $domain = 'https://' . $domain; - } - return $domain; - } - /** * @param string $domain * diff --git a/app/Http/Controllers/Frontend/Social/MastodonController.php b/app/Http/Controllers/Frontend/Social/MastodonController.php index 4366fb6e3..8d3ffc8a9 100644 --- a/app/Http/Controllers/Frontend/Social/MastodonController.php +++ b/app/Http/Controllers/Frontend/Social/MastodonController.php @@ -5,6 +5,7 @@ use App\Exceptions\SocialAuth\InvalidMastodonException; use App\Http\Controllers\Backend\Social\MastodonController as MastodonBackend; use App\Http\Controllers\Controller; +use App\Services\MastodonDomainExtractionService; use Carbon\Carbon; use Exception; use Illuminate\Http\RedirectResponse; @@ -25,7 +26,7 @@ class MastodonController extends Controller * @throws ValidationException */ public function redirect(Request $request): SympfonyRedirectResponse|RedirectResponse { - $domain = MastodonBackend::formatDomain($request->input('domain') ?? ''); + $domain = (new MastodonDomainExtractionService)->formatDomain($request->input('domain') ?? ''); $validator = Validator::make(['domain' => $domain], ['domain' => ['required', 'active_url']]); $validated = $validator->validate(); diff --git a/app/Services/MastodonDomainExtractionService.php b/app/Services/MastodonDomainExtractionService.php new file mode 100644 index 000000000..8e46cea56 --- /dev/null +++ b/app/Services/MastodonDomainExtractionService.php @@ -0,0 +1,48 @@ +removeProtocolFromUrl($domain); + $domain = $this->removePathFromUrl($domain); + $domain = $this->extractUrlFromUserHandleFormat($domain); + + return $this->forceHttps($domain); + } + + private function extractUrlFromUserHandleFormat(string $domain): string { + if (str_contains($domain, '@')) { + $domain = last(explode('@', $domain)); + } + + return $domain; + } + + private function removePathFromUrl(string $domain): string { + return explode('/', $domain)[0]; + } + + private function removeProtocolFromUrl(string $domain): string { + return preg_replace('/^https?:\/\//', '', $domain); + } + + private function forceHttps(string $domain): string { + $domain = str_replace(self::REPLACE_PREFIX, self::HTTP_PREFIX, $domain); + if (!str_starts_with($domain, self::HTTP_PREFIX)) { + $domain = self::HTTP_PREFIX . $domain; + } + + return $domain; + } +} diff --git a/tests/Feature/Social/MastodonControllerTest.php b/tests/Feature/Social/MastodonControllerTest.php index 2c462620b..c70360739 100644 --- a/tests/Feature/Social/MastodonControllerTest.php +++ b/tests/Feature/Social/MastodonControllerTest.php @@ -11,7 +11,6 @@ use GuzzleHttp\Psr7\Response; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Support\Facades\Log; -use Illuminate\Support\Facades\Validator; use Revolution\Mastodon\Facades\Mastodon; use Tests\FeatureTestCase; @@ -27,30 +26,6 @@ class MastodonControllerTest extends FeatureTestCase const TOOTID_ANSWER_3 = "1340"; const OP_CONTEXT_URL = '/statuses/' . self::TOOTID_OP . '/context'; - /** - * @dataProvider providerTestFormatDomain - */ - public function testFormatDomain($case, $expected): void { - $formatted = MastodonController::formatDomain($case); - $this->assertEquals($expected, $formatted); - - $validated = Validator::make(['domain' => $formatted], ['domain' => ['active_url']]); - - $this->assertFalse($validated->fails()); - } - - public static function providerTestFormatDomain(): array { - return [ - ['https://uelfte.club', 'https://uelfte.club'], - ['http://uelfte.club', 'https://uelfte.club'], - ['uelfte.club', 'https://uelfte.club'], - ['great_username@uelfte.club', 'https://uelfte.club'], - ['@great_username@uelfte.club', 'https://uelfte.club'], - ['https://mastodon.sergal.org', 'https://mastodon.sergal.org'] # see issue 1182 - ]; - } - - public function testFindEndOfChainIfThereAreNoAnswers(): void { $user = $this->setupUserWithMastodonAccount(); diff --git a/tests/Unit/Services/MastodonDomainExtractionServiceTest.php b/tests/Unit/Services/MastodonDomainExtractionServiceTest.php new file mode 100644 index 000000000..7b89397e5 --- /dev/null +++ b/tests/Unit/Services/MastodonDomainExtractionServiceTest.php @@ -0,0 +1,40 @@ +formatDomain($case); + $this->assertEquals($expected, $formatted); + + $validated = Validator::make(['domain' => $formatted], ['domain' => ['active_url']]); + + $this->assertFalse($validated->fails()); + } + + public static function providerTestFormatDomain(): array { + return [ + [' https://github.com ', 'https://github.com'], + [' ', ''], + ['', ''], + ['https://github.com', 'https://github.com'], + ['http://github.com', 'https://github.com'], + ['github.com', 'https://github.com'], + ['great_username@github.com', 'https://github.com'], + ['@great_username@github.com', 'https://github.com'], + ['https://traewelling.github.io', 'https://traewelling.github.io'], + ['https://traewelling.github.io/', 'https://traewelling.github.io'], + ['https://traewelling.github.io/@foobar', 'https://traewelling.github.io'], + ['github.com/mastodon/mastodon', 'https://github.com'], + ['@user@github.com/@mastodon/mastodon', 'https://github.com'] // who would do this? + ]; + } +}