PluginProbe
ActivityPub / 9.1.0
ActivityPub v9.1.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
activitypub / includes / rest / class-application-controller.php

class-application-controller.php in ActivityPub 9.1.0, at includes/rest/class-application-controller.php

287 lines 7.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Application Controller file.
4 *
5 * Self-contained controller for the ActivityPub Application actor.
6 * The Application is not a real actor in the plugin's internal sense —
7 * it cannot be followed, addressed, or interacted with. It exists only as:
8 * 1. A JSON-LD document at /wp-json/activitypub/1.0/application
9 * 2. A signing identity for outbound HTTP GET requests
10 *
11 * @package Activitypub
12 */
13
14 namespace Activitypub\Rest;
15
16 use Activitypub\Activity\Actor;
17 use Activitypub\Activity\Generic_Object;
18 use Activitypub\Application;
19
20 use function Activitypub\get_rest_url_by_path;
21 use function Activitypub\home_host;
22
23 /**
24 * ActivityPub Application Controller.
25 */
26 class Application_Controller extends \WP_REST_Controller {
27 /**
28 * The namespace of this controller's route.
29 *
30 * @var string
31 */
32 protected $namespace = ACTIVITYPUB_REST_NAMESPACE;
33
34 /**
35 * The base of this controller's route.
36 *
37 * @var string
38 */
39 protected $rest_base = 'application';
40
41 /**
42 * Register routes.
43 */
44 public function register_routes() {
45 \register_rest_route(
46 $this->namespace,
47 '/' . $this->rest_base,
48 array(
49 array(
50 'methods' => \WP_REST_Server::READABLE,
51 'callback' => array( $this, 'get_item' ),
52 'permission_callback' => '__return_true',
53 ),
54 'schema' => array( $this, 'get_item_schema' ),
55 )
56 );
57
58 \register_rest_route(
59 $this->namespace,
60 '/' . $this->rest_base . '/outbox',
61 array(
62 array(
63 'methods' => \WP_REST_Server::READABLE,
64 'callback' => array( $this, 'get_outbox' ),
65 'permission_callback' => '__return_true',
66 ),
67 )
68 );
69 }
70
71 /**
72 * Retrieves the application actor profile.
73 *
74 * @since 9.1.0
75 *
76 * @param \WP_REST_Request $request The request object.
77 * @return \WP_REST_Response Response object.
78 */
79 public function get_item( $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
80 $id = Application::get_id();
81
82 $json = array(
83 '@context' => Actor::JSON_LD_CONTEXT,
84 'id' => $id,
85 'type' => 'Application',
86 'name' => Application::USERNAME,
87 'preferredUsername' => Application::USERNAME,
88 'summary' => sprintf(
89 /* translators: %s: Domain of the site */
90 \__( 'This is the Application Actor for %s.', 'activitypub' ),
91 home_host()
92 ),
93 'url' => Application::get_url(),
94 'icon' => Application::get_icon(),
95 'published' => Application::get_published(),
96 'inbox' => get_rest_url_by_path( 'inbox' ),
97 'outbox' => get_rest_url_by_path( 'application/outbox' ),
98 'manuallyApprovesFollowers' => true,
99 'discoverable' => false,
100 'indexable' => false,
101 'invisible' => true,
102 'webfinger' => Application::get_webfinger(),
103 'publicKey' => array(
104 'id' => Application::get_key_id(),
105 'owner' => $id,
106 'publicKeyPem' => Application::get_public_key(),
107 ),
108 'implements' => array(
109 array(
110 'href' => 'https://datatracker.ietf.org/doc/html/rfc9421',
111 'name' => 'RFC-9421: HTTP Message Signatures',
112 ),
113 ),
114 );
115
116 /*
117 * Run the same serialization filters the object-based path used, so
118 * integrations that add actor fields via these hooks still apply to the
119 * Application actor. The filters document a Generic_Object argument, so
120 * hydrate one from the array to keep that contract.
121 */
122 $class = 'application';
123 $object = Generic_Object::init_from_array( $json );
124
125 /** This filter is documented in includes/activity/class-generic-object.php */
126 $json = \apply_filters( 'activitypub_activity_object_array', $json, $class, $id, $object );
127
128 /** This filter is documented in includes/activity/class-generic-object.php */
129 $json = \apply_filters( "activitypub_activity_{$class}_object_array", $json, $id, $object );
130
131 $rest_response = new \WP_REST_Response( $json, 200 );
132 $rest_response->header( 'Content-Type', 'application/activity+json; charset=' . \get_option( 'blog_charset' ) );
133
134 return $rest_response;
135 }
136
137 /**
138 * Returns an empty outbox collection for the Application actor.
139 *
140 * The Application is a signing-only identity and does not publish
141 * activities, so its outbox is always an empty OrderedCollection.
142 *
143 * @since 9.1.0
144 *
145 * @param \WP_REST_Request $request The request object.
146 * @return \WP_REST_Response Response object.
147 */
148 public function get_outbox( $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
149 $json = array(
150 '@context' => Actor::JSON_LD_CONTEXT,
151 'id' => get_rest_url_by_path( 'application/outbox' ),
152 'type' => 'OrderedCollection',
153 'totalItems' => 0,
154 'orderedItems' => array(),
155 );
156
157 $rest_response = new \WP_REST_Response( $json, 200 );
158 $rest_response->header( 'Content-Type', 'application/activity+json; charset=' . \get_option( 'blog_charset' ) );
159
160 return $rest_response;
161 }
162
163 /**
164 * Retrieves the schema for the application endpoint.
165 *
166 * @return array Schema data.
167 */
168 public function get_item_schema() {
169 if ( $this->schema ) {
170 return $this->add_additional_fields_schema( $this->schema );
171 }
172
173 $this->schema = array(
174 '$schema' => 'http://json-schema.org/draft-04/schema#',
175 'title' => 'application',
176 'type' => 'object',
177 'properties' => array(
178 '@context' => array(
179 'type' => 'array',
180 'items' => array(
181 'type' => array( 'string', 'object' ),
182 ),
183 ),
184 'id' => array(
185 'type' => 'string',
186 'format' => 'uri',
187 ),
188 'type' => array(
189 'type' => 'string',
190 'enum' => array( 'Application' ),
191 ),
192 'name' => array(
193 'type' => 'string',
194 ),
195 'icon' => array(
196 'type' => 'object',
197 'properties' => array(
198 'type' => array(
199 'type' => 'string',
200 ),
201 'url' => array(
202 'type' => 'string',
203 'format' => 'uri',
204 ),
205 ),
206 ),
207 'published' => array(
208 'type' => 'string',
209 'format' => 'date-time',
210 ),
211 'summary' => array(
212 'type' => 'string',
213 ),
214 'url' => array(
215 'type' => 'string',
216 'format' => 'uri',
217 ),
218 'inbox' => array(
219 'type' => 'string',
220 'format' => 'uri',
221 ),
222 'outbox' => array(
223 'type' => 'string',
224 'format' => 'uri',
225 ),
226 'streams' => array(
227 'type' => 'array',
228 'items' => array(
229 'type' => 'string',
230 ),
231 ),
232 'preferredUsername' => array(
233 'type' => 'string',
234 ),
235 'publicKey' => array(
236 'type' => 'object',
237 'properties' => array(
238 'id' => array(
239 'type' => 'string',
240 'format' => 'uri',
241 ),
242 'owner' => array(
243 'type' => 'string',
244 'format' => 'uri',
245 ),
246 'publicKeyPem' => array(
247 'type' => 'string',
248 ),
249 ),
250 ),
251 'manuallyApprovesFollowers' => array(
252 'type' => 'boolean',
253 ),
254 'discoverable' => array(
255 'type' => 'boolean',
256 ),
257 'indexable' => array(
258 'type' => 'boolean',
259 ),
260 'invisible' => array(
261 'type' => 'boolean',
262 ),
263 'implements' => array(
264 'type' => 'array',
265 'items' => array(
266 'type' => 'object',
267 'properties' => array(
268 'href' => array(
269 'type' => 'string',
270 'format' => 'uri',
271 ),
272 'name' => array(
273 'type' => 'string',
274 ),
275 ),
276 ),
277 ),
278 'webfinger' => array(
279 'type' => 'string',
280 ),
281 ),
282 );
283
284 return $this->add_additional_fields_schema( $this->schema );
285 }
286 }
287