107 lines
3.0 KiB
PHP
107 lines
3.0 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Http\Middleware;
|
|
|
|
use App\Models\User;
|
|
use App\Support\UsernamePolicy;
|
|
use Closure;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Schema;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
|
|
class RedirectLegacyProfileSubdomain
|
|
{
|
|
public function handle(Request $request, Closure $next): Response
|
|
{
|
|
$canonicalUsername = $this->resolveCanonicalUsername($request);
|
|
|
|
if ($canonicalUsername !== null) {
|
|
return redirect()->to($this->targetUrl($request, $canonicalUsername), 301);
|
|
}
|
|
|
|
return $next($request);
|
|
}
|
|
|
|
private function resolveCanonicalUsername(Request $request): ?string
|
|
{
|
|
$configuredHost = parse_url((string) config('app.url'), PHP_URL_HOST);
|
|
|
|
if (! is_string($configuredHost) || $configuredHost === '') {
|
|
return null;
|
|
}
|
|
|
|
$requestHost = strtolower($request->getHost());
|
|
$configuredHost = strtolower($configuredHost);
|
|
|
|
if ($requestHost === $configuredHost || ! str_ends_with($requestHost, '.' . $configuredHost)) {
|
|
return null;
|
|
}
|
|
|
|
$subdomain = substr($requestHost, 0, -strlen('.' . $configuredHost));
|
|
|
|
if ($subdomain === '' || str_contains($subdomain, '.')) {
|
|
return null;
|
|
}
|
|
|
|
$candidate = UsernamePolicy::normalize($subdomain);
|
|
|
|
if ($candidate === '' || $this->isReservedSubdomain($candidate)) {
|
|
return null;
|
|
}
|
|
|
|
$username = User::query()
|
|
->whereRaw('LOWER(username) = ?', [$candidate])
|
|
->value('username');
|
|
|
|
if (is_string($username) && $username !== '') {
|
|
return UsernamePolicy::normalize($username);
|
|
}
|
|
|
|
if (! Schema::hasTable('username_redirects')) {
|
|
return null;
|
|
}
|
|
|
|
$redirect = DB::table('username_redirects')
|
|
->whereRaw('LOWER(old_username) = ?', [$candidate])
|
|
->value('new_username');
|
|
|
|
return is_string($redirect) && $redirect !== ''
|
|
? UsernamePolicy::normalize($redirect)
|
|
: null;
|
|
}
|
|
|
|
private function isReservedSubdomain(string $candidate): bool
|
|
{
|
|
$reserved = UsernamePolicy::reserved();
|
|
|
|
foreach ([config('cp.webroot'), config('cpad.webroot')] as $prefix) {
|
|
$value = strtolower(trim((string) $prefix, '/'));
|
|
if ($value !== '') {
|
|
$reserved[] = $value;
|
|
}
|
|
}
|
|
|
|
return in_array($candidate, array_values(array_unique($reserved)), true);
|
|
}
|
|
|
|
private function targetUrl(Request $request, string $username): string
|
|
{
|
|
$canonicalPath = match ($request->getPathInfo()) {
|
|
'/gallery', '/gallery/' => '/@' . $username . '/gallery',
|
|
default => '/@' . $username,
|
|
};
|
|
|
|
$target = rtrim((string) config('app.url'), '/') . $canonicalPath;
|
|
$query = $request->getQueryString();
|
|
|
|
if (is_string($query) && $query !== '') {
|
|
$target .= '?' . $query;
|
|
}
|
|
|
|
return $target;
|
|
}
|
|
}
|