PluginProbe
ActivityPub / 8.0.2
ActivityPub v8.0.2
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 / functions-activity.php

functions-activity.php in ActivityPub 8.0.2, at includes/functions-activity.php

326 lines 8.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Activity functions.
4 *
5 * Functions for working with ActivityPub activities, objects, and actors.
6 *
7 * @package Activitypub
8 */
9
10 namespace Activitypub;
11
12 use Activitypub\Activity\Activity;
13 use Activitypub\Activity\Actor;
14 use Activitypub\Activity\Base_Object;
15
16 /**
17 * Returns the ActivityPub default JSON-context.
18 *
19 * @return array The activitypub context.
20 *
21 * @deprecated 7.6.0 Use the respective context function instead.
22 */
23 function get_context() {
24 \_deprecated_function( __FUNCTION__, '7.6.0', 'Use the respective context function instead.' );
25
26 $context = Activity::JSON_LD_CONTEXT;
27
28 /**
29 * Filters the ActivityPub JSON-LD context.
30 *
31 * This filter allows developers to modify or extend the JSON-LD context used
32 * in ActivityPub responses. The context defines the vocabulary and terms used
33 * in the ActivityPub JSON objects.
34 *
35 * @param array $context The default ActivityPub JSON-LD context array.
36 */
37 return \apply_filters( 'activitypub_json_context', $context );
38 }
39
40 /**
41 * Extract recipient URLs from Activity object.
42 *
43 * @param array $data The Activity object as array.
44 *
45 * @return array The list of user URLs.
46 */
47 function extract_recipients_from_activity( $data ) {
48 $recipient_items = array();
49
50 foreach ( array( 'to', 'bto', 'cc', 'bcc', 'audience' ) as $i ) {
51 $recipient_items = \array_merge( $recipient_items, extract_recipients_from_activity_property( $i, $data ) );
52 }
53
54 return \array_unique( $recipient_items );
55 }
56
57 /**
58 * Extract recipient URLs from a specific property of an Activity object.
59 *
60 * Checks the activity level first, then falls back to the object property,
61 * and finally checks the instrument property (used by QuoteRequest activities).
62 *
63 * @param string $property The property to extract recipients from (e.g., 'to', 'cc').
64 * @param array $data The Activity object as array.
65 *
66 * @return array The list of user URLs.
67 */
68 function extract_recipients_from_activity_property( $property, $data ) {
69 $recipients = array();
70
71 if ( ! empty( $data[ $property ] ) ) {
72 $recipients = $data[ $property ];
73 } elseif ( ! empty( $data['object'][ $property ] ) ) {
74 $recipients = $data['object'][ $property ];
75 } elseif ( ! empty( $data['instrument'][ $property ] ) ) {
76 // QuoteRequest activities have addressing in the instrument (the quoting Note).
77 $recipients = $data['instrument'][ $property ];
78 }
79
80 $recipients = \array_map( '\Activitypub\object_to_uri', (array) $recipients );
81
82 return \array_unique( \array_filter( $recipients ) );
83 }
84
85 /**
86 * Determine the visibility of the activity based on its recipients.
87 *
88 * @param array $activity The activity data.
89 *
90 * @return string One of ACTIVITYPUB_CONTENT_VISIBILITY_PUBLIC,
91 * ACTIVITYPUB_CONTENT_VISIBILITY_QUIET_PUBLIC, or
92 * ACTIVITYPUB_CONTENT_VISIBILITY_PRIVATE.
93 */
94 function get_activity_visibility( $activity ) {
95 // Set default visibility for specific activity types.
96 if ( ! empty( $activity['type'] ) && in_array( $activity['type'], array( 'Accept', 'Delete', 'Follow', 'Reject', 'Undo' ), true ) ) {
97 return ACTIVITYPUB_CONTENT_VISIBILITY_PRIVATE;
98 }
99
100 // Check 'to' field for public visibility.
101 $to = extract_recipients_from_activity_property( 'to', $activity );
102 if ( ! empty( array_intersect( $to, ACTIVITYPUB_PUBLIC_AUDIENCE_IDENTIFIERS ) ) ) {
103 return ACTIVITYPUB_CONTENT_VISIBILITY_PUBLIC;
104 }
105
106 // Check 'cc' field for quiet public visibility.
107 $cc = extract_recipients_from_activity_property( 'cc', $activity );
108 if ( ! empty( array_intersect( $cc, ACTIVITYPUB_PUBLIC_AUDIENCE_IDENTIFIERS ) ) ) {
109 return ACTIVITYPUB_CONTENT_VISIBILITY_QUIET_PUBLIC;
110 }
111
112 return ACTIVITYPUB_CONTENT_VISIBILITY_PRIVATE;
113 }
114
115 /**
116 * Check if passed Activity is Public.
117 *
118 * @see https://github.com/w3c/activitypub/issues/404#issuecomment-2926310561
119 * @see https://www.w3.org/TR/activitypub/#delivery (Section 7.1, "Silent and private activities")
120 *
121 * @param Base_Object|array $data The Activity object as Base_Object or array.
122 *
123 * @return boolean True if public, false if not.
124 */
125 function is_activity_public( $data ) {
126 if ( $data instanceof Base_Object ) {
127 $data = $data->to_array();
128 }
129
130 $recipients = extract_recipients_from_activity( $data );
131
132 if ( empty( $recipients ) ) {
133 return false;
134 }
135
136 return ! empty( array_intersect( $recipients, ACTIVITYPUB_PUBLIC_AUDIENCE_IDENTIFIERS ) );
137 }
138
139 /**
140 * Check if passed Activity is a reply.
141 *
142 * @param array $data The Activity object as array.
143 *
144 * @return boolean True if a reply, false if not.
145 */
146 function is_activity_reply( $data ) {
147 return ! empty( $data['object']['inReplyTo'] );
148 }
149
150 /**
151 * Check if passed Activity is a quote.
152 *
153 * Checks for quote properties: quote, quoteUrl, quoteUri, or _misskey_quote.
154 *
155 * @param array $data The Activity object as array.
156 *
157 * @return boolean True if a quote, false if not.
158 */
159 function is_quote_activity( $data ) {
160 return ! empty( $data['object']['quote'] ) ||
161 ! empty( $data['object']['quoteUrl'] ) ||
162 ! empty( $data['object']['quoteUri'] ) ||
163 ! empty( $data['object']['_misskey_quote'] );
164 }
165
166 /**
167 * Get the URI of an ActivityPub object.
168 *
169 * @param array|string $data The ActivityPub object.
170 *
171 * @return string|null The URI of the ActivityPub object.
172 */
173 function object_to_uri( $data ) {
174 // Check whether it is already simple.
175 if ( ! $data || is_string( $data ) ) {
176 return $data;
177 }
178
179 if ( is_object( $data ) ) {
180 $data = $data->to_array();
181 }
182
183 /*
184 * Check if it is a list, then take first item.
185 * This plugin does not support collections.
186 */
187 if ( array_is_list( $data ) ) {
188 $data = $data[0];
189 }
190
191 // Check if it is simplified now.
192 if ( is_string( $data ) ) {
193 return $data;
194 }
195
196 $type = 'Object';
197 if ( isset( $data['type'] ) ) {
198 $type = $data['type'];
199 }
200
201 // Return part of Object that makes most sense.
202 switch ( $type ) {
203 case 'Audio': // See https://www.w3.org/TR/activitystreams-vocabulary/#dfn-audio.
204 case 'Document': // See https://www.w3.org/TR/activitystreams-vocabulary/#dfn-document.
205 case 'Image': // See https://www.w3.org/TR/activitystreams-vocabulary/#dfn-image.
206 case 'Video': // See https://www.w3.org/TR/activitystreams-vocabulary/#dfn-video.
207 $data = object_to_uri( $data['url'] );
208 break;
209
210 case 'Link': // See https://www.w3.org/TR/activitystreams-vocabulary/#dfn-link.
211 case 'Mention': // See https://www.w3.org/TR/activitystreams-vocabulary/#dfn-mention.
212 $data = $data['href'];
213 break;
214
215 default:
216 $data = $data['id'];
217 break;
218 }
219
220 return $data;
221 }
222
223 /**
224 * Check if an `$data` is an Activity.
225 *
226 * @see https://www.w3.org/ns/activitystreams#activities
227 *
228 * @param array|object|string $data The data to check.
229 *
230 * @return boolean True if the `$data` is an Activity, false otherwise.
231 */
232 function is_activity( $data ) {
233 /**
234 * Filters the activity types.
235 *
236 * @param array $types The activity types.
237 */
238 $types = apply_filters( 'activitypub_activity_types', Activity::TYPES );
239
240 return _is_type_of( $data, $types );
241 }
242
243 /**
244 * Check if an `$data` is an Activity Object.
245 *
246 * @see https://www.w3.org/TR/activitystreams-vocabulary/#object-types
247 *
248 * @param array|object|string $data The data to check.
249 *
250 * @return boolean True if the `$data` is an Activity Object, false otherwise.
251 */
252 function is_activity_object( $data ) {
253 /**
254 * Filters the activity object types.
255 *
256 * @param array $types The activity object types.
257 */
258 $types = \apply_filters( 'activitypub_activity_object_types', Base_Object::TYPES );
259
260 return _is_type_of( $data, $types );
261 }
262
263 /**
264 * Check if an `$data` is an Actor.
265 *
266 * @see https://www.w3.org/ns/activitystreams#actor
267 *
268 * @param array|object|string $data The data to check.
269 *
270 * @return boolean True if the `$data` is an Actor, false otherwise.
271 */
272 function is_actor( $data ) {
273 /**
274 * Filters the actor types.
275 *
276 * @param array $types The actor types.
277 */
278 $types = apply_filters( 'activitypub_actor_types', Actor::TYPES );
279
280 return _is_type_of( $data, $types );
281 }
282
283 /**
284 * Check if an `$data` is a Collection.
285 *
286 * @see https://www.w3.org/ns/activitystreams#collections
287 *
288 * @param array|object|string $data The data to check.
289 *
290 * @return boolean True if the `$data` is a Collection, false otherwise.
291 */
292 function is_collection( $data ) {
293 /**
294 * Filters the collection types.
295 *
296 * @param array $types The collection types.
297 */
298 $types = apply_filters( 'activitypub_collection_types', array( 'Collection', 'OrderedCollection', 'CollectionPage', 'OrderedCollectionPage' ) );
299
300 return _is_type_of( $data, $types );
301 }
302
303 /**
304 * Private helper to check if $data is of a given type set.
305 *
306 * @param array|object|string $data The data to check.
307 * @param array $types The types to check against.
308 *
309 * @return boolean True if $data is of one of the types, false otherwise.
310 */
311 function _is_type_of( $data, $types ) {
312 if ( is_string( $data ) ) {
313 return in_array( $data, $types, true );
314 }
315
316 if ( is_array( $data ) && isset( $data['type'] ) ) {
317 return in_array( $data['type'], $types, true );
318 }
319
320 if ( $data instanceof Base_Object ) {
321 return in_array( $data->get_type(), $types, true );
322 }
323
324 return false;
325 }
326