Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a parser to the Friends Plugin #172

Merged
merged 19 commits into from
Dec 5, 2022
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ composer.lock
.DS_Store
.idea/
.php_cs.cache
.phpunit.result.cache

8 changes: 8 additions & 0 deletions activitypub.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,11 @@ function enable_buddypress_features() {
\Activitypub\Integration\Buddypress::init();
}
add_action( 'bp_include', '\Activitypub\enable_buddypress_features' );

add_action(
'friends_load_parsers',
function( \Friends\Feed $friends_feed ) {
require_once __DIR__ . '/integration/class-friends-feed-parser-activitypub.php';
$friends_feed->register_parser( Friends_Feed_Parser_ActivityPub::SLUG, new Friends_Feed_Parser_ActivityPub( $friends_feed ) );
}
);
63 changes: 22 additions & 41 deletions includes/class-health-check.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<?php
namespace Activitypub;

use Activitypub\Rest\Webfinger;

/**
* ActivityPub Health_Check Class
*
Expand Down Expand Up @@ -198,58 +200,37 @@ public static function is_author_url_accessible() {
* @return boolean|WP_Error
*/
public static function is_webfinger_endpoint_accessible() {
$user = \wp_get_current_user();
$webfinger = \Activitypub\get_webfinger_resource( $user->ID );

$url = \wp_parse_url( \home_url(), \PHP_URL_SCHEME ) . '://' . \wp_parse_url( \home_url(), \PHP_URL_HOST );

if ( \wp_parse_url( \home_url(), \PHP_URL_PORT ) ) {
$url .= ':' . \wp_parse_url( \home_url(), \PHP_URL_PORT );
}

$url = \trailingslashit( $url ) . '.well-known/webfinger';
$user = \wp_get_current_user();
$account = \Activitypub\get_webfinger_resource( $user->ID );

$url = \add_query_arg( 'resource', 'acct:' . $webfinger, $url );

// try to access author URL
$response = \wp_remote_get(
$url,
array(
'headers' => array( 'Accept' => 'application/activity+json' ),
'redirection' => 0,
)
);

if ( \is_wp_error( $response ) ) {
return new \WP_Error(
'webfinger_url_not_accessible',
\sprintf(
$url = Webfinger::resolve( $account );
if ( \is_wp_error( $url ) ) {
$health_messages = array(
'webfinger_url_not_accessible' => \sprintf(
// translators: %s: Author URL
\__(
'<p>Your WebFinger endpoint <code>%s</code> is not accessible. Please check your WordPress setup or permalink structure.</p>',
'activitypub'
),
$url
)
);
}

$response_code = \wp_remote_retrieve_response_code( $response );

// check if response is JSON
$body = \wp_remote_retrieve_body( $response );

if ( ! \is_string( $body ) || ! \is_array( \json_decode( $body, true ) ) ) {
return new \WP_Error(
'webfinger_url_not_accessible',
\sprintf(
$url->get_error_data()
),
'webfinger_url_invalid_response' => \sprintf(
// translators: %s: Author URL
\__(
'<p>Your WebFinger endpoint <code>%s</code> does not return valid JSON for <code>application/jrd+json</code>.</p>',
'activitypub'
),
$url
)
$url->get_error_data()
),
);
$message = null;
if ( isset( $health_messages[ $url->get_error_code() ] ) ) {
$message = $health_messages[ $url->get_error_code() ];
}
return new \WP_Error(
$url->get_error_code(),
$message,
$url->get_error_data()
);
}

Expand Down
6 changes: 3 additions & 3 deletions includes/class-signature.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public static function generate_key_pair( $user_id ) {
\update_user_meta( $user_id, 'magic_sig_public_key', $detail['key'] );
}

public static function generate_signature( $user_id, $url, $date, $digest = null ) {
public static function generate_signature( $user_id, $http_method, $url, $date, $digest = null ) {
$key = self::get_private_key( $user_id );

$url_parts = \wp_parse_url( $url );
Expand All @@ -89,9 +89,9 @@ public static function generate_signature( $user_id, $url, $date, $digest = null
}

if ( ! empty( $digest ) ) {
$signed_string = "(request-target): post $path\nhost: $host\ndate: $date\ndigest: SHA-256=$digest";
$signed_string = "(request-target): $http_method $path\nhost: $host\ndate: $date\ndigest: SHA-256=$digest";
} else {
$signed_string = "(request-target): post $path\nhost: $host\ndate: $date";
$signed_string = "(request-target): $http_method $path\nhost: $host\ndate: $date";
}

$signature = null;
Expand Down
18 changes: 15 additions & 3 deletions includes/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ function get_context() {
function safe_remote_post( $url, $body, $user_id ) {
$date = \gmdate( 'D, d M Y H:i:s T' );
$digest = \Activitypub\Signature::generate_digest( $body );
$signature = \Activitypub\Signature::generate_signature( $user_id, $url, $date, $digest );
$signature = \Activitypub\Signature::generate_signature( $user_id, 'post', $url, $date, $digest );

$wp_version = \get_bloginfo( 'version' );
$user_agent = \apply_filters( 'http_headers_useragent', 'WordPress/' . $wp_version . '; ' . \get_bloginfo( 'url' ) );
Expand Down Expand Up @@ -63,7 +63,7 @@ function safe_remote_post( $url, $body, $user_id ) {

function safe_remote_get( $url, $user_id ) {
$date = \gmdate( 'D, d M Y H:i:s T' );
$signature = \Activitypub\Signature::generate_signature( $user_id, $url, $date );
$signature = \Activitypub\Signature::generate_signature( $user_id, 'get', $url, $date );

$wp_version = \get_bloginfo( 'version' );
$user_agent = \apply_filters( 'http_headers_useragent', 'WordPress/' . $wp_version . '; ' . \get_bloginfo( 'url' ) );
Expand Down Expand Up @@ -108,11 +108,23 @@ function get_webfinger_resource( $user_id ) {
/**
* [get_metadata_by_actor description]
*
* @param sting $actor
* @param string $actor
*
* @return array
*/
function get_remote_metadata_by_actor( $actor ) {
$pre = apply_filters( 'pre_get_remote_metadata_by_actor', false, $actor );
if ( $pre ) {
return $pre;
}
if ( preg_match( '/^@?[^@]+@((?:[a-z0-9-]+\.)+[a-z]+)$/i', $actor ) ) {
$actor = Rest\Webfinger::resolve( $actor );
}

if ( ! $actor ) {
return null;
}

$metadata = \get_transient( 'activitypub_' . $actor );

if ( $metadata ) {
Expand Down
2 changes: 1 addition & 1 deletion includes/model/class-activity.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public function from_remote_array( $array ) {
}

public function to_array() {
$array = \get_object_vars( $this );
$array = array_filter( \get_object_vars( $this ) );

if ( $this->context ) {
$array = array( '@context' => $this->context ) + $array;
Expand Down
5 changes: 4 additions & 1 deletion includes/rest/class-inbox.php
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,6 @@ public static function user_inbox_post( $request ) {
public static function shared_inbox_post( $request ) {
$data = $request->get_params();
$type = $request->get_param( 'type' );

$users = self::extract_recipients( $data );

if ( ! $users ) {
Expand Down Expand Up @@ -407,6 +406,10 @@ public static function handle_reaction( $object, $user_id ) {
public static function handle_create( $object, $user_id ) {
$meta = \Activitypub\get_remote_metadata_by_actor( $object['actor'] );

if ( ! isset( $object['object']['inReplyTo'] ) ) {
return;
}

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

// save only replys and reactions
Expand Down
40 changes: 40 additions & 0 deletions includes/rest/class-webfinger.php
Original file line number Diff line number Diff line change
Expand Up @@ -120,4 +120,44 @@ public static function add_webfinger_discovery( $array, $resource, $user ) {

return $array;
}

public static function resolve( $account ) {
if ( ! preg_match( '/^@?[^@]+@((?:[a-z0-9-]+\.)+[a-z]+)$/i', $account, $m ) ) {
return null;
}
$url = \add_query_arg( 'resource', 'acct:' . ltrim( $account, '@' ), 'https://' . $m[1] . '/.well-known/webfinger' );
if ( ! \wp_http_validate_url( $url ) ) {
return new \WP_Error( 'invalid_webfinger_url', null, $url );
}

// try to access author URL
$response = \wp_remote_get(
$url,
array(
'headers' => array( 'Accept' => 'application/activity+json' ),
'redirection' => 0,
)
);

if ( \is_wp_error( $response ) ) {
return new \WP_Error( 'webfinger_url_not_accessible', null, $url );
}

$response_code = \wp_remote_retrieve_response_code( $response );

$body = \wp_remote_retrieve_body( $response );
$body = \json_decode( $body, true );

if ( ! isset( $body['links'] ) ) {
return new \WP_Error( 'webfinger_url_invalid_response', null, $url );
}

foreach ( $body['links'] as $link ) {
if ( 'self' === $link['rel'] && 'application/activity+json' === $link['type'] ) {
return $link['href'];
}
}

return new \WP_Error( 'webfinger_url_no_activity_pub', null, $body );
}
}
Loading