Merge pull request #127 from pfefferle/health-check-improvements
added health checks
This commit is contained in:
commit
7cddec43b6
6 changed files with 233 additions and 29 deletions
|
@ -3,8 +3,8 @@
|
||||||
**Donate link:** https://notiz.blog/donate/
|
**Donate link:** https://notiz.blog/donate/
|
||||||
**Tags:** OStatus, fediverse, activitypub, activitystream
|
**Tags:** OStatus, fediverse, activitypub, activitystream
|
||||||
**Requires at least:** 4.7
|
**Requires at least:** 4.7
|
||||||
**Tested up to:** 5.6
|
**Tested up to:** 5.8
|
||||||
**Stable tag:** 0.12.0
|
**Stable tag:** 0.13.0
|
||||||
**Requires PHP:** 5.6
|
**Requires PHP:** 5.6
|
||||||
**License:** MIT
|
**License:** MIT
|
||||||
**License URI:** http://opensource.org/licenses/MIT
|
**License URI:** http://opensource.org/licenses/MIT
|
||||||
|
@ -88,6 +88,11 @@ Where 'blog' is the path to the subdirectory at which your blog resides.
|
||||||
|
|
||||||
Project maintained on GitHub at [pfefferle/wordpress-activitypub](https://github.com/pfefferle/wordpress-activitypub).
|
Project maintained on GitHub at [pfefferle/wordpress-activitypub](https://github.com/pfefferle/wordpress-activitypub).
|
||||||
|
|
||||||
|
### 0.13.0 ###
|
||||||
|
|
||||||
|
* add Autor URL and WebFinger health checks
|
||||||
|
* fix NodeInfo endpoint
|
||||||
|
|
||||||
### 0.12.0 ###
|
### 0.12.0 ###
|
||||||
|
|
||||||
* use "pre_option_require_name_email" filter instead of "check_comment_flood". props [@akirk](https://github.com/akirk)
|
* use "pre_option_require_name_email" filter instead of "check_comment_flood". props [@akirk](https://github.com/akirk)
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* Plugin Name: ActivityPub
|
* Plugin Name: ActivityPub
|
||||||
* Plugin URI: https://github.com/pfefferle/wordpress-activitypub/
|
* Plugin URI: https://github.com/pfefferle/wordpress-activitypub/
|
||||||
* Description: The ActivityPub protocol is a decentralized social networking protocol based upon the ActivityStreams 2.0 data format.
|
* Description: The ActivityPub protocol is a decentralized social networking protocol based upon the ActivityStreams 2.0 data format.
|
||||||
* Version: 0.12.0
|
* Version: 0.13.0
|
||||||
* Author: Matthias Pfefferle
|
* Author: Matthias Pfefferle
|
||||||
* Author URI: https://notiz.blog/
|
* Author URI: https://notiz.blog/
|
||||||
* License: MIT
|
* License: MIT
|
||||||
|
@ -75,6 +75,10 @@ function init() {
|
||||||
\add_filter( 'wp_rest_server_class', function() {
|
\add_filter( 'wp_rest_server_class', function() {
|
||||||
return '\Activitypub\Rest\Server';
|
return '\Activitypub\Rest\Server';
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
if ( \WP_DEBUG ) {
|
||||||
|
require_once \dirname( __FILE__ ) . '/includes/debug.php';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
\add_action( 'plugins_loaded', '\Activitypub\init' );
|
\add_action( 'plugins_loaded', '\Activitypub\init' );
|
||||||
|
|
||||||
|
|
|
@ -7,25 +7,36 @@ namespace Activitypub;
|
||||||
* @author Matthias Pfefferle
|
* @author Matthias Pfefferle
|
||||||
*/
|
*/
|
||||||
class Health_Check {
|
class Health_Check {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize health checks
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
public static function init() {
|
public static function init() {
|
||||||
\add_filter( 'site_status_tests', array( '\Activitypub\Health_Check', 'add_tests' ) );
|
\add_filter( 'site_status_tests', array( '\Activitypub\Health_Check', 'add_tests' ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function add_tests( $tests ) {
|
public static function add_tests( $tests ) {
|
||||||
$tests['direct']['activitypub_test_profile_url'] = array(
|
$tests['direct']['activitypub_test_author_url'] = array(
|
||||||
'label' => \__( 'Profile URL test', 'activitypub' ),
|
'label' => \__( 'Author URL test', 'activitypub' ),
|
||||||
'test' => array( '\Activitypub\Health_Check', 'test_profile_url' ),
|
'test' => array( '\Activitypub\Health_Check', 'test_author_url' ),
|
||||||
);
|
);
|
||||||
|
|
||||||
//$tests['direct']['activitypub_test_profile_url2'] = array(
|
$tests['direct']['activitypub_test_webfinger'] = array(
|
||||||
// 'label' => __( 'Profile URL Test', 'activitypub' ),
|
'label' => __( 'WebFinger Test', 'activitypub' ),
|
||||||
// 'test' => array( '\Activitypub\Health_Check', 'test_profile_url' ),
|
'test' => array( '\Activitypub\Health_Check', 'test_webfinger' ),
|
||||||
//);
|
);
|
||||||
|
|
||||||
return $tests;
|
return $tests;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function test_profile_url() {
|
/**
|
||||||
|
* Author URL tests
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function test_author_url() {
|
||||||
$result = array(
|
$result = array(
|
||||||
'label' => \__( 'Author URL accessible', 'activitypub' ),
|
'label' => \__( 'Author URL accessible', 'activitypub' ),
|
||||||
'status' => 'good',
|
'status' => 'good',
|
||||||
|
@ -38,45 +49,208 @@ class Health_Check {
|
||||||
\__( 'Your author URL is accessible and supports the required "Accept" header.', 'activitypub' )
|
\__( 'Your author URL is accessible and supports the required "Accept" header.', 'activitypub' )
|
||||||
),
|
),
|
||||||
'actions' => '',
|
'actions' => '',
|
||||||
'test' => 'test_profile_url',
|
'test' => 'test_author_url',
|
||||||
);
|
);
|
||||||
|
|
||||||
$enum = self::is_profile_url_accessible();
|
$check = self::is_author_url_accessible();
|
||||||
|
|
||||||
|
if ( true === $check ) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
if ( true !== $enum ) {
|
|
||||||
$result['status'] = 'critical';
|
$result['status'] = 'critical';
|
||||||
$result['label'] = \__( 'Profile URL is not accessible', 'activitypub' );
|
$result['label'] = \__( 'Author URL is not accessible', 'activitypub' );
|
||||||
|
$result['badge']['color'] = 'red';
|
||||||
$result['description'] = \sprintf(
|
$result['description'] = \sprintf(
|
||||||
'<p>%s</p>',
|
'<p>%s</p>',
|
||||||
\__( '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' )
|
$check->get_error_message()
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function is_profile_url_accessible() {
|
/**
|
||||||
|
* WebFinger tests
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function test_webfinger() {
|
||||||
|
$result = array(
|
||||||
|
'label' => \__( 'WebFinger endpoint', 'activitypub' ),
|
||||||
|
'status' => 'good',
|
||||||
|
'badge' => array(
|
||||||
|
'label' => \__( 'ActivityPub', 'activitypub' ),
|
||||||
|
'color' => 'green',
|
||||||
|
),
|
||||||
|
'description' => \sprintf(
|
||||||
|
'<p>%s</p>',
|
||||||
|
\__( 'Your WebFinger endpoint is accessible and returns the correct informations.', 'activitypub' )
|
||||||
|
),
|
||||||
|
'actions' => '',
|
||||||
|
'test' => 'test_webfinger',
|
||||||
|
);
|
||||||
|
|
||||||
|
$check = self::is_webfinger_endpoint_accessible();
|
||||||
|
|
||||||
|
if ( true === $check ) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result['status'] = 'critical';
|
||||||
|
$result['label'] = \__( 'WebFinger endpoint is not accessible', 'activitypub' );
|
||||||
|
$result['badge']['color'] = 'red';
|
||||||
|
$result['description'] = \sprintf(
|
||||||
|
'<p>%s</p>',
|
||||||
|
$check->get_error_message()
|
||||||
|
);
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if `author_posts_url` is accessible and that requerst returns correct JSON
|
||||||
|
*
|
||||||
|
* @return boolean|WP_Error
|
||||||
|
*/
|
||||||
|
public static function is_author_url_accessible() {
|
||||||
$user = \wp_get_current_user();
|
$user = \wp_get_current_user();
|
||||||
$author_url = \get_author_posts_url( $user->ID );
|
$author_url = \get_author_posts_url( $user->ID );
|
||||||
$reference_author_url = self::get_author_posts_url( $user->ID, $user->user_nicename );
|
$reference_author_url = self::get_author_posts_url( $user->ID, $user->user_nicename );
|
||||||
|
|
||||||
// check for "author" in URL
|
// check for "author" in URL
|
||||||
if ( $author_url !== $reference_author_url ) {
|
if ( $author_url !== $reference_author_url ) {
|
||||||
return false;
|
return new \WP_Error(
|
||||||
|
'author_url_not_accessible',
|
||||||
|
\sprintf(
|
||||||
|
// translators: %s: Author URL
|
||||||
|
\__(
|
||||||
|
'<p>Your author URL <code>%s</code> was replaced, this is often done by plugins.</p>',
|
||||||
|
'activitypub'
|
||||||
|
),
|
||||||
|
$author_url
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// try to access author URL
|
// try to access author URL
|
||||||
$response = \wp_remote_get( $author_url, array( 'headers' => array( 'Accept' => 'application/activity+json' ) ) );
|
$response = \wp_remote_get(
|
||||||
|
$author_url,
|
||||||
|
array(
|
||||||
|
'headers' => array( 'Accept' => 'application/activity+json' ),
|
||||||
|
'redirection' => 0,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
if ( \is_wp_error( $response ) ) {
|
if ( \is_wp_error( $response ) ) {
|
||||||
return false;
|
return new \WP_Error(
|
||||||
|
'author_url_not_accessible',
|
||||||
|
\sprintf(
|
||||||
|
// translators: %s: Author URL
|
||||||
|
\__(
|
||||||
|
'<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>',
|
||||||
|
'activitypub'
|
||||||
|
),
|
||||||
|
$author_url
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$response_code = \wp_remote_retrieve_response_code( $response );
|
||||||
|
|
||||||
|
// check for redirects
|
||||||
|
if ( \in_array( $response_code, array( 301, 302, 307, 308 ), true ) ) {
|
||||||
|
return new \WP_Error(
|
||||||
|
'author_url_not_accessible',
|
||||||
|
\sprintf(
|
||||||
|
// translators: %s: Author URL
|
||||||
|
\__(
|
||||||
|
'<p>Your author URL <code>%s</code> is redirecting to another page, this is often done by SEO plugins like "Yoast SEO".</p>',
|
||||||
|
'activitypub'
|
||||||
|
),
|
||||||
|
$author_url
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if response is JSON
|
// check if response is JSON
|
||||||
$body = \wp_remote_retrieve_body( $response );
|
$body = \wp_remote_retrieve_body( $response );
|
||||||
|
|
||||||
if ( ! \is_string( $body ) || ! \is_array( \json_decode( $body, true ) ) ) {
|
if ( ! \is_string( $body ) || ! \is_array( \json_decode( $body, true ) ) ) {
|
||||||
return false;
|
return new \WP_Error(
|
||||||
|
'author_url_not_accessible',
|
||||||
|
\sprintf(
|
||||||
|
// translators: %s: Author URL
|
||||||
|
\__(
|
||||||
|
'<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>',
|
||||||
|
'activitypub'
|
||||||
|
),
|
||||||
|
$author_url
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if WebFinger endoint is accessible and profile requerst returns correct JSON
|
||||||
|
*
|
||||||
|
* @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';
|
||||||
|
|
||||||
|
$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(
|
||||||
|
// 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(
|
||||||
|
// 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
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
16
includes/debug.php
Normal file
16
includes/debug.php
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
namespace Activitypub;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow localhost URLs if WP_DEBUG is true.
|
||||||
|
*
|
||||||
|
* @param array $r Array of HTTP request args.
|
||||||
|
* @param string $url The request URL.
|
||||||
|
* @return array $args Array or string of HTTP request arguments.
|
||||||
|
*/
|
||||||
|
function allow_localhost( $r, $url ) {
|
||||||
|
$r['reject_unsafe_urls'] = false;
|
||||||
|
|
||||||
|
return $r;
|
||||||
|
}
|
||||||
|
add_filter( 'http_request_args', '\Activitypub\allow_localhost', 10, 2 );
|
|
@ -20,11 +20,11 @@ function get_context() {
|
||||||
'Hashtag' => 'as:Hashtag',
|
'Hashtag' => 'as:Hashtag',
|
||||||
'featured' => array(
|
'featured' => array(
|
||||||
'@id' => 'toot:featured',
|
'@id' => 'toot:featured',
|
||||||
'@type' => '@id'
|
'@type' => '@id',
|
||||||
),
|
),
|
||||||
'featuredTags' => array(
|
'featuredTags' => array(
|
||||||
'@id' => 'toot:featuredTags',
|
'@id' => 'toot:featuredTags',
|
||||||
'@type' => '@id'
|
'@type' => '@id',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -3,8 +3,8 @@ Contributors: pfefferle, mediaformat
|
||||||
Donate link: https://notiz.blog/donate/
|
Donate link: https://notiz.blog/donate/
|
||||||
Tags: OStatus, fediverse, activitypub, activitystream
|
Tags: OStatus, fediverse, activitypub, activitystream
|
||||||
Requires at least: 4.7
|
Requires at least: 4.7
|
||||||
Tested up to: 5.6
|
Tested up to: 5.8
|
||||||
Stable tag: 0.12.0
|
Stable tag: 0.13.0
|
||||||
Requires PHP: 5.6
|
Requires PHP: 5.6
|
||||||
License: MIT
|
License: MIT
|
||||||
License URI: http://opensource.org/licenses/MIT
|
License URI: http://opensource.org/licenses/MIT
|
||||||
|
@ -88,6 +88,11 @@ Where 'blog' is the path to the subdirectory at which your blog resides.
|
||||||
|
|
||||||
Project maintained on GitHub at [pfefferle/wordpress-activitypub](https://github.com/pfefferle/wordpress-activitypub).
|
Project maintained on GitHub at [pfefferle/wordpress-activitypub](https://github.com/pfefferle/wordpress-activitypub).
|
||||||
|
|
||||||
|
= 0.13.0 =
|
||||||
|
|
||||||
|
* add Autor URL and WebFinger health checks
|
||||||
|
* fix NodeInfo endpoint
|
||||||
|
|
||||||
= 0.12.0 =
|
= 0.12.0 =
|
||||||
|
|
||||||
* use "pre_option_require_name_email" filter instead of "check_comment_flood". props [@akirk](https://github.com/akirk)
|
* use "pre_option_require_name_email" filter instead of "check_comment_flood". props [@akirk](https://github.com/akirk)
|
||||||
|
|
Loading…
Reference in a new issue