Update Helpers

pull/7243/head
Daniel Supernault 2 weeks ago
parent a27033d2fd
commit fbd0922fd0
No known key found for this signature in database
GPG Key ID: 23740873EE6F76A1

@ -48,6 +48,15 @@ class Helpers
private const DNS_TTL_NEGATIVE = 300;
/**
* Maximum number of ancestors a single status fetch may walk up an
* inReplyTo chain. Without a bound, a remote server that always answers
* with another inReplyTo can hold a worker indefinitely, one outbound
* fetch and one statuses row per hop. Anything deeper than this is not
* rendered in the UI anyway.
*/
private const MAX_REPLY_DEPTH = 5;
private const LOCALHOST_DOMAINS = [
'localhost',
'127.0.0.1',
@ -573,8 +582,13 @@ class Helpers
/**
* Fetch or create a status from URL
*
* $depth counts how many inReplyTo hops we are from the status that
* started this resolution. Every recursive call passes $depth + 1 so the
* walk terminates at MAX_REPLY_DEPTH regardless of what the remote
* server keeps answering.
*/
public static function statusFirstOrFetch(string $url, bool $replyTo = false): ?Status
public static function statusFirstOrFetch(string $url, bool $replyTo = false, int $depth = 0): ?Status
{
if (! $validUrl = self::validateUrl($url)) {
return null;
@ -584,7 +598,14 @@ class Helpers
return $status;
}
return self::createStatusFromUrl($url, $replyTo);
// Bound how far up an inReplyTo chain a single fetch may walk.
// Checked after the DB lookup so a reply to an already-known
// status still links even at the limit, but we never fetch past it.
if ($depth > self::MAX_REPLY_DEPTH) {
return null;
}
return self::createStatusFromUrl($url, $replyTo, $depth);
}
/**
@ -612,7 +633,7 @@ class Helpers
/**
* Create a new status from ActivityPub data
*/
public static function createStatusFromUrl(string $url, bool $replyTo): ?Status
public static function createStatusFromUrl(string $url, bool $replyTo, int $depth = 0): ?Status
{
$res = self::fetchFromUrl($url);
@ -638,7 +659,7 @@ class Helpers
return null;
}
$reply_to = self::getReplyToId($activity, $profile, $replyTo);
$reply_to = self::getReplyToId($activity, $profile, $replyTo, $depth);
$scope = self::getScope($activity, $url);
$cw = self::getSensitive($activity, $url);
@ -655,7 +676,7 @@ class Helpers
);
}
return self::storeStatus($url, $profile, $res);
return self::storeStatus($url, $profile, $res, $depth);
}
/**
@ -805,16 +826,19 @@ class Helpers
/**
* Get reply-to status ID
*
* Resolves (and fetches if needed) the parent referenced by
* object.inReplyTo, one hop deeper than the caller.
*/
public static function getReplyToId(array $activity, Profile $profile, bool $replyTo): ?int
public static function getReplyToId(array $activity, Profile $profile, bool $replyTo, int $depth = 0): ?int
{
$inReplyTo = $activity['object']['inReplyTo'] ?? null;
$inReplyTo = self::pluckval($activity['object']['inReplyTo'] ?? null);
if (! $inReplyTo && ! $replyTo) {
if (! is_string($inReplyTo) || $inReplyTo === '') {
return null;
}
$reply = self::statusFirstOrFetch(self::pluckval($inReplyTo), false);
$reply = self::statusFirstOrFetch($inReplyTo, false, $depth + 1);
if (! $reply) {
return null;
@ -828,7 +852,7 @@ class Helpers
/**
* Store a new regular status
*/
public static function storeStatus(string $url, Profile $profile, array $activity): Status
public static function storeStatus(string $url, Profile $profile, array $activity, int $depth = 0): Status
{
$id = self::getStatusId($activity, $url);
$url = self::getStatusUrl($activity, $id);
@ -852,7 +876,7 @@ class Helpers
]));
}
$reply_to = self::getReplyTo($activity);
$reply_to = self::getReplyTo($activity, $depth);
$ts = self::pluckval($activity['published']);
$scope = self::getScope($activity, $url);
$commentsDisabled = isset($activity['commentsEnabled']) ? (bool) $activity['commentsEnabled'] == false : false;
@ -1026,23 +1050,22 @@ class Helpers
return $cw;
}
public static function getReplyTo($activity)
/**
* Resolve the parent status id for an object's inReplyTo, one hop deeper
* than the caller. Shares the same depth bound as getReplyToId so the
* storeStatus path cannot restart the walk from zero.
*/
public static function getReplyTo($activity, int $depth = 0)
{
$reply_to = null;
$inReplyTo = isset($activity['inReplyTo']) && ! empty($activity['inReplyTo']) ?
$inReplyTo = ! empty($activity['inReplyTo']) ?
self::pluckval($activity['inReplyTo']) :
false;
null;
if ($inReplyTo) {
$reply_to = self::statusFirstOrFetch($inReplyTo);
if ($reply_to) {
$reply_to = $reply_to?->id;
}
} else {
$reply_to = null;
if (! is_string($inReplyTo) || $inReplyTo === '') {
return null;
}
return $reply_to;
return self::statusFirstOrFetch($inReplyTo, false, $depth + 1)?->id;
}
public static function getScope($activity, $url)

Loading…
Cancel
Save