Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Extract Domain formatter + add more formats to accept #3000

Merged
merged 1 commit into from
Nov 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 2 additions & 17 deletions app/Http/Controllers/Backend/Social/MastodonController.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
HerrLevin marked this conversation as resolved.
Show resolved Hide resolved

$mastodonServer = MastodonServer::where('domain', $domain)->first();

Expand All @@ -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
*
Expand Down
3 changes: 2 additions & 1 deletion app/Http/Controllers/Frontend/Social/MastodonController.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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();

Expand Down
48 changes: 48 additions & 0 deletions app/Services/MastodonDomainExtractionService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

namespace App\Services;

class MastodonDomainExtractionService
{
private const string HTTP_PREFIX = 'https://';
private const string REPLACE_PREFIX = 'http://';

public function formatDomain(string $domain): string {
$domain = strtolower(trim($domain));

if (empty($domain)) {
return '';
}

$domain = $this->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;
}
}
25 changes: 0 additions & 25 deletions tests/Feature/Social/MastodonControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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();

Expand Down
40 changes: 40 additions & 0 deletions tests/Unit/Services/MastodonDomainExtractionServiceTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

namespace Tests\Unit\Services;

use App\Services\MastodonDomainExtractionService;
use Illuminate\Support\Facades\Validator;
use Tests\Unit\UnitTestCase;

class MastodonDomainExtractionServiceTest extends UnitTestCase
{
/**
* @dataProvider providerTestFormatDomain
*/
public function testFormatDomain($case, $expected): void {
$formatted = (new MastodonDomainExtractionService())->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?
];
}
}
Loading