improve request validation and added blacklist check
This commit is contained in:
parent
0d48496768
commit
385aac3568
3 changed files with 88 additions and 90 deletions
|
@ -66,6 +66,11 @@ function init() {
|
|||
|
||||
require_once \dirname( __FILE__ ) . '/includes/class-health-check.php';
|
||||
\Activitypub\Health_Check::init();
|
||||
|
||||
require_once \dirname( __FILE__ ) . '/includes/rest/class-server.php';
|
||||
\add_filter( 'wp_rest_server_class', function() {
|
||||
return '\Activitypub\Rest\Server';
|
||||
} );
|
||||
}
|
||||
add_action( 'plugins_loaded', '\Activitypub\init' );
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ class Inbox {
|
|||
*/
|
||||
public static function init() {
|
||||
\add_action( 'rest_api_init', array( '\Activitypub\Rest\Inbox', 'register_routes' ) );
|
||||
//\add_filter( 'rest_pre_serve_request', array( '\Activitypub\Rest\Inbox', 'serve_request' ), 11, 4 );
|
||||
\add_filter( 'rest_pre_serve_request', array( '\Activitypub\Rest\Inbox', 'serve_request' ), 11, 4 );
|
||||
\add_action( 'activitypub_inbox_follow', array( '\Activitypub\Rest\Inbox', 'handle_follow' ), 10, 2 );
|
||||
\add_action( 'activitypub_inbox_unfollow', array( '\Activitypub\Rest\Inbox', 'handle_unfollow' ), 10, 2 );
|
||||
//\add_action( 'activitypub_inbox_like', array( '\Activitypub\Rest\Inbox', 'handle_reaction' ), 10, 2 );
|
||||
|
@ -36,7 +36,7 @@ class Inbox {
|
|||
);
|
||||
|
||||
\register_rest_route(
|
||||
'activitypub/1.0', '/users/(?P<id>\d+)/inbox', array(
|
||||
'activitypub/1.0', '/users/(?P<user_id>\d+)/inbox', array(
|
||||
array(
|
||||
'methods' => \WP_REST_Server::EDITABLE,
|
||||
'callback' => array( '\Activitypub\Rest\Inbox', 'user_inbox' ),
|
||||
|
@ -61,10 +61,6 @@ class Inbox {
|
|||
return $served;
|
||||
}
|
||||
|
||||
if ( 'POST' !== $request->get_method() ) {
|
||||
return $served;
|
||||
}
|
||||
|
||||
$signature = $request->get_header( 'signature' );
|
||||
|
||||
if ( ! $signature ) {
|
||||
|
@ -73,6 +69,7 @@ class Inbox {
|
|||
|
||||
$headers = $request->get_headers();
|
||||
|
||||
// verify signature
|
||||
//\Activitypub\Signature::verify_signature( $headers, $key );
|
||||
|
||||
return $served;
|
||||
|
@ -86,21 +83,13 @@ class Inbox {
|
|||
* @return WP_REST_Response
|
||||
*/
|
||||
public static function user_inbox( $request ) {
|
||||
$author_id = $request->get_param( 'id' );
|
||||
$user_id = $request->get_param( 'user_id' );
|
||||
|
||||
$data = \json_decode( $request->get_body(), true );
|
||||
$data = $request->get_params();
|
||||
$type = $request->get_param( 'type' );
|
||||
|
||||
if ( ! \is_array( $data ) || ! \array_key_exists( 'type', $data ) ) {
|
||||
return new \WP_Error( 'rest_invalid_data', \__( 'Invalid payload', 'activitypub' ), array( 'status' => 422 ) );
|
||||
}
|
||||
|
||||
$type = 'create';
|
||||
if ( ! empty( $data['type'] ) ) {
|
||||
$type = \strtolower( $data['type'] );
|
||||
}
|
||||
|
||||
\do_action( 'activitypub_inbox', $data, $author_id, $type );
|
||||
\do_action( "activitypub_inbox_{$type}", $data, $author_id );
|
||||
\do_action( 'activitypub_inbox', $data, $user_id, $type );
|
||||
\do_action( "activitypub_inbox_{$type}", $data, $user_id );
|
||||
|
||||
return new \WP_REST_Response( array(), 202 );
|
||||
}
|
||||
|
@ -113,61 +102,7 @@ class Inbox {
|
|||
* @return WP_Error not yet implemented
|
||||
*/
|
||||
public static function shared_inbox( $request ) {
|
||||
$data = \json_decode( $request->get_body(), true );
|
||||
|
||||
if ( empty( $data['to'] ) ) {
|
||||
return new \WP_Error( 'rest_invalid_data', \__( 'No receiving actor set', 'activitypub' ), array( 'status' => 422 ) );
|
||||
}
|
||||
|
||||
if ( \filter_var( $data['to'], \FILTER_VALIDATE_URL ) ) {
|
||||
$author_id = \Activitypub\url_to_authorid( $data['to'] );
|
||||
|
||||
if ( ! $author_id ) {
|
||||
return new \WP_Error( 'rest_invalid_data', \__( 'No matching user', 'activitypub' ), array( 'status' => 422 ) );
|
||||
}
|
||||
} else {
|
||||
// get the identifier at the left of the '@'
|
||||
$parts = \explode( '@', $data['to'] );
|
||||
|
||||
if ( 3 === \count( $parts ) ) {
|
||||
$username = $parts[1];
|
||||
$host = $parts[2];
|
||||
} elseif ( 2 === \count( $parts ) ) {
|
||||
$username = $parts[0];
|
||||
$host = $parts[1];
|
||||
}
|
||||
|
||||
if ( ! $username || ! $host ) {
|
||||
return new \WP_Error( 'rest_invalid_data', \__( 'Invalid actor identifier', 'activitypub' ), array( 'status' => 422 ) );
|
||||
}
|
||||
|
||||
// check domain
|
||||
if ( ! \wp_parse_url( \home_url(), \PHP_URL_HOST ) !== $host ) {
|
||||
return new \WP_Error( 'rest_invalid_data', \__( 'Invalid host', 'activitypub' ), array( 'status' => 422 ) );
|
||||
}
|
||||
|
||||
$author = \get_user_by( 'login', $username );
|
||||
|
||||
if ( ! $author ) {
|
||||
return new \WP_Error( 'rest_invalid_data', \__( 'No matching user', 'activitypub' ), array( 'status' => 422 ) );
|
||||
}
|
||||
|
||||
$author_id = $author->ID;
|
||||
}
|
||||
|
||||
if ( ! \is_array( $data ) || ! \array_key_exists( 'type', $data ) ) {
|
||||
return new \WP_Error( 'rest_invalid_data', \__( 'Invalid payload', 'activitypub' ), array( 'status' => 422 ) );
|
||||
}
|
||||
|
||||
$type = 'create';
|
||||
if ( ! empty( $data['type'] ) ) {
|
||||
$type = \strtolower( $data['type'] );
|
||||
}
|
||||
|
||||
\do_action( 'activitypub_inbox', $data, $author_id, $type );
|
||||
\do_action( "activitypub_inbox_{$type}", $data, $author_id );
|
||||
|
||||
return new \WP_REST_Response( array(), 202 );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -182,11 +117,54 @@ class Inbox {
|
|||
'type' => 'integer',
|
||||
);
|
||||
|
||||
$params['id'] = array(
|
||||
$params['user_id'] = array(
|
||||
'required' => true,
|
||||
'type' => 'integer',
|
||||
);
|
||||
|
||||
$params['id'] = array(
|
||||
'required' => true,
|
||||
'type' => 'string',
|
||||
'validate_callback' => function( $param, $request, $key ) {
|
||||
if ( ! is_string( $param ) ) {
|
||||
$param = $param['id'];
|
||||
}
|
||||
return ! \Activitypub\is_blacklisted( $param );
|
||||
},
|
||||
'sanitize_callback' => 'esc_url_raw',
|
||||
);
|
||||
|
||||
$params['actor'] = array(
|
||||
'required' => true,
|
||||
'type' => array( 'object', 'string' ),
|
||||
'validate_callback' => function( $param, $request, $key ) {
|
||||
if ( ! is_string( $param ) ) {
|
||||
$param = $param['id'];
|
||||
}
|
||||
return ! \Activitypub\is_blacklisted( $param );
|
||||
},
|
||||
'sanitize_callback' => function( $param, $request, $key ) {
|
||||
if ( ! is_string( $param ) ) {
|
||||
$param = $param['id'];
|
||||
}
|
||||
return \esc_url_raw( $param );
|
||||
},
|
||||
);
|
||||
|
||||
$params['type'] = array(
|
||||
'required' => true,
|
||||
'type' => 'enum',
|
||||
'enum' => array( 'Create' ),
|
||||
'sanitize_callback' => function( $param, $request, $key ) {
|
||||
return \strtolower( $param );
|
||||
},
|
||||
);
|
||||
|
||||
$params['object'] = array(
|
||||
'required' => true,
|
||||
'type' => 'object',
|
||||
);
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
|
@ -197,10 +175,6 @@ class Inbox {
|
|||
* @param int $user_id The id of the local blog-user
|
||||
*/
|
||||
public static function handle_follow( $object, $user_id ) {
|
||||
if ( ! \array_key_exists( 'actor', $object ) ) {
|
||||
return new \WP_Error( 'activitypub_no_actor', __( 'No "Actor" found', 'activitypub' ) );
|
||||
}
|
||||
|
||||
// save follower
|
||||
\Activitypub\Peer\Followers::add_follower( $object['actor'], $user_id );
|
||||
|
||||
|
@ -226,10 +200,6 @@ class Inbox {
|
|||
* @param int $user_id The id of the local blog-user
|
||||
*/
|
||||
public static function handle_unfollow( $object, $user_id ) {
|
||||
if ( ! \array_key_exists( 'actor', $object ) ) {
|
||||
return new \WP_Error( 'activitypub_no_actor', \__( 'No "Actor" found', 'activitypub' ) );
|
||||
}
|
||||
|
||||
\Activitypub\Peer\Followers::remove_follower( $object['actor'], $user_id );
|
||||
}
|
||||
|
||||
|
@ -240,10 +210,6 @@ class Inbox {
|
|||
* @param int $user_id The id of the local blog-user
|
||||
*/
|
||||
public static function handle_reaction( $object, $user_id ) {
|
||||
if ( ! \array_key_exists( 'actor', $object ) ) {
|
||||
return new \WP_Error( 'activitypub_no_actor', \__( 'No "Actor" found', 'activitypub' ) );
|
||||
}
|
||||
|
||||
$meta = \Activitypub\get_remote_metadata_by_actor( $object['actor'] );
|
||||
|
||||
$commentdata = array(
|
||||
|
@ -277,10 +243,6 @@ class Inbox {
|
|||
* @param int $user_id The id of the local blog-user
|
||||
*/
|
||||
public static function handle_create( $object, $user_id ) {
|
||||
if ( ! \array_key_exists( 'actor', $object ) ) {
|
||||
return new \WP_Error( 'activitypub_no_actor', __( 'No "Actor" found', 'activitypub' ) );
|
||||
}
|
||||
|
||||
$meta = \Activitypub\get_remote_metadata_by_actor( $object['actor'] );
|
||||
|
||||
$commentdata = array(
|
||||
|
|
31
includes/rest/class-server.php
Normal file
31
includes/rest/class-server.php
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
namespace Activitypub\Rest;
|
||||
|
||||
/**
|
||||
* Custom (hopefully temporary) ActivityPub Rest Server
|
||||
*
|
||||
* @author Matthias Pfefferle
|
||||
*/
|
||||
class Server extends \WP_REST_Server {
|
||||
/**
|
||||
* Overwrite dispatch function to quick fix missing subtype featur
|
||||
*
|
||||
* @see https://core.trac.wordpress.org/ticket/49404
|
||||
*
|
||||
* @param WP_REST_Request $request Request to attempt dispatching.
|
||||
* @return WP_REST_Response Response returned by the callback.
|
||||
*/
|
||||
public function dispatch( $request ) {
|
||||
$content_type = $request->get_content_type();
|
||||
|
||||
// check for content-sub-types like 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'
|
||||
if ( preg_match( '/application\/([a-zA-Z+_-]+\+)json/', $content_type['value'] ) ) {
|
||||
$request->set_header( 'Content-Type', 'application/json' );
|
||||
}
|
||||
|
||||
// make request filterable
|
||||
$request = apply_filters( 'activitypub_pre_dispatch_request', $request );
|
||||
|
||||
return parent::dispatch( $request );
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue