Skip to content

Commit

Permalink
Outbox: Fall back to blog author for non-authorized authors (#1208)
Browse files Browse the repository at this point in the history
* Outbox: Don't create items for post from not activitypub-authorized authors

* Use utility function

Props @pfefferle

* Move user_id check into outbox helper

* Update unit tests

* Revert changes in post class

* Skip when blog mode is disabled
  • Loading branch information
obenland authored Jan 27, 2025
1 parent 40c9535 commit 0dce338
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 12 deletions.
9 changes: 9 additions & 0 deletions includes/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -1580,6 +1580,15 @@ function add_to_outbox( $data, $activity_type = 'Create', $user_id = 0, $content
return false;
}

// If the user is disabled, fall back to the blog user when available.
if ( is_user_disabled( $user_id ) ) {
if ( is_user_disabled( Actors::BLOG_USER_ID ) ) {
return false;
} else {
$user_id = Actors::BLOG_USER_ID;
}
}

set_wp_object_state( $data, 'federate' );

$outbox_activity_id = Outbox::add( $activity_object, $activity_type, $user_id, $content_visibility );
Expand Down
7 changes: 4 additions & 3 deletions tests/includes/class-test-signature.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public function test_signature_legacy() {
$this->assertEquals( $key_pair['private_key'], $private_key );

// Check application user.
$user = Actors::get_by_id( -1 );
$user = Actors::get_by_id( Actors::APPLICATION_USER_ID );

$public_key = 'public key ' . $user->get__id();
$private_key = 'private key ' . $user->get__id();
Expand All @@ -73,8 +73,9 @@ public function test_signature_legacy() {
$this->assertEquals( $key_pair['private_key'], $private_key );

// Check blog user.
\define( 'ACTIVITYPUB_DISABLE_BLOG_USER', false );
$user = Actors::get_by_id( 0 );
\update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_AND_BLOG_MODE );
$user = Actors::get_by_id( Actors::BLOG_USER_ID );
\delete_option( 'activitypub_actor_mode' );

$public_key = 'public key ' . $user->get__id();
$private_key = 'private key ' . $user->get__id();
Expand Down
84 changes: 78 additions & 6 deletions tests/includes/collection/class-test-outbox.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,35 @@
*
* @coversDefaultClass \Activitypub\Collection\Outbox
*/
class Test_Outbox extends \Activitypub\Tests\ActivityPub_TestCase_Cache_HTTP {
class Test_Outbox extends \WP_UnitTestCase {
/**
* User ID for testing.
*
* @var int
*/
protected static $user_id;

/**
* Set up test resources.
*/
public static function set_up_before_class() {
parent::set_up_before_class();
self::$user_id = self::factory()->user->create( array( 'role' => 'author' ) );

// Add activitypub capability to the user.
\get_user_by( 'id', self::$user_id )->add_cap( 'activitypub' );

\add_filter( 'pre_schedule_event', '__return_false' );
}

/**
* Clean up test resources.
*/
public static function tear_down_after_class() {
\delete_option( 'activitypub_actor_mode' );
\wp_delete_user( self::$user_id );
\remove_filter( 'pre_schedule_event', '__return_false' );
}

/**
* Test add an item to the outbox.
Expand All @@ -26,11 +54,13 @@ class Test_Outbox extends \Activitypub\Tests\ActivityPub_TestCase_Cache_HTTP {
* @param string $json The JSON representation of the data.
*/
public function test_add( $data, $type, $user_id, $json ) {
\update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_AND_BLOG_MODE );

$id = \Activitypub\add_to_outbox( $data, $type, $user_id );

$this->assertIsInt( $id );

$post = get_post( $id );
$post = \get_post( $id );

$this->assertInstanceOf( 'WP_Post', $post );
$this->assertEquals( 'pending', $post->post_status );
Expand All @@ -39,8 +69,11 @@ public function test_add( $data, $type, $user_id, $json ) {
$activity = json_decode( $post->post_content );
$this->assertSame( $data['content'], $activity->content );

$this->assertEquals( $type, get_post_meta( $id, '_activitypub_activity_type', true ) );
$this->assertEquals( 'user', get_post_meta( $id, '_activitypub_activity_actor', true ) );
$this->assertEquals( $type, \get_post_meta( $id, '_activitypub_activity_type', true ) );

// Fall back to blog if user does not have the activitypub capability.
$actor_type = \user_can( $user_id, 'activitypub' ) ? 'user' : 'blog';
$this->assertEquals( $actor_type, \get_post_meta( $id, '_activitypub_activity_actor', true ) );
}

/**
Expand All @@ -53,13 +86,13 @@ public function activity_object_provider() {
array(
array(
'@context' => 'https://www.w3.org/ns/activitystreams',
'id' => 'https://example.com/1',
'id' => 'https://example.com/' . self::$user_id,
'type' => 'Note',
'content' => '<p>This is a note</p>',
),
'Create',
1,
'{"@context":["https:\/\/www.w3.org\/ns\/activitystreams",{"Hashtag":"as:Hashtag","sensitive":"as:sensitive"}],"id":"https:\/\/example.com\/1","type":"Note","content":"\u003Cp\u003EThis is a note\u003C\/p\u003E","contentMap":{"en":"\u003Cp\u003EThis is a note\u003C\/p\u003E"},"tag":[],"to":["https:\/\/www.w3.org\/ns\/activitystreams#Public"],"cc":[],"mediaType":"text\/html","sensitive":false}',
'{"@context":["https:\/\/www.w3.org\/ns\/activitystreams",{"Hashtag":"as:Hashtag","sensitive":"as:sensitive"}],"id":"https:\/\/example.com\/' . self::$user_id . '","type":"Note","content":"\u003Cp\u003EThis is a note\u003C\/p\u003E","contentMap":{"en":"\u003Cp\u003EThis is a note\u003C\/p\u003E"},"tag":[],"to":["https:\/\/www.w3.org\/ns\/activitystreams#Public"],"cc":[],"mediaType":"text\/html","sensitive":false}',
),
array(
array(
Expand All @@ -74,4 +107,43 @@ public function activity_object_provider() {
),
);
}

/**
* Test add an item to the outbox with a user.
*
* @covers ::add
* @dataProvider author_object_provider
*
* @param string $mode The actor mode.
* @param int $user_id The user ID.
* @param string $expected_actor The expected actor.
*/
public function test_author_fallbacks( $mode, $user_id, $expected_actor ) {
\update_option( 'activitypub_actor_mode', $mode );

$user_id = $user_id ?? self::$user_id;
$data = array(
'@context' => 'https://www.w3.org/ns/activitystreams',
'id' => 'https://example.com/' . $user_id,
'type' => 'Note',
'content' => '<p>This is a note</p>',
);

$id = \Activitypub\add_to_outbox( $data, 'Create', $user_id );
$this->assertEquals( $expected_actor, \get_post_meta( $id, '_activitypub_activity_actor', true ) );
}

/**
* Data provider for test_author_fallbacks.
*
* @return array[]
*/
public function author_object_provider() {
return array(
array( ACTIVITYPUB_ACTOR_AND_BLOG_MODE, self::$user_id, 'user' ), // Not sure why we can't access self::$user_id directly.
array( ACTIVITYPUB_ACTOR_AND_BLOG_MODE, 90210, 'blog' ),
array( ACTIVITYPUB_BLOG_MODE, 90210, 'blog' ),
array( ACTIVITYPUB_ACTOR_MODE, 90210, false ),
);
}
}
4 changes: 2 additions & 2 deletions tests/includes/scheduler/class-test-actor.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ public function test_user_update() {
* @covers ::blog_user_update
*/
public function test_blog_user_update() {
\update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_AND_BLOG_MODE );
$test_value = 'test value';
$result = \Activitypub\Scheduler\Actor::blog_user_update( $test_value );

Expand Down Expand Up @@ -160,7 +161,7 @@ public function test_schedule_post_activity_extra_fields() {
* @covers ::schedule_post_activity
*/
public function test_schedule_post_activity_extra_field_blog() {
\update_option( 'activitypub_actor_mode', ACTIVITYPUB_BLOG_MODE );
\update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_AND_BLOG_MODE );
$blog_post_id = self::factory()->post->create( array( 'post_type' => Extra_Fields::BLOG_POST_TYPE ) );
$activitpub_id = Actors::get_by_id( Actors::BLOG_USER_ID )->get_id();

Expand All @@ -169,6 +170,5 @@ public function test_schedule_post_activity_extra_field_blog() {

// Clean up.
\wp_delete_post( $blog_post_id, true );
\update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_AND_BLOG_MODE );
}
}
2 changes: 1 addition & 1 deletion tests/includes/scheduler/class-test-post.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class Test_Post extends \Activitypub\Tests\ActivityPub_Outbox_TestCase {
* @covers ::schedule_post_activity
*/
public function test_schedule_post_activity_regular_post() {
$post_id = self::factory()->post->create();
$post_id = self::factory()->post->create( array( 'post_author' => self::$user_id ) );
$activitpub_id = \add_query_arg( 'p', $post_id, \home_url( '/' ) );

$post = $this->get_latest_outbox_item( $activitpub_id );
Expand Down

0 comments on commit 0dce338

Please sign in to comment.