Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
FROM php:7.4-alpine3.13

RUN mkdir /app

WORKDIR /app

# Install Git, NPM & needed libraries
RUN apk update \
&& apk add bash git nodejs npm gettext subversion mysql mysql-client zip \
&& rm -f /var/cache/apk/*

RUN docker-php-ext-install mysqli

# Install Composer
RUN EXPECTED_CHECKSUM=$(curl -s https://composer.github.io/installer.sig) \
&& curl https://getcomposer.org/installer -o composer-setup.php \
&& ACTUAL_CHECKSUM="$(php -r "echo hash_file('sha384', 'composer-setup.php');")" \
&& if [ "$EXPECTED_CHECKSUM" != "$ACTUAL_CHECKSUM" ]; then >&2 echo 'ERROR: Invalid installer checksum'; rm composer-setup.php; exit 1; fi \
&& php composer-setup.php --quiet \
&& php -r "unlink('composer-setup.php');" \
&& mv composer.phar /usr/local/bin/composer

RUN curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar && \
chmod +x wp-cli.phar && \
mv wp-cli.phar /usr/local/bin/wp

RUN chmod +x -R ./
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
**Tags:** OStatus, fediverse, activitypub, activitystream
**Requires at least:** 4.7
**Tested up to:** 6.1
**Stable tag:** 0.14.3
**Stable tag:** 0.15.0
**Requires PHP:** 5.6
**License:** MIT
**License URI:** http://opensource.org/licenses/MIT
Expand Down Expand Up @@ -88,6 +88,12 @@ Where 'blog' is the path to the subdirectory at which your blog resides.

Project maintained on GitHub at [pfefferle/wordpress-activitypub](https://github.com/pfefferle/wordpress-activitypub).

### 0.15.0 ###

* Enable ActivityPub only for users that can `publish_posts`
* Persist only public Activities
* Fix remote-delete

### 0.14.3 ###

* Better error handling. props [@akirk](https://github.com/akirk)
Expand Down
2 changes: 1 addition & 1 deletion activitypub.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Plugin Name: ActivityPub
* Plugin URI: https://github.com/pfefferle/wordpress-activitypub/
* Description: The ActivityPub protocol is a decentralized social networking protocol based upon the ActivityStreams 2.0 data format.
* Version: 0.14.3
* Version: 0.15.0
* Author: Matthias Pfefferle
* Author URI: https://notiz.blog/
* License: MIT
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"scripts": {
"test": [
"composer install",
"bin/install-wp-tests.sh wordpress wordpress wordpress",
"bin/install-wp-tests.sh activitypub-test root activitypub-test test-db latest true",
"vendor/bin/phpunit"
]
}
Expand Down
17 changes: 17 additions & 0 deletions docker-compose-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
version: '2'
services:
test-db:
image: mysql:5.7
environment:
MYSQL_DATABASE: activitypub-test
MYSQL_ROOT_PASSWORD: activitypub-test

test-php:
build:
context: .
dockerfile: Dockerfile
links:
- test-db
volumes:
- .:/app
command: ["composer", "run-script", "test"]
29 changes: 29 additions & 0 deletions includes/class-activitypub.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ public static function init() {
}

\add_action( 'transition_post_status', array( '\Activitypub\Activitypub', 'schedule_post_activity' ), 10, 3 );
\add_action( 'wp_trash_post', array( '\Activitypub\Activitypub', 'trash_post' ), 1 );
\add_action( 'untrash_post', array( '\Activitypub\Activitypub', 'untrash_post' ), 1 );
}

/**
Expand All @@ -38,6 +40,11 @@ public static function render_json_template( $template ) {
return $template;
}

// check if user can publish posts
if ( \is_author() && ! user_can( \get_the_author_meta( 'ID' ), 'publish_posts' ) ) {
return $template;
}

if ( \is_author() ) {
$json_template = \dirname( __FILE__ ) . '/../templates/author-json.php';
} elseif ( \is_singular() ) {
Expand Down Expand Up @@ -180,4 +187,26 @@ public static function get_avatar_url( $comment ) {
}
return \get_comment_meta( $comment->comment_ID, 'avatar_url', true );
}

/**
* Store permalink in meta, to send delete Activity
*
* @param string $post_id The Post ID
*
* @return void
*/
public static function trash_post( $post_id ) {
\add_post_meta( $post_id, 'activitypub_canonical_url', \get_permalink( $post_id ), true );
}

/**
* Delete permalink from meta
*
* @param string $post_id The Post ID
*
* @return void
*/
public static function untrash_post( $post_id ) {
\delete_post_meta( $post_id, 'activitypub_canonical_url' );
}
}
12 changes: 8 additions & 4 deletions includes/model/class-post.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,15 @@ public function to_json() {
}

public function generate_id() {
$post = $this->post;
$permalink = \get_permalink( $post );
$post = $this->post;

if ( 'trash' === get_post_status( $post ) ) {
$permalink = \get_post_meta( $post->ID, 'activitypub_canonical_url', true );
} else {
$permalink = \get_permalink( $post );
}

// replace 'trashed' for delete activity
return \str_replace( '__trashed', '', $permalink );
return $permalink;
}

public function generate_attachments() {
Expand Down
3 changes: 3 additions & 0 deletions includes/rest/class-followers.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,9 @@ public static function request_parameters() {
$params['user_id'] = array(
'required' => true,
'type' => 'integer',
'validate_callback' => function( $param, $request, $key ) {
return user_can( $param, 'publish_posts' );
},
);

return $params;
Expand Down
3 changes: 3 additions & 0 deletions includes/rest/class-following.php
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ public static function request_parameters() {
$params['user_id'] = array(
'required' => true,
'type' => 'integer',
'validate_callback' => function( $param, $request, $key ) {
return user_can( $param, 'publish_posts' );
},
);

return $params;
Expand Down
95 changes: 86 additions & 9 deletions includes/rest/class-inbox.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public static function register_routes() {
array(
'methods' => \WP_REST_Server::EDITABLE,
'callback' => array( '\Activitypub\Rest\Inbox', 'shared_inbox_post' ),
'args' => self::shared_inbox_request_parameters(),
'args' => self::shared_inbox_post_parameters(),
'permission_callback' => '__return_true',
),
)
Expand All @@ -46,12 +46,13 @@ public static function register_routes() {
array(
'methods' => \WP_REST_Server::EDITABLE,
'callback' => array( '\Activitypub\Rest\Inbox', 'user_inbox_post' ),
'args' => self::user_inbox_request_parameters(),
'args' => self::user_inbox_post_parameters(),
'permission_callback' => '__return_true',
),
array(
'methods' => \WP_REST_Server::READABLE,
'callback' => array( '\Activitypub\Rest\Inbox', 'user_inbox_get' ),
'args' => self::user_inbox_get_parameters(),
'permission_callback' => '__return_true',
),
)
Expand Down Expand Up @@ -195,7 +196,7 @@ public static function shared_inbox_post( $request ) {
*
* @return array list of parameters
*/
public static function user_inbox_request_parameters() {
public static function user_inbox_get_parameters() {
$params = array();

$params['page'] = array(
Expand All @@ -205,6 +206,32 @@ public static function user_inbox_request_parameters() {
$params['user_id'] = array(
'required' => true,
'type' => 'integer',
'validate_callback' => function( $param, $request, $key ) {
return user_can( $param, 'publish_posts' );
},
);

return $params;
}

/**
* The supported parameters
*
* @return array list of parameters
*/
public static function user_inbox_post_parameters() {
$params = array();

$params['page'] = array(
'type' => 'integer',
);

$params['user_id'] = array(
'required' => true,
'type' => 'integer',
'validate_callback' => function( $param, $request, $key ) {
return user_can( $param, 'publish_posts' );
},
);

$params['id'] = array(
Expand Down Expand Up @@ -243,7 +270,7 @@ public static function user_inbox_request_parameters() {
*
* @return array list of parameters
*/
public static function shared_inbox_request_parameters() {
public static function shared_inbox_post_parameters() {
$params = array();

$params['page'] = array(
Expand Down Expand Up @@ -410,6 +437,12 @@ public static function handle_create( $object, $user_id ) {
return;
}

// check if Activity is public or not
if ( ! self::is_activity_public( $object ) ) {
// @todo maybe send email
return;
}

$comment_post_id = \url_to_postid( $object['object']['inReplyTo'] );

// save only replys and reactions
Expand Down Expand Up @@ -446,21 +479,53 @@ public static function handle_create( $object, $user_id ) {
\add_action( 'check_comment_flood', 'check_comment_flood_db', 10, 4 );
}

/**
* Extract recipient URLs from Activity object
*
* @param array $data
*
* @return array The list of user URLs
*/
public static function extract_recipients( $data ) {
$recipients = array();
$users = array();
$recipient_items = array();

foreach ( array( 'to', 'bto', 'cc', 'bcc', 'audience' ) as $i ) {
if ( array_key_exists( $i, $data ) ) {
$recipients = array_merge( $recipients, $data[ $i ] );
$recipient_items = array_merge( $recipient_items, $data[ $i ] );
}

if ( array_key_exists( $i, $data['object'] ) ) {
$recipients = array_merge( $recipients, $data[ $i ] );
$recipient_items = array_merge( $recipient_items, $data[ $i ] );
}
}

$recipients = array();

// flatten array
foreach ( $recipient_items as $recipient ) {
if ( is_array( $recipient ) ) {
// check if recipient is an object
if ( array_key_exists( 'id', $recipient ) ) {
$recipients[] = $recipient['id'];
}
} else {
$recipients[] = $recipient;
}
}

$recipients = array_unique( $recipients );
return array_unique( $recipients );
}

/**
* Get local user recipients
*
* @param array $data
*
* @return array The list of local users
*/
public static function get_recipients( $data ) {
$recipients = self::extract_recipients( $data );
$users = array();

foreach ( $recipients as $recipient ) {
$user_id = \Activitypub\url_to_authorid( $recipient );
Expand All @@ -474,4 +539,16 @@ public static function extract_recipients( $data ) {

return $users;
}

/**
* Check if passed Activity is Public
*
* @param array $data
* @return boolean
*/
public static function is_activity_public( $data ) {
$recipients = self::extract_recipients( $data );

return in_array( 'https://www.w3.org/ns/activitystreams#Public', $recipients, true );
}
}
3 changes: 3 additions & 0 deletions includes/rest/class-outbox.php
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,9 @@ public static function request_parameters() {
$params['user_id'] = array(
'required' => true,
'type' => 'integer',
'validate_callback' => function( $param, $request, $key ) {
return user_can( $param, 'publish_posts' );
},
);

return $params;
Expand Down
2 changes: 1 addition & 1 deletion includes/rest/class-webfinger.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public static function webfinger( $request ) {

$user = \get_user_by( 'login', \esc_sql( $resource_identifier ) );

if ( ! $user ) {
if ( ! $user || ! user_can( $user, 'publish_posts' ) ) {
return new \WP_Error( 'activitypub_user_not_found', \__( 'User not found', 'activitypub' ), array( 'status' => 404 ) );
}

Expand Down
2 changes: 1 addition & 1 deletion phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
convertWarningsToExceptions="true"
>
<testsuites>
<testsuite>
<testsuite name="ActivityPub">
<directory prefix="test-" suffix=".php">./tests/</directory>
</testsuite>
</testsuites>
Expand Down
8 changes: 7 additions & 1 deletion readme.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Donate link: https://notiz.blog/donate/
Tags: OStatus, fediverse, activitypub, activitystream
Requires at least: 4.7
Tested up to: 6.1
Stable tag: 0.14.3
Stable tag: 0.15.0
Requires PHP: 5.6
License: MIT
License URI: http://opensource.org/licenses/MIT
Expand Down Expand Up @@ -88,6 +88,12 @@ Where 'blog' is the path to the subdirectory at which your blog resides.

Project maintained on GitHub at [pfefferle/wordpress-activitypub](https://github.com/pfefferle/wordpress-activitypub).

= 0.15.0 =

* Enable ActivityPub only for users that can `publish_posts`
* Persist only public Activities
* Fix remote-delete

= 0.14.3 =

* Better error handling. props [@akirk](https://github.com/akirk)
Expand Down
2 changes: 1 addition & 1 deletion templates/blog-json.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
$json->publicKey = array(
'id' => \get_home_url( '/' ) . '#main-key',
'owner' => \get_home_url( '/' ),
'publicKeyPem' => \trim(),
'publicKeyPem' => '',
);

$json->tag = array();
Expand Down