diff --git a/wp-content/plugins/activitypub/.distignore b/wp-content/plugins/activitypub/.distignore index 93fbfdb6..782f2e88 100644 --- a/wp-content/plugins/activitypub/.distignore +++ b/wp-content/plugins/activitypub/.distignore @@ -22,6 +22,8 @@ bin composer.json composer.lock docker-compose.yml +docker-compose-test.yml +Dockerfile gulpfile.js package.json node_modules diff --git a/wp-content/plugins/activitypub/Dockerfile b/wp-content/plugins/activitypub/Dockerfile deleted file mode 100644 index 3b056fd9..00000000 --- a/wp-content/plugins/activitypub/Dockerfile +++ /dev/null @@ -1,27 +0,0 @@ -FROM php:7.4-alpine3.13 - -RUN mkdir /app - -WORKDIR /app - -# Install Git, NPM & needed libraries -RUN apk update \ - && apk add bash git nodejs npm gettext subversion mysql mysql-client zip \ - && rm -f /var/cache/apk/* - -RUN docker-php-ext-install mysqli - -# Install Composer -RUN EXPECTED_CHECKSUM=$(curl -s https://composer.github.io/installer.sig) \ - && curl https://getcomposer.org/installer -o composer-setup.php \ - && ACTUAL_CHECKSUM="$(php -r "echo hash_file('sha384', 'composer-setup.php');")" \ - && if [ "$EXPECTED_CHECKSUM" != "$ACTUAL_CHECKSUM" ]; then >&2 echo 'ERROR: Invalid installer checksum'; rm composer-setup.php; exit 1; fi \ - && php composer-setup.php --quiet \ - && php -r "unlink('composer-setup.php');" \ - && mv composer.phar /usr/local/bin/composer - -RUN curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar && \ - chmod +x wp-cli.phar && \ - mv wp-cli.phar /usr/local/bin/wp - -RUN chmod +x -R ./ diff --git a/wp-content/plugins/activitypub/activitypub.php b/wp-content/plugins/activitypub/activitypub.php index 770a2778..7320f0c6 100644 --- a/wp-content/plugins/activitypub/activitypub.php +++ b/wp-content/plugins/activitypub/activitypub.php @@ -3,9 +3,9 @@ * 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.15.0 - * Author: Matthias Pfefferle - * Author URI: https://notiz.blog/ + * Version: 0.17.0 + * Author: Matthias Pfefferle & Automattic + * Author URI: https://automattic.com/ * License: MIT * License URI: http://opensource.org/licenses/MIT * Requires PHP: 5.6 @@ -19,9 +19,12 @@ namespace Activitypub; * Initialize plugin */ function init() { + \defined( 'ACTIVITYPUB_EXCERPT_LENGTH' ) || \define( 'ACTIVITYPUB_EXCERPT_LENGTH', 400 ); + \defined( 'ACTIVITYPUB_MAX_IMAGE_ATTACHMENTS' ) || \define( 'ACTIVITYPUB_MAX_IMAGE_ATTACHMENTS', 3 ); \defined( 'ACTIVITYPUB_HASHTAGS_REGEXP' ) || \define( 'ACTIVITYPUB_HASHTAGS_REGEXP', '(?:(?<=\s)|(?<=
)|(?<= %title% %hashtags% %shortlink% [ap_title] [ap_hashtags] [ap_shortlink] ' . \__( 'What is the Fediverse?', 'activitypub' ) . ' ' . __( 'The following Template Tags are available:', 'activitypub' ) . ' ' . __( 'You may also use any Shortcode normally available to you on your site, however be aware that Shortcodes may significantly increase the size of your content depending on what they do.', 'activitypub' ) . ' ' . __( 'Note: the old Template Tags are now deprecated and automatically converted to the new ones.', 'activitypub' ) . ' ' . \wp_kses( \__( 'Let me know if you miss a Template Tag.', 'activitypub' ), 'activitypub' ) . '
)|^)#([A-Za-z0-9_]+)(?:(?=\s|[[:punct:]]|$))' );
+ \defined( 'ACTIVITYPUB_USERNAME_REGEXP' ) || \define( 'ACTIVITYPUB_USERNAME_REGEXP', '(?:([A-Za-z0-9_-]+)@((?:[A-Za-z0-9_-]+\.)+[A-Za-z]+))' );
\defined( 'ACTIVITYPUB_ALLOWED_HTML' ) || \define( 'ACTIVITYPUB_ALLOWED_HTML', '
#i',
+ $protect,
+ $the_content
+ );
+
+ $the_content = \preg_replace_callback( '/@' . ACTIVITYPUB_USERNAME_REGEXP . '/', array( '\Activitypub\Mention', 'replace_with_links' ), $the_content );
+
+ $the_content = str_replace( array_reverse( array_keys( $protected_tags ) ), array_reverse( array_values( $protected_tags ) ), $the_content );
+
+ return $the_content;
+ }
+
+ /**
+ * A callback for preg_replace to build the user links
+ *
+ * @param array $result the preg_match results
+ * @return string the final string
+ */
+ public static function replace_with_links( $result ) {
+ $metadata = \ActivityPub\get_remote_metadata_by_actor( $result[0] );
+ if ( ! is_wp_error( $metadata ) && ! empty( $metadata['url'] ) ) {
+ $username = ltrim( $result[0], '@' );
+ if ( ! empty( $metadata['name'] ) ) {
+ $username = $metadata['name'];
+ }
+ if ( ! empty( $metadata['preferredUsername'] ) ) {
+ $username = $metadata['preferredUsername'];
+ }
+ $username = '@' . $username . '';
+ return \sprintf( '%s', $metadata['url'], $username );
+ }
+
+ return $result[0];
+ }
+
+ /**
+ * Extract the mentions from the post_content.
+ *
+ * @param array $mentions The already found mentions.
+ * @param string $post_content The post content.
+ * @return mixed The discovered mentions.
+ */
+ public static function extract_mentions( $mentions, $post_content ) {
+ \preg_match_all( '/@' . ACTIVITYPUB_USERNAME_REGEXP . '/i', $post_content, $matches );
+ foreach ( $matches[0] as $match ) {
+ $link = \Activitypub\Webfinger::resolve( $match );
+ if ( ! is_wp_error( $link ) ) {
+ $mentions[ $match ] = $link;
+ }
+ }
+ return $mentions;
+
+ }
+}
diff --git a/wp-content/plugins/activitypub/includes/class-shortcodes.php b/wp-content/plugins/activitypub/includes/class-shortcodes.php
new file mode 100644
index 00000000..7289808d
--- /dev/null
+++ b/wp-content/plugins/activitypub/includes/class-shortcodes.php
@@ -0,0 +1,527 @@
+#%s',
+ \get_tag_link( $tag ),
+ $tag->slug
+ );
+ }
+
+ return \implode( ' ', $hash_tags );
+ }
+
+ /**
+ * Generates output for the ap_title shortcode
+ *
+ * @param array $atts shortcode attributes
+ * @param string $content shortcode content
+ * @param string $tag shortcode tag name
+ *
+ * @return string
+ */
+ public static function title( $atts, $content, $tag ) {
+ $post_id = get_the_ID();
+
+ if ( ! $post_id ) {
+ return '';
+ }
+
+ return \get_the_title( $post_id );
+
+ }
+
+ /**
+ * Generates output for the ap_excerpt shortcode
+ *
+ * @param array $atts shortcode attributes
+ * @param string $content shortcode content
+ * @param string $tag shortcode tag name
+ *
+ * @return string
+ */
+ public static function excerpt( $atts, $content, $tag ) {
+ $post = get_post();
+
+ if ( ! $post || \post_password_required( $post ) ) {
+ return '';
+ }
+
+ $atts = shortcode_atts(
+ array( 'length' => ACTIVITYPUB_EXCERPT_LENGTH ),
+ $atts,
+ $tag
+ );
+
+ $excerpt_length = intval( $atts['length'] );
+
+ if ( 0 === $excerpt_length ) {
+ $excerpt_length = ACTIVITYPUB_EXCERPT_LENGTH;
+ }
+
+ $excerpt = \get_post_field( 'post_excerpt', $post );
+
+ if ( '' === $excerpt ) {
+
+ $content = \get_post_field( 'post_content', $post );
+
+ // An empty string will make wp_trim_excerpt do stuff we do not want.
+ if ( '' !== $content ) {
+ $excerpt = \strip_shortcodes( $content );
+
+ /** This filter is documented in wp-includes/post-template.php */
+ $excerpt = \apply_filters( 'the_content', $excerpt );
+ $excerpt = \str_replace( ']]>', ']]>', $excerpt );
+ }
+ }
+
+ // Strip out any remaining tags.
+ $excerpt = \wp_strip_all_tags( $excerpt );
+
+ /** This filter is documented in wp-includes/formatting.php */
+ $excerpt_more = \apply_filters( 'excerpt_more', ' [...]' );
+ $excerpt_more_len = strlen( $excerpt_more );
+
+ // We now have a excerpt, but we need to check it's length, it may be longer than we want for two reasons:
+ //
+ // * The user has entered a manual excerpt which is longer that what we want.
+ // * No manual excerpt exists so we've used the content which might be longer than we want.
+ //
+ // Either way, let's trim it up if we need too. Also, don't forget to take into account the more indicator
+ // as part of the total length.
+ //
+
+ // Setup a variable to hold the current excerpts length.
+ $current_excerpt_length = strlen( $excerpt );
+
+ // Setup a variable to keep track of our target length.
+ $target_excerpt_length = $excerpt_length - $excerpt_more_len;
+
+ // Setup a variable to keep track of the current max length.
+ $current_excerpt_max = $target_excerpt_length;
+
+ // This is a loop since we can't calculate word break the string after 'the_excpert' filter has run (we would break
+ // all kinds of html tags), so we have to cut the excerpt down a bit at a time until we hit our target length.
+ while ( $current_excerpt_length > $target_excerpt_length && $current_excerpt_max > 0 ) {
+ // Trim the excerpt based on wordwrap() positioning.
+ // Note: we're using ' );
- \defined( 'ACTIVITYPUB_CUSTOM_POST_CONTENT' ) || \define( 'ACTIVITYPUB_CUSTOM_POST_CONTENT', "
as the linebreak just in case there are any newlines existing in the excerpt from the user.
+ // There won't be any
left after we've run wp_strip_all_tags() in the code above, so they're
+ // safe to use here. It won't be included in the final excerpt as the substr() will trim it off.
+ $excerpt = substr( $excerpt, 0, strpos( wordwrap( $excerpt, $current_excerpt_max, '
' ), '
' ) );
+
+ // If something went wrong, or we're in a language that wordwrap() doesn't understand,
+ // just chop it off and don't worry about breaking in the middle of a word.
+ if ( strlen( $excerpt ) > $excerpt_length - $excerpt_more_len ) {
+ $excerpt = substr( $excerpt, 0, $current_excerpt_max );
+ }
+
+ // Add in the more indicator.
+ $excerpt = $excerpt . $excerpt_more;
+
+ // Run it through the excerpt filter which will add some html tags back in.
+ $excerpt_filtered = apply_filters( 'the_excerpt', $excerpt );
+
+ // Now set the current excerpt length to this new filtered length.
+ $current_excerpt_length = strlen( $excerpt_filtered );
+
+ // Check to see if we're over the target length.
+ if ( $current_excerpt_length > $target_excerpt_length ) {
+ // If so, remove 20 characters from the current max and run the loop again.
+ $current_excerpt_max = $current_excerpt_max - 20;
+ }
+ }
+
+ return \apply_filters( 'the_excerpt', $excerpt );
+ }
+
+ /**
+ * Generates output for the ap_content shortcode
+ *
+ * @param array $atts shortcode attributes
+ * @param string $content shortcode content
+ * @param string $tag shortcode tag name
+ *
+ * @return string
+ */
+ public static function content( $atts, $content, $tag ) {
+ $post = get_post();
+
+ if ( ! $post || \post_password_required( $post ) ) {
+ return '';
+ }
+
+ $atts = shortcode_atts(
+ array( 'apply_filters' => 'yes' ),
+ $atts,
+ $tag
+ );
+
+ $content = \get_post_field( 'post_content', $post );
+
+ if ( 'yes' === $atts['apply_filters'] ) {
+ $content = \apply_filters( 'the_content', $content );
+ } else {
+ $content = do_blocks( $content );
+ $content = wptexturize( $content );
+ $content = wp_filter_content_tags( $content );
+ }
+
+ // replace script and style elements
+ $content = \preg_replace( '@<(script|style)[^>]*?>.*?\\1>@si', '', $content );
+
+ $content = \trim( \preg_replace( '/[\n\r\t]/', '', $content ) );
+
+ return $content;
+ }
+
+ /**
+ * Generates output for the ap_permalink shortcode
+ *
+ * @param array $atts shortcode attributes
+ * @param string $content shortcode content
+ * @param string $tag shortcode tag name
+ *
+ * @return string
+ */
+ public static function permalink( $atts, $content, $tag ) {
+ $post = get_post();
+
+ if ( ! $post ) {
+ return '';
+ }
+
+ $atts = shortcode_atts(
+ array(
+ 'type' => 'url',
+ ),
+ $atts,
+ $tag
+ );
+
+ if ( 'url' === $atts['type'] ) {
+ return \esc_url( \get_permalink( $post->ID ) );
+ }
+
+ return \sprintf( '%1$s', \esc_url( \get_permalink( $post->ID ) ) );
+ }
+
+ /**
+ * Generates output for the ap_shortlink shortcode
+ *
+ * @param array $atts shortcode attributes
+ * @param string $content shortcode content
+ * @param string $tag shortcode tag name
+ *
+ * @return string
+ */
+ public static function shortlink( $atts, $content, $tag ) {
+ $post = get_post();
+
+ if ( ! $post ) {
+ return '';
+ }
+
+ $atts = shortcode_atts(
+ array(
+ 'type' => 'url',
+ ),
+ $atts,
+ $tag
+ );
+
+ if ( 'url' === $atts['type'] ) {
+ return \esc_url( \wp_get_shortlink( $post->ID ) );
+ }
+
+ return \sprintf( '%1$s', \esc_url( \wp_get_shortlink( $post->ID ) ) );
+ }
+
+ /**
+ * Generates output for the ap_image shortcode
+ *
+ * @param array $atts shortcode attributes
+ * @param string $content shortcode content
+ * @param string $tag shortcode tag name
+ *
+ * @return string
+ */
+ public static function image( $atts, $content, $tag ) {
+ $post_id = get_the_ID();
+
+ if ( ! $post_id ) {
+ return '';
+ }
+
+ $atts = shortcode_atts(
+ array(
+ 'type' => 'full',
+ ),
+ $atts,
+ $tag
+ );
+
+ $size = 'full';
+
+ if ( in_array(
+ $atts['type'],
+ array( 'thumbnail', 'medium', 'large', 'full' ),
+ true
+ ) ) {
+ $size = $atts['type'];
+ }
+
+ $image = \get_the_post_thumbnail_url( $post_id, $size );
+
+ if ( ! $image ) {
+ return '';
+ }
+
+ return \esc_url( $image );
+ }
+
+ /**
+ * Generates output for the ap_hashcats shortcode
+ *
+ * @param array $atts shortcode attributes
+ * @param string $content shortcode content
+ * @param string $tag shortcode tag name
+ *
+ * @return string
+ */
+ public static function hashcats( $atts, $content, $tag ) {
+ $post_id = get_the_ID();
+
+ if ( ! $post_id ) {
+ return '';
+ }
+
+ $categories = \get_the_category( $post_id );
+
+ if ( ! $categories ) {
+ return '';
+ }
+
+ $hash_tags = array();
+
+ foreach ( $categories as $category ) {
+ $hash_tags[] = \sprintf( '#%s', \get_category_link( $category ), $category->slug );
+ }
+
+ return \implode( ' ', $hash_tags );
+ }
+
+ /**
+ * Generates output for the ap_author shortcode
+ *
+ * @param array $atts shortcode attributes
+ * @param string $content shortcode content
+ * @param string $tag shortcode tag name
+ *
+ * @return string
+ */
+ public static function author( $atts, $content, $tag ) {
+ $post = get_post();
+
+ if ( ! $post ) {
+ return '';
+ }
+
+ $name = \get_the_author_meta( 'display_name', $post->post_author );
+
+ if ( ! $name ) {
+ return '';
+ }
+
+ return $name;
+ }
+
+ /**
+ * Generates output for the ap_authorurl shortcode
+ *
+ * @param array $atts shortcode attributes
+ * @param string $content shortcode content
+ * @param string $tag shortcode tag name
+ *
+ * @return string
+ */
+ public static function authorurl( $atts, $content, $tag ) {
+ $post = get_post();
+
+ if ( ! $post ) {
+ return '';
+ }
+
+ $url = \get_the_author_meta( 'user_url', $post->post_author );
+
+ if ( ! $url ) {
+ return '';
+ }
+
+ return \esc_url( $url );
+ }
+
+ /**
+ * Generates output for the ap_blogurl shortcode
+ *
+ * @param array $atts shortcode attributes
+ * @param string $content shortcode content
+ * @param string $tag shortcode tag name
+ *
+ * @return string
+ */
+ public static function blogurl( $atts, $content, $tag ) {
+ return \esc_url( \get_bloginfo( 'url' ) );
+ }
+
+ /**
+ * Generates output for the ap_blogname shortcode
+ *
+ * @param array $atts shortcode attributes
+ * @param string $content shortcode content
+ * @param string $tag shortcode tag name
+ *
+ * @return string
+ */
+ public static function blogname( $atts, $content, $tag ) {
+ return \get_bloginfo( 'name' );
+ }
+
+ /**
+ * Generates output for the ap_blogdesc shortcode
+ *
+ * @param array $atts shortcode attributes
+ * @param string $content shortcode content
+ * @param string $tag shortcode tag name
+ *
+ * @return string
+ */
+ public static function blogdesc( $atts, $content, $tag ) {
+ return \get_bloginfo( 'description' );
+ }
+
+ /**
+ * Generates output for the ap_date shortcode
+ *
+ * @param array $atts shortcode attributes
+ * @param string $content shortcode content
+ * @param string $tag shortcode tag name
+ *
+ * @return string
+ */
+ public static function date( $atts, $content, $tag ) {
+ $post = get_post();
+
+ if ( ! $post ) {
+ return '';
+ }
+
+ $datetime = \get_post_datetime( $post );
+ $dateformat = \get_option( 'date_format' );
+ $timeformat = \get_option( 'time_format' );
+
+ $date = $datetime->format( $dateformat );
+
+ if ( ! $date ) {
+ return '';
+ }
+
+ return $date;
+ }
+
+ /**
+ * Generates output for the ap_time shortcode
+ *
+ * @param array $atts shortcode attributes
+ * @param string $content shortcode content
+ * @param string $tag shortcode tag name
+ *
+ * @return string
+ */
+ public static function time( $atts, $content, $tag ) {
+ $post = get_post();
+
+ if ( ! $post ) {
+ return '';
+ }
+
+ $datetime = \get_post_datetime( $post );
+ $dateformat = \get_option( 'date_format' );
+ $timeformat = \get_option( 'time_format' );
+
+ $date = $datetime->format( $timeformat );
+
+ if ( ! $date ) {
+ return '';
+ }
+
+ return $date;
+ }
+
+ /**
+ * Generates output for the ap_datetime shortcode
+ *
+ * @param array $atts shortcode attributes
+ * @param string $content shortcode content
+ * @param string $tag shortcode tag name
+ *
+ * @return string
+ */
+ public static function datetime( $atts, $content, $tag ) {
+ $post = get_post();
+
+ if ( ! $post ) {
+ return '';
+ }
+
+ $datetime = \get_post_datetime( $post );
+ $dateformat = \get_option( 'date_format' );
+ $timeformat = \get_option( 'time_format' );
+
+ $date = $datetime->format( $dateformat . ' @ ' . $timeformat );
+
+ if ( ! $date ) {
+ return '';
+ }
+
+ return $date;
+ }
+}
diff --git a/wp-content/plugins/activitypub/includes/class-webfinger.php b/wp-content/plugins/activitypub/includes/class-webfinger.php
index 8906b60b..ab33411b 100644
--- a/wp-content/plugins/activitypub/includes/class-webfinger.php
+++ b/wp-content/plugins/activitypub/includes/class-webfinger.php
@@ -28,12 +28,21 @@ class Webfinger {
}
public static function resolve( $account ) {
- if ( ! preg_match( '/^@?[^@]+@((?:[a-z0-9-]+\.)+[a-z]+)$/i', $account, $m ) ) {
+ if ( ! preg_match( '/^@?' . ACTIVITYPUB_USERNAME_REGEXP . '$/i', $account, $m ) ) {
return null;
}
- $url = \add_query_arg( 'resource', 'acct:' . ltrim( $account, '@' ), 'https://' . $m[1] . '/.well-known/webfinger' );
+ $transient_key = 'activitypub_resolve_' . ltrim( $account, '@' );
+
+ $link = \get_transient( $transient_key );
+ if ( $link ) {
+ return $link;
+ }
+
+ $url = \add_query_arg( 'resource', 'acct:' . ltrim( $account, '@' ), 'https://' . $m[2] . '/.well-known/webfinger' );
if ( ! \wp_http_validate_url( $url ) ) {
- return new \WP_Error( 'invalid_webfinger_url', null, $url );
+ $response = new \WP_Error( 'invalid_webfinger_url', null, $url );
+ \set_transient( $transient_key, $response, HOUR_IN_SECONDS ); // Cache the error for a shorter period.
+ return $response;
}
// try to access author URL
@@ -42,28 +51,34 @@ class Webfinger {
array(
'headers' => array( 'Accept' => 'application/activity+json' ),
'redirection' => 0,
+ 'timeout' => 2,
)
);
if ( \is_wp_error( $response ) ) {
- return new \WP_Error( 'webfinger_url_not_accessible', null, $url );
+ $link = new \WP_Error( 'webfinger_url_not_accessible', null, $url );
+ \set_transient( $transient_key, $link, HOUR_IN_SECONDS ); // Cache the error for a shorter period.
+ return $link;
}
- $response_code = \wp_remote_retrieve_response_code( $response );
-
$body = \wp_remote_retrieve_body( $response );
$body = \json_decode( $body, true );
- if ( ! isset( $body['links'] ) ) {
- return new \WP_Error( 'webfinger_url_invalid_response', null, $url );
+ if ( empty( $body['links'] ) ) {
+ $link = new \WP_Error( 'webfinger_url_invalid_response', null, $url );
+ \set_transient( $transient_key, $link, HOUR_IN_SECONDS ); // Cache the error for a shorter period.
+ return $link;
}
foreach ( $body['links'] as $link ) {
if ( 'self' === $link['rel'] && 'application/activity+json' === $link['type'] ) {
+ \set_transient( $transient_key, $link['href'], WEEK_IN_SECONDS );
return $link['href'];
}
}
- return new \WP_Error( 'webfinger_url_no_activity_pub', null, $body );
+ $link = new \WP_Error( 'webfinger_url_no_activity_pub', null, $body );
+ \set_transient( $transient_key, $link, HOUR_IN_SECONDS ); // Cache the error for a shorter period.
+ return $link;
}
}
diff --git a/wp-content/plugins/activitypub/includes/functions.php b/wp-content/plugins/activitypub/includes/functions.php
index 1abb9d1c..8f2e5d93 100644
--- a/wp-content/plugins/activitypub/includes/functions.php
+++ b/wp-content/plugins/activitypub/includes/functions.php
@@ -68,7 +68,7 @@ function safe_remote_get( $url, $user_id ) {
$wp_version = \get_bloginfo( 'version' );
$user_agent = \apply_filters( 'http_headers_useragent', 'WordPress/' . $wp_version . '; ' . \get_bloginfo( 'url' ) );
$args = array(
- 'timeout' => 100,
+ 'timeout' => apply_filters( 'activitypub_remote_get_timeout', 100 ),
'limit_response_size' => 1048576,
'redirection' => 3,
'user-agent' => "$user_agent; ActivityPub",
@@ -110,8 +110,8 @@ function get_remote_metadata_by_actor( $actor ) {
if ( $pre ) {
return $pre;
}
- if ( preg_match( '/^@?[^@]+@((?:[a-z0-9-]+\.)+[a-z]+)$/i', $actor ) ) {
- $actor = \Activitypub\Webfinger::resolve( $actor );
+ if ( preg_match( '/^@?' . ACTIVITYPUB_USERNAME_REGEXP . '$/i', $actor ) ) {
+ $actor = Webfinger::resolve( $actor );
}
if ( ! $actor ) {
@@ -122,30 +122,37 @@ function get_remote_metadata_by_actor( $actor ) {
return $actor;
}
- $metadata = \get_transient( 'activitypub_' . $actor );
+ $transient_key = 'activitypub_' . $actor;
+ $metadata = \get_transient( $transient_key );
if ( $metadata ) {
return $metadata;
}
if ( ! \wp_http_validate_url( $actor ) ) {
- return new \WP_Error( 'activitypub_no_valid_actor_url', \__( 'The "actor" is no valid URL', 'activitypub' ), $actor );
+ $metadata = new \WP_Error( 'activitypub_no_valid_actor_url', \__( 'The "actor" is no valid URL', 'activitypub' ), $actor );
+ \set_transient( $transient_key, $metadata, HOUR_IN_SECONDS ); // Cache the error for a shorter period.
+ return $metadata;
}
$user = \get_users(
array(
'number' => 1,
- 'who' => 'authors',
+ 'capability__in' => array( 'publish_posts' ),
'fields' => 'ID',
)
);
// we just need any user to generate a request signature
$user_id = \reset( $user );
-
+ $short_timeout = function() {
+ return 3;
+ };
+ add_filter( 'activitypub_remote_get_timeout', $short_timeout );
$response = \Activitypub\safe_remote_get( $actor, $user_id );
-
+ remove_filter( 'activitypub_remote_get_timeout', $short_timeout );
if ( \is_wp_error( $response ) ) {
+ \set_transient( $transient_key, $response, HOUR_IN_SECONDS ); // Cache the error for a shorter period.
return $response;
}
@@ -153,10 +160,12 @@ function get_remote_metadata_by_actor( $actor ) {
$metadata = \json_decode( $metadata, true );
if ( ! $metadata ) {
- return new \WP_Error( 'activitypub_invalid_json', \__( 'No valid JSON data', 'activitypub' ), $actor );
+ $metadata = new \WP_Error( 'activitypub_invalid_json', \__( 'No valid JSON data', 'activitypub' ), $actor );
+ \set_transient( $transient_key, $metadata, HOUR_IN_SECONDS ); // Cache the error for a shorter period.
+ return $metadata;
}
- \set_transient( 'activitypub_' . $actor, $metadata, WEEK_IN_SECONDS );
+ \set_transient( $transient_key, $metadata, WEEK_IN_SECONDS );
return $metadata;
}
diff --git a/wp-content/plugins/activitypub/includes/help.php b/wp-content/plugins/activitypub/includes/help.php
index 16ffbeab..58339fb0 100644
--- a/wp-content/plugins/activitypub/includes/help.php
+++ b/wp-content/plugins/activitypub/includes/help.php
@@ -2,45 +2,67 @@
\get_current_screen()->add_help_tab(
array(
- 'id' => 'fediverse',
- 'title' => \__( 'Fediverse', 'activitypub' ),
+ 'id' => 'template-tags',
+ 'title' => \__( 'Template Tags', 'activitypub' ),
'content' =>
- '' .
+ '
' .
+ '[ap_title]
[ap_content apply_filters="yes"]
apply_filters
you can decide if filters should be applied or not (default is yes
). The values can be yes
or no
. apply_filters
attribute is optional.', 'activitypub' ), 'default' ) . '[ap_excerpt lenght="400"]
length
attribute is optional.', 'activitypub' ), 'default' ) . '[ap_permalink type="url"]
type
can be either: url
or html
(an <a /> tag). type
attribute is optional.', 'activitypub' ), 'default' ) . '[ap_shortlink type="url"]
type
can be either url
or html
(an <a /> tag). I can recommend Hum, to prettify the Shortlinks. type
attribute is optional.', 'activitypub' ), 'default' ) . '[ap_hashtags]
[ap_hashcats]
[ap_image type=full]
thumbnail
, medium
, large
, full
. type
attribute is optional.', 'activitypub' ), 'default' ) . '[ap_author]
[ap_authorurl]
[ap_date]
[ap_time]
[ap_datetime]
[ap_blogurl]
[ap_blogname]
[ap_blogdesc]
' . \__( 'Fediverse', 'activitypub' ) . '
' . \__( 'The Fediverse is a new word made of two words: "federation" + "universe"', 'activitypub' ) . '
' . '' . \__( 'It is a federated social network running on free open software on a myriad of computers across the globe. Many independent servers are interconnected and allow people to interact with one another. There\'s no one central site: you choose a server to register. This ensures some decentralization and sovereignty of data. Fediverse (also called Fedi) has no built-in advertisements, no tricky algorithms, no one big corporation dictating the rules. Instead we have small cozy communities of like-minded people. Welcome!', 'activitypub' ) . '
' . - '' . \__( 'For more informations please visit fediverse.party', 'activitypub' ) . '
', - ) -); - -\get_current_screen()->add_help_tab( - array( - 'id' => 'activitypub', - 'title' => \__( 'ActivityPub', 'activitypub' ), - 'content' => - '' . \__( 'What is ActivityPub?', 'activitypub' ) . '
' . - '' . \__( 'ActivityPub is a decentralized social networking protocol based on the ActivityStreams 2.0 data format. ActivityPub is an official W3C recommended standard published by the W3C Social Web Working Group. It provides a client to server API for creating, updating and deleting content, as well as a federated server to server API for delivering notifications and subscribing to content.', 'activitypub' ) . '
', - ) -); - -\get_current_screen()->add_help_tab( - array( - 'id' => 'webfinger', - 'title' => \__( 'WebFinger', 'activitypub' ), - 'content' => - '' . \__( 'What is WebFinger?', 'activitypub' ) . '
' . + '' . \__( 'For more informations please visit fediverse.party', 'activitypub' ) . '
' . + '' . \__( 'ActivityPub is a decentralized social networking protocol based on the ActivityStreams 2.0 data format. ActivityPub is an official W3C recommended standard published by the W3C Social Web Working Group. It provides a client to server API for creating, updating and deleting content, as well as a federated server to server API for delivering notifications and subscribing to content.', 'activitypub' ) . '
' . + '' . \__( 'WebFinger is used to discover information about people or other entities on the Internet that are identified by a URI using standard Hypertext Transfer Protocol (HTTP) methods over a secure transport. A WebFinger resource returns a JavaScript Object Notation (JSON) object describing the entity that is queried. The JSON object is referred to as the JSON Resource Descriptor (JRD).', 'activitypub' ) . '
' . '' . \__( 'For a person, the type of information that might be discoverable via WebFinger includes a personal profile address, identity service, telephone number, or preferred avatar. For other entities on the Internet, a WebFinger resource might return JRDs containing link relations that enable a client to discover, for example, that a printer can print in color on A4 paper, the physical location of a server, or other static information.', 'activitypub' ) . '
' . '' . \__( 'On Mastodon [and other Plattforms], user profiles can be hosted either locally on the same website as yours, or remotely on a completely different website. The same username may be used on a different domain. Therefore, a Mastodon user\'s full mention consists of both the username and the domain, in the form @username@domain
. In practical terms, @user@example.com
is not the same as @user@example.org
. If the domain is not included, Mastodon will try to find a local user named @username
. However, in order to deliver to someone over ActivityPub, the @username@domain
mention is not enough – mentions must be translated to an HTTPS URI first, so that the remote actor\'s inbox and outbox can be found. (This paragraph is copied from the Mastodon Documentation)', 'activitypub' ) . '
' . \__( 'For more informations please visit webfinger.net', 'activitypub' ) . '
', - ) -); - -\get_current_screen()->add_help_tab( - array( - 'id' => 'nodeinfo', - 'title' => \__( 'NodeInfo', 'activitypub' ), - 'content' => - '' . \__( 'What is NodeInfo?', 'activitypub' ) . '
' . + '' . \__( 'For more informations please visit webfinger.net', 'activitypub' ) . '
' . + '' . \__( 'NodeInfo is an effort to create a standardized way of exposing metadata about a server running one of the distributed social networks. The two key goals are being able to get better insights into the user base of distributed social networking and the ability to build tools that allow users to choose the best fitting software and server for their needs.', 'activitypub' ) . '
' . '' . \__( 'For more informations please visit nodeinfo.diaspora.software', 'activitypub' ) . '
', ) diff --git a/wp-content/plugins/activitypub/includes/model/class-activity.php b/wp-content/plugins/activitypub/includes/model/class-activity.php index 9de1031c..f865d6dd 100644 --- a/wp-content/plugins/activitypub/includes/model/class-activity.php +++ b/wp-content/plugins/activitypub/includes/model/class-activity.php @@ -45,20 +45,28 @@ class Activity { } } - public function from_post( $object ) { - $this->object = $object; + public function from_post( Post $post ) { + $this->object = $post->to_array(); + if ( isset( $object['published'] ) ) { $this->published = $object['published']; } + $this->cc = array( \get_rest_url( null, '/activitypub/1.0/users/' . intval( $post->get_post_author() ) . '/followers' ) ); - if ( isset( $object['attributedTo'] ) ) { - $this->actor = $object['attributedTo']; + if ( isset( $this->object['attributedTo'] ) ) { + $this->actor = $this->object['attributedTo']; + } + + foreach ( $post->get_tags() as $tag ) { + if ( 'Mention' === $tag['type'] ) { + $this->cc[] = $tag['href']; + } } $type = \strtolower( $this->type ); - if ( isset( $object['id'] ) ) { - $this->id = add_query_arg( 'activity', $type, $object['id'] ); + if ( isset( $this->object['id'] ) ) { + $this->id = add_query_arg( 'activity', $type, $this->object['id'] ); } } diff --git a/wp-content/plugins/activitypub/includes/model/class-post.php b/wp-content/plugins/activitypub/includes/model/class-post.php index cd8f119e..d83384ee 100644 --- a/wp-content/plugins/activitypub/includes/model/class-post.php +++ b/wp-content/plugins/activitypub/includes/model/class-post.php @@ -7,31 +7,127 @@ namespace Activitypub\Model; * @author Matthias Pfefferle */ class Post { + /** + * The WordPress Post Object. + * + * @var WP_Post + */ private $post; + + /** + * The Post Author. + * + * @var string + */ private $post_author; + + /** + * The Object ID. + * + * @var string + */ private $id; + + /** + * The Object Summary. + * + * @var string + */ private $summary; + + /** + * The Object Summary + * + * @var string + */ private $content; + + /** + * The Object Attachments. This is usually a list of Images. + * + * @var array + */ private $attachments; + + /** + * The Object Tags. This is usually the list of used Hashtags. + * + * @var array + */ private $tags; + + /** + * The Onject Type + * + * @var string + */ private $object_type; - public function __construct( $post = null ) { - $this->post = \get_post( $post ); + /** + * The Allowed Tags, used in the content. + * + * @var array + */ + private $allowed_tags = array( + 'a' => array( + 'href' => array(), + 'title' => array(), + 'class' => array(), + 'rel' => array(), + ), + 'br' => array(), + 'p' => array( + 'class' => array(), + ), + 'span' => array( + 'class' => array(), + ), + 'div' => array( + 'class' => array(), + ), + 'ul' => array(), + 'ol' => array(), + 'li' => array(), + 'strong' => array( + 'class' => array(), + ), + 'b' => array( + 'class' => array(), + ), + 'i' => array( + 'class' => array(), + ), + 'em' => array( + 'class' => array(), + ), + 'blockquote' => array(), + 'cite' => array(), + ); - $this->post_author = $this->post->post_author; - $this->id = $this->generate_id(); - $this->summary = $this->generate_the_title(); - $this->content = $this->generate_the_content(); - $this->attachments = $this->generate_attachments(); - $this->tags = $this->generate_tags(); - $this->object_type = $this->generate_object_type(); + /** + * Constructor + * + * @param WP_Post $post + */ + public function __construct( $post ) { + $this->post = \get_post( $post ); } + /** + * Magic function to implement getter and setter + * + * @param string $method + * @param string $params + * + * @return void + */ public function __call( $method, $params ) { $var = \strtolower( \substr( $method, 4 ) ); if ( \strncasecmp( $method, 'get', 3 ) === 0 ) { + if ( empty( $this->$var ) && ! empty( $this->post->$var ) ) { + return $this->post->$var; + } return $this->$var; } @@ -40,34 +136,53 @@ class Post { } } + /** + * Converts this Object into an Array. + * + * @return array + */ public function to_array() { $post = $this->post; $array = array( - 'id' => $this->id, - 'type' => $this->object_type, + 'id' => $this->get_id(), + 'type' => $this->get_object_type(), 'published' => \gmdate( 'Y-m-d\TH:i:s\Z', \strtotime( $post->post_date_gmt ) ), 'attributedTo' => \get_author_posts_url( $post->post_author ), - 'summary' => $this->summary, + 'summary' => $this->get_summary(), 'inReplyTo' => null, - 'content' => $this->content, + 'content' => $this->get_content(), 'contentMap' => array( - \strstr( \get_locale(), '_', true ) => $this->content, + \strstr( \get_locale(), '_', true ) => $this->get_content(), ), 'to' => array( 'https://www.w3.org/ns/activitystreams#Public' ), 'cc' => array( 'https://www.w3.org/ns/activitystreams#Public' ), - 'attachment' => $this->attachments, - 'tag' => $this->tags, + 'attachment' => $this->get_attachments(), + 'tag' => $this->get_tags(), ); - return \apply_filters( 'activitypub_post', $array ); + return \apply_filters( 'activitypub_post', $array, $this->post ); } + /** + * Converts this Object into a JSON String + * + * @return string + */ public function to_json() { return \wp_json_encode( $this->to_array(), \JSON_HEX_TAG | \JSON_HEX_AMP | \JSON_HEX_QUOT ); } - public function generate_id() { + /** + * Returns the ID of an Activity Object + * + * @return string + */ + public function get_id() { + if ( $this->id ) { + return $this->id; + } + $post = $this->post; if ( 'trash' === get_post_status( $post ) ) { @@ -76,42 +191,57 @@ class Post { $permalink = \get_permalink( $post ); } + $this->id = $permalink; + return $permalink; } - public function generate_attachments() { - $max_images = \apply_filters( 'activitypub_max_images', 3 ); + /** + * Returns a list of Image Attachments + * + * @return array + */ + public function get_attachments() { + if ( $this->attachments ) { + return $this->attachments; + } + + $max_images = intval( \apply_filters( 'activitypub_max_image_attachments', \get_option( 'activitypub_max_image_attachments', ACTIVITYPUB_MAX_IMAGE_ATTACHMENTS ) ) ); $images = array(); // max images can't be negative or zero if ( $max_images <= 0 ) { - $max_images = 1; + return $images; } $id = $this->post->ID; $image_ids = array(); + // list post thumbnail first if this post has one if ( \function_exists( 'has_post_thumbnail' ) && \has_post_thumbnail( $id ) ) { $image_ids[] = \get_post_thumbnail_id( $id ); $max_images--; } - // then list any image attachments - $query = new \WP_Query( - array( - 'post_parent' => $id, - 'post_status' => 'inherit', - 'post_type' => 'attachment', - 'post_mime_type' => 'image', - 'order' => 'ASC', - 'orderby' => 'menu_order ID', - 'posts_per_page' => $max_images, - ) - ); - foreach ( $query->get_posts() as $attachment ) { - if ( ! \in_array( $attachment->ID, $image_ids, true ) ) { - $image_ids[] = $attachment->ID; + + if ( $max_images > 0 ) { + // then list any image attachments + $query = new \WP_Query( + array( + 'post_parent' => $id, + 'post_status' => 'inherit', + 'post_type' => 'attachment', + 'post_mime_type' => 'image', + 'order' => 'ASC', + 'orderby' => 'menu_order ID', + 'posts_per_page' => $max_images, + ) + ); + foreach ( $query->get_posts() as $attachment ) { + if ( ! \in_array( $attachment->ID, $image_ids, true ) ) { + $image_ids[] = $attachment->ID; + } } } @@ -136,10 +266,21 @@ class Post { } } + $this->attachments = $images; + return $images; } - public function generate_tags() { + /** + * Returns a list of Tags, used in the Post + * + * @return array + */ + public function get_tags() { + if ( $this->tags ) { + return $this->tags; + } + $tags = array(); $post_tags = \get_the_tags( $this->post->ID ); @@ -154,18 +295,33 @@ class Post { } } + $mentions = apply_filters( 'activitypub_extract_mentions', array(), $this->post->post_content, $this ); + if ( $mentions ) { + foreach ( $mentions as $mention => $url ) { + $tag = array( + 'type' => 'Mention', + 'href' => $url, + 'name' => $mention, + ); + $tags[] = $tag; + } + } + + $this->tags = $tags; + return $tags; } /** * Returns the as2 object-type for a given post * - * @param string $type the object-type - * @param Object $post the post-object - * * @return string the object-type */ - public function generate_object_type() { + public function get_object_type() { + if ( $this->object_type ) { + return $this->object_type; + } + if ( 'wordpress-post-format' !== \get_option( 'activitypub_object_type', 'note' ) ) { return \ucfirst( \get_option( 'activitypub_object_type', 'note' ) ); } @@ -219,146 +375,103 @@ class Post { break; } + $this->object_type = $object_type; + return $object_type; } - public function generate_the_content() { - $post = $this->post; - $content = $this->get_post_content_template(); + /** + * Returns the content for the ActivityPub Item. + * + * @return string the content + */ + public function get_content() { + global $post; - $content = \str_replace( '%title%', \get_the_title( $post->ID ), $content ); - $content = \str_replace( '%excerpt%', $this->get_the_post_excerpt(), $content ); - $content = \str_replace( '%content%', $this->get_the_post_content(), $content ); - $content = \str_replace( '%permalink%', $this->get_the_post_link( 'permalink' ), $content ); - $content = \str_replace( '%shortlink%', $this->get_the_post_link( 'shortlink' ), $content ); - $content = \str_replace( '%hashtags%', $this->get_the_post_hashtags(), $content ); - // backwards compatibility - $content = \str_replace( '%tags%', $this->get_the_post_hashtags(), $content ); - - $content = \trim( \preg_replace( '/[\r\n]{2,}/', '', $content ) ); - - $filtered_content = \apply_filters( 'activitypub_the_content', $content, $this->post ); - $decoded_content = \html_entity_decode( $filtered_content, \ENT_QUOTES, 'UTF-8' ); - - $allowed_html = \apply_filters( 'activitypub_allowed_html', \get_option( 'activitypub_allowed_html', ACTIVITYPUB_ALLOWED_HTML ) ); - - if ( $allowed_html ) { - return \strip_tags( $decoded_content, $allowed_html ); + if ( $this->content ) { + return $this->content; } - return $decoded_content; + // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited + $post = $this->post; + $content = $this->get_post_content_template(); + + // Fill in the shortcodes. + setup_postdata( $post ); + $content = do_shortcode( $content ); + wp_reset_postdata(); + + $content = \wpautop( \wp_kses( $content, $this->allowed_tags ) ); + $content = \trim( \preg_replace( '/[\n\r\t]/', '', $content ) ); + + $content = \apply_filters( 'activitypub_the_content', $content, $post ); + $content = \html_entity_decode( $content, \ENT_QUOTES, 'UTF-8' ); + + $this->content = $content; + + return $content; } + /** + * Gets the template to use to generate the content of the activitypub item. + * + * @return string the template + */ public function get_post_content_template() { if ( 'excerpt' === \get_option( 'activitypub_post_content_type', 'content' ) ) { - return "%excerpt%\n\n%permalink%
"; + return "[ap_excerpt]\n\n[ap_permalink type=\"html\"]"; } if ( 'title' === \get_option( 'activitypub_post_content_type', 'content' ) ) { - return "%title%
\n\n%permalink%
"; + return "[ap_title]\n\n[ap_permalink type=\"html\"]"; } if ( 'content' === \get_option( 'activitypub_post_content_type', 'content' ) ) { - return "%content%\n\n%hashtags%
\n\n%permalink%
"; + return "[ap_content]\n\n[ap_hashtags]\n\n[ap_permalink type=\"html\"]"; } - return \get_option( 'activitypub_custom_post_content', ACTIVITYPUB_CUSTOM_POST_CONTENT ); + // Upgrade from old template codes to shortcodes. + $content = self::upgrade_post_content_template(); + + return $content; } /** - * Get the excerpt for a post for use outside of the loop. + * Updates the custom template to use shortcodes instead of the deprecated templates. * - * @param int Optional excerpt length. - * - * @return string The excerpt. + * @return string the updated template content */ - public function get_the_post_excerpt( $excerpt_length = 400 ) { - $post = $this->post; + public static function upgrade_post_content_template() { + // Get the custom template. + $old_content = \get_option( 'activitypub_custom_post_content', ACTIVITYPUB_CUSTOM_POST_CONTENT ); - $excerpt = \get_post_field( 'post_excerpt', $post ); + // If the old content exists but is a blank string, we're going to need a flag to updated it even + // after setting it to the default contents. + $need_update = false; - if ( '' === $excerpt ) { - - $content = \get_post_field( 'post_content', $post ); - - // An empty string will make wp_trim_excerpt do stuff we do not want. - if ( '' !== $content ) { - - $excerpt = \strip_shortcodes( $content ); - - /** This filter is documented in wp-includes/post-template.php */ - $excerpt = \apply_filters( 'the_content', $excerpt ); - $excerpt = \str_replace( ']]>', ']]>', $excerpt ); - - $excerpt_length = \apply_filters( 'excerpt_length', $excerpt_length ); - - /** This filter is documented in wp-includes/formatting.php */ - $excerpt_more = \apply_filters( 'excerpt_more', ' [...]' ); - - $excerpt = \wp_trim_words( $excerpt, $excerpt_length, $excerpt_more ); - } + // If the old contents is blank, use the defaults. + if ( '' === $old_content ) { + $old_content = ACTIVITYPUB_CUSTOM_POST_CONTENT; + $need_update = true; } - return \apply_filters( 'the_excerpt', $excerpt ); - } + // Set the new content to be the old content. + $content = $old_content; - /** - * Get the content for a post for use outside of the loop. - * - * @return string The content. - */ - public function get_the_post_content() { - $post = $this->post; + // Convert old templates to shortcodes. + $content = \str_replace( '%title%', '[ap_title]', $content ); + $content = \str_replace( '%excerpt%', '[ap_excerpt]', $content ); + $content = \str_replace( '%content%', '[ap_content]', $content ); + $content = \str_replace( '%permalink%', '[ap_permalink type="html"]', $content ); + $content = \str_replace( '%shortlink%', '[ap_shortlink type="html"]', $content ); + $content = \str_replace( '%hashtags%', '[ap_hashtags]', $content ); + $content = \str_replace( '%tags%', '[ap_hashtags]', $content ); - $content = \get_post_field( 'post_content', $post ); - - return \apply_filters( 'the_content', $content ); - } - - /** - * Adds a backlink to the post/summary content - * - * @param string $content - * @param WP_Post $post - * - * @return string - */ - public function get_the_post_link( $type = 'permalink' ) { - $post = $this->post; - - if ( 'shortlink' === $type ) { - $link = \esc_url( \wp_get_shortlink( $post->ID ) ); - } elseif ( 'permalink' === $type ) { - $link = \esc_url( \get_permalink( $post->ID ) ); - } else { - return ''; + // Store the new template if required. + if ( $content !== $old_content || $need_update ) { + \update_option( 'activitypub_custom_post_content', $content ); } - return \sprintf( '%1$s', $link ); - } - - /** - * Adds all tags as hashtags to the post/summary content - * - * @param string $content - * @param WP_Post $post - * - * @return string - */ - public function get_the_post_hashtags() { - $post = $this->post; - $tags = \get_the_tags( $post->ID ); - - if ( ! $tags ) { - return ''; - } - - $hash_tags = array(); - - foreach ( $tags as $tag ) { - $hash_tags[] = \sprintf( '#%s', \get_tag_link( $tag ), $tag->slug ); - } - - return \implode( ' ', $hash_tags ); + return $content; } } diff --git a/wp-content/plugins/activitypub/includes/rest/class-inbox.php b/wp-content/plugins/activitypub/includes/rest/class-inbox.php index 5c21f43c..5d6b6ce5 100644 --- a/wp-content/plugins/activitypub/includes/rest/class-inbox.php +++ b/wp-content/plugins/activitypub/includes/rest/class-inbox.php @@ -491,11 +491,21 @@ class Inbox { foreach ( array( 'to', 'bto', 'cc', 'bcc', 'audience' ) as $i ) { if ( array_key_exists( $i, $data ) ) { - $recipient_items = array_merge( $recipient_items, $data[ $i ] ); + if ( is_array( $data[ $i ] ) ) { + $recipient = $data[ $i ]; + } else { + $recipient = array( $data[ $i ] ); + } + $recipient_items = array_merge( $recipient_items, $recipient ); } if ( array_key_exists( $i, $data['object'] ) ) { - $recipient_items = array_merge( $recipient_items, $data[ $i ] ); + if ( is_array( $data['object'][ $i ] ) ) { + $recipient = $data['object'][ $i ]; + } else { + $recipient = array( $data['object'][ $i ] ); + } + $recipient_items = array_merge( $recipient_items, $recipient ); } } diff --git a/wp-content/plugins/activitypub/includes/rest/class-outbox.php b/wp-content/plugins/activitypub/includes/rest/class-outbox.php index 7eec5ac2..615f06b9 100644 --- a/wp-content/plugins/activitypub/includes/rest/class-outbox.php +++ b/wp-content/plugins/activitypub/includes/rest/class-outbox.php @@ -103,7 +103,7 @@ class Outbox { foreach ( $posts as $post ) { $activitypub_post = new \Activitypub\Model\Post( $post ); $activitypub_activity = new \Activitypub\Model\Activity( 'Create', \Activitypub\Model\Activity::TYPE_NONE ); - $activitypub_activity->from_post( $activitypub_post->to_array() ); + $activitypub_activity->from_post( $activitypub_post ); $json->orderedItems[] = $activitypub_activity->to_array(); // phpcs:ignore } } diff --git a/wp-content/plugins/activitypub/includes/rest/class-server.php b/wp-content/plugins/activitypub/includes/rest/class-server.php deleted file mode 100644 index ac89dcac..00000000 --- a/wp-content/plugins/activitypub/includes/rest/class-server.php +++ /dev/null @@ -1,35 +0,0 @@ -get_content_type(); - - if ( ! $content_type ) { - return parent::dispatch( $request ); - } - - // check for content-sub-types like 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"' - if ( \preg_match( '/application\/([a-zA-Z+_-]+\+)json/', $content_type['value'] ) ) { - $request->set_header( 'Content-Type', 'application/json' ); - } - - // make request filterable - $request = \apply_filters( 'activitypub_pre_dispatch_request', $request ); - - return parent::dispatch( $request ); - } -} diff --git a/wp-content/plugins/activitypub/integration/class-friends-feed-parser-activitypub.php b/wp-content/plugins/activitypub/integration/class-friends-feed-parser-activitypub.php deleted file mode 100644 index 981c9f41..00000000 --- a/wp-content/plugins/activitypub/integration/class-friends-feed-parser-activitypub.php +++ /dev/null @@ -1,409 +0,0 @@ -friends_feed = $friends_feed; - - \add_action( 'activitypub_inbox', array( $this, 'handle_received_activity' ), 10, 3 ); - \add_action( 'friends_user_feed_activated', array( $this, 'queue_follow_user' ), 10 ); - \add_action( 'friends_user_feed_deactivated', array( $this, 'queue_unfollow_user' ), 10 ); - \add_action( 'friends_feed_parser_activitypub_follow', array( $this, 'follow_user' ), 10, 2 ); - \add_action( 'friends_feed_parser_activitypub_unfollow', array( $this, 'unfollow_user' ), 10, 2 ); - \add_filter( 'friends_rewrite_incoming_url', array( $this, 'friends_rewrite_incoming_url' ), 10, 2 ); - } - - /** - * Allow logging a message via an action. - * @param string $message The message to log. - * @param array $objects Optional objects as meta data. - * @return void - */ - private function log( $message, $objects = array() ) { - do_action( 'friends_activitypub_log', $message, $objects ); - } - - /** - * Determines if this is a supported feed and to what degree we feel it's supported. - * - * @param string $url The url. - * @param string $mime_type The mime type. - * @param string $title The title. - * @param string|null $content The content, it can't be assumed that it's always available. - * - * @return int Return 0 if unsupported, a positive value representing the confidence for the feed, use 10 if you're reasonably confident. - */ - public function feed_support_confidence( $url, $mime_type, $title, $content = null ) { - if ( preg_match( '/^@?[^@]+@((?:[a-z0-9-]+\.)+[a-z]+)$/i', $url ) ) { - return 10; - } - - return 0; - } - - /** - * Format the feed title and autoselect the posts feed. - * - * @param array $feed_details The feed details. - * - * @return array The (potentially) modified feed details. - */ - public function update_feed_details( $feed_details ) { - $meta = \Activitypub\get_remote_metadata_by_actor( $feed_details['url'] ); - if ( ! $meta || is_wp_error( $meta ) ) { - return $meta; - } - - if ( isset( $meta['name'] ) ) { - $feed_details['title'] = $meta['name']; - } elseif ( isset( $meta['preferredUsername'] ) ) { - $feed_details['title'] = $meta['preferredUsername']; - } - - if ( isset( $meta['id'] ) ) { - $feed_details['url'] = $meta['id']; - } - - return $feed_details; - } - - /** - * Rewrite a Mastodon style URL @username@server to a URL via webfinger. - * - * @param string $url The URL to filter. - * @param string $incoming_url Potentially a mastodon identifier. - * - * @return
+
-
+
%title%
- %content%
- %excerpt%
- %permalink%
- %shortlink%
- Hum, to prettify the Shortlinks', 'activitypub' ), 'default' ); ?>%hashtags%
- [ap_title]
- [ap_content]
- [ap_excerpt]
- [ap_permalink]
- [ap_shortlink]
- Hum.', 'activitypub' ), 'default' ); ?>[ap_hashtags]
- [ap_hashcats]
- [ap_image]
-
Let me know if you miss a template pattern.', 'activitypub' ), 'default' ); ?>
+ + ++ %s', 'activitypub' ), + \esc_html( ACTIVITYPUB_MAX_IMAGE_ATTACHMENTS ) + ), + 'default' + ); + ?> +
- -
-
- Leave list empty to support all HTML elements. Default: %s
', 'activitypub' ),
- \esc_html( ACTIVITYPUB_ALLOWED_HTML )
- ),
- 'default'
- );
- ?>
+