Optimize verification code and returns WP_Errors
This commit is contained in:
parent
7dbce74a96
commit
f396c6da4e
4 changed files with 70 additions and 16 deletions
|
@ -57,6 +57,9 @@ function init() {
|
||||||
require_once \dirname( __FILE__ ) . '/includes/rest/class-following.php';
|
require_once \dirname( __FILE__ ) . '/includes/rest/class-following.php';
|
||||||
Rest\Following::init();
|
Rest\Following::init();
|
||||||
|
|
||||||
|
require_once \dirname( __FILE__ ) . '/includes/rest/class-server.php';
|
||||||
|
\Activitypub\Rest\Server::init();
|
||||||
|
|
||||||
require_once \dirname( __FILE__ ) . '/includes/rest/class-webfinger.php';
|
require_once \dirname( __FILE__ ) . '/includes/rest/class-webfinger.php';
|
||||||
Rest\Webfinger::init();
|
Rest\Webfinger::init();
|
||||||
|
|
||||||
|
|
|
@ -114,7 +114,7 @@ class Signature {
|
||||||
$headers = $request->get_headers();
|
$headers = $request->get_headers();
|
||||||
|
|
||||||
if ( ! $headers ) {
|
if ( ! $headers ) {
|
||||||
return false;
|
return new \WP_Error( 'activitypub_signature', 'Request not signed', array( 'status' => 403 ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
$actor = isset( json_decode( $request->get_body() )->actor ) ? json_decode( $request->get_body() )->actor : '';
|
$actor = isset( json_decode( $request->get_body() )->actor ) ? json_decode( $request->get_body() )->actor : '';
|
||||||
|
@ -127,7 +127,7 @@ class Signature {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ! isset( $signature_block ) || ! $signature_block ) {
|
if ( ! isset( $signature_block ) || ! $signature_block ) {
|
||||||
return false;
|
return new \WP_Error( 'activitypub_signature', 'Incompatible request signature. keyId and signature are required', array( 'status' => 403 ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
$signed_headers = $signature_block['headers'];
|
$signed_headers = $signature_block['headers'];
|
||||||
|
@ -137,12 +137,12 @@ class Signature {
|
||||||
|
|
||||||
$signed_data = self::get_signed_data( $signed_headers, $signature_block, $headers );
|
$signed_data = self::get_signed_data( $signed_headers, $signature_block, $headers );
|
||||||
if ( ! $signed_data ) {
|
if ( ! $signed_data ) {
|
||||||
return false;
|
return new \WP_Error( 'activitypub_signature', 'Signed request date outside acceptable time window', array( 'status' => 403 ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
$algorithm = self::get_signature_algorithm( $signature_block );
|
$algorithm = self::get_signature_algorithm( $signature_block );
|
||||||
if ( ! $algorithm ) {
|
if ( ! $algorithm ) {
|
||||||
return false;
|
return new \WP_Error( 'activitypub_signature', 'Unsupported signature algorithm (only rsa-sha256 and hs2019 are supported)', array( 'status' => 403 ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( \in_array( 'digest', $signed_headers, true ) && isset( $body ) ) {
|
if ( \in_array( 'digest', $signed_headers, true ) && isset( $body ) ) {
|
||||||
|
@ -158,13 +158,17 @@ class Signature {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( \base64_encode( \hash( $hashalg, $body, true ) ) !== $digest[1] ) { // phpcs:ignore
|
if ( \base64_encode( \hash( $hashalg, $body, true ) ) !== $digest[1] ) { // phpcs:ignore
|
||||||
return false;
|
return new \WP_Error( 'activitypub_signature', 'Invalid Digest header', array( 'status' => 403 ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$public_key = \rtrim( \Activitypub\get_publickey_by_actor( $actor, $signature_block['keyId'] ) ); // phpcs:ignore
|
$public_key = \Activitypub\get_publickey_by_actor( $actor, $signature_block['keyId'] ); // phpcs:ignore
|
||||||
|
if ( \is_wp_error( $public_key ) ) {
|
||||||
return \openssl_verify( $signed_data, $signature_block['signature'], $public_key, $algorithm ) > 0;
|
return $public_key;
|
||||||
|
} else {
|
||||||
|
$public_key = \rtrim( $public_key );
|
||||||
|
}
|
||||||
|
return \openssl_verify( $signed_data, $signature_block['signature'], $public_key, $algorithm ) > 0 ?? new \WP_Error( 'activitypub_signature', 'Invalid signature', array( 'status' => 403 ) );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -134,10 +134,6 @@ class Inbox {
|
||||||
* @return WP_REST_Response
|
* @return WP_REST_Response
|
||||||
*/
|
*/
|
||||||
public static function user_inbox_post( $request ) {
|
public static function user_inbox_post( $request ) {
|
||||||
// SecureMode/Authorized fetch.
|
|
||||||
if ( ! \Activitypub\Signature::verify_http_signature( $request ) ) {
|
|
||||||
return new \WP_REST_Response( array(), 403 );
|
|
||||||
}
|
|
||||||
|
|
||||||
$user_id = $request->get_param( 'user_id' );
|
$user_id = $request->get_param( 'user_id' );
|
||||||
|
|
||||||
|
@ -159,10 +155,6 @@ class Inbox {
|
||||||
* @return WP_REST_Response
|
* @return WP_REST_Response
|
||||||
*/
|
*/
|
||||||
public static function shared_inbox_post( $request ) {
|
public static function shared_inbox_post( $request ) {
|
||||||
// SecureMode/Authorized fetch.
|
|
||||||
if ( ! \Activitypub\Signature::verify_http_signature( $request ) ) {
|
|
||||||
return new \WP_REST_Response( array(), 403 );
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = $request->get_params();
|
$data = $request->get_params();
|
||||||
$type = $request->get_param( 'type' );
|
$type = $request->get_param( 'type' );
|
||||||
|
|
55
includes/rest/class-server.php
Normal file
55
includes/rest/class-server.php
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
<?php
|
||||||
|
namespace Activitypub\Rest;
|
||||||
|
|
||||||
|
use Activitypub\Signature;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ActivityPub Server REST-Class
|
||||||
|
*
|
||||||
|
* @author Django Doucet
|
||||||
|
*
|
||||||
|
* @see https://www.w3.org/TR/activitypub/#security-verification
|
||||||
|
*/
|
||||||
|
class Server {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the class, registering WordPress hooks
|
||||||
|
*/
|
||||||
|
public static function init() {
|
||||||
|
\add_filter( 'rest_request_before_callbacks', array( '\Activitypub\Rest\Server', 'authorize_activitypub_requests' ), 10, 3 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback function to authorize each api requests
|
||||||
|
*
|
||||||
|
* @see \WP_REST_Request
|
||||||
|
*
|
||||||
|
* @param $response
|
||||||
|
* @param $handler
|
||||||
|
* @param \WP_REST_Request $request
|
||||||
|
*
|
||||||
|
* @return mixed|\WP_Error
|
||||||
|
*/
|
||||||
|
public static function authorize_activitypub_requests( $response, $handler, $request ) {
|
||||||
|
|
||||||
|
$maybe_activitypub = $request->get_route();
|
||||||
|
if ( str_starts_with( $maybe_activitypub, '/activitypub' ) ) {
|
||||||
|
if ( 'POST' === $request->get_method() ) {
|
||||||
|
$verified_request = Signature::verify_http_signature( $request );
|
||||||
|
|
||||||
|
if ( \is_wp_error( $verified_request ) ) {
|
||||||
|
return $verified_request;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// SecureMode/Authorized fetch.
|
||||||
|
$secure_mode = \get_option( 'activitypub_use_secure_mode', '0' );
|
||||||
|
|
||||||
|
if ( $secure_mode ) {
|
||||||
|
if ( \is_wp_error( $verified_request ) ) {
|
||||||
|
return $verified_request;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue