Merge pull request #127 from pfefferle/health-check-improvements

added health checks
This commit is contained in:
Matthias Pfefferle 2021-07-23 15:47:49 +02:00 committed by GitHub
commit 7cddec43b6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 233 additions and 29 deletions

View file

@ -3,8 +3,8 @@
**Donate link:** https://notiz.blog/donate/
**Tags:** OStatus, fediverse, activitypub, activitystream
**Requires at least:** 4.7
**Tested up to:** 5.6
**Stable tag:** 0.12.0
**Tested up to:** 5.8
**Stable tag:** 0.13.0
**Requires PHP:** 5.6
**License:** 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).
### 0.13.0 ###
* add Autor URL and WebFinger health checks
* fix NodeInfo endpoint
### 0.12.0 ###
* use "pre_option_require_name_email" filter instead of "check_comment_flood". props [@akirk](https://github.com/akirk)

View file

@ -3,7 +3,7 @@
* Plugin Name: 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.
* Version: 0.12.0
* Version: 0.13.0
* Author: Matthias Pfefferle
* Author URI: https://notiz.blog/
* License: MIT
@ -75,6 +75,10 @@ function init() {
\add_filter( 'wp_rest_server_class', function() {
return '\Activitypub\Rest\Server';
} );
if ( \WP_DEBUG ) {
require_once \dirname( __FILE__ ) . '/includes/debug.php';
}
}
\add_action( 'plugins_loaded', '\Activitypub\init' );

View file

@ -7,25 +7,36 @@ namespace Activitypub;
* @author Matthias Pfefferle
*/
class Health_Check {
/**
* Initialize health checks
*
* @return void
*/
public static function init() {
\add_filter( 'site_status_tests', array( '\Activitypub\Health_Check', 'add_tests' ) );
}
public static function add_tests( $tests ) {
$tests['direct']['activitypub_test_profile_url'] = array(
'label' => \__( 'Profile URL test', 'activitypub' ),
'test' => array( '\Activitypub\Health_Check', 'test_profile_url' ),
$tests['direct']['activitypub_test_author_url'] = array(
'label' => \__( 'Author URL test', 'activitypub' ),
'test' => array( '\Activitypub\Health_Check', 'test_author_url' ),
);
//$tests['direct']['activitypub_test_profile_url2'] = array(
// 'label' => __( 'Profile URL Test', 'activitypub' ),
// 'test' => array( '\Activitypub\Health_Check', 'test_profile_url' ),
//);
$tests['direct']['activitypub_test_webfinger'] = array(
'label' => __( 'WebFinger Test', 'activitypub' ),
'test' => array( '\Activitypub\Health_Check', 'test_webfinger' ),
);
return $tests;
}
public static function test_profile_url() {
/**
* Author URL tests
*
* @return void
*/
public static function test_author_url() {
$result = array(
'label' => \__( 'Author URL accessible', 'activitypub' ),
'status' => 'good',
@ -38,45 +49,208 @@ class Health_Check {
\__( 'Your author URL is accessible and supports the required "Accept" header.', 'activitypub' )
),
'actions' => '',
'test' => 'test_profile_url',
'test' => 'test_author_url',
);
$enum = self::is_profile_url_accessible();
$check = self::is_author_url_accessible();
if ( true !== $enum ) {
$result['status'] = 'critical';
$result['label'] = \__( 'Profile URL is not accessible', 'activitypub' );
$result['description'] = \sprintf(
'<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' )
);
if ( true === $check ) {
return $result;
}
$result['status'] = 'critical';
$result['label'] = \__( 'Author URL is not accessible', 'activitypub' );
$result['badge']['color'] = 'red';
$result['description'] = \sprintf(
'<p>%s</p>',
$check->get_error_message()
);
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();
$author_url = \get_author_posts_url( $user->ID );
$reference_author_url = self::get_author_posts_url( $user->ID, $user->user_nicename );
// check for "author" in 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
$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 ) ) {
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
$body = \wp_remote_retrieve_body( $response );
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;

16
includes/debug.php Normal file
View 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 );

View file

@ -20,11 +20,11 @@ function get_context() {
'Hashtag' => 'as:Hashtag',
'featured' => array(
'@id' => 'toot:featured',
'@type' => '@id'
'@type' => '@id',
),
'featuredTags' => array(
'@id' => 'toot:featuredTags',
'@type' => '@id'
'@type' => '@id',
),
),
);

View file

@ -3,8 +3,8 @@ Contributors: pfefferle, mediaformat
Donate link: https://notiz.blog/donate/
Tags: OStatus, fediverse, activitypub, activitystream
Requires at least: 4.7
Tested up to: 5.6
Stable tag: 0.12.0
Tested up to: 5.8
Stable tag: 0.13.0
Requires PHP: 5.6
License: 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).
= 0.13.0 =
* add Autor URL and WebFinger health checks
* fix NodeInfo endpoint
= 0.12.0 =
* use "pre_option_require_name_email" filter instead of "check_comment_flood". props [@akirk](https://github.com/akirk)