|
|
|
|
@ -5,6 +5,7 @@ namespace App\Util\ActivityPub;
|
|
|
|
|
use App\Instance;
|
|
|
|
|
use App\Jobs\AvatarPipeline\RemoteAvatarFetch;
|
|
|
|
|
use App\Jobs\HomeFeedPipeline\FeedInsertRemotePipeline;
|
|
|
|
|
use App\Jobs\InstancePipeline\FetchNodeinfoPipeline;
|
|
|
|
|
use App\Jobs\MediaPipeline\MediaStoragePipeline;
|
|
|
|
|
use App\Jobs\StatusPipeline\StatusReplyPipeline;
|
|
|
|
|
use App\Jobs\StatusPipeline\StatusTagsPipeline;
|
|
|
|
|
@ -26,7 +27,6 @@ use App\Util\Media\License;
|
|
|
|
|
use Cache;
|
|
|
|
|
use Carbon\Carbon;
|
|
|
|
|
use Illuminate\Validation\Rule;
|
|
|
|
|
use League\Uri\Exceptions\UriException;
|
|
|
|
|
use League\Uri\Uri;
|
|
|
|
|
use Purify;
|
|
|
|
|
use Validator;
|
|
|
|
|
@ -52,7 +52,6 @@ class Helpers
|
|
|
|
|
'ip6-loopback',
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Validate an ActivityPub object
|
|
|
|
|
*/
|
|
|
|
|
@ -213,7 +212,6 @@ class Helpers
|
|
|
|
|
return $uri->toString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Normalize URL input
|
|
|
|
|
*/
|
|
|
|
|
@ -244,7 +242,6 @@ class Helpers
|
|
|
|
|
return $url;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Validate basic URI requirements
|
|
|
|
|
*/
|
|
|
|
|
@ -326,7 +323,6 @@ class Helpers
|
|
|
|
|
return $host;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static function resolvePublicIps(string $host): array
|
|
|
|
|
{
|
|
|
|
|
$host = self::normalizeHost($host);
|
|
|
|
|
@ -335,14 +331,14 @@ class Helpers
|
|
|
|
|
return [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$key = self::URL_CACHE_PREFIX .
|
|
|
|
|
'public-ips:sha256-' .
|
|
|
|
|
$key = self::URL_CACHE_PREFIX.
|
|
|
|
|
'public-ips:sha256-'.
|
|
|
|
|
hash('sha256', $host);
|
|
|
|
|
|
|
|
|
|
return Cache::remember($key, 60, function () use ($host) {
|
|
|
|
|
$ips = [];
|
|
|
|
|
|
|
|
|
|
$aRecords = @dns_get_record($host . '.', DNS_A);
|
|
|
|
|
$aRecords = @dns_get_record($host.'.', DNS_A);
|
|
|
|
|
|
|
|
|
|
if (is_array($aRecords)) {
|
|
|
|
|
foreach ($aRecords as $record) {
|
|
|
|
|
@ -352,7 +348,7 @@ class Helpers
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$aaaaRecords = @dns_get_record($host . '.', DNS_AAAA);
|
|
|
|
|
$aaaaRecords = @dns_get_record($host.'.', DNS_AAAA);
|
|
|
|
|
|
|
|
|
|
if (is_array($aaaaRecords)) {
|
|
|
|
|
foreach ($aaaaRecords as $record) {
|
|
|
|
|
@ -446,7 +442,7 @@ class Helpers
|
|
|
|
|
public static function hasValidDNS(string $host): bool
|
|
|
|
|
{
|
|
|
|
|
$hash = hash('sha256', $host);
|
|
|
|
|
$key = self::URL_CACHE_PREFIX . "valid-dns:sha256-{$hash}";
|
|
|
|
|
$key = self::URL_CACHE_PREFIX."valid-dns:sha256-{$hash}";
|
|
|
|
|
|
|
|
|
|
return Cache::remember($key, self::CACHE_TTL, function () use ($host) {
|
|
|
|
|
return DomainService::hasValidDns($host);
|
|
|
|
|
@ -469,7 +465,7 @@ class Helpers
|
|
|
|
|
$host = strtolower(rtrim($host, '.'));
|
|
|
|
|
|
|
|
|
|
$bannedInstances = array_map(
|
|
|
|
|
fn($domain) => strtolower(rtrim($domain, '.')),
|
|
|
|
|
fn ($domain) => strtolower(rtrim($domain, '.')),
|
|
|
|
|
InstanceService::getBannedDomains()
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
@ -720,7 +716,7 @@ class Helpers
|
|
|
|
|
|
|
|
|
|
if (is_array($attributedTo)) {
|
|
|
|
|
return collect($attributedTo)
|
|
|
|
|
->filter(fn($o) => $o && isset($o['type']) && $o['type'] == 'Person')
|
|
|
|
|
->filter(fn ($o) => $o && isset($o['type']) && $o['type'] == 'Person')
|
|
|
|
|
->pluck('id')
|
|
|
|
|
->first();
|
|
|
|
|
}
|
|
|
|
|
@ -733,21 +729,42 @@ class Helpers
|
|
|
|
|
*/
|
|
|
|
|
public static function validateStatusUrls(string $url, array $activity): bool
|
|
|
|
|
{
|
|
|
|
|
$id = isset($activity['id']) ?
|
|
|
|
|
self::pluckval($activity['id']) :
|
|
|
|
|
self::pluckval($url);
|
|
|
|
|
$id = self::extractActivityPubUrl(
|
|
|
|
|
$activity['id'] ?? $url
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (! $id) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$idDomain = parse_url($id, PHP_URL_HOST);
|
|
|
|
|
$urlDomain = parse_url($url, PHP_URL_HOST);
|
|
|
|
|
|
|
|
|
|
if (! $idDomain || ! $urlDomain) {
|
|
|
|
|
if (! is_string($idDomain) || ! is_string($urlDomain)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (strcasecmp($idDomain, $urlDomain) !== 0) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$attributedTo = $activity['attributedTo'] ?? $activity['object']['attributedTo'] ?? null;
|
|
|
|
|
if ($attributedTo) {
|
|
|
|
|
$authorDomain = parse_url(self::pluckval($attributedTo), PHP_URL_HOST);
|
|
|
|
|
if ($authorDomain && strtolower($idDomain) !== strtolower($authorDomain)) {
|
|
|
|
|
$attributedTo = $activity['attributedTo']
|
|
|
|
|
?? $activity['object']['attributedTo']
|
|
|
|
|
?? null;
|
|
|
|
|
|
|
|
|
|
if ($attributedTo !== null) {
|
|
|
|
|
$author = self::extractActivityPubUrl($attributedTo);
|
|
|
|
|
|
|
|
|
|
if (! $author) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$authorDomain = parse_url($author, PHP_URL_HOST);
|
|
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
! is_string($authorDomain) ||
|
|
|
|
|
strcasecmp($idDomain, $authorDomain) !== 0
|
|
|
|
|
) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -755,6 +772,31 @@ class Helpers
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static function extractActivityPubUrl($value): ?string
|
|
|
|
|
{
|
|
|
|
|
$value = self::pluckval($value);
|
|
|
|
|
|
|
|
|
|
if (is_string($value)) {
|
|
|
|
|
return $value !== '' ? $value : null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (is_array($value)) {
|
|
|
|
|
foreach ($value as $item) {
|
|
|
|
|
$item = self::pluckval($item);
|
|
|
|
|
|
|
|
|
|
if (is_string($item) && $item !== '') {
|
|
|
|
|
return $item;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (is_array($item) && isset($item['id']) && is_string($item['id'])) {
|
|
|
|
|
return $item['id'];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get reply-to status ID
|
|
|
|
|
*/
|
|
|
|
|
@ -1442,7 +1484,7 @@ class Helpers
|
|
|
|
|
$instance = Instance::updateOrCreate(['domain' => $domain]);
|
|
|
|
|
|
|
|
|
|
if ($instance->wasRecentlyCreated) {
|
|
|
|
|
\App\Jobs\InstancePipeline\FetchNodeinfoPipeline::dispatch($instance)
|
|
|
|
|
FetchNodeinfoPipeline::dispatch($instance)
|
|
|
|
|
->onQueue('low');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -1505,6 +1547,7 @@ class Helpers
|
|
|
|
|
if ($url === null) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return self::profileFirstOrNew($url);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|