PluginProbe
ActivityPub / 0.10.1
ActivityPub v0.10.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 / functions.php

functions.php in ActivityPub 0.10.1, at includes/functions.php

335 lines 8.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Activitypub;
3
4 /**
5 * Returns the ActivityPub default JSON-context
6 *
7 * @return array the activitypub context
8 */
9 function get_context() {
10 $context = array(
11 'https://www.w3.org/ns/activitystreams',
12 'https://w3id.org/security/v1',
13 array(
14 'manuallyApprovesFollowers' => 'as:manuallyApprovesFollowers',
15 'PropertyValue' => 'schema:PropertyValue',
16 'schema' => 'http://schema.org#',
17 'value' => 'schema:value',
18 ),
19 );
20
21 return \apply_filters( 'activitypub_json_context', $context );
22 }
23
24 function safe_remote_post( $url, $body, $user_id ) {
25 $date = \gmdate( 'D, d M Y H:i:s T' );
26 $signature = \Activitypub\Signature::generate_signature( $user_id, $url, $date );
27
28 $wp_version = \get_bloginfo( 'version' );
29 $user_agent = \apply_filters( 'http_headers_useragent', 'WordPress/' . $wp_version . '; ' . \get_bloginfo( 'url' ) );
30 $args = array(
31 'timeout' => 100,
32 'limit_response_size' => 1048576,
33 'redirection' => 3,
34 'user-agent' => "$user_agent; ActivityPub",
35 'headers' => array(
36 'Accept' => 'application/activity+json',
37 'Content-Type' => 'application/activity+json',
38 'Signature' => $signature,
39 'Date' => $date,
40 ),
41 'body' => $body,
42 );
43
44 $response = \wp_safe_remote_post( $url, $args );
45
46 \do_action( 'activitypub_safe_remote_post_response', $response, $url, $body, $user_id );
47
48 return $response;
49 }
50
51 function safe_remote_get( $url, $user_id ) {
52 $date = \gmdate( 'D, d M Y H:i:s T' );
53 $signature = \Activitypub\Signature::generate_signature( $user_id, $url, $date );
54
55 $wp_version = \get_bloginfo( 'version' );
56 $user_agent = \apply_filters( 'http_headers_useragent', 'WordPress/' . $wp_version . '; ' . \get_bloginfo( 'url' ) );
57 $args = array(
58 'timeout' => 100,
59 'limit_response_size' => 1048576,
60 'redirection' => 3,
61 'user-agent' => "$user_agent; ActivityPub",
62 'headers' => array(
63 'Accept' => 'application/activity+json',
64 'Content-Type' => 'application/activity+json',
65 'Signature' => $signature,
66 'Date' => $date,
67 ),
68 );
69
70 $response = \wp_safe_remote_get( $url, $args );
71
72 \do_action( 'activitypub_safe_remote_get_response', $response, $url, $user_id );
73
74 return $response;
75 }
76
77 /**
78 * Returns a users WebFinger "resource"
79 *
80 * @param int $user_id
81 *
82 * @return string The user-resource
83 */
84 function get_webfinger_resource( $user_id ) {
85 // use WebFinger plugin if installed
86 if ( \function_exists( '\get_webfinger_resource' ) ) {
87 return \get_webfinger_resource( $user_id, false );
88 }
89
90 $user = \get_user_by( 'id', $user_id );
91
92 return $user->user_login . '@' . \wp_parse_url( \home_url(), PHP_URL_HOST );
93 }
94
95 /**
96 * [get_metadata_by_actor description]
97 *
98 * @param sting $actor
99 *
100 * @return array
101 */
102 function get_remote_metadata_by_actor( $actor ) {
103 $metadata = \get_transient( 'activitypub_' . $actor );
104
105 if ( $metadata ) {
106 return $metadata;
107 }
108
109 if ( ! \wp_http_validate_url( $actor ) ) {
110 return new \WP_Error( 'activitypub_no_valid_actor_url', \__( 'The "actor" is no valid URL', 'activitypub' ), $actor );
111 }
112
113 $user = \get_users( array (
114 'number' => 1,
115 'who' => 'authors',
116 'fields' => 'ID',
117 ) );
118
119 // we just need any user to generate a request signature
120 $user_id = \reset( $user );
121
122 $response = \Activitypub\safe_remote_get( $actor, $user_id );
123
124 if ( \is_wp_error( $response ) ) {
125 return $response;
126 }
127
128 $metadata = \wp_remote_retrieve_body( $response );
129 $metadata = \json_decode( $metadata, true );
130
131 if ( ! $metadata ) {
132 return new \WP_Error( 'activitypub_invalid_json', \__( 'No valid JSON data', 'activitypub' ), $actor );
133 }
134
135 \set_transient( 'activitypub_' . $actor, $metadata, WEEK_IN_SECONDS );
136
137 return $metadata;
138 }
139
140 /**
141 * [get_inbox_by_actor description]
142 * @param [type] $actor [description]
143 * @return [type] [description]
144 */
145 function get_inbox_by_actor( $actor ) {
146 $metadata = \Activitypub\get_remote_metadata_by_actor( $actor );
147
148 if ( \is_wp_error( $metadata ) ) {
149 return $metadata;
150 }
151
152 if ( isset( $metadata['endpoints'] ) && isset( $metadata['endpoints']['sharedInbox'] ) ) {
153 return $metadata['endpoints']['sharedInbox'];
154 }
155
156 if ( \array_key_exists( 'inbox', $metadata ) ) {
157 return $metadata['inbox'];
158 }
159
160 return new \WP_Error( 'activitypub_no_inbox', __( 'No "Inbox" found', 'activitypub' ), $metadata );
161 }
162
163 /**
164 * [get_inbox_by_actor description]
165 * @param [type] $actor [description]
166 * @return [type] [description]
167 */
168 function get_publickey_by_actor( $actor, $key_id ) {
169 $metadata = \Activitypub\get_remote_metadata_by_actor( $actor );
170
171 if ( \is_wp_error( $metadata ) ) {
172 return $metadata;
173 }
174
175 if (
176 isset( $metadata['publicKey'] ) &&
177 isset( $metadata['publicKey']['id'] ) &&
178 isset( $metadata['publicKey']['owner'] ) &&
179 isset( $metadata['publicKey']['publicKeyPem'] ) &&
180 $key_id === $metadata['publicKey']['id'] &&
181 $actor === $metadata['publicKey']['owner']
182 ) {
183 return $metadata['publicKey']['publicKeyPem'];
184 }
185
186 return new \WP_Error( 'activitypub_no_public_key', \__( 'No "Public-Key" found', 'activitypub' ), $metadata );
187 }
188
189 function get_follower_inboxes( $user_id ) {
190 $followers = \Activitypub\Peer\Followers::get_followers( $user_id );
191 $inboxes = array();
192
193 foreach ( $followers as $follower ) {
194 $inbox = \Activitypub\get_inbox_by_actor( $follower );
195 if ( ! $inbox || \is_wp_error( $inbox ) ) {
196 continue;
197 }
198 // init array if empty
199 if ( ! isset( $inboxes[ $inbox ] ) ) {
200 $inboxes[ $inbox ] = array();
201 }
202 $inboxes[ $inbox ][] = $follower;
203 }
204
205 return $inboxes;
206 }
207
208 function get_identifier_settings( $user_id ) {
209 ?>
210 <table class="form-table">
211 <tbody>
212 <tr>
213 <th scope="row">
214 <label><?php \esc_html_e( 'Profile identifier', 'activitypub' ); ?></label>
215 </th>
216 <td>
217 <p><code><?php echo \esc_html( \Activitypub\get_webfinger_resource( $user_id ) ); ?></code> or <code><?php echo \esc_url( \get_author_posts_url( $user_id ) ); ?></code></p>
218 <?php // translators: the webfinger resource ?>
219 <p class="description"><?php \printf( \esc_html__( 'Try to follow "@%s" in the Mastodon/Friendica search field.', 'activitypub' ), \esc_html( \Activitypub\get_webfinger_resource( $user_id ) ) ); ?></p>
220 </td>
221 </tr>
222 </tbody>
223 </table>
224 <?php
225 }
226
227 function get_followers( $user_id ) {
228 $followers = \Activitypub\Peer\Followers::get_followers( $user_id );
229
230 if ( ! $followers ) {
231 return array();
232 }
233
234 return $followers;
235 }
236
237 function count_followers( $user_id ) {
238 $followers = \Activitypub\get_followers( $user_id );
239
240 return \count( $followers );
241 }
242
243 /**
244 * Examine a url and try to determine the author ID it represents.
245 *
246 * Checks are supposedly from the hosted site blog.
247 *
248 * @param string $url Permalink to check.
249 *
250 * @return int User ID, or 0 on failure.
251 */
252 function url_to_authorid( $url ) {
253 global $wp_rewrite;
254
255 // check if url hase the same host
256 if ( wp_parse_url( site_url(), PHP_URL_HOST ) !== wp_parse_url( $url, PHP_URL_HOST ) ) {
257 return 0;
258 }
259
260 // first, check to see if there is a 'author=N' to match against
261 if ( \preg_match( '/[?&]author=(\d+)/i', $url, $values ) ) {
262 $id = absint( $values[1] );
263 if ( $id ) {
264 return $id;
265 }
266 }
267
268 // check to see if we are using rewrite rules
269 $rewrite = $wp_rewrite->wp_rewrite_rules();
270
271 // not using rewrite rules, and 'author=N' method failed, so we're out of options
272 if ( empty( $rewrite ) ) {
273 return 0;
274 }
275
276 // generate rewrite rule for the author url
277 $author_rewrite = $wp_rewrite->get_author_permastruct();
278 $author_regexp = \str_replace( '%author%', '', $author_rewrite );
279
280 // match the rewrite rule with the passed url
281 if ( \preg_match( '/https?:\/\/(.+)' . \preg_quote( $author_regexp, '/' ) . '([^\/]+)/i', $url, $match ) ) {
282 $user = get_user_by( 'slug', $match[2] );
283 if ( $user ) {
284 return $user->ID;
285 }
286 }
287
288 return 0;
289 }
290
291 /**
292 * Get the blacklist from the WordPress options table
293 *
294 * @return array the list of blacklisted hosts
295 *
296 * @uses apply_filters() Calls 'activitypub_blacklist' filter
297 */
298 function get_blacklist() {
299 $blacklist = \get_option( 'activitypub_blacklist' );
300 $blacklist_hosts = \explode( PHP_EOL, $blacklist );
301
302 // if no values have been set, revert to the defaults
303 if ( ! $blacklist || ! $blacklist_hosts || ! \is_array( $blacklist_hosts ) ) {
304 $blacklist_hosts = array();
305 }
306
307 // clean out any blank values
308 foreach ( $blacklist_hosts as $key => $value ) {
309 if ( empty( $value ) ) {
310 unset( $blacklist_hosts[ $key ] );
311 } else {
312 $blacklist_hosts[ $key ] = \trim( $blacklist_hosts[ $key ] );
313 }
314 }
315
316 return \apply_filters( 'activitypub_blacklist', $blacklist_hosts );
317 }
318
319 /**
320 * Check if an URL is blacklisted
321 *
322 * @param string $url an URL to check
323 *
324 * @return boolean
325 */
326 function is_blacklisted( $url ) {
327 foreach ( \ActivityPub\get_blacklist() as $blacklisted_host ) {
328 if ( \strpos( $url, $blacklisted_host ) !== false ) {
329 return true;
330 }
331 }
332
333 return false;
334 }
335