2019-09-27 10:12:59 +02:00
< ? php
namespace Activitypub ;
/**
* ActivityPub Health_Check Class
*
* @ author Matthias Pfefferle
*/
class Health_Check {
2021-07-23 15:46:28 +02:00
/**
* Initialize health checks
*
* @ return void
*/
2019-09-27 10:12:59 +02:00
public static function init () {
2020-07-21 09:23:35 +02:00
\add_filter ( 'site_status_tests' , array ( '\Activitypub\Health_Check' , 'add_tests' ) );
}
public static function add_tests ( $tests ) {
2021-07-23 15:46:28 +02:00
$tests [ 'direct' ][ 'activitypub_test_author_url' ] = array (
'label' => \__ ( 'Author URL test' , 'activitypub' ),
'test' => array ( '\Activitypub\Health_Check' , 'test_author_url' ),
2020-07-21 09:23:35 +02:00
);
2021-07-23 15:46:28 +02:00
$tests [ 'direct' ][ 'activitypub_test_webfinger' ] = array (
'label' => __ ( 'WebFinger Test' , 'activitypub' ),
'test' => array ( '\Activitypub\Health_Check' , 'test_webfinger' ),
);
2020-07-21 09:23:35 +02:00
return $tests ;
}
2021-07-23 15:46:28 +02:00
/**
* Author URL tests
*
* @ return void
*/
public static function test_author_url () {
2020-07-21 09:23:35 +02:00
$result = array (
2021-01-13 23:22:17 +01:00
'label' => \__ ( 'Author URL accessible' , 'activitypub' ),
2020-07-21 09:23:35 +02:00
'status' => 'good' ,
'badge' => array (
'label' => \__ ( 'ActivityPub' , 'activitypub' ),
'color' => 'green' ,
),
'description' => \sprintf (
'<p>%s</p>' ,
2021-01-13 23:22:17 +01:00
\__ ( 'Your author URL is accessible and supports the required "Accept" header.' , 'activitypub' )
2020-07-21 09:23:35 +02:00
),
'actions' => '' ,
2021-07-23 15:46:28 +02:00
'test' => 'test_author_url' ,
);
$check = self :: is_author_url_accessible ();
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 ()
2020-07-21 09:23:35 +02:00
);
2021-07-23 15:46:28 +02:00
return $result ;
}
2020-07-21 09:23:35 +02:00
2021-07-23 15:46:28 +02:00
/**
* 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 (
2020-07-21 09:23:35 +02:00
'<p>%s</p>' ,
2021-07-23 15:46:28 +02:00
\__ ( '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 ;
2020-07-21 09:23:35 +02:00
}
2021-07-23 15:46:28 +02:00
$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 ()
);
2020-07-21 09:23:35 +02:00
return $result ;
}
2021-07-23 15:46:28 +02:00
/**
* Check if `author_posts_url` is accessible and that requerst returns correct JSON
*
* @ return boolean | WP_Error
*/
public static function is_author_url_accessible () {
2020-07-21 09:23:35 +02:00
$user = \wp_get_current_user ();
$author_url = \get_author_posts_url ( $user -> ID );
2021-01-13 23:22:17 +01:00
$reference_author_url = self :: get_author_posts_url ( $user -> ID , $user -> user_nicename );
2020-07-21 09:23:35 +02:00
// check for "author" in URL
2021-01-13 23:22:17 +01:00
if ( $author_url !== $reference_author_url ) {
2021-07-23 15:46:28 +02:00
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
)
);
2020-07-21 09:23:35 +02:00
}
// try to access author URL
2021-07-23 15:46:28 +02:00
$response = \wp_remote_get (
$author_url ,
array (
'headers' => array ( 'Accept' => 'application/activity+json' ),
'redirection' => 0 ,
)
);
2020-07-21 09:23:35 +02:00
if ( \is_wp_error ( $response ) ) {
2021-07-23 15:46:28 +02:00
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
)
);
2020-07-21 09:23:35 +02:00
}
// check if response is JSON
$body = \wp_remote_retrieve_body ( $response );
if ( ! \is_string ( $body ) || ! \is_array ( \json_decode ( $body , true ) ) ) {
2021-07-23 15:46:28 +02:00
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
)
);
2020-07-21 09:23:35 +02:00
}
return true ;
2019-09-27 10:12:59 +02:00
}
2021-01-13 23:22:17 +01:00
/**
* Retrieve the URL to the author page for the user with the ID provided .
*
* @ global WP_Rewrite $wp_rewrite WordPress rewrite component .
*
* @ param int $author_id Author ID .
* @ param string $author_nicename Optional . The author ' s nicename ( slug ) . Default empty .
*
* @ return string The URL to the author ' s page .
*/
public static function get_author_posts_url ( $author_id , $author_nicename = '' ) {
global $wp_rewrite ;
$auth_id = ( int ) $author_id ;
$link = $wp_rewrite -> get_author_permastruct ();
if ( empty ( $link ) ) {
$file = home_url ( '/' );
$link = $file . '?author=' . $auth_id ;
} else {
if ( '' === $author_nicename ) {
$user = get_userdata ( $author_id );
if ( ! empty ( $user -> user_nicename ) ) {
$author_nicename = $user -> user_nicename ;
}
}
$link = str_replace ( '%author%' , $author_nicename , $link );
$link = home_url ( user_trailingslashit ( $link ) );
}
return $link ;
}
2019-09-27 10:12:59 +02:00
}