PluginProbe
ActivityPub / 7.0.0
ActivityPub v7.0.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-inbox-controller.php

class-inbox-controller.php in ActivityPub 7.0.0, at includes/rest/class-inbox-controller.php

271 lines 7.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Inbox_Controller file.
4 *
5 * @package Activitypub
6 */
7
8 namespace Activitypub\Rest;
9
10 use Activitypub\Activity\Activity;
11 use Activitypub\Collection\Actors;
12 use Activitypub\Debug;
13
14 use function Activitypub\is_same_domain;
15 use function Activitypub\extract_recipients_from_activity;
16
17 /**
18 * Inbox_Controller class.
19 *
20 * @author Matthias Pfefferle
21 *
22 * @see https://www.w3.org/TR/activitypub/#inbox
23 */
24 class Inbox_Controller extends \WP_REST_Controller {
25 /**
26 * The namespace of this controller's route.
27 *
28 * @var string
29 */
30 protected $namespace = ACTIVITYPUB_REST_NAMESPACE;
31
32 /**
33 * The base of this controller's route.
34 *
35 * @var string
36 */
37 protected $rest_base = 'inbox';
38
39 /**
40 * Register routes.
41 */
42 public function register_routes() {
43 \register_rest_route(
44 $this->namespace,
45 '/' . $this->rest_base,
46 array(
47 array(
48 'methods' => \WP_REST_Server::CREATABLE,
49 'callback' => array( $this, 'create_item' ),
50 'permission_callback' => array( 'Activitypub\Rest\Server', 'verify_signature' ),
51 'args' => array(
52 'id' => array(
53 'description' => 'The unique identifier for the activity.',
54 'type' => 'string',
55 'format' => 'uri',
56 'required' => true,
57 ),
58 'actor' => array(
59 'description' => 'The actor performing the activity.',
60 'type' => 'string',
61 'required' => true,
62 'sanitize_callback' => '\Activitypub\object_to_uri',
63 ),
64 'type' => array(
65 'description' => 'The type of the activity.',
66 'type' => 'string',
67 'required' => true,
68 ),
69 'object' => array(
70 'description' => 'The object of the activity.',
71 'required' => true,
72 'validate_callback' => function ( $param, $request, $key ) {
73 /**
74 * Filter the ActivityPub object validation.
75 *
76 * @param bool $validate The validation result.
77 * @param array $param The object data.
78 * @param object $request The request object.
79 * @param string $key The key.
80 */
81 return \apply_filters( 'activitypub_validate_object', true, $param, $request, $key );
82 },
83 ),
84 'to' => array(
85 'description' => 'The primary recipients of the activity.',
86 'type' => array( 'string', 'array' ),
87 'required' => false,
88 'sanitize_callback' => function ( $param ) {
89 if ( \is_string( $param ) ) {
90 $param = array( $param );
91 }
92
93 return $param;
94 },
95 ),
96 'cc' => array(
97 'description' => 'The secondary recipients of the activity.',
98 'type' => array( 'string', 'array' ),
99 'sanitize_callback' => function ( $param ) {
100 if ( \is_string( $param ) ) {
101 $param = array( $param );
102 }
103
104 return $param;
105 },
106 ),
107 'bcc' => array(
108 'description' => 'The private recipients of the activity.',
109 'type' => array( 'string', 'array' ),
110 'sanitize_callback' => function ( $param ) {
111 if ( \is_string( $param ) ) {
112 $param = array( $param );
113 }
114
115 return $param;
116 },
117 ),
118 ),
119 ),
120 'schema' => array( $this, 'get_item_schema' ),
121 )
122 );
123 }
124
125 /**
126 * The shared inbox.
127 *
128 * @param \WP_REST_Request $request The request object.
129 *
130 * @return \WP_REST_Response|\WP_Error Response object or WP_Error.
131 */
132 public function create_item( $request ) {
133 $data = $request->get_json_params();
134 $activity = Activity::init_from_array( $data );
135 $type = \strtolower( $request->get_param( 'type' ) );
136
137 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
138 if ( \wp_check_comment_disallowed_list( $activity->to_json( false ), '', '', '', $_SERVER['REMOTE_ADDR'], $_SERVER['HTTP_USER_AGENT'] ?? '' ) ) {
139 /**
140 * ActivityPub inbox disallowed activity.
141 *
142 * @param array $data The data array.
143 * @param null $user_id The user ID.
144 * @param string $type The type of the activity.
145 * @param Activity|\WP_Error $activity The Activity object.
146 */
147 do_action( 'activitypub_rest_inbox_disallowed', $data, null, $type, $activity );
148 } else {
149 $recipients = extract_recipients_from_activity( $data );
150
151 foreach ( $recipients as $recipient ) {
152 if ( ! is_same_domain( $recipient ) ) {
153 continue;
154 }
155
156 $actor = Actors::get_by_various( $recipient );
157
158 if ( ! $actor || \is_wp_error( $actor ) ) {
159 continue;
160 }
161
162 /**
163 * ActivityPub inbox action.
164 *
165 * @param array $data The data array.
166 * @param int $user_id The user ID.
167 * @param string $type The type of the activity.
168 * @param Activity|\WP_Error $activity The Activity object.
169 */
170 \do_action( 'activitypub_inbox', $data, $actor->get__id(), $type, $activity );
171
172 /**
173 * ActivityPub inbox action for specific activity types.
174 *
175 * @param array $data The data array.
176 * @param int $user_id The user ID.
177 * @param Activity|\WP_Error $activity The Activity object.
178 */
179 \do_action( 'activitypub_inbox_' . $type, $data, $actor->get__id(), $activity );
180 }
181 }
182
183 $response = \rest_ensure_response(
184 array(
185 'type' => 'https://w3id.org/fep/c180#approval-required',
186 'title' => 'Approval Required',
187 'status' => '202',
188 'detail' => 'This activity requires approval before it can be processed.',
189 )
190 );
191 $response->set_status( 202 );
192 $response->header( 'Content-Type', 'application/activity+json; charset=' . \get_option( 'blog_charset' ) );
193
194 return $response;
195 }
196
197 /**
198 * Retrieves the schema for a single inbox item, conforming to JSON Schema.
199 *
200 * @return array Item schema data.
201 */
202 public function get_item_schema() {
203 if ( $this->schema ) {
204 return $this->add_additional_fields_schema( $this->schema );
205 }
206
207 $schema = array(
208 '$schema' => 'https://json-schema.org/draft-04/schema#',
209 'title' => 'activity',
210 'type' => 'object',
211 'properties' => array(
212 '@context' => array(
213 'description' => 'The JSON-LD context for the activity.',
214 'type' => array( 'string', 'array', 'object' ),
215 'required' => true,
216 ),
217 'id' => array(
218 'description' => 'The unique identifier for the activity.',
219 'type' => 'string',
220 'format' => 'uri',
221 'required' => true,
222 ),
223 'type' => array(
224 'description' => 'The type of the activity.',
225 'type' => 'string',
226 'required' => true,
227 ),
228 'actor' => array(
229 'description' => 'The actor performing the activity.',
230 'type' => array( 'string', 'object' ),
231 'format' => 'uri',
232 'required' => true,
233 ),
234 'object' => array(
235 'description' => 'The object of the activity.',
236 'type' => array( 'string', 'object' ),
237 'required' => true,
238 ),
239 'to' => array(
240 'description' => 'The primary recipients of the activity.',
241 'type' => 'array',
242 'items' => array(
243 'type' => 'string',
244 'format' => 'uri',
245 ),
246 ),
247 'cc' => array(
248 'description' => 'The secondary recipients of the activity.',
249 'type' => 'array',
250 'items' => array(
251 'type' => 'string',
252 'format' => 'uri',
253 ),
254 ),
255 'bcc' => array(
256 'description' => 'The private recipients of the activity.',
257 'type' => 'array',
258 'items' => array(
259 'type' => 'string',
260 'format' => 'uri',
261 ),
262 ),
263 ),
264 );
265
266 $this->schema = $schema;
267
268 return $this->add_additional_fields_schema( $this->schema );
269 }
270 }
271