Skip to content

Commit 7cddec4

Browse files
authored
Merge pull request #127 from pfefferle/health-check-improvements
added health checks
2 parents 56a9323 + f4f46fc commit 7cddec4

File tree

6 files changed

+232
-28
lines changed

6 files changed

+232
-28
lines changed

README.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
**Donate link:** https://notiz.blog/donate/
44
**Tags:** OStatus, fediverse, activitypub, activitystream
55
**Requires at least:** 4.7
6-
**Tested up to:** 5.6
7-
**Stable tag:** 0.12.0
6+
**Tested up to:** 5.8
7+
**Stable tag:** 0.13.0
88
**Requires PHP:** 5.6
99
**License:** MIT
1010
**License URI:** http://opensource.org/licenses/MIT
@@ -88,6 +88,11 @@ Where 'blog' is the path to the subdirectory at which your blog resides.
8888

8989
Project maintained on GitHub at [pfefferle/wordpress-activitypub](https://github.com/pfefferle/wordpress-activitypub).
9090

91+
### 0.13.0 ###
92+
93+
* add Autor URL and WebFinger health checks
94+
* fix NodeInfo endpoint
95+
9196
### 0.12.0 ###
9297

9398
* use "pre_option_require_name_email" filter instead of "check_comment_flood". props [@akirk](https://github.com/akirk)

activitypub.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* Plugin Name: ActivityPub
44
* Plugin URI: https://github.com/pfefferle/wordpress-activitypub/
55
* Description: The ActivityPub protocol is a decentralized social networking protocol based upon the ActivityStreams 2.0 data format.
6-
* Version: 0.12.0
6+
* Version: 0.13.0
77
* Author: Matthias Pfefferle
88
* Author URI: https://notiz.blog/
99
* License: MIT
@@ -75,6 +75,10 @@ function init() {
7575
\add_filter( 'wp_rest_server_class', function() {
7676
return '\Activitypub\Rest\Server';
7777
} );
78+
79+
if ( \WP_DEBUG ) {
80+
require_once \dirname( __FILE__ ) . '/includes/debug.php';
81+
}
7882
}
7983
\add_action( 'plugins_loaded', '\Activitypub\init' );
8084

includes/class-health-check.php

Lines changed: 195 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,36 @@
77
* @author Matthias Pfefferle
88
*/
99
class Health_Check {
10+
11+
/**
12+
* Initialize health checks
13+
*
14+
* @return void
15+
*/
1016
public static function init() {
1117
\add_filter( 'site_status_tests', array( '\Activitypub\Health_Check', 'add_tests' ) );
1218
}
1319

1420
public static function add_tests( $tests ) {
15-
$tests['direct']['activitypub_test_profile_url'] = array(
16-
'label' => \__( 'Profile URL test', 'activitypub' ),
17-
'test' => array( '\Activitypub\Health_Check', 'test_profile_url' ),
21+
$tests['direct']['activitypub_test_author_url'] = array(
22+
'label' => \__( 'Author URL test', 'activitypub' ),
23+
'test' => array( '\Activitypub\Health_Check', 'test_author_url' ),
1824
);
1925

20-
//$tests['direct']['activitypub_test_profile_url2'] = array(
21-
// 'label' => __( 'Profile URL Test', 'activitypub' ),
22-
// 'test' => array( '\Activitypub\Health_Check', 'test_profile_url' ),
23-
//);
26+
$tests['direct']['activitypub_test_webfinger'] = array(
27+
'label' => __( 'WebFinger Test', 'activitypub' ),
28+
'test' => array( '\Activitypub\Health_Check', 'test_webfinger' ),
29+
);
2430

2531
return $tests;
2632
}
2733

28-
public static function test_profile_url() {
34+
/**
35+
* Author URL tests
36+
*
37+
* @return void
38+
*/
39+
public static function test_author_url() {
2940
$result = array(
3041
'label' => \__( 'Author URL accessible', 'activitypub' ),
3142
'status' => 'good',
@@ -38,45 +49,208 @@ public static function test_profile_url() {
3849
\__( 'Your author URL is accessible and supports the required "Accept" header.', 'activitypub' )
3950
),
4051
'actions' => '',
41-
'test' => 'test_profile_url',
52+
'test' => 'test_author_url',
53+
);
54+
55+
$check = self::is_author_url_accessible();
56+
57+
if ( true === $check ) {
58+
return $result;
59+
}
60+
61+
$result['status'] = 'critical';
62+
$result['label'] = \__( 'Author URL is not accessible', 'activitypub' );
63+
$result['badge']['color'] = 'red';
64+
$result['description'] = \sprintf(
65+
'<p>%s</p>',
66+
$check->get_error_message()
4267
);
4368

44-
$enum = self::is_profile_url_accessible();
69+
return $result;
70+
}
4571

46-
if ( true !== $enum ) {
47-
$result['status'] = 'critical';
48-
$result['label'] = \__( 'Profile URL is not accessible', 'activitypub' );
49-
$result['description'] = \sprintf(
72+
/**
73+
* WebFinger tests
74+
*
75+
* @return void
76+
*/
77+
public static function test_webfinger() {
78+
$result = array(
79+
'label' => \__( 'WebFinger endpoint', 'activitypub' ),
80+
'status' => 'good',
81+
'badge' => array(
82+
'label' => \__( 'ActivityPub', 'activitypub' ),
83+
'color' => 'green',
84+
),
85+
'description' => \sprintf(
5086
'<p>%s</p>',
51-
\__( 'Your author URL is not accessible and/or does not return valid JSON. Please check if the author URL is accessible and does not redirect to another page (often done by SEO plugins).', 'activitypub' )
52-
);
87+
\__( 'Your WebFinger endpoint is accessible and returns the correct informations.', 'activitypub' )
88+
),
89+
'actions' => '',
90+
'test' => 'test_webfinger',
91+
);
92+
93+
$check = self::is_webfinger_endpoint_accessible();
94+
95+
if ( true === $check ) {
96+
return $result;
5397
}
5498

99+
$result['status'] = 'critical';
100+
$result['label'] = \__( 'WebFinger endpoint is not accessible', 'activitypub' );
101+
$result['badge']['color'] = 'red';
102+
$result['description'] = \sprintf(
103+
'<p>%s</p>',
104+
$check->get_error_message()
105+
);
106+
55107
return $result;
56108
}
57109

58-
public static function is_profile_url_accessible() {
110+
/**
111+
* Check if `author_posts_url` is accessible and that requerst returns correct JSON
112+
*
113+
* @return boolean|WP_Error
114+
*/
115+
public static function is_author_url_accessible() {
59116
$user = \wp_get_current_user();
60117
$author_url = \get_author_posts_url( $user->ID );
61118
$reference_author_url = self::get_author_posts_url( $user->ID, $user->user_nicename );
62119

63120
// check for "author" in URL
64121
if ( $author_url !== $reference_author_url ) {
65-
return false;
122+
return new \WP_Error(
123+
'author_url_not_accessible',
124+
\sprintf(
125+
// translators: %s: Author URL
126+
\__(
127+
'<p>Your author URL <code>%s</code> was replaced, this is often done by plugins.</p>',
128+
'activitypub'
129+
),
130+
$author_url
131+
)
132+
);
66133
}
67134

68135
// try to access author URL
69-
$response = \wp_remote_get( $author_url, array( 'headers' => array( 'Accept' => 'application/activity+json' ) ) );
136+
$response = \wp_remote_get(
137+
$author_url,
138+
array(
139+
'headers' => array( 'Accept' => 'application/activity+json' ),
140+
'redirection' => 0,
141+
)
142+
);
70143

71144
if ( \is_wp_error( $response ) ) {
72-
return false;
145+
return new \WP_Error(
146+
'author_url_not_accessible',
147+
\sprintf(
148+
// translators: %s: Author URL
149+
\__(
150+
'<p>Your author URL <code>%s</code> is not accessible. Please check your WordPress setup or permalink structure. If the setup seems fine, maybe check if a plugin might restrict the access.</p>',
151+
'activitypub'
152+
),
153+
$author_url
154+
)
155+
);
156+
}
157+
158+
$response_code = \wp_remote_retrieve_response_code( $response );
159+
160+
// check for redirects
161+
if ( \in_array( $response_code, array( 301, 302, 307, 308 ), true ) ) {
162+
return new \WP_Error(
163+
'author_url_not_accessible',
164+
\sprintf(
165+
// translators: %s: Author URL
166+
\__(
167+
'<p>Your author URL <code>%s</code> is redirecting to another page, this is often done by SEO plugins like "Yoast SEO".</p>',
168+
'activitypub'
169+
),
170+
$author_url
171+
)
172+
);
73173
}
74174

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

78178
if ( ! \is_string( $body ) || ! \is_array( \json_decode( $body, true ) ) ) {
79-
return false;
179+
return new \WP_Error(
180+
'author_url_not_accessible',
181+
\sprintf(
182+
// translators: %s: Author URL
183+
\__(
184+
'<p>Your author URL <code>%s</code> does not return valid JSON for <code>application/activity+json</code>. Please check if your hosting supports alternate <code>Accept</code> headers.</p>',
185+
'activitypub'
186+
),
187+
$author_url
188+
)
189+
);
190+
}
191+
192+
return true;
193+
}
194+
195+
/**
196+
* Check if WebFinger endoint is accessible and profile requerst returns correct JSON
197+
*
198+
* @return boolean|WP_Error
199+
*/
200+
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';
211+
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(
227+
// translators: %s: Author URL
228+
\__(
229+
'<p>Your WebFinger endpoint <code>%s</code> is not accessible. Please check your WordPress setup or permalink structure.</p>',
230+
'activitypub'
231+
),
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(
246+
// translators: %s: Author URL
247+
\__(
248+
'<p>Your WebFinger endpoint <code>%s</code> does not return valid JSON for <code>application/jrd+json</code>.</p>',
249+
'activitypub'
250+
),
251+
$url
252+
)
253+
);
80254
}
81255

82256
return true;

includes/debug.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
namespace Activitypub;
3+
4+
/**
5+
* Allow localhost URLs if WP_DEBUG is true.
6+
*
7+
* @param array $r Array of HTTP request args.
8+
* @param string $url The request URL.
9+
* @return array $args Array or string of HTTP request arguments.
10+
*/
11+
function allow_localhost( $r, $url ) {
12+
$r['reject_unsafe_urls'] = false;
13+
14+
return $r;
15+
}
16+
add_filter( 'http_request_args', '\Activitypub\allow_localhost', 10, 2 );

includes/functions.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ function get_context() {
2020
'Hashtag' => 'as:Hashtag',
2121
'featured' => array(
2222
'@id' => 'toot:featured',
23-
'@type' => '@id'
23+
'@type' => '@id',
2424
),
2525
'featuredTags' => array(
2626
'@id' => 'toot:featuredTags',
27-
'@type' => '@id'
27+
'@type' => '@id',
2828
),
2929
),
3030
);

readme.txt

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ Contributors: pfefferle, mediaformat
33
Donate link: https://notiz.blog/donate/
44
Tags: OStatus, fediverse, activitypub, activitystream
55
Requires at least: 4.7
6-
Tested up to: 5.6
7-
Stable tag: 0.12.0
6+
Tested up to: 5.8
7+
Stable tag: 0.13.0
88
Requires PHP: 5.6
99
License: MIT
1010
License URI: http://opensource.org/licenses/MIT
@@ -88,6 +88,11 @@ Where 'blog' is the path to the subdirectory at which your blog resides.
8888

8989
Project maintained on GitHub at [pfefferle/wordpress-activitypub](https://github.com/pfefferle/wordpress-activitypub).
9090

91+
= 0.13.0 =
92+
93+
* add Autor URL and WebFinger health checks
94+
* fix NodeInfo endpoint
95+
9196
= 0.12.0 =
9297

9398
* use "pre_option_require_name_email" filter instead of "check_comment_flood". props [@akirk](https://github.com/akirk)

0 commit comments

Comments
 (0)