ProShell v2.0
Dashboard
Server Info
Server: 158.106.128.192
PHP: 8.2.33
home
planet5
public_html
bansibaba.com
wp-includes
2026-09-16 14:34:51
Editing: activitypub.php
Cancel
Save Changes
<?php /** * Compatibility shim so Jetpack-signed admin requests can reach the * ActivityPub plugin's auth-gated client-to-server endpoints, used by the * Jetpack-connected site's wp.com Reader to read the timeline and publish * notes. * * Scope: * - Three routes, with method affinity (inbox GET, proxy POST, outbox POST). * - Blog-mode AP sites only; user-mode is out of scope. * - Real OAuth flows are never overridden — when a Bearer is present we * defer to the plugin's normal verification. * * @package automattic/jetpack */ declare( strict_types = 1 ); use Automattic\Jetpack\Connection\Manager as Connection_Manager; use Automattic\Jetpack\Connection\Rest_Authentication; use Automattic\Jetpack\Status; use Automattic\Jetpack\Status\Host; if ( ! defined( 'ABSPATH' ) ) { exit( 0 ); } // The upstream filter passes a third `$scope` arg; the shim deliberately // drops it (`accepted_args = 2`) because a Jetpack-signed admin grants full // client-to-server access by design. add_filter( 'activitypub_oauth_check_permission', 'jetpack_activitypub_reader_auth_check_permission', 10, 2 ); /** * Filter callback for `activitypub_oauth_check_permission`. * * Returns `true` to authorise the request without an AP OAuth bearer when * every scope predicate holds. Returns the incoming `$result` (typically * null) otherwise, letting the plugin's normal OAuth check run. * * `$request` is typed `mixed` rather than `\WP_REST_Request` because the * WordPress filter ABI provides no guarantee — `is_target_route()` performs * the shape check before any method is dispatched on the argument. * * @since 15.9 * * @param mixed $result Result from a previous filter, or null. * @param mixed $request The REST request being checked, expected to be a `\WP_REST_Request`. * @return mixed `true` when authorised; `$result` otherwise. */ function jetpack_activitypub_reader_auth_check_permission( $result, $request ) { if ( null !== $result ) { return $result; } // Only run on sites where the wp.com Reader actually needs the bridge: // connected, non-offline Jetpack sites that aren't wpcom Simple. Simple // sites already share the AP OAuth datastore with the plugin and pass the // standard verify_authentication path. if ( ( new Host() )->is_wpcom_simple() || ! ( new Connection_Manager() )->is_connected() || ( new Status() )->is_offline_mode() ) { return $result; } // A real OAuth client beat us here. Let the plugin handle it normally. if ( jetpack_activitypub_reader_auth_is_oauth_request() ) { return $result; } if ( ! jetpack_activitypub_reader_auth_is_target_route( $request ) ) { return $result; } if ( ! jetpack_activitypub_reader_auth_is_jetpack_signed() ) { return $result; } // Must follow the signing check: Rest_Authentication installs the wpcom // user on user-token signed requests, so the current user is only trustworthy // after that gate has passed. if ( ! current_user_can( 'manage_options' ) ) { return $result; } if ( ! jetpack_activitypub_reader_auth_is_blog_mode() ) { return $result; } return true; } /** * Whether the current request carries a verified AP OAuth bearer. * * Wrapped so the `Server` class absence in non-AP environments is a clean * `false` rather than a fatal. * * @since 15.9 * * @return bool */ function jetpack_activitypub_reader_auth_is_oauth_request(): bool { if ( ! class_exists( 'Activitypub\OAuth\Server' ) ) { return false; } return \Activitypub\OAuth\Server::is_oauth_request(); } /** * Whether the current request was Jetpack-signed (blog or user token). * * Both signing flavours are accepted: the wpcom bridge signs outbound calls * with the user's Jetpack token when one is available and falls back to the * blog token otherwise. Either is sufficient evidence the call originated * from a wpcom shadow request the destination already trusts. * * @since 15.9 * * @return bool */ function jetpack_activitypub_reader_auth_is_jetpack_signed(): bool { if ( ! class_exists( Rest_Authentication::class ) ) { return false; } return Rest_Authentication::is_signed_with_user_token() || Rest_Authentication::is_signed_with_blog_token(); } /** * Whether the destination AP plugin is configured to expose a blog actor. * * Accepts both `'blog'` (blog-only) and `'actor_blog'` (per-user + blog). * On `'actor_blog'` sites the blog actor behaves identically to pure * blog-mode and is the only actor the wpcom Reader operates on — the * route patterns are pinned to `user_id=0`, so widening the grant to * arbitrary user actors is not possible here. * * Pure user-mode (`'actor'`) is still rejected: the blog actor doesn't * exist on those sites, so authorizing `user_id=0` routes would be * nonsensical. * * Uses a `null` sentinel default so an unset option is treated as * "unknown, deny" rather than implicitly accepted — the AP plugin's own * option default is `ACTIVITYPUB_ACTOR_MODE` (i.e. `'actor'`), so * falling back to a blog-accepting mode here would silently widen the * grant surface on fresh installs. * * @since 15.9 * * @return bool */ function jetpack_activitypub_reader_auth_is_blog_mode(): bool { $mode = get_option( 'activitypub_actor_mode', null ); return 'blog' === $mode || 'actor_blog' === $mode; } /** * Whether the request targets one of the three Reader auth-gated routes. * * Each pattern is anchored to the AP namespace and includes a method affinity, * so callers can't widen the shim by sending an unexpected verb at an allowed * path (e.g. POSTing to inbox). * * @since 15.9 * * @param \WP_REST_Request $request The REST request. * @return bool */ function jetpack_activitypub_reader_auth_is_target_route( $request ): bool { if ( ! is_object( $request ) || ! method_exists( $request, 'get_route' ) || ! method_exists( $request, 'get_method' ) ) { return false; } $route = (string) $request->get_route(); $method = strtoupper( (string) $request->get_method() ); // Patterns are pinned to the blog actor (user_id 0) on purpose: the wpcom // Reader only operates on the blog actor, and granting the OAuth bypass // for arbitrary user ids would silently widen the surface if the AP // plugin ever loosened its downstream `verify_owner` check. static $patterns = array( 'GET' => array( '#^/activitypub/\d+\.\d+/(?:users|actors)/0/inbox/?$#', ), 'POST' => array( '#^/activitypub/\d+\.\d+/proxy/?$#', '#^/activitypub/\d+\.\d+/(?:users|actors)/0/outbox/?$#', ), ); if ( ! isset( $patterns[ $method ] ) ) { return false; } foreach ( $patterns[ $method ] as $pattern ) { if ( preg_match( $pattern, $route ) ) { return true; } } return false; }
Upload Files
Cancel
Upload
Create New
Cancel
Create
Change Permissions
Cancel
Save
Change Date
Cancel
Save
Rename Item
Cancel
Save
Confirm Delete
Are you sure you want to delete the selected items?
Cancel
Delete