Update ap inbox

This commit is contained in:
Daniel Supernault 2023-06-06 04:53:09 -06:00
parent 8cc91babd7
commit 29961c4a80
No known key found for this signature in database
GPG key ID: 0DEF1C662C9033F7
3 changed files with 217 additions and 0 deletions

View file

@ -0,0 +1,88 @@
<?php
namespace App\Jobs\ProfilePipeline;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use App\Avatar;
use App\Profile;
use App\Util\ActivityPub\Helpers;
use Purify;
use App\Jobs\AvatarPipeline\RemoteAvatarFetch;
use App\Util\Lexer\Autolink;
class HandleUpdateActivity implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $payload;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct($payload)
{
$this->payload = $payload;
}
/**
* Execute the job.
*
* @return void
*/
public function handle(): void
{
$payload = $this->payload;
if(empty($payload) || !isset($payload['actor'])) {
return;
}
$profile = Profile::whereRemoteUrl($payload['actor'])->first();
if(!$profile || $profile->domain === null || $profile->private_key) {
return;
}
if($profile->sharedInbox == null || $profile->sharedInbox != $payload['object']['endpoints']['sharedInbox']) {
$profile->sharedInbox = $payload['object']['endpoints']['sharedInbox'];
}
if($profile->public_key !== $payload['object']['publicKey']['publicKeyPem']) {
$profile->public_key = $payload['object']['publicKey']['publicKeyPem'];
}
if($profile->bio !== $payload['object']['summary']) {
$len = strlen(strip_tags($payload['object']['summary']));
if($len) {
if($len > 500) {
$updated = strip_tags($payload['object']['summary']);
$updated = substr($updated, 0, config('pixelfed.max_bio_length'));
$profile->bio = Autolink::create()->autolink($updated);
} else {
$profile->bio = Purify::clean($payload['object']['summary']);
}
} else {
$profile->bio = null;
}
}
if($profile->name !== $payload['object']['name']) {
$profile->name = Purify::clean(substr($payload['object']['name'], 0, config('pixelfed.max_name_length')));
}
if($profile->isDirty()) {
$profile->save();
}
RemoteAvatarFetch::dispatch($profile)->onQueue('low');
return;
}
}

View file

@ -29,6 +29,7 @@ use App\Jobs\DeletePipeline\DeleteRemoteStatusPipeline;
use App\Jobs\StoryPipeline\StoryExpire; use App\Jobs\StoryPipeline\StoryExpire;
use App\Jobs\StoryPipeline\StoryFetch; use App\Jobs\StoryPipeline\StoryFetch;
use App\Jobs\StatusPipeline\StatusRemoteUpdatePipeline; use App\Jobs\StatusPipeline\StatusRemoteUpdatePipeline;
use App\Jobs\ProfilePipeline\HandleUpdateActivity;
use App\Util\ActivityPub\Validator\Accept as AcceptValidator; use App\Util\ActivityPub\Validator\Accept as AcceptValidator;
use App\Util\ActivityPub\Validator\Add as AddValidator; use App\Util\ActivityPub\Validator\Add as AddValidator;
@ -36,6 +37,7 @@ use App\Util\ActivityPub\Validator\Announce as AnnounceValidator;
use App\Util\ActivityPub\Validator\Follow as FollowValidator; use App\Util\ActivityPub\Validator\Follow as FollowValidator;
use App\Util\ActivityPub\Validator\Like as LikeValidator; use App\Util\ActivityPub\Validator\Like as LikeValidator;
use App\Util\ActivityPub\Validator\UndoFollow as UndoFollowValidator; use App\Util\ActivityPub\Validator\UndoFollow as UndoFollowValidator;
use App\Util\ActivityPub\Validator\UpdatePersonValidator;
use App\Services\PollService; use App\Services\PollService;
use App\Services\FollowerService; use App\Services\FollowerService;
@ -1217,10 +1219,18 @@ class Inbox
return; return;
} }
if(!Helpers::validateUrl($activity['id'])) {
return;
}
if($activity['type'] === 'Note') { if($activity['type'] === 'Note') {
if(Status::whereObjectUrl($activity['id'])->exists()) { if(Status::whereObjectUrl($activity['id'])->exists()) {
StatusRemoteUpdatePipeline::dispatch($activity); StatusRemoteUpdatePipeline::dispatch($activity);
} }
} else if ($activity['type'] === 'Person') {
if(UpdatePersonValidator::validate($this->payload)) {
HandleUpdateActivity::dispatch($this->payload)->onQueue('low');
}
} }
} }
} }

View file

@ -0,0 +1,119 @@
<?php
namespace App\Util\ActivityPub\Validator;
use Validator;
use Closure;
use Illuminate\Validation\Rule;
use \App\Rules\SameHostDomain;
class UpdatePersonValidator
{
public static function validate($payload)
{
$valid = Validator::make($payload, [
'@context' => 'required',
'id' => 'required|string|url',
'type' => [
'required',
Rule::in(['Update'])
],
'actor' => 'required|url',
'object' => 'required',
'object.id' => [
'required',
'url',
'same:actor',
function (string $attribute, mixed $value, Closure $fail) use($payload) {
self::sameHost($attribute, $value, $fail, $payload['actor']);
},
],
'object.type' => [
'required',
Rule::in(['Person'])
],
'object.publicKey' => 'required',
'object.publicKey.id' => [
'required',
'url',
function (string $attribute, mixed $value, Closure $fail) use($payload) {
self::sameHost($attribute, $value, $fail, $payload['actor']);
},
],
'object.publicKey.owner' => [
'required',
'url',
'same:actor',
function (string $attribute, mixed $value, Closure $fail) use($payload) {
self::sameHost($attribute, $value, $fail, $payload['actor']);
},
],
'object.publicKey.publicKeyPem' => 'required|string',
'object.url' => [
'required',
'url',
function (string $attribute, mixed $value, Closure $fail) use($payload) {
self::sameHost($attribute, $value, $fail, $payload['actor']);
},
],
'object.summary' => 'required|string|nullable',
'object.preferredUsername' => 'required|string',
'object.name' => 'required|string|nullable',
'object.inbox' => [
'required',
'url',
function (string $attribute, mixed $value, Closure $fail) use($payload) {
self::sameHost($attribute, $value, $fail, $payload['actor']);
},
],
'object.outbox' => [
'required',
'url',
function (string $attribute, mixed $value, Closure $fail) use($payload) {
self::sameHost($attribute, $value, $fail, $payload['actor']);
},
],
'object.following' => [
'required',
'url',
function (string $attribute, mixed $value, Closure $fail) use($payload) {
self::sameHost($attribute, $value, $fail, $payload['actor']);
},
],
'object.followers' => [
'required',
'url',
function (string $attribute, mixed $value, Closure $fail) use($payload) {
self::sameHost($attribute, $value, $fail, $payload['actor']);
},
],
'object.manuallyApprovesFollowers' => 'required',
'object.icon' => 'sometimes|nullable',
'object.icon.type' => 'sometimes|required_with:object.icon.url,object.icon.mediaType|in:Image',
'object.icon.url' => 'sometimes|required_with:object.icon.type,object.icon.mediaType|url',
'object.icon.mediaType' => 'sometimes|required_with:object.icon.url,object.icon.type|in:image/jpeg,image/png,image/jpg',
'object.endpoints' => 'sometimes',
'object.endpoints.sharedInbox' => [
'sometimes',
'url',
function (string $attribute, mixed $value, Closure $fail) use($payload) {
self::sameHost($attribute, $value, $fail, $payload['actor']);
},
]
])->passes();
return $valid;
}
public static function sameHost(string $attribute, mixed $value, Closure $fail, string $comparedHost)
{
if(empty($value)) {
$fail('The ' . $attribute . ' is invalid or empty');
}
$host = parse_url($value, PHP_URL_HOST);
$idHost = parse_url($comparedHost, PHP_URL_HOST);
if ($host !== $idHost) {
$fail('The ' . $attribute . ' is invalid');
}
}
}