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/rest/class-actors-controller.php +21 -90 9.2.05.7.0 View file →
@@ -9,9 +9,9 @@
9 9
10 10 use Activitypub\Collection\Actors as Actor_Collection;
11 11 use Activitypub\Webfinger;
12 12
13 -use function Activitypub\get_client_ip;
13 +use function Activitypub\is_activitypub_request;
14 14
15 15 /**
16 16 * ActivityPub Actors REST-Class.
17 17 *
@@ -19,10 +19,8 @@
19 19 *
20 20 * @see https://www.w3.org/TR/activitypub/#followers
21 21 */
22 22 class Actors_Controller extends \WP_REST_Controller {
23 - use Verification;
24 -
25 23 /**
26 24 * The namespace of this controller's route.
27 25 *
28 26 * @var string
@@ -33,9 +31,9 @@
33 31 * The base of this controller's route.
34 32 *
35 33 * @var string
36 34 */
37 - protected $rest_base = '(?:users|actors)\/(?P<user_id>[-]?\d+)';
35 + protected $rest_base = '(?:users|actors)\/(?P<user_id>[\w\-\.]+)';
38 36
39 37 /**
40 38 * Register routes.
41 39 */
@@ -45,18 +43,18 @@
45 43 '/' . $this->rest_base,
46 44 array(
47 45 'args' => array(
48 46 'user_id' => array(
49 - 'description' => 'The ID of the actor.',
50 - 'type' => 'integer',
51 - 'required' => true,
52 - 'validate_callback' => array( $this, 'validate_user_id' ),
47 + 'description' => 'The ID or username of the actor.',
48 + 'type' => 'string',
49 + 'required' => true,
50 + 'pattern' => '[\w\-\.]+',
53 51 ),
54 52 ),
55 53 array(
56 54 'methods' => \WP_REST_Server::READABLE,
57 55 'callback' => array( $this, 'get_item' ),
58 - 'permission_callback' => array( $this, 'verify_signature' ),
56 + 'permission_callback' => array( 'Activitypub\Rest\Server', 'verify_signature' ),
59 57 ),
60 58 'schema' => array( $this, 'get_public_item_schema' ),
61 59 )
62 60 );
@@ -66,12 +64,12 @@
66 64 '/' . $this->rest_base . '/remote-follow',
67 65 array(
68 66 'args' => array(
69 67 'user_id' => array(
70 - 'description' => 'The ID of the actor.',
71 - 'type' => 'integer',
72 - 'required' => true,
73 - 'validate_callback' => array( $this, 'validate_user_id' ),
68 + 'description' => 'The ID or username of the actor.',
69 + 'type' => 'string',
70 + 'required' => true,
71 + 'pattern' => '[\w\-\.]+',
74 72 ),
75 73 ),
76 74 array(
77 75 'methods' => \WP_REST_Server::READABLE,
@@ -96,10 +94,14 @@
96 94 * @return \WP_REST_Response|\WP_Error Response object on success, or WP_Error object on failure.
97 95 */
98 96 public function get_item( $request ) {
99 97 $user_id = $request->get_param( 'user_id' );
100 - $user = Actor_Collection::get_by_id( $user_id );
98 + $user = Actor_Collection::get_by_various( $user_id );
101 99
100 + if ( \is_wp_error( $user ) ) {
101 + return $user;
102 + }
103 +
102 104 /**
103 105 * Action triggered prior to the ActivityPub profile being created and sent to the client.
104 106 */
105 107 \do_action( 'activitypub_rest_users_pre' );
@@ -119,29 +121,16 @@
119 121 * @param \WP_REST_Request $request Full details about the request.
120 122 * @return \WP_REST_Response|\WP_Error Response object on success, or WP_Error object on failure.
121 123 */
122 124 public function get_remote_follow_item( $request ) {
123 - /*
124 - * This endpoint is unauthenticated and triggers an outbound WebFinger request to a
125 - * user-supplied host, so throttle it per IP (max 10 per minute) to limit its use as
126 - * a blind SSRF / request-amplification vector. Fail closed when no IP is available.
127 - */
128 - $ip = get_client_ip();
129 - if ( '' === $ip ) {
130 - return self::rate_limit_response();
131 - }
125 + $resource = $request->get_param( 'resource' );
126 + $user_id = $request->get_param( 'user_id' );
127 + $user = Actor_Collection::get_by_various( $user_id );
132 128
133 - $transient_key = 'ap_remote_follow_' . \md5( $ip );
134 - $count = (int) \get_transient( $transient_key );
135 - if ( $count >= 10 ) {
136 - return self::rate_limit_response();
129 + if ( \is_wp_error( $user ) ) {
130 + return $user;
137 131 }
138 - \set_transient( $transient_key, $count + 1, MINUTE_IN_SECONDS );
139 132
140 - $resource = $request->get_param( 'resource' );
141 - $user_id = $request->get_param( 'user_id' );
142 - $user = Actor_Collection::get_by_id( $user_id );
143 -
144 133 $template = Webfinger::get_remote_follow_endpoint( $resource );
145 134
146 135 if ( \is_wp_error( $template ) ) {
147 136 return $template;
@@ -158,26 +147,8 @@
158 147 );
159 148 }
160 149
161 150 /**
162 - * Build a 429 rate-limit response for the remote-follow endpoint.
163 - *
164 - * @return \WP_REST_Response The rate-limit response.
165 - */
166 - private static function rate_limit_response() {
167 - return new \WP_REST_Response(
168 - array(
169 - 'code' => 'activitypub_rate_limited',
170 - 'message' => \__( 'Too many requests. Please try again later.', 'activitypub' ),
171 - 'data' => array( 'status' => 429 ),
172 - ),
173 - 429,
174 - // RFC 6585 ยง4: send Retry-After so clients can back off.
175 - array( 'Retry-After' => (string) MINUTE_IN_SECONDS )
176 - );
177 - }
178 -
179 - /**
180 151 * Retrieves the actor schema, conforming to JSON Schema.
181 152 *
182 153 * @return array Item schema data.
183 154 */
@@ -379,50 +350,10 @@
379 350 'description' => 'Whether the actor is discoverable.',
380 351 'type' => 'boolean',
381 352 'readonly' => true,
382 353 ),
383 - 'generator' => array(
384 - 'description' => 'The generator of the object.',
385 - 'type' => 'object',
386 - 'properties' => array(
387 - 'type' => array(
388 - 'type' => 'string',
389 - ),
390 - 'implements' => array(
391 - 'type' => 'array',
392 - 'items' => array(
393 - 'type' => 'object',
394 - 'properties' => array(
395 - 'href' => array(
396 - 'type' => 'string',
397 - 'format' => 'uri',
398 - ),
399 - 'name' => array(
400 - 'type' => 'string',
401 - ),
402 - ),
403 - ),
404 - ),
405 - ),
406 - 'readonly' => true,
407 - ),
408 354 ),
409 355 );
410 356
411 357 return $this->add_additional_fields_schema( $this->schema );
412 - }
413 -
414 - /**
415 - * Validates the user_id parameter.
416 - *
417 - * @param mixed $user_id The user_id parameter.
418 - * @return bool|\WP_Error True if the user_id is valid, WP_Error otherwise.
419 - */
420 - public function validate_user_id( $user_id ) {
421 - $user = Actor_Collection::get_by_id( $user_id );
422 - if ( \is_wp_error( $user ) ) {
423 - return $user;
424 - }
425 -
426 - return true;
427 358 }
428 359 }