PluginProbe
ActivityPub / 5.3.1
ActivityPub v5.3.1
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
activitypub / includes / rest / class-actors-controller.php

class-actors-controller.php in ActivityPub 5.3.1, at includes/rest/class-actors-controller.php

369 lines 10.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * ActivityPub Actors REST-Class
4 *
5 * @package Activitypub
6 */
7
8 namespace Activitypub\Rest;
9
10 use Activitypub\Collection\Actors as Actor_Collection;
11 use Activitypub\Webfinger;
12
13 use function Activitypub\is_activitypub_request;
14
15 /**
16 * ActivityPub Actors REST-Class.
17 *
18 * @author Matthias Pfefferle
19 *
20 * @see https://www.w3.org/TR/activitypub/#followers
21 */
22 class Actors_Controller extends \WP_REST_Controller {
23 /**
24 * The namespace of this controller's route.
25 *
26 * @var string
27 */
28 protected $namespace = ACTIVITYPUB_REST_NAMESPACE;
29
30 /**
31 * The base of this controller's route.
32 *
33 * @var string
34 */
35 protected $rest_base = '(?:users|actors)\/(?P<user_id>[\w\-\.]+)';
36
37 /**
38 * Register routes.
39 */
40 public function register_routes() {
41 \register_rest_route(
42 $this->namespace,
43 '/' . $this->rest_base,
44 array(
45 'args' => array(
46 'user_id' => array(
47 'description' => 'The ID or username of the actor.',
48 'type' => 'string',
49 'required' => true,
50 'pattern' => '[\w\-\.]+',
51 ),
52 ),
53 array(
54 'methods' => \WP_REST_Server::READABLE,
55 'callback' => array( $this, 'get_item' ),
56 'permission_callback' => array( 'Activitypub\Rest\Server', 'verify_signature' ),
57 ),
58 'schema' => array( $this, 'get_public_item_schema' ),
59 )
60 );
61
62 \register_rest_route(
63 $this->namespace,
64 '/' . $this->rest_base . '/remote-follow',
65 array(
66 'args' => array(
67 'user_id' => array(
68 'description' => 'The ID or username of the actor.',
69 'type' => 'string',
70 'required' => true,
71 'pattern' => '[\w\-\.]+',
72 ),
73 ),
74 array(
75 'methods' => \WP_REST_Server::READABLE,
76 'callback' => array( $this, 'get_remote_follow_item' ),
77 'permission_callback' => '__return_true',
78 'args' => array(
79 'resource' => array(
80 'description' => 'The resource to follow.',
81 'type' => 'string',
82 'required' => true,
83 ),
84 ),
85 ),
86 )
87 );
88 }
89
90 /**
91 * Retrieves a single actor.
92 *
93 * @param \WP_REST_Request $request Full details about the request.
94 * @return \WP_REST_Response|\WP_Error Response object on success, or WP_Error object on failure.
95 */
96 public function get_item( $request ) {
97 $user_id = $request->get_param( 'user_id' );
98 $user = Actor_Collection::get_by_various( $user_id );
99
100 if ( \is_wp_error( $user ) ) {
101 return $user;
102 }
103
104 $link_header = \sprintf( '<%1$s>; rel="alternate"; type="application/activity+json"', $user->get_id() );
105
106 // Redirect to canonical URL if it is not an ActivityPub request.
107 if ( ! is_activitypub_request() ) {
108 \header( 'Link: ' . $link_header );
109 \header( 'Location: ' . $user->get_canonical_url(), true, 301 );
110 exit;
111 }
112
113 /**
114 * Action triggered prior to the ActivityPub profile being created and sent to the client.
115 */
116 \do_action( 'activitypub_rest_users_pre' );
117
118 $data = $user->to_array();
119
120 $response = \rest_ensure_response( $data );
121 $response->header( 'Content-Type', 'application/activity+json; charset=' . \get_option( 'blog_charset' ) );
122 $response->header( 'Link', $link_header );
123
124 return $response;
125 }
126
127 /**
128 * Retrieves the remote follow endpoint.
129 *
130 * @param \WP_REST_Request $request Full details about the request.
131 * @return \WP_REST_Response|\WP_Error Response object on success, or WP_Error object on failure.
132 */
133 public function get_remote_follow_item( $request ) {
134 $resource = $request->get_param( 'resource' );
135 $user_id = $request->get_param( 'user_id' );
136 $user = Actor_Collection::get_by_various( $user_id );
137
138 if ( \is_wp_error( $user ) ) {
139 return $user;
140 }
141
142 $template = Webfinger::get_remote_follow_endpoint( $resource );
143
144 if ( \is_wp_error( $template ) ) {
145 return $template;
146 }
147
148 $resource = $user->get_webfinger();
149 $url = \str_replace( '{uri}', $resource, $template );
150
151 return \rest_ensure_response(
152 array(
153 'url' => $url,
154 'template' => $template,
155 )
156 );
157 }
158
159 /**
160 * Retrieves the actor schema, conforming to JSON Schema.
161 *
162 * @return array Item schema data.
163 */
164 public function get_item_schema() {
165 if ( $this->schema ) {
166 return $this->add_additional_fields_schema( $this->schema );
167 }
168
169 $this->schema = array(
170 '$schema' => 'http://json-schema.org/draft-04/schema#',
171 'title' => 'actor',
172 'type' => 'object',
173 'properties' => array(
174 '@context' => array(
175 'description' => 'The JSON-LD context for the response.',
176 'type' => array( 'array', 'object' ),
177 'readonly' => true,
178 ),
179 'id' => array(
180 'description' => 'The unique identifier for the actor.',
181 'type' => 'string',
182 'format' => 'uri',
183 'readonly' => true,
184 ),
185 'type' => array(
186 'description' => 'The type of the actor.',
187 'type' => 'string',
188 'enum' => array( 'Person', 'Service', 'Organization', 'Application', 'Group' ),
189 'readonly' => true,
190 ),
191 'attachment' => array(
192 'description' => 'Additional information attached to the actor.',
193 'type' => 'array',
194 'items' => array(
195 'type' => 'object',
196 'properties' => array(
197 'type' => array(
198 'type' => 'string',
199 'enum' => array( 'PropertyValue', 'Link' ),
200 ),
201 'name' => array(
202 'type' => 'string',
203 ),
204 'value' => array(
205 'type' => 'string',
206 ),
207 'href' => array(
208 'type' => 'string',
209 'format' => 'uri',
210 ),
211 'rel' => array(
212 'type' => 'array',
213 'items' => array(
214 'type' => 'string',
215 ),
216 ),
217 ),
218 ),
219 'readonly' => true,
220 ),
221 'name' => array(
222 'description' => 'The display name of the actor.',
223 'type' => 'string',
224 'readonly' => true,
225 ),
226 'icon' => array(
227 'description' => 'The icon/avatar of the actor.',
228 'type' => 'object',
229 'properties' => array(
230 'type' => array(
231 'type' => 'string',
232 ),
233 'url' => array(
234 'type' => 'string',
235 'format' => 'uri',
236 ),
237 ),
238 'readonly' => true,
239 ),
240 'published' => array(
241 'description' => 'The date the actor was published.',
242 'type' => 'string',
243 'format' => 'date-time',
244 'readonly' => true,
245 ),
246 'summary' => array(
247 'description' => 'A summary about the actor.',
248 'type' => 'string',
249 'readonly' => true,
250 ),
251 'tag' => array(
252 'description' => 'Tags associated with the actor.',
253 'type' => 'array',
254 'items' => array(
255 'type' => 'object',
256 'properties' => array(
257 'type' => array(
258 'type' => 'string',
259 ),
260 'href' => array(
261 'type' => 'string',
262 'format' => 'uri',
263 ),
264 'name' => array(
265 'type' => 'string',
266 ),
267 ),
268 ),
269 'readonly' => true,
270 ),
271 'url' => array(
272 'description' => 'The URL to the actor\'s profile page.',
273 'type' => 'string',
274 'format' => 'uri',
275 'readonly' => true,
276 ),
277 'inbox' => array(
278 'description' => 'The inbox endpoint for the actor.',
279 'type' => 'string',
280 'format' => 'uri',
281 'readonly' => true,
282 ),
283 'outbox' => array(
284 'description' => 'The outbox endpoint for the actor.',
285 'type' => 'string',
286 'format' => 'uri',
287 'readonly' => true,
288 ),
289 'following' => array(
290 'description' => 'The following endpoint for the actor.',
291 'type' => 'string',
292 'format' => 'uri',
293 'readonly' => true,
294 ),
295 'followers' => array(
296 'description' => 'The followers endpoint for the actor.',
297 'type' => 'string',
298 'format' => 'uri',
299 'readonly' => true,
300 ),
301 'streams' => array(
302 'description' => 'The streams associated with the actor.',
303 'type' => 'array',
304 'readonly' => true,
305 ),
306 'preferredUsername' => array(
307 'description' => 'The preferred username of the actor.',
308 'type' => 'string',
309 'readonly' => true,
310 ),
311 'publicKey' => array(
312 'description' => 'The public key information for the actor.',
313 'type' => 'object',
314 'properties' => array(
315 'id' => array(
316 'type' => 'string',
317 'format' => 'uri',
318 ),
319 'owner' => array(
320 'type' => 'string',
321 'format' => 'uri',
322 ),
323 'publicKeyPem' => array(
324 'type' => 'string',
325 ),
326 ),
327 'readonly' => true,
328 ),
329 'manuallyApprovesFollowers' => array(
330 'description' => 'Whether the actor manually approves followers.',
331 'type' => 'boolean',
332 'readonly' => true,
333 ),
334 'attributionDomains' => array(
335 'description' => 'The attribution domains for the actor.',
336 'type' => 'array',
337 'items' => array(
338 'type' => 'string',
339 ),
340 'readonly' => true,
341 ),
342 'featured' => array(
343 'description' => 'The featured collection endpoint for the actor.',
344 'type' => 'string',
345 'format' => 'uri',
346 'readonly' => true,
347 ),
348 'indexable' => array(
349 'description' => 'Whether the actor is indexable.',
350 'type' => 'boolean',
351 'readonly' => true,
352 ),
353 'webfinger' => array(
354 'description' => 'The webfinger identifier for the actor.',
355 'type' => 'string',
356 'readonly' => true,
357 ),
358 'discoverable' => array(
359 'description' => 'Whether the actor is discoverable.',
360 'type' => 'boolean',
361 'readonly' => true,
362 ),
363 ),
364 );
365
366 return $this->add_additional_fields_schema( $this->schema );
367 }
368 }
369