Add Service actor for signing get requests
This commit is contained in:
parent
3a0fef27e0
commit
27636b62d5
4 changed files with 80 additions and 29 deletions
|
@ -60,9 +60,9 @@ class Http {
|
|||
*
|
||||
* @return array|WP_Error The GET Response or an WP_ERROR
|
||||
*/
|
||||
public static function get( $url, $user_id ) {
|
||||
public static function get( $url ) {
|
||||
$date = \gmdate( 'D, d M Y H:i:s T' );
|
||||
$signature = Signature::generate_signature( $user_id, 'get', $url, $date );
|
||||
$signature = Signature::generate_signature( -1, 'get', $url, $date );
|
||||
|
||||
$wp_version = \get_bloginfo( 'version' );
|
||||
$user_agent = \apply_filters( 'http_headers_useragent', 'WordPress/' . $wp_version . '; ' . \get_bloginfo( 'url' ) );
|
||||
|
|
|
@ -35,14 +35,15 @@ class Signature {
|
|||
* @return mixed
|
||||
*/
|
||||
public static function get_private_key( $user_id, $force = false ) {
|
||||
$key = \get_user_meta( $user_id, 'magic_sig_private_key' );
|
||||
|
||||
if ( $key && ! $force ) {
|
||||
return $key[0];
|
||||
if ( $force ) {
|
||||
self::generate_key_pair( $user_id );
|
||||
}
|
||||
|
||||
self::generate_key_pair( $user_id );
|
||||
$key = \get_user_meta( $user_id, 'magic_sig_private_key' );
|
||||
if ( -1 === $user_id ) {
|
||||
$key = \get_option('activitypub_magic_sig_private_key' );
|
||||
} else {
|
||||
$key = \get_user_meta( $user_id, 'magic_sig_private_key' );
|
||||
}
|
||||
|
||||
return $key[0];
|
||||
}
|
||||
|
@ -63,14 +64,22 @@ class Signature {
|
|||
$priv_key = null;
|
||||
|
||||
\openssl_pkey_export( $key, $priv_key );
|
||||
|
||||
// private key
|
||||
\update_user_meta( $user_id, 'magic_sig_private_key', $priv_key );
|
||||
|
||||
$detail = \openssl_pkey_get_details( $key );
|
||||
|
||||
// public key
|
||||
\update_user_meta( $user_id, 'magic_sig_public_key', $detail['key'] );
|
||||
if ( -1 === $user_id ) {
|
||||
// private key
|
||||
\add_option('activitypub_magic_sig_private_key', $priv_key );
|
||||
|
||||
// public key
|
||||
\add_option('activitypub_magic_sig_public_key', $detail['key'] );
|
||||
|
||||
} else {
|
||||
// private key
|
||||
\update_user_meta( $user_id, 'magic_sig_private_key', $priv_key );
|
||||
|
||||
// public key
|
||||
\update_user_meta( $user_id, 'magic_sig_public_key', $detail['key'] );
|
||||
}
|
||||
}
|
||||
|
||||
public static function generate_signature( $user_id, $http_method, $url, $date, $digest = null ) {
|
||||
|
@ -101,7 +110,11 @@ class Signature {
|
|||
\openssl_sign( $signed_string, $signature, $key, \OPENSSL_ALGO_SHA256 );
|
||||
$signature = \base64_encode( $signature ); // phpcs:ignore
|
||||
|
||||
$key_id = \get_author_posts_url( $user_id ) . '#main-key';
|
||||
if ( -1 === $user_id ) {
|
||||
$key_id = \get_rest_url( null, 'activitypub/1.0/service#main-key' );
|
||||
} else {
|
||||
$key_id = \get_author_posts_url( $user_id ) . '#main-key';
|
||||
}
|
||||
|
||||
if ( ! empty( $digest ) ) {
|
||||
return \sprintf( 'keyId="%s",algorithm="rsa-sha256",headers="(request-target) host date digest",signature="%s"', $key_id, $signature );
|
||||
|
|
|
@ -36,8 +36,8 @@ function safe_remote_post( $url, $body, $user_id ) {
|
|||
return \Activitypub\Http::post( $url, $body, $user_id );
|
||||
}
|
||||
|
||||
function safe_remote_get( $url, $user_id ) {
|
||||
return \Activitypub\Http::get( $url, $user_id );
|
||||
function safe_remote_get( $url ) {
|
||||
return \Activitypub\Http::get( $url );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -88,21 +88,11 @@ function get_remote_metadata_by_actor( $actor ) {
|
|||
return $metadata;
|
||||
}
|
||||
|
||||
$user = \get_users(
|
||||
array(
|
||||
'number' => 1,
|
||||
'capability__in' => array( 'publish_posts' ),
|
||||
'fields' => 'ID',
|
||||
)
|
||||
);
|
||||
|
||||
// we just need any user to generate a request signature
|
||||
$user_id = \reset( $user );
|
||||
$short_timeout = function() {
|
||||
return 3;
|
||||
};
|
||||
add_filter( 'activitypub_remote_get_timeout', $short_timeout );
|
||||
$response = Http::get( $actor, $user_id );
|
||||
$response = Http::get( $actor );
|
||||
remove_filter( 'activitypub_remote_get_timeout', $short_timeout );
|
||||
if ( \is_wp_error( $response ) ) {
|
||||
\set_transient( $transient_key, $response, HOUR_IN_SECONDS ); // Cache the error for a shorter period.
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<?php
|
||||
namespace Activitypub\Rest;
|
||||
|
||||
use WP_REST_Response;
|
||||
use Activitypub\Signature;
|
||||
|
||||
/**
|
||||
|
@ -16,7 +17,54 @@ 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 );
|
||||
\add_filter( 'rest_request_before_callbacks', array( self::class, 'authorize_activitypub_requests' ), 10, 3 );
|
||||
\add_action( 'rest_api_init', array( self::class, 'register_routes' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register routes
|
||||
*/
|
||||
public static function register_routes() {
|
||||
\register_rest_route(
|
||||
'activitypub/1.0',
|
||||
'/service',
|
||||
array(
|
||||
array(
|
||||
'methods' => \WP_REST_Server::READABLE,
|
||||
'callback' => array( self::class, 'service_actor' ),
|
||||
'permission_callback' => '__return_true',
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render Service actor profile
|
||||
*
|
||||
* @return WP_REST_Response
|
||||
*/
|
||||
public static function service_actor() {
|
||||
$json = new \stdClass();
|
||||
|
||||
$json->{'@context'} = \Activitypub\get_context();
|
||||
$json->id = \get_rest_url( null, 'activitypub/1.0/service' );
|
||||
$json->type = 'Application';
|
||||
$json->preferredUsername = parse_url( get_site_url(), PHP_URL_HOST );
|
||||
$json->name = get_bloginfo( 'name' );
|
||||
$json->summary = "ActivityPub service actor";
|
||||
$json->manuallyApprovesFollowers = TRUE;
|
||||
$json->icon = [ get_site_icon_url() ];
|
||||
$json->publicKey = (object) array(
|
||||
'id' => \get_rest_url( null, 'activitypub/1.0/service#main-key' ),
|
||||
'owner' => \get_rest_url( null, 'activitypub/1.0/service' ),
|
||||
'publicKeyPem' => Signature::get_public_key( -1 ),
|
||||
);
|
||||
|
||||
$response = new WP_REST_Response( $json, 200 );
|
||||
|
||||
$response->header( 'Content-Type', 'application/activity+json' );
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue