Skip to content

Commit 229e1cd

Browse files
authored
Merge pull request #172 from akirk/add-friends-plugin-support
Add a parser to the Friends Plugin
2 parents 010ccc7 + f916bca commit 229e1cd

12 files changed

+837
-49
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,5 @@ composer.lock
55
.DS_Store
66
.idea/
77
.php_cs.cache
8+
.phpunit.result.cache
9+

activitypub.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,3 +132,11 @@ function enable_buddypress_features() {
132132
\Activitypub\Integration\Buddypress::init();
133133
}
134134
add_action( 'bp_include', '\Activitypub\enable_buddypress_features' );
135+
136+
add_action(
137+
'friends_load_parsers',
138+
function( \Friends\Feed $friends_feed ) {
139+
require_once __DIR__ . '/integration/class-friends-feed-parser-activitypub.php';
140+
$friends_feed->register_parser( Friends_Feed_Parser_ActivityPub::SLUG, new Friends_Feed_Parser_ActivityPub( $friends_feed ) );
141+
}
142+
);

includes/class-health-check.php

Lines changed: 22 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
<?php
22
namespace Activitypub;
33

4+
use Activitypub\Rest\Webfinger;
5+
46
/**
57
* ActivityPub Health_Check Class
68
*
@@ -198,58 +200,37 @@ public static function is_author_url_accessible() {
198200
* @return boolean|WP_Error
199201
*/
200202
public static function is_webfinger_endpoint_accessible() {
201-
$user = \wp_get_current_user();
202-
$webfinger = \Activitypub\get_webfinger_resource( $user->ID );
203-
204-
$url = \wp_parse_url( \home_url(), \PHP_URL_SCHEME ) . '://' . \wp_parse_url( \home_url(), \PHP_URL_HOST );
205-
206-
if ( \wp_parse_url( \home_url(), \PHP_URL_PORT ) ) {
207-
$url .= ':' . \wp_parse_url( \home_url(), \PHP_URL_PORT );
208-
}
209-
210-
$url = \trailingslashit( $url ) . '.well-known/webfinger';
203+
$user = \wp_get_current_user();
204+
$account = \Activitypub\get_webfinger_resource( $user->ID );
211205

212-
$url = \add_query_arg( 'resource', 'acct:' . $webfinger, $url );
213-
214-
// try to access author URL
215-
$response = \wp_remote_get(
216-
$url,
217-
array(
218-
'headers' => array( 'Accept' => 'application/activity+json' ),
219-
'redirection' => 0,
220-
)
221-
);
222-
223-
if ( \is_wp_error( $response ) ) {
224-
return new \WP_Error(
225-
'webfinger_url_not_accessible',
226-
\sprintf(
206+
$url = Webfinger::resolve( $account );
207+
if ( \is_wp_error( $url ) ) {
208+
$health_messages = array(
209+
'webfinger_url_not_accessible' => \sprintf(
227210
// translators: %s: Author URL
228211
\__(
229212
'<p>Your WebFinger endpoint <code>%s</code> is not accessible. Please check your WordPress setup or permalink structure.</p>',
230213
'activitypub'
231214
),
232-
$url
233-
)
234-
);
235-
}
236-
237-
$response_code = \wp_remote_retrieve_response_code( $response );
238-
239-
// check if response is JSON
240-
$body = \wp_remote_retrieve_body( $response );
241-
242-
if ( ! \is_string( $body ) || ! \is_array( \json_decode( $body, true ) ) ) {
243-
return new \WP_Error(
244-
'webfinger_url_not_accessible',
245-
\sprintf(
215+
$url->get_error_data()
216+
),
217+
'webfinger_url_invalid_response' => \sprintf(
246218
// translators: %s: Author URL
247219
\__(
248220
'<p>Your WebFinger endpoint <code>%s</code> does not return valid JSON for <code>application/jrd+json</code>.</p>',
249221
'activitypub'
250222
),
251-
$url
252-
)
223+
$url->get_error_data()
224+
),
225+
);
226+
$message = null;
227+
if ( isset( $health_messages[ $url->get_error_code() ] ) ) {
228+
$message = $health_messages[ $url->get_error_code() ];
229+
}
230+
return new \WP_Error(
231+
$url->get_error_code(),
232+
$message,
233+
$url->get_error_data()
253234
);
254235
}
255236

includes/class-signature.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public static function generate_key_pair( $user_id ) {
7070
\update_user_meta( $user_id, 'magic_sig_public_key', $detail['key'] );
7171
}
7272

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

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

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

9797
$signature = null;

includes/functions.php

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ function get_context() {
3535
function safe_remote_post( $url, $body, $user_id ) {
3636
$date = \gmdate( 'D, d M Y H:i:s T' );
3737
$digest = \Activitypub\Signature::generate_digest( $body );
38-
$signature = \Activitypub\Signature::generate_signature( $user_id, $url, $date, $digest );
38+
$signature = \Activitypub\Signature::generate_signature( $user_id, 'post', $url, $date, $digest );
3939

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

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

6868
$wp_version = \get_bloginfo( 'version' );
6969
$user_agent = \apply_filters( 'http_headers_useragent', 'WordPress/' . $wp_version . '; ' . \get_bloginfo( 'url' ) );
@@ -108,11 +108,23 @@ function get_webfinger_resource( $user_id ) {
108108
/**
109109
* [get_metadata_by_actor description]
110110
*
111-
* @param sting $actor
111+
* @param string $actor
112112
*
113113
* @return array
114114
*/
115115
function get_remote_metadata_by_actor( $actor ) {
116+
$pre = apply_filters( 'pre_get_remote_metadata_by_actor', false, $actor );
117+
if ( $pre ) {
118+
return $pre;
119+
}
120+
if ( preg_match( '/^@?[^@]+@((?:[a-z0-9-]+\.)+[a-z]+)$/i', $actor ) ) {
121+
$actor = Rest\Webfinger::resolve( $actor );
122+
}
123+
124+
if ( ! $actor ) {
125+
return null;
126+
}
127+
116128
$metadata = \get_transient( 'activitypub_' . $actor );
117129

118130
if ( $metadata ) {

includes/model/class-activity.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ public function from_remote_array( $array ) {
7575
}
7676

7777
public function to_array() {
78-
$array = \get_object_vars( $this );
78+
$array = array_filter( \get_object_vars( $this ) );
7979

8080
if ( $this->context ) {
8181
$array = array( '@context' => $this->context ) + $array;

includes/rest/class-inbox.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,6 @@ public static function user_inbox_post( $request ) {
161161
public static function shared_inbox_post( $request ) {
162162
$data = $request->get_params();
163163
$type = $request->get_param( 'type' );
164-
165164
$users = self::extract_recipients( $data );
166165

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

409+
if ( ! isset( $object['object']['inReplyTo'] ) ) {
410+
return;
411+
}
412+
410413
$comment_post_id = \url_to_postid( $object['object']['inReplyTo'] );
411414

412415
// save only replys and reactions

includes/rest/class-webfinger.php

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,4 +120,44 @@ public static function add_webfinger_discovery( $array, $resource, $user ) {
120120

121121
return $array;
122122
}
123+
124+
public static function resolve( $account ) {
125+
if ( ! preg_match( '/^@?[^@]+@((?:[a-z0-9-]+\.)+[a-z]+)$/i', $account, $m ) ) {
126+
return null;
127+
}
128+
$url = \add_query_arg( 'resource', 'acct:' . ltrim( $account, '@' ), 'https://' . $m[1] . '/.well-known/webfinger' );
129+
if ( ! \wp_http_validate_url( $url ) ) {
130+
return new \WP_Error( 'invalid_webfinger_url', null, $url );
131+
}
132+
133+
// try to access author URL
134+
$response = \wp_remote_get(
135+
$url,
136+
array(
137+
'headers' => array( 'Accept' => 'application/activity+json' ),
138+
'redirection' => 0,
139+
)
140+
);
141+
142+
if ( \is_wp_error( $response ) ) {
143+
return new \WP_Error( 'webfinger_url_not_accessible', null, $url );
144+
}
145+
146+
$response_code = \wp_remote_retrieve_response_code( $response );
147+
148+
$body = \wp_remote_retrieve_body( $response );
149+
$body = \json_decode( $body, true );
150+
151+
if ( ! isset( $body['links'] ) ) {
152+
return new \WP_Error( 'webfinger_url_invalid_response', null, $url );
153+
}
154+
155+
foreach ( $body['links'] as $link ) {
156+
if ( 'self' === $link['rel'] && 'application/activity+json' === $link['type'] ) {
157+
return $link['href'];
158+
}
159+
}
160+
161+
return new \WP_Error( 'webfinger_url_no_activity_pub', null, $body );
162+
}
123163
}

0 commit comments

Comments
 (0)