PluginProbe
ActivityPub / 5.7.0
ActivityPub v5.7.0
9.3.1 9.3.0 9.2.2 9.2.1 9.2.0 9.1.0 9.0.2 9.0.1 9.0.0 8.3.0 8.2.1 8.2.0 8.1.1 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.2.0 1.3.0 2.0.0 2.0.1 2.1.0 2.1.1 All 160 releases
← All changes | includes/class-webfinger.php +63 -125 8.2.15.7.0 View file →
@@ -6,11 +6,10 @@
6 6 */
7 7
8 8 namespace Activitypub;
9 9
10 -use Activitypub\Activity\Actor;
10 +use WP_Error;
11 11 use Activitypub\Collection\Actors;
12 -use Activitypub\Collection\Remote_Actors;
13 12
14 13 /**
15 14 * ActivityPub WebFinger Class.
16 15 *
@@ -39,9 +38,9 @@
39 38 * Resolve a WebFinger resource.
40 39 *
41 40 * @param string $uri The WebFinger Resource.
42 41 *
43 - * @return string|\WP_Error The URL or WP_Error.
42 + * @return string|WP_Error The URL or WP_Error.
44 43 */
45 44 public static function resolve( $uri ) {
46 45 $data = self::get_data( $uri );
47 46
@@ -49,9 +48,9 @@
49 48 return $data;
50 49 }
51 50
52 51 if ( ! is_array( $data ) || empty( $data['links'] ) ) {
53 - return new \WP_Error(
52 + return new WP_Error(
54 53 'webfinger_missing_links',
55 54 __( 'No valid Link elements found.', 'activitypub' ),
56 55 array(
57 56 'status' => 400,
@@ -72,9 +71,9 @@
72 71 return $link['href'];
73 72 }
74 73 }
75 74
76 - return new \WP_Error(
75 + return new WP_Error(
77 76 'webfinger_url_no_activitypub',
78 77 __( 'The Site supports WebFinger but not ActivityPub', 'activitypub' ),
79 78 array(
80 79 'status' => 400,
@@ -89,9 +88,9 @@
89 88 * @see https://swicg.github.io/activitypub-webfinger/#reverse-discovery
90 89 *
91 90 * @param string $uri The URI (acct:, mailto:, http:, https:).
92 91 *
93 - * @return string|\WP_Error Error or acct URI.
92 + * @return string|WP_Error Error or acct URI.
94 93 */
95 94 public static function uri_to_acct( $uri ) {
96 95 $data = self::get_data( $uri );
97 96
@@ -115,9 +114,9 @@
115 114 }
116 115 }
117 116 }
118 117
119 - return new \WP_Error(
118 + return new WP_Error(
120 119 'webfinger_url_no_acct',
121 120 __( 'No acct URI found.', 'activitypub' ),
122 121 array(
123 122 'status' => 400,
@@ -131,13 +130,13 @@
131 130 * Automatically adds acct: if it's missing.
132 131 *
133 132 * @param string $url The URI (acct:, mailto:, http:, https:).
134 133 *
135 - * @return \WP_Error|array Error reaction or array with identifier and host as values.
134 + * @return WP_Error|array Error reaction or array with identifier and host as values.
136 135 */
137 136 public static function get_identifier_and_host( $url ) {
138 137 if ( ! $url ) {
139 - return new \WP_Error(
138 + return new WP_Error(
140 139 'webfinger_invalid_identifier',
141 140 __( 'Invalid Identifier', 'activitypub' ),
142 141 array(
143 142 'status' => 400,
@@ -172,9 +171,9 @@
172 171 break;
173 172 }
174 173
175 174 if ( empty( $host ) ) {
176 - return new \WP_Error(
175 + return new WP_Error(
177 176 'webfinger_invalid_identifier',
178 177 __( 'Invalid Identifier', 'activitypub' ),
179 178 array(
180 179 'status' => 400,
@@ -190,9 +189,9 @@
190 189 * Get the WebFinger data for a given URI.
191 190 *
192 191 * @param string $uri The Identifier: <identifier>@<host> or URI.
193 192 *
194 - * @return \WP_Error|array Error reaction or array with identifier and host as values.
193 + * @return WP_Error|array Error reaction or array with identifier and host as values.
195 194 */
196 195 public static function get_data( $uri ) {
197 196 $identifier_and_host = self::get_identifier_and_host( $uri );
198 197
@@ -199,30 +198,47 @@
199 198 if ( is_wp_error( $identifier_and_host ) ) {
200 199 return $identifier_and_host;
201 200 }
202 201
202 + $transient_key = self::generate_cache_key( $uri );
203 +
203 204 list( $identifier, $host ) = $identifier_and_host;
204 205
206 + $data = \get_transient( $transient_key );
207 + if ( $data ) {
208 + return $data;
209 + }
210 +
205 211 $webfinger_url = sprintf(
206 212 'https://%s/.well-known/webfinger?resource=%s',
207 213 $host,
208 - \rawurlencode( $identifier )
214 + rawurlencode( $identifier )
209 215 );
210 216
211 - // Use Http::get() which handles all caching (success and errors).
212 - $response = Http::get(
217 + $response = wp_safe_remote_get(
213 218 $webfinger_url,
214 - array( 'headers' => array( 'Accept' => 'application/jrd+json' ) ),
215 - WEEK_IN_SECONDS
219 + array(
220 + 'headers' => array( 'Accept' => 'application/jrd+json' ),
221 + )
216 222 );
217 223
218 - if ( \is_wp_error( $response ) ) {
219 - return $response;
224 + if ( is_wp_error( $response ) ) {
225 + return new WP_Error(
226 + 'webfinger_url_not_accessible',
227 + __( 'The WebFinger Resource is not accessible.', 'activitypub' ),
228 + array(
229 + 'status' => 400,
230 + 'data' => $webfinger_url,
231 + )
232 + );
220 233 }
221 234
222 - $body = \wp_remote_retrieve_body( $response );
235 + $body = wp_remote_retrieve_body( $response );
236 + $data = json_decode( $body, true );
223 237
224 - return \json_decode( $body, true );
238 + \set_transient( $transient_key, $data, WEEK_IN_SECONDS );
239 +
240 + return $data;
225 241 }
226 242
227 243 /**
228 244 * Get the Remote-Follow endpoint for a given URI.
@@ -228,80 +244,21 @@
228 244 * Get the Remote-Follow endpoint for a given URI.
229 245 *
230 246 * @param string $uri The WebFinger Resource URI.
231 247 *
232 - * @return string|\WP_Error Error or the Remote-Follow endpoint URI.
248 + * @return string|WP_Error Error or the Remote-Follow endpoint URI.
233 249 */
234 250 public static function get_remote_follow_endpoint( $uri ) {
235 - return self::get_intent_endpoint( $uri, 'http://ostatus.org/schema/1.0/subscribe' );
236 - }
237 -
238 - /**
239 - * Generate a cache key for a given URI.
240 - *
241 - * @param string $uri A WebFinger Resource URI.
242 - *
243 - * @return string The cache key.
244 - */
245 - public static function generate_cache_key( $uri ) {
246 - $uri = ltrim( $uri, '@' );
247 -
248 - if ( filter_var( $uri, FILTER_VALIDATE_EMAIL ) ) {
249 - $uri = 'acct:' . $uri;
250 - }
251 -
252 - return 'webfinger_' . md5( $uri );
253 - }
254 -
255 - /**
256 - * Infer a shortname from the Actor ID or URL. Used only for fallbacks,
257 - * we will try to use what's supplied.
258 - *
259 - * @param Actor|string $actor_or_uri The Actor or URI.
260 - *
261 - * @return string Hopefully the name of the Follower.
262 - */
263 - public static function guess( $actor_or_uri ) {
264 - if ( ! $actor_or_uri instanceof Actor ) {
265 - $actor = Remote_Actors::fetch_by_uri( $actor_or_uri );
266 - if ( \is_wp_error( $actor ) ) {
267 - return extract_name_from_uri( $actor_or_uri ) . '@' . \wp_parse_url( $actor_or_uri, PHP_URL_HOST );
268 - }
269 -
270 - $actor_or_uri = $actor;
271 - }
272 -
273 - if ( $actor_or_uri->get_preferred_username() ) {
274 - return $actor_or_uri->get_preferred_username() . '@' . \wp_parse_url( $actor_or_uri->get_id(), PHP_URL_HOST );
275 - }
276 -
277 - return extract_name_from_uri( $actor_or_uri->get_id() ) . '@' . \wp_parse_url( $actor_or_uri->get_id(), PHP_URL_HOST );
278 - }
279 -
280 - /**
281 - * Get the Intent endpoint for a given URI and intent.
282 - *
283 - * @since 8.0.0
284 - *
285 - * @see https://codeberg.org/fediverse/fep/src/branch/main/fep/3b86/fep-3b86.md
286 - *
287 - * @param string $uri The WebFinger Resource URI.
288 - * @param string $intent The intent to look for.
289 - * @param bool $fallback Whether to fallback to the Remote-Follow endpoint.
290 - *
291 - * @return string|\WP_Error Error or the Intent endpoint URI (may contain `{uri}` placeholder).
292 - */
293 - public static function get_intent_endpoint( $uri, $intent, $fallback = false ) {
294 251 $data = self::get_data( $uri );
295 252
296 - if ( \is_wp_error( $data ) ) {
253 + if ( is_wp_error( $data ) ) {
297 254 return $data;
298 255 }
299 256
300 257 if ( empty( $data['links'] ) ) {
301 - return new \WP_Error(
258 + return new WP_Error(
302 259 'webfinger_missing_links',
303 - \__( 'No valid Link elements found.', 'activitypub' ),
260 + __( 'No valid Link elements found.', 'activitypub' ),
304 261 array(
305 262 'status' => 400,
306 263 'data' => $data,
307 264 )
@@ -307,56 +264,37 @@
307 264 )
308 265 );
309 266 }
310 267
311 - // Normalize the links with $rel as key.
312 - $links = array();
313 -
314 268 foreach ( $data['links'] as $link ) {
315 - if ( isset( $link['rel'] ) && isset( $link['template'] ) ) {
316 - $links[ \strtolower( $link['rel'] ) ] = $link['template'];
269 + if ( 'http://ostatus.org/schema/1.0/subscribe' === $link['rel'] ) {
270 + return $link['template'];
317 271 }
318 272 }
319 273
320 - $intent = \sanitize_text_field( $intent );
321 - $intent = \strtolower( $intent );
274 + return new WP_Error(
275 + 'webfinger_missing_remote_follow_endpoint',
276 + __( 'No valid Remote-Follow endpoint found.', 'activitypub' ),
277 + array(
278 + 'status' => 400,
279 + 'data' => $data,
280 + )
281 + );
282 + }
322 283
323 - if ( ! \filter_var( $intent, FILTER_VALIDATE_URL ) ) {
324 - $intent = 'https://w3id.org/fep/3b86/' . $intent;
325 - }
284 + /**
285 + * Generate a cache key for a given URI.
286 + *
287 + * @param string $uri A WebFinger Resource URI.
288 + *
289 + * @return string The cache key.
290 + */
291 + public static function generate_cache_key( $uri ) {
292 + $uri = ltrim( $uri, '@' );
326 293
327 - if ( isset( $links[ $intent ] ) ) {
328 - return $links[ $intent ];
294 + if ( filter_var( $uri, FILTER_VALIDATE_EMAIL ) ) {
295 + $uri = 'acct:' . $uri;
329 296 }
330 297
331 - if ( ! $fallback ) {
332 - return new \WP_Error(
333 - 'webfinger_missing_intent_endpoint',
334 - \__( 'No valid Intent endpoint found.', 'activitypub' ),
335 - array(
336 - 'status' => 400,
337 - 'data' => $data,
338 - )
339 - );
340 - }
341 -
342 - if ( isset( $links['http://ostatus.org/schema/1.0/subscribe'] ) ) {
343 - return $links['http://ostatus.org/schema/1.0/subscribe'];
344 - }
345 -
346 - // Last-resort: construct a Mastodon-compatible authorize_interaction URL.
347 - $identifier_and_host = self::get_identifier_and_host( $uri );
348 -
349 - if ( \is_wp_error( $identifier_and_host ) ) {
350 - return new \WP_Error(
351 - 'webfinger_missing_intent_endpoint',
352 - \__( 'No valid Intent endpoint found.', 'activitypub' ),
353 - array(
354 - 'status' => 400,
355 - 'data' => $data,
356 - )
357 - );
358 - }
359 -
360 - return 'https://' . $identifier_and_host[1] . '/authorize_interaction?uri={uri}';
298 + return 'webfinger_' . md5( $uri );
361 299 }
362 300 }